001package react4j; 002 003import java.util.Objects; 004import javaemul.internal.annotations.DoNotAutobox; 005import javax.annotation.Nonnull; 006import javax.annotation.Nullable; 007import jsinterop.annotations.JsOverlay; 008import jsinterop.annotations.JsPackage; 009import jsinterop.annotations.JsProperty; 010import jsinterop.annotations.JsType; 011import jsinterop.base.JsPropertyMap; 012import react4j.internal.ViewConstructorFunction; 013 014/** 015 * Element represents either a view or a host component. 016 */ 017@SuppressWarnings( "unused" ) 018@JsType( isNative = true, name = "Object", namespace = JsPackage.GLOBAL ) 019public class ReactElement 020 implements ReactNode 021{ 022 @JsProperty( name = "$$typeof" ) 023 private Object typeof; 024 private Object type; 025 private String key; 026 private Object ref; 027 @JsProperty( name = "props" ) 028 private JsPropertyMap<Object> inputs; 029 // The view responsible for creating this element. 030 // can be null if create happens outside of a render method (i.e. at the top level). 031 @Nullable 032 private Object _owner; 033 034 @JsOverlay 035 public final ReactElement dup() 036 { 037 final ReactElement element = createRawNode( typeof, type ); 038 element.key = key; 039 element.ref = ref; 040 element.inputs = JsPropertyMap.of(); 041 inputs.forEach( key -> element.inputs.set( key, inputs.get( key ) ) ); 042 return element; 043 } 044 045 @JsOverlay 046 @Nonnull 047 public static ReactElement createViewElement( @Nonnull final ViewConstructorFunction type ) 048 { 049 final ReactElement element = create( type ); 050 element.inputs = JsPropertyMap.of(); 051 element.key = null; 052 element.ref = null; 053 return element; 054 } 055 056 @JsOverlay 057 @Nonnull 058 static ReactElement createContextElement( @Nonnull final Object type ) 059 { 060 final ReactElement element = create( type ); 061 element.inputs = JsPropertyMap.of(); 062 element.key = null; 063 element.ref = null; 064 return element; 065 } 066 067 @JsOverlay 068 @Nonnull 069 private static ReactElement create( @Nonnull final Object type ) 070 { 071 return createRawNode( React.Element, type ); 072 } 073 074 @JsOverlay 075 @Nonnull 076 private static ReactElement createRawNode( @Nonnull final Object typeof, @Nonnull final Object type ) 077 { 078 final ReactElement element = new ReactElement(); 079 element.typeof = Objects.requireNonNull( typeof ); 080 element.type = Objects.requireNonNull( type ); 081 element._owner = React.currentOwner(); 082 return element; 083 } 084 085 @JsOverlay 086 @Nonnull 087 private static ReactElement createRawElement( @Nonnull final Object type, 088 @Nullable final String key, 089 @Nullable final Object ref, 090 @Nonnull final JsPropertyMap<Object> inputs ) 091 { 092 final ReactElement element = create( type ); 093 element.key = key; 094 element.ref = ref; 095 element.inputs = Objects.requireNonNull( inputs ); 096 return element; 097 } 098 099 @JsOverlay 100 @Nonnull 101 public static ReactElement createFragment( @Nullable final String key, @Nonnull final ReactNode... children ) 102 { 103 final ReactElement element = createRawNode( React.Element, React.Fragment ); 104 element.key = key; 105 element.ref = null; 106 element.inputs = JsPropertyMap.of( "children", Objects.requireNonNull( children ) ); 107 return element; 108 } 109 110 /** 111 * Create a StrictMode component with the specified children. 112 * 113 * @param children the child nodes. 114 * @return a new React.StrictMode component. 115 */ 116 @JsOverlay 117 @Nonnull 118 public static ReactNode createStrictMode( @Nonnull final ReactNode... children ) 119 { 120 return ReactElement.createRawElement( React.StrictMode, 121 null, 122 null, 123 JsPropertyMap.of( "children", Objects.requireNonNull( children ) ) ); 124 } 125 126 @JsOverlay 127 @Nonnull 128 public static ReactElement createSuspense( @Nullable final String key, 129 @Nullable final ReactNode fallback, 130 final int maxTimeToFallback, 131 @Nonnull final ReactNode... children ) 132 { 133 final ReactElement element = createRawNode( React.Element, React.Suspense ); 134 element.key = key; 135 element.ref = null; 136 element.inputs = JsPropertyMap.of( "children", Objects.requireNonNull( children ), 137 "fallback", fallback, 138 "ms", maxTimeToFallback ); 139 return element; 140 } 141 142 @JsOverlay 143 @Nonnull 144 public static ReactElement createHostElement( @Nonnull final String type, 145 @Nullable final String key, 146 @Nullable final Object ref, 147 @Nonnull final JsPropertyMap<Object> inputs ) 148 { 149 return createRawElement( type, key, ref, inputs ); 150 } 151 152 @JsOverlay 153 @Nullable 154 public final String key() 155 { 156 return key; 157 } 158 159 @JsOverlay 160 public final void setKey( @Nullable final String key ) 161 { 162 this.key = key; 163 } 164 165 @JsOverlay 166 @Nonnull 167 public final JsPropertyMap<Object> inputs() 168 { 169 return inputs; 170 } 171 172 @JsOverlay 173 @Nonnull 174 public final ReactElement input( @Nonnull final String key, @DoNotAutobox final Object value ) 175 { 176 inputs.set( key, value ); 177 return this; 178 } 179 180 @JsOverlay 181 protected final void setInputs( @Nonnull final JsPropertyMap<Object> inputs ) 182 { 183 this.inputs = inputs; 184 } 185}