@remix-run/ui 0.4.0 → 0.5.0
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/README.md +74 -1
- package/dist/accordion/index.js +2 -2
- package/dist/accordion/primitives.d.ts +1 -1
- package/dist/accordion/primitives.js.map +1 -1
- package/dist/anchor/index.js.map +1 -1
- package/dist/animation/animate-layout-mixin.js +1 -1
- package/dist/animation/animate-layout-mixin.js.map +1 -1
- package/dist/animation/animate-mixins.js +2 -2
- package/dist/animation/animate-mixins.js.map +1 -1
- package/dist/animation/demos/color-interpolation.js +1 -1
- package/dist/animation/demos/color-interpolation.js.map +1 -1
- package/dist/animation/demos/drag-release.d.ts +1 -1
- package/dist/animation/demos/hold-to-confirm.d.ts +3 -3
- package/dist/animation/demos/material-ripple.js +1 -3
- package/dist/animation/demos/material-ripple.js.map +1 -1
- package/dist/animation/index.js +4 -4
- package/dist/animation/spring.js.map +1 -1
- package/dist/breadcrumbs/index.js +2 -2
- package/dist/button/index.js +25 -25
- package/dist/button/index.js.map +1 -1
- package/dist/checkbox/index.js +11 -9
- package/dist/checkbox/index.js.map +1 -1
- package/dist/combobox/index.js +4 -4
- package/dist/combobox/index.js.map +1 -1
- package/dist/combobox/primitives.d.ts +1 -1
- package/dist/combobox/primitives.js +5 -5
- package/dist/combobox/primitives.js.map +1 -1
- package/dist/dev/refresh.d.ts +1 -0
- package/dist/dev/refresh.js +2 -0
- package/dist/dev/refresh.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -14
- package/dist/input/index.js +9 -9
- package/dist/input/index.js.map +1 -1
- package/dist/jsx-runtime.js +2 -2
- package/dist/listbox/index.js +2 -2
- package/dist/menu/hover-aim.js.map +1 -1
- package/dist/menu/index.js +3 -3
- package/dist/menu/primitives.d.ts +1 -1
- package/dist/menu/primitives.js +6 -6
- package/dist/menu/primitives.js.map +1 -1
- package/dist/popover/index.js +3 -3
- package/dist/popover/scroll-lock.js.map +1 -1
- package/dist/radio/index.js +7 -7
- package/dist/radio/index.js.map +1 -1
- package/dist/runtime/client-entry-boundary.d.ts +14 -0
- package/dist/runtime/client-entry-boundary.js +29 -0
- package/dist/runtime/client-entry-boundary.js.map +1 -0
- package/dist/runtime/component.d.ts +19 -4
- package/dist/runtime/component.js +39 -9
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/attributes.js +36 -3
- package/dist/runtime/core/attributes.js.map +1 -1
- package/dist/runtime/core/children.d.ts +2 -0
- package/dist/runtime/core/children.js +26 -2
- package/dist/runtime/core/children.js.map +1 -1
- package/dist/runtime/core/props.js +2 -2
- package/dist/runtime/core/vnode.d.ts +3 -3
- package/dist/runtime/core/vnode.js +22 -1
- package/dist/runtime/core/vnode.js.map +1 -1
- package/dist/runtime/create-element.d.ts +2 -2
- package/dist/runtime/create-element.js +3 -2
- package/dist/runtime/create-element.js.map +1 -1
- package/dist/runtime/diff-dom.js +294 -219
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/diff-props.js +3 -3
- package/dist/runtime/dom.d.ts +12 -0
- package/dist/runtime/element-function.d.ts +3 -0
- package/dist/runtime/element-function.js +2 -0
- package/dist/runtime/element-function.js.map +1 -0
- package/dist/runtime/form-navigation.d.ts +25 -0
- package/dist/runtime/form-navigation.js +132 -0
- package/dist/runtime/form-navigation.js.map +1 -0
- package/dist/runtime/frame-resolution.d.ts +5 -0
- package/dist/runtime/frame-resolution.js +10 -0
- package/dist/runtime/frame-resolution.js.map +1 -0
- package/dist/runtime/frame.d.ts +58 -15
- package/dist/runtime/frame.js +367 -114
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/jsx.d.ts +1 -1
- package/dist/runtime/jsx.js +1 -1
- package/dist/runtime/jsx.js.map +1 -1
- package/dist/runtime/key.d.ts +1 -0
- package/dist/runtime/key.js +2 -0
- package/dist/runtime/key.js.map +1 -0
- package/dist/runtime/mixins/attrs-mixin.js +2 -2
- package/dist/runtime/mixins/link-mixin.js +4 -3
- package/dist/runtime/mixins/link-mixin.js.map +1 -1
- package/dist/runtime/mixins/mixin.d.ts +15 -10
- package/dist/runtime/mixins/mixin.js +4 -4
- package/dist/runtime/mixins/mixin.js.map +1 -1
- package/dist/runtime/mixins/on-mixin.js +1 -1
- package/dist/runtime/mixins/ref-mixin.js +1 -1
- package/dist/runtime/navigation.d.ts +4 -1
- package/dist/runtime/navigation.js +157 -32
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.d.ts +11 -10
- package/dist/runtime/reconcile.js +549 -421
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/refresh.d.ts +28 -0
- package/dist/runtime/refresh.js +31 -0
- package/dist/runtime/refresh.js.map +1 -0
- package/dist/runtime/render.js +1 -1
- package/dist/runtime/render.js.map +1 -1
- package/dist/runtime/run.d.ts +3 -1
- package/dist/runtime/run.js +15 -7
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/scheduler.js +8 -16
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/to-vnode.d.ts +2 -2
- package/dist/runtime/to-vnode.js +68 -20
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/vdom.d.ts +4 -2
- package/dist/runtime/vdom.js +87 -42
- package/dist/runtime/vdom.js.map +1 -1
- package/dist/runtime/vnode.d.ts +138 -67
- package/dist/runtime/vnode.js +17 -12
- package/dist/runtime/vnode.js.map +1 -1
- package/dist/select/index.js +11 -11
- package/dist/select/index.js.map +1 -1
- package/dist/select/primitives.d.ts +1 -1
- package/dist/select/primitives.js +6 -6
- package/dist/server/stream.js +20 -27
- package/dist/server/stream.js.map +1 -1
- package/dist/shared/focus-styles.d.ts +1 -1
- package/dist/shared/focus-styles.js +1 -1
- package/dist/shared/focus-styles.js.map +1 -1
- package/dist/shared/listbox-popover-styles.js +1 -1
- package/dist/shared/style-values.js +26 -26
- package/dist/shared/style-values.js.map +1 -1
- package/dist/style/css-mixin.js +3 -3
- package/dist/style/index.js +2 -2
- package/dist/style/style.js +25 -6
- package/dist/style/style.js.map +1 -1
- package/dist/style/stylesheet.d.ts +0 -1
- package/dist/style/stylesheet.js +13 -54
- package/dist/style/stylesheet.js.map +1 -1
- package/dist/tabs/index.js +11 -11
- package/dist/tabs/index.js.map +1 -1
- package/dist/tabs/primitives.d.ts +1 -1
- package/dist/test.js +1 -1
- package/dist/toggle/index.js +9 -9
- package/dist/toggle/index.js.map +1 -1
- package/dist/toggle/primitives.d.ts +1 -1
- package/package.json +10 -7
- package/src/animation/animate-mixins.ts +3 -3
- package/src/animation/demos/color-interpolation.tsx +1 -1
- package/src/button/index.ts +24 -24
- package/src/checkbox/index.ts +10 -8
- package/src/combobox/index.tsx +1 -1
- package/src/dev/refresh.ts +1 -0
- package/src/index.ts +1 -1
- package/src/input/index.ts +8 -8
- package/src/radio/index.ts +6 -5
- package/src/runtime/client-entry-boundary.ts +54 -0
- package/src/runtime/component.ts +65 -16
- package/src/runtime/core/attributes.ts +35 -1
- package/src/runtime/core/children.ts +24 -2
- package/src/runtime/core/vnode.ts +25 -4
- package/src/runtime/create-element.ts +6 -5
- package/src/runtime/demos/readme.demo.tsx +4 -4
- package/src/runtime/diff-dom.ts +358 -243
- package/src/runtime/dom.ts +331 -214
- package/src/runtime/element-function.ts +1 -0
- package/src/runtime/event-listeners.ts +1 -1
- package/src/runtime/form-navigation.ts +184 -0
- package/src/runtime/frame-resolution.ts +13 -0
- package/src/runtime/frame.ts +482 -124
- package/src/runtime/jsx.ts +3 -5
- package/src/runtime/key.ts +1 -0
- package/src/runtime/mixins/link-mixin.ts +1 -0
- package/src/runtime/mixins/mixin.ts +21 -18
- package/src/runtime/navigation.ts +204 -30
- package/src/runtime/reconcile.ts +762 -759
- package/src/runtime/refresh.ts +46 -0
- package/src/runtime/run.ts +12 -2
- package/src/runtime/scheduler.ts +9 -29
- package/src/runtime/to-vnode.ts +85 -23
- package/src/runtime/vdom.ts +89 -70
- package/src/runtime/vnode.ts +192 -88
- package/src/select/index.tsx +9 -9
- package/src/server/stream.ts +22 -28
- package/src/shared/focus-styles.ts +1 -1
- package/src/shared/style-values.ts +26 -26
- package/src/style/style.ts +25 -6
- package/src/style/stylesheet.ts +32 -57
- package/src/tabs/index.tsx +12 -11
- package/src/test/README.md +151 -60
- package/src/toggle/index.tsx +9 -7
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { createComponent
|
|
2
|
-
import { createFrame } from
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { createComponent } from './component.js';
|
|
2
|
+
import { createFrame, isFrameRuntime } from './frame.js';
|
|
3
|
+
import { unwrapFrameResolution } from './frame-resolution.js';
|
|
4
|
+
import { createRangeRoot } from './vdom.js';
|
|
5
|
+
import { isCommittedComponentNode, isCommittedHostNode, isCommittedTextNode, isFragmentNode, isHostNode, findContextFromAncestry, } from './vnode.js';
|
|
6
|
+
import { invariant } from './invariant.js';
|
|
7
|
+
import { patchHostProps } from './core/props.js';
|
|
8
|
+
import { skipComments, logHydrationMismatch } from './client-entries.js';
|
|
9
|
+
import { toVNode } from './to-vnode.js';
|
|
10
|
+
import { bindMixinRuntime, cancelPendingMixinRemoval, dispatchMixinBeforeUpdate, dispatchMixinCommit, getMixinRuntimeSignal, prepareMixinRemoval, resolveMixedProps, teardownMixins, } from './mixins/mixin.js';
|
|
11
|
+
import { isOnMixinDescriptor } from './mixins/on-mixin.js';
|
|
12
|
+
import { createComponentErrorEvent } from './error-event.js';
|
|
13
|
+
import { componentStalenessCheck } from './refresh.js';
|
|
11
14
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
12
15
|
let idCounter = 0;
|
|
13
16
|
let persistedRemovalToken = 0;
|
|
@@ -15,40 +18,36 @@ const persistedMixinNodes = new Set();
|
|
|
15
18
|
let activeSchedulerUpdateParents;
|
|
16
19
|
// Compute SVG context for a node based on its parent and type.
|
|
17
20
|
// Returns true if the node is within an SVG subtree, false otherwise.
|
|
18
|
-
function getSvgContext(vParent,
|
|
21
|
+
function getSvgContext(vParent, node) {
|
|
19
22
|
// Only host elements (strings) can affect SVG context
|
|
20
|
-
if (
|
|
23
|
+
if (node.kind === 'host') {
|
|
21
24
|
// svg element creates SVG context
|
|
22
|
-
if (
|
|
25
|
+
if (node.type === 'svg')
|
|
23
26
|
return true;
|
|
24
27
|
// foreignObject switches back to HTML context
|
|
25
|
-
if (
|
|
28
|
+
if (node.type === 'foreignObject')
|
|
26
29
|
return false;
|
|
27
30
|
}
|
|
28
31
|
// Otherwise inherit from parent
|
|
29
|
-
return vParent._svg
|
|
32
|
+
return vParent._svg;
|
|
30
33
|
}
|
|
31
34
|
function getHostProps(node) {
|
|
32
|
-
return node._mixedProps
|
|
35
|
+
return '_mixedProps' in node ? node._mixedProps : node.props;
|
|
33
36
|
}
|
|
34
37
|
function markNodePersistedByMixins(node, domParent, token) {
|
|
35
|
-
node.
|
|
36
|
-
node._persistedParentByMixins = domParent;
|
|
37
|
-
node._persistedRemovalToken = token;
|
|
38
|
+
node._persistence = { parent: domParent, token };
|
|
38
39
|
persistedMixinNodes.add(node);
|
|
39
40
|
bindMixinRuntime(node._mixState, undefined);
|
|
40
41
|
}
|
|
41
42
|
function unmarkNodePersistedByMixins(node) {
|
|
42
|
-
node.
|
|
43
|
-
node._persistedParentByMixins = undefined;
|
|
44
|
-
node._persistedRemovalToken = undefined;
|
|
43
|
+
node._persistence = undefined;
|
|
45
44
|
persistedMixinNodes.delete(node);
|
|
46
45
|
}
|
|
47
46
|
function findMatchingPersistedMixinNode(type, key, domParent) {
|
|
48
47
|
if (key == null)
|
|
49
48
|
return null;
|
|
50
49
|
for (let node of persistedMixinNodes) {
|
|
51
|
-
if (node.
|
|
50
|
+
if (node._persistence?.parent !== domParent)
|
|
52
51
|
continue;
|
|
53
52
|
if (node.type !== type)
|
|
54
53
|
continue;
|
|
@@ -59,6 +58,7 @@ function findMatchingPersistedMixinNode(type, key, domParent) {
|
|
|
59
58
|
return null;
|
|
60
59
|
}
|
|
61
60
|
const EMPTY_DIRECT_EVENT_DESCRIPTORS = [];
|
|
61
|
+
const EMPTY_COMMITTED_CHILDREN = [];
|
|
62
62
|
function shouldRestoreControlledReflectionOnInput(node, state) {
|
|
63
63
|
// Some controls dispatch `input` before `change` for the same interaction.
|
|
64
64
|
// When checked/value state is typically handled on `change`, restoring on the
|
|
@@ -152,6 +152,15 @@ function teardownControlledReflection(node) {
|
|
|
152
152
|
state.listenersAttached = false;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
+
// See abandonDirectEventListeners: skips removeEventListener for discarded subtrees.
|
|
156
|
+
function abandonControlledReflection(node) {
|
|
157
|
+
let state = node._controlledState;
|
|
158
|
+
if (!state)
|
|
159
|
+
return;
|
|
160
|
+
state.disposed = true;
|
|
161
|
+
state.pendingRestoreVersion++;
|
|
162
|
+
state.listenersAttached = false;
|
|
163
|
+
}
|
|
155
164
|
function canManageValue(type, element) {
|
|
156
165
|
if (type === 'progress')
|
|
157
166
|
return false;
|
|
@@ -176,23 +185,16 @@ function setPropertyReflection(element, key, value) {
|
|
|
176
185
|
return;
|
|
177
186
|
element[key] = value == null ? '' : value;
|
|
178
187
|
}
|
|
179
|
-
function resolveNodeMixProps(node, frame, scheduler, state) {
|
|
188
|
+
function resolveNodeMixProps(node, parent, frame, scheduler, state) {
|
|
180
189
|
let mix = node.props.mix;
|
|
181
190
|
let directEventDescriptors = resolveDirectEventDescriptors(mix);
|
|
182
191
|
if (directEventDescriptors) {
|
|
183
|
-
if (state)
|
|
192
|
+
if (state)
|
|
184
193
|
teardownMixins(state);
|
|
185
|
-
}
|
|
186
|
-
node._mixState = undefined;
|
|
187
|
-
node._mixedProps = node.props;
|
|
188
|
-
node._directEventDescriptors = directEventDescriptors;
|
|
189
|
-
return node.props;
|
|
194
|
+
return { props: node.props, directEventDescriptors };
|
|
190
195
|
}
|
|
191
|
-
node._directEventDescriptors = undefined;
|
|
192
196
|
if (state == null && (mix == null || (Array.isArray(mix) && mix.length === 0))) {
|
|
193
|
-
node.
|
|
194
|
-
node._mixedProps = node.props;
|
|
195
|
-
return node.props;
|
|
197
|
+
return { props: node.props };
|
|
196
198
|
}
|
|
197
199
|
let resolved = resolveMixedProps({
|
|
198
200
|
hostType: node.type,
|
|
@@ -202,14 +204,17 @@ function resolveNodeMixProps(node, frame, scheduler, state) {
|
|
|
202
204
|
if (typeof type !== 'function') {
|
|
203
205
|
return undefined;
|
|
204
206
|
}
|
|
205
|
-
return findContextFromAncestry(
|
|
207
|
+
return findContextFromAncestry(parent, type);
|
|
206
208
|
},
|
|
207
209
|
props: node.props,
|
|
208
210
|
state,
|
|
209
211
|
});
|
|
210
|
-
|
|
212
|
+
return { props: resolved.props, mixState: resolved.state };
|
|
213
|
+
}
|
|
214
|
+
function applyResolvedHostProps(node, resolved) {
|
|
211
215
|
node._mixedProps = resolved.props;
|
|
212
|
-
|
|
216
|
+
node._mixState = resolved.mixState;
|
|
217
|
+
node._directEventDescriptors = resolved.directEventDescriptors;
|
|
213
218
|
}
|
|
214
219
|
function resolveDirectEventDescriptors(mix) {
|
|
215
220
|
if (!mix)
|
|
@@ -220,8 +225,8 @@ function resolveDirectEventDescriptors(mix) {
|
|
|
220
225
|
return areOnMixinDescriptors(mix) ? mix : null;
|
|
221
226
|
}
|
|
222
227
|
function areOnMixinDescriptors(descriptors) {
|
|
223
|
-
for (let
|
|
224
|
-
if (!isOnMixinDescriptor(
|
|
228
|
+
for (let i = 0; i < descriptors.length; i++) {
|
|
229
|
+
if (!isOnMixinDescriptor(descriptors[i]))
|
|
225
230
|
return false;
|
|
226
231
|
}
|
|
227
232
|
return true;
|
|
@@ -237,11 +242,12 @@ function enqueueMixinBindingUpdate(done) {
|
|
|
237
242
|
}
|
|
238
243
|
dispatchMixinBeforeUpdate(state);
|
|
239
244
|
let prevProps = getHostProps(node);
|
|
240
|
-
let
|
|
241
|
-
|
|
242
|
-
|
|
245
|
+
let resolved = resolveNodeMixProps(node, node._parent, this.frame, this.scheduler, state);
|
|
246
|
+
applyResolvedHostProps(node, resolved);
|
|
247
|
+
patchHostProps(prevProps, resolved.props, this.node);
|
|
248
|
+
if (node._controlledState || shouldTrackControlledReflection(resolved.props)) {
|
|
243
249
|
ensureControlledReflection(node, this.scheduler);
|
|
244
|
-
syncControlledReflection(node,
|
|
250
|
+
syncControlledReflection(node, resolved.props);
|
|
245
251
|
}
|
|
246
252
|
dispatchMixinCommit(state);
|
|
247
253
|
done(state ? getMixinRuntimeSignal(state) : AbortSignal.abort());
|
|
@@ -252,7 +258,7 @@ function bindNodeMixRuntime(node, frame, scheduler, styles, reclaimed = false, p
|
|
|
252
258
|
let state = node._mixState;
|
|
253
259
|
bindMixinRuntime(state, {
|
|
254
260
|
node: node._dom,
|
|
255
|
-
parent: parent ?? node._dom
|
|
261
|
+
parent: parent ?? getRequiredDomParent(node._dom),
|
|
256
262
|
key: node.key,
|
|
257
263
|
target: node,
|
|
258
264
|
frame,
|
|
@@ -267,6 +273,11 @@ function isHeadHostNode(node) {
|
|
|
267
273
|
return false;
|
|
268
274
|
return node.type.toLowerCase() === 'head';
|
|
269
275
|
}
|
|
276
|
+
function getRequiredDomParent(node) {
|
|
277
|
+
let parent = node.parentNode;
|
|
278
|
+
invariant(parent, 'Expected mounted host node to have a DOM parent');
|
|
279
|
+
return parent;
|
|
280
|
+
}
|
|
270
281
|
function getDocumentHead(domParent) {
|
|
271
282
|
if (domParent instanceof Document) {
|
|
272
283
|
return domParent.head;
|
|
@@ -276,65 +287,112 @@ function getDocumentHead(domParent) {
|
|
|
276
287
|
}
|
|
277
288
|
return null;
|
|
278
289
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
290
|
+
function commitNonRenderNode(node, parent, svg) {
|
|
291
|
+
let committed = node;
|
|
292
|
+
committed._parent = parent;
|
|
293
|
+
committed._svg = svg;
|
|
294
|
+
return committed;
|
|
295
|
+
}
|
|
296
|
+
function commitTextNode(node, parent, svg, dom) {
|
|
297
|
+
let committed = node;
|
|
298
|
+
committed._parent = parent;
|
|
299
|
+
committed._svg = svg;
|
|
300
|
+
committed._dom = dom;
|
|
301
|
+
return committed;
|
|
302
|
+
}
|
|
303
|
+
function beginFragmentNode(node, parent, svg) {
|
|
304
|
+
let committed = node;
|
|
305
|
+
committed._parent = parent;
|
|
306
|
+
committed._svg = svg;
|
|
307
|
+
committed._children = EMPTY_COMMITTED_CHILDREN;
|
|
308
|
+
return committed;
|
|
309
|
+
}
|
|
310
|
+
function commitHostNode(node, parent, svg, dom, resolved, children = EMPTY_COMMITTED_CHILDREN) {
|
|
311
|
+
let committed = node;
|
|
312
|
+
committed._parent = parent;
|
|
313
|
+
committed._svg = svg;
|
|
314
|
+
committed._dom = dom;
|
|
315
|
+
committed._children = children;
|
|
316
|
+
committed._mixedProps = resolved.props;
|
|
317
|
+
committed._mixState = resolved.mixState;
|
|
318
|
+
committed._directEventDescriptors = resolved.directEventDescriptors;
|
|
319
|
+
return committed;
|
|
320
|
+
}
|
|
321
|
+
function beginComponentNode(node, parent, svg, handle, context) {
|
|
322
|
+
let mounting = node;
|
|
323
|
+
mounting._parent = parent;
|
|
324
|
+
mounting._svg = svg;
|
|
325
|
+
mounting._handle = handle;
|
|
326
|
+
mounting._context = context;
|
|
327
|
+
return mounting;
|
|
328
|
+
}
|
|
329
|
+
function commitComponentNode(node, content) {
|
|
330
|
+
let committed = node;
|
|
331
|
+
committed._content = content;
|
|
332
|
+
return committed;
|
|
333
|
+
}
|
|
334
|
+
export function diffVNodes(curr, next, domParent, vParent, context, anchor, cursor) {
|
|
283
335
|
if (curr === null) {
|
|
284
|
-
return insert(next, domParent,
|
|
285
|
-
}
|
|
286
|
-
if (curr.type !== next.type) {
|
|
287
|
-
replace(curr, next, domParent, frame, scheduler, styles, vParent, rootTarget, anchor);
|
|
288
|
-
return rootCursor;
|
|
289
|
-
}
|
|
290
|
-
if (isNonRenderNode(curr) && isNonRenderNode(next)) {
|
|
291
|
-
return rootCursor;
|
|
336
|
+
return insert(next, domParent, vParent, context, anchor, cursor);
|
|
292
337
|
}
|
|
293
|
-
if (
|
|
294
|
-
|
|
295
|
-
|
|
338
|
+
if (componentStalenessCheck !== null &&
|
|
339
|
+
curr.kind === 'component' &&
|
|
340
|
+
next.kind === 'component' &&
|
|
341
|
+
componentStalenessCheck(curr.type) === true) {
|
|
342
|
+
return replace(curr, next, domParent, vParent, context, anchor);
|
|
296
343
|
}
|
|
297
|
-
if (
|
|
298
|
-
|
|
299
|
-
return rootCursor;
|
|
344
|
+
if (curr.kind !== next.kind || curr.type !== next.type) {
|
|
345
|
+
return replace(curr, next, domParent, vParent, context, anchor);
|
|
300
346
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
347
|
+
switch (next.kind) {
|
|
348
|
+
case 'host': {
|
|
349
|
+
return diffHost(curr, next, vParent, context);
|
|
350
|
+
}
|
|
351
|
+
case 'text': {
|
|
352
|
+
return diffText(curr, next, vParent, getSvgContext(vParent, next));
|
|
353
|
+
}
|
|
354
|
+
case 'empty': {
|
|
355
|
+
return commitNonRenderNode(next, vParent, getSvgContext(vParent, next));
|
|
356
|
+
}
|
|
357
|
+
case 'fragment': {
|
|
358
|
+
let childInputs = next._children;
|
|
359
|
+
let committed = beginFragmentNode(next, vParent, getSvgContext(vParent, next));
|
|
360
|
+
committed._children = diffChildren(curr._children, childInputs, domParent, committed, context, undefined, anchor);
|
|
361
|
+
return committed;
|
|
362
|
+
}
|
|
363
|
+
case 'frame': {
|
|
364
|
+
return diffFrame(curr, next, domParent, vParent, context, getSvgContext(vParent, next), anchor);
|
|
365
|
+
}
|
|
366
|
+
case 'component': {
|
|
367
|
+
return diffComponent(curr, next, domParent, vParent, context, getSvgContext(vParent, next), anchor, cursor);
|
|
368
|
+
}
|
|
312
369
|
}
|
|
313
|
-
invariant(false, 'Unexpected diff case');
|
|
314
370
|
}
|
|
315
|
-
function replace(curr, next, domParent,
|
|
371
|
+
function replace(curr, next, domParent, vParent, context, anchor) {
|
|
316
372
|
let currAnchor = findFirstDomAnchor(curr);
|
|
317
373
|
if (currAnchor && currAnchor.parentNode === domParent) {
|
|
318
374
|
let replacementAnchor = document.createComment('rmx:replace');
|
|
319
375
|
domParent.insertBefore(replacementAnchor, currAnchor);
|
|
320
376
|
try {
|
|
321
|
-
remove(curr, domParent,
|
|
322
|
-
insert(next, domParent,
|
|
377
|
+
remove(curr, domParent, context);
|
|
378
|
+
return insert(next, domParent, vParent, context, replacementAnchor);
|
|
323
379
|
}
|
|
324
380
|
finally {
|
|
325
381
|
replacementAnchor.parentNode?.removeChild(replacementAnchor);
|
|
326
382
|
}
|
|
327
|
-
return;
|
|
328
383
|
}
|
|
329
384
|
let replacementAnchor = findNextSiblingDomAnchor(curr) ?? anchor;
|
|
330
|
-
remove(curr, domParent,
|
|
331
|
-
insert(next, domParent,
|
|
385
|
+
remove(curr, domParent, context);
|
|
386
|
+
return insert(next, domParent, vParent, context, replacementAnchor);
|
|
332
387
|
}
|
|
333
|
-
function diffHost(curr, next,
|
|
388
|
+
function diffHost(curr, next, vParent, context) {
|
|
389
|
+
let { frame, scheduler, styles } = context;
|
|
334
390
|
let mixState = curr._mixState;
|
|
335
391
|
let currProps = getHostProps(curr);
|
|
336
|
-
let
|
|
337
|
-
let
|
|
392
|
+
let resolved = resolveNodeMixProps(next, vParent, frame, scheduler, mixState);
|
|
393
|
+
let childInputs = next._children;
|
|
394
|
+
let nextProps = resolved.props;
|
|
395
|
+
let nextMixState = resolved.mixState;
|
|
338
396
|
let shouldDispatchMixinLifecycle = (nextMixState?.runners.length ?? 0) > 0 && shouldDispatchInlineMixinLifecycle(curr._dom);
|
|
339
397
|
if (shouldDispatchMixinLifecycle) {
|
|
340
398
|
dispatchMixinBeforeUpdate(nextMixState);
|
|
@@ -350,34 +408,30 @@ function diffHost(curr, next, frame, scheduler, styles, vParent, rootTarget) {
|
|
|
350
408
|
// innerHTML was removed, clear it before adding children
|
|
351
409
|
curr._dom.innerHTML = '';
|
|
352
410
|
}
|
|
353
|
-
|
|
411
|
+
let committed = commitHostNode(next, vParent, getSvgContext(vParent, next), curr._dom, resolved);
|
|
412
|
+
committed._directEventState = curr._directEventState;
|
|
413
|
+
committed._controlledState = curr._controlledState;
|
|
414
|
+
committed._children = diffChildren(curr._children, childInputs, curr._dom, committed, context);
|
|
354
415
|
patchHostProps(currProps, nextProps, curr._dom);
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
ensureControlledReflection(next, scheduler);
|
|
363
|
-
syncControlledReflection(next, nextProps);
|
|
364
|
-
}
|
|
365
|
-
if (next._mixState) {
|
|
366
|
-
bindNodeMixRuntime(next, frame, scheduler, styles);
|
|
416
|
+
syncDirectEventListeners(committed);
|
|
417
|
+
if (committed._controlledState || shouldTrackControlledReflection(nextProps)) {
|
|
418
|
+
ensureControlledReflection(committed, scheduler);
|
|
419
|
+
syncControlledReflection(committed, nextProps);
|
|
420
|
+
}
|
|
421
|
+
if (committed._mixState) {
|
|
422
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles);
|
|
367
423
|
}
|
|
368
424
|
if (shouldDispatchMixinLifecycle) {
|
|
369
425
|
scheduler.enqueueCommitPhase([() => dispatchMixinCommit(nextMixState)]);
|
|
370
426
|
}
|
|
371
|
-
return;
|
|
427
|
+
return committed;
|
|
372
428
|
}
|
|
373
|
-
function setupHostNode(node,
|
|
374
|
-
node._dom = dom;
|
|
429
|
+
function setupHostNode(node, scheduler) {
|
|
375
430
|
let props = getHostProps(node);
|
|
376
|
-
|
|
377
|
-
syncDirectEventListeners(committedNode);
|
|
431
|
+
syncDirectEventListeners(node);
|
|
378
432
|
if (shouldTrackControlledReflection(props)) {
|
|
379
|
-
ensureControlledReflection(
|
|
380
|
-
syncControlledReflection(
|
|
433
|
+
ensureControlledReflection(node, scheduler);
|
|
434
|
+
syncControlledReflection(node, props);
|
|
381
435
|
}
|
|
382
436
|
}
|
|
383
437
|
function syncDirectEventListeners(node) {
|
|
@@ -397,8 +451,12 @@ function syncDirectEventListeners(node) {
|
|
|
397
451
|
}
|
|
398
452
|
let bindings = state.bindings;
|
|
399
453
|
for (let index = 0; index < descriptors.length; index++) {
|
|
400
|
-
|
|
401
|
-
|
|
454
|
+
// Indexed access instead of array destructuring: destructuring goes through
|
|
455
|
+
// the iterator protocol and allocates on every host-node update.
|
|
456
|
+
let args = descriptors[index].args;
|
|
457
|
+
let type = args[0];
|
|
458
|
+
let handler = args[1];
|
|
459
|
+
let captureBoolean = args[2] ?? false;
|
|
402
460
|
let binding = bindings[index];
|
|
403
461
|
if (!binding) {
|
|
404
462
|
binding = createDirectEventBinding(type, handler, captureBoolean);
|
|
@@ -457,258 +515,286 @@ function teardownDirectEventListeners(node) {
|
|
|
457
515
|
state.bindings.length = 0;
|
|
458
516
|
node._directEventState = undefined;
|
|
459
517
|
}
|
|
518
|
+
// Teardown for a node whose DOM subtree is being discarded wholesale: abort
|
|
519
|
+
// pending handler work but skip removeEventListener — the listeners die with
|
|
520
|
+
// the detached node, and removing them one-by-one dominates large teardowns.
|
|
521
|
+
function abandonDirectEventListeners(node) {
|
|
522
|
+
let state = node._directEventState;
|
|
523
|
+
if (!state)
|
|
524
|
+
return;
|
|
525
|
+
for (let binding of state.bindings) {
|
|
526
|
+
binding.reentry?.abort(new DOMException('', 'AbortError'));
|
|
527
|
+
binding.reentry = null;
|
|
528
|
+
}
|
|
529
|
+
state.bindings.length = 0;
|
|
530
|
+
node._directEventState = undefined;
|
|
531
|
+
}
|
|
460
532
|
function invokeDirectEventBinding(binding, event) {
|
|
461
533
|
binding.reentry?.abort(new DOMException('', 'EventReentry'));
|
|
462
534
|
binding.reentry = new AbortController();
|
|
463
535
|
void binding.handler(event, binding.reentry.signal);
|
|
464
536
|
}
|
|
465
|
-
function diffText(curr, next, vParent) {
|
|
537
|
+
function diffText(curr, next, vParent, svg) {
|
|
466
538
|
if (curr._text !== next._text) {
|
|
467
539
|
curr._dom.textContent = next._text;
|
|
468
540
|
}
|
|
469
|
-
next
|
|
470
|
-
next._parent = vParent;
|
|
541
|
+
return commitTextNode(next, vParent, svg, curr._dom);
|
|
471
542
|
}
|
|
472
|
-
function insert(node, domParent,
|
|
473
|
-
|
|
474
|
-
|
|
543
|
+
function insert(node, domParent, vParent, context, anchor, cursor) {
|
|
544
|
+
let { frame, scheduler, styles } = context;
|
|
545
|
+
let svg = getSvgContext(vParent, node);
|
|
546
|
+
let hydrationNode = cursor?.current;
|
|
475
547
|
// Stop hydration if cursor has reached the anchor (end boundary)
|
|
476
548
|
// Check BEFORE skipComments to prevent escaping range root markers
|
|
477
|
-
if (
|
|
478
|
-
|
|
549
|
+
if (hydrationNode && anchor && hydrationNode === anchor) {
|
|
550
|
+
hydrationNode = null;
|
|
479
551
|
}
|
|
480
552
|
// Preserve frame-start markers for non-Frame nodes too, so a following <Frame>
|
|
481
553
|
// (e.g. the first child of a bare Fragment at a clientEntry boundary) can still
|
|
482
554
|
// claim its rmx:f marker during hydration instead of being re-inserted fresh.
|
|
483
555
|
// A rmx:f marker always belongs to a <Frame>, so no non-Frame node should
|
|
484
556
|
// consume one.
|
|
485
|
-
|
|
557
|
+
hydrationNode = skipCommentsExceptFrameStart(hydrationNode ?? null);
|
|
486
558
|
// Also check after skipComments in case we skipped past the anchor
|
|
487
|
-
if (
|
|
488
|
-
|
|
559
|
+
if (hydrationNode && anchor && hydrationNode === anchor) {
|
|
560
|
+
hydrationNode = null;
|
|
489
561
|
}
|
|
562
|
+
if (cursor)
|
|
563
|
+
cursor.current = hydrationNode;
|
|
490
564
|
let doInsert = anchor
|
|
491
565
|
? (dom) => domParent.insertBefore(dom, anchor)
|
|
492
566
|
: (dom) => domParent.appendChild(dom);
|
|
493
|
-
if (
|
|
494
|
-
return
|
|
567
|
+
if (node.kind === 'empty') {
|
|
568
|
+
return commitNonRenderNode(node, vParent, svg);
|
|
495
569
|
}
|
|
496
|
-
if (
|
|
497
|
-
if (
|
|
498
|
-
node._parent = vParent;
|
|
570
|
+
if (node.kind === 'text') {
|
|
571
|
+
if (hydrationNode instanceof Text) {
|
|
499
572
|
// Handle text node consolidation: server renders adjacent text as single node
|
|
500
573
|
// e.g., <span>Hello {world}</span> → server: "Hello world", client: ["Hello ", "world"]
|
|
501
|
-
if (
|
|
502
|
-
if (
|
|
574
|
+
if (hydrationNode.data !== node._text) {
|
|
575
|
+
if (hydrationNode.data.startsWith(node._text) &&
|
|
576
|
+
node._text.length < hydrationNode.data.length) {
|
|
503
577
|
// Consolidation case: split the text node at the boundary
|
|
504
578
|
// cursor becomes the first part (node._text), remainder is returned for next vnode
|
|
505
|
-
let remainder =
|
|
506
|
-
|
|
507
|
-
|
|
579
|
+
let remainder = hydrationNode.splitText(node._text.length);
|
|
580
|
+
if (cursor)
|
|
581
|
+
cursor.current = remainder;
|
|
582
|
+
return commitTextNode(node, vParent, svg, hydrationNode);
|
|
508
583
|
}
|
|
509
584
|
// Genuine mismatch - correct it
|
|
510
|
-
logHydrationMismatch('text mismatch',
|
|
511
|
-
|
|
585
|
+
logHydrationMismatch('text mismatch', hydrationNode.data, node._text);
|
|
586
|
+
hydrationNode.data = node._text;
|
|
512
587
|
}
|
|
513
|
-
|
|
514
|
-
|
|
588
|
+
if (cursor)
|
|
589
|
+
cursor.current = hydrationNode.nextSibling;
|
|
590
|
+
return commitTextNode(node, vParent, svg, hydrationNode);
|
|
515
591
|
}
|
|
516
592
|
let dom = document.createTextNode(node._text);
|
|
517
|
-
node._dom = dom;
|
|
518
|
-
node._parent = vParent;
|
|
519
593
|
doInsert(dom);
|
|
520
|
-
return
|
|
594
|
+
return commitTextNode(node, vParent, svg, dom);
|
|
521
595
|
}
|
|
522
|
-
if (
|
|
523
|
-
let
|
|
596
|
+
if (node.kind === 'host') {
|
|
597
|
+
let resolved = resolveNodeMixProps(node, vParent, frame, scheduler);
|
|
598
|
+
let hostProps = resolved.props;
|
|
599
|
+
let childInputs = node._children;
|
|
524
600
|
if (isHeadHostNode(node)) {
|
|
525
601
|
let targetHead = getDocumentHead(domParent);
|
|
526
602
|
if (targetHead) {
|
|
527
|
-
let childCursor = cursor;
|
|
528
|
-
if (
|
|
529
|
-
childCursor
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
603
|
+
let childCursor = cursor ? { current: hydrationNode } : undefined;
|
|
604
|
+
if (hydrationNode instanceof Element && hydrationNode.tagName.toLowerCase() === 'head') {
|
|
605
|
+
if (childCursor)
|
|
606
|
+
childCursor.current = hydrationNode.firstChild;
|
|
607
|
+
let nextCursor = hydrationNode.nextSibling;
|
|
608
|
+
if (hydrationNode !== targetHead) {
|
|
609
|
+
while (hydrationNode.firstChild) {
|
|
610
|
+
targetHead.appendChild(hydrationNode.firstChild);
|
|
534
611
|
}
|
|
535
|
-
|
|
612
|
+
hydrationNode.remove();
|
|
536
613
|
}
|
|
537
|
-
cursor
|
|
614
|
+
if (cursor)
|
|
615
|
+
cursor.current = nextCursor;
|
|
538
616
|
}
|
|
617
|
+
let committed = commitHostNode(node, vParent, svg, targetHead, resolved);
|
|
539
618
|
// Render explicit <head> children directly into document.head.
|
|
540
|
-
diffChildren(null,
|
|
619
|
+
committed._children = diffChildren(null, childInputs, targetHead, committed, context, childCursor);
|
|
541
620
|
patchHostProps({}, hostProps, targetHead);
|
|
542
|
-
setupHostNode(
|
|
543
|
-
if (
|
|
544
|
-
bindNodeMixRuntime(
|
|
621
|
+
setupHostNode(committed, scheduler);
|
|
622
|
+
if (committed._mixState) {
|
|
623
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles);
|
|
545
624
|
}
|
|
546
|
-
return
|
|
625
|
+
return committed;
|
|
547
626
|
}
|
|
548
627
|
}
|
|
549
628
|
// Check for matching mixin-persisted node that can be reclaimed
|
|
550
629
|
let persistedNode = findMatchingPersistedMixinNode(node.type, node.key, domParent);
|
|
551
630
|
if (persistedNode) {
|
|
552
|
-
reclaimPersistedMixinNode(persistedNode, node,
|
|
553
|
-
return cursor;
|
|
631
|
+
return reclaimPersistedMixinNode(persistedNode, node, vParent, context);
|
|
554
632
|
}
|
|
555
|
-
if (
|
|
633
|
+
if (hydrationNode instanceof Element) {
|
|
556
634
|
// SVG elements have case-sensitive tag names (e.g. linearGradient, clipPath)
|
|
557
635
|
// HTML elements are case-insensitive, so we lowercase for comparison
|
|
558
|
-
let cursorTag =
|
|
636
|
+
let cursorTag = svg ? hydrationNode.tagName : hydrationNode.tagName.toLowerCase();
|
|
559
637
|
if (cursorTag === node.type) {
|
|
560
|
-
let nextCursor =
|
|
561
|
-
patchHostProps({}, hostProps,
|
|
638
|
+
let nextCursor = hydrationNode.nextSibling;
|
|
639
|
+
patchHostProps({}, hostProps, hydrationNode);
|
|
640
|
+
let committed = commitHostNode(node, vParent, svg, hydrationNode, resolved);
|
|
562
641
|
// Handle innerHTML prop
|
|
563
642
|
if (hostProps.innerHTML != null) {
|
|
564
|
-
|
|
643
|
+
hydrationNode.innerHTML = hostProps.innerHTML;
|
|
565
644
|
}
|
|
566
645
|
else {
|
|
567
|
-
let childCursor =
|
|
646
|
+
let childCursor = { current: hydrationNode.firstChild };
|
|
568
647
|
// Ignore excess nodes - browser extensions may inject content
|
|
569
|
-
|
|
648
|
+
committed._children = diffChildren(null, childInputs, hydrationNode, committed, context, childCursor);
|
|
570
649
|
}
|
|
571
|
-
setupHostNode(
|
|
572
|
-
if (
|
|
573
|
-
bindNodeMixRuntime(
|
|
650
|
+
setupHostNode(committed, scheduler);
|
|
651
|
+
if (committed._mixState) {
|
|
652
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles);
|
|
574
653
|
}
|
|
575
|
-
|
|
654
|
+
if (cursor)
|
|
655
|
+
cursor.current = nextCursor;
|
|
656
|
+
return committed;
|
|
576
657
|
}
|
|
577
658
|
else {
|
|
578
659
|
// Type mismatch - try single-advance retry to handle browser extension injections
|
|
579
660
|
// at the start of containers. Skip this node and try the next sibling once.
|
|
580
|
-
let nextSibling = skipComments(
|
|
661
|
+
let nextSibling = skipComments(hydrationNode.nextSibling);
|
|
581
662
|
if (nextSibling instanceof Element) {
|
|
582
|
-
let nextTag =
|
|
663
|
+
let nextTag = svg ? nextSibling.tagName : nextSibling.tagName.toLowerCase();
|
|
583
664
|
if (nextTag === node.type) {
|
|
584
665
|
let nextCursor = nextSibling.nextSibling;
|
|
585
666
|
// Found a match after skipping - adopt it and leave skipped node in place
|
|
586
667
|
patchHostProps({}, hostProps, nextSibling);
|
|
668
|
+
let committed = commitHostNode(node, vParent, svg, nextSibling, resolved);
|
|
587
669
|
if (hostProps.innerHTML != null) {
|
|
588
670
|
nextSibling.innerHTML = hostProps.innerHTML;
|
|
589
671
|
}
|
|
590
672
|
else {
|
|
591
|
-
let childCursor = nextSibling.firstChild;
|
|
592
|
-
diffChildren(null,
|
|
673
|
+
let childCursor = { current: nextSibling.firstChild };
|
|
674
|
+
committed._children = diffChildren(null, childInputs, nextSibling, committed, context, childCursor);
|
|
593
675
|
}
|
|
594
|
-
setupHostNode(
|
|
595
|
-
if (
|
|
596
|
-
bindNodeMixRuntime(
|
|
676
|
+
setupHostNode(committed, scheduler);
|
|
677
|
+
if (committed._mixState) {
|
|
678
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles);
|
|
597
679
|
}
|
|
598
|
-
|
|
680
|
+
if (cursor)
|
|
681
|
+
cursor.current = nextCursor;
|
|
682
|
+
return committed;
|
|
599
683
|
}
|
|
600
684
|
}
|
|
601
685
|
// Retry failed - log mismatch and create new element (don't remove mismatched nodes)
|
|
602
686
|
logHydrationMismatch('tag', cursorTag, node.type);
|
|
603
|
-
cursor
|
|
687
|
+
if (cursor)
|
|
688
|
+
cursor.current = undefined; // stop hydration for this tree
|
|
604
689
|
}
|
|
605
690
|
}
|
|
606
|
-
let dom = node.
|
|
607
|
-
? document.createElementNS(SVG_NS, node.type)
|
|
608
|
-
: document.createElement(node.type);
|
|
691
|
+
let dom = svg ? document.createElementNS(SVG_NS, node.type) : document.createElement(node.type);
|
|
609
692
|
patchHostProps({}, hostProps, dom);
|
|
693
|
+
let committed = commitHostNode(node, vParent, svg, dom, resolved);
|
|
610
694
|
// Handle innerHTML prop
|
|
611
695
|
if (hostProps.innerHTML != null) {
|
|
612
696
|
dom.innerHTML = hostProps.innerHTML;
|
|
613
697
|
}
|
|
614
698
|
else {
|
|
615
|
-
diffChildren(null,
|
|
699
|
+
committed._children = diffChildren(null, childInputs, dom, committed, context);
|
|
616
700
|
}
|
|
617
|
-
setupHostNode(
|
|
618
|
-
if (
|
|
619
|
-
bindNodeMixRuntime(
|
|
701
|
+
setupHostNode(committed, scheduler);
|
|
702
|
+
if (committed._mixState) {
|
|
703
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles, false, domParent);
|
|
620
704
|
}
|
|
621
705
|
doInsert(dom);
|
|
622
|
-
return
|
|
706
|
+
return committed;
|
|
623
707
|
}
|
|
624
|
-
if (
|
|
708
|
+
if (node.kind === 'fragment') {
|
|
709
|
+
let childInputs = node._children;
|
|
710
|
+
let committed = beginFragmentNode(node, vParent, svg);
|
|
711
|
+
let children = childInputs;
|
|
625
712
|
// Insert fragment children in order before the same anchor
|
|
626
|
-
for (let
|
|
627
|
-
|
|
713
|
+
for (let i = 0; i < childInputs.length; i++) {
|
|
714
|
+
children[i] = insert(childInputs[i], domParent, committed, context, anchor, cursor);
|
|
628
715
|
}
|
|
629
|
-
|
|
716
|
+
committed._children = children;
|
|
717
|
+
return committed;
|
|
630
718
|
}
|
|
631
|
-
if (
|
|
632
|
-
return diffComponent(null, node,
|
|
719
|
+
if (node.kind === 'component') {
|
|
720
|
+
return diffComponent(null, node, domParent, vParent, context, svg, anchor, cursor);
|
|
633
721
|
}
|
|
634
|
-
if (node.
|
|
635
|
-
return insertFrame(node, domParent,
|
|
722
|
+
if (node.kind === 'frame') {
|
|
723
|
+
return insertFrame(node, domParent, vParent, context, svg, anchor, cursor);
|
|
636
724
|
}
|
|
637
725
|
invariant(false, 'Unexpected node type');
|
|
638
726
|
}
|
|
639
|
-
function diffFrame(curr, next, domParent,
|
|
727
|
+
function diffFrame(curr, next, domParent, vParent, context, svg, anchor) {
|
|
728
|
+
let { frame } = context;
|
|
640
729
|
let currSrc = getFrameSrc(curr);
|
|
641
730
|
let nextSrc = getFrameSrc(next);
|
|
642
731
|
let currName = getFrameName(curr);
|
|
643
732
|
let nextName = getFrameName(next);
|
|
644
733
|
if (currName !== nextName) {
|
|
645
|
-
let replaceAnchor = curr._rangeEnd
|
|
646
|
-
remove(curr, domParent,
|
|
647
|
-
|
|
648
|
-
return;
|
|
734
|
+
let replaceAnchor = curr._rangeEnd.nextSibling ?? anchor;
|
|
735
|
+
remove(curr, domParent, context);
|
|
736
|
+
return insertFrame(next, domParent, vParent, context, svg, replaceAnchor);
|
|
649
737
|
}
|
|
650
738
|
// If the frame hasn't resolved yet, preserve existing cancel/remount behavior
|
|
651
739
|
// so pending streams from the old src cannot take over the new src.
|
|
652
|
-
if (currSrc !== nextSrc && !curr.
|
|
653
|
-
let replaceAnchor = curr._rangeEnd
|
|
654
|
-
remove(curr, domParent,
|
|
655
|
-
|
|
656
|
-
return;
|
|
740
|
+
if (currSrc !== nextSrc && !curr._state.resolved) {
|
|
741
|
+
let replaceAnchor = curr._rangeEnd.nextSibling ?? anchor;
|
|
742
|
+
remove(curr, domParent, context);
|
|
743
|
+
return insertFrame(next, domParent, vParent, context, svg, replaceAnchor);
|
|
657
744
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
745
|
+
let committed = next;
|
|
746
|
+
Object.assign(committed, {
|
|
747
|
+
_rangeStart: curr._rangeStart,
|
|
748
|
+
_rangeEnd: curr._rangeEnd,
|
|
749
|
+
_state: curr._state,
|
|
750
|
+
_parent: vParent,
|
|
751
|
+
_svg: svg,
|
|
752
|
+
});
|
|
753
|
+
let frameRuntime = getFrameRuntime(frame);
|
|
754
|
+
let frameInstance = committed._state.instance;
|
|
755
|
+
let serverFrameReload = frameRuntime?.serverFrameReload;
|
|
665
756
|
if (currSrc !== nextSrc) {
|
|
666
|
-
let frameInstance = next._frameInstance;
|
|
667
757
|
if (frameInstance) {
|
|
668
758
|
frameInstance.handle.src = nextSrc;
|
|
669
759
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
resolveClientFrame(next, runtime);
|
|
760
|
+
if (frameRuntime) {
|
|
761
|
+
resolveClientFrame(committed, frameRuntime, serverFrameReload);
|
|
673
762
|
}
|
|
674
763
|
}
|
|
675
|
-
if (
|
|
676
|
-
|
|
764
|
+
else if (frameRuntime && frameInstance && serverFrameReload) {
|
|
765
|
+
// Reload client frames that have the same src during a render triggered by an ancestor frame reload
|
|
766
|
+
resolveClientFrame(committed, frameRuntime, serverFrameReload);
|
|
767
|
+
}
|
|
768
|
+
if (!committed._state.resolved && committed._state.fallbackRoot) {
|
|
769
|
+
committed._state.fallbackRoot.render(committed.props.fallback ?? null);
|
|
677
770
|
}
|
|
771
|
+
return committed;
|
|
678
772
|
}
|
|
679
|
-
function insertFrame(node, domParent,
|
|
773
|
+
function insertFrame(node, domParent, vParent, context, svg, anchor, cursor) {
|
|
774
|
+
let { frame, styles } = context;
|
|
680
775
|
let runtime = getFrameRuntime(frame);
|
|
681
776
|
if (!runtime || runtime.canResolveFrames === false) {
|
|
682
777
|
throw new Error('Cannot render <Frame /> without frame runtime. Use run() or pass frameInit to createRoot/createRangeRoot.');
|
|
683
778
|
}
|
|
684
779
|
// Hydration path: adopt server-rendered frame markers and reuse the existing
|
|
685
780
|
// frame instance created during createSubFrames().
|
|
686
|
-
if (isFrameStartComment(cursor)) {
|
|
687
|
-
let start = cursor;
|
|
781
|
+
if (isFrameStartComment(cursor?.current)) {
|
|
782
|
+
let start = cursor.current;
|
|
688
783
|
let end = findFrameEndComment(start);
|
|
689
784
|
if (end) {
|
|
690
|
-
node._rangeStart = start;
|
|
691
|
-
node._rangeEnd = end;
|
|
692
|
-
node._parent = vParent;
|
|
693
|
-
node._frameResolveToken = 0;
|
|
694
|
-
node._frameResolveController = undefined;
|
|
695
|
-
node._frameFallbackRoot = undefined;
|
|
696
|
-
node._frameResolved = true;
|
|
697
|
-
let frameId = getFrameIdFromComment(start);
|
|
698
|
-
let marker = frameId ? runtime.data.f?.[frameId] : undefined;
|
|
699
|
-
let src = marker?.src ?? getFrameSrc(node);
|
|
700
785
|
let instance = runtime.frameInstances.get(start);
|
|
786
|
+
let src = instance?.handle.src ?? getFrameSrc(node);
|
|
701
787
|
if (!instance) {
|
|
702
788
|
instance = createFrame([start, end], {
|
|
703
789
|
name: getFrameName(node),
|
|
704
790
|
src,
|
|
705
|
-
marker: frameId && marker ? { ...marker, id: frameId } : undefined,
|
|
706
791
|
errorTarget: runtime.errorTarget,
|
|
707
792
|
loadModule: runtime.loadModule,
|
|
708
793
|
resolveFrame: runtime.resolveFrame,
|
|
709
794
|
pendingClientEntries: runtime.pendingClientEntries,
|
|
710
795
|
scheduler: runtime.scheduler,
|
|
711
|
-
|
|
796
|
+
styleManager: runtime.styleManager,
|
|
797
|
+
data: {},
|
|
712
798
|
moduleCache: runtime.moduleCache,
|
|
713
799
|
moduleLoads: runtime.moduleLoads,
|
|
714
800
|
frameInstances: runtime.frameInstances,
|
|
@@ -716,8 +802,20 @@ function insertFrame(node, domParent, frame, scheduler, styles, vParent, rootTar
|
|
|
716
802
|
});
|
|
717
803
|
runtime.frameInstances.set(start, instance);
|
|
718
804
|
}
|
|
719
|
-
|
|
720
|
-
return
|
|
805
|
+
cursor.current = end.nextSibling;
|
|
806
|
+
return Object.assign(node, {
|
|
807
|
+
_rangeStart: start,
|
|
808
|
+
_rangeEnd: end,
|
|
809
|
+
_parent: vParent,
|
|
810
|
+
_svg: svg,
|
|
811
|
+
_state: {
|
|
812
|
+
instance,
|
|
813
|
+
resolveToken: 0,
|
|
814
|
+
resolveController: undefined,
|
|
815
|
+
fallbackRoot: undefined,
|
|
816
|
+
resolved: true,
|
|
817
|
+
},
|
|
818
|
+
});
|
|
721
819
|
}
|
|
722
820
|
}
|
|
723
821
|
let start = document.createComment(` rmx:f:${randomFrameId()} `);
|
|
@@ -727,17 +825,11 @@ function insertFrame(node, domParent, frame, scheduler, styles, vParent, rootTar
|
|
|
727
825
|
: (dom) => domParent.appendChild(dom);
|
|
728
826
|
doInsert(start);
|
|
729
827
|
doInsert(end);
|
|
730
|
-
node._rangeStart = start;
|
|
731
|
-
node._rangeEnd = end;
|
|
732
|
-
node._parent = vParent;
|
|
733
828
|
let fallbackRoot = createRangeRoot([start, end], {
|
|
734
829
|
frame,
|
|
735
830
|
styleManager: styles,
|
|
736
831
|
});
|
|
737
|
-
fallbackRoot.render(node.props
|
|
738
|
-
node._frameFallbackRoot = fallbackRoot;
|
|
739
|
-
node._frameResolved = false;
|
|
740
|
-
node._frameResolveToken = 0;
|
|
832
|
+
fallbackRoot.render(node.props.fallback ?? null);
|
|
741
833
|
let instance = createFrame([start, end], {
|
|
742
834
|
name: getFrameName(node),
|
|
743
835
|
src: getFrameSrc(node),
|
|
@@ -746,57 +838,84 @@ function insertFrame(node, domParent, frame, scheduler, styles, vParent, rootTar
|
|
|
746
838
|
resolveFrame: runtime.resolveFrame,
|
|
747
839
|
pendingClientEntries: runtime.pendingClientEntries,
|
|
748
840
|
scheduler: runtime.scheduler,
|
|
749
|
-
|
|
841
|
+
styleManager: runtime.styleManager,
|
|
842
|
+
data: {},
|
|
750
843
|
moduleCache: runtime.moduleCache,
|
|
751
844
|
moduleLoads: runtime.moduleLoads,
|
|
752
845
|
frameInstances: runtime.frameInstances,
|
|
753
846
|
namedFrames: runtime.namedFrames,
|
|
754
847
|
});
|
|
755
|
-
node._frameInstance = instance;
|
|
756
848
|
runtime.frameInstances.set(start, instance);
|
|
757
|
-
|
|
758
|
-
|
|
849
|
+
let committed = Object.assign(node, {
|
|
850
|
+
_rangeStart: start,
|
|
851
|
+
_rangeEnd: end,
|
|
852
|
+
_parent: vParent,
|
|
853
|
+
_svg: svg,
|
|
854
|
+
_state: {
|
|
855
|
+
instance,
|
|
856
|
+
fallbackRoot,
|
|
857
|
+
resolved: false,
|
|
858
|
+
resolveToken: 0,
|
|
859
|
+
resolveController: undefined,
|
|
860
|
+
},
|
|
861
|
+
});
|
|
862
|
+
resolveClientFrame(committed, runtime);
|
|
863
|
+
return committed;
|
|
759
864
|
}
|
|
760
|
-
function resolveClientFrame(node, runtime) {
|
|
865
|
+
function resolveClientFrame(node, runtime, serverFrameReload) {
|
|
761
866
|
let frameSrc = getFrameSrc(node);
|
|
762
|
-
let
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
.
|
|
772
|
-
|
|
867
|
+
let state = node._state;
|
|
868
|
+
let instance = state.instance;
|
|
869
|
+
let token = state.resolveToken + 1;
|
|
870
|
+
state.resolveToken = token;
|
|
871
|
+
state.resolveController?.abort();
|
|
872
|
+
let reload = serverFrameReload
|
|
873
|
+
? instance.beginClientFrameReloadForAncestorReload(serverFrameReload.signal)
|
|
874
|
+
: undefined;
|
|
875
|
+
if (!reload) {
|
|
876
|
+
instance.cancelReload();
|
|
877
|
+
}
|
|
878
|
+
let resolveController = reload?.controller ?? new AbortController();
|
|
879
|
+
state.resolveController = resolveController;
|
|
880
|
+
Promise.resolve()
|
|
881
|
+
.then(() => runtime.resolveFrame(frameSrc, {
|
|
882
|
+
signal: resolveController.signal,
|
|
883
|
+
target: getFrameName(node),
|
|
884
|
+
}))
|
|
885
|
+
.then(async (resolution) => {
|
|
886
|
+
if (state.resolveToken !== token || resolveController.signal.aborted)
|
|
773
887
|
return;
|
|
774
|
-
|
|
775
|
-
|
|
888
|
+
let { content } = await unwrapFrameResolution(resolution);
|
|
889
|
+
if (state.resolveToken !== token || resolveController.signal.aborted)
|
|
890
|
+
return;
|
|
891
|
+
state.fallbackRoot?.dispose();
|
|
892
|
+
state.fallbackRoot = undefined;
|
|
776
893
|
let nextContent = asAbortableFrameContent(content, resolveController.signal);
|
|
777
894
|
await instance.render(nextContent, { signal: resolveController.signal });
|
|
778
|
-
if (
|
|
895
|
+
if (state.resolveToken !== token || resolveController.signal.aborted)
|
|
779
896
|
return;
|
|
780
|
-
|
|
897
|
+
state.resolved = true;
|
|
898
|
+
})
|
|
899
|
+
.catch((error) => {
|
|
900
|
+
if (reload && state.resolveToken === token && !resolveController.signal.aborted) {
|
|
901
|
+
runtime.errorTarget.dispatchEvent(createComponentErrorEvent(error));
|
|
902
|
+
}
|
|
781
903
|
})
|
|
782
|
-
.catch(() => { })
|
|
783
904
|
.finally(() => {
|
|
784
|
-
|
|
785
|
-
|
|
905
|
+
reload?.complete();
|
|
906
|
+
if (state.resolveController === resolveController) {
|
|
907
|
+
state.resolveController = undefined;
|
|
786
908
|
}
|
|
787
909
|
});
|
|
788
910
|
}
|
|
789
911
|
function disposeFrameResources(node) {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
frameInstance.dispose();
|
|
798
|
-
node._frameInstance = undefined;
|
|
799
|
-
}
|
|
912
|
+
let state = node._state;
|
|
913
|
+
state.resolveToken++;
|
|
914
|
+
state.resolveController?.abort();
|
|
915
|
+
state.resolveController = undefined;
|
|
916
|
+
state.fallbackRoot?.dispose();
|
|
917
|
+
state.fallbackRoot = undefined;
|
|
918
|
+
state.instance.dispose();
|
|
800
919
|
}
|
|
801
920
|
function asAbortableFrameContent(content, signal) {
|
|
802
921
|
if (!(content instanceof ReadableStream))
|
|
@@ -832,13 +951,13 @@ function createAbortableReadableStream(source, signal) {
|
|
|
832
951
|
removeAbortReadListener = () => signal.removeEventListener('abort', onAbortRead);
|
|
833
952
|
signal.addEventListener('abort', onAbortRead, { once: true });
|
|
834
953
|
});
|
|
835
|
-
let
|
|
954
|
+
let result = await Promise.race([reader.read(), abortRead]);
|
|
836
955
|
removeAbortReadListener?.();
|
|
837
|
-
if (done) {
|
|
956
|
+
if (result.done) {
|
|
838
957
|
controller.close();
|
|
839
958
|
return;
|
|
840
959
|
}
|
|
841
|
-
controller.enqueue(value);
|
|
960
|
+
controller.enqueue(result.value);
|
|
842
961
|
},
|
|
843
962
|
cancel(reason) {
|
|
844
963
|
signal.removeEventListener('abort', onAbort);
|
|
@@ -849,8 +968,6 @@ function createAbortableReadableStream(source, signal) {
|
|
|
849
968
|
function removeFrameDomRange(node, domParent) {
|
|
850
969
|
let start = node._rangeStart;
|
|
851
970
|
let end = node._rangeEnd;
|
|
852
|
-
if (!(start instanceof Comment) || !(end instanceof Comment))
|
|
853
|
-
return;
|
|
854
971
|
let cursor = start;
|
|
855
972
|
while (cursor) {
|
|
856
973
|
let nextSibling = cursor.nextSibling;
|
|
@@ -861,19 +978,16 @@ function removeFrameDomRange(node, domParent) {
|
|
|
861
978
|
break;
|
|
862
979
|
cursor = nextSibling;
|
|
863
980
|
}
|
|
864
|
-
node._rangeStart = undefined;
|
|
865
|
-
node._rangeEnd = undefined;
|
|
866
981
|
}
|
|
867
982
|
function getFrameRuntime(frame) {
|
|
868
|
-
|
|
983
|
+
let runtime = frame.$runtime;
|
|
984
|
+
return isFrameRuntime(runtime) ? runtime : undefined;
|
|
869
985
|
}
|
|
870
986
|
function getFrameSrc(node) {
|
|
871
|
-
|
|
872
|
-
invariant(typeof src === 'string' && src.length > 0, '<Frame /> requires a src prop');
|
|
873
|
-
return src;
|
|
987
|
+
return node.props.src;
|
|
874
988
|
}
|
|
875
989
|
function getFrameName(node) {
|
|
876
|
-
let name = node.props
|
|
990
|
+
let name = node.props.name;
|
|
877
991
|
return typeof name === 'string' && name.length > 0 ? name : undefined;
|
|
878
992
|
}
|
|
879
993
|
function randomFrameId() {
|
|
@@ -888,16 +1002,13 @@ function skipCommentsExceptFrameStart(cursor) {
|
|
|
888
1002
|
return cursor;
|
|
889
1003
|
}
|
|
890
1004
|
function isFrameStartComment(node) {
|
|
891
|
-
return node
|
|
1005
|
+
return isCommentNode(node) && node.data.trim().startsWith('rmx:f:');
|
|
892
1006
|
}
|
|
893
1007
|
function isFrameEndComment(node) {
|
|
894
|
-
return node
|
|
1008
|
+
return isCommentNode(node) && node.data.trim() === '/rmx:f';
|
|
895
1009
|
}
|
|
896
|
-
function
|
|
897
|
-
|
|
898
|
-
if (!text.startsWith('rmx:f:'))
|
|
899
|
-
return undefined;
|
|
900
|
-
return text.slice('rmx:f:'.length);
|
|
1010
|
+
function isCommentNode(node) {
|
|
1011
|
+
return node?.nodeType === Node.COMMENT_NODE;
|
|
901
1012
|
}
|
|
902
1013
|
function findFrameEndComment(start) {
|
|
903
1014
|
let depth = 1;
|
|
@@ -914,32 +1025,32 @@ function findFrameEndComment(start) {
|
|
|
914
1025
|
}
|
|
915
1026
|
return null;
|
|
916
1027
|
}
|
|
917
|
-
export function renderComponent(
|
|
918
|
-
|
|
919
|
-
|
|
1028
|
+
export function renderComponent(currContent, next, domParent, context, anchor, cursor) {
|
|
1029
|
+
let { scheduler } = context;
|
|
1030
|
+
let handle = next._handle;
|
|
1031
|
+
if (handle.isRemoved()) {
|
|
1032
|
+
invariant('_content' in next, 'Expected removed component to be committed');
|
|
1033
|
+
return next;
|
|
1034
|
+
}
|
|
920
1035
|
let [element, tasks] = handle.render(next.props);
|
|
921
|
-
let content = toVNode(element);
|
|
922
|
-
let
|
|
923
|
-
|
|
924
|
-
next._handle = handle;
|
|
925
|
-
next._parent = vParent;
|
|
926
|
-
let committed = next;
|
|
927
|
-
handle.setScheduleUpdate(() => {
|
|
928
|
-
scheduler.enqueue(committed, domParent);
|
|
929
|
-
});
|
|
1036
|
+
let content = diffVNodes(currContent, toVNode(element), domParent, next, context, anchor, cursor);
|
|
1037
|
+
let committed = commitComponentNode(next, content);
|
|
1038
|
+
handle.setScheduleUpdate(scheduler, committed, domParent);
|
|
930
1039
|
scheduler.enqueueTasks(tasks);
|
|
931
|
-
return
|
|
1040
|
+
return committed;
|
|
932
1041
|
}
|
|
933
|
-
function diffComponent(curr, next,
|
|
1042
|
+
function diffComponent(curr, next, domParent, vParent, context, svg, anchor, cursor) {
|
|
1043
|
+
let { frame } = context;
|
|
934
1044
|
if (curr === null) {
|
|
935
|
-
let componentId = vParent._pendingHydrationComponentId;
|
|
1045
|
+
let componentId = vParent.kind === 'root' ? vParent._pendingHydrationComponentId : undefined;
|
|
936
1046
|
if (componentId) {
|
|
937
|
-
vParent.
|
|
1047
|
+
if (vParent.kind === 'root')
|
|
1048
|
+
vParent._pendingHydrationComponentId = undefined;
|
|
938
1049
|
}
|
|
939
1050
|
else {
|
|
940
1051
|
componentId = `c${++idCounter}`;
|
|
941
1052
|
}
|
|
942
|
-
|
|
1053
|
+
let handle = createComponent({
|
|
943
1054
|
id: componentId,
|
|
944
1055
|
frame,
|
|
945
1056
|
type: next.type,
|
|
@@ -953,52 +1064,54 @@ function diffComponent(curr, next, frame, scheduler, styles, domParent, vParent,
|
|
|
953
1064
|
return runtime?.topFrame;
|
|
954
1065
|
},
|
|
955
1066
|
});
|
|
956
|
-
|
|
1067
|
+
let mounting = beginComponentNode(next, vParent, svg, handle, context);
|
|
1068
|
+
return renderComponent(null, mounting, domParent, context, anchor, cursor);
|
|
957
1069
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
return renderComponent(_handle, _content, next, domParent, frame, scheduler, styles, rootTarget, vParent, anchor, cursor);
|
|
1070
|
+
let mounting = beginComponentNode(next, vParent, svg, curr._handle, context);
|
|
1071
|
+
return renderComponent(curr._content, mounting, domParent, context, anchor, cursor);
|
|
961
1072
|
}
|
|
962
1073
|
// Cleanup without DOM removal - used for descendants when parent DOM node is removed
|
|
963
|
-
function cleanupDescendants(node,
|
|
1074
|
+
function cleanupDescendants(node, context) {
|
|
1075
|
+
let { scheduler } = context;
|
|
964
1076
|
if (isCommittedTextNode(node)) {
|
|
965
1077
|
return;
|
|
966
1078
|
}
|
|
967
1079
|
if (isCommittedHostNode(node)) {
|
|
968
|
-
|
|
969
|
-
|
|
1080
|
+
let children = node._children;
|
|
1081
|
+
for (let i = 0; i < children.length; i++) {
|
|
1082
|
+
cleanupDescendants(children[i], context);
|
|
970
1083
|
}
|
|
971
1084
|
teardownMixins(node._mixState);
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
if (node._controller)
|
|
975
|
-
node._controller.abort();
|
|
1085
|
+
abandonDirectEventListeners(node);
|
|
1086
|
+
abandonControlledReflection(node);
|
|
976
1087
|
return;
|
|
977
1088
|
}
|
|
978
1089
|
if (isFragmentNode(node)) {
|
|
979
|
-
|
|
980
|
-
|
|
1090
|
+
let children = node._children;
|
|
1091
|
+
for (let i = 0; i < children.length; i++) {
|
|
1092
|
+
cleanupDescendants(children[i], context);
|
|
981
1093
|
}
|
|
982
1094
|
return;
|
|
983
1095
|
}
|
|
984
1096
|
if (isCommittedComponentNode(node)) {
|
|
985
|
-
cleanupDescendants(node._content,
|
|
1097
|
+
cleanupDescendants(node._content, context);
|
|
986
1098
|
let tasks = node._handle.remove();
|
|
987
1099
|
scheduler.enqueueTasks(tasks);
|
|
988
1100
|
return;
|
|
989
1101
|
}
|
|
990
|
-
if (node.
|
|
1102
|
+
if (node.kind === 'frame') {
|
|
991
1103
|
disposeFrameResources(node);
|
|
992
1104
|
return;
|
|
993
1105
|
}
|
|
994
1106
|
}
|
|
995
|
-
export function remove(node, domParent,
|
|
1107
|
+
export function remove(node, domParent, context) {
|
|
1108
|
+
let { scheduler } = context;
|
|
996
1109
|
if (isCommittedTextNode(node)) {
|
|
997
1110
|
node._dom.parentNode?.removeChild(node._dom);
|
|
998
1111
|
return;
|
|
999
1112
|
}
|
|
1000
1113
|
if (isCommittedHostNode(node)) {
|
|
1001
|
-
if (node.
|
|
1114
|
+
if (node._persistence)
|
|
1002
1115
|
return;
|
|
1003
1116
|
let persistedRemoval = prepareMixinRemoval(node._mixState);
|
|
1004
1117
|
if (persistedRemoval) {
|
|
@@ -1007,106 +1120,108 @@ export function remove(node, domParent, scheduler, styles) {
|
|
|
1007
1120
|
void persistedRemoval
|
|
1008
1121
|
.catch(() => { })
|
|
1009
1122
|
.finally(() => {
|
|
1010
|
-
if (!node.
|
|
1123
|
+
if (!node._persistence)
|
|
1011
1124
|
return;
|
|
1012
|
-
if (node.
|
|
1125
|
+
if (node._persistence.token !== token)
|
|
1013
1126
|
return;
|
|
1014
1127
|
unmarkNodePersistedByMixins(node);
|
|
1015
|
-
performHostNodeRemoval(node, domParent,
|
|
1128
|
+
performHostNodeRemoval(node, domParent, context);
|
|
1016
1129
|
});
|
|
1017
1130
|
return;
|
|
1018
1131
|
}
|
|
1019
|
-
performHostNodeRemoval(node, domParent,
|
|
1132
|
+
performHostNodeRemoval(node, domParent, context);
|
|
1020
1133
|
return;
|
|
1021
1134
|
}
|
|
1022
1135
|
if (isFragmentNode(node)) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1136
|
+
let children = node._children;
|
|
1137
|
+
for (let i = 0; i < children.length; i++) {
|
|
1138
|
+
remove(children[i], domParent, context);
|
|
1025
1139
|
}
|
|
1026
1140
|
return;
|
|
1027
1141
|
}
|
|
1028
1142
|
if (isCommittedComponentNode(node)) {
|
|
1029
|
-
remove(node._content, domParent,
|
|
1143
|
+
remove(node._content, domParent, context);
|
|
1030
1144
|
let tasks = node._handle.remove();
|
|
1031
1145
|
scheduler.enqueueTasks(tasks);
|
|
1032
1146
|
return;
|
|
1033
1147
|
}
|
|
1034
|
-
if (node.
|
|
1148
|
+
if (node.kind === 'frame') {
|
|
1035
1149
|
disposeFrameResources(node);
|
|
1036
1150
|
removeFrameDomRange(node, domParent);
|
|
1037
1151
|
return;
|
|
1038
1152
|
}
|
|
1039
1153
|
}
|
|
1040
1154
|
// Actually remove a host node from DOM and clean up
|
|
1041
|
-
function performHostNodeRemoval(node, domParent,
|
|
1155
|
+
function performHostNodeRemoval(node, domParent, context) {
|
|
1156
|
+
let children = node._children;
|
|
1042
1157
|
if (isHeadHostNode(node)) {
|
|
1043
|
-
for (let
|
|
1044
|
-
remove(
|
|
1158
|
+
for (let i = 0; i < children.length; i++) {
|
|
1159
|
+
remove(children[i], node._dom, context);
|
|
1045
1160
|
}
|
|
1046
1161
|
}
|
|
1047
1162
|
else {
|
|
1048
1163
|
// Clean up all descendants first (before removing DOM subtree)
|
|
1049
|
-
for (let
|
|
1050
|
-
cleanupDescendants(
|
|
1164
|
+
for (let i = 0; i < children.length; i++) {
|
|
1165
|
+
cleanupDescendants(children[i], context);
|
|
1051
1166
|
}
|
|
1052
1167
|
}
|
|
1053
1168
|
teardownMixins(node._mixState);
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1169
|
+
// Never remove the real document.head node when reconciling a <head> vnode,
|
|
1170
|
+
// and since it stays alive, detach its listeners for real.
|
|
1171
|
+
if (isHeadHostNode(node)) {
|
|
1172
|
+
teardownDirectEventListeners(node);
|
|
1173
|
+
teardownControlledReflection(node);
|
|
1174
|
+
}
|
|
1175
|
+
else {
|
|
1176
|
+
abandonDirectEventListeners(node);
|
|
1177
|
+
abandonControlledReflection(node);
|
|
1058
1178
|
node._dom.parentNode?.removeChild(node._dom);
|
|
1059
1179
|
}
|
|
1060
|
-
if (node._controller)
|
|
1061
|
-
node._controller.abort();
|
|
1062
1180
|
}
|
|
1063
|
-
function diffChildren(curr, next, domParent,
|
|
1181
|
+
function diffChildren(curr, next, domParent, vParent, context, cursor, anchor) {
|
|
1064
1182
|
let hasKeys = hasKeyedChildren(next);
|
|
1183
|
+
let committed = next;
|
|
1065
1184
|
if (curr === null) {
|
|
1066
1185
|
if (hasKeys) {
|
|
1067
1186
|
warnDuplicateKeys(next);
|
|
1068
1187
|
}
|
|
1069
|
-
for (let
|
|
1070
|
-
|
|
1188
|
+
for (let i = 0; i < next.length; i++) {
|
|
1189
|
+
committed[i] = insert(next[i], domParent, vParent, context, anchor, cursor);
|
|
1071
1190
|
}
|
|
1072
|
-
|
|
1073
|
-
return cursor;
|
|
1191
|
+
return committed;
|
|
1074
1192
|
}
|
|
1075
1193
|
if (next.length === 0 &&
|
|
1076
1194
|
anchor === undefined &&
|
|
1077
1195
|
!parentUsesInnerHTML(vParent) &&
|
|
1078
1196
|
canBulkClearChildren(curr)) {
|
|
1079
|
-
for (let
|
|
1080
|
-
cleanupDescendants(
|
|
1197
|
+
for (let i = 0; i < curr.length; i++) {
|
|
1198
|
+
cleanupDescendants(curr[i], context);
|
|
1081
1199
|
}
|
|
1082
1200
|
domParent.textContent = '';
|
|
1083
|
-
|
|
1084
|
-
return;
|
|
1201
|
+
return EMPTY_COMMITTED_CHILDREN;
|
|
1085
1202
|
}
|
|
1086
1203
|
if (!hasKeys) {
|
|
1087
1204
|
for (let i = 0; i < next.length; i++) {
|
|
1088
1205
|
let currentNode = i < curr.length ? curr[i] : null;
|
|
1089
|
-
diffVNodes(currentNode, next[i], domParent,
|
|
1206
|
+
committed[i] = diffVNodes(currentNode, next[i], domParent, vParent, context, anchor, cursor);
|
|
1090
1207
|
}
|
|
1091
1208
|
if (curr.length > next.length) {
|
|
1092
1209
|
for (let i = next.length; i < curr.length; i++) {
|
|
1093
1210
|
let node = curr[i];
|
|
1094
1211
|
if (node)
|
|
1095
|
-
remove(node, domParent,
|
|
1212
|
+
remove(node, domParent, context);
|
|
1096
1213
|
}
|
|
1097
1214
|
}
|
|
1098
|
-
|
|
1099
|
-
return;
|
|
1215
|
+
return committed;
|
|
1100
1216
|
}
|
|
1101
|
-
patchKeyedChildren(curr, next, domParent,
|
|
1102
|
-
return;
|
|
1217
|
+
return patchKeyedChildren(curr, next, domParent, vParent, context, cursor, anchor);
|
|
1103
1218
|
}
|
|
1104
1219
|
function parentUsesInnerHTML(parent) {
|
|
1105
1220
|
return isHostNode(parent) && getHostProps(parent).innerHTML != null;
|
|
1106
1221
|
}
|
|
1107
1222
|
function canBulkClearChildren(children) {
|
|
1108
|
-
for (let
|
|
1109
|
-
if (!canBulkClearNode(
|
|
1223
|
+
for (let i = 0; i < children.length; i++) {
|
|
1224
|
+
if (!canBulkClearNode(children[i]))
|
|
1110
1225
|
return false;
|
|
1111
1226
|
}
|
|
1112
1227
|
return true;
|
|
@@ -1117,11 +1232,7 @@ function canBulkClearNode(node) {
|
|
|
1117
1232
|
if (isCommittedHostNode(node)) {
|
|
1118
1233
|
if (node._mixState)
|
|
1119
1234
|
return false;
|
|
1120
|
-
|
|
1121
|
-
if (!canBulkClearNode(child))
|
|
1122
|
-
return false;
|
|
1123
|
-
}
|
|
1124
|
-
return true;
|
|
1235
|
+
return canBulkClearChildren(node._children);
|
|
1125
1236
|
}
|
|
1126
1237
|
if (isFragmentNode(node)) {
|
|
1127
1238
|
return canBulkClearChildren(node._children);
|
|
@@ -1132,8 +1243,8 @@ function canBulkClearNode(node) {
|
|
|
1132
1243
|
return false;
|
|
1133
1244
|
}
|
|
1134
1245
|
function hasKeyedChildren(children) {
|
|
1135
|
-
for (let
|
|
1136
|
-
if (
|
|
1246
|
+
for (let i = 0; i < children.length; i++) {
|
|
1247
|
+
if (children[i].key != null)
|
|
1137
1248
|
return true;
|
|
1138
1249
|
}
|
|
1139
1250
|
return false;
|
|
@@ -1157,11 +1268,11 @@ function warnDuplicateKeys(children) {
|
|
|
1157
1268
|
}
|
|
1158
1269
|
}
|
|
1159
1270
|
if (duplicateKeys?.size) {
|
|
1160
|
-
let quotedKeys = Array.from(duplicateKeys, (key) => `"${key}"`);
|
|
1271
|
+
let quotedKeys = Array.from(duplicateKeys, (key) => `"${String(key)}"`);
|
|
1161
1272
|
console.warn(`Duplicate keys detected in siblings: ${quotedKeys.join(', ')}. Keys should be unique.`);
|
|
1162
1273
|
}
|
|
1163
1274
|
}
|
|
1164
|
-
function patchKeyedChildren(curr, next, domParent,
|
|
1275
|
+
function patchKeyedChildren(curr, next, domParent, vParent, context, cursor, anchor) {
|
|
1165
1276
|
let matches = matchKeyedChildrenInOrder(curr, next) ??
|
|
1166
1277
|
matchKeyedChildrenAfterSingleRemoval(curr, next) ??
|
|
1167
1278
|
matchKeyedChildrenAfterPairSwap(curr, next);
|
|
@@ -1169,34 +1280,36 @@ function patchKeyedChildren(curr, next, domParent, frame, scheduler, styles, vPa
|
|
|
1169
1280
|
warnDuplicateKeys(next);
|
|
1170
1281
|
matches = matchKeyedChildren(curr, next);
|
|
1171
1282
|
}
|
|
1283
|
+
let committed = next;
|
|
1172
1284
|
let matchAnalysis = analyzeKeyedChildMatches(curr.length, matches);
|
|
1173
1285
|
if (matchAnalysis.hasRemovals) {
|
|
1174
1286
|
let usedOldIndexes = new Uint8Array(curr.length);
|
|
1175
|
-
for (let
|
|
1176
|
-
|
|
1177
|
-
|
|
1287
|
+
for (let index = 0; index < matches.length; index++) {
|
|
1288
|
+
let oldIndex = matches[index];
|
|
1289
|
+
if (oldIndex >= 0) {
|
|
1290
|
+
usedOldIndexes[oldIndex] = 1;
|
|
1178
1291
|
}
|
|
1179
1292
|
}
|
|
1180
1293
|
for (let oldIndex = 0; oldIndex < curr.length; oldIndex++) {
|
|
1181
1294
|
if (usedOldIndexes[oldIndex] === 0) {
|
|
1182
|
-
remove(curr[oldIndex], domParent,
|
|
1295
|
+
remove(curr[oldIndex], domParent, context);
|
|
1183
1296
|
}
|
|
1184
1297
|
}
|
|
1185
1298
|
}
|
|
1186
|
-
vParent._children = next;
|
|
1187
1299
|
for (let index = 0; index < next.length; index++) {
|
|
1188
|
-
let
|
|
1189
|
-
let oldNode =
|
|
1190
|
-
diffVNodes(oldNode, next[index], domParent,
|
|
1300
|
+
let oldIndex = matches[index];
|
|
1301
|
+
let oldNode = oldIndex >= 0 ? curr[oldIndex] : null;
|
|
1302
|
+
committed[index] = diffVNodes(oldNode, next[index], domParent, vParent, context, anchor, cursor);
|
|
1191
1303
|
}
|
|
1304
|
+
let committedChildren = committed;
|
|
1192
1305
|
if (matchAnalysis.canSkipPlacement) {
|
|
1193
|
-
return;
|
|
1306
|
+
return committedChildren;
|
|
1194
1307
|
}
|
|
1195
1308
|
let stableIndexes = lisMatches(matches);
|
|
1196
1309
|
let stableCursor = stableIndexes.length - 1;
|
|
1197
1310
|
let placementAnchor = anchor ?? null;
|
|
1198
1311
|
for (let index = next.length - 1; index >= 0; index--) {
|
|
1199
|
-
let nextNode =
|
|
1312
|
+
let nextNode = committedChildren[index];
|
|
1200
1313
|
let isStable = stableIndexes[stableCursor] === index;
|
|
1201
1314
|
if (isStable) {
|
|
1202
1315
|
stableCursor--;
|
|
@@ -1206,7 +1319,11 @@ function patchKeyedChildren(curr, next, domParent, frame, scheduler, styles, vPa
|
|
|
1206
1319
|
}
|
|
1207
1320
|
placementAnchor = findFirstDomAnchor(nextNode) ?? placementAnchor;
|
|
1208
1321
|
}
|
|
1322
|
+
return committedChildren;
|
|
1209
1323
|
}
|
|
1324
|
+
// Keyed child matches are arrays of old indexes (-1 = no match / new node),
|
|
1325
|
+
// parallel to `next`. Plain numbers instead of wrapper objects keep large
|
|
1326
|
+
// keyed diffs (1000-row tables) allocation-free.
|
|
1210
1327
|
function matchKeyedChildren(curr, next) {
|
|
1211
1328
|
let oldKeyMap = new Map();
|
|
1212
1329
|
let usedOldIndexes = new Set();
|
|
@@ -1216,7 +1333,9 @@ function matchKeyedChildren(curr, next) {
|
|
|
1216
1333
|
if (key != null)
|
|
1217
1334
|
oldKeyMap.set(key, index);
|
|
1218
1335
|
}
|
|
1219
|
-
|
|
1336
|
+
let matches = [];
|
|
1337
|
+
for (let nextIndex = 0; nextIndex < next.length; nextIndex++) {
|
|
1338
|
+
let nextNode = next[nextIndex];
|
|
1220
1339
|
let oldIndex = -1;
|
|
1221
1340
|
if (nextNode.key != null) {
|
|
1222
1341
|
let keyedOldIndex = oldKeyMap.get(nextNode.key);
|
|
@@ -1240,8 +1359,9 @@ function matchKeyedChildren(curr, next) {
|
|
|
1240
1359
|
}
|
|
1241
1360
|
if (oldIndex >= 0)
|
|
1242
1361
|
usedOldIndexes.add(oldIndex);
|
|
1243
|
-
|
|
1244
|
-
}
|
|
1362
|
+
matches.push(oldIndex);
|
|
1363
|
+
}
|
|
1364
|
+
return matches;
|
|
1245
1365
|
}
|
|
1246
1366
|
function matchKeyedChildrenInOrder(curr, next) {
|
|
1247
1367
|
let length = Math.min(curr.length, next.length);
|
|
@@ -1254,12 +1374,12 @@ function matchKeyedChildrenInOrder(curr, next) {
|
|
|
1254
1374
|
if (oldNode.key !== nextNode.key || oldNode.type !== nextNode.type) {
|
|
1255
1375
|
return null;
|
|
1256
1376
|
}
|
|
1257
|
-
matches.push(
|
|
1377
|
+
matches.push(index);
|
|
1258
1378
|
}
|
|
1259
1379
|
for (let index = length; index < next.length; index++) {
|
|
1260
1380
|
if (next[index].key == null)
|
|
1261
1381
|
return null;
|
|
1262
|
-
matches.push(
|
|
1382
|
+
matches.push(-1);
|
|
1263
1383
|
}
|
|
1264
1384
|
return matches;
|
|
1265
1385
|
}
|
|
@@ -1275,7 +1395,7 @@ function matchKeyedChildrenAfterSingleRemoval(curr, next) {
|
|
|
1275
1395
|
return null;
|
|
1276
1396
|
let oldNode = curr[oldIndex];
|
|
1277
1397
|
if (oldNode.key === nextNode.key && oldNode.type === nextNode.type) {
|
|
1278
|
-
matches.push(
|
|
1398
|
+
matches.push(oldIndex);
|
|
1279
1399
|
oldIndex++;
|
|
1280
1400
|
continue;
|
|
1281
1401
|
}
|
|
@@ -1287,7 +1407,7 @@ function matchKeyedChildrenAfterSingleRemoval(curr, next) {
|
|
|
1287
1407
|
if (oldNode.key !== nextNode.key || oldNode.type !== nextNode.type) {
|
|
1288
1408
|
return null;
|
|
1289
1409
|
}
|
|
1290
|
-
matches.push(
|
|
1410
|
+
matches.push(oldIndex);
|
|
1291
1411
|
oldIndex++;
|
|
1292
1412
|
}
|
|
1293
1413
|
return matches;
|
|
@@ -1304,7 +1424,7 @@ function matchKeyedChildrenAfterPairSwap(curr, next) {
|
|
|
1304
1424
|
return null;
|
|
1305
1425
|
let oldNode = curr[index];
|
|
1306
1426
|
if (oldNode.key === nextNode.key && oldNode.type === nextNode.type) {
|
|
1307
|
-
matches.push(
|
|
1427
|
+
matches.push(index);
|
|
1308
1428
|
continue;
|
|
1309
1429
|
}
|
|
1310
1430
|
if (firstMismatch === -1) {
|
|
@@ -1316,7 +1436,7 @@ function matchKeyedChildrenAfterPairSwap(curr, next) {
|
|
|
1316
1436
|
else {
|
|
1317
1437
|
return null;
|
|
1318
1438
|
}
|
|
1319
|
-
matches.push(
|
|
1439
|
+
matches.push(-1);
|
|
1320
1440
|
}
|
|
1321
1441
|
if (firstMismatch === -1)
|
|
1322
1442
|
return matches;
|
|
@@ -1332,8 +1452,8 @@ function matchKeyedChildrenAfterPairSwap(curr, next) {
|
|
|
1332
1452
|
secondOldNode.type !== firstNextNode.type) {
|
|
1333
1453
|
return null;
|
|
1334
1454
|
}
|
|
1335
|
-
matches[firstMismatch] =
|
|
1336
|
-
matches[secondMismatch] =
|
|
1455
|
+
matches[firstMismatch] = secondMismatch;
|
|
1456
|
+
matches[secondMismatch] = firstMismatch;
|
|
1337
1457
|
return matches;
|
|
1338
1458
|
}
|
|
1339
1459
|
function analyzeKeyedChildMatches(currentLength, matches) {
|
|
@@ -1341,16 +1461,17 @@ function analyzeKeyedChildMatches(currentLength, matches) {
|
|
|
1341
1461
|
let canSkipPlacement = true;
|
|
1342
1462
|
let lastOldIndex = -1;
|
|
1343
1463
|
let sawNewNode = false;
|
|
1344
|
-
for (let
|
|
1345
|
-
|
|
1464
|
+
for (let index = 0; index < matches.length; index++) {
|
|
1465
|
+
let oldIndex = matches[index];
|
|
1466
|
+
if (oldIndex < 0) {
|
|
1346
1467
|
hasRemovals = true;
|
|
1347
1468
|
sawNewNode = true;
|
|
1348
1469
|
continue;
|
|
1349
1470
|
}
|
|
1350
|
-
if (sawNewNode ||
|
|
1471
|
+
if (sawNewNode || oldIndex < lastOldIndex) {
|
|
1351
1472
|
canSkipPlacement = false;
|
|
1352
1473
|
}
|
|
1353
|
-
lastOldIndex =
|
|
1474
|
+
lastOldIndex = oldIndex;
|
|
1354
1475
|
}
|
|
1355
1476
|
return { hasRemovals, canSkipPlacement };
|
|
1356
1477
|
}
|
|
@@ -1358,14 +1479,14 @@ function lisMatches(matches) {
|
|
|
1358
1479
|
let predecessors = Array.from({ length: matches.length });
|
|
1359
1480
|
let tails = [];
|
|
1360
1481
|
for (let index = 0; index < matches.length; index++) {
|
|
1361
|
-
let value = matches[index]
|
|
1482
|
+
let value = matches[index] + 1;
|
|
1362
1483
|
if (value === 0)
|
|
1363
1484
|
continue;
|
|
1364
1485
|
let low = 0;
|
|
1365
1486
|
let high = tails.length;
|
|
1366
1487
|
while (low < high) {
|
|
1367
1488
|
let middle = (low + high) >> 1;
|
|
1368
|
-
if (matches[tails[middle]]
|
|
1489
|
+
if (matches[tails[middle]] + 1 < value) {
|
|
1369
1490
|
low = middle + 1;
|
|
1370
1491
|
}
|
|
1371
1492
|
else {
|
|
@@ -1404,11 +1525,12 @@ export function findFirstDomAnchor(node) {
|
|
|
1404
1525
|
return node._dom;
|
|
1405
1526
|
if (isCommittedComponentNode(node))
|
|
1406
1527
|
return findFirstDomAnchor(node._content);
|
|
1407
|
-
if (node.
|
|
1408
|
-
return node._rangeStart
|
|
1528
|
+
if (node.kind === 'frame')
|
|
1529
|
+
return node._rangeStart;
|
|
1409
1530
|
if (isFragmentNode(node)) {
|
|
1410
|
-
|
|
1411
|
-
|
|
1531
|
+
let children = node._children;
|
|
1532
|
+
for (let i = 0; i < children.length; i++) {
|
|
1533
|
+
let dom = findFirstDomAnchor(children[i]);
|
|
1412
1534
|
if (dom)
|
|
1413
1535
|
return dom;
|
|
1414
1536
|
}
|
|
@@ -1424,8 +1546,8 @@ export function findLastDomAnchor(node) {
|
|
|
1424
1546
|
return node._dom;
|
|
1425
1547
|
if (isCommittedComponentNode(node))
|
|
1426
1548
|
return findLastDomAnchor(node._content);
|
|
1427
|
-
if (node.
|
|
1428
|
-
return node._rangeEnd
|
|
1549
|
+
if (node.kind === 'frame')
|
|
1550
|
+
return node._rangeEnd;
|
|
1429
1551
|
if (isFragmentNode(node)) {
|
|
1430
1552
|
for (let i = node._children.length - 1; i >= 0; i--) {
|
|
1431
1553
|
let dom = findLastDomAnchor(node._children[i]);
|
|
@@ -1464,6 +1586,8 @@ function shouldDispatchInlineMixinLifecycle(node) {
|
|
|
1464
1586
|
if (!parents?.length)
|
|
1465
1587
|
return true;
|
|
1466
1588
|
for (let parent of parents) {
|
|
1589
|
+
if (!(parent instanceof Node))
|
|
1590
|
+
continue;
|
|
1467
1591
|
let parentNode = parent;
|
|
1468
1592
|
if (parentNode === node)
|
|
1469
1593
|
return false;
|
|
@@ -1474,11 +1598,16 @@ function shouldDispatchInlineMixinLifecycle(node) {
|
|
|
1474
1598
|
}
|
|
1475
1599
|
export function findNextSiblingDomAnchor(curr) {
|
|
1476
1600
|
let vParent = curr._parent;
|
|
1477
|
-
if (
|
|
1478
|
-
return null;
|
|
1479
|
-
let children = vParent._children;
|
|
1480
|
-
if (children.length === 0)
|
|
1601
|
+
if (vParent.kind === 'component')
|
|
1481
1602
|
return findNextSiblingDomAnchor(vParent);
|
|
1603
|
+
let children = vParent._children;
|
|
1604
|
+
if (children.length === 0) {
|
|
1605
|
+
if (vParent.kind === 'root')
|
|
1606
|
+
return vParent._rangeEnd ?? null;
|
|
1607
|
+
if (vParent.kind === 'fragment')
|
|
1608
|
+
return findNextSiblingDomAnchor(vParent);
|
|
1609
|
+
return null;
|
|
1610
|
+
}
|
|
1482
1611
|
let idx = children.indexOf(curr);
|
|
1483
1612
|
if (idx === -1)
|
|
1484
1613
|
return null;
|
|
@@ -1490,34 +1619,33 @@ export function findNextSiblingDomAnchor(curr) {
|
|
|
1490
1619
|
if (isFragmentNode(vParent)) {
|
|
1491
1620
|
return findNextSiblingDomAnchor(vParent);
|
|
1492
1621
|
}
|
|
1493
|
-
return null;
|
|
1622
|
+
return vParent.kind === 'root' ? (vParent._rangeEnd ?? null) : null;
|
|
1494
1623
|
}
|
|
1495
|
-
function reclaimPersistedMixinNode(persistedNode, newNode,
|
|
1624
|
+
function reclaimPersistedMixinNode(persistedNode, newNode, vParent, context) {
|
|
1625
|
+
let { frame, scheduler, styles } = context;
|
|
1496
1626
|
cancelPendingMixinRemoval(persistedNode._mixState);
|
|
1497
1627
|
unmarkNodePersistedByMixins(persistedNode);
|
|
1498
|
-
newNode._dom = persistedNode._dom;
|
|
1499
|
-
newNode._parent = vParent;
|
|
1500
|
-
newNode._controller = persistedNode._controller;
|
|
1501
|
-
newNode._mixState = persistedNode._mixState;
|
|
1502
|
-
newNode._directEventState = persistedNode._directEventState;
|
|
1503
|
-
newNode._controlledState = persistedNode._controlledState;
|
|
1504
1628
|
let prevProps = getHostProps(persistedNode);
|
|
1505
|
-
let
|
|
1629
|
+
let childInputs = newNode._children;
|
|
1630
|
+
let resolved = resolveNodeMixProps(newNode, vParent, frame, scheduler, persistedNode._mixState);
|
|
1631
|
+
let nextProps = resolved.props;
|
|
1632
|
+
let committed = commitHostNode(newNode, vParent, getSvgContext(vParent, newNode), persistedNode._dom, resolved);
|
|
1633
|
+
committed._directEventState = persistedNode._directEventState;
|
|
1634
|
+
committed._controlledState = persistedNode._controlledState;
|
|
1506
1635
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
1507
|
-
dispatchMixinBeforeUpdate(
|
|
1636
|
+
dispatchMixinBeforeUpdate(committed._mixState);
|
|
1508
1637
|
}
|
|
1509
1638
|
patchHostProps(prevProps, nextProps, persistedNode._dom);
|
|
1510
|
-
syncDirectEventListeners(
|
|
1511
|
-
ensureControlledReflection(
|
|
1512
|
-
syncControlledReflection(
|
|
1513
|
-
diffChildren(persistedNode._children,
|
|
1514
|
-
if (
|
|
1515
|
-
bindNodeMixRuntime(
|
|
1639
|
+
syncDirectEventListeners(committed);
|
|
1640
|
+
ensureControlledReflection(committed, scheduler);
|
|
1641
|
+
syncControlledReflection(committed, nextProps);
|
|
1642
|
+
committed._children = diffChildren(persistedNode._children, childInputs, persistedNode._dom, committed, context);
|
|
1643
|
+
if (committed._mixState) {
|
|
1644
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles, true);
|
|
1516
1645
|
}
|
|
1517
1646
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
1518
|
-
scheduler.enqueueCommitPhase([
|
|
1519
|
-
() => dispatchMixinCommit(newNode._mixState),
|
|
1520
|
-
]);
|
|
1647
|
+
scheduler.enqueueCommitPhase([() => dispatchMixinCommit(committed._mixState)]);
|
|
1521
1648
|
}
|
|
1649
|
+
return committed;
|
|
1522
1650
|
}
|
|
1523
1651
|
//# sourceMappingURL=reconcile.js.map
|