@reckona/mreact-compat 0.0.171 → 0.0.173
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/devtools.js +2 -0
- package/dist/devtools.js.map +1 -1
- package/dist/dom-host-rules.d.ts.map +1 -1
- package/dist/dom-host-rules.js +4 -1
- package/dist/dom-host-rules.js.map +1 -1
- package/dist/dom-props.js +2 -1
- package/dist/dom-props.js.map +1 -1
- package/dist/element.d.ts +13 -1
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +30 -2
- package/dist/element.js.map +1 -1
- package/dist/fiber-commit.js +2 -1
- package/dist/fiber-commit.js.map +1 -1
- package/dist/fiber-host.d.ts +1 -1
- package/dist/fiber-host.d.ts.map +1 -1
- package/dist/fiber-host.js +1 -1
- package/dist/fiber-host.js.map +1 -1
- package/dist/fiber.d.ts +2 -1
- package/dist/fiber.d.ts.map +1 -1
- package/dist/fiber.js +2 -0
- package/dist/fiber.js.map +1 -1
- package/dist/hooks.d.ts +9 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +127 -44
- package/dist/hooks.js.map +1 -1
- package/dist/host-reconciler.d.ts +2 -0
- package/dist/host-reconciler.d.ts.map +1 -1
- package/dist/host-reconciler.js +696 -55
- package/dist/host-reconciler.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +3 -1
- package/dist/jsx-dev-runtime.d.ts.map +1 -1
- package/dist/jsx-dev-runtime.js +3 -1
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +4 -2
- package/dist/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx-runtime.js +9 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/reactive-prop-cell.d.ts +13 -0
- package/dist/reactive-prop-cell.d.ts.map +1 -0
- package/dist/reactive-prop-cell.js +36 -0
- package/dist/reactive-prop-cell.js.map +1 -0
- package/dist/root.d.ts.map +1 -1
- package/dist/root.js +8 -5
- package/dist/root.js.map +1 -1
- package/package.json +3 -3
- package/src/devtools.ts +2 -0
- package/src/dom-host-rules.ts +4 -1
- package/src/dom-props.ts +2 -1
- package/src/element.ts +60 -3
- package/src/fiber-commit.ts +3 -1
- package/src/fiber-host.ts +2 -0
- package/src/fiber.ts +4 -0
- package/src/hooks.ts +187 -46
- package/src/host-reconciler.ts +1031 -70
- package/src/jsx-dev-runtime.ts +4 -0
- package/src/jsx-runtime.ts +16 -0
- package/src/reactive-prop-cell.ts +67 -0
- package/src/root.ts +14 -4
package/dist/host-reconciler.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Activity, ERROR_BOUNDARY_TYPE, FORWARD_REF_TYPE, Fragment, HOST_CHILDREN_ONLY_PROPS_META, LAZY_TYPE, MEMO_TYPE, Profiler, REACTIVE_TEXT_BINDING_META, STRICT_MODE_TYPE, Suspense, SuspenseList, isReactCompatElement, isReactCompatPortal, } from "./element.js";
|
|
1
|
+
import { Activity, ERROR_BOUNDARY_TYPE, FORWARD_REF_TYPE, Fragment, HOST_CHILDREN_ONLY_PROPS_META, LAZY_TYPE, MEMO_TYPE, Profiler, REACTIVE_DOM_BLOCK_TYPE, REACTIVE_TEXT_BINDING_META, STRICT_MODE_TYPE, Suspense, SuspenseList, isReactCompatElement, isReactCompatPortal, } from "./element.js";
|
|
2
|
+
import { createReactivePropCell, createReactivePropProxy, setReactivePropCell, } from "./reactive-prop-cell.js";
|
|
2
3
|
import { consumerContext, isReactCompatConsumer, isReactCompatProvider, renderWithContextProvider, useContext, } from "./context.js";
|
|
3
4
|
import { applyPostChildFormProps, applyProps } from "./dom-props.js";
|
|
4
5
|
import { syncChildNodes, syncOwnedChildNodes, syncScopedChildNodes } from "./dom-children.js";
|
|
@@ -13,6 +14,7 @@ import { areMemoPropsEqual, getPendingProps, shallowEqual } from "./prop-compari
|
|
|
13
14
|
import { reportElementTextMismatch, reportExtraHydrationNodes, reportHydrationNodeTypeMismatch, reportMissingHydrationNode, reportReactSuspenseServerError, reportRecoverable, withHydrationComponentStack, } from "./hydration.js";
|
|
14
15
|
const committedPortalContainers = new Set();
|
|
15
16
|
const pendingHostRefUpdates = [];
|
|
17
|
+
const emptyInstanceKeys = [];
|
|
16
18
|
const SKIP_COMMIT_PATH = "\0";
|
|
17
19
|
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
18
20
|
let suspensePrimaryRenderDepth = 0;
|
|
@@ -49,6 +51,9 @@ export function canRenderHostFiber(node) {
|
|
|
49
51
|
if (node.type === ERROR_BOUNDARY_TYPE) {
|
|
50
52
|
return true;
|
|
51
53
|
}
|
|
54
|
+
if (node.type === REACTIVE_DOM_BLOCK_TYPE) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
52
57
|
if (isReactCompatProvider(node.type)) {
|
|
53
58
|
return canRenderHostFiber(node.props.children);
|
|
54
59
|
}
|
|
@@ -100,7 +105,12 @@ export function commitHostFiberRoot(root, finishedWork, options = {}) {
|
|
|
100
105
|
pendingHostRefUpdates.length = 0;
|
|
101
106
|
const commitPath = getRootCommitPath(options);
|
|
102
107
|
if (!hasChildListMutation(finishedWork)) {
|
|
103
|
-
|
|
108
|
+
commitHostDirtyChildrenOf(finishedWork, finishedWork.child, root.container, root.container, commitPath, options);
|
|
109
|
+
committed = true;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (finishedWork.childListChanged &&
|
|
113
|
+
commitHostKeyedChildListMutationFiber(finishedWork, root.container, root.container, commitPath, options)) {
|
|
104
114
|
committed = true;
|
|
105
115
|
return;
|
|
106
116
|
}
|
|
@@ -151,6 +161,53 @@ export function commitHydratingHostFiberRoot(root, finishedWork, scope, options
|
|
|
151
161
|
scope.after?.parentNode?.removeChild(scope.after);
|
|
152
162
|
}
|
|
153
163
|
}
|
|
164
|
+
export function disposeHostFiberResources(fiber) {
|
|
165
|
+
if (fiber === undefined || fiber.hasDisposableResources !== true) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Dispose this fiber and its SUBTREE only — not its siblings. This is called
|
|
169
|
+
// once per deleted fiber, and deleted siblings are disposed by their own
|
|
170
|
+
// calls; walking siblings here re-walked the whole deleted list per deletion
|
|
171
|
+
// (O(n^2) on a cleared 1k-row reactive list). The dedupe set is allocated
|
|
172
|
+
// once for the subtree walk.
|
|
173
|
+
const seen = new Set();
|
|
174
|
+
if (fiber.tag === "reactive-dom-block") {
|
|
175
|
+
disposeReactiveDomBlockState(fiber.stateNode, seen);
|
|
176
|
+
}
|
|
177
|
+
disposeHostFiberChildResources(fiber.child, seen);
|
|
178
|
+
}
|
|
179
|
+
export function disposeUnretainedHostFiberResources(fiber, retained) {
|
|
180
|
+
if (fiber === undefined || fiber.hasDisposableResources !== true || retained.has(fiber)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const seen = new Set();
|
|
184
|
+
disposeUnretainedHostFiberSubtreeResources(fiber, seen, retained);
|
|
185
|
+
}
|
|
186
|
+
function disposeHostFiberChildResources(fiber, seen) {
|
|
187
|
+
let cursor = fiber;
|
|
188
|
+
while (cursor !== undefined) {
|
|
189
|
+
if (cursor.hasDisposableResources === true) {
|
|
190
|
+
if (cursor.tag === "reactive-dom-block") {
|
|
191
|
+
disposeReactiveDomBlockState(cursor.stateNode, seen);
|
|
192
|
+
}
|
|
193
|
+
disposeHostFiberChildResources(cursor.child, seen);
|
|
194
|
+
}
|
|
195
|
+
cursor = cursor.sibling;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function disposeUnretainedHostFiberSubtreeResources(fiber, seen, retained) {
|
|
199
|
+
if (fiber === undefined || retained.has(fiber) || fiber.hasDisposableResources !== true) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (fiber.tag === "reactive-dom-block") {
|
|
203
|
+
disposeReactiveDomBlockState(fiber.stateNode, seen);
|
|
204
|
+
}
|
|
205
|
+
let child = fiber.child;
|
|
206
|
+
while (child !== undefined) {
|
|
207
|
+
disposeUnretainedHostFiberSubtreeResources(child, seen, retained);
|
|
208
|
+
child = child.sibling;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
154
211
|
function reconcileHostChild(parent, currentFirstChild, node, runtime, path, options = {}) {
|
|
155
212
|
resetFiberRefSubtree(parent);
|
|
156
213
|
parent.subtreeFlags = NoFlags;
|
|
@@ -166,7 +223,8 @@ function reconcileHostChild(parent, currentFirstChild, node, runtime, path, opti
|
|
|
166
223
|
const children = Array.isArray(node) ? node : undefined;
|
|
167
224
|
const rowResult = children === undefined
|
|
168
225
|
? undefined
|
|
169
|
-
: reconcileKeyedRowHostChildren(parent, currentFirstChild, children, options)
|
|
226
|
+
: reconcileKeyedRowHostChildren(parent, currentFirstChild, children, options) ??
|
|
227
|
+
reconcileKeyedMemoRowHostChildren(parent, currentFirstChild, children, runtime, path, options);
|
|
170
228
|
if (rowResult !== undefined) {
|
|
171
229
|
return rowResult;
|
|
172
230
|
}
|
|
@@ -182,6 +240,7 @@ function reconcileHostChild(parent, currentFirstChild, node, runtime, path, opti
|
|
|
182
240
|
let skipRemainingKeyedLookup = false;
|
|
183
241
|
let sequentialCurrentCursor = currentFirstChild;
|
|
184
242
|
let childListOrderChanged = false;
|
|
243
|
+
let dirtyChildren;
|
|
185
244
|
let usedCurrentChildren = currentFirstChild === undefined || hasKeyedChildren ? undefined : new Set();
|
|
186
245
|
const ensureUsedCurrentChildren = () => {
|
|
187
246
|
if (usedCurrentChildren === undefined) {
|
|
@@ -224,11 +283,17 @@ function reconcileHostChild(parent, currentFirstChild, node, runtime, path, opti
|
|
|
224
283
|
else if (children !== undefined &&
|
|
225
284
|
currentKeyed?.sibling?.key === key &&
|
|
226
285
|
canSkipSingleDeletedKeyedFiber(children, index, currentKeyed.sibling)) {
|
|
286
|
+
const deleted = currentKeyed;
|
|
287
|
+
const matched = currentKeyed.sibling;
|
|
288
|
+
const suffixResult = tryReuseDependencyFreeMemoRemovalSuffix(parent, children, index, deleted, matched, runtime, options, first, previous, consumed);
|
|
289
|
+
if (suffixResult !== undefined) {
|
|
290
|
+
return suffixResult;
|
|
291
|
+
}
|
|
227
292
|
childListOrderChanged = true;
|
|
228
293
|
ensureUsedCurrentChildren();
|
|
229
|
-
matchedCurrent =
|
|
294
|
+
matchedCurrent = matched;
|
|
230
295
|
canReuseMatchedCurrentFiber = false;
|
|
231
|
-
currentKeyed =
|
|
296
|
+
currentKeyed = matched.sibling;
|
|
232
297
|
}
|
|
233
298
|
else {
|
|
234
299
|
if (children !== undefined &&
|
|
@@ -287,6 +352,13 @@ function reconcileHostChild(parent, currentFirstChild, node, runtime, path, opti
|
|
|
287
352
|
&& fiber.memoizedState === undefined) {
|
|
288
353
|
fiber.memoizedState = index;
|
|
289
354
|
}
|
|
355
|
+
else if (fiber.tag === "memo" &&
|
|
356
|
+
(fiber.stateNode === undefined || typeof fiber.stateNode === "number")) {
|
|
357
|
+
fiber.stateNode = index;
|
|
358
|
+
}
|
|
359
|
+
if (hasHostCommitWork(fiber)) {
|
|
360
|
+
(dirtyChildren ??= []).push(fiber);
|
|
361
|
+
}
|
|
290
362
|
previous = fiber;
|
|
291
363
|
}
|
|
292
364
|
if (usedCurrentChildren === undefined && hasKeyedChildren && currentKeyed !== undefined) {
|
|
@@ -297,6 +369,7 @@ function reconcileHostChild(parent, currentFirstChild, node, runtime, path, opti
|
|
|
297
369
|
}
|
|
298
370
|
parent.childListChanged =
|
|
299
371
|
childListOrderChanged || childFiberListShapeChanged(currentFirstChild, first);
|
|
372
|
+
recordDirtyChildCommitHints(parent, dirtyChildren);
|
|
300
373
|
return { fiber: first, consumed };
|
|
301
374
|
}
|
|
302
375
|
function reconcileKeyedRowHostChildren(parent, currentFirstChild, children, options) {
|
|
@@ -315,6 +388,7 @@ function reconcileKeyedRowHostChildren(parent, currentFirstChild, children, opti
|
|
|
315
388
|
let subtreeFlags = NoFlags;
|
|
316
389
|
let subtreeChildListChanged = false;
|
|
317
390
|
let hasRefSubtree = false;
|
|
391
|
+
let hasDisposableResources = false;
|
|
318
392
|
let appendSuffix;
|
|
319
393
|
const canReuseUnchangedRows = hasSameKeyOrderPrefix(currentFirstChild, children);
|
|
320
394
|
const row = createKeyedRowHostElementScratch();
|
|
@@ -375,6 +449,9 @@ function reconcileKeyedRowHostChildren(parent, currentFirstChild, children, opti
|
|
|
375
449
|
if (fiber.hasRefSubtree) {
|
|
376
450
|
hasRefSubtree = true;
|
|
377
451
|
}
|
|
452
|
+
if (fiber.hasDisposableResources) {
|
|
453
|
+
hasDisposableResources = true;
|
|
454
|
+
}
|
|
378
455
|
subtreeFlags |= fiber.flags | fiber.subtreeFlags;
|
|
379
456
|
subtreeChildListChanged =
|
|
380
457
|
subtreeChildListChanged ||
|
|
@@ -390,6 +467,7 @@ function reconcileKeyedRowHostChildren(parent, currentFirstChild, children, opti
|
|
|
390
467
|
markOptimizedChildrenForDeletion(parent, currentKeyed);
|
|
391
468
|
}
|
|
392
469
|
parent.hasRefSubtree = hasRefSubtree;
|
|
470
|
+
parent.hasDisposableResources = hasDisposableResources;
|
|
393
471
|
parent.subtreeFlags = subtreeFlags;
|
|
394
472
|
parent.subtreeChildListChanged = subtreeChildListChanged;
|
|
395
473
|
parent.childListChanged = listShapeChanged;
|
|
@@ -398,6 +476,270 @@ function reconcileKeyedRowHostChildren(parent, currentFirstChild, children, opti
|
|
|
398
476
|
}
|
|
399
477
|
return { fiber: first, consumed: 0 };
|
|
400
478
|
}
|
|
479
|
+
function isKeyedMemoRowCandidate(node) {
|
|
480
|
+
return (isReactCompatElement(node) &&
|
|
481
|
+
node.key !== null &&
|
|
482
|
+
node.ref === null &&
|
|
483
|
+
isMemoType(node.type));
|
|
484
|
+
}
|
|
485
|
+
// Marker the compiler stamps on a lowered host-only component that returns its
|
|
486
|
+
// props verbatim as a reactive block (`createReactiveDomBlock(render, props)`).
|
|
487
|
+
// Such a component is pure and structurally static, so on a props change the
|
|
488
|
+
// reconciler can drive its committed block straight through the prop cell instead
|
|
489
|
+
// of re-invoking the component (the block's bound DOM updates via subscriptions).
|
|
490
|
+
const STATIC_REACTIVE_BLOCK_MARKER = "__mreactStaticBlock";
|
|
491
|
+
function isStaticReactiveBlockComponent(type) {
|
|
492
|
+
return (typeof type === "function" &&
|
|
493
|
+
type[STATIC_REACTIVE_BLOCK_MARKER] === true);
|
|
494
|
+
}
|
|
495
|
+
// In-place bailout for a keyed memo row whose props are unchanged and which has
|
|
496
|
+
// no hook/context/effect dependencies. The caller has proven the key order is
|
|
497
|
+
// unchanged (hasSameKeyOrderPrefix), so the fiber keeps its position and can be
|
|
498
|
+
// reused WITHOUT createWorkInProgress — no allocation, and the retained subtree
|
|
499
|
+
// (including any reactive-dom-block subscriptions) is left untouched. Returns
|
|
500
|
+
// undefined when the row must re-render or has dependencies (handled by the
|
|
501
|
+
// general per-child path instead). Mirrors tryReuseDependencyFreeMemoBailout +
|
|
502
|
+
// getMemoBailoutFiber's in-place branch, but is safe to reuse a fiber with
|
|
503
|
+
// disposable resources because a stable position means nothing is disposed.
|
|
504
|
+
function tryReuseDependencyFreeKeyedMemoRow(matched, child) {
|
|
505
|
+
if (matched.tag !== "memo" ||
|
|
506
|
+
matched.type !== child.type ||
|
|
507
|
+
matched.hasRefSubtree === true ||
|
|
508
|
+
matched.hydrateExisting === true) {
|
|
509
|
+
return undefined;
|
|
510
|
+
}
|
|
511
|
+
const state = matched.memoizedState;
|
|
512
|
+
if (state === undefined ||
|
|
513
|
+
state.hasDirtyInstanceDependencies !== false ||
|
|
514
|
+
state.hasUnflushedEffectDependencies !== false ||
|
|
515
|
+
state.hasRetainedInstanceDependencies !== false ||
|
|
516
|
+
!areMemoPropsEqual(child.type, state.props, child.props)) {
|
|
517
|
+
return undefined;
|
|
518
|
+
}
|
|
519
|
+
matched.pendingProps = child.props;
|
|
520
|
+
matched.flags = NoFlags;
|
|
521
|
+
matched.subtreeFlags = NoFlags;
|
|
522
|
+
matched.childListChanged = false;
|
|
523
|
+
matched.subtreeChildListChanged = false;
|
|
524
|
+
matched.hostChildListChanged = false;
|
|
525
|
+
matched.child = getSkippedChild(matched);
|
|
526
|
+
return matched;
|
|
527
|
+
}
|
|
528
|
+
// In-place CHANGED-row update for a keyed memo row whose inner component is a
|
|
529
|
+
// compiler-marked static reactive block (returns its props verbatim as the block
|
|
530
|
+
// props). Instead of re-invoking the component to rebuild a throwaway block
|
|
531
|
+
// element, push the new props straight into the committed block's prop cell — the
|
|
532
|
+
// bound DOM updates via subscriptions, exactly as the normal block re-render path
|
|
533
|
+
// would, but without the memo/component render machinery. Same-order is proven by
|
|
534
|
+
// the caller, so the fiber is reused in place. Returns undefined when this is not
|
|
535
|
+
// a marked, dependency-free, single-block memo row (the general path handles it).
|
|
536
|
+
function tryCellUpdateStaticBlockMemoRow(matched, child) {
|
|
537
|
+
if (matched.tag !== "memo" ||
|
|
538
|
+
matched.type !== child.type ||
|
|
539
|
+
matched.hasRefSubtree === true ||
|
|
540
|
+
matched.hydrateExisting === true ||
|
|
541
|
+
!isStaticReactiveBlockComponent(matched.type.type)) {
|
|
542
|
+
return undefined;
|
|
543
|
+
}
|
|
544
|
+
const state = matched.memoizedState;
|
|
545
|
+
if (state === undefined ||
|
|
546
|
+
state.hasDirtyInstanceDependencies !== false ||
|
|
547
|
+
state.hasUnflushedEffectDependencies !== false ||
|
|
548
|
+
state.hasRetainedInstanceDependencies !== false) {
|
|
549
|
+
return undefined;
|
|
550
|
+
}
|
|
551
|
+
// Navigate memo -> component fiber -> reactive-dom-block fiber. The marked
|
|
552
|
+
// component renders exactly one static block, so anything else is unexpected.
|
|
553
|
+
const componentFiber = matched.child;
|
|
554
|
+
if (componentFiber === undefined || componentFiber.sibling !== undefined) {
|
|
555
|
+
return undefined;
|
|
556
|
+
}
|
|
557
|
+
const blockFiber = componentFiber.child;
|
|
558
|
+
if (blockFiber === undefined ||
|
|
559
|
+
blockFiber.tag !== "reactive-dom-block" ||
|
|
560
|
+
blockFiber.sibling !== undefined) {
|
|
561
|
+
return undefined;
|
|
562
|
+
}
|
|
563
|
+
const blockState = blockFiber.stateNode;
|
|
564
|
+
if (blockState?.propCell === undefined) {
|
|
565
|
+
return undefined;
|
|
566
|
+
}
|
|
567
|
+
// Drive the bound DOM through the prop cell (the marker guarantees the block's
|
|
568
|
+
// props are the component's props verbatim), then reuse the memo fiber in place.
|
|
569
|
+
setReactivePropCell(blockState.propCell, child.props);
|
|
570
|
+
matched.memoizedState = { ...state, props: child.props };
|
|
571
|
+
matched.pendingProps = child.props;
|
|
572
|
+
matched.flags = NoFlags;
|
|
573
|
+
matched.subtreeFlags = NoFlags;
|
|
574
|
+
matched.childListChanged = false;
|
|
575
|
+
matched.subtreeChildListChanged = false;
|
|
576
|
+
matched.hostChildListChanged = false;
|
|
577
|
+
matched.child = getSkippedChild(matched);
|
|
578
|
+
return matched;
|
|
579
|
+
}
|
|
580
|
+
// Fast path for a keyed list of memo-wrapped rows (e.g. `<RowMemo key={id} />`)
|
|
581
|
+
// whose key order is UNCHANGED between renders — the js-framework-benchmark
|
|
582
|
+
// "select row" and "partial update" shapes. Walks current fibers and new
|
|
583
|
+
// children in lockstep: unchanged rows bail in place (no allocation, no general
|
|
584
|
+
// keyed-reconcile machinery), changed rows re-render through the proven
|
|
585
|
+
// per-child path. Any reorder / insert / delete / non-memo child / length change
|
|
586
|
+
// makes it return undefined so the general reconcile takes over.
|
|
587
|
+
function reconcileKeyedMemoRowHostChildren(parent, currentFirstChild, children, runtime, path, options) {
|
|
588
|
+
if (children.length === 0 ||
|
|
589
|
+
currentFirstChild === undefined ||
|
|
590
|
+
runtime === undefined ||
|
|
591
|
+
options.previousNodes !== undefined ||
|
|
592
|
+
!isKeyedMemoRowCandidate(children[0]) ||
|
|
593
|
+
!hasSameKeyOrderPrefix(currentFirstChild, children)) {
|
|
594
|
+
return undefined;
|
|
595
|
+
}
|
|
596
|
+
let currentKeyed = currentFirstChild;
|
|
597
|
+
let first;
|
|
598
|
+
let previous;
|
|
599
|
+
let subtreeFlags = NoFlags;
|
|
600
|
+
let subtreeChildListChanged = false;
|
|
601
|
+
let hasRefSubtree = false;
|
|
602
|
+
let hasDisposableResources = false;
|
|
603
|
+
let dirtyChildren;
|
|
604
|
+
for (let index = 0; index < children.length; index += 1) {
|
|
605
|
+
const child = children[index];
|
|
606
|
+
if (currentKeyed === undefined || !isKeyedMemoRowCandidate(child)) {
|
|
607
|
+
return undefined;
|
|
608
|
+
}
|
|
609
|
+
const matched = currentKeyed;
|
|
610
|
+
currentKeyed = currentKeyed.sibling;
|
|
611
|
+
const childElement = child;
|
|
612
|
+
let fiber = tryReuseDependencyFreeKeyedMemoRow(matched, childElement) ??
|
|
613
|
+
tryCellUpdateStaticBlockMemoRow(matched, childElement);
|
|
614
|
+
if (fiber === undefined) {
|
|
615
|
+
const result = createHostFiber(parent, matched, child, childElement.key ?? undefined, runtime, getReconcileChildPath(path, child, index, options), options, false);
|
|
616
|
+
fiber = result.fiber;
|
|
617
|
+
if (fiber === undefined) {
|
|
618
|
+
return undefined;
|
|
619
|
+
}
|
|
620
|
+
if (fiber !== matched && fiber.alternate !== matched) {
|
|
621
|
+
markOptimizedChildForDeletion(parent, matched);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if (first === undefined) {
|
|
625
|
+
first = fiber;
|
|
626
|
+
}
|
|
627
|
+
else if (previous !== undefined) {
|
|
628
|
+
previous.sibling = fiber;
|
|
629
|
+
}
|
|
630
|
+
fiber.return = parent;
|
|
631
|
+
fiber.sibling = undefined;
|
|
632
|
+
if (fiber.hasRefSubtree) {
|
|
633
|
+
hasRefSubtree = true;
|
|
634
|
+
}
|
|
635
|
+
if (fiber.hasDisposableResources) {
|
|
636
|
+
hasDisposableResources = true;
|
|
637
|
+
}
|
|
638
|
+
subtreeFlags |= fiber.flags | fiber.subtreeFlags;
|
|
639
|
+
subtreeChildListChanged =
|
|
640
|
+
subtreeChildListChanged || fiber.childListChanged || fiber.subtreeChildListChanged;
|
|
641
|
+
if (fiber.tag === "memo" &&
|
|
642
|
+
(fiber.stateNode === undefined || typeof fiber.stateNode === "number")) {
|
|
643
|
+
fiber.stateNode = index;
|
|
644
|
+
}
|
|
645
|
+
if (hasHostCommitWork(fiber)) {
|
|
646
|
+
(dirtyChildren ??= []).push(fiber);
|
|
647
|
+
}
|
|
648
|
+
previous = fiber;
|
|
649
|
+
}
|
|
650
|
+
if (currentKeyed !== undefined) {
|
|
651
|
+
return undefined;
|
|
652
|
+
}
|
|
653
|
+
parent.hasRefSubtree = hasRefSubtree;
|
|
654
|
+
parent.hasDisposableResources = hasDisposableResources;
|
|
655
|
+
parent.subtreeFlags = subtreeFlags;
|
|
656
|
+
parent.subtreeChildListChanged = subtreeChildListChanged;
|
|
657
|
+
parent.childListChanged = false;
|
|
658
|
+
recordDirtyChildCommitHints(parent, dirtyChildren);
|
|
659
|
+
return { fiber: first, consumed: 0 };
|
|
660
|
+
}
|
|
661
|
+
function canReuseDependencyFreeMemoAtKey(current, node, key) {
|
|
662
|
+
return (current !== undefined &&
|
|
663
|
+
current.key === key &&
|
|
664
|
+
current.tag === "memo" &&
|
|
665
|
+
current.type === node.type &&
|
|
666
|
+
current.hasRefSubtree !== true &&
|
|
667
|
+
current.hasDisposableResources !== true &&
|
|
668
|
+
current.hydrateExisting !== true &&
|
|
669
|
+
isMemoType(node.type));
|
|
670
|
+
}
|
|
671
|
+
function tryReuseDependencyFreeMemoRemovalSuffix(parent, children, startIndex, removed, matchedCurrent, runtime, options, prefixFirst, prefixPrevious, consumed) {
|
|
672
|
+
if (runtime === undefined ||
|
|
673
|
+
options.previousNodes !== undefined ||
|
|
674
|
+
removed.hasRefSubtree) {
|
|
675
|
+
return undefined;
|
|
676
|
+
}
|
|
677
|
+
const suffix = [];
|
|
678
|
+
let current = matchedCurrent;
|
|
679
|
+
for (let index = startIndex; index < children.length; index += 1) {
|
|
680
|
+
const child = children[index];
|
|
681
|
+
const key = getNodeKey(child);
|
|
682
|
+
if (key === undefined || !isReactCompatElement(child) || !isMemoType(child.type)) {
|
|
683
|
+
return undefined;
|
|
684
|
+
}
|
|
685
|
+
if (!canReuseDependencyFreeMemoAtKey(current, child, key)) {
|
|
686
|
+
return undefined;
|
|
687
|
+
}
|
|
688
|
+
if (current === undefined) {
|
|
689
|
+
return undefined;
|
|
690
|
+
}
|
|
691
|
+
const matched = current;
|
|
692
|
+
const fiber = reuseDependencyFreeMemoFiber(matched, child);
|
|
693
|
+
if (fiber === undefined) {
|
|
694
|
+
return undefined;
|
|
695
|
+
}
|
|
696
|
+
suffix.push(fiber);
|
|
697
|
+
current = matched.sibling;
|
|
698
|
+
}
|
|
699
|
+
if (current !== undefined) {
|
|
700
|
+
return undefined;
|
|
701
|
+
}
|
|
702
|
+
let first = prefixFirst;
|
|
703
|
+
let previous = prefixPrevious;
|
|
704
|
+
for (const fiber of suffix) {
|
|
705
|
+
if (first === undefined) {
|
|
706
|
+
first = fiber;
|
|
707
|
+
}
|
|
708
|
+
else if (previous !== undefined) {
|
|
709
|
+
previous.sibling = fiber;
|
|
710
|
+
}
|
|
711
|
+
fiber.return = parent;
|
|
712
|
+
fiber.sibling = undefined;
|
|
713
|
+
previous = fiber;
|
|
714
|
+
}
|
|
715
|
+
parent.childListChanged = true;
|
|
716
|
+
parent.deletions = [removed];
|
|
717
|
+
markOptimizedChildForDeletion(parent, removed);
|
|
718
|
+
return { fiber: first, consumed };
|
|
719
|
+
}
|
|
720
|
+
function reuseDependencyFreeMemoFiber(current, node) {
|
|
721
|
+
if (!isMemoType(node.type)) {
|
|
722
|
+
return undefined;
|
|
723
|
+
}
|
|
724
|
+
const previousMemoState = current.memoizedState;
|
|
725
|
+
if (previousMemoState === undefined ||
|
|
726
|
+
previousMemoState.hasDirtyInstanceDependencies !== false ||
|
|
727
|
+
previousMemoState.hasUnflushedEffectDependencies !== false ||
|
|
728
|
+
previousMemoState.hasRetainedInstanceDependencies !== false ||
|
|
729
|
+
!areMemoPropsEqual(node.type, previousMemoState.props, node.props)) {
|
|
730
|
+
return undefined;
|
|
731
|
+
}
|
|
732
|
+
current.pendingProps = node.props;
|
|
733
|
+
current.flags = NoFlags;
|
|
734
|
+
current.subtreeFlags = NoFlags;
|
|
735
|
+
current.childListChanged = false;
|
|
736
|
+
current.subtreeChildListChanged = false;
|
|
737
|
+
current.hostChildListChanged = false;
|
|
738
|
+
current.type = node.type;
|
|
739
|
+
current.child = getSkippedChild(current);
|
|
740
|
+
current.memoizedState = previousMemoState;
|
|
741
|
+
return current;
|
|
742
|
+
}
|
|
401
743
|
function canStoreAppendSuffixCommitHint(parent) {
|
|
402
744
|
return (parent.tag === "fragment" ||
|
|
403
745
|
parent.tag === "host-component" ||
|
|
@@ -459,6 +801,7 @@ function getReusableKeyedRowHostFiber(current, row) {
|
|
|
459
801
|
current.subtreeChildListChanged = false;
|
|
460
802
|
current.hostChildListChanged = false;
|
|
461
803
|
current.hasRefSubtree = false;
|
|
804
|
+
current.hasDisposableResources = false;
|
|
462
805
|
return current;
|
|
463
806
|
}
|
|
464
807
|
function createKeyedRowHostElementScratch() {
|
|
@@ -512,6 +855,7 @@ function createKeyedRowHostFiber(parent, current, row, options) {
|
|
|
512
855
|
fiber.pendingProps = node.props;
|
|
513
856
|
fiber.hostChildListChanged = false;
|
|
514
857
|
fiber.hasRefSubtree = false;
|
|
858
|
+
fiber.hasDisposableResources = false;
|
|
515
859
|
if (current === undefined || fiber.alternate !== current) {
|
|
516
860
|
fiber.flags |= Placement;
|
|
517
861
|
fiber.hostChildListChanged = true;
|
|
@@ -617,14 +961,25 @@ function bubbleHostChild(parent, child) {
|
|
|
617
961
|
if (child.hasRefSubtree) {
|
|
618
962
|
parent.hasRefSubtree = true;
|
|
619
963
|
}
|
|
964
|
+
if (child.hasDisposableResources) {
|
|
965
|
+
parent.hasDisposableResources = true;
|
|
966
|
+
}
|
|
620
967
|
parent.subtreeFlags |= child.flags | child.subtreeFlags;
|
|
621
968
|
parent.subtreeChildListChanged =
|
|
622
969
|
parent.subtreeChildListChanged ||
|
|
623
970
|
child.childListChanged ||
|
|
624
971
|
child.subtreeChildListChanged;
|
|
625
972
|
}
|
|
973
|
+
function recordDirtyChildCommitHints(parent, dirtyChildren) {
|
|
974
|
+
if (parent.childListChanged || dirtyChildren === undefined || dirtyChildren.length === 0) {
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
// Reuse the effect-list slot only when there are no child-list deletions.
|
|
978
|
+
parent.deletions = dirtyChildren;
|
|
979
|
+
}
|
|
626
980
|
function resetFiberRefSubtree(fiber) {
|
|
627
981
|
fiber.hasRefSubtree = false;
|
|
982
|
+
fiber.hasDisposableResources = false;
|
|
628
983
|
}
|
|
629
984
|
function includeNodeRef(fiber, node) {
|
|
630
985
|
fiber.hasRefSubtree =
|
|
@@ -722,6 +1077,12 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
722
1077
|
}
|
|
723
1078
|
return { fiber: undefined, consumed: 0 };
|
|
724
1079
|
}
|
|
1080
|
+
// Host elements (string type) are by far the most common node. Dispatch them
|
|
1081
|
+
// before the component-type checks below, none of which a string can match,
|
|
1082
|
+
// so each reconciled host element skips ~12 type comparisons / probes.
|
|
1083
|
+
if (typeof node.type === "string") {
|
|
1084
|
+
return createHostComponentFiber(parent, current, node, key, runtime, path, options);
|
|
1085
|
+
}
|
|
725
1086
|
if (node.type === Fragment) {
|
|
726
1087
|
const fiber = current?.tag === "fragment"
|
|
727
1088
|
? createWorkInProgress(current, node.props.children)
|
|
@@ -790,6 +1151,36 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
790
1151
|
}
|
|
791
1152
|
return { fiber, consumed: options.previousNodes?.length ?? 0 };
|
|
792
1153
|
}
|
|
1154
|
+
if (node.type === REACTIVE_DOM_BLOCK_TYPE) {
|
|
1155
|
+
const blockProps = node.props.blockProps;
|
|
1156
|
+
if (current?.tag === "reactive-dom-block") {
|
|
1157
|
+
// Re-render: reuse the committed DOM/subscriptions and push the new props
|
|
1158
|
+
// into the prop cell instead of re-running render(). Bound text/attributes
|
|
1159
|
+
// update via their reactive subscriptions; the subtree is never reconciled.
|
|
1160
|
+
const fiber = createWorkInProgress(current, node.props);
|
|
1161
|
+
fiber.type = node.type;
|
|
1162
|
+
fiber.hasDisposableResources = true;
|
|
1163
|
+
const previousState = current.stateNode;
|
|
1164
|
+
if (previousState?.propCell !== undefined && blockProps !== undefined) {
|
|
1165
|
+
setReactivePropCell(previousState.propCell, blockProps);
|
|
1166
|
+
}
|
|
1167
|
+
fiber.stateNode = previousState;
|
|
1168
|
+
return { fiber, consumed: options.previousNodes?.length ?? 0 };
|
|
1169
|
+
}
|
|
1170
|
+
const fiber = createFiber("reactive-dom-block", node.props, key);
|
|
1171
|
+
fiber.type = node.type;
|
|
1172
|
+
fiber.hasDisposableResources = true;
|
|
1173
|
+
const render = node.props.render;
|
|
1174
|
+
if (blockProps !== undefined) {
|
|
1175
|
+
const propCell = createReactivePropCell(blockProps);
|
|
1176
|
+
const result = render(createReactivePropProxy(propCell));
|
|
1177
|
+
fiber.stateNode = { node: result.node, dispose: result.dispose, propCell };
|
|
1178
|
+
}
|
|
1179
|
+
else {
|
|
1180
|
+
fiber.stateNode = render();
|
|
1181
|
+
}
|
|
1182
|
+
return { fiber, consumed: options.previousNodes?.length ?? 0 };
|
|
1183
|
+
}
|
|
793
1184
|
if (isReactCompatProvider(node.type)) {
|
|
794
1185
|
const fiber = current?.tag === "context-provider" && current.type === node.type
|
|
795
1186
|
? createWorkInProgress(current, node.props)
|
|
@@ -858,8 +1249,11 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
858
1249
|
: createFiber("memo", node.props, key);
|
|
859
1250
|
fiber.type = memoType;
|
|
860
1251
|
const renderedElement = {
|
|
861
|
-
|
|
1252
|
+
$$typeof: node.$$typeof,
|
|
862
1253
|
type: memoType.type,
|
|
1254
|
+
key: node.key,
|
|
1255
|
+
ref: node.ref,
|
|
1256
|
+
props: node.props,
|
|
863
1257
|
};
|
|
864
1258
|
const childResult = createHostFiber(fiber, current?.tag === "memo" ? current.child : undefined, renderedElement, key, runtime, memoPath, options);
|
|
865
1259
|
fiber.child = childResult.fiber;
|
|
@@ -868,7 +1262,7 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
868
1262
|
fiber.child.sibling = undefined;
|
|
869
1263
|
bubbleHostChild(fiber, fiber.child);
|
|
870
1264
|
}
|
|
871
|
-
const instanceKeys =
|
|
1265
|
+
const instanceKeys = collectMemoInstanceKeys(runtime, memoPath);
|
|
872
1266
|
const hasClassDescendant = hasClassComponentDescendant(fiber.child);
|
|
873
1267
|
fiber.memoizedState = {
|
|
874
1268
|
props: node.props,
|
|
@@ -890,8 +1284,11 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
890
1284
|
fiber.type = lazyType;
|
|
891
1285
|
if (lazyType.status === "resolved" && lazyType.resolved !== undefined) {
|
|
892
1286
|
const renderedElement = {
|
|
893
|
-
|
|
1287
|
+
$$typeof: node.$$typeof,
|
|
894
1288
|
type: lazyType.resolved,
|
|
1289
|
+
key: node.key,
|
|
1290
|
+
ref: node.ref,
|
|
1291
|
+
props: node.props,
|
|
895
1292
|
};
|
|
896
1293
|
const childResult = createHostFiber(fiber, current?.tag === "lazy" ? current.child : undefined, renderedElement, key, runtime, `${path}.lazy`, options);
|
|
897
1294
|
fiber.child = childResult.fiber;
|
|
@@ -1006,45 +1403,64 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
1006
1403
|
const instanceKeys = collectInstanceKeys(runtime, path);
|
|
1007
1404
|
fiber.stateNode = {
|
|
1008
1405
|
element: node,
|
|
1009
|
-
props:
|
|
1406
|
+
props: node.props,
|
|
1010
1407
|
instanceKeys,
|
|
1011
1408
|
hasContextDependencies: hasContextDependency(runtime, instanceKeys),
|
|
1012
1409
|
};
|
|
1013
1410
|
return { fiber, consumed: childResult.consumed };
|
|
1014
1411
|
}
|
|
1412
|
+
return { fiber: undefined, consumed: 0 };
|
|
1413
|
+
}
|
|
1414
|
+
// The host-component reconcile, split out of createHostFiberImpl so host
|
|
1415
|
+
// elements can be dispatched before the component-type checks. Only called with
|
|
1416
|
+
// a string element type.
|
|
1417
|
+
function createHostComponentFiber(parent, current, node, key, runtime, path, options) {
|
|
1015
1418
|
if (typeof node.type !== "string") {
|
|
1016
1419
|
return { fiber: undefined, consumed: 0 };
|
|
1017
1420
|
}
|
|
1421
|
+
const initialHostOnlyFiber = tryCreateInitialHostOnlyFiber(current, node, key, options);
|
|
1422
|
+
if (initialHostOnlyFiber !== undefined) {
|
|
1423
|
+
return { fiber: initialHostOnlyFiber, consumed: 0 };
|
|
1424
|
+
}
|
|
1018
1425
|
const elementNamespace = namespaceForHostElement(options.namespace ?? "html", node.type);
|
|
1019
1426
|
const childNamespace = namespaceForHostChildren(elementNamespace, node.type);
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1427
|
+
const reusableCurrent = current?.tag === "host-component" && current.type === node.type ? current : undefined;
|
|
1428
|
+
const fiber = reusableCurrent !== undefined
|
|
1429
|
+
? createWorkInProgress(reusableCurrent, node.props)
|
|
1022
1430
|
: createFiber("host-component", node.props, key);
|
|
1431
|
+
// The hydration node bookkeeping only matters when hydrating. Skipping it for
|
|
1432
|
+
// the common (non-hydration) render avoids an isHostElement(undefined) probe
|
|
1433
|
+
// and the mismatch checks on every reconciled element.
|
|
1023
1434
|
const existing = options.previousNodes?.[0];
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1435
|
+
let existingElement;
|
|
1436
|
+
let tagMatches = false;
|
|
1437
|
+
if (options.previousNodes !== undefined) {
|
|
1438
|
+
existingElement = isHostElement(existing) ? existing : undefined;
|
|
1439
|
+
tagMatches =
|
|
1440
|
+
existingElement !== undefined &&
|
|
1441
|
+
hostElementMatches(existingElement, node.type, elementNamespace);
|
|
1442
|
+
if (existing === undefined) {
|
|
1443
|
+
reportMissingHydrationNode(options, path);
|
|
1444
|
+
}
|
|
1445
|
+
else if (!isHostElement(existing)) {
|
|
1446
|
+
reportHydrationNodeTypeMismatch(options, path, `<${node.type}>`, existing);
|
|
1447
|
+
}
|
|
1448
|
+
if (existingElement !== undefined && !tagMatches) {
|
|
1449
|
+
reportRecoverable(options, "tag", path, new Error(`Hydration tag mismatch: expected <${node.type}> but found <${existingElement.tagName.toLowerCase()}>.`));
|
|
1450
|
+
reportElementTextMismatch(options, `${path}.c`, existingElement, node.props.children);
|
|
1451
|
+
}
|
|
1036
1452
|
}
|
|
1037
1453
|
fiber.type = node.type;
|
|
1454
|
+
// When reusing a same-type current fiber, its stateNode was created for this
|
|
1455
|
+
// exact tag and namespace (same tree position), so the hostElementMatches
|
|
1456
|
+
// re-check (localName + namespaceURI reads) is redundant.
|
|
1038
1457
|
fiber.stateNode =
|
|
1039
1458
|
tagMatches
|
|
1040
1459
|
? existingElement
|
|
1041
|
-
:
|
|
1042
|
-
|
|
1043
|
-
isHostElement(current.stateNode) &&
|
|
1044
|
-
hostElementMatches(current.stateNode, node.type, elementNamespace)
|
|
1045
|
-
? current.stateNode
|
|
1460
|
+
: reusableCurrent !== undefined && isHostElement(reusableCurrent.stateNode)
|
|
1461
|
+
? reusableCurrent.stateNode
|
|
1046
1462
|
: createHostElement(getDocumentRef(options), node.type, options.namespace ?? "html");
|
|
1047
|
-
fiber.hydrateExisting = tagMatches
|
|
1463
|
+
fiber.hydrateExisting = tagMatches;
|
|
1048
1464
|
const previousChildNodes = tagMatches && existingElement !== undefined
|
|
1049
1465
|
? Array.from(existingElement.childNodes)
|
|
1050
1466
|
: undefined;
|
|
@@ -1069,11 +1485,7 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
1069
1485
|
parent.child ??= fiber;
|
|
1070
1486
|
return { fiber, consumed: existing === undefined ? 0 : 1 };
|
|
1071
1487
|
}
|
|
1072
|
-
const childResult = reconcileHostChild(fiber, current?.tag === "host-component" ? current.child : undefined, node.props.children, runtime, `${path}.c`,
|
|
1073
|
-
...options,
|
|
1074
|
-
namespace: childNamespace,
|
|
1075
|
-
...(previousChildNodes === undefined ? {} : { previousNodes: previousChildNodes }),
|
|
1076
|
-
});
|
|
1488
|
+
const childResult = reconcileHostChild(fiber, current?.tag === "host-component" ? current.child : undefined, node.props.children, runtime, `${path}.c`, getHostChildFiberOptions(options, childNamespace, previousChildNodes));
|
|
1077
1489
|
fiber.child = childResult.fiber;
|
|
1078
1490
|
if (previousChildNodes !== undefined) {
|
|
1079
1491
|
reportExtraHydrationNodes(options, `${path}.c`, previousChildNodes, childResult.consumed);
|
|
@@ -1086,6 +1498,114 @@ function isFunctionComponentType(value) {
|
|
|
1086
1498
|
typeof value.prototype?.render !==
|
|
1087
1499
|
"function");
|
|
1088
1500
|
}
|
|
1501
|
+
function tryCreateInitialHostOnlyFiber(current, node, key, options) {
|
|
1502
|
+
if (current !== undefined ||
|
|
1503
|
+
options.previousNodes !== undefined ||
|
|
1504
|
+
!shouldUseDirectHostTextChild() ||
|
|
1505
|
+
typeof node.type !== "string" ||
|
|
1506
|
+
!canCreateInitialHostOnlyNode(node)) {
|
|
1507
|
+
return undefined;
|
|
1508
|
+
}
|
|
1509
|
+
return createInitialHostOnlyElementFiber(node, key, options.namespace ?? "html", getDocumentRef(options));
|
|
1510
|
+
}
|
|
1511
|
+
function createInitialHostOnlyElementFiber(node, key, namespace, documentRef) {
|
|
1512
|
+
const elementType = node.type;
|
|
1513
|
+
const elementNamespace = namespaceForHostElement(namespace, elementType);
|
|
1514
|
+
const childNamespace = namespaceForHostChildren(elementNamespace, elementType);
|
|
1515
|
+
const fiber = createFiber("host-component", node.props, key);
|
|
1516
|
+
fiber.type = elementType;
|
|
1517
|
+
fiber.stateNode = createHostElement(documentRef, elementType, namespace);
|
|
1518
|
+
fiber.flags |= Placement;
|
|
1519
|
+
fiber.hostChildListChanged = true;
|
|
1520
|
+
if (getDirectHostTextChild(node.props.children) === undefined) {
|
|
1521
|
+
fiber.child = createInitialHostOnlyChildList(fiber, node.props.children, childNamespace, documentRef);
|
|
1522
|
+
}
|
|
1523
|
+
return fiber;
|
|
1524
|
+
}
|
|
1525
|
+
function createInitialHostOnlyChildList(parent, children, namespace, documentRef) {
|
|
1526
|
+
const normalized = normalizeChildren(children);
|
|
1527
|
+
let first;
|
|
1528
|
+
let previous;
|
|
1529
|
+
for (let index = 0; index < normalized.length; index += 1) {
|
|
1530
|
+
const child = normalized[index];
|
|
1531
|
+
const fiber = createInitialHostOnlyChildFiber(child, namespace, documentRef);
|
|
1532
|
+
if (fiber === undefined) {
|
|
1533
|
+
continue;
|
|
1534
|
+
}
|
|
1535
|
+
fiber.return = parent;
|
|
1536
|
+
fiber.memoizedState = index;
|
|
1537
|
+
if (first === undefined) {
|
|
1538
|
+
first = fiber;
|
|
1539
|
+
}
|
|
1540
|
+
else if (previous !== undefined) {
|
|
1541
|
+
previous.sibling = fiber;
|
|
1542
|
+
}
|
|
1543
|
+
bubbleHostChild(parent, fiber);
|
|
1544
|
+
previous = fiber;
|
|
1545
|
+
}
|
|
1546
|
+
return first;
|
|
1547
|
+
}
|
|
1548
|
+
function createInitialHostOnlyChildFiber(node, namespace, documentRef) {
|
|
1549
|
+
if (node === null || node === undefined || typeof node === "boolean") {
|
|
1550
|
+
return undefined;
|
|
1551
|
+
}
|
|
1552
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
1553
|
+
const fiber = createFiber("host-text", String(node));
|
|
1554
|
+
fiber.stateNode = createHostTextNode(documentRef);
|
|
1555
|
+
fiber.flags |= Placement;
|
|
1556
|
+
return fiber;
|
|
1557
|
+
}
|
|
1558
|
+
if (Array.isArray(node)) {
|
|
1559
|
+
const fiber = createFiber("fragment", node);
|
|
1560
|
+
fiber.child = createInitialHostOnlyChildList(fiber, node, namespace, documentRef);
|
|
1561
|
+
return fiber.child === undefined ? undefined : fiber;
|
|
1562
|
+
}
|
|
1563
|
+
if (!isReactCompatElement(node) || typeof node.type !== "string") {
|
|
1564
|
+
return undefined;
|
|
1565
|
+
}
|
|
1566
|
+
return createInitialHostOnlyElementFiber(node, node.key === null ? undefined : node.key, namespace, documentRef);
|
|
1567
|
+
}
|
|
1568
|
+
function canCreateInitialHostOnlyNode(node) {
|
|
1569
|
+
if (node === null ||
|
|
1570
|
+
node === undefined ||
|
|
1571
|
+
typeof node === "boolean" ||
|
|
1572
|
+
typeof node === "string" ||
|
|
1573
|
+
typeof node === "number") {
|
|
1574
|
+
return true;
|
|
1575
|
+
}
|
|
1576
|
+
if (Array.isArray(node)) {
|
|
1577
|
+
return node.every(canCreateInitialHostOnlyNode);
|
|
1578
|
+
}
|
|
1579
|
+
if (!isReactCompatElement(node) ||
|
|
1580
|
+
typeof node.type !== "string" ||
|
|
1581
|
+
node.ref !== null ||
|
|
1582
|
+
hasInitialHostOnlyExcludedProps(node.props)) {
|
|
1583
|
+
return false;
|
|
1584
|
+
}
|
|
1585
|
+
return canCreateInitialHostOnlyNode(node.props.children);
|
|
1586
|
+
}
|
|
1587
|
+
function hasInitialHostOnlyExcludedProps(props) {
|
|
1588
|
+
return (hasOwnProperty.call(props, REACTIVE_TEXT_BINDING_META) ||
|
|
1589
|
+
props.dangerouslySetInnerHTML !== undefined ||
|
|
1590
|
+
props.contentEditable === true ||
|
|
1591
|
+
props.suppressContentEditableWarning === true ||
|
|
1592
|
+
props.value !== undefined ||
|
|
1593
|
+
props.defaultValue !== undefined ||
|
|
1594
|
+
props.checked !== undefined ||
|
|
1595
|
+
props.defaultChecked !== undefined);
|
|
1596
|
+
}
|
|
1597
|
+
function getHostChildFiberOptions(options, namespace, previousNodes) {
|
|
1598
|
+
const namespaceUnchanged = options.namespace === namespace ||
|
|
1599
|
+
(options.namespace === undefined && namespace === "html");
|
|
1600
|
+
if (previousNodes === undefined && namespaceUnchanged) {
|
|
1601
|
+
return options;
|
|
1602
|
+
}
|
|
1603
|
+
return {
|
|
1604
|
+
...options,
|
|
1605
|
+
namespace,
|
|
1606
|
+
...(previousNodes === undefined ? {} : { previousNodes }),
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1089
1609
|
function commitHostChildren(fiber, parent, eventRoot, path, options = {}) {
|
|
1090
1610
|
const nodes = [];
|
|
1091
1611
|
let cursor = fiber;
|
|
@@ -1110,6 +1630,29 @@ function commitHostDirtyChildren(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1110
1630
|
index += 1;
|
|
1111
1631
|
}
|
|
1112
1632
|
}
|
|
1633
|
+
function commitHostDirtyChildrenOf(owner, fiber, parent, eventRoot, path, options = {}) {
|
|
1634
|
+
const dirtyChildren = readDirtyChildCommitHints(owner);
|
|
1635
|
+
if (dirtyChildren === undefined) {
|
|
1636
|
+
commitHostDirtyChildren(fiber, parent, eventRoot, path, options);
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
for (let index = 0; index < dirtyChildren.length; index += 1) {
|
|
1640
|
+
const dirtyChild = dirtyChildren[index];
|
|
1641
|
+
if (dirtyChild !== undefined && hasHostCommitWork(dirtyChild)) {
|
|
1642
|
+
commitHostDirtyFiber(dirtyChild, parent, eventRoot, joinCommitPath(path, String(getDirtyChildCommitIndex(dirtyChild, index))), options);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
owner.deletions = undefined;
|
|
1646
|
+
}
|
|
1647
|
+
function readDirtyChildCommitHints(fiber) {
|
|
1648
|
+
return fiber.childListChanged ? undefined : fiber.deletions;
|
|
1649
|
+
}
|
|
1650
|
+
function getDirtyChildCommitIndex(fiber, fallback) {
|
|
1651
|
+
if (typeof fiber.memoizedState === "number") {
|
|
1652
|
+
return fiber.memoizedState;
|
|
1653
|
+
}
|
|
1654
|
+
return typeof fiber.stateNode === "number" ? fiber.stateNode : fallback;
|
|
1655
|
+
}
|
|
1113
1656
|
function commitHostDirtyFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
1114
1657
|
if (fiber.tag === "host-text") {
|
|
1115
1658
|
commitHostFiber(fiber, parent, eventRoot, path, options);
|
|
@@ -1121,6 +1664,7 @@ function commitHostDirtyFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1121
1664
|
finishCommittedFiber(fiber);
|
|
1122
1665
|
return;
|
|
1123
1666
|
}
|
|
1667
|
+
const isDomElement = isDomHostElement(element);
|
|
1124
1668
|
const props = fiber.pendingProps;
|
|
1125
1669
|
const previousProps = fiber.memoizedProps;
|
|
1126
1670
|
const directTextChild = fiber.child === undefined && fiber.hydrateExisting !== true
|
|
@@ -1140,7 +1684,7 @@ function commitHostDirtyFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1140
1684
|
!propsAreChildrenOnly &&
|
|
1141
1685
|
fiber.hydrateExisting !== true &&
|
|
1142
1686
|
isRowTextOnlyUpdate(fiber.memoizedProps, props);
|
|
1143
|
-
if (
|
|
1687
|
+
if (isDomElement && !propsAreUnchanged && !propsAreChildrenOnly && !textOnlyRowUpdate) {
|
|
1144
1688
|
applyProps(element, props, path, {
|
|
1145
1689
|
...options,
|
|
1146
1690
|
eventRoot,
|
|
@@ -1155,15 +1699,15 @@ function commitHostDirtyFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1155
1699
|
fiber.childListChanged ||
|
|
1156
1700
|
fiber.subtreeChildListChanged) {
|
|
1157
1701
|
const childNodes = commitHostChildren(fiber.child, element, eventRoot, `${path}.c`, options);
|
|
1158
|
-
if (!(
|
|
1159
|
-
!(
|
|
1702
|
+
if (!(isDomElement && childNodes.length === 0 && committedPortalContainers.has(element)) &&
|
|
1703
|
+
!(isDomElement && shouldPreserveContentEditableChildren(element, props, childNodes))) {
|
|
1160
1704
|
syncChildNodes(element, childNodes);
|
|
1161
1705
|
}
|
|
1162
1706
|
}
|
|
1163
1707
|
else if (fiber.subtreeFlags !== NoFlags) {
|
|
1164
|
-
|
|
1708
|
+
commitHostDirtyChildrenOf(fiber, fiber.child, element, eventRoot, `${path}.c`, options);
|
|
1165
1709
|
}
|
|
1166
|
-
if (
|
|
1710
|
+
if (isDomElement && isFormHostType(fiber.type)) {
|
|
1167
1711
|
applyPostChildFormProps(element, props, previousProps);
|
|
1168
1712
|
}
|
|
1169
1713
|
applyChangedRef(previousProps?.ref, props.ref, element);
|
|
@@ -1182,7 +1726,7 @@ function commitHostDirtyFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1182
1726
|
: container instanceof Element
|
|
1183
1727
|
? container
|
|
1184
1728
|
: eventRoot;
|
|
1185
|
-
const portalOptions =
|
|
1729
|
+
const portalOptions = withPortalHostOptions(options, container);
|
|
1186
1730
|
if (fiber.childListChanged ||
|
|
1187
1731
|
fiber.subtreeChildListChanged ||
|
|
1188
1732
|
(fiber.subtreeFlags & Placement) !== NoFlags) {
|
|
@@ -1192,15 +1736,20 @@ function commitHostDirtyFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1192
1736
|
fiber.memoizedState = childNodes;
|
|
1193
1737
|
}
|
|
1194
1738
|
else {
|
|
1195
|
-
|
|
1739
|
+
commitHostDirtyChildrenOf(fiber, fiber.child, container, portalEventRoot, `${path}.portal`, portalOptions);
|
|
1196
1740
|
}
|
|
1197
1741
|
}
|
|
1198
1742
|
fiber.memoizedProps = fiber.pendingProps;
|
|
1199
1743
|
finishCommittedFiber(fiber);
|
|
1200
1744
|
return;
|
|
1201
1745
|
}
|
|
1746
|
+
if (fiber.tag === "reactive-dom-block") {
|
|
1747
|
+
fiber.memoizedProps = fiber.pendingProps;
|
|
1748
|
+
finishCommittedFiber(fiber);
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1202
1751
|
if (fiber.subtreeFlags !== NoFlags) {
|
|
1203
|
-
|
|
1752
|
+
commitHostDirtyChildrenOf(fiber, fiber.child, parent, eventRoot, path, options);
|
|
1204
1753
|
}
|
|
1205
1754
|
fiber.memoizedProps = fiber.pendingProps;
|
|
1206
1755
|
finishCommittedFiber(fiber);
|
|
@@ -1307,7 +1856,9 @@ function readAppendSuffixCommitHint(value) {
|
|
|
1307
1856
|
: undefined;
|
|
1308
1857
|
}
|
|
1309
1858
|
function commitHostSingleRemoval(fiber, parent) {
|
|
1310
|
-
const removed =
|
|
1859
|
+
const removed = fiber.deletions?.length === 1
|
|
1860
|
+
? fiber.deletions[0]
|
|
1861
|
+
: getSingleRemovedFiber(fiber.alternate?.child, fiber.child);
|
|
1311
1862
|
if (removed === undefined) {
|
|
1312
1863
|
return false;
|
|
1313
1864
|
}
|
|
@@ -1319,6 +1870,9 @@ function commitHostSingleRemoval(fiber, parent) {
|
|
|
1319
1870
|
parent.removeChild(node);
|
|
1320
1871
|
removedAny = true;
|
|
1321
1872
|
}
|
|
1873
|
+
if (removedAny) {
|
|
1874
|
+
fiber.deletions = undefined;
|
|
1875
|
+
}
|
|
1322
1876
|
return removedAny;
|
|
1323
1877
|
}
|
|
1324
1878
|
function getAppendSuffix(current, next) {
|
|
@@ -1372,6 +1926,10 @@ function isSameFiberSlot(current, next) {
|
|
|
1372
1926
|
current.key === next.key);
|
|
1373
1927
|
}
|
|
1374
1928
|
function collectCommittedHostNodes(fiber) {
|
|
1929
|
+
if (fiber.tag === "reactive-dom-block") {
|
|
1930
|
+
const node = getReactiveDomBlockNode(fiber.stateNode);
|
|
1931
|
+
return node === undefined ? [] : [node];
|
|
1932
|
+
}
|
|
1375
1933
|
if ((fiber.tag === "host-component" || fiber.tag === "host-text") &&
|
|
1376
1934
|
fiber.stateNode instanceof Node) {
|
|
1377
1935
|
return [fiber.stateNode];
|
|
@@ -1385,6 +1943,9 @@ function collectCommittedHostNodes(fiber) {
|
|
|
1385
1943
|
return nodes;
|
|
1386
1944
|
}
|
|
1387
1945
|
function hasCommittedHostNode(fiber) {
|
|
1946
|
+
if (fiber.tag === "reactive-dom-block") {
|
|
1947
|
+
return getReactiveDomBlockNode(fiber.stateNode) !== undefined;
|
|
1948
|
+
}
|
|
1388
1949
|
if ((fiber.tag === "host-component" || fiber.tag === "host-text") &&
|
|
1389
1950
|
fiber.stateNode instanceof Node) {
|
|
1390
1951
|
return true;
|
|
@@ -1428,6 +1989,12 @@ function commitHostFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1428
1989
|
finishCommittedFiber(fiber);
|
|
1429
1990
|
return [text];
|
|
1430
1991
|
}
|
|
1992
|
+
if (fiber.tag === "reactive-dom-block") {
|
|
1993
|
+
const node = getReactiveDomBlockNode(fiber.stateNode);
|
|
1994
|
+
fiber.memoizedProps = fiber.pendingProps;
|
|
1995
|
+
finishCommittedFiber(fiber);
|
|
1996
|
+
return node === undefined ? [] : [node];
|
|
1997
|
+
}
|
|
1431
1998
|
if (fiber.tag === "host-component") {
|
|
1432
1999
|
const element = fiber.stateNode;
|
|
1433
2000
|
if (!isHostElement(element)) {
|
|
@@ -1443,6 +2010,7 @@ function commitHostFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1443
2010
|
fiber.memoizedProps = fiber.pendingProps;
|
|
1444
2011
|
return [element];
|
|
1445
2012
|
}
|
|
2013
|
+
const isDomElement = isDomHostElement(element);
|
|
1446
2014
|
const props = fiber.pendingProps;
|
|
1447
2015
|
const previousProps = fiber.memoizedProps;
|
|
1448
2016
|
const directTextChild = fiber.child === undefined && fiber.hydrateExisting !== true
|
|
@@ -1462,7 +2030,7 @@ function commitHostFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1462
2030
|
!propsAreChildrenOnly &&
|
|
1463
2031
|
fiber.hydrateExisting !== true &&
|
|
1464
2032
|
isRowTextOnlyUpdate(fiber.memoizedProps, props);
|
|
1465
|
-
if (
|
|
2033
|
+
if (isDomElement && !propsAreUnchanged && !propsAreChildrenOnly && !textOnlyRowUpdate) {
|
|
1466
2034
|
applyProps(element, props, path, {
|
|
1467
2035
|
...options,
|
|
1468
2036
|
eventRoot,
|
|
@@ -1479,15 +2047,15 @@ function commitHostFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1479
2047
|
fiber.hydrateExisting === true ||
|
|
1480
2048
|
(fiber.subtreeFlags & Placement) !== NoFlags) {
|
|
1481
2049
|
const childNodes = commitHostChildren(fiber.child, element, eventRoot, `${path}.c`, options);
|
|
1482
|
-
if (!(
|
|
1483
|
-
!(
|
|
2050
|
+
if (!(isDomElement && childNodes.length === 0 && committedPortalContainers.has(element)) &&
|
|
2051
|
+
!(isDomElement && shouldPreserveContentEditableChildren(element, props, childNodes))) {
|
|
1484
2052
|
syncChildNodes(element, childNodes);
|
|
1485
2053
|
}
|
|
1486
2054
|
}
|
|
1487
2055
|
else if (fiber.subtreeFlags !== NoFlags) {
|
|
1488
2056
|
commitHostChildren(fiber.child, element, eventRoot, `${path}.c`, options);
|
|
1489
2057
|
}
|
|
1490
|
-
if (
|
|
2058
|
+
if (isDomElement && isFormHostType(fiber.type)) {
|
|
1491
2059
|
applyPostChildFormProps(element, props, previousProps);
|
|
1492
2060
|
}
|
|
1493
2061
|
applyChangedRef(previousProps?.ref, props.ref, element);
|
|
@@ -1581,7 +2149,7 @@ function commitHostFiber(fiber, parent, eventRoot, path, options = {}) {
|
|
|
1581
2149
|
: container instanceof Element
|
|
1582
2150
|
? container
|
|
1583
2151
|
: eventRoot;
|
|
1584
|
-
const portalOptions =
|
|
2152
|
+
const portalOptions = withPortalHostOptions(options, container);
|
|
1585
2153
|
const childNodes = commitHostChildren(fiber.child, container, portalEventRoot, `${path}.portal`, portalOptions);
|
|
1586
2154
|
const previousNodes = committedHostNodesFromState(fiber.alternate?.memoizedState);
|
|
1587
2155
|
syncOwnedChildNodes(container, previousNodes, childNodes);
|
|
@@ -1600,6 +2168,26 @@ function finishCommittedFiber(fiber) {
|
|
|
1600
2168
|
fiber.subtreeChildListChanged = false;
|
|
1601
2169
|
fiber.hostChildListChanged = false;
|
|
1602
2170
|
}
|
|
2171
|
+
function getReactiveDomBlockNode(state) {
|
|
2172
|
+
if (typeof state === "object" &&
|
|
2173
|
+
state !== null &&
|
|
2174
|
+
"node" in state &&
|
|
2175
|
+
state.node instanceof Node) {
|
|
2176
|
+
return state.node;
|
|
2177
|
+
}
|
|
2178
|
+
return undefined;
|
|
2179
|
+
}
|
|
2180
|
+
function disposeReactiveDomBlockState(state, seen) {
|
|
2181
|
+
if (typeof state !== "object" || state === null || seen.has(state)) {
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
seen.add(state);
|
|
2185
|
+
const dispose = state.dispose;
|
|
2186
|
+
if (typeof dispose === "function") {
|
|
2187
|
+
dispose();
|
|
2188
|
+
state.dispose = undefined;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
1603
2191
|
function hasChildListMutation(fiber) {
|
|
1604
2192
|
return fiber.childListChanged || fiber.subtreeChildListChanged;
|
|
1605
2193
|
}
|
|
@@ -1746,6 +2334,12 @@ function getDirectHostTextChild(children) {
|
|
|
1746
2334
|
? String(children)
|
|
1747
2335
|
: undefined;
|
|
1748
2336
|
}
|
|
2337
|
+
// Only these host tags carry post-child form value/checked semantics. Gating on
|
|
2338
|
+
// the (cheap, already-known) type string lets the commit skip applyPostChildFormProps
|
|
2339
|
+
// and its instanceof probes for every other element.
|
|
2340
|
+
function isFormHostType(type) {
|
|
2341
|
+
return type === "input" || type === "textarea" || type === "select";
|
|
2342
|
+
}
|
|
1749
2343
|
const hostFastPathMode = (() => {
|
|
1750
2344
|
try {
|
|
1751
2345
|
// The literal process.env.NODE_ENV member expression is what bundler
|
|
@@ -2016,7 +2610,23 @@ function tryReuseMemoBailout(current, node, runtime, path, options, canReuseCurr
|
|
|
2016
2610
|
!areMemoPropsEqual(node.type, previousMemoState.props, node.props)) {
|
|
2017
2611
|
return undefined;
|
|
2018
2612
|
}
|
|
2019
|
-
|
|
2613
|
+
if (memoStateNeedsActiveInstanceMark(previousMemoState)) {
|
|
2614
|
+
markActiveInstanceKeys(runtime, previousMemoState.instanceKeys);
|
|
2615
|
+
}
|
|
2616
|
+
const fiber = canReuseCurrentFiber &&
|
|
2617
|
+
current.hasRefSubtree !== true &&
|
|
2618
|
+
current.hasDisposableResources !== true &&
|
|
2619
|
+
current.hydrateExisting !== true
|
|
2620
|
+
? current
|
|
2621
|
+
: createWorkInProgress(current, node.props);
|
|
2622
|
+
if (fiber === current) {
|
|
2623
|
+
current.pendingProps = node.props;
|
|
2624
|
+
current.flags = NoFlags;
|
|
2625
|
+
current.subtreeFlags = NoFlags;
|
|
2626
|
+
current.childListChanged = false;
|
|
2627
|
+
current.subtreeChildListChanged = false;
|
|
2628
|
+
current.hostChildListChanged = false;
|
|
2629
|
+
}
|
|
2020
2630
|
fiber.type = node.type;
|
|
2021
2631
|
fiber.child = getSkippedChild(current);
|
|
2022
2632
|
fiber.memoizedState = previousMemoState;
|
|
@@ -2139,7 +2749,11 @@ function createPortalFiber(parent, current, portal, key, runtime, path, options
|
|
|
2139
2749
|
? createWorkInProgress(current, portal.children)
|
|
2140
2750
|
: createFiber("portal", portal.children, key);
|
|
2141
2751
|
fiber.stateNode = portal.container;
|
|
2142
|
-
const childResult = reconcileHostChild(fiber, current?.tag === "portal" ? current.child : undefined, portal.children, runtime, `${path}.portal`, {
|
|
2752
|
+
const childResult = reconcileHostChild(fiber, current?.tag === "portal" ? current.child : undefined, portal.children, runtime, `${path}.portal`, {
|
|
2753
|
+
...options,
|
|
2754
|
+
documentRef: portal.container.ownerDocument,
|
|
2755
|
+
namespace: namespaceForPortalContainer(portal.container),
|
|
2756
|
+
});
|
|
2143
2757
|
fiber.child = childResult.fiber;
|
|
2144
2758
|
fiber.return = parent;
|
|
2145
2759
|
return { fiber, consumed: childResult.consumed };
|
|
@@ -2239,6 +2853,24 @@ function isLazyType(value) {
|
|
|
2239
2853
|
function collectInstanceKeys(runtime, prefix) {
|
|
2240
2854
|
return collectRuntimeInstanceKeys(runtime, prefix);
|
|
2241
2855
|
}
|
|
2856
|
+
function collectMemoInstanceKeys(runtime, prefix) {
|
|
2857
|
+
return readDependencyFreeMemoInstanceKey(runtime, prefix) === undefined
|
|
2858
|
+
? collectInstanceKeys(runtime, prefix)
|
|
2859
|
+
: emptyInstanceKeys;
|
|
2860
|
+
}
|
|
2861
|
+
function readDependencyFreeMemoInstanceKey(runtime, prefix) {
|
|
2862
|
+
const keys = runtime.instanceKeysByPrefix.get(prefix);
|
|
2863
|
+
if (keys === undefined || keys.size !== 1 || !keys.has(prefix)) {
|
|
2864
|
+
return undefined;
|
|
2865
|
+
}
|
|
2866
|
+
const instance = runtime.instances.get(prefix);
|
|
2867
|
+
if (instance === undefined ||
|
|
2868
|
+
instance.contextDependencies !== undefined ||
|
|
2869
|
+
(instance.hooks !== undefined && instance.hooks.length > 0)) {
|
|
2870
|
+
return undefined;
|
|
2871
|
+
}
|
|
2872
|
+
return prefix;
|
|
2873
|
+
}
|
|
2242
2874
|
function markActiveInstanceKeys(runtime, keys) {
|
|
2243
2875
|
for (const key of keys) {
|
|
2244
2876
|
runtime.activeInstanceKeys?.add(key);
|
|
@@ -2254,6 +2886,9 @@ function memoStateNeedsActiveInstanceMark(state) {
|
|
|
2254
2886
|
return state.hasRetainedInstanceDependencies !== false;
|
|
2255
2887
|
}
|
|
2256
2888
|
function getMemoBailoutFiber(runtime, current, pendingProps, state, canReuseCurrentFiber) {
|
|
2889
|
+
if (memoStateNeedsActiveInstanceMark(state)) {
|
|
2890
|
+
markActiveInstanceKeys(runtime, state.instanceKeys);
|
|
2891
|
+
}
|
|
2257
2892
|
if (canReuseCurrentFiber && canReuseMemoBailoutFiber(current, state)) {
|
|
2258
2893
|
current.pendingProps = pendingProps;
|
|
2259
2894
|
current.flags = NoFlags;
|
|
@@ -2264,14 +2899,12 @@ function getMemoBailoutFiber(runtime, current, pendingProps, state, canReuseCurr
|
|
|
2264
2899
|
return current;
|
|
2265
2900
|
}
|
|
2266
2901
|
const fiber = createWorkInProgress(current, pendingProps);
|
|
2267
|
-
if (memoStateNeedsActiveInstanceMark(state)) {
|
|
2268
|
-
markActiveInstanceKeys(runtime, state.instanceKeys);
|
|
2269
|
-
}
|
|
2270
2902
|
return fiber;
|
|
2271
2903
|
}
|
|
2272
2904
|
function canReuseMemoBailoutFiber(current, state) {
|
|
2273
2905
|
return (state.hasRetainedInstanceDependencies === false &&
|
|
2274
2906
|
current.hasRefSubtree !== true &&
|
|
2907
|
+
current.hasDisposableResources !== true &&
|
|
2275
2908
|
current.hydrateExisting !== true);
|
|
2276
2909
|
}
|
|
2277
2910
|
function hasDirtyInstanceDependencies(runtime, keys) {
|
|
@@ -2413,7 +3046,8 @@ function isPortalHostContainer(value) {
|
|
|
2413
3046
|
typeof candidate.removeChild === "function" &&
|
|
2414
3047
|
typeof candidate.ownerDocument?.createElement === "function");
|
|
2415
3048
|
}
|
|
2416
|
-
function
|
|
3049
|
+
function withPortalHostOptions(options, container) {
|
|
3050
|
+
const namespace = namespaceForPortalContainer(container);
|
|
2417
3051
|
const ownerDocument = container.ownerDocument;
|
|
2418
3052
|
if (typeof ownerDocument === "object" &&
|
|
2419
3053
|
ownerDocument !== null &&
|
|
@@ -2421,9 +3055,16 @@ function withPortalDocumentRef(options, container) {
|
|
|
2421
3055
|
return {
|
|
2422
3056
|
...options,
|
|
2423
3057
|
documentRef: ownerDocument,
|
|
3058
|
+
namespace,
|
|
2424
3059
|
};
|
|
2425
3060
|
}
|
|
2426
|
-
return options;
|
|
3061
|
+
return { ...options, namespace };
|
|
3062
|
+
}
|
|
3063
|
+
function namespaceForPortalContainer(container) {
|
|
3064
|
+
if (container instanceof SVGElement && container.localName !== "foreignObject") {
|
|
3065
|
+
return "svg";
|
|
3066
|
+
}
|
|
3067
|
+
return "html";
|
|
2427
3068
|
}
|
|
2428
3069
|
function committedHostNodesFromState(state) {
|
|
2429
3070
|
return Array.isArray(state) ? state : [];
|