@fictjs/runtime 0.0.10 → 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.js CHANGED
@@ -300,7 +300,7 @@ function handleError(err, info, startRoot) {
300
300
  }
301
301
  }
302
302
  }
303
- throw error;
303
+ return false;
304
304
  }
305
305
  function handleSuspend(token, startRoot) {
306
306
  let root = startRoot ?? currentRoot;
@@ -346,6 +346,11 @@ var isInTransition = false;
346
346
  var enqueueMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : (fn) => {
347
347
  Promise.resolve().then(fn);
348
348
  };
349
+ var inCleanup = false;
350
+ var SIGNAL_MARKER = Symbol.for("fict:signal");
351
+ var COMPUTED_MARKER = Symbol.for("fict:computed");
352
+ var EFFECT_MARKER = Symbol.for("fict:effect");
353
+ var EFFECT_SCOPE_MARKER = Symbol.for("fict:effectScope");
349
354
  function link(dep, sub, version) {
350
355
  const prevDep = sub.depsTail;
351
356
  if (prevDep !== void 0 && prevDep.dep === dep) return;
@@ -469,13 +474,21 @@ function checkDirty(firstLink, sub) {
469
474
  dirty = true;
470
475
  }
471
476
  } else if ((depFlags & MutablePending) === MutablePending) {
472
- if (link2.nextSub !== void 0 || link2.prevSub !== void 0) {
473
- stack = { value: link2, prev: stack };
477
+ if (!dep.deps) {
478
+ const nextDep = link2.nextDep;
479
+ if (nextDep !== void 0) {
480
+ link2 = nextDep;
481
+ continue;
482
+ }
483
+ } else {
484
+ if (link2.nextSub !== void 0 || link2.prevSub !== void 0) {
485
+ stack = { value: link2, prev: stack };
486
+ }
487
+ link2 = dep.deps;
488
+ sub = dep;
489
+ ++checkDepth;
490
+ continue;
474
491
  }
475
- link2 = dep.deps;
476
- sub = dep;
477
- ++checkDepth;
478
- continue;
479
492
  }
480
493
  if (!dirty) {
481
494
  const nextDep = link2.nextDep;
@@ -553,8 +566,12 @@ function disposeNode(node) {
553
566
  node.depsTail = void 0;
554
567
  node.flags = 0;
555
568
  purgeDeps(node);
556
- const sub = node.subs;
557
- if (sub !== void 0) unlink(sub, node);
569
+ let sub = node.subs;
570
+ while (sub !== void 0) {
571
+ const next = sub.nextSub;
572
+ unlink(sub);
573
+ sub = next;
574
+ }
558
575
  }
559
576
  function updateSignal(s) {
560
577
  s.flags = Mutable;
@@ -591,7 +608,15 @@ function updateComputed(c) {
591
608
  }
592
609
  function runEffect(e) {
593
610
  const flags = e.flags;
594
- if (flags & Dirty || flags & Pending && e.deps && checkDirty(e.deps, e)) {
611
+ if (flags & Dirty) {
612
+ if (e.runCleanup) {
613
+ inCleanup = true;
614
+ try {
615
+ e.runCleanup();
616
+ } finally {
617
+ inCleanup = false;
618
+ }
619
+ }
595
620
  ++cycle;
596
621
  effectRunDevtools(e);
597
622
  e.depsTail = void 0;
@@ -608,6 +633,35 @@ function runEffect(e) {
608
633
  e.flags = Watching;
609
634
  throw err;
610
635
  }
636
+ } else if (flags & Pending && e.deps) {
637
+ if (e.runCleanup) {
638
+ inCleanup = true;
639
+ try {
640
+ e.runCleanup();
641
+ } finally {
642
+ inCleanup = false;
643
+ }
644
+ }
645
+ if (checkDirty(e.deps, e)) {
646
+ ++cycle;
647
+ effectRunDevtools(e);
648
+ e.depsTail = void 0;
649
+ e.flags = WatchingRunning;
650
+ const prevSub = activeSub;
651
+ activeSub = e;
652
+ try {
653
+ e.fn();
654
+ activeSub = prevSub;
655
+ e.flags = Watching;
656
+ purgeDeps(e);
657
+ } catch (err) {
658
+ activeSub = prevSub;
659
+ e.flags = Watching;
660
+ throw err;
661
+ }
662
+ } else {
663
+ e.flags = Watching;
664
+ }
611
665
  } else {
612
666
  e.flags = Watching;
613
667
  }
@@ -686,7 +740,9 @@ function signal(initialValue) {
686
740
  __id: void 0
687
741
  };
688
742
  registerSignalDevtools(initialValue, s);
689
- return signalOper.bind(s);
743
+ const accessor = signalOper.bind(s);
744
+ accessor[SIGNAL_MARKER] = true;
745
+ return accessor;
690
746
  }
691
747
  function signalOper(value) {
692
748
  if (arguments.length > 0) {
@@ -703,7 +759,7 @@ function signalOper(value) {
703
759
  return;
704
760
  }
705
761
  const flags = this.flags;
706
- if (flags & Dirty) {
762
+ if (flags & Dirty && !inCleanup) {
707
763
  if (updateSignal(this)) {
708
764
  const subs = this.subs;
709
765
  if (subs !== void 0) shallowPropagate(subs);
@@ -731,6 +787,7 @@ function computed(getter) {
731
787
  getter
732
788
  };
733
789
  const bound = computedOper.bind(c);
790
+ bound[COMPUTED_MARKER] = true;
734
791
  return bound;
735
792
  }
736
793
  function computedOper() {
@@ -783,7 +840,35 @@ function effect(fn) {
783
840
  activeSub = prevSub;
784
841
  e.flags &= ~Running;
785
842
  }
786
- return effectOper.bind(e);
843
+ const disposer = effectOper.bind(e);
844
+ disposer[EFFECT_MARKER] = true;
845
+ return disposer;
846
+ }
847
+ function effectWithCleanup(fn, cleanupRunner) {
848
+ const e = {
849
+ fn,
850
+ subs: void 0,
851
+ subsTail: void 0,
852
+ deps: void 0,
853
+ depsTail: void 0,
854
+ flags: WatchingRunning,
855
+ runCleanup: cleanupRunner,
856
+ __id: void 0
857
+ };
858
+ registerEffectDevtools(e);
859
+ const prevSub = activeSub;
860
+ if (prevSub !== void 0) link(e, prevSub, 0);
861
+ activeSub = e;
862
+ try {
863
+ effectRunDevtools(e);
864
+ fn();
865
+ } finally {
866
+ activeSub = prevSub;
867
+ e.flags &= ~Running;
868
+ }
869
+ const disposer = effectOper.bind(e);
870
+ disposer[EFFECT_MARKER] = true;
871
+ return disposer;
787
872
  }
788
873
  function effectOper() {
789
874
  disposeNode(this);
@@ -798,7 +883,9 @@ function effectScope(fn) {
798
883
  } finally {
799
884
  activeSub = prevSub;
800
885
  }
801
- return effectScopeOper.bind(e);
886
+ const disposer = effectScopeOper.bind(e);
887
+ disposer[EFFECT_SCOPE_MARKER] = true;
888
+ return disposer;
802
889
  }
803
890
  function effectScopeOper() {
804
891
  disposeNode(this);
@@ -1030,8 +1117,11 @@ var $memo = createMemo;
1030
1117
  function createEffect(fn) {
1031
1118
  let cleanups = [];
1032
1119
  const rootForError = getCurrentRoot();
1033
- const run = () => {
1120
+ const doCleanup = () => {
1034
1121
  runCleanupList(cleanups);
1122
+ cleanups = [];
1123
+ };
1124
+ const run = () => {
1035
1125
  const bucket = [];
1036
1126
  withEffectCleanups(bucket, () => {
1037
1127
  try {
@@ -1048,7 +1138,7 @@ function createEffect(fn) {
1048
1138
  });
1049
1139
  cleanups = bucket;
1050
1140
  };
1051
- const disposeEffect = effect(run);
1141
+ const disposeEffect = effectWithCleanup(run, doCleanup);
1052
1142
  const teardown = () => {
1053
1143
  runCleanupList(cleanups);
1054
1144
  disposeEffect();
@@ -1060,11 +1150,13 @@ var $effect = createEffect;
1060
1150
  function createRenderEffect(fn) {
1061
1151
  let cleanup;
1062
1152
  const rootForError = getCurrentRoot();
1063
- const run = () => {
1153
+ const doCleanup = () => {
1064
1154
  if (cleanup) {
1065
1155
  cleanup();
1066
1156
  cleanup = void 0;
1067
1157
  }
1158
+ };
1159
+ const run = () => {
1068
1160
  try {
1069
1161
  const maybeCleanup = fn();
1070
1162
  if (typeof maybeCleanup === "function") {
@@ -1078,7 +1170,7 @@ function createRenderEffect(fn) {
1078
1170
  throw err;
1079
1171
  }
1080
1172
  };
1081
- const disposeEffect = effect(run);
1173
+ const disposeEffect = effectWithCleanup(run, doCleanup);
1082
1174
  const teardown = () => {
1083
1175
  if (cleanup) {
1084
1176
  cleanup();
@@ -1610,9 +1702,6 @@ function mergeProps(...sources) {
1610
1702
  };
1611
1703
  return new Proxy({}, {
1612
1704
  get(_, prop) {
1613
- if (typeof prop === "symbol") {
1614
- return void 0;
1615
- }
1616
1705
  for (let i = validSources.length - 1; i >= 0; i--) {
1617
1706
  const src = validSources[i];
1618
1707
  const raw = resolveSource(src);
@@ -1685,8 +1774,8 @@ function startTransition(fn) {
1685
1774
  function useTransition() {
1686
1775
  const pending = signal(false);
1687
1776
  const start = (fn) => {
1688
- pending(true);
1689
1777
  startTransition(() => {
1778
+ pending(true);
1690
1779
  try {
1691
1780
  fn();
1692
1781
  } finally {
@@ -1931,7 +2020,8 @@ function applyRef(el, value) {
1931
2020
  if (typeof value === "function") {
1932
2021
  const refFn = value;
1933
2022
  refFn(el);
1934
- if (getCurrentRoot()) {
2023
+ const root = getCurrentRoot();
2024
+ if (root) {
1935
2025
  registerRootCleanup(() => {
1936
2026
  refFn(null);
1937
2027
  });
@@ -1939,7 +2029,8 @@ function applyRef(el, value) {
1939
2029
  } else if (value && typeof value === "object" && "current" in value) {
1940
2030
  const refObj = value;
1941
2031
  refObj.current = el;
1942
- if (getCurrentRoot()) {
2032
+ const root = getCurrentRoot();
2033
+ if (root) {
1943
2034
  registerRootCleanup(() => {
1944
2035
  refObj.current = null;
1945
2036
  });
@@ -2350,8 +2441,6 @@ function reconcileArrays(parentNode, a, b) {
2350
2441
  }
2351
2442
  }
2352
2443
  }
2353
-
2354
- // src/list-helpers.ts
2355
2444
  function moveNodesBefore(parent, nodes, anchor) {
2356
2445
  for (let i = nodes.length - 1; i >= 0; i--) {
2357
2446
  const node = nodes[i];
@@ -2413,6 +2502,7 @@ function removeBlockRange(block) {
2413
2502
  cursor = next;
2414
2503
  }
2415
2504
  }
2505
+ var MAX_SAFE_VERSION = 9007199254740991;
2416
2506
  function createVersionedSignalAccessor(initialValue) {
2417
2507
  let current = initialValue;
2418
2508
  let version = 0;
@@ -2423,7 +2513,7 @@ function createVersionedSignalAccessor(initialValue) {
2423
2513
  return current;
2424
2514
  }
2425
2515
  current = value;
2426
- version++;
2516
+ version = version >= MAX_SAFE_VERSION ? 1 : version + 1;
2427
2517
  track2(version);
2428
2518
  }
2429
2519
  return accessor;
@@ -2479,15 +2569,21 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
2479
2569
  });
2480
2570
  const root = createRootContext(hostRoot);
2481
2571
  const prevRoot = pushRoot(root);
2482
- const prevSub = setActiveSub(void 0);
2483
2572
  let nodes = [];
2573
+ let scopeDispose;
2574
+ const prevSub = setActiveSub(void 0);
2484
2575
  try {
2485
- const rendered = render2(itemSig, indexSig, key);
2486
- if (rendered instanceof Node || Array.isArray(rendered) && rendered.every((n) => n instanceof Node)) {
2487
- nodes = toNodeArray(rendered);
2488
- } else {
2489
- const element = createElement(rendered);
2490
- nodes = toNodeArray(element);
2576
+ scopeDispose = effectScope(() => {
2577
+ const rendered = render2(itemSig, indexSig, key);
2578
+ if (rendered instanceof Node || Array.isArray(rendered) && rendered.every((n) => n instanceof Node)) {
2579
+ nodes = toNodeArray(rendered);
2580
+ } else {
2581
+ const element = createElement(rendered);
2582
+ nodes = toNodeArray(element);
2583
+ }
2584
+ });
2585
+ if (scopeDispose) {
2586
+ root.cleanups.push(scopeDispose);
2491
2587
  }
2492
2588
  } finally {
2493
2589
  setActiveSub(prevSub);
@@ -2514,6 +2610,86 @@ function isNodeBetweenMarkers(node, startMarker, endMarker) {
2514
2610
  }
2515
2611
  return false;
2516
2612
  }
2613
+ function reorderBySwap(parent, first, second) {
2614
+ if (first === second) return false;
2615
+ const firstNodes = first.nodes;
2616
+ const secondNodes = second.nodes;
2617
+ if (firstNodes.length === 0 || secondNodes.length === 0) return false;
2618
+ const lastFirst = firstNodes[firstNodes.length - 1];
2619
+ const lastSecond = secondNodes[secondNodes.length - 1];
2620
+ const afterFirst = lastFirst.nextSibling;
2621
+ const afterSecond = lastSecond.nextSibling;
2622
+ moveNodesBefore(parent, firstNodes, afterSecond);
2623
+ moveNodesBefore(parent, secondNodes, afterFirst);
2624
+ return true;
2625
+ }
2626
+ function getLISIndices(sequence) {
2627
+ const predecessors = new Array(sequence.length);
2628
+ const result = [];
2629
+ for (let i = 0; i < sequence.length; i++) {
2630
+ const value = sequence[i];
2631
+ if (value < 0) {
2632
+ predecessors[i] = -1;
2633
+ continue;
2634
+ }
2635
+ let low = 0;
2636
+ let high = result.length;
2637
+ while (low < high) {
2638
+ const mid = low + high >> 1;
2639
+ if (sequence[result[mid]] < value) {
2640
+ low = mid + 1;
2641
+ } else {
2642
+ high = mid;
2643
+ }
2644
+ }
2645
+ predecessors[i] = low > 0 ? result[low - 1] : -1;
2646
+ if (low === result.length) {
2647
+ result.push(i);
2648
+ } else {
2649
+ result[low] = i;
2650
+ }
2651
+ }
2652
+ const lis = new Array(result.length);
2653
+ let k = result.length > 0 ? result[result.length - 1] : -1;
2654
+ for (let i = result.length - 1; i >= 0; i--) {
2655
+ lis[i] = k;
2656
+ k = predecessors[k];
2657
+ }
2658
+ return lis;
2659
+ }
2660
+ function reorderByLIS(parent, endMarker, prev, next) {
2661
+ const positions = /* @__PURE__ */ new Map();
2662
+ for (let i = 0; i < prev.length; i++) {
2663
+ positions.set(prev[i], i);
2664
+ }
2665
+ const sequence = new Array(next.length);
2666
+ for (let i = 0; i < next.length; i++) {
2667
+ const position = positions.get(next[i]);
2668
+ if (position === void 0) return false;
2669
+ sequence[i] = position;
2670
+ }
2671
+ const lisIndices = getLISIndices(sequence);
2672
+ if (lisIndices.length === sequence.length) return true;
2673
+ const inLIS = new Array(sequence.length).fill(false);
2674
+ for (let i = 0; i < lisIndices.length; i++) {
2675
+ inLIS[lisIndices[i]] = true;
2676
+ }
2677
+ let anchor = endMarker;
2678
+ let moved = false;
2679
+ for (let i = next.length - 1; i >= 0; i--) {
2680
+ const block = next[i];
2681
+ const nodes = block.nodes;
2682
+ if (nodes.length === 0) continue;
2683
+ if (inLIS[i]) {
2684
+ anchor = nodes[0];
2685
+ continue;
2686
+ }
2687
+ moveNodesBefore(parent, nodes, anchor);
2688
+ anchor = nodes[0];
2689
+ moved = true;
2690
+ }
2691
+ return moved;
2692
+ }
2517
2693
  function createKeyedList(getItems, keyFn, renderItem, needsIndex) {
2518
2694
  const resolvedNeedsIndex = arguments.length >= 4 ? !!needsIndex : renderItem.length > 1;
2519
2695
  return createFineGrainedKeyedList(getItems, keyFn, renderItem, resolvedNeedsIndex);
@@ -2546,10 +2722,6 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2546
2722
  const prevOrderedBlocks = container.orderedBlocks;
2547
2723
  const nextOrderedBlocks = container.nextOrderedBlocks;
2548
2724
  const orderedIndexByKey = container.orderedIndexByKey;
2549
- newBlocks.clear();
2550
- nextOrderedBlocks.length = 0;
2551
- orderedIndexByKey.clear();
2552
- const createdBlocks = [];
2553
2725
  const newItems = getItems();
2554
2726
  if (newItems.length === 0) {
2555
2727
  if (oldBlocks.size > 0) {
@@ -2572,8 +2744,44 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2572
2744
  return;
2573
2745
  }
2574
2746
  const prevCount = prevOrderedBlocks.length;
2747
+ if (prevCount > 0 && newItems.length === prevCount && orderedIndexByKey.size === prevCount) {
2748
+ let stableOrder = true;
2749
+ const seen = /* @__PURE__ */ new Set();
2750
+ for (let i = 0; i < prevCount; i++) {
2751
+ const item = newItems[i];
2752
+ const key = keyFn(item, i);
2753
+ if (seen.has(key) || prevOrderedBlocks[i].key !== key) {
2754
+ stableOrder = false;
2755
+ break;
2756
+ }
2757
+ seen.add(key);
2758
+ }
2759
+ if (stableOrder) {
2760
+ for (let i = 0; i < prevCount; i++) {
2761
+ const item = newItems[i];
2762
+ const block = prevOrderedBlocks[i];
2763
+ if (block.rawItem !== item) {
2764
+ block.rawItem = item;
2765
+ block.item(item);
2766
+ }
2767
+ if (needsIndex && block.rawIndex !== i) {
2768
+ block.rawIndex = i;
2769
+ block.index(i);
2770
+ }
2771
+ }
2772
+ return;
2773
+ }
2774
+ }
2775
+ newBlocks.clear();
2776
+ nextOrderedBlocks.length = 0;
2777
+ orderedIndexByKey.clear();
2778
+ const createdBlocks = [];
2575
2779
  let appendCandidate = prevCount > 0 && newItems.length >= prevCount;
2576
2780
  const appendedBlocks = [];
2781
+ let mismatchCount = 0;
2782
+ let mismatchFirst = -1;
2783
+ let mismatchSecond = -1;
2784
+ let hasDuplicateKey = false;
2577
2785
  newItems.forEach((item, index) => {
2578
2786
  const key = keyFn(item, index);
2579
2787
  let block = oldBlocks.get(key);
@@ -2605,6 +2813,7 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2605
2813
  const position = orderedIndexByKey.get(key);
2606
2814
  if (position !== void 0) {
2607
2815
  appendCandidate = false;
2816
+ hasDuplicateKey = true;
2608
2817
  const prior = nextOrderedBlocks[position];
2609
2818
  if (prior && prior !== resolvedBlock) {
2610
2819
  destroyRoot(prior.root);
@@ -2621,8 +2830,17 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2621
2830
  appendCandidate = false;
2622
2831
  }
2623
2832
  }
2624
- orderedIndexByKey.set(key, nextOrderedBlocks.length);
2833
+ const nextIndex = nextOrderedBlocks.length;
2834
+ orderedIndexByKey.set(key, nextIndex);
2625
2835
  nextOrderedBlocks.push(resolvedBlock);
2836
+ if (mismatchCount < 3 && (nextIndex >= prevCount || prevOrderedBlocks[nextIndex] !== resolvedBlock)) {
2837
+ if (mismatchCount === 0) {
2838
+ mismatchFirst = nextIndex;
2839
+ } else if (mismatchCount === 1) {
2840
+ mismatchSecond = nextIndex;
2841
+ }
2842
+ mismatchCount++;
2843
+ }
2626
2844
  }
2627
2845
  if (appendCandidate && index >= prevCount) {
2628
2846
  appendedBlocks.push(resolvedBlock);
@@ -2663,7 +2881,26 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2663
2881
  }
2664
2882
  oldBlocks.clear();
2665
2883
  }
2666
- if (newBlocks.size > 0 || container.currentNodes.length > 0) {
2884
+ const canReorderInPlace = createdBlocks.length === 0 && oldBlocks.size === 0 && nextOrderedBlocks.length === prevOrderedBlocks.length;
2885
+ let skipReconcile = false;
2886
+ let updateNodeBuffer = true;
2887
+ if (canReorderInPlace && nextOrderedBlocks.length > 0 && !hasDuplicateKey) {
2888
+ if (mismatchCount === 0) {
2889
+ skipReconcile = true;
2890
+ updateNodeBuffer = false;
2891
+ } else if (mismatchCount === 2 && prevOrderedBlocks[mismatchFirst] === nextOrderedBlocks[mismatchSecond] && prevOrderedBlocks[mismatchSecond] === nextOrderedBlocks[mismatchFirst]) {
2892
+ if (reorderBySwap(
2893
+ parent,
2894
+ prevOrderedBlocks[mismatchFirst],
2895
+ prevOrderedBlocks[mismatchSecond]
2896
+ )) {
2897
+ skipReconcile = true;
2898
+ }
2899
+ } else if (reorderByLIS(parent, container.endMarker, prevOrderedBlocks, nextOrderedBlocks)) {
2900
+ skipReconcile = true;
2901
+ }
2902
+ }
2903
+ if (!skipReconcile && (newBlocks.size > 0 || container.currentNodes.length > 0)) {
2667
2904
  const prevNodes = container.currentNodes;
2668
2905
  const nextNodes = container.nextNodes;
2669
2906
  nextNodes.length = 0;
@@ -2678,6 +2915,20 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2678
2915
  reconcileArrays(parent, prevNodes, nextNodes);
2679
2916
  container.currentNodes = nextNodes;
2680
2917
  container.nextNodes = prevNodes;
2918
+ } else if (skipReconcile && updateNodeBuffer) {
2919
+ const prevNodes = container.currentNodes;
2920
+ const nextNodes = container.nextNodes;
2921
+ nextNodes.length = 0;
2922
+ nextNodes.push(container.startMarker);
2923
+ for (let i = 0; i < nextOrderedBlocks.length; i++) {
2924
+ const nodes = nextOrderedBlocks[i].nodes;
2925
+ for (let j = 0; j < nodes.length; j++) {
2926
+ nextNodes.push(nodes[j]);
2927
+ }
2928
+ }
2929
+ nextNodes.push(container.endMarker);
2930
+ container.currentNodes = nextNodes;
2931
+ container.nextNodes = prevNodes;
2681
2932
  }
2682
2933
  container.blocks = newBlocks;
2683
2934
  container.nextBlocks = oldBlocks;
@@ -3319,7 +3570,9 @@ function bindEvent(el, eventName, handler, options2) {
3319
3570
  const fn = resolveHandler();
3320
3571
  callEventHandler(fn, args[0], el);
3321
3572
  } catch (err) {
3322
- handleError(err, { source: "event", eventName }, rootRef);
3573
+ if (!handleError(err, { source: "event", eventName }, rootRef)) {
3574
+ throw err;
3575
+ }
3323
3576
  }
3324
3577
  };
3325
3578
  return () => {
@@ -4097,10 +4350,12 @@ function ErrorBoundary(props) {
4097
4350
  renderingFallback = true;
4098
4351
  try {
4099
4352
  renderValue(toView(err));
4100
- } finally {
4101
4353
  renderingFallback = false;
4354
+ props.onError?.(err);
4355
+ } catch (fallbackErr) {
4356
+ props.onError?.(err);
4357
+ throw fallbackErr;
4102
4358
  }
4103
- props.onError?.(err);
4104
4359
  return;
4105
4360
  }
4106
4361
  popRoot(prev);
@@ -4195,7 +4450,9 @@ function Suspense(props) {
4195
4450
  popRoot(prev);
4196
4451
  flushOnMount(root);
4197
4452
  destroyRoot(root);
4198
- handleError(err, { source: "render" });
4453
+ if (!handleError(err, { source: "render" }, hostRoot)) {
4454
+ throw err;
4455
+ }
4199
4456
  return;
4200
4457
  }
4201
4458
  popRoot(prev);
@@ -4225,18 +4482,26 @@ function Suspense(props) {
4225
4482
  if (thenable) {
4226
4483
  thenable.then(
4227
4484
  () => {
4228
- if (epoch !== tokenEpoch) return;
4229
- pending(Math.max(0, pending() - 1));
4230
- if (pending() === 0) {
4485
+ if (epoch !== tokenEpoch) {
4486
+ return;
4487
+ }
4488
+ const newPending = Math.max(0, pending() - 1);
4489
+ pending(newPending);
4490
+ if (newPending === 0) {
4231
4491
  switchView(props.children ?? null);
4232
4492
  onResolveMaybe();
4233
4493
  }
4234
4494
  },
4235
4495
  (err) => {
4236
- if (epoch !== tokenEpoch) return;
4237
- pending(Math.max(0, pending() - 1));
4496
+ if (epoch !== tokenEpoch) {
4497
+ return;
4498
+ }
4499
+ const newPending = Math.max(0, pending() - 1);
4500
+ pending(newPending);
4238
4501
  props.onReject?.(err);
4239
- handleError(err, { source: "render" }, hostRoot);
4502
+ if (!handleError(err, { source: "render" }, hostRoot)) {
4503
+ throw err;
4504
+ }
4240
4505
  }
4241
4506
  );
4242
4507
  return true;