octane 0.1.25 → 0.1.26
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/runtime.js +109 -5
- package/dist/universal-core.d.ts +1 -0
- package/dist/universal-core.js +439 -90
- package/package.json +1 -1
package/dist/runtime.js
CHANGED
|
@@ -100,6 +100,14 @@ function profilePortalComponent(rawBody) {
|
|
|
100
100
|
function ensureHooks(scope) {
|
|
101
101
|
return scope.hooks ?? (scope.hooks = /* @__PURE__ */ new Map());
|
|
102
102
|
}
|
|
103
|
+
function registerHookCleanup(scope, cleanup) {
|
|
104
|
+
if (process.env.NODE_ENV !== "production") {
|
|
105
|
+
if (scope.block.body[HMR] !== void 0) {
|
|
106
|
+
cleanup[HMR] = true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
(scope.cleanups ??= []).push(cleanup);
|
|
110
|
+
}
|
|
103
111
|
let nextHookSlot = 0;
|
|
104
112
|
function hookSlots(count) {
|
|
105
113
|
const base = nextHookSlot;
|
|
@@ -2446,7 +2454,7 @@ function unmountScope(scope, detachDom = true) {
|
|
|
2446
2454
|
unmountScopeChildrenAndSlots(scope, detachDom);
|
|
2447
2455
|
});
|
|
2448
2456
|
}
|
|
2449
|
-
function
|
|
2457
|
+
function runScopeCleanups(scope) {
|
|
2450
2458
|
const c = scope.cleanups;
|
|
2451
2459
|
if (c !== null)
|
|
2452
2460
|
for (let i = c.length - 1; i >= 0; i--) {
|
|
@@ -2456,6 +2464,12 @@ function unmountScopeChildrenAndSlots(scope, detachDom) {
|
|
|
2456
2464
|
reportTeardownError(err);
|
|
2457
2465
|
}
|
|
2458
2466
|
}
|
|
2467
|
+
}
|
|
2468
|
+
function unmountScopeChildrenAndSlots(scope, detachDom) {
|
|
2469
|
+
runScopeCleanups(scope);
|
|
2470
|
+
unmountScopeChildrenAndSlotsOnly(scope, detachDom);
|
|
2471
|
+
}
|
|
2472
|
+
function unmountScopeChildrenAndSlotsOnly(scope, detachDom) {
|
|
2459
2473
|
const children = scope.children;
|
|
2460
2474
|
if (children !== null)
|
|
2461
2475
|
for (let i = 0, n = children.length; i < n; i++) unmountScope(children[i].scope, detachDom);
|
|
@@ -3123,7 +3137,7 @@ function useEffectEvent(fn, slot) {
|
|
|
3123
3137
|
s = { impl: fn, active: true };
|
|
3124
3138
|
ensureHooks(scope).set(slot, s);
|
|
3125
3139
|
const cell2 = s;
|
|
3126
|
-
(scope
|
|
3140
|
+
registerHookCleanup(scope, () => {
|
|
3127
3141
|
cell2.active = false;
|
|
3128
3142
|
});
|
|
3129
3143
|
} else {
|
|
@@ -3205,6 +3219,87 @@ function scopedChildrenAsBody(props) {
|
|
|
3205
3219
|
return (_props, scope, extra) => childrenAsBody(props.children)(void 0, scope, extra);
|
|
3206
3220
|
}
|
|
3207
3221
|
const CHILDREN_DIALECT_SLOT = /* @__PURE__ */ Symbol("octane.childrenDialect");
|
|
3222
|
+
function hasResettableHmrRange(block) {
|
|
3223
|
+
const start = block.startMarker;
|
|
3224
|
+
const end = block.endMarker;
|
|
3225
|
+
if (start === void 0 || end === void 0) return false;
|
|
3226
|
+
if (start === null || end === null) {
|
|
3227
|
+
return start === null && end === null && (block.kind === "root" || block.exclusiveMarkers === true);
|
|
3228
|
+
}
|
|
3229
|
+
if (start !== end) {
|
|
3230
|
+
return start.parentNode === block.parentNode && end.parentNode === block.parentNode;
|
|
3231
|
+
}
|
|
3232
|
+
for (let parent = block.parentBlock; parent !== null; parent = parent.parentBlock) {
|
|
3233
|
+
if (parent.startMarker === start && parent.endMarker === end) return false;
|
|
3234
|
+
}
|
|
3235
|
+
return start.parentNode === block.parentNode;
|
|
3236
|
+
}
|
|
3237
|
+
function promoteHmrBlockRange(block) {
|
|
3238
|
+
const root = block.startMarker;
|
|
3239
|
+
if (root === null || root !== block.endMarker) return;
|
|
3240
|
+
const parent = block.parentNode;
|
|
3241
|
+
const rangeStart = document.createComment("hmr");
|
|
3242
|
+
const rangeEnd = document.createComment("/hmr");
|
|
3243
|
+
parent.insertBefore(rangeStart, root);
|
|
3244
|
+
parent.insertBefore(rangeEnd, root.nextSibling);
|
|
3245
|
+
block.startMarker = rangeStart;
|
|
3246
|
+
block.endMarker = rangeEnd;
|
|
3247
|
+
block.exclusiveMarkers = false;
|
|
3248
|
+
}
|
|
3249
|
+
function resetHmrBlock(block) {
|
|
3250
|
+
if (TEARDOWN_DEPTH === 0) {
|
|
3251
|
+
TEARDOWN_HANDLER = findTryHandler(block.parentBlock) ?? rendererRegionTryHandler(block);
|
|
3252
|
+
}
|
|
3253
|
+
TEARDOWN_DEPTH++;
|
|
3254
|
+
let abortedRefs = null;
|
|
3255
|
+
if (!block.mounted) {
|
|
3256
|
+
abortedRefs = [];
|
|
3257
|
+
collectVisibleSubtreeRefs(block, abortedRefs);
|
|
3258
|
+
}
|
|
3259
|
+
try {
|
|
3260
|
+
withRefDetachSuppression(abortedRefs, () => {
|
|
3261
|
+
if (block.deoptNode !== null) detachDeoptTreeRefs(block.deoptNode, null);
|
|
3262
|
+
const cleanups = block.cleanups;
|
|
3263
|
+
let preserved = null;
|
|
3264
|
+
if (cleanups !== null) {
|
|
3265
|
+
for (let i = cleanups.length - 1; i >= 0; i--) {
|
|
3266
|
+
const cleanup = cleanups[i];
|
|
3267
|
+
if (cleanup[HMR] === true) continue;
|
|
3268
|
+
try {
|
|
3269
|
+
runEffectLifecycleCallback(cleanup);
|
|
3270
|
+
} catch (err) {
|
|
3271
|
+
reportTeardownError(err);
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
for (let i = 0; i < cleanups.length; i++) {
|
|
3275
|
+
const cleanup = cleanups[i];
|
|
3276
|
+
if (cleanup[HMR] === true) (preserved ??= []).push(cleanup);
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
unmountScopeChildrenAndSlotsOnly(block, true);
|
|
3280
|
+
removeRange(
|
|
3281
|
+
block.startMarker !== null ? block.startMarker.nextSibling : block.parentNode.firstChild,
|
|
3282
|
+
block.endMarker
|
|
3283
|
+
);
|
|
3284
|
+
block.children = null;
|
|
3285
|
+
block.cleanups = preserved;
|
|
3286
|
+
block._slots = null;
|
|
3287
|
+
block.refFields = null;
|
|
3288
|
+
block.slots = [];
|
|
3289
|
+
block.deoptNode = null;
|
|
3290
|
+
});
|
|
3291
|
+
const hooks = block.hooks;
|
|
3292
|
+
if (hooks !== null) {
|
|
3293
|
+
for (const value of hooks.values()) {
|
|
3294
|
+
if (value !== null && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, "deps")) {
|
|
3295
|
+
value.deps = void 0;
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
} finally {
|
|
3300
|
+
if (--TEARDOWN_DEPTH === 0) dispatchTeardownErrors();
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3208
3303
|
function resetScopeChildren(scope) {
|
|
3209
3304
|
const block = scope.block;
|
|
3210
3305
|
if (TEARDOWN_DEPTH === 0) {
|
|
@@ -10559,6 +10654,13 @@ function hmr(fn) {
|
|
|
10559
10654
|
const nextFn = incomingMeta ? incomingMeta.fn : incoming;
|
|
10560
10655
|
if (meta.fn.__octaneReturnedOutput !== nextFn.__octaneReturnedOutput)
|
|
10561
10656
|
return false;
|
|
10657
|
+
for (const b of meta.liveBlocks) {
|
|
10658
|
+
if (b.disposed) {
|
|
10659
|
+
meta.liveBlocks.delete(b);
|
|
10660
|
+
continue;
|
|
10661
|
+
}
|
|
10662
|
+
if (!hasResettableHmrRange(b)) return false;
|
|
10663
|
+
}
|
|
10562
10664
|
meta.fn = nextFn;
|
|
10563
10665
|
if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__)
|
|
10564
10666
|
__profileComponentSource(wrapper, meta.fn);
|
|
@@ -10573,6 +10675,8 @@ function hmr(fn) {
|
|
|
10573
10675
|
b.body = wrapper;
|
|
10574
10676
|
if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__)
|
|
10575
10677
|
__profileSchedule(b, "hmr");
|
|
10678
|
+
promoteHmrBlockRange(b);
|
|
10679
|
+
resetHmrBlock(b);
|
|
10576
10680
|
scheduleRender(b);
|
|
10577
10681
|
}
|
|
10578
10682
|
return true;
|
|
@@ -11684,7 +11788,7 @@ function useTransition(slot) {
|
|
|
11684
11788
|
}
|
|
11685
11789
|
};
|
|
11686
11790
|
TRANSITION_LISTENERS.add(listener);
|
|
11687
|
-
(scope
|
|
11791
|
+
registerHookCleanup(scope, () => TRANSITION_LISTENERS.delete(listener));
|
|
11688
11792
|
}
|
|
11689
11793
|
return [s.isPending, s.start];
|
|
11690
11794
|
}
|
|
@@ -11786,7 +11890,7 @@ function useFormStatus(slot) {
|
|
|
11786
11890
|
s = { form: null, listener: null };
|
|
11787
11891
|
const slotRef = s;
|
|
11788
11892
|
ensureHooks(scope).set(slot, slotRef);
|
|
11789
|
-
(scope
|
|
11893
|
+
registerHookCleanup(scope, () => {
|
|
11790
11894
|
if (slotRef.form && slotRef.listener)
|
|
11791
11895
|
FORM_STATUS_LISTENERS.get(slotRef.form)?.delete(slotRef.listener);
|
|
11792
11896
|
});
|
|
@@ -11861,7 +11965,7 @@ function useOptimistic(passthrough, updateFnOrSlot, slot) {
|
|
|
11861
11965
|
if (TRANSITION_PENDING_COUNT === 0 && slotRef.armed) clear();
|
|
11862
11966
|
};
|
|
11863
11967
|
TRANSITION_LISTENERS.add(listener);
|
|
11864
|
-
(scope
|
|
11968
|
+
registerHookCleanup(scope, () => TRANSITION_LISTENERS.delete(listener));
|
|
11865
11969
|
}
|
|
11866
11970
|
s.updateFn = updateFn;
|
|
11867
11971
|
let optimistic = passthrough;
|
package/dist/universal-core.d.ts
CHANGED
|
@@ -611,6 +611,7 @@ export interface ObjectHostInstance {
|
|
|
611
611
|
}
|
|
612
612
|
interface ObjectDriverState {
|
|
613
613
|
instances: Map<number, ObjectHostInstance>;
|
|
614
|
+
parents: Map<number, number | null>;
|
|
614
615
|
events: Map<number, Map<string, UniversalEventListenerDescriptor>>;
|
|
615
616
|
lifecycles: Map<number, Map<string, UniversalListenerDescriptor>>;
|
|
616
617
|
localCallbacks: Map<number, Map<string, UniversalListenerDescriptor>>;
|
package/dist/universal-core.js
CHANGED
|
@@ -616,6 +616,7 @@ function createOwnerRecord(root, component, parent, identityPath, key) {
|
|
|
616
616
|
root,
|
|
617
617
|
renderer: root.renderer,
|
|
618
618
|
component,
|
|
619
|
+
componentProps: null,
|
|
619
620
|
parent,
|
|
620
621
|
identityPath,
|
|
621
622
|
key,
|
|
@@ -624,6 +625,7 @@ function createOwnerRecord(root, component, parent, identityPath, key) {
|
|
|
624
625
|
hooks: /* @__PURE__ */ new Map(),
|
|
625
626
|
effectOrder: [],
|
|
626
627
|
children: [],
|
|
628
|
+
range: null,
|
|
627
629
|
contextValues: null,
|
|
628
630
|
updates: /* @__PURE__ */ new Map(),
|
|
629
631
|
isBoundary: false,
|
|
@@ -639,6 +641,7 @@ function createOwnerRecord(root, component, parent, identityPath, key) {
|
|
|
639
641
|
function draftOwner(record, parent, replayPath) {
|
|
640
642
|
return {
|
|
641
643
|
record,
|
|
644
|
+
componentProps: record.componentProps,
|
|
642
645
|
parent,
|
|
643
646
|
replayPath,
|
|
644
647
|
hooks: new Map(record.hooks),
|
|
@@ -658,7 +661,7 @@ function draftOwner(record, parent, replayPath) {
|
|
|
658
661
|
boundaryThenable: record.boundaryThenable,
|
|
659
662
|
isBoundary: record.isBoundary,
|
|
660
663
|
canHandleSuspense: record.canHandleSuspense,
|
|
661
|
-
visibility: parent?.visibility ??
|
|
664
|
+
visibility: parent?.visibility ?? record.visibility
|
|
662
665
|
};
|
|
663
666
|
}
|
|
664
667
|
function childReplayPath(parent, component, identityPath, key) {
|
|
@@ -733,6 +736,15 @@ function readOwnerContext(owner, context, trackMemoRead = true) {
|
|
|
733
736
|
return value;
|
|
734
737
|
}
|
|
735
738
|
}
|
|
739
|
+
if (currentAttempt().scope !== null) {
|
|
740
|
+
for (let current = owner?.record.parent ?? null; current !== null; current = current.parent) {
|
|
741
|
+
if (current.contextValues?.has(context)) {
|
|
742
|
+
value = current.contextValues.get(context);
|
|
743
|
+
if (trackMemoRead) CURRENT_MEMO_CONTEXT_READS?.set(context, value);
|
|
744
|
+
return value;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
736
748
|
value = currentAttempt().root.readBridgeContext(context);
|
|
737
749
|
if (trackMemoRead) CURRENT_MEMO_CONTEXT_READS?.set(context, value);
|
|
738
750
|
return value;
|
|
@@ -808,7 +820,7 @@ function renderLazyLeafItem(scope, render, item, index, key) {
|
|
|
808
820
|
}
|
|
809
821
|
}
|
|
810
822
|
function ownerRange(owner, children) {
|
|
811
|
-
return [{ kind: "range", key: owner.record.rangeKey, children }];
|
|
823
|
+
return [{ kind: "range", key: owner.record.rangeKey, owner: owner.record, children }];
|
|
812
824
|
}
|
|
813
825
|
function componentContext(renderer) {
|
|
814
826
|
return {
|
|
@@ -836,6 +848,7 @@ function materializeComponentValue(value, expectedRenderer, path) {
|
|
|
836
848
|
const normalized = normalizePropsValue(value.props);
|
|
837
849
|
const owner = claimChildOwner(parent, value.component, path, value.hasKey ? value.key : null);
|
|
838
850
|
const props = { ...normalized.props };
|
|
851
|
+
owner.componentProps = props;
|
|
839
852
|
const nodes = executeOwner(owner, () => {
|
|
840
853
|
const rendered = value.component(props, componentContext(expectedRenderer));
|
|
841
854
|
return materializeValue(rendered, expectedRenderer, null, [...path, "output"]);
|
|
@@ -862,6 +875,8 @@ function disposeUncommittedDraft(owner) {
|
|
|
862
875
|
for (const child of owner.children) disposeUncommittedDraft(child);
|
|
863
876
|
if (!owner.record.mounted) {
|
|
864
877
|
owner.record.disposed = true;
|
|
878
|
+
owner.record.componentProps = null;
|
|
879
|
+
owner.record.range = null;
|
|
865
880
|
owner.record.updates.clear();
|
|
866
881
|
for (const hook of owner.hooks.values()) {
|
|
867
882
|
if (hook.kind === "effect-event") hook.cell.active = false;
|
|
@@ -907,6 +922,7 @@ function blueprintFromLogical(record) {
|
|
|
907
922
|
return {
|
|
908
923
|
kind: "range",
|
|
909
924
|
key: record.key,
|
|
925
|
+
...record.owner === null ? null : { owner: record.owner },
|
|
910
926
|
children: record.children.map(blueprintFromLogical)
|
|
911
927
|
};
|
|
912
928
|
}
|
|
@@ -1777,6 +1793,61 @@ function walkDraftPostOrder(record, visit) {
|
|
|
1777
1793
|
for (const child of record.children) walkDraftPostOrder(child, visit);
|
|
1778
1794
|
visit(record);
|
|
1779
1795
|
}
|
|
1796
|
+
function logicalTreeFeatures(record) {
|
|
1797
|
+
let features = 0;
|
|
1798
|
+
walkLogical(record, (current) => {
|
|
1799
|
+
if (current.kind === "portal") {
|
|
1800
|
+
features |= UNIVERSAL_TREE_PORTAL;
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1803
|
+
if (current.kind !== "host") return;
|
|
1804
|
+
if (current.events.size !== 0) features |= UNIVERSAL_TREE_EVENT;
|
|
1805
|
+
if (current.lifecycles.size !== 0) features |= UNIVERSAL_TREE_LIFECYCLE;
|
|
1806
|
+
if (current.localCallbacks.size !== 0) features |= UNIVERSAL_TREE_LOCAL_CALLBACK;
|
|
1807
|
+
if (current.ref != null) features |= UNIVERSAL_TREE_REF;
|
|
1808
|
+
if (current.visibility !== "visible") features |= UNIVERSAL_TREE_HIDDEN;
|
|
1809
|
+
for (const value of Object.values(current.props)) {
|
|
1810
|
+
if (isRendererRegion(value)) {
|
|
1811
|
+
features |= UNIVERSAL_TREE_REGION;
|
|
1812
|
+
break;
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
});
|
|
1816
|
+
return features;
|
|
1817
|
+
}
|
|
1818
|
+
function ownerTreeHasWarmPlan(owner) {
|
|
1819
|
+
if (owner.component?.__warm !== void 0) return true;
|
|
1820
|
+
for (const child of owner.children) {
|
|
1821
|
+
if (ownerTreeHasWarmPlan(child)) return true;
|
|
1822
|
+
}
|
|
1823
|
+
return false;
|
|
1824
|
+
}
|
|
1825
|
+
function commonOwnerAncestor(left, right) {
|
|
1826
|
+
let leftDepth = 0;
|
|
1827
|
+
for (let current = left.parent; current !== null; current = current.parent) leftDepth++;
|
|
1828
|
+
let rightDepth = 0;
|
|
1829
|
+
for (let current = right.parent; current !== null; current = current.parent) rightDepth++;
|
|
1830
|
+
let a = left;
|
|
1831
|
+
let b = right;
|
|
1832
|
+
for (; leftDepth > rightDepth; leftDepth--) a = a.parent;
|
|
1833
|
+
for (; rightDepth > leftDepth; rightDepth--) b = b.parent;
|
|
1834
|
+
while (a !== null && a !== b) {
|
|
1835
|
+
a = a.parent;
|
|
1836
|
+
b = b.parent;
|
|
1837
|
+
}
|
|
1838
|
+
return a;
|
|
1839
|
+
}
|
|
1840
|
+
function stableLogicalChildren(records, blueprints) {
|
|
1841
|
+
if (records.length !== blueprints.length) return false;
|
|
1842
|
+
for (let index = 0; index < records.length; index++) {
|
|
1843
|
+
const record = records[index];
|
|
1844
|
+
const blueprint = blueprints[index];
|
|
1845
|
+
if (blueprint.kind === "range" && blueprint.compactLeafList !== void 0 || !sameRecordShape(record, blueprint) || !stableLogicalChildren(record.children, blueprint.children)) {
|
|
1846
|
+
return false;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
return true;
|
|
1850
|
+
}
|
|
1780
1851
|
function collectRemovedPostOrder(record, output) {
|
|
1781
1852
|
for (const child of record.children) collectRemovedPostOrder(child, output);
|
|
1782
1853
|
if (record.kind === "host") output.push(record);
|
|
@@ -2090,7 +2161,7 @@ function scheduleOwner(owner, slot) {
|
|
|
2090
2161
|
"state",
|
|
2091
2162
|
typeof slot === "symbol" || typeof slot === "number" ? slot : void 0
|
|
2092
2163
|
);
|
|
2093
|
-
owner.root.
|
|
2164
|
+
owner.root.scheduleOwned(owner);
|
|
2094
2165
|
}
|
|
2095
2166
|
function currentDraftOwner() {
|
|
2096
2167
|
currentAttempt();
|
|
@@ -3395,6 +3466,8 @@ class UniversalRootImpl {
|
|
|
3395
3466
|
retryRenderInput = null;
|
|
3396
3467
|
scheduled = false;
|
|
3397
3468
|
scheduledUrgent = false;
|
|
3469
|
+
scheduledFullRoot = false;
|
|
3470
|
+
scheduledOwners = /* @__PURE__ */ new Set();
|
|
3398
3471
|
scheduledPreparationDepth = 0;
|
|
3399
3472
|
scheduledTransitionBatches = /* @__PURE__ */ new Set();
|
|
3400
3473
|
unattemptedTransitionBatches = /* @__PURE__ */ new Set();
|
|
@@ -4041,7 +4114,7 @@ class UniversalRootImpl {
|
|
|
4041
4114
|
}
|
|
4042
4115
|
this.__scheduleMicrotask(() => this.flushScheduledWork());
|
|
4043
4116
|
}
|
|
4044
|
-
|
|
4117
|
+
markUrgentScheduled() {
|
|
4045
4118
|
if (this.unmounted || this.owner?.disposed || this.lastComponent === null) return;
|
|
4046
4119
|
this.scheduledUrgent = true;
|
|
4047
4120
|
if (this.scheduled) return;
|
|
@@ -4049,6 +4122,15 @@ class UniversalRootImpl {
|
|
|
4049
4122
|
SCHEDULED_UNIVERSAL_ROOTS.add(this);
|
|
4050
4123
|
if (this.eventScopeDepth === 0 && UNIVERSAL_SYNC_DEPTH === 0) this.queueScheduledWork();
|
|
4051
4124
|
}
|
|
4125
|
+
scheduleOwned(owner) {
|
|
4126
|
+
if (owner.root !== this || owner.disposed) return;
|
|
4127
|
+
this.scheduledOwners.add(owner);
|
|
4128
|
+
this.markUrgentScheduled();
|
|
4129
|
+
}
|
|
4130
|
+
schedule() {
|
|
4131
|
+
this.scheduledFullRoot = true;
|
|
4132
|
+
this.markUrgentScheduled();
|
|
4133
|
+
}
|
|
4052
4134
|
/** @internal Associates promoted transition work with its accepting transaction. */
|
|
4053
4135
|
scheduleTransition(batch) {
|
|
4054
4136
|
if (batch.settled || this.unmounted || this.owner?.disposed || this.lastComponent === null) {
|
|
@@ -4391,6 +4473,8 @@ class UniversalRootImpl {
|
|
|
4391
4473
|
for (const draft of owners) {
|
|
4392
4474
|
if (committed.has(draft.record)) continue;
|
|
4393
4475
|
draft.record.disposed = true;
|
|
4476
|
+
draft.record.componentProps = null;
|
|
4477
|
+
draft.record.range = null;
|
|
4394
4478
|
draft.record.updates.clear();
|
|
4395
4479
|
for (const hook of draft.hooks.values()) {
|
|
4396
4480
|
if (hook.kind === "effect-event") hook.cell.active = false;
|
|
@@ -4439,9 +4523,184 @@ class UniversalRootImpl {
|
|
|
4439
4523
|
projectedThenable: null
|
|
4440
4524
|
};
|
|
4441
4525
|
}
|
|
4526
|
+
// A local state update may replay only the component range that owns its hook.
|
|
4527
|
+
// The retained topology check keeps reconciliation atomic: features that need
|
|
4528
|
+
// root-wide coordination, or any structural change, fall back to the ordinary
|
|
4529
|
+
// full-root attempt before a host batch is prepared.
|
|
4530
|
+
prepareOwnedUpdate(target, component, props) {
|
|
4531
|
+
const range = target.range;
|
|
4532
|
+
if (this.transport !== null || this.bridge !== null || target.component === null || target.componentProps === null || ownerTreeHasWarmPlan(target) || range === null || range.kind !== "range" || range.owner !== target || target.visibility === "suspense-hidden") {
|
|
4533
|
+
return null;
|
|
4534
|
+
}
|
|
4535
|
+
for (let ancestor = target.parent; ancestor !== null; ancestor = ancestor.parent) {
|
|
4536
|
+
if (ancestor.isBoundary && (ancestor.hasBoundaryError || ancestor.boundaryThenable !== null)) {
|
|
4537
|
+
return null;
|
|
4538
|
+
}
|
|
4539
|
+
}
|
|
4540
|
+
const unsupported = UNIVERSAL_TREE_PORTAL | UNIVERSAL_TREE_REGION;
|
|
4541
|
+
const scopeFeatures = logicalTreeFeatures(range);
|
|
4542
|
+
if ((scopeFeatures & unsupported) !== 0) return null;
|
|
4543
|
+
this.flushPassivesBeforeRender();
|
|
4544
|
+
this.pending?.abort();
|
|
4545
|
+
const owner = draftOwner(target, null, [
|
|
4546
|
+
{
|
|
4547
|
+
component: target.component,
|
|
4548
|
+
identityPath: target.identityPath,
|
|
4549
|
+
key: target.key,
|
|
4550
|
+
ordinal: 0
|
|
4551
|
+
}
|
|
4552
|
+
]);
|
|
4553
|
+
const previousAttempt = CURRENT_ATTEMPT;
|
|
4554
|
+
const previousOwner = CURRENT_OWNER;
|
|
4555
|
+
const previousWarm = CURRENT_UNIVERSAL_WARM;
|
|
4556
|
+
const previousWarmClaims = CURRENT_UNIVERSAL_WARM_CLAIMS;
|
|
4557
|
+
const previousWarmPlans = ACTIVE_UNIVERSAL_WARM_PLANS.slice();
|
|
4558
|
+
const attempt = {
|
|
4559
|
+
root: this,
|
|
4560
|
+
owner,
|
|
4561
|
+
scope: target,
|
|
4562
|
+
owners: [owner],
|
|
4563
|
+
treeFeatures: 0,
|
|
4564
|
+
replayEntries: [],
|
|
4565
|
+
retryThenables: /* @__PURE__ */ new Set(),
|
|
4566
|
+
nextUniversalId: this.nextUniversalId,
|
|
4567
|
+
implicitSlot: 0,
|
|
4568
|
+
transitionBatches: EMPTY_UNIVERSAL_TRANSITION_BATCHES,
|
|
4569
|
+
transitionRender: false,
|
|
4570
|
+
bridgeContextReads: null
|
|
4571
|
+
};
|
|
4572
|
+
ACTIVE_UNIVERSAL_WARM_PLANS.length = 0;
|
|
4573
|
+
CURRENT_UNIVERSAL_WARM = null;
|
|
4574
|
+
CURRENT_UNIVERSAL_WARM_CLAIMS = null;
|
|
4575
|
+
CURRENT_ATTEMPT = attempt;
|
|
4576
|
+
CURRENT_OWNER = owner;
|
|
4577
|
+
let nodes;
|
|
4578
|
+
try {
|
|
4579
|
+
nodes = executeOwner(owner, () => {
|
|
4580
|
+
const value = target.component(target.componentProps, componentContext(this.renderer));
|
|
4581
|
+
return materializeValue(value, this.renderer, null, [...target.identityPath, "output"]);
|
|
4582
|
+
});
|
|
4583
|
+
} catch (error) {
|
|
4584
|
+
this.discardDraftOwners(attempt.owners);
|
|
4585
|
+
if (error instanceof UniversalSuspense) {
|
|
4586
|
+
UNIVERSAL_WARM_CACHES.delete(this);
|
|
4587
|
+
return null;
|
|
4588
|
+
}
|
|
4589
|
+
for (let ancestor = target.parent; ancestor !== null; ancestor = ancestor.parent) {
|
|
4590
|
+
if (ancestor.isBoundary) {
|
|
4591
|
+
UNIVERSAL_WARM_CACHES.delete(this);
|
|
4592
|
+
return null;
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
throw error;
|
|
4596
|
+
} finally {
|
|
4597
|
+
ACTIVE_UNIVERSAL_WARM_PLANS.length = 0;
|
|
4598
|
+
ACTIVE_UNIVERSAL_WARM_PLANS.push(...previousWarmPlans);
|
|
4599
|
+
CURRENT_UNIVERSAL_WARM = previousWarm;
|
|
4600
|
+
CURRENT_UNIVERSAL_WARM_CLAIMS = previousWarmClaims;
|
|
4601
|
+
CURRENT_ATTEMPT = previousAttempt;
|
|
4602
|
+
CURRENT_OWNER = previousOwner;
|
|
4603
|
+
}
|
|
4604
|
+
if (attempt.retryThenables.size !== 0 || (attempt.treeFeatures & unsupported) !== 0) {
|
|
4605
|
+
this.discardDraftOwners(attempt.owners);
|
|
4606
|
+
UNIVERSAL_WARM_CACHES.delete(this);
|
|
4607
|
+
return null;
|
|
4608
|
+
}
|
|
4609
|
+
const blueprint = {
|
|
4610
|
+
kind: "range",
|
|
4611
|
+
key: target.rangeKey,
|
|
4612
|
+
owner: target,
|
|
4613
|
+
children: nodes
|
|
4614
|
+
};
|
|
4615
|
+
this.expandCompactLeafLists(blueprint);
|
|
4616
|
+
let scopePlacement = null;
|
|
4617
|
+
if (!stableLogicalChildren(range.children, blueprint.children)) {
|
|
4618
|
+
scopePlacement = this.scopePhysicalPlacement(range);
|
|
4619
|
+
if (scopePlacement === null) {
|
|
4620
|
+
this.discardDraftOwners(attempt.owners);
|
|
4621
|
+
UNIVERSAL_WARM_CACHES.delete(this);
|
|
4622
|
+
return null;
|
|
4623
|
+
}
|
|
4624
|
+
}
|
|
4625
|
+
try {
|
|
4626
|
+
const transaction = this.createPreparedTransaction(
|
|
4627
|
+
blueprint,
|
|
4628
|
+
attempt,
|
|
4629
|
+
component,
|
|
4630
|
+
props,
|
|
4631
|
+
/* @__PURE__ */ new Set(),
|
|
4632
|
+
range,
|
|
4633
|
+
scopeFeatures,
|
|
4634
|
+
scopePlacement
|
|
4635
|
+
);
|
|
4636
|
+
this.pending = transaction;
|
|
4637
|
+
return transaction;
|
|
4638
|
+
} catch (error) {
|
|
4639
|
+
this.discardDraftOwners(attempt.owners);
|
|
4640
|
+
throw error;
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
// The physical frame a scoped range commits into: its nearest host (or
|
|
4644
|
+
// container) ancestor plus the first physical host that follows the scope
|
|
4645
|
+
// inside that parent. Untouched siblings cannot move during a scoped commit,
|
|
4646
|
+
// so both stay valid anchors for inserted or reordered scope content. A
|
|
4647
|
+
// portal or detached ancestor owns a separate physical tree: no frame.
|
|
4648
|
+
scopePhysicalPlacement(scope) {
|
|
4649
|
+
let endAnchor = null;
|
|
4650
|
+
let current = scope;
|
|
4651
|
+
for (let parent = current.parent; parent !== null; current = parent, parent = current.parent) {
|
|
4652
|
+
if (parent.kind !== "host" && parent.kind !== "range") return null;
|
|
4653
|
+
if (endAnchor === null) {
|
|
4654
|
+
const siblings = parent.children;
|
|
4655
|
+
for (let index = siblings.indexOf(current) + 1; index < siblings.length; index++) {
|
|
4656
|
+
const found = physicalRecords([siblings[index]]);
|
|
4657
|
+
if (found.length !== 0) {
|
|
4658
|
+
endAnchor = found[0].id;
|
|
4659
|
+
break;
|
|
4660
|
+
}
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
if (parent.kind === "host") return { parent: parent.id, endAnchor };
|
|
4664
|
+
if (parent === this.rootRecord) return { parent: null, endAnchor };
|
|
4665
|
+
}
|
|
4666
|
+
return null;
|
|
4667
|
+
}
|
|
4668
|
+
// A scheduled owner that cannot replay alone (an anonymous @for-item owner,
|
|
4669
|
+
// or several owners raised by one event scope) still has one smallest
|
|
4670
|
+
// ancestor whose retained props and range can replay every queued update:
|
|
4671
|
+
// the nearest enclosing component owner of their common ancestor.
|
|
4672
|
+
resolveScopedTarget() {
|
|
4673
|
+
let scope = null;
|
|
4674
|
+
for (const owner of this.scheduledOwners) {
|
|
4675
|
+
if (owner.disposed) continue;
|
|
4676
|
+
if (owner.visibility === "suspense-hidden") return void 0;
|
|
4677
|
+
scope = scope === null ? owner : commonOwnerAncestor(scope, owner);
|
|
4678
|
+
if (scope === null) return void 0;
|
|
4679
|
+
}
|
|
4680
|
+
let target = null;
|
|
4681
|
+
for (let current = scope; current !== null; current = current.parent) {
|
|
4682
|
+
if (current.component !== null && current.componentProps !== null && current.range !== null) {
|
|
4683
|
+
target = current;
|
|
4684
|
+
break;
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
if (target === null) return void 0;
|
|
4688
|
+
for (const owner of this.scheduledOwners) {
|
|
4689
|
+
if (owner.disposed) continue;
|
|
4690
|
+
for (let current = owner; current !== target; current = current.parent) {
|
|
4691
|
+
if (current === null || current.isBoundary && (current.hasBoundaryError || current.boundaryThenable !== null)) {
|
|
4692
|
+
return void 0;
|
|
4693
|
+
}
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4696
|
+
return target;
|
|
4697
|
+
}
|
|
4442
4698
|
prepare(component, props) {
|
|
4699
|
+
const ownedTarget = this.scheduledPreparationDepth > 0 && this.scheduledUrgent && !this.scheduledFullRoot && this.scheduledOwners.size !== 0 ? this.resolveScopedTarget() : void 0;
|
|
4443
4700
|
const scheduledUrgent = this.scheduledUrgent || this.scheduledPreparationDepth === 0;
|
|
4444
4701
|
this.scheduledUrgent = false;
|
|
4702
|
+
this.scheduledFullRoot = false;
|
|
4703
|
+
this.scheduledOwners.clear();
|
|
4445
4704
|
if (scheduledUrgent) this.urgentBoundarySuspension = null;
|
|
4446
4705
|
const bridgeReplay = this.bridge === null ? null : this.queuedReplay;
|
|
4447
4706
|
if (!scheduledUrgent && bridgeReplay !== null && bridgeReplay.component === component && bridgeReplay.active) {
|
|
@@ -4468,6 +4727,10 @@ class UniversalRootImpl {
|
|
|
4468
4727
|
const scheduledTransitions = scheduledUrgent ? EMPTY_UNIVERSAL_TRANSITION_BATCHES : this.takeScheduledTransitionBatches();
|
|
4469
4728
|
UNIVERSAL_WARM_CACHES.delete(this);
|
|
4470
4729
|
try {
|
|
4730
|
+
if (ownedTarget !== void 0 && component === this.lastComponent && universalShallowEqual(props, this.lastProps)) {
|
|
4731
|
+
const ownedAttempt = this.prepareOwnedUpdate(ownedTarget, component, props);
|
|
4732
|
+
if (ownedAttempt !== null) return ownedAttempt;
|
|
4733
|
+
}
|
|
4471
4734
|
const attempt = this.prepareWithReplay(
|
|
4472
4735
|
component,
|
|
4473
4736
|
props,
|
|
@@ -4505,6 +4768,7 @@ class UniversalRootImpl {
|
|
|
4505
4768
|
{ component, identityPath: ownerRecord.identityPath, key: ownerRecord.key, ordinal: 0 }
|
|
4506
4769
|
];
|
|
4507
4770
|
const owner = draftOwner(ownerRecord, null, rootPath);
|
|
4771
|
+
owner.componentProps = props;
|
|
4508
4772
|
const previousAttempt = CURRENT_ATTEMPT;
|
|
4509
4773
|
const previousOwner = CURRENT_OWNER;
|
|
4510
4774
|
const previousWarm = CURRENT_UNIVERSAL_WARM;
|
|
@@ -4513,6 +4777,7 @@ class UniversalRootImpl {
|
|
|
4513
4777
|
const attempt = {
|
|
4514
4778
|
root: this,
|
|
4515
4779
|
owner,
|
|
4780
|
+
scope: null,
|
|
4516
4781
|
owners: [owner],
|
|
4517
4782
|
treeFeatures: 0,
|
|
4518
4783
|
replayEntries,
|
|
@@ -4758,6 +5023,7 @@ class UniversalRootImpl {
|
|
|
4758
5023
|
}
|
|
4759
5024
|
for (const draft of attempt.owners) {
|
|
4760
5025
|
const record = draft.record;
|
|
5026
|
+
record.componentProps = draft.componentProps;
|
|
4761
5027
|
record.parent = draft.parent?.record ?? null;
|
|
4762
5028
|
record.hooks = draft.hooks;
|
|
4763
5029
|
record.effectOrder = [...draft.seenEffects];
|
|
@@ -4866,6 +5132,7 @@ class UniversalRootImpl {
|
|
|
4866
5132
|
}
|
|
4867
5133
|
for (const draft of attempt.owners) {
|
|
4868
5134
|
const record = draft.record;
|
|
5135
|
+
record.componentProps = draft.componentProps;
|
|
4869
5136
|
record.parent = draft.parent?.record ?? null;
|
|
4870
5137
|
record.hooks = draft.hooks;
|
|
4871
5138
|
record.effectOrder = [...draft.seenEffects];
|
|
@@ -4955,23 +5222,29 @@ class UniversalRootImpl {
|
|
|
4955
5222
|
throw error;
|
|
4956
5223
|
}
|
|
4957
5224
|
}
|
|
4958
|
-
createPreparedTransaction(blueprint, attempt, component, props, stagedPortalRegistrations) {
|
|
5225
|
+
createPreparedTransaction(blueprint, attempt, component, props, stagedPortalRegistrations, scopeRecord = this.rootRecord, scopeFeatures = 0, scopePlacement = null) {
|
|
4959
5226
|
let nextId = this.nextId;
|
|
4960
|
-
const
|
|
4961
|
-
const
|
|
5227
|
+
const scoped = scopeRecord !== this.rootRecord;
|
|
5228
|
+
const treeFeatures = (scoped ? scopeFeatures : this.treeFeatures) | attempt.treeFeatures;
|
|
5229
|
+
const used = /* @__PURE__ */ new Set([scopeRecord]);
|
|
5230
|
+
const changedRangeOwners = [];
|
|
4962
5231
|
let topologyChanged = false;
|
|
4963
5232
|
const reconcileChildren = (oldChildren, blueprints) => {
|
|
4964
5233
|
if ((treeFeatures & UNIVERSAL_TREE_PORTAL) === 0 && oldChildren.length === blueprints.length && oldChildren.every((record, index) => sameRecordShape(record, blueprints[index]))) {
|
|
4965
5234
|
return oldChildren.map((record, index) => {
|
|
4966
5235
|
used.add(record);
|
|
4967
5236
|
const blueprint2 = blueprints[index];
|
|
4968
|
-
|
|
5237
|
+
const draft = {
|
|
4969
5238
|
record,
|
|
4970
5239
|
blueprint: blueprint2,
|
|
4971
5240
|
children: reconcileChildren(record.children, blueprint2.children),
|
|
4972
5241
|
isNew: false,
|
|
4973
5242
|
hostUpdate: null
|
|
4974
5243
|
};
|
|
5244
|
+
if (record.kind === "range" && record.owner !== (blueprint2.owner ?? null)) {
|
|
5245
|
+
changedRangeOwners.push(draft);
|
|
5246
|
+
}
|
|
5247
|
+
return draft;
|
|
4975
5248
|
});
|
|
4976
5249
|
}
|
|
4977
5250
|
const keyed = /* @__PURE__ */ new Map();
|
|
@@ -5012,13 +5285,17 @@ class UniversalRootImpl {
|
|
|
5012
5285
|
record ??= createLogicalRecord(nextId++, child);
|
|
5013
5286
|
claimed.add(record);
|
|
5014
5287
|
used.add(record);
|
|
5015
|
-
|
|
5288
|
+
const draft = {
|
|
5016
5289
|
record,
|
|
5017
5290
|
blueprint: child,
|
|
5018
5291
|
children: reconcileChildren(record.children, child.children),
|
|
5019
5292
|
isNew,
|
|
5020
5293
|
hostUpdate: null
|
|
5021
|
-
}
|
|
5294
|
+
};
|
|
5295
|
+
if (record.kind === "range" && record.owner !== (child.owner ?? null)) {
|
|
5296
|
+
changedRangeOwners.push(draft);
|
|
5297
|
+
}
|
|
5298
|
+
output.push(draft);
|
|
5022
5299
|
}
|
|
5023
5300
|
if (oldChildren.length !== output.length || output.some((draft, index) => draft.record !== oldChildren[index])) {
|
|
5024
5301
|
topologyChanged = true;
|
|
@@ -5026,9 +5303,9 @@ class UniversalRootImpl {
|
|
|
5026
5303
|
return output;
|
|
5027
5304
|
};
|
|
5028
5305
|
const draftRoot = {
|
|
5029
|
-
record:
|
|
5306
|
+
record: scopeRecord,
|
|
5030
5307
|
blueprint,
|
|
5031
|
-
children: reconcileChildren(
|
|
5308
|
+
children: reconcileChildren(scopeRecord.children, blueprint.children),
|
|
5032
5309
|
isNew: false,
|
|
5033
5310
|
hostUpdate: null
|
|
5034
5311
|
};
|
|
@@ -5039,13 +5316,13 @@ class UniversalRootImpl {
|
|
|
5039
5316
|
else findRemoved(child);
|
|
5040
5317
|
}
|
|
5041
5318
|
};
|
|
5042
|
-
if (topologyChanged) findRemoved(
|
|
5319
|
+
if (topologyChanged) findRemoved(scopeRecord);
|
|
5043
5320
|
const previousPortalRegistrations = /* @__PURE__ */ new Set();
|
|
5044
5321
|
const nextPortalRegistrations = /* @__PURE__ */ new Set();
|
|
5045
5322
|
let reorderedPortalRecords = null;
|
|
5046
5323
|
if ((treeFeatures & UNIVERSAL_TREE_PORTAL) !== 0) {
|
|
5047
5324
|
const previousPortalsByTarget = topologyChanged ? /* @__PURE__ */ new Map() : null;
|
|
5048
|
-
for (const child of
|
|
5325
|
+
for (const child of scopeRecord.children) {
|
|
5049
5326
|
walkLogical(child, (record) => {
|
|
5050
5327
|
if (record.kind === "portal" && record.portalRegistration !== null) {
|
|
5051
5328
|
previousPortalRegistrations.add(record.portalRegistration);
|
|
@@ -5092,7 +5369,7 @@ class UniversalRootImpl {
|
|
|
5092
5369
|
const stagedRegionBridges = [];
|
|
5093
5370
|
const nextRegionBridges = /* @__PURE__ */ new Set();
|
|
5094
5371
|
if ((treeFeatures & UNIVERSAL_TREE_REGION) !== 0) {
|
|
5095
|
-
for (const child of
|
|
5372
|
+
for (const child of scopeRecord.children) {
|
|
5096
5373
|
walkLogical(child, (record) => {
|
|
5097
5374
|
if (record.kind !== "host") return;
|
|
5098
5375
|
for (const value of Object.values(record.props)) {
|
|
@@ -5176,7 +5453,7 @@ class UniversalRootImpl {
|
|
|
5176
5453
|
});
|
|
5177
5454
|
const removes = [];
|
|
5178
5455
|
const placements = [];
|
|
5179
|
-
const planPlacements = (parentId, oldRecords, newDrafts, sourceParentId = parentId, forceMove = false) => {
|
|
5456
|
+
const planPlacements = (parentId, oldRecords, newDrafts, sourceParentId = parentId, forceMove = false, endAnchor = null) => {
|
|
5180
5457
|
const oldPhysical = physicalRecords(oldRecords);
|
|
5181
5458
|
const newPhysical = physicalDrafts(newDrafts);
|
|
5182
5459
|
const desiredIds = new Set(newPhysical.map((entry) => entry.record.id));
|
|
@@ -5192,7 +5469,7 @@ class UniversalRootImpl {
|
|
|
5192
5469
|
const id = draft.record.id;
|
|
5193
5470
|
if (current[index] === id) continue;
|
|
5194
5471
|
const currentIndex = current.indexOf(id);
|
|
5195
|
-
const before = current[index] ??
|
|
5472
|
+
const before = current[index] ?? endAnchor;
|
|
5196
5473
|
if (currentIndex === -1) {
|
|
5197
5474
|
placements.push({
|
|
5198
5475
|
op: forceMove && previousIds.has(id) ? "move" : "insert",
|
|
@@ -5211,6 +5488,15 @@ class UniversalRootImpl {
|
|
|
5211
5488
|
walkDraftPostOrder(draftRoot, (draft) => {
|
|
5212
5489
|
if (draft.record === this.rootRecord) {
|
|
5213
5490
|
planPlacements(null, this.rootRecord.children, draft.children);
|
|
5491
|
+
} else if (scoped && draft === draftRoot && scopePlacement !== null) {
|
|
5492
|
+
planPlacements(
|
|
5493
|
+
scopePlacement.parent,
|
|
5494
|
+
draft.record.children,
|
|
5495
|
+
draft.children,
|
|
5496
|
+
scopePlacement.parent,
|
|
5497
|
+
false,
|
|
5498
|
+
scopePlacement.endAnchor
|
|
5499
|
+
);
|
|
5214
5500
|
} else if (draft.record.kind === "host") {
|
|
5215
5501
|
planPlacements(draft.record.id, draft.record.children, draft.children);
|
|
5216
5502
|
} else if (draft.record.kind === "portal") {
|
|
@@ -5441,7 +5727,7 @@ class UniversalRootImpl {
|
|
|
5441
5727
|
committedOwnersParentFirst.push(owner);
|
|
5442
5728
|
for (const child of owner.children) walkCommittedOwners(child);
|
|
5443
5729
|
};
|
|
5444
|
-
walkCommittedOwners(this.owner);
|
|
5730
|
+
walkCommittedOwners(scoped ? attempt.owner.record : this.owner);
|
|
5445
5731
|
const removedOwners = committedOwnersParentFirst.filter((owner) => !draftedRecords.has(owner));
|
|
5446
5732
|
const removedEffectEventCells = collectEffectEventCells(removedOwners);
|
|
5447
5733
|
const orderedEffectCleanups = [];
|
|
@@ -5506,20 +5792,34 @@ class UniversalRootImpl {
|
|
|
5506
5792
|
record.localCallbacks = localCallbackStage.staged.get(record) ?? record.localCallbacks;
|
|
5507
5793
|
record.visibility = host.visibility;
|
|
5508
5794
|
};
|
|
5795
|
+
const applyRangeOwner = (draft) => {
|
|
5796
|
+
const record = draft.record;
|
|
5797
|
+
const nextOwner = draft.blueprint.owner ?? null;
|
|
5798
|
+
if (record.owner !== nextOwner && record.owner?.range === record) {
|
|
5799
|
+
record.owner.range = null;
|
|
5800
|
+
}
|
|
5801
|
+
record.owner = nextOwner;
|
|
5802
|
+
if (nextOwner !== null) nextOwner.range = record;
|
|
5803
|
+
};
|
|
5509
5804
|
const apply = (draft, parent) => {
|
|
5510
5805
|
const record = draft.record;
|
|
5511
5806
|
record.parent = parent;
|
|
5512
5807
|
record.key = draft.blueprint.key;
|
|
5513
5808
|
if (record.kind === "host") {
|
|
5514
5809
|
applyHost(draft);
|
|
5810
|
+
} else if (record.kind === "range") {
|
|
5811
|
+
applyRangeOwner(draft);
|
|
5515
5812
|
} else if (record.kind === "portal") {
|
|
5516
5813
|
record.portalRegistration = draft.blueprint.registration;
|
|
5517
5814
|
}
|
|
5518
5815
|
record.children = draft.children.map((child) => child.record);
|
|
5519
5816
|
for (const child of draft.children) apply(child, record);
|
|
5520
5817
|
};
|
|
5521
|
-
if (topologyChanged) apply(draftRoot, null);
|
|
5522
|
-
else
|
|
5818
|
+
if (topologyChanged) apply(draftRoot, scoped ? scopeRecord.parent : null);
|
|
5819
|
+
else {
|
|
5820
|
+
for (const draft of hostDrafts) applyHost(draft);
|
|
5821
|
+
for (const draft of changedRangeOwners) applyRangeOwner(draft);
|
|
5822
|
+
}
|
|
5523
5823
|
stagedPortalRegistrations.clear();
|
|
5524
5824
|
for (const registration of previousPortalRegistrations) {
|
|
5525
5825
|
if (nextPortalRegistrations.has(registration)) continue;
|
|
@@ -5537,6 +5837,19 @@ class UniversalRootImpl {
|
|
|
5537
5837
|
});
|
|
5538
5838
|
}
|
|
5539
5839
|
const hasPassiveWork = removedEffectEventCells.length !== 0 || orderedEffectCleanups.some((cleanup) => cleanup.phase === "passive") || effectChanges.some(({ next, changed }) => changed && next.phase === "passive");
|
|
5840
|
+
const previousScopedEventListeners = /* @__PURE__ */ new Set();
|
|
5841
|
+
const previousScopedLocalCallbacks = /* @__PURE__ */ new Set();
|
|
5842
|
+
if (scoped) {
|
|
5843
|
+
walkLogical(scopeRecord, (record) => {
|
|
5844
|
+
if (record.kind !== "host") return;
|
|
5845
|
+
for (const event of record.events.values()) {
|
|
5846
|
+
previousScopedEventListeners.add(event.listener);
|
|
5847
|
+
}
|
|
5848
|
+
for (const callback of record.localCallbacks.values()) {
|
|
5849
|
+
previousScopedLocalCallbacks.add(callback.listener);
|
|
5850
|
+
}
|
|
5851
|
+
});
|
|
5852
|
+
}
|
|
5540
5853
|
const prepareHost = (value) => this.driver.prepareBatch(this.container, value, {
|
|
5541
5854
|
invokeLocalCallback: (listener, args) => this.invokeLocalCallback(listener, args)
|
|
5542
5855
|
});
|
|
@@ -5571,9 +5884,13 @@ class UniversalRootImpl {
|
|
|
5571
5884
|
}
|
|
5572
5885
|
}
|
|
5573
5886
|
if ((treeFeatures & UNIVERSAL_TREE_EVENT) !== 0) {
|
|
5574
|
-
|
|
5575
|
-
this.publishedListeners
|
|
5576
|
-
const
|
|
5887
|
+
const handlers = scoped ? this.handlers : /* @__PURE__ */ new Map();
|
|
5888
|
+
const replacedListeners = scoped ? previousScopedEventListeners : this.publishedListeners;
|
|
5889
|
+
for (const listener of replacedListeners) {
|
|
5890
|
+
EVENT_DISPATCHERS.delete(listener);
|
|
5891
|
+
this.publishedListeners.delete(listener);
|
|
5892
|
+
handlers.delete(listener);
|
|
5893
|
+
}
|
|
5577
5894
|
for (const [record, events] of stagedEvents) {
|
|
5578
5895
|
if (!stagedVisibleEventRecords.has(record)) continue;
|
|
5579
5896
|
for (const event of events.values()) {
|
|
@@ -5588,7 +5905,10 @@ class UniversalRootImpl {
|
|
|
5588
5905
|
this.handlers = handlers;
|
|
5589
5906
|
}
|
|
5590
5907
|
if ((treeFeatures & UNIVERSAL_TREE_LOCAL_CALLBACK) !== 0) {
|
|
5591
|
-
const localCallbacks = /* @__PURE__ */ new Map();
|
|
5908
|
+
const localCallbacks = scoped ? this.localCallbacks : /* @__PURE__ */ new Map();
|
|
5909
|
+
for (const listener of previousScopedLocalCallbacks) {
|
|
5910
|
+
localCallbacks.delete(listener);
|
|
5911
|
+
}
|
|
5592
5912
|
for (const callbacks of localCallbackStage.staged.values()) {
|
|
5593
5913
|
for (const callback of callbacks.values()) {
|
|
5594
5914
|
localCallbacks.set(callback.listener, callback);
|
|
@@ -5599,11 +5919,16 @@ class UniversalRootImpl {
|
|
|
5599
5919
|
for (const owner of removedOwners) {
|
|
5600
5920
|
owner.disposed = true;
|
|
5601
5921
|
owner.mounted = false;
|
|
5922
|
+
owner.componentProps = null;
|
|
5923
|
+
owner.range = null;
|
|
5602
5924
|
owner.updates.clear();
|
|
5603
5925
|
}
|
|
5604
5926
|
for (const draft of draftOwnersParentFirst) {
|
|
5605
5927
|
const record = draft.record;
|
|
5606
|
-
record.
|
|
5928
|
+
record.componentProps = draft.componentProps;
|
|
5929
|
+
if (!scoped || draft !== attempt.owner) {
|
|
5930
|
+
record.parent = draft.parent?.record ?? null;
|
|
5931
|
+
}
|
|
5607
5932
|
record.hooks = draft.hooks;
|
|
5608
5933
|
record.effectOrder = [...draft.seenEffects];
|
|
5609
5934
|
record.children = draft.children.map((child) => child.record);
|
|
@@ -5659,19 +5984,19 @@ class UniversalRootImpl {
|
|
|
5659
5984
|
}
|
|
5660
5985
|
}
|
|
5661
5986
|
}
|
|
5662
|
-
this.owner = attempt.owner.record;
|
|
5987
|
+
if (!scoped) this.owner = attempt.owner.record;
|
|
5663
5988
|
this.lastComponent = component;
|
|
5664
5989
|
this.lastProps = props;
|
|
5665
5990
|
this.retryRenderInput = null;
|
|
5666
5991
|
this.urgentBoundarySuspension = null;
|
|
5667
|
-
this.bridgeContextReads = attempt.bridgeContextReads;
|
|
5992
|
+
if (!scoped) this.bridgeContextReads = attempt.bridgeContextReads;
|
|
5668
5993
|
if (retryThenables.length > 0) {
|
|
5669
5994
|
this.publishLocalReplay(retryThenables, retryMemos, component, props);
|
|
5670
5995
|
}
|
|
5671
5996
|
this.nextId = nextId;
|
|
5672
5997
|
this.nextUniversalId = attempt.nextUniversalId;
|
|
5673
5998
|
this.nextListener = nextListener;
|
|
5674
|
-
this.treeFeatures = attempt.treeFeatures;
|
|
5999
|
+
this.treeFeatures = scoped ? this.treeFeatures | attempt.treeFeatures : attempt.treeFeatures;
|
|
5675
6000
|
for (const context of changedContexts) context.$$version++;
|
|
5676
6001
|
const retainedRegionCells = /* @__PURE__ */ new Set();
|
|
5677
6002
|
for (const { next, previous } of stagedRegionBridges) {
|
|
@@ -6034,6 +6359,8 @@ class UniversalRootImpl {
|
|
|
6034
6359
|
finalize: (acceptedHostError) => {
|
|
6035
6360
|
this.scheduled = false;
|
|
6036
6361
|
this.scheduledUrgent = false;
|
|
6362
|
+
this.scheduledFullRoot = false;
|
|
6363
|
+
this.scheduledOwners.clear();
|
|
6037
6364
|
SCHEDULED_UNIVERSAL_ROOTS.delete(this);
|
|
6038
6365
|
const transitionBatches = new Set(this.takeScheduledTransitionBatches());
|
|
6039
6366
|
for (const transition of stagedTransitionBatches) transitionBatches.add(transition);
|
|
@@ -6042,6 +6369,8 @@ class UniversalRootImpl {
|
|
|
6042
6369
|
this.cancelSuspendedReplays();
|
|
6043
6370
|
this.scheduled = false;
|
|
6044
6371
|
this.scheduledUrgent = false;
|
|
6372
|
+
this.scheduledFullRoot = false;
|
|
6373
|
+
this.scheduledOwners.clear();
|
|
6045
6374
|
SCHEDULED_UNIVERSAL_ROOTS.delete(this);
|
|
6046
6375
|
let attachmentUnsubscribeError = NO_PENDING_PASSIVE_ERROR;
|
|
6047
6376
|
if (this.hostAttachments !== null) {
|
|
@@ -6068,6 +6397,8 @@ class UniversalRootImpl {
|
|
|
6068
6397
|
for (const owner of owners) {
|
|
6069
6398
|
owner.disposed = true;
|
|
6070
6399
|
owner.mounted = false;
|
|
6400
|
+
owner.componentProps = null;
|
|
6401
|
+
owner.range = null;
|
|
6071
6402
|
owner.updates.clear();
|
|
6072
6403
|
}
|
|
6073
6404
|
const deactivatedRegionCells = /* @__PURE__ */ new Set();
|
|
@@ -6450,6 +6781,7 @@ function createObjectContainer(renderer = "object") {
|
|
|
6450
6781
|
assertRendererId(renderer, "Object container renderer");
|
|
6451
6782
|
const state = {
|
|
6452
6783
|
instances: /* @__PURE__ */ new Map(),
|
|
6784
|
+
parents: /* @__PURE__ */ new Map(),
|
|
6453
6785
|
events: /* @__PURE__ */ new Map(),
|
|
6454
6786
|
lifecycles: /* @__PURE__ */ new Map(),
|
|
6455
6787
|
localCallbacks: /* @__PURE__ */ new Map(),
|
|
@@ -6517,8 +6849,14 @@ function createObjectDriver(renderer = "object") {
|
|
|
6517
6849
|
}
|
|
6518
6850
|
const state = container[OBJECT_DRIVER_STATE];
|
|
6519
6851
|
const simulated = /* @__PURE__ */ new Map();
|
|
6520
|
-
|
|
6521
|
-
|
|
6852
|
+
const destroyed = /* @__PURE__ */ new Set();
|
|
6853
|
+
const readSimulated = (id) => {
|
|
6854
|
+
if (destroyed.has(id)) return void 0;
|
|
6855
|
+
let value = simulated.get(id);
|
|
6856
|
+
if (value !== void 0) return value;
|
|
6857
|
+
const instance = state.instances.get(id);
|
|
6858
|
+
if (instance === void 0) return void 0;
|
|
6859
|
+
value = {
|
|
6522
6860
|
type: instance.type,
|
|
6523
6861
|
props: instance.props,
|
|
6524
6862
|
visible: instance.visible,
|
|
@@ -6526,8 +6864,11 @@ function createObjectDriver(renderer = "object") {
|
|
|
6526
6864
|
events: new Map(state.events.get(id)),
|
|
6527
6865
|
lifecycles: new Map(state.lifecycles.get(id)),
|
|
6528
6866
|
localCallbacks: new Map(state.localCallbacks.get(id))
|
|
6529
|
-
}
|
|
6530
|
-
|
|
6867
|
+
};
|
|
6868
|
+
simulated.set(id, value);
|
|
6869
|
+
return value;
|
|
6870
|
+
};
|
|
6871
|
+
const hasSimulated = (id) => !destroyed.has(id) && (simulated.has(id) || state.instances.has(id));
|
|
6531
6872
|
const stagedInstances = /* @__PURE__ */ new Map();
|
|
6532
6873
|
const cleanupKeys = /* @__PURE__ */ new Set();
|
|
6533
6874
|
const invokeKeys = /* @__PURE__ */ new Set();
|
|
@@ -6536,17 +6877,35 @@ function createObjectDriver(renderer = "object") {
|
|
|
6536
6877
|
const separator = key.indexOf(":");
|
|
6537
6878
|
return [Number(key.slice(0, separator)), key.slice(separator + 1)];
|
|
6538
6879
|
};
|
|
6539
|
-
const
|
|
6880
|
+
const DETACHED = /* @__PURE__ */ Symbol("octane.object-driver.detached");
|
|
6881
|
+
const parentChanges = /* @__PURE__ */ new Map();
|
|
6882
|
+
let rootChildren = null;
|
|
6883
|
+
const readParent = (id) => {
|
|
6884
|
+
if (parentChanges.has(id)) return parentChanges.get(id);
|
|
6885
|
+
return state.parents.has(id) ? state.parents.get(id) : DETACHED;
|
|
6886
|
+
};
|
|
6540
6887
|
const simulatedChildren = (parent) => {
|
|
6541
|
-
if (parent === null)
|
|
6542
|
-
|
|
6888
|
+
if (parent === null) {
|
|
6889
|
+
return rootChildren ??= container.children.map((child) => child.id);
|
|
6890
|
+
}
|
|
6891
|
+
const value = readSimulated(parent);
|
|
6543
6892
|
if (value === void 0) throw new Error(`Object driver: unknown parent ${parent}.`);
|
|
6544
6893
|
return value.children;
|
|
6545
6894
|
};
|
|
6895
|
+
const detachSimulated = (id) => {
|
|
6896
|
+
const parent = readParent(id);
|
|
6897
|
+
if (parent === DETACHED) return;
|
|
6898
|
+
const children = simulatedChildren(parent);
|
|
6899
|
+
const index = children.indexOf(id);
|
|
6900
|
+
if (index === -1) throw new Error(`Object driver: child ${id} is not attached.`);
|
|
6901
|
+
children.splice(index, 1);
|
|
6902
|
+
parentChanges.set(id, DETACHED);
|
|
6903
|
+
};
|
|
6546
6904
|
for (const command of batch.commands) {
|
|
6547
6905
|
if (command.op === "create") {
|
|
6548
|
-
if (
|
|
6906
|
+
if (hasSimulated(command.id))
|
|
6549
6907
|
throw new Error(`Object driver: duplicate id ${command.id}.`);
|
|
6908
|
+
destroyed.delete(command.id);
|
|
6550
6909
|
simulated.set(command.id, {
|
|
6551
6910
|
type: command.type,
|
|
6552
6911
|
props: command.props,
|
|
@@ -6564,11 +6923,11 @@ function createObjectDriver(renderer = "object") {
|
|
|
6564
6923
|
children: []
|
|
6565
6924
|
});
|
|
6566
6925
|
} else if (command.op === "update") {
|
|
6567
|
-
const value =
|
|
6926
|
+
const value = readSimulated(command.id);
|
|
6568
6927
|
if (value === void 0) throw new Error(`Object driver: unknown update ${command.id}.`);
|
|
6569
6928
|
value.props = command.props;
|
|
6570
6929
|
} else if (command.op === "recreate") {
|
|
6571
|
-
const value =
|
|
6930
|
+
const value = readSimulated(command.id);
|
|
6572
6931
|
const current = state.instances.get(command.id);
|
|
6573
6932
|
if (value === void 0 || current === void 0) {
|
|
6574
6933
|
throw new Error(`Object driver: unknown recreate ${command.id}.`);
|
|
@@ -6589,25 +6948,25 @@ function createObjectDriver(renderer = "object") {
|
|
|
6589
6948
|
invokeKeys.add(keyFor(command.id, type));
|
|
6590
6949
|
}
|
|
6591
6950
|
} else if (command.op === "visibility") {
|
|
6592
|
-
const value =
|
|
6951
|
+
const value = readSimulated(command.id);
|
|
6593
6952
|
if (value === void 0) {
|
|
6594
6953
|
throw new Error(`Object driver: unknown visibility target ${command.id}.`);
|
|
6595
6954
|
}
|
|
6596
6955
|
value.visible = command.state === "visible";
|
|
6597
6956
|
} else if (command.op === "event") {
|
|
6598
|
-
const value =
|
|
6957
|
+
const value = readSimulated(command.id);
|
|
6599
6958
|
if (value === void 0)
|
|
6600
6959
|
throw new Error(`Object driver: unknown event target ${command.id}.`);
|
|
6601
6960
|
if (command.listener === null) value.events.delete(command.type);
|
|
6602
6961
|
else value.events.set(command.type, command.listener);
|
|
6603
6962
|
} else if (command.op === "lifecycle") {
|
|
6604
|
-
const value =
|
|
6963
|
+
const value = readSimulated(command.id);
|
|
6605
6964
|
if (value === void 0)
|
|
6606
6965
|
throw new Error(`Object driver: unknown lifecycle target ${command.id}.`);
|
|
6607
6966
|
if (command.listener === null) value.lifecycles.delete(command.type);
|
|
6608
6967
|
else value.lifecycles.set(command.type, command.listener);
|
|
6609
6968
|
} else if (command.op === "local-callback") {
|
|
6610
|
-
const value =
|
|
6969
|
+
const value = readSimulated(command.id);
|
|
6611
6970
|
if (value === void 0)
|
|
6612
6971
|
throw new Error(`Object driver: unknown local callback target ${command.id}.`);
|
|
6613
6972
|
const key = keyFor(command.id, command.type);
|
|
@@ -6621,21 +6980,16 @@ function createObjectDriver(renderer = "object") {
|
|
|
6621
6980
|
if (command.parent !== null && typeof command.parent !== "number") {
|
|
6622
6981
|
throw new Error("Object driver does not support portal target parents.");
|
|
6623
6982
|
}
|
|
6624
|
-
if (!
|
|
6983
|
+
if (!hasSimulated(command.id))
|
|
6625
6984
|
throw new Error(`Object driver: unknown child ${command.id}.`);
|
|
6626
|
-
|
|
6627
|
-
rootChildren,
|
|
6628
|
-
...[...simulated.values()].map((entry) => entry.children)
|
|
6629
|
-
]) {
|
|
6630
|
-
const old = value.indexOf(command.id);
|
|
6631
|
-
if (old !== -1) value.splice(old, 1);
|
|
6632
|
-
}
|
|
6985
|
+
detachSimulated(command.id);
|
|
6633
6986
|
const children = simulatedChildren(command.parent);
|
|
6634
6987
|
const before = command.before === null ? children.length : children.indexOf(command.before);
|
|
6635
6988
|
if (before === -1) throw new Error(`Object driver: unknown before id ${command.before}.`);
|
|
6636
6989
|
children.splice(before, 0, command.id);
|
|
6990
|
+
parentChanges.set(command.id, command.parent);
|
|
6637
6991
|
if (command.op === "move") {
|
|
6638
|
-
for (const type of
|
|
6992
|
+
for (const type of readSimulated(command.id).localCallbacks.keys()) {
|
|
6639
6993
|
const key = keyFor(command.id, type);
|
|
6640
6994
|
cleanupKeys.add(key);
|
|
6641
6995
|
invokeKeys.add(key);
|
|
@@ -6649,26 +7003,22 @@ function createObjectDriver(renderer = "object") {
|
|
|
6649
7003
|
const index = children.indexOf(command.id);
|
|
6650
7004
|
if (index === -1) throw new Error(`Object driver: child ${command.id} is not attached.`);
|
|
6651
7005
|
children.splice(index, 1);
|
|
6652
|
-
|
|
7006
|
+
parentChanges.set(command.id, DETACHED);
|
|
7007
|
+
for (const type of readSimulated(command.id).localCallbacks.keys()) {
|
|
6653
7008
|
cleanupKeys.add(keyFor(command.id, type));
|
|
6654
7009
|
}
|
|
6655
7010
|
} else if (command.op === "destroy") {
|
|
6656
|
-
const instance =
|
|
7011
|
+
const instance = readSimulated(command.id);
|
|
6657
7012
|
if (instance === void 0)
|
|
6658
7013
|
throw new Error(`Object driver: unknown destroy ${command.id}.`);
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
...[...simulated.values()].map((entry) => entry.children)
|
|
6662
|
-
]) {
|
|
6663
|
-
const attached = value.indexOf(command.id);
|
|
6664
|
-
if (attached !== -1) value.splice(attached, 1);
|
|
6665
|
-
}
|
|
7014
|
+
detachSimulated(command.id);
|
|
7015
|
+
for (const child of instance.children) parentChanges.set(child, DETACHED);
|
|
6666
7016
|
instance.children.length = 0;
|
|
6667
|
-
|
|
7017
|
+
destroyed.add(command.id);
|
|
6668
7018
|
}
|
|
6669
7019
|
}
|
|
6670
7020
|
for (const [id, instance] of stagedInstances) {
|
|
6671
|
-
const staged =
|
|
7021
|
+
const staged = readSimulated(id);
|
|
6672
7022
|
if (staged === void 0) continue;
|
|
6673
7023
|
instance.visible = staged.visible;
|
|
6674
7024
|
instance.children.splice(
|
|
@@ -6681,6 +7031,16 @@ function createObjectDriver(renderer = "object") {
|
|
|
6681
7031
|
}
|
|
6682
7032
|
let status = "prepared";
|
|
6683
7033
|
let acceptedCallbacksRan = false;
|
|
7034
|
+
const liveChildren = (parent) => objectChildren(container, parent, state.instances);
|
|
7035
|
+
const detachLive = (id) => {
|
|
7036
|
+
if (!state.parents.has(id)) return;
|
|
7037
|
+
const parent = state.parents.get(id);
|
|
7038
|
+
const instance = state.instances.get(id);
|
|
7039
|
+
const children = liveChildren(parent);
|
|
7040
|
+
const index = children.indexOf(instance);
|
|
7041
|
+
if (index !== -1) children.splice(index, 1);
|
|
7042
|
+
state.parents.delete(id);
|
|
7043
|
+
};
|
|
6684
7044
|
return {
|
|
6685
7045
|
apply() {
|
|
6686
7046
|
if (status !== "prepared") return;
|
|
@@ -6697,7 +7057,11 @@ function createObjectDriver(renderer = "object") {
|
|
|
6697
7057
|
tasks.push(() => {
|
|
6698
7058
|
for (const command of batch.commands) {
|
|
6699
7059
|
if (command.op === "create") {
|
|
6700
|
-
|
|
7060
|
+
const instance = stagedInstances.get(command.id);
|
|
7061
|
+
state.instances.set(command.id, instance);
|
|
7062
|
+
for (const child of instance.children) {
|
|
7063
|
+
state.parents.set(child.id, command.id);
|
|
7064
|
+
}
|
|
6701
7065
|
state.events.set(command.id, /* @__PURE__ */ new Map());
|
|
6702
7066
|
state.lifecycles.set(command.id, /* @__PURE__ */ new Map());
|
|
6703
7067
|
state.localCallbacks.set(command.id, /* @__PURE__ */ new Map());
|
|
@@ -6707,10 +7071,8 @@ function createObjectDriver(renderer = "object") {
|
|
|
6707
7071
|
} else if (command.op === "recreate") {
|
|
6708
7072
|
const previous = state.instances.get(command.id);
|
|
6709
7073
|
const replacement = stagedInstances.get(command.id);
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
...[...state.instances.values()].map((entry) => entry.children)
|
|
6713
|
-
]) {
|
|
7074
|
+
if (state.parents.has(command.id)) {
|
|
7075
|
+
const parent = liveChildren(state.parents.get(command.id));
|
|
6714
7076
|
const index = parent.indexOf(previous);
|
|
6715
7077
|
if (index !== -1) parent[index] = replacement;
|
|
6716
7078
|
}
|
|
@@ -6735,33 +7097,25 @@ function createObjectDriver(renderer = "object") {
|
|
|
6735
7097
|
throw new Error("Object driver does not support portal target parents.");
|
|
6736
7098
|
}
|
|
6737
7099
|
const instance = state.instances.get(command.id);
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
...[...state.instances.values()].map((entry) => entry.children)
|
|
6741
|
-
]) {
|
|
6742
|
-
const old = parent.indexOf(instance);
|
|
6743
|
-
if (old !== -1) parent.splice(old, 1);
|
|
6744
|
-
}
|
|
6745
|
-
const children = objectChildren(container, command.parent, state.instances);
|
|
7100
|
+
detachLive(command.id);
|
|
7101
|
+
const children = liveChildren(command.parent);
|
|
6746
7102
|
const before = command.before === null ? children.length : children.indexOf(state.instances.get(command.before));
|
|
6747
7103
|
children.splice(before, 0, instance);
|
|
7104
|
+
state.parents.set(command.id, command.parent);
|
|
6748
7105
|
} else if (command.op === "remove") {
|
|
6749
7106
|
if (command.parent !== null && typeof command.parent !== "number") {
|
|
6750
7107
|
throw new Error("Object driver does not support portal target parents.");
|
|
6751
7108
|
}
|
|
6752
|
-
const children =
|
|
7109
|
+
const children = liveChildren(command.parent);
|
|
6753
7110
|
children.splice(children.indexOf(state.instances.get(command.id)), 1);
|
|
7111
|
+
state.parents.delete(command.id);
|
|
6754
7112
|
} else if (command.op === "destroy") {
|
|
6755
7113
|
const instance = state.instances.get(command.id);
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
...[...state.instances.values()].map((entry) => entry.children)
|
|
6759
|
-
]) {
|
|
6760
|
-
const attached = parent.indexOf(instance);
|
|
6761
|
-
if (attached !== -1) parent.splice(attached, 1);
|
|
6762
|
-
}
|
|
7114
|
+
detachLive(command.id);
|
|
7115
|
+
for (const child of instance.children) state.parents.delete(child.id);
|
|
6763
7116
|
instance.children.length = 0;
|
|
6764
7117
|
state.instances.delete(command.id);
|
|
7118
|
+
state.parents.delete(command.id);
|
|
6765
7119
|
state.events.delete(command.id);
|
|
6766
7120
|
state.lifecycles.delete(command.id);
|
|
6767
7121
|
state.localCallbacks.delete(command.id);
|
|
@@ -6782,13 +7136,8 @@ function createObjectDriver(renderer = "object") {
|
|
|
6782
7136
|
const listener = state.localCallbacks.get(id)?.get(type);
|
|
6783
7137
|
if (instance === void 0 || listener === void 0) continue;
|
|
6784
7138
|
tasks.push(() => {
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
if (candidate.children.includes(instance)) {
|
|
6788
|
-
parent = candidate;
|
|
6789
|
-
break;
|
|
6790
|
-
}
|
|
6791
|
-
}
|
|
7139
|
+
const parentId = state.parents.get(id);
|
|
7140
|
+
const parent = parentId == null ? null : state.instances.get(parentId) ?? null;
|
|
6792
7141
|
const cleanup = context.invokeLocalCallback(listener.id, [parent, instance]);
|
|
6793
7142
|
if (cleanup == null) return;
|
|
6794
7143
|
if (typeof cleanup !== "function") {
|