@fictjs/runtime 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +243 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.dev.js +258 -43
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +243 -45
- package/dist/index.js.map +1 -1
- package/dist/slim.cjs +221 -35
- package/dist/slim.cjs.map +1 -1
- package/dist/slim.js +221 -35
- package/dist/slim.js.map +1 -1
- package/package.json +1 -1
- package/src/binding.ts +3 -1
- package/src/dev.d.ts +5 -0
- package/src/dom.ts +20 -2
- package/src/error-boundary.ts +11 -2
- package/src/lifecycle.ts +4 -1
- package/src/list-helpers.ts +243 -22
- package/src/props.ts +2 -4
- package/src/reconcile.ts +4 -0
- package/src/signal.ts +69 -24
- package/src/suspense.ts +24 -7
- package/src/transition.ts +4 -1
package/dist/index.d.cts
CHANGED
|
@@ -1431,6 +1431,10 @@ declare const UnitlessStyles: Set<string>;
|
|
|
1431
1431
|
* @param a - The old array of nodes (currently in DOM)
|
|
1432
1432
|
* @param b - The new array of nodes (target state)
|
|
1433
1433
|
*
|
|
1434
|
+
* **Note:** This function may mutate the input array `a` during the swap
|
|
1435
|
+
* optimization (step 5a). If you need to preserve the original array,
|
|
1436
|
+
* pass a shallow copy: `reconcileArrays(parent, [...oldNodes], newNodes)`.
|
|
1437
|
+
*
|
|
1434
1438
|
* @example
|
|
1435
1439
|
* ```ts
|
|
1436
1440
|
* const oldNodes = [node1, node2, node3]
|
package/dist/index.d.ts
CHANGED
|
@@ -1431,6 +1431,10 @@ declare const UnitlessStyles: Set<string>;
|
|
|
1431
1431
|
* @param a - The old array of nodes (currently in DOM)
|
|
1432
1432
|
* @param b - The new array of nodes (target state)
|
|
1433
1433
|
*
|
|
1434
|
+
* **Note:** This function may mutate the input array `a` during the swap
|
|
1435
|
+
* optimization (step 5a). If you need to preserve the original array,
|
|
1436
|
+
* pass a shallow copy: `reconcileArrays(parent, [...oldNodes], newNodes)`.
|
|
1437
|
+
*
|
|
1434
1438
|
* @example
|
|
1435
1439
|
* ```ts
|
|
1436
1440
|
* const oldNodes = [node1, node2, node3]
|
package/dist/index.dev.js
CHANGED
|
@@ -301,7 +301,7 @@ function handleError(err, info, startRoot) {
|
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
|
-
|
|
304
|
+
return false;
|
|
305
305
|
}
|
|
306
306
|
function handleSuspend(token, startRoot) {
|
|
307
307
|
let root = startRoot ?? currentRoot;
|
|
@@ -349,6 +349,10 @@ var enqueueMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : (
|
|
|
349
349
|
Promise.resolve().then(fn);
|
|
350
350
|
};
|
|
351
351
|
var inCleanup = false;
|
|
352
|
+
var SIGNAL_MARKER = Symbol.for("fict:signal");
|
|
353
|
+
var COMPUTED_MARKER = Symbol.for("fict:computed");
|
|
354
|
+
var EFFECT_MARKER = Symbol.for("fict:effect");
|
|
355
|
+
var EFFECT_SCOPE_MARKER = Symbol.for("fict:effectScope");
|
|
352
356
|
function link(dep, sub, version) {
|
|
353
357
|
const prevDep = sub.depsTail;
|
|
354
358
|
if (prevDep !== void 0 && prevDep.dep === dep) return;
|
|
@@ -472,13 +476,21 @@ function checkDirty(firstLink, sub) {
|
|
|
472
476
|
dirty = true;
|
|
473
477
|
}
|
|
474
478
|
} else if ((depFlags & MutablePending) === MutablePending) {
|
|
475
|
-
if (
|
|
476
|
-
|
|
479
|
+
if (!dep.deps) {
|
|
480
|
+
const nextDep = link2.nextDep;
|
|
481
|
+
if (nextDep !== void 0) {
|
|
482
|
+
link2 = nextDep;
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
if (link2.nextSub !== void 0 || link2.prevSub !== void 0) {
|
|
487
|
+
stack = { value: link2, prev: stack };
|
|
488
|
+
}
|
|
489
|
+
link2 = dep.deps;
|
|
490
|
+
sub = dep;
|
|
491
|
+
++checkDepth;
|
|
492
|
+
continue;
|
|
477
493
|
}
|
|
478
|
-
link2 = dep.deps;
|
|
479
|
-
sub = dep;
|
|
480
|
-
++checkDepth;
|
|
481
|
-
continue;
|
|
482
494
|
}
|
|
483
495
|
if (!dirty) {
|
|
484
496
|
const nextDep = link2.nextDep;
|
|
@@ -556,8 +568,12 @@ function disposeNode(node) {
|
|
|
556
568
|
node.depsTail = void 0;
|
|
557
569
|
node.flags = 0;
|
|
558
570
|
purgeDeps(node);
|
|
559
|
-
|
|
560
|
-
|
|
571
|
+
let sub = node.subs;
|
|
572
|
+
while (sub !== void 0) {
|
|
573
|
+
const next = sub.nextSub;
|
|
574
|
+
unlink(sub);
|
|
575
|
+
sub = next;
|
|
576
|
+
}
|
|
561
577
|
}
|
|
562
578
|
function updateSignal(s) {
|
|
563
579
|
s.flags = Mutable;
|
|
@@ -726,7 +742,9 @@ function signal(initialValue) {
|
|
|
726
742
|
__id: void 0
|
|
727
743
|
};
|
|
728
744
|
registerSignalDevtools(initialValue, s);
|
|
729
|
-
|
|
745
|
+
const accessor = signalOper.bind(s);
|
|
746
|
+
accessor[SIGNAL_MARKER] = true;
|
|
747
|
+
return accessor;
|
|
730
748
|
}
|
|
731
749
|
function signalOper(value) {
|
|
732
750
|
if (arguments.length > 0) {
|
|
@@ -771,6 +789,7 @@ function computed(getter) {
|
|
|
771
789
|
getter
|
|
772
790
|
};
|
|
773
791
|
const bound = computedOper.bind(c);
|
|
792
|
+
bound[COMPUTED_MARKER] = true;
|
|
774
793
|
return bound;
|
|
775
794
|
}
|
|
776
795
|
function computedOper() {
|
|
@@ -823,7 +842,9 @@ function effect(fn) {
|
|
|
823
842
|
activeSub = prevSub;
|
|
824
843
|
e.flags &= ~Running;
|
|
825
844
|
}
|
|
826
|
-
|
|
845
|
+
const disposer = effectOper.bind(e);
|
|
846
|
+
disposer[EFFECT_MARKER] = true;
|
|
847
|
+
return disposer;
|
|
827
848
|
}
|
|
828
849
|
function effectWithCleanup(fn, cleanupRunner) {
|
|
829
850
|
const e = {
|
|
@@ -847,7 +868,9 @@ function effectWithCleanup(fn, cleanupRunner) {
|
|
|
847
868
|
activeSub = prevSub;
|
|
848
869
|
e.flags &= ~Running;
|
|
849
870
|
}
|
|
850
|
-
|
|
871
|
+
const disposer = effectOper.bind(e);
|
|
872
|
+
disposer[EFFECT_MARKER] = true;
|
|
873
|
+
return disposer;
|
|
851
874
|
}
|
|
852
875
|
function effectOper() {
|
|
853
876
|
disposeNode(this);
|
|
@@ -862,7 +885,9 @@ function effectScope(fn) {
|
|
|
862
885
|
} finally {
|
|
863
886
|
activeSub = prevSub;
|
|
864
887
|
}
|
|
865
|
-
|
|
888
|
+
const disposer = effectScopeOper.bind(e);
|
|
889
|
+
disposer[EFFECT_SCOPE_MARKER] = true;
|
|
890
|
+
return disposer;
|
|
866
891
|
}
|
|
867
892
|
function effectScopeOper() {
|
|
868
893
|
disposeNode(this);
|
|
@@ -1681,9 +1706,6 @@ function mergeProps(...sources) {
|
|
|
1681
1706
|
};
|
|
1682
1707
|
return new Proxy({}, {
|
|
1683
1708
|
get(_, prop) {
|
|
1684
|
-
if (typeof prop === "symbol") {
|
|
1685
|
-
return void 0;
|
|
1686
|
-
}
|
|
1687
1709
|
for (let i = validSources.length - 1; i >= 0; i--) {
|
|
1688
1710
|
const src = validSources[i];
|
|
1689
1711
|
const raw = resolveSource(src);
|
|
@@ -1756,8 +1778,8 @@ function startTransition(fn) {
|
|
|
1756
1778
|
function useTransition() {
|
|
1757
1779
|
const pending = signal(false);
|
|
1758
1780
|
const start = (fn) => {
|
|
1759
|
-
pending(true);
|
|
1760
1781
|
startTransition(() => {
|
|
1782
|
+
pending(true);
|
|
1761
1783
|
try {
|
|
1762
1784
|
fn();
|
|
1763
1785
|
} finally {
|
|
@@ -1792,6 +1814,7 @@ function untrack2(fn) {
|
|
|
1792
1814
|
// src/dom.ts
|
|
1793
1815
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1794
1816
|
var MATHML_NS = "http://www.w3.org/1998/Math/MathML";
|
|
1817
|
+
var isDev = true ? true : typeof process === "undefined" || process.env?.NODE_ENV !== "production";
|
|
1795
1818
|
function render(view, container) {
|
|
1796
1819
|
const root = createRootContext();
|
|
1797
1820
|
const prev = pushRoot(root);
|
|
@@ -2002,18 +2025,28 @@ function applyRef(el, value) {
|
|
|
2002
2025
|
if (typeof value === "function") {
|
|
2003
2026
|
const refFn = value;
|
|
2004
2027
|
refFn(el);
|
|
2005
|
-
|
|
2028
|
+
const root = getCurrentRoot();
|
|
2029
|
+
if (root) {
|
|
2006
2030
|
registerRootCleanup(() => {
|
|
2007
2031
|
refFn(null);
|
|
2008
2032
|
});
|
|
2033
|
+
} else if (isDev) {
|
|
2034
|
+
console.warn(
|
|
2035
|
+
"[fict] Ref applied outside of a root context. The ref cleanup (setting to null) will not run automatically. Consider using createRoot() or ensure the element is created within a component."
|
|
2036
|
+
);
|
|
2009
2037
|
}
|
|
2010
2038
|
} else if (value && typeof value === "object" && "current" in value) {
|
|
2011
2039
|
const refObj = value;
|
|
2012
2040
|
refObj.current = el;
|
|
2013
|
-
|
|
2041
|
+
const root = getCurrentRoot();
|
|
2042
|
+
if (root) {
|
|
2014
2043
|
registerRootCleanup(() => {
|
|
2015
2044
|
refObj.current = null;
|
|
2016
2045
|
});
|
|
2046
|
+
} else if (isDev) {
|
|
2047
|
+
console.warn(
|
|
2048
|
+
"[fict] Ref applied outside of a root context. The ref cleanup (setting to null) will not run automatically. Consider using createRoot() or ensure the element is created within a component."
|
|
2049
|
+
);
|
|
2017
2050
|
}
|
|
2018
2051
|
}
|
|
2019
2052
|
}
|
|
@@ -2427,6 +2460,7 @@ function reconcileArrays(parentNode, a, b) {
|
|
|
2427
2460
|
}
|
|
2428
2461
|
|
|
2429
2462
|
// src/list-helpers.ts
|
|
2463
|
+
var isDev2 = true ? true : typeof process === "undefined" || process.env?.NODE_ENV !== "production";
|
|
2430
2464
|
function moveNodesBefore(parent, nodes, anchor) {
|
|
2431
2465
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
2432
2466
|
const node = nodes[i];
|
|
@@ -2488,6 +2522,7 @@ function removeBlockRange(block) {
|
|
|
2488
2522
|
cursor = next;
|
|
2489
2523
|
}
|
|
2490
2524
|
}
|
|
2525
|
+
var MAX_SAFE_VERSION = 9007199254740991;
|
|
2491
2526
|
function createVersionedSignalAccessor(initialValue) {
|
|
2492
2527
|
let current = initialValue;
|
|
2493
2528
|
let version = 0;
|
|
@@ -2498,7 +2533,7 @@ function createVersionedSignalAccessor(initialValue) {
|
|
|
2498
2533
|
return current;
|
|
2499
2534
|
}
|
|
2500
2535
|
current = value;
|
|
2501
|
-
version
|
|
2536
|
+
version = version >= MAX_SAFE_VERSION ? 1 : version + 1;
|
|
2502
2537
|
track2(version);
|
|
2503
2538
|
}
|
|
2504
2539
|
return accessor;
|
|
@@ -2554,15 +2589,21 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
|
|
|
2554
2589
|
});
|
|
2555
2590
|
const root = createRootContext(hostRoot);
|
|
2556
2591
|
const prevRoot = pushRoot(root);
|
|
2557
|
-
const prevSub = setActiveSub(void 0);
|
|
2558
2592
|
let nodes = [];
|
|
2593
|
+
let scopeDispose;
|
|
2594
|
+
const prevSub = setActiveSub(void 0);
|
|
2559
2595
|
try {
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2596
|
+
scopeDispose = effectScope(() => {
|
|
2597
|
+
const rendered = render2(itemSig, indexSig, key);
|
|
2598
|
+
if (rendered instanceof Node || Array.isArray(rendered) && rendered.every((n) => n instanceof Node)) {
|
|
2599
|
+
nodes = toNodeArray(rendered);
|
|
2600
|
+
} else {
|
|
2601
|
+
const element = createElement(rendered);
|
|
2602
|
+
nodes = toNodeArray(element);
|
|
2603
|
+
}
|
|
2604
|
+
});
|
|
2605
|
+
if (scopeDispose) {
|
|
2606
|
+
root.cleanups.push(scopeDispose);
|
|
2566
2607
|
}
|
|
2567
2608
|
} finally {
|
|
2568
2609
|
setActiveSub(prevSub);
|
|
@@ -2589,6 +2630,86 @@ function isNodeBetweenMarkers(node, startMarker, endMarker) {
|
|
|
2589
2630
|
}
|
|
2590
2631
|
return false;
|
|
2591
2632
|
}
|
|
2633
|
+
function reorderBySwap(parent, first, second) {
|
|
2634
|
+
if (first === second) return false;
|
|
2635
|
+
const firstNodes = first.nodes;
|
|
2636
|
+
const secondNodes = second.nodes;
|
|
2637
|
+
if (firstNodes.length === 0 || secondNodes.length === 0) return false;
|
|
2638
|
+
const lastFirst = firstNodes[firstNodes.length - 1];
|
|
2639
|
+
const lastSecond = secondNodes[secondNodes.length - 1];
|
|
2640
|
+
const afterFirst = lastFirst.nextSibling;
|
|
2641
|
+
const afterSecond = lastSecond.nextSibling;
|
|
2642
|
+
moveNodesBefore(parent, firstNodes, afterSecond);
|
|
2643
|
+
moveNodesBefore(parent, secondNodes, afterFirst);
|
|
2644
|
+
return true;
|
|
2645
|
+
}
|
|
2646
|
+
function getLISIndices(sequence) {
|
|
2647
|
+
const predecessors = new Array(sequence.length);
|
|
2648
|
+
const result = [];
|
|
2649
|
+
for (let i = 0; i < sequence.length; i++) {
|
|
2650
|
+
const value = sequence[i];
|
|
2651
|
+
if (value < 0) {
|
|
2652
|
+
predecessors[i] = -1;
|
|
2653
|
+
continue;
|
|
2654
|
+
}
|
|
2655
|
+
let low = 0;
|
|
2656
|
+
let high = result.length;
|
|
2657
|
+
while (low < high) {
|
|
2658
|
+
const mid = low + high >> 1;
|
|
2659
|
+
if (sequence[result[mid]] < value) {
|
|
2660
|
+
low = mid + 1;
|
|
2661
|
+
} else {
|
|
2662
|
+
high = mid;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
predecessors[i] = low > 0 ? result[low - 1] : -1;
|
|
2666
|
+
if (low === result.length) {
|
|
2667
|
+
result.push(i);
|
|
2668
|
+
} else {
|
|
2669
|
+
result[low] = i;
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
const lis = new Array(result.length);
|
|
2673
|
+
let k = result.length > 0 ? result[result.length - 1] : -1;
|
|
2674
|
+
for (let i = result.length - 1; i >= 0; i--) {
|
|
2675
|
+
lis[i] = k;
|
|
2676
|
+
k = predecessors[k];
|
|
2677
|
+
}
|
|
2678
|
+
return lis;
|
|
2679
|
+
}
|
|
2680
|
+
function reorderByLIS(parent, endMarker, prev, next) {
|
|
2681
|
+
const positions = /* @__PURE__ */ new Map();
|
|
2682
|
+
for (let i = 0; i < prev.length; i++) {
|
|
2683
|
+
positions.set(prev[i], i);
|
|
2684
|
+
}
|
|
2685
|
+
const sequence = new Array(next.length);
|
|
2686
|
+
for (let i = 0; i < next.length; i++) {
|
|
2687
|
+
const position = positions.get(next[i]);
|
|
2688
|
+
if (position === void 0) return false;
|
|
2689
|
+
sequence[i] = position;
|
|
2690
|
+
}
|
|
2691
|
+
const lisIndices = getLISIndices(sequence);
|
|
2692
|
+
if (lisIndices.length === sequence.length) return true;
|
|
2693
|
+
const inLIS = new Array(sequence.length).fill(false);
|
|
2694
|
+
for (let i = 0; i < lisIndices.length; i++) {
|
|
2695
|
+
inLIS[lisIndices[i]] = true;
|
|
2696
|
+
}
|
|
2697
|
+
let anchor = endMarker;
|
|
2698
|
+
let moved = false;
|
|
2699
|
+
for (let i = next.length - 1; i >= 0; i--) {
|
|
2700
|
+
const block = next[i];
|
|
2701
|
+
const nodes = block.nodes;
|
|
2702
|
+
if (nodes.length === 0) continue;
|
|
2703
|
+
if (inLIS[i]) {
|
|
2704
|
+
anchor = nodes[0];
|
|
2705
|
+
continue;
|
|
2706
|
+
}
|
|
2707
|
+
moveNodesBefore(parent, nodes, anchor);
|
|
2708
|
+
anchor = nodes[0];
|
|
2709
|
+
moved = true;
|
|
2710
|
+
}
|
|
2711
|
+
return moved;
|
|
2712
|
+
}
|
|
2592
2713
|
function createKeyedList(getItems, keyFn, renderItem, needsIndex) {
|
|
2593
2714
|
const resolvedNeedsIndex = arguments.length >= 4 ? !!needsIndex : renderItem.length > 1;
|
|
2594
2715
|
return createFineGrainedKeyedList(getItems, keyFn, renderItem, resolvedNeedsIndex);
|
|
@@ -2621,10 +2742,6 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
|
|
|
2621
2742
|
const prevOrderedBlocks = container.orderedBlocks;
|
|
2622
2743
|
const nextOrderedBlocks = container.nextOrderedBlocks;
|
|
2623
2744
|
const orderedIndexByKey = container.orderedIndexByKey;
|
|
2624
|
-
newBlocks.clear();
|
|
2625
|
-
nextOrderedBlocks.length = 0;
|
|
2626
|
-
orderedIndexByKey.clear();
|
|
2627
|
-
const createdBlocks = [];
|
|
2628
2745
|
const newItems = getItems();
|
|
2629
2746
|
if (newItems.length === 0) {
|
|
2630
2747
|
if (oldBlocks.size > 0) {
|
|
@@ -2647,8 +2764,44 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
|
|
|
2647
2764
|
return;
|
|
2648
2765
|
}
|
|
2649
2766
|
const prevCount = prevOrderedBlocks.length;
|
|
2767
|
+
if (prevCount > 0 && newItems.length === prevCount && orderedIndexByKey.size === prevCount) {
|
|
2768
|
+
let stableOrder = true;
|
|
2769
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2770
|
+
for (let i = 0; i < prevCount; i++) {
|
|
2771
|
+
const item = newItems[i];
|
|
2772
|
+
const key = keyFn(item, i);
|
|
2773
|
+
if (seen.has(key) || prevOrderedBlocks[i].key !== key) {
|
|
2774
|
+
stableOrder = false;
|
|
2775
|
+
break;
|
|
2776
|
+
}
|
|
2777
|
+
seen.add(key);
|
|
2778
|
+
}
|
|
2779
|
+
if (stableOrder) {
|
|
2780
|
+
for (let i = 0; i < prevCount; i++) {
|
|
2781
|
+
const item = newItems[i];
|
|
2782
|
+
const block = prevOrderedBlocks[i];
|
|
2783
|
+
if (block.rawItem !== item) {
|
|
2784
|
+
block.rawItem = item;
|
|
2785
|
+
block.item(item);
|
|
2786
|
+
}
|
|
2787
|
+
if (needsIndex && block.rawIndex !== i) {
|
|
2788
|
+
block.rawIndex = i;
|
|
2789
|
+
block.index(i);
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
return;
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
newBlocks.clear();
|
|
2796
|
+
nextOrderedBlocks.length = 0;
|
|
2797
|
+
orderedIndexByKey.clear();
|
|
2798
|
+
const createdBlocks = [];
|
|
2650
2799
|
let appendCandidate = prevCount > 0 && newItems.length >= prevCount;
|
|
2651
2800
|
const appendedBlocks = [];
|
|
2801
|
+
let mismatchCount = 0;
|
|
2802
|
+
let mismatchFirst = -1;
|
|
2803
|
+
let mismatchSecond = -1;
|
|
2804
|
+
let hasDuplicateKey = false;
|
|
2652
2805
|
newItems.forEach((item, index) => {
|
|
2653
2806
|
const key = keyFn(item, index);
|
|
2654
2807
|
let block = oldBlocks.get(key);
|
|
@@ -2669,6 +2822,11 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
|
|
|
2669
2822
|
} else {
|
|
2670
2823
|
const existingBlock = newBlocks.get(key);
|
|
2671
2824
|
if (existingBlock) {
|
|
2825
|
+
if (isDev2) {
|
|
2826
|
+
console.warn(
|
|
2827
|
+
`[fict] Duplicate key "${String(key)}" detected in list rendering. Each item should have a unique key. The previous item with this key will be replaced.`
|
|
2828
|
+
);
|
|
2829
|
+
}
|
|
2672
2830
|
destroyRoot(existingBlock.root);
|
|
2673
2831
|
removeNodes(existingBlock.nodes);
|
|
2674
2832
|
}
|
|
@@ -2680,6 +2838,7 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
|
|
|
2680
2838
|
const position = orderedIndexByKey.get(key);
|
|
2681
2839
|
if (position !== void 0) {
|
|
2682
2840
|
appendCandidate = false;
|
|
2841
|
+
hasDuplicateKey = true;
|
|
2683
2842
|
const prior = nextOrderedBlocks[position];
|
|
2684
2843
|
if (prior && prior !== resolvedBlock) {
|
|
2685
2844
|
destroyRoot(prior.root);
|
|
@@ -2696,8 +2855,17 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
|
|
|
2696
2855
|
appendCandidate = false;
|
|
2697
2856
|
}
|
|
2698
2857
|
}
|
|
2699
|
-
|
|
2858
|
+
const nextIndex = nextOrderedBlocks.length;
|
|
2859
|
+
orderedIndexByKey.set(key, nextIndex);
|
|
2700
2860
|
nextOrderedBlocks.push(resolvedBlock);
|
|
2861
|
+
if (mismatchCount < 3 && (nextIndex >= prevCount || prevOrderedBlocks[nextIndex] !== resolvedBlock)) {
|
|
2862
|
+
if (mismatchCount === 0) {
|
|
2863
|
+
mismatchFirst = nextIndex;
|
|
2864
|
+
} else if (mismatchCount === 1) {
|
|
2865
|
+
mismatchSecond = nextIndex;
|
|
2866
|
+
}
|
|
2867
|
+
mismatchCount++;
|
|
2868
|
+
}
|
|
2701
2869
|
}
|
|
2702
2870
|
if (appendCandidate && index >= prevCount) {
|
|
2703
2871
|
appendedBlocks.push(resolvedBlock);
|
|
@@ -2738,7 +2906,26 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
|
|
|
2738
2906
|
}
|
|
2739
2907
|
oldBlocks.clear();
|
|
2740
2908
|
}
|
|
2741
|
-
|
|
2909
|
+
const canReorderInPlace = createdBlocks.length === 0 && oldBlocks.size === 0 && nextOrderedBlocks.length === prevOrderedBlocks.length;
|
|
2910
|
+
let skipReconcile = false;
|
|
2911
|
+
let updateNodeBuffer = true;
|
|
2912
|
+
if (canReorderInPlace && nextOrderedBlocks.length > 0 && !hasDuplicateKey) {
|
|
2913
|
+
if (mismatchCount === 0) {
|
|
2914
|
+
skipReconcile = true;
|
|
2915
|
+
updateNodeBuffer = false;
|
|
2916
|
+
} else if (mismatchCount === 2 && prevOrderedBlocks[mismatchFirst] === nextOrderedBlocks[mismatchSecond] && prevOrderedBlocks[mismatchSecond] === nextOrderedBlocks[mismatchFirst]) {
|
|
2917
|
+
if (reorderBySwap(
|
|
2918
|
+
parent,
|
|
2919
|
+
prevOrderedBlocks[mismatchFirst],
|
|
2920
|
+
prevOrderedBlocks[mismatchSecond]
|
|
2921
|
+
)) {
|
|
2922
|
+
skipReconcile = true;
|
|
2923
|
+
}
|
|
2924
|
+
} else if (reorderByLIS(parent, container.endMarker, prevOrderedBlocks, nextOrderedBlocks)) {
|
|
2925
|
+
skipReconcile = true;
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
if (!skipReconcile && (newBlocks.size > 0 || container.currentNodes.length > 0)) {
|
|
2742
2929
|
const prevNodes = container.currentNodes;
|
|
2743
2930
|
const nextNodes = container.nextNodes;
|
|
2744
2931
|
nextNodes.length = 0;
|
|
@@ -2753,6 +2940,20 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
|
|
|
2753
2940
|
reconcileArrays(parent, prevNodes, nextNodes);
|
|
2754
2941
|
container.currentNodes = nextNodes;
|
|
2755
2942
|
container.nextNodes = prevNodes;
|
|
2943
|
+
} else if (skipReconcile && updateNodeBuffer) {
|
|
2944
|
+
const prevNodes = container.currentNodes;
|
|
2945
|
+
const nextNodes = container.nextNodes;
|
|
2946
|
+
nextNodes.length = 0;
|
|
2947
|
+
nextNodes.push(container.startMarker);
|
|
2948
|
+
for (let i = 0; i < nextOrderedBlocks.length; i++) {
|
|
2949
|
+
const nodes = nextOrderedBlocks[i].nodes;
|
|
2950
|
+
for (let j = 0; j < nodes.length; j++) {
|
|
2951
|
+
nextNodes.push(nodes[j]);
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
nextNodes.push(container.endMarker);
|
|
2955
|
+
container.currentNodes = nextNodes;
|
|
2956
|
+
container.nextNodes = prevNodes;
|
|
2756
2957
|
}
|
|
2757
2958
|
container.blocks = newBlocks;
|
|
2758
2959
|
container.nextBlocks = oldBlocks;
|
|
@@ -3399,7 +3600,9 @@ function bindEvent(el, eventName, handler, options2) {
|
|
|
3399
3600
|
const fn = resolveHandler();
|
|
3400
3601
|
callEventHandler(fn, args[0], el);
|
|
3401
3602
|
} catch (err) {
|
|
3402
|
-
handleError(err, { source: "event", eventName }, rootRef)
|
|
3603
|
+
if (!handleError(err, { source: "event", eventName }, rootRef)) {
|
|
3604
|
+
throw err;
|
|
3605
|
+
}
|
|
3403
3606
|
}
|
|
3404
3607
|
};
|
|
3405
3608
|
return () => {
|
|
@@ -4186,10 +4389,12 @@ function ErrorBoundary(props) {
|
|
|
4186
4389
|
renderingFallback = true;
|
|
4187
4390
|
try {
|
|
4188
4391
|
renderValue(toView(err));
|
|
4189
|
-
} finally {
|
|
4190
4392
|
renderingFallback = false;
|
|
4393
|
+
props.onError?.(err);
|
|
4394
|
+
} catch (fallbackErr) {
|
|
4395
|
+
props.onError?.(err);
|
|
4396
|
+
throw fallbackErr;
|
|
4191
4397
|
}
|
|
4192
|
-
props.onError?.(err);
|
|
4193
4398
|
return;
|
|
4194
4399
|
}
|
|
4195
4400
|
popRoot(prev);
|
|
@@ -4284,7 +4489,9 @@ function Suspense(props) {
|
|
|
4284
4489
|
popRoot(prev);
|
|
4285
4490
|
flushOnMount(root);
|
|
4286
4491
|
destroyRoot(root);
|
|
4287
|
-
handleError(err, { source: "render" })
|
|
4492
|
+
if (!handleError(err, { source: "render" }, hostRoot)) {
|
|
4493
|
+
throw err;
|
|
4494
|
+
}
|
|
4288
4495
|
return;
|
|
4289
4496
|
}
|
|
4290
4497
|
popRoot(prev);
|
|
@@ -4314,18 +4521,26 @@ function Suspense(props) {
|
|
|
4314
4521
|
if (thenable) {
|
|
4315
4522
|
thenable.then(
|
|
4316
4523
|
() => {
|
|
4317
|
-
if (epoch !== tokenEpoch)
|
|
4318
|
-
|
|
4319
|
-
|
|
4524
|
+
if (epoch !== tokenEpoch) {
|
|
4525
|
+
return;
|
|
4526
|
+
}
|
|
4527
|
+
const newPending = Math.max(0, pending() - 1);
|
|
4528
|
+
pending(newPending);
|
|
4529
|
+
if (newPending === 0) {
|
|
4320
4530
|
switchView(props.children ?? null);
|
|
4321
4531
|
onResolveMaybe();
|
|
4322
4532
|
}
|
|
4323
4533
|
},
|
|
4324
4534
|
(err) => {
|
|
4325
|
-
if (epoch !== tokenEpoch)
|
|
4326
|
-
|
|
4535
|
+
if (epoch !== tokenEpoch) {
|
|
4536
|
+
return;
|
|
4537
|
+
}
|
|
4538
|
+
const newPending = Math.max(0, pending() - 1);
|
|
4539
|
+
pending(newPending);
|
|
4327
4540
|
props.onReject?.(err);
|
|
4328
|
-
handleError(err, { source: "render" }, hostRoot)
|
|
4541
|
+
if (!handleError(err, { source: "render" }, hostRoot)) {
|
|
4542
|
+
throw err;
|
|
4543
|
+
}
|
|
4329
4544
|
}
|
|
4330
4545
|
);
|
|
4331
4546
|
return true;
|