@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/slim.cjs CHANGED
@@ -262,7 +262,7 @@ function handleError(err, info, startRoot) {
262
262
  }
263
263
  }
264
264
  }
265
- throw error;
265
+ return false;
266
266
  }
267
267
  function handleSuspend(token, startRoot) {
268
268
  let root = startRoot ?? currentRoot;
@@ -308,6 +308,10 @@ var enqueueMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : (
308
308
  Promise.resolve().then(fn);
309
309
  };
310
310
  var inCleanup = false;
311
+ var SIGNAL_MARKER = Symbol.for("fict:signal");
312
+ var COMPUTED_MARKER = Symbol.for("fict:computed");
313
+ var EFFECT_MARKER = Symbol.for("fict:effect");
314
+ var EFFECT_SCOPE_MARKER = Symbol.for("fict:effectScope");
311
315
  function link(dep, sub, version) {
312
316
  const prevDep = sub.depsTail;
313
317
  if (prevDep !== void 0 && prevDep.dep === dep) return;
@@ -431,13 +435,21 @@ function checkDirty(firstLink, sub) {
431
435
  dirty = true;
432
436
  }
433
437
  } else if ((depFlags & MutablePending) === MutablePending) {
434
- if (link2.nextSub !== void 0 || link2.prevSub !== void 0) {
435
- stack = { value: link2, prev: stack };
438
+ if (!dep.deps) {
439
+ const nextDep = link2.nextDep;
440
+ if (nextDep !== void 0) {
441
+ link2 = nextDep;
442
+ continue;
443
+ }
444
+ } else {
445
+ if (link2.nextSub !== void 0 || link2.prevSub !== void 0) {
446
+ stack = { value: link2, prev: stack };
447
+ }
448
+ link2 = dep.deps;
449
+ sub = dep;
450
+ ++checkDepth;
451
+ continue;
436
452
  }
437
- link2 = dep.deps;
438
- sub = dep;
439
- ++checkDepth;
440
- continue;
441
453
  }
442
454
  if (!dirty) {
443
455
  const nextDep = link2.nextDep;
@@ -515,8 +527,12 @@ function disposeNode(node) {
515
527
  node.depsTail = void 0;
516
528
  node.flags = 0;
517
529
  purgeDeps(node);
518
- const sub = node.subs;
519
- if (sub !== void 0) unlink(sub, node);
530
+ let sub = node.subs;
531
+ while (sub !== void 0) {
532
+ const next = sub.nextSub;
533
+ unlink(sub);
534
+ sub = next;
535
+ }
520
536
  }
521
537
  function updateSignal(s) {
522
538
  s.flags = Mutable;
@@ -685,7 +701,9 @@ function signal(initialValue) {
685
701
  __id: void 0
686
702
  };
687
703
  registerSignalDevtools(initialValue, s);
688
- return signalOper.bind(s);
704
+ const accessor = signalOper.bind(s);
705
+ accessor[SIGNAL_MARKER] = true;
706
+ return accessor;
689
707
  }
690
708
  function signalOper(value) {
691
709
  if (arguments.length > 0) {
@@ -730,6 +748,7 @@ function computed(getter) {
730
748
  getter
731
749
  };
732
750
  const bound = computedOper.bind(c);
751
+ bound[COMPUTED_MARKER] = true;
733
752
  return bound;
734
753
  }
735
754
  function computedOper() {
@@ -782,7 +801,9 @@ function effect(fn) {
782
801
  activeSub = prevSub;
783
802
  e.flags &= ~Running;
784
803
  }
785
- return effectOper.bind(e);
804
+ const disposer = effectOper.bind(e);
805
+ disposer[EFFECT_MARKER] = true;
806
+ return disposer;
786
807
  }
787
808
  function effectWithCleanup(fn, cleanupRunner) {
788
809
  const e = {
@@ -806,7 +827,9 @@ function effectWithCleanup(fn, cleanupRunner) {
806
827
  activeSub = prevSub;
807
828
  e.flags &= ~Running;
808
829
  }
809
- return effectOper.bind(e);
830
+ const disposer = effectOper.bind(e);
831
+ disposer[EFFECT_MARKER] = true;
832
+ return disposer;
810
833
  }
811
834
  function effectOper() {
812
835
  disposeNode(this);
@@ -821,7 +844,9 @@ function effectScope(fn) {
821
844
  } finally {
822
845
  activeSub = prevSub;
823
846
  }
824
- return effectScopeOper.bind(e);
847
+ const disposer = effectScopeOper.bind(e);
848
+ disposer[EFFECT_SCOPE_MARKER] = true;
849
+ return disposer;
825
850
  }
826
851
  function effectScopeOper() {
827
852
  disposeNode(this);
@@ -1506,9 +1531,6 @@ function mergeProps(...sources) {
1506
1531
  };
1507
1532
  return new Proxy({}, {
1508
1533
  get(_, prop) {
1509
- if (typeof prop === "symbol") {
1510
- return void 0;
1511
- }
1512
1534
  for (let i = validSources.length - 1; i >= 0; i--) {
1513
1535
  const src = validSources[i];
1514
1536
  const raw = resolveSource(src);
@@ -1789,7 +1811,8 @@ function applyRef(el, value) {
1789
1811
  if (typeof value === "function") {
1790
1812
  const refFn = value;
1791
1813
  refFn(el);
1792
- if (getCurrentRoot()) {
1814
+ const root = getCurrentRoot();
1815
+ if (root) {
1793
1816
  registerRootCleanup(() => {
1794
1817
  refFn(null);
1795
1818
  });
@@ -1797,7 +1820,8 @@ function applyRef(el, value) {
1797
1820
  } else if (value && typeof value === "object" && "current" in value) {
1798
1821
  const refObj = value;
1799
1822
  refObj.current = el;
1800
- if (getCurrentRoot()) {
1823
+ const root = getCurrentRoot();
1824
+ if (root) {
1801
1825
  registerRootCleanup(() => {
1802
1826
  refObj.current = null;
1803
1827
  });
@@ -2208,8 +2232,6 @@ function reconcileArrays(parentNode, a, b) {
2208
2232
  }
2209
2233
  }
2210
2234
  }
2211
-
2212
- // src/list-helpers.ts
2213
2235
  function moveNodesBefore(parent, nodes, anchor) {
2214
2236
  for (let i = nodes.length - 1; i >= 0; i--) {
2215
2237
  const node = nodes[i];
@@ -2271,6 +2293,7 @@ function removeBlockRange(block) {
2271
2293
  cursor = next;
2272
2294
  }
2273
2295
  }
2296
+ var MAX_SAFE_VERSION = 9007199254740991;
2274
2297
  function createVersionedSignalAccessor(initialValue) {
2275
2298
  let current = initialValue;
2276
2299
  let version = 0;
@@ -2281,7 +2304,7 @@ function createVersionedSignalAccessor(initialValue) {
2281
2304
  return current;
2282
2305
  }
2283
2306
  current = value;
2284
- version++;
2307
+ version = version >= MAX_SAFE_VERSION ? 1 : version + 1;
2285
2308
  track(version);
2286
2309
  }
2287
2310
  return accessor;
@@ -2337,15 +2360,21 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
2337
2360
  });
2338
2361
  const root = createRootContext(hostRoot);
2339
2362
  const prevRoot = pushRoot(root);
2340
- const prevSub = setActiveSub(void 0);
2341
2363
  let nodes = [];
2364
+ let scopeDispose;
2365
+ const prevSub = setActiveSub(void 0);
2342
2366
  try {
2343
- const rendered = render2(itemSig, indexSig, key);
2344
- if (rendered instanceof Node || Array.isArray(rendered) && rendered.every((n) => n instanceof Node)) {
2345
- nodes = toNodeArray(rendered);
2346
- } else {
2347
- const element = createElement(rendered);
2348
- nodes = toNodeArray(element);
2367
+ scopeDispose = effectScope(() => {
2368
+ const rendered = render2(itemSig, indexSig, key);
2369
+ if (rendered instanceof Node || Array.isArray(rendered) && rendered.every((n) => n instanceof Node)) {
2370
+ nodes = toNodeArray(rendered);
2371
+ } else {
2372
+ const element = createElement(rendered);
2373
+ nodes = toNodeArray(element);
2374
+ }
2375
+ });
2376
+ if (scopeDispose) {
2377
+ root.cleanups.push(scopeDispose);
2349
2378
  }
2350
2379
  } finally {
2351
2380
  setActiveSub(prevSub);
@@ -2364,6 +2393,86 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
2364
2393
  function getFirstNodeAfter(marker) {
2365
2394
  return marker.nextSibling;
2366
2395
  }
2396
+ function reorderBySwap(parent, first, second) {
2397
+ if (first === second) return false;
2398
+ const firstNodes = first.nodes;
2399
+ const secondNodes = second.nodes;
2400
+ if (firstNodes.length === 0 || secondNodes.length === 0) return false;
2401
+ const lastFirst = firstNodes[firstNodes.length - 1];
2402
+ const lastSecond = secondNodes[secondNodes.length - 1];
2403
+ const afterFirst = lastFirst.nextSibling;
2404
+ const afterSecond = lastSecond.nextSibling;
2405
+ moveNodesBefore(parent, firstNodes, afterSecond);
2406
+ moveNodesBefore(parent, secondNodes, afterFirst);
2407
+ return true;
2408
+ }
2409
+ function getLISIndices(sequence) {
2410
+ const predecessors = new Array(sequence.length);
2411
+ const result = [];
2412
+ for (let i = 0; i < sequence.length; i++) {
2413
+ const value = sequence[i];
2414
+ if (value < 0) {
2415
+ predecessors[i] = -1;
2416
+ continue;
2417
+ }
2418
+ let low = 0;
2419
+ let high = result.length;
2420
+ while (low < high) {
2421
+ const mid = low + high >> 1;
2422
+ if (sequence[result[mid]] < value) {
2423
+ low = mid + 1;
2424
+ } else {
2425
+ high = mid;
2426
+ }
2427
+ }
2428
+ predecessors[i] = low > 0 ? result[low - 1] : -1;
2429
+ if (low === result.length) {
2430
+ result.push(i);
2431
+ } else {
2432
+ result[low] = i;
2433
+ }
2434
+ }
2435
+ const lis = new Array(result.length);
2436
+ let k = result.length > 0 ? result[result.length - 1] : -1;
2437
+ for (let i = result.length - 1; i >= 0; i--) {
2438
+ lis[i] = k;
2439
+ k = predecessors[k];
2440
+ }
2441
+ return lis;
2442
+ }
2443
+ function reorderByLIS(parent, endMarker, prev, next) {
2444
+ const positions = /* @__PURE__ */ new Map();
2445
+ for (let i = 0; i < prev.length; i++) {
2446
+ positions.set(prev[i], i);
2447
+ }
2448
+ const sequence = new Array(next.length);
2449
+ for (let i = 0; i < next.length; i++) {
2450
+ const position = positions.get(next[i]);
2451
+ if (position === void 0) return false;
2452
+ sequence[i] = position;
2453
+ }
2454
+ const lisIndices = getLISIndices(sequence);
2455
+ if (lisIndices.length === sequence.length) return true;
2456
+ const inLIS = new Array(sequence.length).fill(false);
2457
+ for (let i = 0; i < lisIndices.length; i++) {
2458
+ inLIS[lisIndices[i]] = true;
2459
+ }
2460
+ let anchor = endMarker;
2461
+ let moved = false;
2462
+ for (let i = next.length - 1; i >= 0; i--) {
2463
+ const block = next[i];
2464
+ const nodes = block.nodes;
2465
+ if (nodes.length === 0) continue;
2466
+ if (inLIS[i]) {
2467
+ anchor = nodes[0];
2468
+ continue;
2469
+ }
2470
+ moveNodesBefore(parent, nodes, anchor);
2471
+ anchor = nodes[0];
2472
+ moved = true;
2473
+ }
2474
+ return moved;
2475
+ }
2367
2476
  function createKeyedList(getItems, keyFn, renderItem, needsIndex) {
2368
2477
  const resolvedNeedsIndex = arguments.length >= 4 ? !!needsIndex : renderItem.length > 1;
2369
2478
  return createFineGrainedKeyedList(getItems, keyFn, renderItem, resolvedNeedsIndex);
@@ -2396,10 +2505,6 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2396
2505
  const prevOrderedBlocks = container.orderedBlocks;
2397
2506
  const nextOrderedBlocks = container.nextOrderedBlocks;
2398
2507
  const orderedIndexByKey = container.orderedIndexByKey;
2399
- newBlocks.clear();
2400
- nextOrderedBlocks.length = 0;
2401
- orderedIndexByKey.clear();
2402
- const createdBlocks = [];
2403
2508
  const newItems = getItems();
2404
2509
  if (newItems.length === 0) {
2405
2510
  if (oldBlocks.size > 0) {
@@ -2422,8 +2527,44 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2422
2527
  return;
2423
2528
  }
2424
2529
  const prevCount = prevOrderedBlocks.length;
2530
+ if (prevCount > 0 && newItems.length === prevCount && orderedIndexByKey.size === prevCount) {
2531
+ let stableOrder = true;
2532
+ const seen = /* @__PURE__ */ new Set();
2533
+ for (let i = 0; i < prevCount; i++) {
2534
+ const item = newItems[i];
2535
+ const key = keyFn(item, i);
2536
+ if (seen.has(key) || prevOrderedBlocks[i].key !== key) {
2537
+ stableOrder = false;
2538
+ break;
2539
+ }
2540
+ seen.add(key);
2541
+ }
2542
+ if (stableOrder) {
2543
+ for (let i = 0; i < prevCount; i++) {
2544
+ const item = newItems[i];
2545
+ const block = prevOrderedBlocks[i];
2546
+ if (block.rawItem !== item) {
2547
+ block.rawItem = item;
2548
+ block.item(item);
2549
+ }
2550
+ if (needsIndex && block.rawIndex !== i) {
2551
+ block.rawIndex = i;
2552
+ block.index(i);
2553
+ }
2554
+ }
2555
+ return;
2556
+ }
2557
+ }
2558
+ newBlocks.clear();
2559
+ nextOrderedBlocks.length = 0;
2560
+ orderedIndexByKey.clear();
2561
+ const createdBlocks = [];
2425
2562
  let appendCandidate = prevCount > 0 && newItems.length >= prevCount;
2426
2563
  const appendedBlocks = [];
2564
+ let mismatchCount = 0;
2565
+ let mismatchFirst = -1;
2566
+ let mismatchSecond = -1;
2567
+ let hasDuplicateKey = false;
2427
2568
  newItems.forEach((item, index) => {
2428
2569
  const key = keyFn(item, index);
2429
2570
  let block = oldBlocks.get(key);
@@ -2455,6 +2596,7 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2455
2596
  const position = orderedIndexByKey.get(key);
2456
2597
  if (position !== void 0) {
2457
2598
  appendCandidate = false;
2599
+ hasDuplicateKey = true;
2458
2600
  const prior = nextOrderedBlocks[position];
2459
2601
  if (prior && prior !== resolvedBlock) {
2460
2602
  destroyRoot(prior.root);
@@ -2471,8 +2613,17 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2471
2613
  appendCandidate = false;
2472
2614
  }
2473
2615
  }
2474
- orderedIndexByKey.set(key, nextOrderedBlocks.length);
2616
+ const nextIndex = nextOrderedBlocks.length;
2617
+ orderedIndexByKey.set(key, nextIndex);
2475
2618
  nextOrderedBlocks.push(resolvedBlock);
2619
+ if (mismatchCount < 3 && (nextIndex >= prevCount || prevOrderedBlocks[nextIndex] !== resolvedBlock)) {
2620
+ if (mismatchCount === 0) {
2621
+ mismatchFirst = nextIndex;
2622
+ } else if (mismatchCount === 1) {
2623
+ mismatchSecond = nextIndex;
2624
+ }
2625
+ mismatchCount++;
2626
+ }
2476
2627
  }
2477
2628
  if (appendCandidate && index >= prevCount) {
2478
2629
  appendedBlocks.push(resolvedBlock);
@@ -2513,7 +2664,26 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2513
2664
  }
2514
2665
  oldBlocks.clear();
2515
2666
  }
2516
- if (newBlocks.size > 0 || container.currentNodes.length > 0) {
2667
+ const canReorderInPlace = createdBlocks.length === 0 && oldBlocks.size === 0 && nextOrderedBlocks.length === prevOrderedBlocks.length;
2668
+ let skipReconcile = false;
2669
+ let updateNodeBuffer = true;
2670
+ if (canReorderInPlace && nextOrderedBlocks.length > 0 && !hasDuplicateKey) {
2671
+ if (mismatchCount === 0) {
2672
+ skipReconcile = true;
2673
+ updateNodeBuffer = false;
2674
+ } else if (mismatchCount === 2 && prevOrderedBlocks[mismatchFirst] === nextOrderedBlocks[mismatchSecond] && prevOrderedBlocks[mismatchSecond] === nextOrderedBlocks[mismatchFirst]) {
2675
+ if (reorderBySwap(
2676
+ parent,
2677
+ prevOrderedBlocks[mismatchFirst],
2678
+ prevOrderedBlocks[mismatchSecond]
2679
+ )) {
2680
+ skipReconcile = true;
2681
+ }
2682
+ } else if (reorderByLIS(parent, container.endMarker, prevOrderedBlocks, nextOrderedBlocks)) {
2683
+ skipReconcile = true;
2684
+ }
2685
+ }
2686
+ if (!skipReconcile && (newBlocks.size > 0 || container.currentNodes.length > 0)) {
2517
2687
  const prevNodes = container.currentNodes;
2518
2688
  const nextNodes = container.nextNodes;
2519
2689
  nextNodes.length = 0;
@@ -2528,6 +2698,20 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2528
2698
  reconcileArrays(parent, prevNodes, nextNodes);
2529
2699
  container.currentNodes = nextNodes;
2530
2700
  container.nextNodes = prevNodes;
2701
+ } else if (skipReconcile && updateNodeBuffer) {
2702
+ const prevNodes = container.currentNodes;
2703
+ const nextNodes = container.nextNodes;
2704
+ nextNodes.length = 0;
2705
+ nextNodes.push(container.startMarker);
2706
+ for (let i = 0; i < nextOrderedBlocks.length; i++) {
2707
+ const nodes = nextOrderedBlocks[i].nodes;
2708
+ for (let j = 0; j < nodes.length; j++) {
2709
+ nextNodes.push(nodes[j]);
2710
+ }
2711
+ }
2712
+ nextNodes.push(container.endMarker);
2713
+ container.currentNodes = nextNodes;
2714
+ container.nextNodes = prevNodes;
2531
2715
  }
2532
2716
  container.blocks = newBlocks;
2533
2717
  container.nextBlocks = oldBlocks;
@@ -3122,7 +3306,9 @@ function bindEvent(el, eventName, handler, options2) {
3122
3306
  const fn = resolveHandler();
3123
3307
  callEventHandler(fn, args[0], el);
3124
3308
  } catch (err) {
3125
- handleError(err, { source: "event", eventName }, rootRef);
3309
+ if (!handleError(err, { source: "event", eventName }, rootRef)) {
3310
+ throw err;
3311
+ }
3126
3312
  }
3127
3313
  };
3128
3314
  return () => {