@@ -11,11 +11,22 @@ import { insert } from './operations';
11
11
import { setProperty } from './props' ;
12
12
import { assign , isArray , slice } from '../util' ;
13
13
import options from '../options' ;
14
+ import {
15
+ createInternal ,
16
+ MODE_MATH ,
17
+ MODE_SVG ,
18
+ TYPE_CLASS ,
19
+ TYPE_COMPONENT ,
20
+ TYPE_ELEMENT ,
21
+ TYPE_FUNCTION ,
22
+ TYPE_INVALID ,
23
+ TYPE_TEXT
24
+ } from '../tree' ;
14
25
15
26
/**
16
27
* Diff two virtual nodes and apply proper changes to the DOM
17
28
* @param {PreactElement } parentDom The parent of the DOM element
18
- * @param {VNode } newVNode The new virtual node
29
+ * @param {Internal } internal The backing node.
19
30
* @param {object } globalContext The current context object. Modified by
20
31
* getChildContext
21
32
* @param {string } namespace Current namespace of the DOM node (HTML, SVG, or MathML)
@@ -31,7 +42,7 @@ import options from '../options';
31
42
*/
32
43
export function mount (
33
44
parentDom ,
34
- newVNode ,
45
+ internal ,
35
46
globalContext ,
36
47
namespace ,
37
48
excessDomChildren ,
@@ -40,22 +51,24 @@ export function mount(
40
51
isHydrating ,
41
52
refQueue
42
53
) {
54
+ // @ts -expect-error
55
+ const newVNode = internal . vnode ;
56
+
43
57
// When passing through createElement it assigns the object
44
58
// constructor as undefined. This to prevent JSON-injection.
45
- if ( newVNode . constructor !== UNDEFINED ) return null ;
59
+ if ( internal . flags & TYPE_INVALID ) return null ;
46
60
47
61
/** @type {any } */
48
- let tmp ,
49
- newType = newVNode . type ;
62
+ let tmp ;
50
63
51
64
if ( ( tmp = options . _diff ) ) tmp ( newVNode ) ;
52
65
53
- if ( typeof newType == 'function' ) {
66
+ if ( internal . flags & TYPE_COMPONENT ) {
54
67
try {
55
68
let c ,
56
- newProps = newVNode . props ;
57
- const isClassComponent =
58
- 'prototype' in newType && newType . prototype . render ;
69
+ newProps = internal . props ,
70
+ newType = /** @type { ComponentType } */ ( internal . type ) ;
71
+ const isClassComponent = ! ! ( internal . flags & TYPE_CLASS ) ;
59
72
60
73
// Necessary for createContext api. Setting this property will pass
61
74
// the context value as `this.context` just for this component.
@@ -69,11 +82,17 @@ export function mount(
69
82
70
83
// Instantiate the new component
71
84
if ( isClassComponent ) {
72
- // @ts -expect-error The check above verifies that newType is suppose to be constructed
73
- newVNode . _component = c = new newType ( newProps , componentContext ) ; // eslint-disable-line new-cap
85
+ internal . _component =
86
+ newVNode . _component =
87
+ c =
88
+ // @ts -expect-error The check above verifies that newType is suppose to be constructed
89
+ new newType ( newProps , componentContext ) ; // eslint-disable-line new-cap
74
90
} else {
75
- // @ts -expect-error Trust me, Component implements the interface we want
76
- newVNode . _component = c = new BaseComponent ( newProps , componentContext ) ;
91
+ // @ts -expect-error The check above verifies that newType is suppose to be constructed
92
+ internal . _component =
93
+ newVNode . _component =
94
+ c =
95
+ new BaseComponent ( newProps , componentContext ) ;
77
96
c . constructor = newType ;
78
97
c . render = doRender ;
79
98
}
@@ -156,6 +175,7 @@ export function mount(
156
175
let renderResult = isTopLevelFragment ? tmp . props . children : tmp ;
157
176
158
177
oldDom = mountChildren (
178
+ internal ,
159
179
parentDom ,
160
180
isArray ( renderResult ) ? renderResult : [ renderResult ] ,
161
181
newVNode ,
@@ -200,7 +220,7 @@ export function mount(
200
220
}
201
221
} else {
202
222
oldDom = newVNode . _dom = mountElementNode (
203
- newVNode ,
223
+ internal ,
204
224
globalContext ,
205
225
namespace ,
206
226
excessDomChildren ,
@@ -217,7 +237,7 @@ export function mount(
217
237
218
238
/**
219
239
* Diff two virtual nodes representing DOM element
220
- * @param {VNode } newVNode The new virtual node
240
+ * @param {Internal } internal The new virtual node
221
241
* @param {object } globalContext The current context object
222
242
* @param {string } namespace Current namespace of the DOM node (HTML, SVG, or MathML)
223
243
* @param {Array<PreactElement> } excessDomChildren
@@ -228,19 +248,21 @@ export function mount(
228
248
* @returns {PreactElement }
229
249
*/
230
250
function mountElementNode (
231
- newVNode ,
251
+ internal ,
232
252
globalContext ,
233
253
namespace ,
234
254
excessDomChildren ,
235
255
commitQueue ,
236
256
isHydrating ,
237
257
refQueue
238
258
) {
259
+ // @ts -expect-error
260
+ const newVNode = internal . vnode ;
239
261
/** @type {PreactElement } */
240
262
let dom ;
241
263
let oldProps = EMPTY_OBJ ;
242
- let newProps = newVNode . props ;
243
- let nodeType = /** @type {string } */ ( newVNode . type ) ;
264
+ let newProps = internal . props ;
265
+ let nodeType = /** @type {string } */ ( internal . type ) ;
244
266
/** @type {any } */
245
267
let i ;
246
268
/** @type {{ __html?: string } } */
@@ -252,8 +274,8 @@ function mountElementNode(
252
274
let checked ;
253
275
254
276
// Tracks entering and exiting namespaces when descending through the tree.
255
- if ( nodeType === 'svg' ) namespace = 'http://www.w3.org/2000/svg' ;
256
- else if ( nodeType === 'math' )
277
+ if ( internal . flags & MODE_SVG ) namespace = 'http://www.w3.org/2000/svg' ;
278
+ else if ( internal . flags & MODE_MATH )
257
279
namespace = 'http://www.w3.org/1998/Math/MathML' ;
258
280
else if ( ! namespace ) namespace = 'http://www.w3.org/1999/xhtml' ;
259
281
@@ -277,7 +299,7 @@ function mountElementNode(
277
299
}
278
300
279
301
if ( dom == null ) {
280
- if ( nodeType === null ) {
302
+ if ( internal . flags & TYPE_TEXT ) {
281
303
return document . createTextNode ( newProps ) ;
282
304
}
283
305
@@ -298,7 +320,7 @@ function mountElementNode(
298
320
excessDomChildren = null ;
299
321
}
300
322
301
- if ( nodeType === null ) {
323
+ if ( internal . flags & TYPE_TEXT ) {
302
324
// During hydration, we still have to split merged text from SSR'd HTML.
303
325
dom . data = newProps ;
304
326
} else {
@@ -361,6 +383,7 @@ function mountElementNode(
361
383
newVNode . _children = [ ] ;
362
384
} else {
363
385
mountChildren (
386
+ internal ,
364
387
dom ,
365
388
isArray ( newChildren ) ? newChildren : [ newChildren ] ,
366
389
newVNode ,
@@ -416,6 +439,7 @@ function doRender(props, _state, context) {
416
439
417
440
/**
418
441
* Diff the children of a virtual node
442
+ * @param {Internal } internal The DOM element whose children are being
419
443
* @param {PreactElement } parentDom The DOM element whose children are being
420
444
* diffed
421
445
* @param {ComponentChildren[] } renderResult
@@ -435,6 +459,7 @@ function doRender(props, _state, context) {
435
459
* @param {any[] } refQueue an array of elements needed to invoke refs
436
460
*/
437
461
function mountChildren (
462
+ internal ,
438
463
parentDom ,
439
464
renderResult ,
440
465
newParentVNode ,
@@ -517,10 +542,11 @@ function mountChildren(
517
542
childVNode . _parent = newParentVNode ;
518
543
childVNode . _depth = newParentVNode . _depth + 1 ;
519
544
545
+ const childInternal = createInternal ( childVNode , internal ) ;
520
546
// Morph the old element into the new one, but don't append it to the dom yet
521
547
const result = mount (
522
548
parentDom ,
523
- childVNode ,
549
+ childInternal ,
524
550
globalContext ,
525
551
namespace ,
526
552
excessDomChildren ,
@@ -544,9 +570,13 @@ function mountChildren(
544
570
firstChildDom = newDom ;
545
571
}
546
572
547
- if ( typeof childVNode . type != 'function' ) {
573
+ if ( childInternal . flags & TYPE_ELEMENT || childInternal . flags & TYPE_TEXT ) {
548
574
oldDom = insert ( childVNode , oldDom , parentDom ) ;
549
- } else if ( typeof childVNode . type == 'function' && result !== UNDEFINED ) {
575
+ } else if (
576
+ ( childInternal . flags & TYPE_FUNCTION ||
577
+ childInternal . flags & TYPE_CLASS ) &&
578
+ result !== UNDEFINED
579
+ ) {
550
580
oldDom = result ;
551
581
} else if ( newDom ) {
552
582
oldDom = newDom . nextSibling ;
0 commit comments