@@ -19,20 +19,23 @@ export class ReactNode {
1919 // so that the dirty "render pending" state of this object can be properly
2020 // tracked and all nodes with "render pending" can be flushed at the end
2121 // of render operation.
22- private props = { } ;
23- private comment : string ;
24- private text : string ;
25- private typeIsReactElementClass ;
26- private children : Array < ReactNode > = [ ] ;
27- private typeName : string ;
28- private childrenToAppend : Array < HTMLElement > = [ ] ;
29-
30- private renderedDomElement : HTMLElement ;
22+ private _props = { } ;
23+ private _comment : string ;
24+ private _text : string ;
25+ private _typeIsReactElementClass : boolean | undefined ;
26+ private _children : Array < ReactNode > = [ ] ;
27+ private _typeName : string ;
28+ private _childrenToAppend : Array < HTMLElement > = [ ] ;
29+ private _renderedDomElement : HTMLElement ;
30+ private _parent : HTMLElement | ReactNode ;
31+ private _isNotRenderable : boolean ;
32+ private _isDestroyPending : boolean = false ;
33+ private _isRenderPending = true ;
34+
3135 get domElement ( ) {
32- return this . renderedDomElement ;
36+ return this . _renderedDomElement ;
3337 }
3438
35- private _parent : HTMLElement | ReactNode ;
3639 set parent ( parent : HTMLElement | ReactNode ) {
3740 this . _parent = parent ;
3841 this . setRenderPending ( ) ;
@@ -42,69 +45,46 @@ export class ReactNode {
4245 return this . _parent ;
4346 }
4447
45- private isNotRenderable : boolean ;
4648 get shouldRender ( ) {
47- return ! this . isNotRenderable ;
49+ return ! this . _isNotRenderable ;
4850 }
4951
50- private isDestroyPending = false ;
5152 get destroyPending ( ) {
52- return this . isDestroyPending ;
53+ return this . _isDestroyPending ;
54+ }
55+
56+ constructor ( private type ?: React . ReactType ) {
57+ this . setRenderPending ( ) ;
58+ this . _tryResolveTypeIsReactElementClass ( ) ;
5359 }
5460
55- private isRenderPending = true ;
5661 setRenderPendingCallback = ( ) => null ;
57- // Track all pending render operations internally and set flag on
58- // renderer factory so that a flush operation can be scheduled for
59- // the "end" of render.
62+
63+ /**
64+ * Track all pending render operations internally and set flag on
65+ * renderer factory so that a flush operation can be scheduled for
66+ * the "end" of render.
67+ */
6068 setRenderPending ( ) {
6169 this . setRenderPendingCallback ( ) ;
62- this . isRenderPending = true ;
70+ this . _isRenderPending = true ;
6371 }
6472
6573 destroyNode ( ) {
6674 this . setRenderPending ( ) ;
67- this . isDestroyPending = true ;
68- }
69-
70- private tryResolveTypeIsReactElementClass ( ) {
71- if ( this . typeIsReactElementClass === undefined ) {
72- // Comments and text have no type.
73- if ( ! this . type ) {
74- return ;
75- }
76-
77- // Store the name of the type for the toString message (debugging).
78- this . typeName = this . type as string ;
79-
80- // Attempt to resolve the type as a React Element class name/type.
81- if ( typeof this . type === 'string' ) {
82- this . type = getComponentClass ( this . type ) ;
83- }
84-
85- // If type is still a string, then no React Element matches this string.
86- this . typeIsReactElementClass = typeof this . type !== 'string' ;
87-
88- if ( DEBUG ) {
89- console . log ( 'ReactNode > tryResolveTypeIsReactElementClass > type:' , this . typeName ) ;
90- }
91- }
75+ this . _isDestroyPending = true ;
9276 }
9377
9478 setAttribute ( name : string , value : any ) {
95- this . setAttributes ( {
96- [ name ] : value ,
97- } ) ;
79+ this . setAttributes ( { [ name ] : value } ) ;
9880 }
9981
10082 setAttributes ( attributes : StringMap ) {
10183 this . setProperties ( attributes ) ;
10284 }
10385
10486 setProperty ( name : string , value : any ) {
105- this . setProperties ( {
106- [ name ] : value ,
107- } ) ;
87+ this . setProperties ( { [ name ] : value } ) ;
10888 }
10989
11090 setProperties ( properties : StringMap ) {
@@ -115,43 +95,38 @@ export class ReactNode {
11595 removeProperty ( name : string , childName ?: string ) {
11696 this . setRenderPending ( ) ;
11797 if ( childName ) {
118- return delete this . props [ name ] [ childName ] ;
98+ return delete this . _props [ name ] [ childName ] ;
11999 }
120100
121- return delete this . props [ name ] ;
101+ return delete this . _props [ name ] ;
122102 }
123103
124104 addChild ( node : ReactNode ) {
125105 this . setRenderPending ( ) ;
126- this . children . push ( node ) ;
106+ this . _children . push ( node ) ;
127107 }
128108
129109 removeChild ( node : ReactNode ) {
130110 this . setRenderPending ( ) ;
131- this . children = this . children . filter ( child => child !== node ) ;
132- }
133-
134- constructor ( private type ?: React . ReactType ) {
135- this . setRenderPending ( ) ;
136- this . tryResolveTypeIsReactElementClass ( ) ;
111+ this . _children = this . _children . filter ( child => child !== node ) ;
137112 }
138113
139114 asComment ( value : string ) {
140115 this . setRenderPending ( ) ;
141116 this . type = undefined ;
142- this . comment = value ;
117+ this . _comment = value ;
143118 return this ;
144119 }
145120
146121 asText ( value : string ) {
147122 this . setRenderPending ( ) ;
148123 this . type = undefined ;
149- this . text = value ;
124+ this . _text = value ;
150125
151126 // Skip appending and rendering of empty text nodes. This may cause a bug
152127 // if a single space is desired...
153128 if ( ! value || ! value . trim ( ) ) {
154- this . isNotRenderable = true ;
129+ this . _isNotRenderable = true ;
155130 }
156131
157132 return this ;
@@ -162,55 +137,95 @@ export class ReactNode {
162137 // Those that are parented by other ReactNodes will be rendered recursively by their
163138 // parent.
164139 if ( ! isReactNode ( this . _parent ) ) {
165- if ( this . isDestroyPending && this . _parent ) {
140+ if ( this . _isDestroyPending && this . _parent ) {
166141 if ( DEBUG ) {
167142 console . log ( 'ReactNode > render > destroy > node:' , this . toString ( ) , 'parent:' , this . parent ) ;
168143 }
169144 ReactDOM . unmountComponentAtNode ( this . _parent ) ;
170145 return this ;
171146 }
172147
173- if ( this . isRenderPending ) {
148+ if ( this . _isRenderPending ) {
174149 if ( DEBUG ) {
175150 console . log ( 'ReactNode > render > node:' , this . toString ( ) , 'parent:' , this . parent ) ;
176151 }
177152 // It is expected that the element will be recreated and re-rendered with each attribute change.
178153 // See: https://reactjs.org/docs/rendering-elements.html
179- ReactDOM . render ( this . renderRecursive ( ) as React . ReactElement < { } > , this . _parent ) ;
180- this . isRenderPending = false ;
154+ ReactDOM . render ( this . _renderRecursive ( ) as React . ReactElement < { } > , this . _parent ) ;
155+ this . _isRenderPending = false ;
181156 }
182157 }
183158
184159 return this ;
185160 }
186161
187- private renderRecursive ( key ?: string ) : React . ReactElement < { } > | string {
188- const children = this . children ? this . children . map ( ( child , index ) => child . renderRecursive ( index . toString ( ) ) ) : [ ] ;
162+ // This is called by Angular core when projected content is being added.
163+ appendChild ( projectedContent : HTMLElement ) {
164+ if ( DEBUG ) {
165+ console . error (
166+ 'ReactNode > appendChild > node:' ,
167+ this . toString ( ) ,
168+ 'projectedContent:' ,
169+ projectedContent . toString ( ) . trim ( )
170+ ) ;
171+ }
172+ this . _childrenToAppend . push ( projectedContent ) ;
173+ }
189174
190- if ( this . text ) {
191- return this . text ;
175+ toString ( ) : string {
176+ if ( this . _typeName ) {
177+ return `[${ this . _typeName } ReactNode]` ;
192178 }
193179
194- this . props [ CHILDREN_TO_APPEND_PROP ] = this . childrenToAppend ;
180+ if ( this . _text ) {
181+ return '[text ReactNode]' ;
182+ }
195183
196- if ( key ) this . props [ 'key' ] = key ;
184+ if ( this . _comment ) {
185+ return '[comment ReactNode]' ;
186+ }
187+
188+ return '[undefined ReactNode]' ;
189+ }
190+
191+ private _renderRecursive ( key ?: string ) : React . ReactElement < { } > | string {
192+ const children = this . _children
193+ ? this . _children . map ( ( child , index ) => child . _renderRecursive ( index . toString ( ) ) )
194+ : [ ] ;
195+
196+ if ( this . _text ) {
197+ return this . _text ;
198+ }
199+
200+ this . _props [ CHILDREN_TO_APPEND_PROP ] = this . _childrenToAppend ;
201+
202+ if ( key ) {
203+ this . _props [ 'key' ] = key ;
204+ }
197205
198- const clearedProps = this . transformProps ( removeUndefinedProperties ( this . props ) ) ;
206+ const clearedProps = this . _transformProps ( removeUndefinedProperties ( this . _props ) ) ;
199207
200208 if ( DEBUG ) {
201- console . warn ( 'ReactNode > renderRecursive > type:' , this . toString ( ) , 'props:' , this . props , 'children:' , children ) ;
209+ console . warn (
210+ 'ReactNode > renderRecursive > type:' ,
211+ this . toString ( ) ,
212+ 'props:' ,
213+ this . _props ,
214+ 'children:' ,
215+ children
216+ ) ;
202217 }
203218 return React . createElement ( this . type , clearedProps , children . length > 0 ? children : undefined ) ;
204219 }
205220
206- private transformProps < TProps extends object > ( props : TProps ) {
221+ private _transformProps < TProps extends object > ( props : TProps ) {
207222 return Object . entries ( props ) . reduce ( ( acc , [ key , value ] ) => {
208- const [ newKey , newValue ] = typeof key !== 'string' ? [ key , value ] : this . transformProp ( key , value ) ;
223+ const [ newKey , newValue ] = typeof key !== 'string' ? [ key , value ] : this . _transformProp ( key , value ) ;
209224 return Object . assign ( acc , { [ newKey ] : newValue } ) ;
210225 } , { } ) ;
211226 }
212227
213- private transformProp < TValue = any > ( name : string , value : TValue ) : [ string , TValue ] {
228+ private _transformProp < TValue = any > ( name : string , value : TValue ) : [ string , TValue ] {
214229 // prop name is camelCased already
215230 const firstLetter = name [ 0 ] ;
216231 if ( firstLetter === firstLetter . toLowerCase ( ) ) {
@@ -223,32 +238,27 @@ export class ReactNode {
223238 return [ `on${ name } ` , value ] ;
224239 }
225240
226- // This is called by Angular core when projected content is being added.
227- appendChild ( projectedContent : HTMLElement ) {
228- if ( DEBUG ) {
229- console . error (
230- 'ReactNode > appendChild > node:' ,
231- this . toString ( ) ,
232- 'projectedContent:' ,
233- projectedContent . toString ( ) . trim ( )
234- ) ;
235- }
236- this . childrenToAppend . push ( projectedContent ) ;
237- }
241+ private _tryResolveTypeIsReactElementClass ( ) {
242+ if ( this . _typeIsReactElementClass === undefined ) {
243+ // Comments and text have no type.
244+ if ( ! this . type ) {
245+ return ;
246+ }
238247
239- toString ( ) : string {
240- if ( this . typeName ) {
241- return `[${ this . typeName } ReactNode]` ;
242- }
248+ // Store the name of the type for the toString message (debugging).
249+ this . _typeName = this . type as string ;
243250
244- if ( this . text ) {
245- return '[text ReactNode]' ;
246- }
251+ // Attempt to resolve the type as a React Element class name/type.
252+ if ( typeof this . type === 'string' ) {
253+ this . type = getComponentClass ( this . type ) ;
254+ }
247255
248- if ( this . comment ) {
249- return '[comment ReactNode]' ;
250- }
256+ // If type is still a string, then no React Element matches this string.
257+ this . _typeIsReactElementClass = typeof this . type !== 'string' ;
251258
252- return '[undefined ReactNode]' ;
259+ if ( DEBUG ) {
260+ console . log ( 'ReactNode > tryResolveTypeIsReactElementClass > type:' , this . _typeName ) ;
261+ }
262+ }
253263 }
254264}
0 commit comments