@remix-run/ui 0.1.0 → 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 +51 -52
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/jsx.js +2 -27
- 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.d.ts +6 -0
- package/dist/runtime/navigation.js +16 -3
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.js +444 -181
- 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.js +10 -0
- 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/to-vnode.js +17 -18
- 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 +80 -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 +6 -7
- 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 +84 -61
- package/src/runtime/jsx.ts +2 -30
- package/src/runtime/mixins/mixin.ts +9 -4
- package/src/runtime/mixins/on-mixin.ts +20 -12
- package/src/runtime/navigation.ts +24 -3
- package/src/runtime/reconcile.ts +552 -186
- package/src/runtime/run.ts +17 -1
- package/src/runtime/scheduler.ts +7 -0
- package/src/runtime/stream-protocol.ts +27 -0
- package/src/runtime/to-vnode.ts +15 -17
- package/src/runtime/vnode.ts +6 -9
- package/src/server/README.md +88 -0
- package/src/server/stream.ts +105 -117
- 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
- package/src/test/setup.ts +0 -7
|
@@ -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
|
},
|
|
@@ -232,6 +257,10 @@ function bindNodeMixRuntime(node, frame, scheduler, styles, reclaimed = false, p
|
|
|
232
257
|
}, { dispatchReclaimed: reclaimed });
|
|
233
258
|
}
|
|
234
259
|
function isHeadHostNode(node) {
|
|
260
|
+
if (node.type === 'head')
|
|
261
|
+
return true;
|
|
262
|
+
if (node.type.length !== 4)
|
|
263
|
+
return false;
|
|
235
264
|
return node.type.toLowerCase() === 'head';
|
|
236
265
|
}
|
|
237
266
|
function getDocumentHead(domParent) {
|
|
@@ -298,8 +327,10 @@ function diffHost(curr, next, frame, scheduler, styles, vParent, rootTarget) {
|
|
|
298
327
|
let mixState = curr._mixState;
|
|
299
328
|
let currProps = getHostProps(curr);
|
|
300
329
|
let nextProps = resolveNodeMixProps(next, frame, scheduler, mixState);
|
|
301
|
-
|
|
302
|
-
|
|
330
|
+
let nextMixState = next._mixState;
|
|
331
|
+
let shouldDispatchMixinLifecycle = (nextMixState?.runners.length ?? 0) > 0 && shouldDispatchInlineMixinLifecycle(curr._dom);
|
|
332
|
+
if (shouldDispatchMixinLifecycle) {
|
|
333
|
+
dispatchMixinBeforeUpdate(nextMixState);
|
|
303
334
|
}
|
|
304
335
|
// Handle innerHTML prop BEFORE diffChildren to avoid clearing children
|
|
305
336
|
if (nextProps.innerHTML != null) {
|
|
@@ -313,20 +344,22 @@ function diffHost(curr, next, frame, scheduler, styles, vParent, rootTarget) {
|
|
|
313
344
|
curr._dom.innerHTML = '';
|
|
314
345
|
}
|
|
315
346
|
diffChildren(curr._children, next._children, curr._dom, frame, scheduler, styles, next, rootTarget);
|
|
316
|
-
|
|
347
|
+
patchHostProps(currProps, nextProps, curr._dom);
|
|
317
348
|
next._dom = curr._dom;
|
|
318
349
|
next._parent = vParent;
|
|
319
350
|
next._controller = curr._controller;
|
|
351
|
+
next._directEventState = curr._directEventState;
|
|
320
352
|
next._controlledState = curr._controlledState;
|
|
353
|
+
syncDirectEventListeners(next);
|
|
321
354
|
if (next._controlledState || shouldTrackControlledReflection(nextProps)) {
|
|
322
355
|
ensureControlledReflection(next, scheduler);
|
|
323
356
|
syncControlledReflection(next, nextProps);
|
|
324
357
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
]);
|
|
358
|
+
if (next._mixState) {
|
|
359
|
+
bindNodeMixRuntime(next, frame, scheduler, styles);
|
|
360
|
+
}
|
|
361
|
+
if (shouldDispatchMixinLifecycle) {
|
|
362
|
+
scheduler.enqueueCommitPhase([() => dispatchMixinCommit(nextMixState)]);
|
|
330
363
|
}
|
|
331
364
|
return;
|
|
332
365
|
}
|
|
@@ -334,11 +367,94 @@ function setupHostNode(node, dom, scheduler) {
|
|
|
334
367
|
node._dom = dom;
|
|
335
368
|
let props = getHostProps(node);
|
|
336
369
|
let committedNode = node;
|
|
370
|
+
syncDirectEventListeners(committedNode);
|
|
337
371
|
if (shouldTrackControlledReflection(props)) {
|
|
338
372
|
ensureControlledReflection(committedNode, scheduler);
|
|
339
373
|
syncControlledReflection(committedNode, props);
|
|
340
374
|
}
|
|
341
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
|
+
}
|
|
342
458
|
function diffText(curr, next, vParent) {
|
|
343
459
|
if (curr._text !== next._text) {
|
|
344
460
|
curr._dom.textContent = next._text;
|
|
@@ -410,9 +526,11 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
410
526
|
}
|
|
411
527
|
// Render explicit <head> children directly into document.head.
|
|
412
528
|
diffChildren(null, node._children, targetHead, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
413
|
-
|
|
529
|
+
patchHostProps({}, hostProps, targetHead);
|
|
414
530
|
setupHostNode(node, targetHead, scheduler);
|
|
415
|
-
|
|
531
|
+
if (node._mixState) {
|
|
532
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
533
|
+
}
|
|
416
534
|
return cursor;
|
|
417
535
|
}
|
|
418
536
|
}
|
|
@@ -428,7 +546,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
428
546
|
let cursorTag = node._svg ? cursor.tagName : cursor.tagName.toLowerCase();
|
|
429
547
|
if (cursorTag === node.type) {
|
|
430
548
|
let nextCursor = cursor.nextSibling;
|
|
431
|
-
|
|
549
|
+
patchHostProps({}, hostProps, cursor);
|
|
432
550
|
// Handle innerHTML prop
|
|
433
551
|
if (hostProps.innerHTML != null) {
|
|
434
552
|
cursor.innerHTML = hostProps.innerHTML;
|
|
@@ -439,7 +557,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
439
557
|
diffChildren(null, node._children, cursor, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
440
558
|
}
|
|
441
559
|
setupHostNode(node, cursor, scheduler);
|
|
442
|
-
|
|
560
|
+
if (node._mixState) {
|
|
561
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
562
|
+
}
|
|
443
563
|
return nextCursor;
|
|
444
564
|
}
|
|
445
565
|
else {
|
|
@@ -451,7 +571,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
451
571
|
if (nextTag === node.type) {
|
|
452
572
|
let nextCursor = nextSibling.nextSibling;
|
|
453
573
|
// Found a match after skipping - adopt it and leave skipped node in place
|
|
454
|
-
|
|
574
|
+
patchHostProps({}, hostProps, nextSibling);
|
|
455
575
|
if (hostProps.innerHTML != null) {
|
|
456
576
|
nextSibling.innerHTML = hostProps.innerHTML;
|
|
457
577
|
}
|
|
@@ -460,7 +580,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
460
580
|
diffChildren(null, node._children, nextSibling, frame, scheduler, styles, node, rootTarget, childCursor);
|
|
461
581
|
}
|
|
462
582
|
setupHostNode(node, nextSibling, scheduler);
|
|
463
|
-
|
|
583
|
+
if (node._mixState) {
|
|
584
|
+
bindNodeMixRuntime(node, frame, scheduler, styles);
|
|
585
|
+
}
|
|
464
586
|
return nextCursor;
|
|
465
587
|
}
|
|
466
588
|
}
|
|
@@ -472,7 +594,7 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
472
594
|
let dom = node._svg
|
|
473
595
|
? document.createElementNS(SVG_NS, node.type)
|
|
474
596
|
: document.createElement(node.type);
|
|
475
|
-
|
|
597
|
+
patchHostProps({}, hostProps, dom);
|
|
476
598
|
// Handle innerHTML prop
|
|
477
599
|
if (hostProps.innerHTML != null) {
|
|
478
600
|
dom.innerHTML = hostProps.innerHTML;
|
|
@@ -481,7 +603,9 @@ function insert(node, domParent, frame, scheduler, styles, vParent, rootTarget,
|
|
|
481
603
|
diffChildren(null, node._children, dom, frame, scheduler, styles, node, rootTarget);
|
|
482
604
|
}
|
|
483
605
|
setupHostNode(node, dom, scheduler);
|
|
484
|
-
|
|
606
|
+
if (node._mixState) {
|
|
607
|
+
bindNodeMixRuntime(node, frame, scheduler, styles, false, domParent);
|
|
608
|
+
}
|
|
485
609
|
doInsert(dom);
|
|
486
610
|
return cursor;
|
|
487
611
|
}
|
|
@@ -831,6 +955,7 @@ function cleanupDescendants(node, scheduler, styles) {
|
|
|
831
955
|
cleanupDescendants(child, scheduler, styles);
|
|
832
956
|
}
|
|
833
957
|
teardownMixins(node._mixState);
|
|
958
|
+
teardownDirectEventListeners(node);
|
|
834
959
|
teardownControlledReflection(node);
|
|
835
960
|
if (node._controller)
|
|
836
961
|
node._controller.abort();
|
|
@@ -912,6 +1037,7 @@ function performHostNodeRemoval(node, domParent, scheduler, styles) {
|
|
|
912
1037
|
}
|
|
913
1038
|
}
|
|
914
1039
|
teardownMixins(node._mixState);
|
|
1040
|
+
teardownDirectEventListeners(node);
|
|
915
1041
|
teardownControlledReflection(node);
|
|
916
1042
|
// Never remove the real document.head node when reconciling a <head> vnode.
|
|
917
1043
|
if (!isHeadHostNode(node)) {
|
|
@@ -921,55 +1047,35 @@ function performHostNodeRemoval(node, domParent, scheduler, styles) {
|
|
|
921
1047
|
node._controller.abort();
|
|
922
1048
|
}
|
|
923
1049
|
function diffChildren(curr, next, domParent, frame, scheduler, styles, vParent, rootTarget, cursor, anchor) {
|
|
924
|
-
let
|
|
925
|
-
// Warn when duplicate keys are present among siblings. Duplicate keys are
|
|
926
|
-
// still processed (last one wins), but they make keyed diffing ambiguous.
|
|
927
|
-
let hasKeys = false;
|
|
928
|
-
let seenKeys;
|
|
929
|
-
let duplicateKeys;
|
|
930
|
-
for (let i = 0; i < nextLength; i++) {
|
|
931
|
-
let node = next[i];
|
|
932
|
-
if (node && node.key != null) {
|
|
933
|
-
hasKeys = true;
|
|
934
|
-
if (!seenKeys) {
|
|
935
|
-
seenKeys = new Set([node.key]);
|
|
936
|
-
continue;
|
|
937
|
-
}
|
|
938
|
-
if (seenKeys.has(node.key)) {
|
|
939
|
-
if (!duplicateKeys) {
|
|
940
|
-
duplicateKeys = new Set();
|
|
941
|
-
}
|
|
942
|
-
duplicateKeys.add(node.key);
|
|
943
|
-
}
|
|
944
|
-
else {
|
|
945
|
-
seenKeys.add(node.key);
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
if (duplicateKeys?.size) {
|
|
950
|
-
let quotedKeys = Array.from(duplicateKeys, (key) => `"${key}"`);
|
|
951
|
-
console.warn(`Duplicate keys detected in siblings: ${quotedKeys.join(', ')}. Keys should be unique.`);
|
|
952
|
-
}
|
|
953
|
-
// Initial mount / hydration: delegate to insert() for each child so that
|
|
954
|
-
// hydration cursors and creation logic remain centralized there.
|
|
1050
|
+
let hasKeys = hasKeyedChildren(next);
|
|
955
1051
|
if (curr === null) {
|
|
1052
|
+
if (hasKeys) {
|
|
1053
|
+
warnDuplicateKeys(next);
|
|
1054
|
+
}
|
|
956
1055
|
for (let node of next) {
|
|
957
1056
|
cursor = insert(node, domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
958
1057
|
}
|
|
959
1058
|
vParent._children = next;
|
|
960
1059
|
return cursor;
|
|
961
1060
|
}
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
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
|
+
}
|
|
966
1072
|
if (!hasKeys) {
|
|
967
|
-
for (let i = 0; i <
|
|
968
|
-
let currentNode = i <
|
|
1073
|
+
for (let i = 0; i < next.length; i++) {
|
|
1074
|
+
let currentNode = i < curr.length ? curr[i] : null;
|
|
969
1075
|
diffVNodes(currentNode, next[i], domParent, frame, scheduler, styles, vParent, rootTarget, anchor, cursor);
|
|
970
1076
|
}
|
|
971
|
-
if (
|
|
972
|
-
for (let i =
|
|
1077
|
+
if (curr.length > next.length) {
|
|
1078
|
+
for (let i = next.length; i < curr.length; i++) {
|
|
973
1079
|
let node = curr[i];
|
|
974
1080
|
if (node)
|
|
975
1081
|
remove(node, domParent, scheduler, styles);
|
|
@@ -978,149 +1084,302 @@ function diffChildren(curr, next, domParent, frame, scheduler, styles, vParent,
|
|
|
978
1084
|
vParent._children = next;
|
|
979
1085
|
return;
|
|
980
1086
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
if (
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
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;
|
|
1097
|
+
}
|
|
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;
|
|
994
1109
|
}
|
|
1110
|
+
return true;
|
|
1111
|
+
}
|
|
1112
|
+
if (isFragmentNode(node)) {
|
|
1113
|
+
return canBulkClearChildren(node._children);
|
|
995
1114
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
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]);
|
|
1003
1135
|
continue;
|
|
1004
1136
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
let matchingIndex = -1;
|
|
1009
|
-
let key = childVNode.key;
|
|
1010
|
-
let type = childVNode.type;
|
|
1011
|
-
if (key != null) {
|
|
1012
|
-
// O(1) Map lookup for keyed children
|
|
1013
|
-
let mapIndex = oldKeyMap.get(key);
|
|
1014
|
-
if (mapIndex !== undefined) {
|
|
1015
|
-
let candidate = oldChildren[mapIndex];
|
|
1016
|
-
let candidateFlags = candidate?._flags ?? 0;
|
|
1017
|
-
if (candidate && (candidateFlags & MATCHED) === 0 && candidate.type === type) {
|
|
1018
|
-
matchingIndex = mapIndex;
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1137
|
+
if (seenKeys.has(node.key)) {
|
|
1138
|
+
duplicateKeys ??= new Set();
|
|
1139
|
+
duplicateKeys.add(node.key);
|
|
1021
1140
|
}
|
|
1022
1141
|
else {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
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;
|
|
1029
1164
|
}
|
|
1030
1165
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
matchedOldVNode = oldChildren[matchingIndex];
|
|
1035
|
-
remainingOldChildren--;
|
|
1036
|
-
if (matchedOldVNode) {
|
|
1037
|
-
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);
|
|
1038
1169
|
}
|
|
1039
1170
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
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;
|
|
1051
1213
|
}
|
|
1052
1214
|
}
|
|
1053
|
-
childVNode._flags = (childVNode._flags ?? 0) | INSERT_VNODE;
|
|
1054
1215
|
}
|
|
1055
|
-
else
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
skew--;
|
|
1065
|
-
else
|
|
1066
|
-
skew++;
|
|
1067
|
-
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;
|
|
1068
1225
|
}
|
|
1069
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 });
|
|
1070
1244
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
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;
|
|
1078
1275
|
}
|
|
1276
|
+
matches.push({ oldIndex });
|
|
1277
|
+
oldIndex++;
|
|
1079
1278
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
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 });
|
|
1087
1294
|
continue;
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
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;
|
|
1103
1356
|
}
|
|
1104
1357
|
else {
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
if (target === null && anchor)
|
|
1108
|
-
target = anchor;
|
|
1109
|
-
// If target lies within the range we're moving, skip the move.
|
|
1110
|
-
if (target && domRangeContainsNode(firstDom, lastDom, target)) {
|
|
1111
|
-
// no-op
|
|
1112
|
-
}
|
|
1113
|
-
else if (firstDom !== target) {
|
|
1114
|
-
moveDomRange(domParent, firstDom, lastDom, target);
|
|
1358
|
+
high = middle;
|
|
1115
1359
|
}
|
|
1116
1360
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
// Clear internal flags for next diff
|
|
1120
|
-
childVNode._flags = 0;
|
|
1121
|
-
childVNode._index = undefined;
|
|
1361
|
+
predecessors[index] = low > 0 ? tails[low - 1] : -1;
|
|
1362
|
+
tails[low] = index;
|
|
1122
1363
|
}
|
|
1123
|
-
|
|
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);
|
|
1124
1383
|
}
|
|
1125
1384
|
export function findFirstDomAnchor(node) {
|
|
1126
1385
|
if (!node)
|
|
@@ -1220,17 +1479,21 @@ function reclaimPersistedMixinNode(persistedNode, newNode, frame, scheduler, sty
|
|
|
1220
1479
|
newNode._parent = vParent;
|
|
1221
1480
|
newNode._controller = persistedNode._controller;
|
|
1222
1481
|
newNode._mixState = persistedNode._mixState;
|
|
1482
|
+
newNode._directEventState = persistedNode._directEventState;
|
|
1223
1483
|
newNode._controlledState = persistedNode._controlledState;
|
|
1224
1484
|
let prevProps = getHostProps(persistedNode);
|
|
1225
1485
|
let nextProps = resolveNodeMixProps(newNode, frame, scheduler, newNode._mixState);
|
|
1226
1486
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
1227
1487
|
dispatchMixinBeforeUpdate(newNode._mixState);
|
|
1228
1488
|
}
|
|
1229
|
-
|
|
1489
|
+
patchHostProps(prevProps, nextProps, persistedNode._dom);
|
|
1490
|
+
syncDirectEventListeners(newNode);
|
|
1230
1491
|
ensureControlledReflection(newNode, scheduler);
|
|
1231
1492
|
syncControlledReflection(newNode, nextProps);
|
|
1232
1493
|
diffChildren(persistedNode._children, newNode._children, persistedNode._dom, frame, scheduler, styles, newNode, rootTarget);
|
|
1233
|
-
|
|
1494
|
+
if (newNode._mixState) {
|
|
1495
|
+
bindNodeMixRuntime(newNode, frame, scheduler, styles, true);
|
|
1496
|
+
}
|
|
1234
1497
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
1235
1498
|
scheduler.enqueueCommitPhase([
|
|
1236
1499
|
() => dispatchMixinCommit(newNode._mixState),
|