@remix-run/ui 0.1.1 → 0.1.2
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 +24 -3
- package/dist/animation/animate-layout-mixin.js +66 -66
- package/dist/animation/animate-layout-mixin.js.map +1 -1
- package/dist/components/accordion/accordion.d.ts +3 -3
- 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.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 +82 -0
- package/dist/components/button/button.js +60 -2
- 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 +3 -3
- 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 +1 -6
- 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 +5 -14
- 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/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 +3 -3
- package/dist/components/select/select.js +17 -26
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/tabs/tabs.d.ts +3 -3
- package/dist/components/tabs/tabs.js +0 -2
- package/dist/components/tabs/tabs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/component.d.ts +8 -5
- package/dist/runtime/component.js +84 -80
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/attributes.d.ts +12 -0
- package/dist/runtime/core/attributes.js +85 -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 +169 -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 +4 -0
- 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.js +2 -28
- package/dist/runtime/jsx.js.map +1 -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/navigation.js +9 -1
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.js +433 -192
- 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/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/to-vnode.js +5 -9
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/vnode.d.ts +5 -4
- package/dist/runtime/vnode.js +2 -3
- package/dist/runtime/vnode.js.map +1 -1
- package/dist/server/stream.js +76 -106
- package/dist/server/stream.js.map +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 +3 -1
- package/dist/style/stylesheet.js +69 -8
- package/dist/style/stylesheet.js.map +1 -1
- package/dist/theme/glyph-contract.d.ts +1 -1
- package/dist/theme/runtime.js +4 -1
- package/dist/theme/runtime.js.map +1 -1
- package/package.json +3 -3
- package/src/animation/README.md +314 -0
- package/src/animation/animate-layout-mixin.ts +79 -71
- package/src/components/accordion/README.md +166 -0
- package/src/components/accordion/accordion.tsx +8 -10
- 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/breadcrumbs/README.md +55 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +0 -2
- 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 +88 -2
- 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/combobox.tsx +8 -10
- package/src/components/combobox/demos/overview.demo.tsx +199 -0
- package/src/components/glyph/README.md +72 -0
- package/src/components/listbox/README.md +115 -0
- package/src/components/listbox/demos/overview.demo.tsx +101 -0
- package/src/components/listbox/listbox.ts +23 -32
- 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 +35 -41
- package/src/components/popover/README.md +3 -3
- package/src/components/popover/demos/overview.demo.tsx +143 -0
- 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 +28 -28
- package/src/components/tabs/tabs.tsx +10 -5
- package/src/index.ts +1 -1
- package/src/runtime/component.ts +94 -82
- package/src/runtime/core/attributes.ts +97 -0
- package/src/runtime/core/children.ts +42 -0
- package/src/runtime/core/props.ts +185 -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 +4 -0
- package/src/runtime/frame.ts +71 -55
- package/src/runtime/jsx.ts +2 -29
- package/src/runtime/mixins/mixin.ts +9 -4
- package/src/runtime/mixins/on-mixin.ts +20 -12
- package/src/runtime/navigation.ts +10 -1
- package/src/runtime/reconcile.ts +540 -209
- package/src/runtime/run.ts +17 -1
- package/src/runtime/stream-protocol.ts +27 -0
- package/src/runtime/to-vnode.ts +5 -8
- package/src/runtime/vnode.ts +6 -9
- package/src/server/README.md +88 -0
- package/src/server/stream.ts +99 -116
- package/src/style/layers.ts +2 -0
- package/src/style/stylesheet.ts +75 -10
- package/src/test/README.md +107 -0
- package/src/test/utils.ts +3 -1
- package/src/theme/README.md +103 -0
- package/src/theme/runtime.ts +4 -1
- package/src/utils/scroll-lock/README.md +33 -0
|
@@ -3,14 +3,12 @@ import { createFrame } from "./frame.js";
|
|
|
3
3
|
import { createRangeRoot } from "./vdom.js";
|
|
4
4
|
import { isCommittedComponentNode, isComponentNode, isCommittedHostNode, isCommittedTextNode, isFragmentNode, isHostNode, 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
|
},
|
|
@@ -319,16 +344,20 @@ function diffHost(curr, next, frame, scheduler, styles, vParent, rootTarget) {
|
|
|
319
344
|
curr._dom.innerHTML = '';
|
|
320
345
|
}
|
|
321
346
|
diffChildren(curr._children, next._children, curr._dom, frame, scheduler, styles, next, rootTarget);
|
|
322
|
-
|
|
347
|
+
patchHostProps(currProps, nextProps, curr._dom);
|
|
323
348
|
next._dom = curr._dom;
|
|
324
349
|
next._parent = vParent;
|
|
325
350
|
next._controller = curr._controller;
|
|
351
|
+
next._directEventState = curr._directEventState;
|
|
326
352
|
next._controlledState = curr._controlledState;
|
|
353
|
+
syncDirectEventListeners(next);
|
|
327
354
|
if (next._controlledState || shouldTrackControlledReflection(nextProps)) {
|
|
328
355
|
ensureControlledReflection(next, scheduler);
|
|
329
356
|
syncControlledReflection(next, nextProps);
|
|
330
357
|
}
|
|
331
|
-
|
|
358
|
+
if (next._mixState) {
|
|
359
|
+
bindNodeMixRuntime(next, frame, scheduler, styles);
|
|
360
|
+
}
|
|
332
361
|
if (shouldDispatchMixinLifecycle) {
|
|
333
362
|
scheduler.enqueueCommitPhase([() => dispatchMixinCommit(nextMixState)]);
|
|
334
363
|
}
|
|
@@ -338,11 +367,94 @@ function setupHostNode(node, dom, scheduler) {
|
|
|
338
367
|
node._dom = dom;
|
|
339
368
|
let props = getHostProps(node);
|
|
340
369
|
let committedNode = node;
|
|
370
|
+
syncDirectEventListeners(committedNode);
|
|
341
371
|
if (shouldTrackControlledReflection(props)) {
|
|
342
372
|
ensureControlledReflection(committedNode, scheduler);
|
|
343
373
|
syncControlledReflection(committedNode, props);
|
|
344
374
|
}
|
|
345
375
|
}
|
|
376
|
+
function syncDirectEventListeners(node) {
|
|
377
|
+
let descriptors = node._directEventDescriptors;
|
|
378
|
+
if (!descriptors) {
|
|
379
|
+
teardownDirectEventListeners(node);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (descriptors.length === 0) {
|
|
383
|
+
teardownDirectEventListeners(node);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
let state = node._directEventState;
|
|
387
|
+
if (!state) {
|
|
388
|
+
state = { bindings: [] };
|
|
389
|
+
node._directEventState = state;
|
|
390
|
+
}
|
|
391
|
+
let bindings = state.bindings;
|
|
392
|
+
for (let index = 0; index < descriptors.length; index++) {
|
|
393
|
+
let descriptor = descriptors[index];
|
|
394
|
+
let [type, handler, captureBoolean = false] = descriptor.args;
|
|
395
|
+
let binding = bindings[index];
|
|
396
|
+
if (!binding) {
|
|
397
|
+
binding = createDirectEventBinding(type, handler, captureBoolean);
|
|
398
|
+
bindings[index] = binding;
|
|
399
|
+
attachDirectEventBinding(node._dom, binding);
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
if (binding.type !== type || binding.capture !== captureBoolean) {
|
|
403
|
+
removeDirectEventBinding(node._dom, binding);
|
|
404
|
+
binding.type = type;
|
|
405
|
+
binding.capture = captureBoolean;
|
|
406
|
+
attachDirectEventBinding(node._dom, binding);
|
|
407
|
+
}
|
|
408
|
+
binding.handler = handler;
|
|
409
|
+
}
|
|
410
|
+
for (let index = descriptors.length; index < bindings.length; index++) {
|
|
411
|
+
removeDirectEventBinding(node._dom, bindings[index]);
|
|
412
|
+
}
|
|
413
|
+
bindings.length = descriptors.length;
|
|
414
|
+
}
|
|
415
|
+
function createDirectEventBinding(type, handler, capture) {
|
|
416
|
+
let binding = {
|
|
417
|
+
type,
|
|
418
|
+
handler,
|
|
419
|
+
capture,
|
|
420
|
+
reentry: null,
|
|
421
|
+
stableHandler: null,
|
|
422
|
+
};
|
|
423
|
+
return binding;
|
|
424
|
+
}
|
|
425
|
+
function getStableDirectEventHandler(binding) {
|
|
426
|
+
if (binding.stableHandler)
|
|
427
|
+
return binding.stableHandler;
|
|
428
|
+
binding.stableHandler = (event) => {
|
|
429
|
+
invokeDirectEventBinding(binding, event);
|
|
430
|
+
};
|
|
431
|
+
return binding.stableHandler;
|
|
432
|
+
}
|
|
433
|
+
function attachDirectEventBinding(dom, binding) {
|
|
434
|
+
dom.addEventListener(binding.type, getStableDirectEventHandler(binding), binding.capture);
|
|
435
|
+
}
|
|
436
|
+
function removeDirectEventBinding(dom, binding) {
|
|
437
|
+
if (binding.stableHandler) {
|
|
438
|
+
dom.removeEventListener(binding.type, binding.stableHandler, binding.capture);
|
|
439
|
+
}
|
|
440
|
+
binding.reentry?.abort(new DOMException('', 'AbortError'));
|
|
441
|
+
binding.reentry = null;
|
|
442
|
+
}
|
|
443
|
+
function teardownDirectEventListeners(node) {
|
|
444
|
+
let state = node._directEventState;
|
|
445
|
+
if (!state)
|
|
446
|
+
return;
|
|
447
|
+
for (let binding of state.bindings) {
|
|
448
|
+
removeDirectEventBinding(node._dom, binding);
|
|
449
|
+
}
|
|
450
|
+
state.bindings.length = 0;
|
|
451
|
+
node._directEventState = undefined;
|
|
452
|
+
}
|
|
453
|
+
function invokeDirectEventBinding(binding, event) {
|
|
454
|
+
binding.reentry?.abort(new DOMException('', 'EventReentry'));
|
|
455
|
+
binding.reentry = new AbortController();
|
|
456
|
+
void binding.handler(event, binding.reentry.signal);
|
|
457
|
+
}
|
|
346
458
|
function diffText(curr, next, vParent) {
|
|
347
459
|
if (curr._text !== next._text) {
|
|
348
460
|
curr._dom.textContent = next._text;
|
|
@@ -414,9 +526,11 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
414
526
|
}
|
|
415
527
|
// Render explicit <head> children directly into document.head.
|
|
416
528
|
diffChildren(null, node._children, targetHead, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
417
|
-
|
|
529
|
+
patchHostProps({}, hostProps, targetHead);
|
|
418
530
|
setupHostNode(node, targetHead, scheduler);
|
|
419
|
-
|
|
531
|
+
if (node._mixState) {
|
|
532
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
533
|
+
}
|
|
420
534
|
return cursor;
|
|
421
535
|
}
|
|
422
536
|
}
|
|
@@ -432,7 +546,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
432
546
|
let cursorTag = node._svg ? cursor.tagName : cursor.tagName.toLowerCase();
|
|
433
547
|
if (cursorTag === node.type) {
|
|
434
548
|
let nextCursor = cursor.nextSibling;
|
|
435
|
-
|
|
549
|
+
patchHostProps({}, hostProps, cursor);
|
|
436
550
|
// Handle innerHTML prop
|
|
437
551
|
if (hostProps.innerHTML != null) {
|
|
438
552
|
cursor.innerHTML = hostProps.innerHTML;
|
|
@@ -443,7 +557,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
443
557
|
diffChildren(null, node._children, cursor, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
444
558
|
}
|
|
445
559
|
setupHostNode(node, cursor, scheduler);
|
|
446
|
-
|
|
560
|
+
if (node._mixState) {
|
|
561
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
562
|
+
}
|
|
447
563
|
return nextCursor;
|
|
448
564
|
}
|
|
449
565
|
else {
|
|
@@ -455,7 +571,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
455
571
|
if (nextTag === node.type) {
|
|
456
572
|
let nextCursor = nextSibling.nextSibling;
|
|
457
573
|
// Found a match after skipping - adopt it and leave skipped node in place
|
|
458
|
-
|
|
574
|
+
patchHostProps({}, hostProps, nextSibling);
|
|
459
575
|
if (hostProps.innerHTML != null) {
|
|
460
576
|
nextSibling.innerHTML = hostProps.innerHTML;
|
|
461
577
|
}
|
|
@@ -464,7 +580,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
464
580
|
diffChildren(null, node._children, nextSibling, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
465
581
|
}
|
|
466
582
|
setupHostNode(node, nextSibling, scheduler);
|
|
467
|
-
|
|
583
|
+
if (node._mixState) {
|
|
584
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
585
|
+
}
|
|
468
586
|
return nextCursor;
|
|
469
587
|
}
|
|
470
588
|
}
|
|
@@ -476,7 +594,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
476
594
|
let dom = node._svg
|
|
477
595
|
? document.createElementNS(SVG_NS, node.type)
|
|
478
596
|
: document.createElement(node.type);
|
|
479
|
-
|
|
597
|
+
patchHostProps({}, hostProps, dom);
|
|
480
598
|
// Handle innerHTML prop
|
|
481
599
|
if (hostProps.innerHTML != null) {
|
|
482
600
|
dom.innerHTML = hostProps.innerHTML;
|
|
@@ -485,7 +603,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
485
603
|
diffChildren(null, node._children, dom, frame, scheduler, styles, node, rootTarget);
|
|
486
604
|
}
|
|
487
605
|
setupHostNode(node, dom, scheduler);
|
|
488
|
-
|
|
606
|
+
if (node._mixState) {
|
|
607
|
+
bindNodeMixRuntime(node, frame, scheduler, styles, false, domParent);
|
|
608
|
+
}
|
|
489
609
|
doInsert(dom);
|
|
490
610
|
return cursor;
|
|
491
611
|
}
|
|
@@ -835,6 +955,7 @@ function cleanupDescendants(node, scheduler, styles) {
|
|
|
835
955
|
cleanupDescendants(child, scheduler, styles);
|
|
836
956
|
}
|
|
837
957
|
teardownMixins(node._mixState);
|
|
958
|
+
teardownDirectEventListeners(node);
|
|
838
959
|
teardownControlledReflection(node);
|
|
839
960
|
if (node._controller)
|
|
840
961
|
node._controller.abort();
|
|
@@ -916,6 +1037,7 @@ function performHostNodeRemoval(node, domParent, scheduler, styles) {
|
|
|
916
1037
|
}
|
|
917
1038
|
}
|
|
918
1039
|
teardownMixins(node._mixState);
|
|
1040
|
+
teardownDirectEventListeners(node);
|
|
919
1041
|
teardownControlledReflection(node);
|
|
920
1042
|
// Never remove the real document.head node when reconciling a <head> vnode.
|
|
921
1043
|
if (!isHeadHostNode(node)) {
|
|
@@ -925,55 +1047,35 @@ function performHostNodeRemoval(node, domParent, scheduler, styles) {
|
|
|
925
1047
|
node._controller.abort();
|
|
926
1048
|
}
|
|
927
1049
|
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.
|
|
1050
|
+
let hasKeys = hasKeyedChildren(next);
|
|
959
1051
|
if (curr === null) {
|
|
1052
|
+
if (hasKeys) {
|
|
1053
|
+
warnDuplicateKeys(next);
|
|
1054
|
+
}
|
|
960
1055
|
for (let node of next) {
|
|
961
1056
|
cursor = insert(node, domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
962
1057
|
}
|
|
963
1058
|
vParent._children = next;
|
|
964
1059
|
return cursor;
|
|
965
1060
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1061
|
+
if (next.length === 0 &&
|
|
1062
|
+
anchor === undefined &&
|
|
1063
|
+
!parentUsesInnerHTML(vParent) &&
|
|
1064
|
+
canBulkClearChildren(curr)) {
|
|
1065
|
+
for (let node of curr) {
|
|
1066
|
+
cleanupDescendants(node, scheduler, styles);
|
|
1067
|
+
}
|
|
1068
|
+
domParent.textContent = '';
|
|
1069
|
+
vParent._children = next;
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
970
1072
|
if (!hasKeys) {
|
|
971
|
-
for (let i = 0; i <
|
|
972
|
-
let currentNode = i <
|
|
1073
|
+
for (let i = 0; i < next.length; i++) {
|
|
1074
|
+
let currentNode = i < curr.length ? curr[i] : null;
|
|
973
1075
|
diffVNodes(currentNode, next[i], domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
974
1076
|
}
|
|
975
|
-
if (
|
|
976
|
-
for (let i =
|
|
1077
|
+
if (curr.length > next.length) {
|
|
1078
|
+
for (let i = next.length; i < curr.length; i++) {
|
|
977
1079
|
let node = curr[i];
|
|
978
1080
|
if (node)
|
|
979
1081
|
remove(node, domParent, scheduler, styles);
|
|
@@ -982,167 +1084,302 @@ function diffChildren(curr, next, domParent, frame, scheduler, styles, vParent,
|
|
|
982
1084
|
vParent._children = next;
|
|
983
1085
|
return;
|
|
984
1086
|
}
|
|
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
|
-
}
|
|
1087
|
+
patchKeyedChildren(curr, next, domParent, frame, scheduler, styles, vParent, rootTarget, cursor, anchor);
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
function parentUsesInnerHTML(parent) {
|
|
1091
|
+
return isHostNode(parent) && getHostProps(parent).innerHTML != null;
|
|
1092
|
+
}
|
|
1093
|
+
function canBulkClearChildren(children) {
|
|
1094
|
+
for (let child of children) {
|
|
1095
|
+
if (!canBulkClearNode(child))
|
|
1096
|
+
return false;
|
|
1002
1097
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
oldKeyMap.set(c.key, i);
|
|
1015
|
-
}
|
|
1098
|
+
return true;
|
|
1099
|
+
}
|
|
1100
|
+
function canBulkClearNode(node) {
|
|
1101
|
+
if (isCommittedTextNode(node))
|
|
1102
|
+
return true;
|
|
1103
|
+
if (isCommittedHostNode(node)) {
|
|
1104
|
+
if (node._mixState)
|
|
1105
|
+
return false;
|
|
1106
|
+
for (let child of node._children) {
|
|
1107
|
+
if (!canBulkClearNode(child))
|
|
1108
|
+
return false;
|
|
1016
1109
|
}
|
|
1110
|
+
return true;
|
|
1111
|
+
}
|
|
1112
|
+
if (isFragmentNode(node)) {
|
|
1113
|
+
return canBulkClearChildren(node._children);
|
|
1017
1114
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1115
|
+
if (isCommittedComponentNode(node)) {
|
|
1116
|
+
return canBulkClearNode(node._content);
|
|
1117
|
+
}
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
function hasKeyedChildren(children) {
|
|
1121
|
+
for (let node of children) {
|
|
1122
|
+
if (node.key != null)
|
|
1123
|
+
return true;
|
|
1124
|
+
}
|
|
1125
|
+
return false;
|
|
1126
|
+
}
|
|
1127
|
+
function warnDuplicateKeys(children) {
|
|
1128
|
+
let seenKeys;
|
|
1129
|
+
let duplicateKeys;
|
|
1130
|
+
for (let node of children) {
|
|
1131
|
+
if (node.key == null)
|
|
1132
|
+
continue;
|
|
1133
|
+
if (!seenKeys) {
|
|
1134
|
+
seenKeys = new Set([node.key]);
|
|
1025
1135
|
continue;
|
|
1026
1136
|
}
|
|
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
|
-
}
|
|
1137
|
+
if (seenKeys.has(node.key)) {
|
|
1138
|
+
duplicateKeys ??= new Set();
|
|
1139
|
+
duplicateKeys.add(node.key);
|
|
1043
1140
|
}
|
|
1044
1141
|
else {
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1142
|
+
seenKeys.add(node.key);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
if (duplicateKeys?.size) {
|
|
1146
|
+
let quotedKeys = Array.from(duplicateKeys, (key) => `"${key}"`);
|
|
1147
|
+
console.warn(`Duplicate keys detected in siblings: ${quotedKeys.join(', ')}. Keys should be unique.`);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
function patchKeyedChildren(curr, next, domParent, frame, scheduler, styles, vParent, rootTarget, cursor, anchor) {
|
|
1151
|
+
let matches = matchKeyedChildrenInOrder(curr, next) ??
|
|
1152
|
+
matchKeyedChildrenAfterSingleRemoval(curr, next) ??
|
|
1153
|
+
matchKeyedChildrenAfterPairSwap(curr, next);
|
|
1154
|
+
if (!matches) {
|
|
1155
|
+
warnDuplicateKeys(next);
|
|
1156
|
+
matches = matchKeyedChildren(curr, next);
|
|
1157
|
+
}
|
|
1158
|
+
let matchAnalysis = analyzeKeyedChildMatches(curr.length, matches);
|
|
1159
|
+
if (matchAnalysis.hasRemovals) {
|
|
1160
|
+
let usedOldIndexes = new Uint8Array(curr.length);
|
|
1161
|
+
for (let match of matches) {
|
|
1162
|
+
if (match.oldIndex >= 0) {
|
|
1163
|
+
usedOldIndexes[match.oldIndex] = 1;
|
|
1051
1164
|
}
|
|
1052
1165
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
matchedOldVNode = oldChildren[matchingIndex];
|
|
1057
|
-
remainingOldChildren--;
|
|
1058
|
-
if (matchedOldVNode) {
|
|
1059
|
-
matchedOldVNode._flags = (matchedOldVNode._flags ?? 0) | MATCHED;
|
|
1166
|
+
for (let oldIndex = 0; oldIndex < curr.length; oldIndex++) {
|
|
1167
|
+
if (usedOldIndexes[oldIndex] === 0) {
|
|
1168
|
+
remove(curr[oldIndex], domParent, scheduler, styles);
|
|
1060
1169
|
}
|
|
1061
1170
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1171
|
+
}
|
|
1172
|
+
vParent._children = next;
|
|
1173
|
+
for (let index = 0; index < next.length; index++) {
|
|
1174
|
+
let match = matches[index];
|
|
1175
|
+
let oldNode = match.oldIndex >= 0 ? curr[match.oldIndex] : null;
|
|
1176
|
+
diffVNodes(oldNode, next[index], domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
1177
|
+
}
|
|
1178
|
+
if (matchAnalysis.canSkipPlacement) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
let stableIndexes = lisMatches(matches);
|
|
1182
|
+
let stableCursor = stableIndexes.length - 1;
|
|
1183
|
+
let placementAnchor = anchor ?? null;
|
|
1184
|
+
for (let index = next.length - 1; index >= 0; index--) {
|
|
1185
|
+
let nextNode = next[index];
|
|
1186
|
+
let isStable = stableIndexes[stableCursor] === index;
|
|
1187
|
+
if (isStable) {
|
|
1188
|
+
stableCursor--;
|
|
1189
|
+
}
|
|
1190
|
+
else {
|
|
1191
|
+
placeVNode(nextNode, domParent, placementAnchor);
|
|
1192
|
+
}
|
|
1193
|
+
placementAnchor = findFirstDomAnchor(nextNode) ?? placementAnchor;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
function matchKeyedChildren(curr, next) {
|
|
1197
|
+
let oldKeyMap = new Map();
|
|
1198
|
+
let usedOldIndexes = new Set();
|
|
1199
|
+
let unkeyedSearchStart = 0;
|
|
1200
|
+
for (let index = 0; index < curr.length; index++) {
|
|
1201
|
+
let key = curr[index].key;
|
|
1202
|
+
if (key != null)
|
|
1203
|
+
oldKeyMap.set(key, index);
|
|
1204
|
+
}
|
|
1205
|
+
return next.map((nextNode) => {
|
|
1206
|
+
let oldIndex = -1;
|
|
1207
|
+
if (nextNode.key != null) {
|
|
1208
|
+
let keyedOldIndex = oldKeyMap.get(nextNode.key);
|
|
1209
|
+
if (keyedOldIndex !== undefined) {
|
|
1210
|
+
let oldNode = curr[keyedOldIndex];
|
|
1211
|
+
if (!usedOldIndexes.has(keyedOldIndex) && oldNode.type === nextNode.type) {
|
|
1212
|
+
oldIndex = keyedOldIndex;
|
|
1073
1213
|
}
|
|
1074
1214
|
}
|
|
1075
|
-
childVNode._flags = (childVNode._flags ?? 0) | INSERT_VNODE;
|
|
1076
1215
|
}
|
|
1077
|
-
else
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
skew--;
|
|
1087
|
-
else
|
|
1088
|
-
skew++;
|
|
1089
|
-
childVNode._flags = (childVNode._flags ?? 0) | INSERT_VNODE;
|
|
1216
|
+
else {
|
|
1217
|
+
for (let index = unkeyedSearchStart; index < curr.length; index++) {
|
|
1218
|
+
let oldNode = curr[index];
|
|
1219
|
+
if (usedOldIndexes.has(index) || oldNode.key != null || oldNode.type !== nextNode.type) {
|
|
1220
|
+
continue;
|
|
1221
|
+
}
|
|
1222
|
+
oldIndex = index;
|
|
1223
|
+
unkeyedSearchStart = index + 1;
|
|
1224
|
+
break;
|
|
1090
1225
|
}
|
|
1091
1226
|
}
|
|
1227
|
+
if (oldIndex >= 0)
|
|
1228
|
+
usedOldIndexes.add(oldIndex);
|
|
1229
|
+
return { oldIndex };
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
function matchKeyedChildrenInOrder(curr, next) {
|
|
1233
|
+
let length = Math.min(curr.length, next.length);
|
|
1234
|
+
let matches = [];
|
|
1235
|
+
for (let index = 0; index < length; index++) {
|
|
1236
|
+
let nextNode = next[index];
|
|
1237
|
+
if (nextNode.key == null)
|
|
1238
|
+
return null;
|
|
1239
|
+
let oldNode = curr[index];
|
|
1240
|
+
if (oldNode.key !== nextNode.key || oldNode.type !== nextNode.type) {
|
|
1241
|
+
return null;
|
|
1242
|
+
}
|
|
1243
|
+
matches.push({ oldIndex: index });
|
|
1092
1244
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1245
|
+
for (let index = length; index < next.length; index++) {
|
|
1246
|
+
if (next[index].key == null)
|
|
1247
|
+
return null;
|
|
1248
|
+
matches.push({ oldIndex: -1 });
|
|
1249
|
+
}
|
|
1250
|
+
return matches;
|
|
1251
|
+
}
|
|
1252
|
+
function matchKeyedChildrenAfterSingleRemoval(curr, next) {
|
|
1253
|
+
if (curr.length !== next.length + 1)
|
|
1254
|
+
return null;
|
|
1255
|
+
let matches = [];
|
|
1256
|
+
let oldIndex = 0;
|
|
1257
|
+
let skippedOldNode = false;
|
|
1258
|
+
for (let nextIndex = 0; nextIndex < next.length; nextIndex++) {
|
|
1259
|
+
let nextNode = next[nextIndex];
|
|
1260
|
+
if (nextNode.key == null)
|
|
1261
|
+
return null;
|
|
1262
|
+
let oldNode = curr[oldIndex];
|
|
1263
|
+
if (oldNode.key === nextNode.key && oldNode.type === nextNode.type) {
|
|
1264
|
+
matches.push({ oldIndex });
|
|
1265
|
+
oldIndex++;
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
if (skippedOldNode)
|
|
1269
|
+
return null;
|
|
1270
|
+
skippedOldNode = true;
|
|
1271
|
+
oldIndex++;
|
|
1272
|
+
oldNode = curr[oldIndex];
|
|
1273
|
+
if (oldNode.key !== nextNode.key || oldNode.type !== nextNode.type) {
|
|
1274
|
+
return null;
|
|
1100
1275
|
}
|
|
1276
|
+
matches.push({ oldIndex });
|
|
1277
|
+
oldIndex++;
|
|
1101
1278
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1279
|
+
return matches;
|
|
1280
|
+
}
|
|
1281
|
+
function matchKeyedChildrenAfterPairSwap(curr, next) {
|
|
1282
|
+
if (curr.length !== next.length)
|
|
1283
|
+
return null;
|
|
1284
|
+
let matches = [];
|
|
1285
|
+
let firstMismatch = -1;
|
|
1286
|
+
let secondMismatch = -1;
|
|
1287
|
+
for (let index = 0; index < next.length; index++) {
|
|
1288
|
+
let nextNode = next[index];
|
|
1289
|
+
if (nextNode.key == null)
|
|
1290
|
+
return null;
|
|
1291
|
+
let oldNode = curr[index];
|
|
1292
|
+
if (oldNode.key === nextNode.key && oldNode.type === nextNode.type) {
|
|
1293
|
+
matches.push({ oldIndex: index });
|
|
1109
1294
|
continue;
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1295
|
+
}
|
|
1296
|
+
if (firstMismatch === -1) {
|
|
1297
|
+
firstMismatch = index;
|
|
1298
|
+
}
|
|
1299
|
+
else if (secondMismatch === -1) {
|
|
1300
|
+
secondMismatch = index;
|
|
1301
|
+
}
|
|
1302
|
+
else {
|
|
1303
|
+
return null;
|
|
1304
|
+
}
|
|
1305
|
+
matches.push({ oldIndex: -1 });
|
|
1306
|
+
}
|
|
1307
|
+
if (firstMismatch === -1)
|
|
1308
|
+
return matches;
|
|
1309
|
+
if (secondMismatch === -1)
|
|
1310
|
+
return null;
|
|
1311
|
+
let firstOldNode = curr[firstMismatch];
|
|
1312
|
+
let secondOldNode = curr[secondMismatch];
|
|
1313
|
+
let firstNextNode = next[firstMismatch];
|
|
1314
|
+
let secondNextNode = next[secondMismatch];
|
|
1315
|
+
if (firstOldNode.key !== secondNextNode.key ||
|
|
1316
|
+
firstOldNode.type !== secondNextNode.type ||
|
|
1317
|
+
secondOldNode.key !== firstNextNode.key ||
|
|
1318
|
+
secondOldNode.type !== firstNextNode.type) {
|
|
1319
|
+
return null;
|
|
1320
|
+
}
|
|
1321
|
+
matches[firstMismatch] = { oldIndex: secondMismatch };
|
|
1322
|
+
matches[secondMismatch] = { oldIndex: firstMismatch };
|
|
1323
|
+
return matches;
|
|
1324
|
+
}
|
|
1325
|
+
function analyzeKeyedChildMatches(currentLength, matches) {
|
|
1326
|
+
let hasRemovals = matches.length !== currentLength;
|
|
1327
|
+
let canSkipPlacement = true;
|
|
1328
|
+
let lastOldIndex = -1;
|
|
1329
|
+
let sawNewNode = false;
|
|
1330
|
+
for (let match of matches) {
|
|
1331
|
+
if (match.oldIndex < 0) {
|
|
1332
|
+
hasRemovals = true;
|
|
1333
|
+
sawNewNode = true;
|
|
1334
|
+
continue;
|
|
1335
|
+
}
|
|
1336
|
+
if (sawNewNode || match.oldIndex < lastOldIndex) {
|
|
1337
|
+
canSkipPlacement = false;
|
|
1338
|
+
}
|
|
1339
|
+
lastOldIndex = match.oldIndex;
|
|
1340
|
+
}
|
|
1341
|
+
return { hasRemovals, canSkipPlacement };
|
|
1342
|
+
}
|
|
1343
|
+
function lisMatches(matches) {
|
|
1344
|
+
let predecessors = Array.from({ length: matches.length });
|
|
1345
|
+
let tails = [];
|
|
1346
|
+
for (let index = 0; index < matches.length; index++) {
|
|
1347
|
+
let value = matches[index].oldIndex + 1;
|
|
1348
|
+
if (value === 0)
|
|
1349
|
+
continue;
|
|
1350
|
+
let low = 0;
|
|
1351
|
+
let high = tails.length;
|
|
1352
|
+
while (low < high) {
|
|
1353
|
+
let middle = (low + high) >> 1;
|
|
1354
|
+
if (matches[tails[middle]].oldIndex + 1 < value) {
|
|
1355
|
+
low = middle + 1;
|
|
1125
1356
|
}
|
|
1126
1357
|
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);
|
|
1358
|
+
high = middle;
|
|
1137
1359
|
}
|
|
1138
1360
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
// Clear internal flags for next diff
|
|
1142
|
-
childVNode._flags = 0;
|
|
1143
|
-
childVNode._index = undefined;
|
|
1361
|
+
predecessors[index] = low > 0 ? tails[low - 1] : -1;
|
|
1362
|
+
tails[low] = index;
|
|
1144
1363
|
}
|
|
1145
|
-
|
|
1364
|
+
let cursor = tails.at(-1) ?? -1;
|
|
1365
|
+
for (let index = tails.length - 1; index >= 0; index--) {
|
|
1366
|
+
tails[index] = cursor;
|
|
1367
|
+
cursor = predecessors[cursor] ?? -1;
|
|
1368
|
+
}
|
|
1369
|
+
return tails;
|
|
1370
|
+
}
|
|
1371
|
+
function placeVNode(node, domParent, anchor) {
|
|
1372
|
+
let firstDom = findFirstDomAnchor(node);
|
|
1373
|
+
if (!firstDom || firstDom.parentNode !== domParent)
|
|
1374
|
+
return;
|
|
1375
|
+
let lastDom = findLastDomAnchor(node);
|
|
1376
|
+
if (!lastDom)
|
|
1377
|
+
return;
|
|
1378
|
+
if (anchor && domRangeContainsNode(firstDom, lastDom, anchor))
|
|
1379
|
+
return;
|
|
1380
|
+
if (firstDom === anchor)
|
|
1381
|
+
return;
|
|
1382
|
+
moveDomRange(domParent, firstDom, lastDom, anchor);
|
|
1146
1383
|
}
|
|
1147
1384
|
export function findFirstDomAnchor(node) {
|
|
1148
1385
|
if (!node)
|
|
@@ -1242,17 +1479,21 @@ function reclaimPersistedMixinNode(persistedNode, newNode, frame, scheduler, sty
|
|
|
1242
1479
|
newNode._parent = vParent;
|
|
1243
1480
|
newNode._controller = persistedNode._controller;
|
|
1244
1481
|
newNode._mixState = persistedNode._mixState;
|
|
1482
|
+
newNode._directEventState = persistedNode._directEventState;
|
|
1245
1483
|
newNode._controlledState = persistedNode._controlledState;
|
|
1246
1484
|
let prevProps = getHostProps(persistedNode);
|
|
1247
1485
|
let nextProps = resolveNodeMixProps(newNode, frame, scheduler, newNode._mixState);
|
|
1248
1486
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
1249
1487
|
dispatchMixinBeforeUpdate(newNode._mixState);
|
|
1250
1488
|
}
|
|
1251
|
-
|
|
1489
|
+
patchHostProps(prevProps, nextProps, persistedNode._dom);
|
|
1490
|
+
syncDirectEventListeners(newNode);
|
|
1252
1491
|
ensureControlledReflection(newNode, scheduler);
|
|
1253
1492
|
syncControlledReflection(newNode, nextProps);
|
|
1254
1493
|
diffChildren(persistedNode._children, newNode._children, persistedNode._dom, frame, scheduler, styles, newNode, rootTarget);
|
|
1255
|
-
|
|
1494
|
+
if (newNode._mixState) {
|
|
1495
|
+
bindNodeMixRuntime(newNode, frame, scheduler, styles, true);
|
|
1496
|
+
}
|
|
1256
1497
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
1257
1498
|
scheduler.enqueueCommitPhase([
|
|
1258
1499
|
() => dispatchMixinCommit(newNode._mixState),
|