@remix-run/ui 0.1.1 → 0.2.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 +33 -10
- package/dist/animation/animate-layout-mixin.js +66 -66
- package/dist/animation/animate-layout-mixin.js.map +1 -1
- package/dist/animation/spring.d.ts +6 -35
- package/dist/animation/spring.js +9 -8
- package/dist/animation/spring.js.map +1 -1
- package/dist/components/accordion/accordion.d.ts +7 -7
- package/dist/components/accordion/accordion.js +0 -2
- package/dist/components/accordion/accordion.js.map +1 -1
- package/dist/components/accordion/demos/card.demo.d.ts +6 -0
- package/dist/components/accordion/demos/card.demo.js +58 -0
- package/dist/components/accordion/demos/card.demo.js.map +1 -0
- package/dist/components/accordion/demos/multiple.demo.d.ts +6 -0
- package/dist/components/accordion/demos/multiple.demo.js +19 -0
- package/dist/components/accordion/demos/multiple.demo.js.map +1 -0
- package/dist/components/accordion/demos/overview.demo.d.ts +6 -0
- package/dist/components/accordion/demos/overview.demo.js +19 -0
- package/dist/components/accordion/demos/overview.demo.js.map +1 -0
- package/dist/components/breadcrumbs/breadcrumbs.d.ts +1 -1
- package/dist/components/breadcrumbs/breadcrumbs.js +0 -2
- package/dist/components/breadcrumbs/breadcrumbs.js.map +1 -1
- package/dist/components/breadcrumbs/demos/basic.demo.d.ts +5 -0
- package/dist/components/breadcrumbs/demos/basic.demo.js +14 -0
- package/dist/components/breadcrumbs/demos/basic.demo.js.map +1 -0
- package/dist/components/breadcrumbs/demos/separator.demo.d.ts +5 -0
- package/dist/components/breadcrumbs/demos/separator.demo.js +14 -0
- package/dist/components/breadcrumbs/demos/separator.demo.js.map +1 -0
- package/dist/components/button/button.d.ts +86 -4
- package/dist/components/button/button.js +63 -3
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/button/demos/aliases.demo.d.ts +6 -0
- package/dist/components/button/demos/aliases.demo.js +18 -0
- package/dist/components/button/demos/aliases.demo.js.map +1 -0
- package/dist/components/button/demos/basic.demo.d.ts +6 -0
- package/dist/components/button/demos/basic.demo.js +19 -0
- package/dist/components/button/demos/basic.demo.js.map +1 -0
- package/dist/components/button/demos/states.demo.d.ts +6 -0
- package/dist/components/button/demos/states.demo.js +29 -0
- package/dist/components/button/demos/states.demo.js.map +1 -0
- package/dist/components/combobox/combobox.d.ts +11 -11
- package/dist/components/combobox/combobox.js +0 -2
- package/dist/components/combobox/combobox.js.map +1 -1
- package/dist/components/combobox/demos/overview.demo.d.ts +6 -0
- package/dist/components/combobox/demos/overview.demo.js +153 -0
- package/dist/components/combobox/demos/overview.demo.js.map +1 -0
- package/dist/components/listbox/demos/overview.demo.d.ts +6 -0
- package/dist/components/listbox/demos/overview.demo.js +64 -0
- package/dist/components/listbox/demos/overview.demo.js.map +1 -0
- package/dist/components/listbox/listbox.d.ts +4 -9
- package/dist/components/listbox/listbox.js +21 -33
- package/dist/components/listbox/listbox.js.map +1 -1
- package/dist/components/menu/demos/bubbling.demo.d.ts +5 -0
- package/dist/components/menu/demos/bubbling.demo.js +15 -0
- package/dist/components/menu/demos/bubbling.demo.js.map +1 -0
- package/dist/components/menu/demos/overview.demo.d.ts +6 -0
- package/dist/components/menu/demos/overview.demo.js +32 -0
- package/dist/components/menu/demos/overview.demo.js.map +1 -0
- package/dist/components/menu/menu.d.ts +15 -24
- package/dist/components/menu/menu.js +23 -38
- package/dist/components/menu/menu.js.map +1 -1
- package/dist/components/popover/demos/overview.demo.d.ts +6 -0
- package/dist/components/popover/demos/overview.demo.js +64 -0
- package/dist/components/popover/demos/overview.demo.js.map +1 -0
- package/dist/components/popover/popover.d.ts +5 -5
- package/dist/components/popover/popover.js.map +1 -1
- package/dist/components/select/demos/deconstructed.demo.d.ts +6 -0
- package/dist/components/select/demos/deconstructed.demo.js +53 -0
- package/dist/components/select/demos/deconstructed.demo.js.map +1 -0
- package/dist/components/select/demos/overview.demo.d.ts +5 -0
- package/dist/components/select/demos/overview.demo.js +27 -0
- package/dist/components/select/demos/overview.demo.js.map +1 -0
- package/dist/components/select/select.d.ts +11 -11
- package/dist/components/select/select.js +17 -26
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/tabs/tabs.d.ts +6 -6
- package/dist/components/tabs/tabs.js +0 -2
- package/dist/components/tabs/tabs.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/interactions/keydown/keydown.d.ts +1 -1
- package/dist/interactions/outside-click/outside-click-mixin.d.ts +2 -1
- package/dist/interactions/typeahead/typeahead-mixin.d.ts +3 -1
- package/dist/runtime/component.d.ts +18 -12
- package/dist/runtime/component.js +93 -80
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/attributes.d.ts +14 -0
- package/dist/runtime/core/attributes.js +103 -0
- package/dist/runtime/core/attributes.js.map +1 -0
- package/dist/runtime/core/children.d.ts +7 -0
- package/dist/runtime/core/children.js +30 -0
- package/dist/runtime/core/children.js.map +1 -0
- package/dist/runtime/core/props.d.ts +9 -0
- package/dist/runtime/core/props.js +170 -0
- package/dist/runtime/core/props.js.map +1 -0
- package/dist/runtime/core/vnode.d.ts +3 -0
- package/dist/runtime/core/vnode.js +39 -0
- package/dist/runtime/core/vnode.js.map +1 -0
- package/dist/runtime/create-element.js +2 -1
- package/dist/runtime/create-element.js.map +1 -1
- package/dist/runtime/diff-dom.js +47 -14
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/diff-props.d.ts +1 -2
- package/dist/runtime/diff-props.js +2 -181
- package/dist/runtime/diff-props.js.map +1 -1
- package/dist/runtime/dom.d.ts +20 -9
- package/dist/runtime/frame.d.ts +23 -2
- package/dist/runtime/frame.js +41 -47
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/jsx.d.ts +1 -1
- package/dist/runtime/jsx.js +2 -28
- package/dist/runtime/jsx.js.map +1 -1
- package/dist/runtime/mixins/link-mixin.d.ts +5 -1
- package/dist/runtime/mixins/link-mixin.js.map +1 -1
- package/dist/runtime/mixins/mixin.d.ts +2 -1
- package/dist/runtime/mixins/mixin.js +9 -4
- package/dist/runtime/mixins/mixin.js.map +1 -1
- package/dist/runtime/mixins/on-mixin.d.ts +15 -4
- package/dist/runtime/mixins/on-mixin.js +9 -2
- package/dist/runtime/mixins/on-mixin.js.map +1 -1
- package/dist/runtime/mixins/ref-mixin.d.ts +2 -1
- package/dist/runtime/mixins/ref-mixin.js.map +1 -1
- package/dist/runtime/navigation.js +9 -1
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.d.ts +1 -1
- package/dist/runtime/reconcile.js +452 -197
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/run.d.ts +17 -2
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/scheduler.d.ts +10 -10
- package/dist/runtime/scheduler.js +1 -1
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/stream-protocol.d.ts +8 -0
- package/dist/runtime/stream-protocol.js +20 -0
- package/dist/runtime/stream-protocol.js.map +1 -0
- package/dist/runtime/svg-attributes.js +1 -0
- package/dist/runtime/svg-attributes.js.map +1 -1
- package/dist/runtime/to-vnode.js +7 -11
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/vnode.d.ts +11 -5
- package/dist/runtime/vnode.js +6 -3
- package/dist/runtime/vnode.js.map +1 -1
- package/dist/server/stream.d.ts +2 -0
- package/dist/server/stream.js +154 -114
- package/dist/server/stream.js.map +1 -1
- package/dist/style/css-mixin.d.ts +2 -1
- package/dist/style/css-mixin.js.map +1 -1
- package/dist/style/index.d.ts +1 -1
- package/dist/style/layers.d.ts +2 -0
- package/dist/style/layers.js +3 -0
- package/dist/style/layers.js.map +1 -0
- package/dist/style/stylesheet.d.ts +13 -11
- package/dist/style/stylesheet.js +69 -8
- package/dist/style/stylesheet.js.map +1 -1
- package/dist/theme/contract.d.ts +24 -222
- package/dist/theme/contract.js +2 -2
- package/dist/theme/contract.js.map +1 -1
- package/dist/theme/glyph-contract.d.ts +1 -3
- package/dist/theme/glyph-contract.js.map +1 -1
- package/dist/theme/presets/rmx-01/index.d.ts +4 -2
- package/dist/theme/presets/rmx-01/index.js.map +1 -1
- package/dist/theme/runtime.js +4 -1
- package/dist/theme/runtime.js.map +1 -1
- package/dist/utils/scroll-lock.d.ts +3 -3
- package/dist/utils/scroll-lock.js.map +1 -1
- package/package.json +3 -3
- package/src/animation/README.md +316 -0
- package/src/animation/animate-layout-mixin.ts +79 -71
- package/src/animation/spring.ts +21 -9
- package/src/components/accordion/README.md +166 -0
- package/src/components/accordion/accordion.tsx +14 -14
- package/src/components/accordion/demos/card.demo.tsx +113 -0
- package/src/components/accordion/demos/multiple.demo.tsx +56 -0
- package/src/components/accordion/demos/overview.demo.tsx +56 -0
- package/src/components/anchor/README.md +153 -0
- package/src/components/anchor/anchor.ts +1 -1
- package/src/components/breadcrumbs/README.md +55 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +1 -3
- package/src/components/breadcrumbs/demos/basic.demo.tsx +17 -0
- package/src/components/breadcrumbs/demos/separator.demo.tsx +18 -0
- package/src/components/button/README.md +4 -4
- package/src/components/button/button.tsx +118 -20
- package/src/components/button/demos/aliases.demo.tsx +27 -0
- package/src/components/button/demos/basic.demo.tsx +30 -0
- package/src/components/button/demos/states.demo.tsx +52 -0
- package/src/components/combobox/README.md +1 -1
- package/src/components/combobox/combobox.tsx +37 -21
- package/src/components/combobox/demos/overview.demo.tsx +199 -0
- package/src/components/glyph/README.md +72 -0
- package/src/components/glyph/glyph.tsx +2 -2
- package/src/components/listbox/README.md +115 -0
- package/src/components/listbox/demos/overview.demo.tsx +101 -0
- package/src/components/listbox/listbox.ts +106 -110
- package/src/components/menu/README.md +96 -0
- package/src/components/menu/demos/bubbling.demo.tsx +34 -0
- package/src/components/menu/demos/overview.demo.tsx +76 -0
- package/src/components/menu/menu.tsx +61 -55
- package/src/components/popover/README.md +3 -3
- package/src/components/popover/demos/overview.demo.tsx +143 -0
- package/src/components/popover/popover.ts +90 -79
- package/src/components/select/README.md +107 -0
- package/src/components/select/demos/deconstructed.demo.tsx +95 -0
- package/src/components/select/demos/overview.demo.tsx +51 -0
- package/src/components/select/select.tsx +53 -36
- package/src/components/tabs/tabs.tsx +10 -5
- package/src/index.ts +2 -1
- package/src/runtime/component.ts +122 -88
- package/src/runtime/core/attributes.ts +118 -0
- package/src/runtime/core/children.ts +42 -0
- package/src/runtime/core/props.ts +187 -0
- package/src/runtime/core/vnode.ts +48 -0
- package/src/runtime/create-element.ts +2 -1
- package/src/runtime/diff-dom.ts +59 -12
- package/src/runtime/diff-props.ts +2 -187
- package/src/runtime/dom.ts +20 -9
- package/src/runtime/frame.ts +71 -55
- package/src/runtime/jsx.ts +3 -30
- package/src/runtime/mixins/link-mixin.ts +88 -86
- package/src/runtime/mixins/mixin.ts +18 -5
- package/src/runtime/mixins/on-mixin.ts +20 -12
- package/src/runtime/mixins/ref-mixin.ts +4 -5
- package/src/runtime/navigation.ts +10 -1
- package/src/runtime/reconcile.ts +563 -223
- package/src/runtime/run.ts +17 -1
- package/src/runtime/scheduler.ts +20 -20
- package/src/runtime/stream-protocol.ts +27 -0
- package/src/runtime/svg-attributes.ts +1 -0
- package/src/runtime/to-vnode.ts +7 -10
- package/src/runtime/vnode.ts +16 -9
- package/src/server/README.md +90 -0
- package/src/server/stream.ts +176 -124
- package/src/style/css-mixin.ts +6 -1
- package/src/style/index.ts +1 -2
- package/src/style/layers.ts +2 -0
- package/src/style/stylesheet.ts +88 -11
- package/src/test/README.md +107 -0
- package/src/test/utils.ts +3 -1
- package/src/theme/README.md +103 -0
- package/src/theme/contract.ts +37 -5
- package/src/theme/glyph-contract.ts +3 -1
- package/src/theme/presets/rmx-01/index.ts +4 -2
- package/src/theme/runtime.ts +4 -1
- package/src/utils/scroll-lock/README.md +33 -0
- package/src/utils/scroll-lock.ts +7 -3
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { createComponent, Frame } from "./component.js";
|
|
2
2
|
import { createFrame } from "./frame.js";
|
|
3
3
|
import { createRangeRoot } from "./vdom.js";
|
|
4
|
-
import { isCommittedComponentNode, isComponentNode, isCommittedHostNode, isCommittedTextNode, isFragmentNode, isHostNode, isTextNode, findContextFromAncestry, } from "./vnode.js";
|
|
4
|
+
import { isCommittedComponentNode, isComponentNode, isCommittedHostNode, isCommittedTextNode, isFragmentNode, isHostNode, isNonRenderNode, isTextNode, findContextFromAncestry, } from "./vnode.js";
|
|
5
5
|
import { invariant } from "./invariant.js";
|
|
6
|
-
import {
|
|
6
|
+
import { patchHostProps } from "./core/props.js";
|
|
7
7
|
import { skipComments, logHydrationMismatch } from "./client-entries.js";
|
|
8
8
|
import { toVNode } from "./to-vnode.js";
|
|
9
9
|
import { bindMixinRuntime, cancelPendingMixinRemoval, dispatchMixinBeforeUpdate, dispatchMixinCommit, getMixinRuntimeSignal, prepareMixinRemoval, resolveMixedProps, teardownMixins, } from "./mixins/mixin.js";
|
|
10
|
+
import { isOnMixinDescriptor } from "./mixins/on-mixin.js";
|
|
10
11
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
11
|
-
// Internal diffing flags (modeled after Preact)
|
|
12
|
-
const INSERT_VNODE = 1 << 0;
|
|
13
|
-
const MATCHED = 1 << 1;
|
|
14
12
|
let idCounter = 0;
|
|
15
13
|
let persistedRemovalToken = 0;
|
|
16
14
|
const persistedMixinNodes = new Set();
|
|
@@ -60,6 +58,7 @@ function findMatchingPersistedMixinNode(type, key, domParent) {
|
|
|
60
58
|
}
|
|
61
59
|
return null;
|
|
62
60
|
}
|
|
61
|
+
const EMPTY_DIRECT_EVENT_DESCRIPTORS = [];
|
|
63
62
|
function shouldRestoreControlledReflectionOnInput(node, state) {
|
|
64
63
|
// Some controls dispatch `input` before `change` for the same interaction.
|
|
65
64
|
// When checked/value state is typically handled on `change`, restoring on the
|
|
@@ -179,6 +178,17 @@ function setPropertyReflection(element, key, value) {
|
|
|
179
178
|
}
|
|
180
179
|
function resolveNodeMixProps(node, frame, scheduler, state) {
|
|
181
180
|
let mix = node.props.mix;
|
|
181
|
+
let directEventDescriptors = resolveDirectEventDescriptors(mix);
|
|
182
|
+
if (directEventDescriptors) {
|
|
183
|
+
if (state) {
|
|
184
|
+
teardownMixins(state);
|
|
185
|
+
}
|
|
186
|
+
node._mixState = undefined;
|
|
187
|
+
node._mixedProps = node.props;
|
|
188
|
+
node._directEventDescriptors = directEventDescriptors;
|
|
189
|
+
return node.props;
|
|
190
|
+
}
|
|
191
|
+
node._directEventDescriptors = undefined;
|
|
182
192
|
if (state == null && (mix == null || (Array.isArray(mix) && mix.length === 0))) {
|
|
183
193
|
node._mixState = undefined;
|
|
184
194
|
node._mixedProps = node.props;
|
|
@@ -201,6 +211,21 @@ function resolveNodeMixProps(node, frame, scheduler, state) {
|
|
|
201
211
|
node._mixedProps = resolved.props;
|
|
202
212
|
return resolved.props;
|
|
203
213
|
}
|
|
214
|
+
function resolveDirectEventDescriptors(mix) {
|
|
215
|
+
if (!mix)
|
|
216
|
+
return EMPTY_DIRECT_EVENT_DESCRIPTORS;
|
|
217
|
+
if (!Array.isArray(mix)) {
|
|
218
|
+
return isOnMixinDescriptor(mix) ? [mix] : null;
|
|
219
|
+
}
|
|
220
|
+
return areOnMixinDescriptors(mix) ? mix : null;
|
|
221
|
+
}
|
|
222
|
+
function areOnMixinDescriptors(descriptors) {
|
|
223
|
+
for (let item of descriptors) {
|
|
224
|
+
if (!isOnMixinDescriptor(item))
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
204
229
|
function enqueueMixinBindingUpdate(done) {
|
|
205
230
|
let node = this.target;
|
|
206
231
|
let state = node._mixState;
|
|
@@ -213,7 +238,7 @@ function enqueueMixinBindingUpdate(done) {
|
|
|
213
238
|
dispatchMixinBeforeUpdate(state);
|
|
214
239
|
let prevProps = getHostProps(node);
|
|
215
240
|
let nextProps = resolveNodeMixProps(node, this.frame, this.scheduler, state);
|
|
216
|
-
|
|
241
|
+
patchHostProps(prevProps, nextProps, this.node);
|
|
217
242
|
dispatchMixinCommit(state);
|
|
218
243
|
done(state ? getMixinRuntimeSignal(state) : AbortSignal.abort());
|
|
219
244
|
},
|
|
@@ -258,6 +283,9 @@ export function diffVNodes(curr, next, domParent, frame, scheduler, styles, vPar
|
|
|
258
283
|
replace(curr, next, domParent, frame, scheduler, styles, vParent, rootTarget, anchor);
|
|
259
284
|
return rootCursor;
|
|
260
285
|
}
|
|
286
|
+
if (isNonRenderNode(curr) && isNonRenderNode(next)) {
|
|
287
|
+
return rootCursor;
|
|
288
|
+
}
|
|
261
289
|
if (isCommittedTextNode(curr) && isTextNode(next)) {
|
|
262
290
|
diffText(curr, next, vParent);
|
|
263
291
|
return rootCursor;
|
|
@@ -271,7 +299,7 @@ export function diffVNodes(curr, next, domParent, frame, scheduler, styles, vPar
|
|
|
271
299
|
return rootCursor;
|
|
272
300
|
}
|
|
273
301
|
if (isFragmentNode(curr) && isFragmentNode(next)) {
|
|
274
|
-
diffChildren(curr._children, next._children, domParent, frame, scheduler, styles,
|
|
302
|
+
diffChildren(curr._children, next._children, domParent, frame, scheduler, styles, next, rootTarget, undefined, anchor);
|
|
275
303
|
return rootCursor;
|
|
276
304
|
}
|
|
277
305
|
if (curr.type === Frame && next.type === Frame) {
|
|
@@ -294,7 +322,7 @@ function replace(curr, next, domParent, frame, scheduler, styles, vParent, rootT
|
|
|
294
322
|
}
|
|
295
323
|
return;
|
|
296
324
|
}
|
|
297
|
-
let replacementAnchor = findNextSiblingDomAnchor(curr
|
|
325
|
+
let replacementAnchor = findNextSiblingDomAnchor(curr) ?? anchor;
|
|
298
326
|
remove(curr, domParent, scheduler, styles);
|
|
299
327
|
insert(next, domParent, frame, scheduler, styles, vParent, rootTarget, replacementAnchor);
|
|
300
328
|
}
|
|
@@ -319,16 +347,20 @@ function diffHost(curr, next, frame, scheduler, styles, vParent, rootTarget) {
|
|
|
319
347
|
curr._dom.innerHTML = '';
|
|
320
348
|
}
|
|
321
349
|
diffChildren(curr._children, next._children, curr._dom, frame, scheduler, styles, next, rootTarget);
|
|
322
|
-
|
|
350
|
+
patchHostProps(currProps, nextProps, curr._dom);
|
|
323
351
|
next._dom = curr._dom;
|
|
324
352
|
next._parent = vParent;
|
|
325
353
|
next._controller = curr._controller;
|
|
354
|
+
next._directEventState = curr._directEventState;
|
|
326
355
|
next._controlledState = curr._controlledState;
|
|
356
|
+
syncDirectEventListeners(next);
|
|
327
357
|
if (next._controlledState || shouldTrackControlledReflection(nextProps)) {
|
|
328
358
|
ensureControlledReflection(next, scheduler);
|
|
329
359
|
syncControlledReflection(next, nextProps);
|
|
330
360
|
}
|
|
331
|
-
|
|
361
|
+
if (next._mixState) {
|
|
362
|
+
bindNodeMixRuntime(next, frame, scheduler, styles);
|
|
363
|
+
}
|
|
332
364
|
if (shouldDispatchMixinLifecycle) {
|
|
333
365
|
scheduler.enqueueCommitPhase([() => dispatchMixinCommit(nextMixState)]);
|
|
334
366
|
}
|
|
@@ -338,11 +370,94 @@ function setupHostNode(node, dom, scheduler) {
|
|
|
338
370
|
node._dom = dom;
|
|
339
371
|
let props = getHostProps(node);
|
|
340
372
|
let committedNode = node;
|
|
373
|
+
syncDirectEventListeners(committedNode);
|
|
341
374
|
if (shouldTrackControlledReflection(props)) {
|
|
342
375
|
ensureControlledReflection(committedNode, scheduler);
|
|
343
376
|
syncControlledReflection(committedNode, props);
|
|
344
377
|
}
|
|
345
378
|
}
|
|
379
|
+
function syncDirectEventListeners(node) {
|
|
380
|
+
let descriptors = node._directEventDescriptors;
|
|
381
|
+
if (!descriptors) {
|
|
382
|
+
teardownDirectEventListeners(node);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (descriptors.length === 0) {
|
|
386
|
+
teardownDirectEventListeners(node);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
let state = node._directEventState;
|
|
390
|
+
if (!state) {
|
|
391
|
+
state = { bindings: [] };
|
|
392
|
+
node._directEventState = state;
|
|
393
|
+
}
|
|
394
|
+
let bindings = state.bindings;
|
|
395
|
+
for (let index = 0; index < descriptors.length; index++) {
|
|
396
|
+
let descriptor = descriptors[index];
|
|
397
|
+
let [type, handler, captureBoolean = false] = descriptor.args;
|
|
398
|
+
let binding = bindings[index];
|
|
399
|
+
if (!binding) {
|
|
400
|
+
binding = createDirectEventBinding(type, handler, captureBoolean);
|
|
401
|
+
bindings[index] = binding;
|
|
402
|
+
attachDirectEventBinding(node._dom, binding);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (binding.type !== type || binding.capture !== captureBoolean) {
|
|
406
|
+
removeDirectEventBinding(node._dom, binding);
|
|
407
|
+
binding.type = type;
|
|
408
|
+
binding.capture = captureBoolean;
|
|
409
|
+
attachDirectEventBinding(node._dom, binding);
|
|
410
|
+
}
|
|
411
|
+
binding.handler = handler;
|
|
412
|
+
}
|
|
413
|
+
for (let index = descriptors.length; index < bindings.length; index++) {
|
|
414
|
+
removeDirectEventBinding(node._dom, bindings[index]);
|
|
415
|
+
}
|
|
416
|
+
bindings.length = descriptors.length;
|
|
417
|
+
}
|
|
418
|
+
function createDirectEventBinding(type, handler, capture) {
|
|
419
|
+
let binding = {
|
|
420
|
+
type,
|
|
421
|
+
handler,
|
|
422
|
+
capture,
|
|
423
|
+
reentry: null,
|
|
424
|
+
stableHandler: null,
|
|
425
|
+
};
|
|
426
|
+
return binding;
|
|
427
|
+
}
|
|
428
|
+
function getStableDirectEventHandler(binding) {
|
|
429
|
+
if (binding.stableHandler)
|
|
430
|
+
return binding.stableHandler;
|
|
431
|
+
binding.stableHandler = (event) => {
|
|
432
|
+
invokeDirectEventBinding(binding, event);
|
|
433
|
+
};
|
|
434
|
+
return binding.stableHandler;
|
|
435
|
+
}
|
|
436
|
+
function attachDirectEventBinding(dom, binding) {
|
|
437
|
+
dom.addEventListener(binding.type, getStableDirectEventHandler(binding), binding.capture);
|
|
438
|
+
}
|
|
439
|
+
function removeDirectEventBinding(dom, binding) {
|
|
440
|
+
if (binding.stableHandler) {
|
|
441
|
+
dom.removeEventListener(binding.type, binding.stableHandler, binding.capture);
|
|
442
|
+
}
|
|
443
|
+
binding.reentry?.abort(new DOMException('', 'AbortError'));
|
|
444
|
+
binding.reentry = null;
|
|
445
|
+
}
|
|
446
|
+
function teardownDirectEventListeners(node) {
|
|
447
|
+
let state = node._directEventState;
|
|
448
|
+
if (!state)
|
|
449
|
+
return;
|
|
450
|
+
for (let binding of state.bindings) {
|
|
451
|
+
removeDirectEventBinding(node._dom, binding);
|
|
452
|
+
}
|
|
453
|
+
state.bindings.length = 0;
|
|
454
|
+
node._directEventState = undefined;
|
|
455
|
+
}
|
|
456
|
+
function invokeDirectEventBinding(binding, event) {
|
|
457
|
+
binding.reentry?.abort(new DOMException('', 'EventReentry'));
|
|
458
|
+
binding.reentry = new AbortController();
|
|
459
|
+
void binding.handler(event, binding.reentry.signal);
|
|
460
|
+
}
|
|
346
461
|
function diffText(curr, next, vParent) {
|
|
347
462
|
if (curr._text !== next._text) {
|
|
348
463
|
curr._dom.textContent = next._text;
|
|
@@ -369,6 +484,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
369
484
|
let doInsert = anchor
|
|
370
485
|
? (dom) => domParent.insertBefore(dom, anchor)
|
|
371
486
|
: (dom) => domParent.appendChild(dom);
|
|
487
|
+
if (isNonRenderNode(node)) {
|
|
488
|
+
return cursor;
|
|
489
|
+
}
|
|
372
490
|
if (isTextNode(node)) {
|
|
373
491
|
if (cursor instanceof Text) {
|
|
374
492
|
node._parent = vParent;
|
|
@@ -414,9 +532,11 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
414
532
|
}
|
|
415
533
|
// Render explicit <head> children directly into document.head.
|
|
416
534
|
diffChildren(null, node._children, targetHead, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
417
|
-
|
|
535
|
+
patchHostProps({}, hostProps, targetHead);
|
|
418
536
|
setupHostNode(node, targetHead, scheduler);
|
|
419
|
-
|
|
537
|
+
if (node._mixState) {
|
|
538
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
539
|
+
}
|
|
420
540
|
return cursor;
|
|
421
541
|
}
|
|
422
542
|
}
|
|
@@ -432,7 +552,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
432
552
|
let cursorTag = node._svg ? cursor.tagName : cursor.tagName.toLowerCase();
|
|
433
553
|
if (cursorTag === node.type) {
|
|
434
554
|
let nextCursor = cursor.nextSibling;
|
|
435
|
-
|
|
555
|
+
patchHostProps({}, hostProps, cursor);
|
|
436
556
|
// Handle innerHTML prop
|
|
437
557
|
if (hostProps.innerHTML != null) {
|
|
438
558
|
cursor.innerHTML = hostProps.innerHTML;
|
|
@@ -443,7 +563,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
443
563
|
diffChildren(null, node._children, cursor, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
444
564
|
}
|
|
445
565
|
setupHostNode(node, cursor, scheduler);
|
|
446
|
-
|
|
566
|
+
if (node._mixState) {
|
|
567
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
568
|
+
}
|
|
447
569
|
return nextCursor;
|
|
448
570
|
}
|
|
449
571
|
else {
|
|
@@ -455,7 +577,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
455
577
|
if (nextTag === node.type) {
|
|
456
578
|
let nextCursor = nextSibling.nextSibling;
|
|
457
579
|
// Found a match after skipping - adopt it and leave skipped node in place
|
|
458
|
-
|
|
580
|
+
patchHostProps({}, hostProps, nextSibling);
|
|
459
581
|
if (hostProps.innerHTML != null) {
|
|
460
582
|
nextSibling.innerHTML = hostProps.innerHTML;
|
|
461
583
|
}
|
|
@@ -464,7 +586,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
464
586
|
diffChildren(null, node._children, nextSibling, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
465
587
|
}
|
|
466
588
|
setupHostNode(node, nextSibling, scheduler);
|
|
467
|
-
|
|
589
|
+
if (node._mixState) {
|
|
590
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
591
|
+
}
|
|
468
592
|
return nextCursor;
|
|
469
593
|
}
|
|
470
594
|
}
|
|
@@ -476,7 +600,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
476
600
|
let dom = node._svg
|
|
477
601
|
? document.createElementNS(SVG_NS, node.type)
|
|
478
602
|
: document.createElement(node.type);
|
|
479
|
-
|
|
603
|
+
patchHostProps({}, hostProps, dom);
|
|
480
604
|
// Handle innerHTML prop
|
|
481
605
|
if (hostProps.innerHTML != null) {
|
|
482
606
|
dom.innerHTML = hostProps.innerHTML;
|
|
@@ -485,14 +609,16 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
485
609
|
diffChildren(null, node._children, dom, frame, scheduler, styles, node, rootTarget);
|
|
486
610
|
}
|
|
487
611
|
setupHostNode(node, dom, scheduler);
|
|
488
|
-
|
|
612
|
+
if (node._mixState) {
|
|
613
|
+
bindNodeMixRuntime(node, frame, scheduler, styles, false, domParent);
|
|
614
|
+
}
|
|
489
615
|
doInsert(dom);
|
|
490
616
|
return cursor;
|
|
491
617
|
}
|
|
492
618
|
if (isFragmentNode(node)) {
|
|
493
619
|
// Insert fragment children in order before the same anchor
|
|
494
620
|
for (let child of node._children) {
|
|
495
|
-
cursor = insert(child, domParent, frame, scheduler, styles,
|
|
621
|
+
cursor = insert(child, domParent, frame, scheduler, styles, node, rootTarget, anchor, cursor);
|
|
496
622
|
}
|
|
497
623
|
return cursor;
|
|
498
624
|
}
|
|
@@ -783,6 +909,8 @@ function findFrameEndComment(start) {
|
|
|
783
909
|
return null;
|
|
784
910
|
}
|
|
785
911
|
export function renderComponent(handle, currContent, next, domParent, frame, scheduler, styles, rootTarget, vParent, anchor, cursor) {
|
|
912
|
+
if (handle.isRemoved())
|
|
913
|
+
return cursor;
|
|
786
914
|
let [element, tasks] = handle.render(next.props);
|
|
787
915
|
let content = toVNode(element);
|
|
788
916
|
let newCursor = diffVNodes(currContent, content, domParent, frame, scheduler, styles, next, rootTarget, anchor, cursor);
|
|
@@ -835,6 +963,7 @@ function cleanupDescendants(node, scheduler, styles) {
|
|
|
835
963
|
cleanupDescendants(child, scheduler, styles);
|
|
836
964
|
}
|
|
837
965
|
teardownMixins(node._mixState);
|
|
966
|
+
teardownDirectEventListeners(node);
|
|
838
967
|
teardownControlledReflection(node);
|
|
839
968
|
if (node._controller)
|
|
840
969
|
node._controller.abort();
|
|
@@ -916,6 +1045,7 @@ function performHostNodeRemoval(node, domParent, scheduler, styles) {
|
|
|
916
1045
|
}
|
|
917
1046
|
}
|
|
918
1047
|
teardownMixins(node._mixState);
|
|
1048
|
+
teardownDirectEventListeners(node);
|
|
919
1049
|
teardownControlledReflection(node);
|
|
920
1050
|
// Never remove the real document.head node when reconciling a <head> vnode.
|
|
921
1051
|
if (!isHeadHostNode(node)) {
|
|
@@ -925,55 +1055,35 @@ function performHostNodeRemoval(node, domParent, scheduler, styles) {
|
|
|
925
1055
|
node._controller.abort();
|
|
926
1056
|
}
|
|
927
1057
|
function diffChildren(curr, next, domParent, frame, scheduler, styles, vParent, rootTarget, cursor, anchor) {
|
|
928
|
-
let
|
|
929
|
-
// Warn when duplicate keys are present among siblings. Duplicate keys are
|
|
930
|
-
// still processed (last one wins), but they make keyed diffing ambiguous.
|
|
931
|
-
let hasKeys = false;
|
|
932
|
-
let seenKeys;
|
|
933
|
-
let duplicateKeys;
|
|
934
|
-
for (let i = 0; i < nextLength; i++) {
|
|
935
|
-
let node = next[i];
|
|
936
|
-
if (node && node.key != null) {
|
|
937
|
-
hasKeys = true;
|
|
938
|
-
if (!seenKeys) {
|
|
939
|
-
seenKeys = new Set([node.key]);
|
|
940
|
-
continue;
|
|
941
|
-
}
|
|
942
|
-
if (seenKeys.has(node.key)) {
|
|
943
|
-
if (!duplicateKeys) {
|
|
944
|
-
duplicateKeys = new Set();
|
|
945
|
-
}
|
|
946
|
-
duplicateKeys.add(node.key);
|
|
947
|
-
}
|
|
948
|
-
else {
|
|
949
|
-
seenKeys.add(node.key);
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
if (duplicateKeys?.size) {
|
|
954
|
-
let quotedKeys = Array.from(duplicateKeys, (key) => `"${key}"`);
|
|
955
|
-
console.warn(`Duplicate keys detected in siblings: ${quotedKeys.join(', ')}. Keys should be unique.`);
|
|
956
|
-
}
|
|
957
|
-
// Initial mount / hydration: delegate to insert() for each child so that
|
|
958
|
-
// hydration cursors and creation logic remain centralized there.
|
|
1058
|
+
let hasKeys = hasKeyedChildren(next);
|
|
959
1059
|
if (curr === null) {
|
|
1060
|
+
if (hasKeys) {
|
|
1061
|
+
warnDuplicateKeys(next);
|
|
1062
|
+
}
|
|
960
1063
|
for (let node of next) {
|
|
961
1064
|
cursor = insert(node, domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
962
1065
|
}
|
|
963
1066
|
vParent._children = next;
|
|
964
1067
|
return cursor;
|
|
965
1068
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1069
|
+
if (next.length === 0 &&
|
|
1070
|
+
anchor === undefined &&
|
|
1071
|
+
!parentUsesInnerHTML(vParent) &&
|
|
1072
|
+
canBulkClearChildren(curr)) {
|
|
1073
|
+
for (let node of curr) {
|
|
1074
|
+
cleanupDescendants(node, scheduler, styles);
|
|
1075
|
+
}
|
|
1076
|
+
domParent.textContent = '';
|
|
1077
|
+
vParent._children = next;
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
970
1080
|
if (!hasKeys) {
|
|
971
|
-
for (let i = 0; i <
|
|
972
|
-
let currentNode = i <
|
|
1081
|
+
for (let i = 0; i < next.length; i++) {
|
|
1082
|
+
let currentNode = i < curr.length ? curr[i] : null;
|
|
973
1083
|
diffVNodes(currentNode, next[i], domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
974
1084
|
}
|
|
975
|
-
if (
|
|
976
|
-
for (let i =
|
|
1085
|
+
if (curr.length > next.length) {
|
|
1086
|
+
for (let i = next.length; i < curr.length; i++) {
|
|
977
1087
|
let node = curr[i];
|
|
978
1088
|
if (node)
|
|
979
1089
|
remove(node, domParent, scheduler, styles);
|
|
@@ -982,167 +1092,302 @@ function diffChildren(curr, next, domParent, frame, scheduler, styles, vParent,
|
|
|
982
1092
|
vParent._children = next;
|
|
983
1093
|
return;
|
|
984
1094
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
if (canDiffByPosition) {
|
|
996
|
-
for (let i = 0; i < nextLength; i++) {
|
|
997
|
-
diffVNodes(curr[i], next[i], domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
998
|
-
}
|
|
999
|
-
vParent._children = next;
|
|
1000
|
-
return;
|
|
1001
|
-
}
|
|
1095
|
+
patchKeyedChildren(curr, next, domParent, frame, scheduler, styles, vParent, rootTarget, cursor, anchor);
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
function parentUsesInnerHTML(parent) {
|
|
1099
|
+
return isHostNode(parent) && getHostProps(parent).innerHTML != null;
|
|
1100
|
+
}
|
|
1101
|
+
function canBulkClearChildren(children) {
|
|
1102
|
+
for (let child of children) {
|
|
1103
|
+
if (!canBulkClearNode(child))
|
|
1104
|
+
return false;
|
|
1002
1105
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
oldKeyMap.set(c.key, i);
|
|
1015
|
-
}
|
|
1106
|
+
return true;
|
|
1107
|
+
}
|
|
1108
|
+
function canBulkClearNode(node) {
|
|
1109
|
+
if (isCommittedTextNode(node))
|
|
1110
|
+
return true;
|
|
1111
|
+
if (isCommittedHostNode(node)) {
|
|
1112
|
+
if (node._mixState)
|
|
1113
|
+
return false;
|
|
1114
|
+
for (let child of node._children) {
|
|
1115
|
+
if (!canBulkClearNode(child))
|
|
1116
|
+
return false;
|
|
1016
1117
|
}
|
|
1118
|
+
return true;
|
|
1017
1119
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1120
|
+
if (isFragmentNode(node)) {
|
|
1121
|
+
return canBulkClearChildren(node._children);
|
|
1122
|
+
}
|
|
1123
|
+
if (isCommittedComponentNode(node)) {
|
|
1124
|
+
return canBulkClearNode(node._content);
|
|
1125
|
+
}
|
|
1126
|
+
return false;
|
|
1127
|
+
}
|
|
1128
|
+
function hasKeyedChildren(children) {
|
|
1129
|
+
for (let node of children) {
|
|
1130
|
+
if (node.key != null)
|
|
1131
|
+
return true;
|
|
1132
|
+
}
|
|
1133
|
+
return false;
|
|
1134
|
+
}
|
|
1135
|
+
function warnDuplicateKeys(children) {
|
|
1136
|
+
let seenKeys;
|
|
1137
|
+
let duplicateKeys;
|
|
1138
|
+
for (let node of children) {
|
|
1139
|
+
if (node.key == null)
|
|
1140
|
+
continue;
|
|
1141
|
+
if (!seenKeys) {
|
|
1142
|
+
seenKeys = new Set([node.key]);
|
|
1025
1143
|
continue;
|
|
1026
1144
|
}
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
let matchingIndex = -1;
|
|
1031
|
-
let key = childVNode.key;
|
|
1032
|
-
let type = childVNode.type;
|
|
1033
|
-
if (key != null) {
|
|
1034
|
-
// O(1) Map lookup for keyed children
|
|
1035
|
-
let mapIndex = oldKeyMap.get(key);
|
|
1036
|
-
if (mapIndex !== undefined) {
|
|
1037
|
-
let candidate = oldChildren[mapIndex];
|
|
1038
|
-
let candidateFlags = candidate?._flags ?? 0;
|
|
1039
|
-
if (candidate && (candidateFlags & MATCHED) === 0 && candidate.type === type) {
|
|
1040
|
-
matchingIndex = mapIndex;
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1145
|
+
if (seenKeys.has(node.key)) {
|
|
1146
|
+
duplicateKeys ??= new Set();
|
|
1147
|
+
duplicateKeys.add(node.key);
|
|
1043
1148
|
}
|
|
1044
1149
|
else {
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1150
|
+
seenKeys.add(node.key);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
if (duplicateKeys?.size) {
|
|
1154
|
+
let quotedKeys = Array.from(duplicateKeys, (key) => `"${key}"`);
|
|
1155
|
+
console.warn(`Duplicate keys detected in siblings: ${quotedKeys.join(', ')}. Keys should be unique.`);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
function patchKeyedChildren(curr, next, domParent, frame, scheduler, styles, vParent, rootTarget, cursor, anchor) {
|
|
1159
|
+
let matches = matchKeyedChildrenInOrder(curr, next) ??
|
|
1160
|
+
matchKeyedChildrenAfterSingleRemoval(curr, next) ??
|
|
1161
|
+
matchKeyedChildrenAfterPairSwap(curr, next);
|
|
1162
|
+
if (!matches) {
|
|
1163
|
+
warnDuplicateKeys(next);
|
|
1164
|
+
matches = matchKeyedChildren(curr, next);
|
|
1165
|
+
}
|
|
1166
|
+
let matchAnalysis = analyzeKeyedChildMatches(curr.length, matches);
|
|
1167
|
+
if (matchAnalysis.hasRemovals) {
|
|
1168
|
+
let usedOldIndexes = new Uint8Array(curr.length);
|
|
1169
|
+
for (let match of matches) {
|
|
1170
|
+
if (match.oldIndex >= 0) {
|
|
1171
|
+
usedOldIndexes[match.oldIndex] = 1;
|
|
1051
1172
|
}
|
|
1052
1173
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
matchedOldVNode = oldChildren[matchingIndex];
|
|
1057
|
-
remainingOldChildren--;
|
|
1058
|
-
if (matchedOldVNode) {
|
|
1059
|
-
matchedOldVNode._flags = (matchedOldVNode._flags ?? 0) | MATCHED;
|
|
1174
|
+
for (let oldIndex = 0; oldIndex < curr.length; oldIndex++) {
|
|
1175
|
+
if (usedOldIndexes[oldIndex] === 0) {
|
|
1176
|
+
remove(curr[oldIndex], domParent, scheduler, styles);
|
|
1060
1177
|
}
|
|
1061
1178
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1179
|
+
}
|
|
1180
|
+
vParent._children = next;
|
|
1181
|
+
for (let index = 0; index < next.length; index++) {
|
|
1182
|
+
let match = matches[index];
|
|
1183
|
+
let oldNode = match.oldIndex >= 0 ? curr[match.oldIndex] : null;
|
|
1184
|
+
diffVNodes(oldNode, next[index], domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
1185
|
+
}
|
|
1186
|
+
if (matchAnalysis.canSkipPlacement) {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
let stableIndexes = lisMatches(matches);
|
|
1190
|
+
let stableCursor = stableIndexes.length - 1;
|
|
1191
|
+
let placementAnchor = anchor ?? null;
|
|
1192
|
+
for (let index = next.length - 1; index >= 0; index--) {
|
|
1193
|
+
let nextNode = next[index];
|
|
1194
|
+
let isStable = stableIndexes[stableCursor] === index;
|
|
1195
|
+
if (isStable) {
|
|
1196
|
+
stableCursor--;
|
|
1197
|
+
}
|
|
1198
|
+
else {
|
|
1199
|
+
placeVNode(nextNode, domParent, placementAnchor);
|
|
1200
|
+
}
|
|
1201
|
+
placementAnchor = findFirstDomAnchor(nextNode) ?? placementAnchor;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
function matchKeyedChildren(curr, next) {
|
|
1205
|
+
let oldKeyMap = new Map();
|
|
1206
|
+
let usedOldIndexes = new Set();
|
|
1207
|
+
let unkeyedSearchStart = 0;
|
|
1208
|
+
for (let index = 0; index < curr.length; index++) {
|
|
1209
|
+
let key = curr[index].key;
|
|
1210
|
+
if (key != null)
|
|
1211
|
+
oldKeyMap.set(key, index);
|
|
1212
|
+
}
|
|
1213
|
+
return next.map((nextNode) => {
|
|
1214
|
+
let oldIndex = -1;
|
|
1215
|
+
if (nextNode.key != null) {
|
|
1216
|
+
let keyedOldIndex = oldKeyMap.get(nextNode.key);
|
|
1217
|
+
if (keyedOldIndex !== undefined) {
|
|
1218
|
+
let oldNode = curr[keyedOldIndex];
|
|
1219
|
+
if (!usedOldIndexes.has(keyedOldIndex) && oldNode.type === nextNode.type) {
|
|
1220
|
+
oldIndex = keyedOldIndex;
|
|
1073
1221
|
}
|
|
1074
1222
|
}
|
|
1075
|
-
childVNode._flags = (childVNode._flags ?? 0) | INSERT_VNODE;
|
|
1076
1223
|
}
|
|
1077
|
-
else
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
skew--;
|
|
1087
|
-
else
|
|
1088
|
-
skew++;
|
|
1089
|
-
childVNode._flags = (childVNode._flags ?? 0) | INSERT_VNODE;
|
|
1224
|
+
else {
|
|
1225
|
+
for (let index = unkeyedSearchStart; index < curr.length; index++) {
|
|
1226
|
+
let oldNode = curr[index];
|
|
1227
|
+
if (usedOldIndexes.has(index) || oldNode.key != null || oldNode.type !== nextNode.type) {
|
|
1228
|
+
continue;
|
|
1229
|
+
}
|
|
1230
|
+
oldIndex = index;
|
|
1231
|
+
unkeyedSearchStart = index + 1;
|
|
1232
|
+
break;
|
|
1090
1233
|
}
|
|
1091
1234
|
}
|
|
1235
|
+
if (oldIndex >= 0)
|
|
1236
|
+
usedOldIndexes.add(oldIndex);
|
|
1237
|
+
return { oldIndex };
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
function matchKeyedChildrenInOrder(curr, next) {
|
|
1241
|
+
let length = Math.min(curr.length, next.length);
|
|
1242
|
+
let matches = [];
|
|
1243
|
+
for (let index = 0; index < length; index++) {
|
|
1244
|
+
let nextNode = next[index];
|
|
1245
|
+
if (nextNode.key == null)
|
|
1246
|
+
return null;
|
|
1247
|
+
let oldNode = curr[index];
|
|
1248
|
+
if (oldNode.key !== nextNode.key || oldNode.type !== nextNode.type) {
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
matches.push({ oldIndex: index });
|
|
1092
1252
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1253
|
+
for (let index = length; index < next.length; index++) {
|
|
1254
|
+
if (next[index].key == null)
|
|
1255
|
+
return null;
|
|
1256
|
+
matches.push({ oldIndex: -1 });
|
|
1257
|
+
}
|
|
1258
|
+
return matches;
|
|
1259
|
+
}
|
|
1260
|
+
function matchKeyedChildrenAfterSingleRemoval(curr, next) {
|
|
1261
|
+
if (curr.length !== next.length + 1)
|
|
1262
|
+
return null;
|
|
1263
|
+
let matches = [];
|
|
1264
|
+
let oldIndex = 0;
|
|
1265
|
+
let skippedOldNode = false;
|
|
1266
|
+
for (let nextIndex = 0; nextIndex < next.length; nextIndex++) {
|
|
1267
|
+
let nextNode = next[nextIndex];
|
|
1268
|
+
if (nextNode.key == null)
|
|
1269
|
+
return null;
|
|
1270
|
+
let oldNode = curr[oldIndex];
|
|
1271
|
+
if (oldNode.key === nextNode.key && oldNode.type === nextNode.type) {
|
|
1272
|
+
matches.push({ oldIndex });
|
|
1273
|
+
oldIndex++;
|
|
1274
|
+
continue;
|
|
1275
|
+
}
|
|
1276
|
+
if (skippedOldNode)
|
|
1277
|
+
return null;
|
|
1278
|
+
skippedOldNode = true;
|
|
1279
|
+
oldIndex++;
|
|
1280
|
+
oldNode = curr[oldIndex];
|
|
1281
|
+
if (oldNode.key !== nextNode.key || oldNode.type !== nextNode.type) {
|
|
1282
|
+
return null;
|
|
1100
1283
|
}
|
|
1284
|
+
matches.push({ oldIndex });
|
|
1285
|
+
oldIndex++;
|
|
1101
1286
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1287
|
+
return matches;
|
|
1288
|
+
}
|
|
1289
|
+
function matchKeyedChildrenAfterPairSwap(curr, next) {
|
|
1290
|
+
if (curr.length !== next.length)
|
|
1291
|
+
return null;
|
|
1292
|
+
let matches = [];
|
|
1293
|
+
let firstMismatch = -1;
|
|
1294
|
+
let secondMismatch = -1;
|
|
1295
|
+
for (let index = 0; index < next.length; index++) {
|
|
1296
|
+
let nextNode = next[index];
|
|
1297
|
+
if (nextNode.key == null)
|
|
1298
|
+
return null;
|
|
1299
|
+
let oldNode = curr[index];
|
|
1300
|
+
if (oldNode.key === nextNode.key && oldNode.type === nextNode.type) {
|
|
1301
|
+
matches.push({ oldIndex: index });
|
|
1109
1302
|
continue;
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1303
|
+
}
|
|
1304
|
+
if (firstMismatch === -1) {
|
|
1305
|
+
firstMismatch = index;
|
|
1306
|
+
}
|
|
1307
|
+
else if (secondMismatch === -1) {
|
|
1308
|
+
secondMismatch = index;
|
|
1309
|
+
}
|
|
1310
|
+
else {
|
|
1311
|
+
return null;
|
|
1312
|
+
}
|
|
1313
|
+
matches.push({ oldIndex: -1 });
|
|
1314
|
+
}
|
|
1315
|
+
if (firstMismatch === -1)
|
|
1316
|
+
return matches;
|
|
1317
|
+
if (secondMismatch === -1)
|
|
1318
|
+
return null;
|
|
1319
|
+
let firstOldNode = curr[firstMismatch];
|
|
1320
|
+
let secondOldNode = curr[secondMismatch];
|
|
1321
|
+
let firstNextNode = next[firstMismatch];
|
|
1322
|
+
let secondNextNode = next[secondMismatch];
|
|
1323
|
+
if (firstOldNode.key !== secondNextNode.key ||
|
|
1324
|
+
firstOldNode.type !== secondNextNode.type ||
|
|
1325
|
+
secondOldNode.key !== firstNextNode.key ||
|
|
1326
|
+
secondOldNode.type !== firstNextNode.type) {
|
|
1327
|
+
return null;
|
|
1328
|
+
}
|
|
1329
|
+
matches[firstMismatch] = { oldIndex: secondMismatch };
|
|
1330
|
+
matches[secondMismatch] = { oldIndex: firstMismatch };
|
|
1331
|
+
return matches;
|
|
1332
|
+
}
|
|
1333
|
+
function analyzeKeyedChildMatches(currentLength, matches) {
|
|
1334
|
+
let hasRemovals = matches.length !== currentLength;
|
|
1335
|
+
let canSkipPlacement = true;
|
|
1336
|
+
let lastOldIndex = -1;
|
|
1337
|
+
let sawNewNode = false;
|
|
1338
|
+
for (let match of matches) {
|
|
1339
|
+
if (match.oldIndex < 0) {
|
|
1340
|
+
hasRemovals = true;
|
|
1341
|
+
sawNewNode = true;
|
|
1342
|
+
continue;
|
|
1343
|
+
}
|
|
1344
|
+
if (sawNewNode || match.oldIndex < lastOldIndex) {
|
|
1345
|
+
canSkipPlacement = false;
|
|
1346
|
+
}
|
|
1347
|
+
lastOldIndex = match.oldIndex;
|
|
1348
|
+
}
|
|
1349
|
+
return { hasRemovals, canSkipPlacement };
|
|
1350
|
+
}
|
|
1351
|
+
function lisMatches(matches) {
|
|
1352
|
+
let predecessors = Array.from({ length: matches.length });
|
|
1353
|
+
let tails = [];
|
|
1354
|
+
for (let index = 0; index < matches.length; index++) {
|
|
1355
|
+
let value = matches[index].oldIndex + 1;
|
|
1356
|
+
if (value === 0)
|
|
1357
|
+
continue;
|
|
1358
|
+
let low = 0;
|
|
1359
|
+
let high = tails.length;
|
|
1360
|
+
while (low < high) {
|
|
1361
|
+
let middle = (low + high) >> 1;
|
|
1362
|
+
if (matches[tails[middle]].oldIndex + 1 < value) {
|
|
1363
|
+
low = middle + 1;
|
|
1125
1364
|
}
|
|
1126
1365
|
else {
|
|
1127
|
-
|
|
1128
|
-
}
|
|
1129
|
-
if (target === null && anchor)
|
|
1130
|
-
target = anchor;
|
|
1131
|
-
// If target lies within the range we're moving, skip the move.
|
|
1132
|
-
if (target && domRangeContainsNode(firstDom, lastDom, target)) {
|
|
1133
|
-
// no-op
|
|
1134
|
-
}
|
|
1135
|
-
else if (firstDom !== target) {
|
|
1136
|
-
moveDomRange(domParent, firstDom, lastDom, target);
|
|
1366
|
+
high = middle;
|
|
1137
1367
|
}
|
|
1138
1368
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
// Clear internal flags for next diff
|
|
1142
|
-
childVNode._flags = 0;
|
|
1143
|
-
childVNode._index = undefined;
|
|
1369
|
+
predecessors[index] = low > 0 ? tails[low - 1] : -1;
|
|
1370
|
+
tails[low] = index;
|
|
1144
1371
|
}
|
|
1145
|
-
|
|
1372
|
+
let cursor = tails.at(-1) ?? -1;
|
|
1373
|
+
for (let index = tails.length - 1; index >= 0; index--) {
|
|
1374
|
+
tails[index] = cursor;
|
|
1375
|
+
cursor = predecessors[cursor] ?? -1;
|
|
1376
|
+
}
|
|
1377
|
+
return tails;
|
|
1378
|
+
}
|
|
1379
|
+
function placeVNode(node, domParent, anchor) {
|
|
1380
|
+
let firstDom = findFirstDomAnchor(node);
|
|
1381
|
+
if (!firstDom || firstDom.parentNode !== domParent)
|
|
1382
|
+
return;
|
|
1383
|
+
let lastDom = findLastDomAnchor(node);
|
|
1384
|
+
if (!lastDom)
|
|
1385
|
+
return;
|
|
1386
|
+
if (anchor && domRangeContainsNode(firstDom, lastDom, anchor))
|
|
1387
|
+
return;
|
|
1388
|
+
if (firstDom === anchor)
|
|
1389
|
+
return;
|
|
1390
|
+
moveDomRange(domParent, firstDom, lastDom, anchor);
|
|
1146
1391
|
}
|
|
1147
1392
|
export function findFirstDomAnchor(node) {
|
|
1148
1393
|
if (!node)
|
|
@@ -1221,10 +1466,13 @@ function shouldDispatchInlineMixinLifecycle(node) {
|
|
|
1221
1466
|
}
|
|
1222
1467
|
return true;
|
|
1223
1468
|
}
|
|
1224
|
-
export function findNextSiblingDomAnchor(curr
|
|
1469
|
+
export function findNextSiblingDomAnchor(curr) {
|
|
1470
|
+
let vParent = curr._parent;
|
|
1225
1471
|
if (!vParent || !Array.isArray(vParent._children))
|
|
1226
1472
|
return null;
|
|
1227
1473
|
let children = vParent._children;
|
|
1474
|
+
if (children.length === 0)
|
|
1475
|
+
return findNextSiblingDomAnchor(vParent);
|
|
1228
1476
|
let idx = children.indexOf(curr);
|
|
1229
1477
|
if (idx === -1)
|
|
1230
1478
|
return null;
|
|
@@ -1233,6 +1481,9 @@ export function findNextSiblingDomAnchor(curr, vParent) {
|
|
|
1233
1481
|
if (dom)
|
|
1234
1482
|
return dom;
|
|
1235
1483
|
}
|
|
1484
|
+
if (isFragmentNode(vParent)) {
|
|
1485
|
+
return findNextSiblingDomAnchor(vParent);
|
|
1486
|
+
}
|
|
1236
1487
|
return null;
|
|
1237
1488
|
}
|
|
1238
1489
|
function reclaimPersistedMixinNode(persistedNode, newNode, frame, scheduler, styles, vParent, rootTarget) {
|
|
@@ -1242,17 +1493,21 @@ function reclaimPersistedMixinNode(persistedNode, newNode, frame, scheduler, sty
|
|
|
1242
1493
|
newNode._parent = vParent;
|
|
1243
1494
|
newNode._controller = persistedNode._controller;
|
|
1244
1495
|
newNode._mixState = persistedNode._mixState;
|
|
1496
|
+
newNode._directEventState = persistedNode._directEventState;
|
|
1245
1497
|
newNode._controlledState = persistedNode._controlledState;
|
|
1246
1498
|
let prevProps = getHostProps(persistedNode);
|
|
1247
1499
|
let nextProps = resolveNodeMixProps(newNode, frame, scheduler, newNode._mixState);
|
|
1248
1500
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
1249
1501
|
dispatchMixinBeforeUpdate(newNode._mixState);
|
|
1250
1502
|
}
|
|
1251
|
-
|
|
1503
|
+
patchHostProps(prevProps, nextProps, persistedNode._dom);
|
|
1504
|
+
syncDirectEventListeners(newNode);
|
|
1252
1505
|
ensureControlledReflection(newNode, scheduler);
|
|
1253
1506
|
syncControlledReflection(newNode, nextProps);
|
|
1254
1507
|
diffChildren(persistedNode._children, newNode._children, persistedNode._dom, frame, scheduler, styles, newNode, rootTarget);
|
|
1255
|
-
|
|
1508
|
+
if (newNode._mixState) {
|
|
1509
|
+
bindNodeMixRuntime(newNode, frame, scheduler, styles, true);
|
|
1510
|
+
}
|
|
1256
1511
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
1257
1512
|
scheduler.enqueueCommitPhase([
|
|
1258
1513
|
() => dispatchMixinCommit(newNode._mixState),
|