sibujs 4.14.0 → 4.15.0

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.
Files changed (93) hide show
  1. package/dist/browser.cjs +297 -45
  2. package/dist/browser.js +6 -7
  3. package/dist/build.cjs +2189 -573
  4. package/dist/build.js +16 -15
  5. package/dist/cdn.dev.global.js +13 -12
  6. package/dist/cdn.full.dev.global.js +14 -13
  7. package/dist/cdn.full.global.js +12 -12
  8. package/dist/cdn.global.js +12 -12
  9. package/dist/{chunk-RVR5NPFL.js → chunk-2VKTFA7C.js} +1 -1
  10. package/dist/{chunk-7ILEHTVX.js → chunk-4AEFGRYW.js} +1 -1
  11. package/dist/{chunk-4TQDTWWN.js → chunk-6IV5ZRG6.js} +5 -7
  12. package/dist/{chunk-GVAMIU6K.js → chunk-75EAQH3U.js} +2 -2
  13. package/dist/{chunk-TLS4NVIB.js → chunk-7JO7DPSS.js} +4 -4
  14. package/dist/{chunk-SVULV7O4.js → chunk-AQH7WDSE.js} +6 -8
  15. package/dist/{chunk-S37PZD6I.js → chunk-BF3WBJJQ.js} +60 -10
  16. package/dist/{chunk-LJMX4SQ7.js → chunk-BG4BP44S.js} +3 -3
  17. package/dist/{chunk-N7A6FKWW.js → chunk-D44TAGCT.js} +2 -2
  18. package/dist/{chunk-CCKUNHVU.js → chunk-DAEXQJQA.js} +1 -1
  19. package/dist/chunk-DNCQDFJJ.js +22 -0
  20. package/dist/{chunk-BKZ5N6NK.js → chunk-DNCT2UXB.js} +4 -4
  21. package/dist/{chunk-BOYKGGVD.js → chunk-DRWOD7RZ.js} +4 -4
  22. package/dist/chunk-DS5V2PRE.js +64 -0
  23. package/dist/{chunk-VM2U5LEL.js → chunk-EHSJESRN.js} +595 -123
  24. package/dist/{chunk-MIRKTVH4.js → chunk-GFM5WWPU.js} +252 -5
  25. package/dist/{chunk-52XFPGSN.js → chunk-HTPOIAAL.js} +1 -1
  26. package/dist/{chunk-3HEX6QJQ.js → chunk-I2R5QALY.js} +2 -4
  27. package/dist/{chunk-4FJSAUKB.js → chunk-IUBV5WO5.js} +1 -1
  28. package/dist/{chunk-A454RAEK.js → chunk-KIDETDMU.js} +5 -7
  29. package/dist/{chunk-JTFQ7IL4.js → chunk-KPAXG5IR.js} +7 -9
  30. package/dist/{chunk-AE32RGWX.js → chunk-LGUXYHTZ.js} +3 -3
  31. package/dist/{chunk-Y4LUM2XS.js → chunk-LQWLPQOK.js} +6 -8
  32. package/dist/{chunk-CNPT6NKV.js → chunk-MINLMJUY.js} +48 -9
  33. package/dist/{chunk-BNXRWZZV.js → chunk-OURTGOJT.js} +8 -10
  34. package/dist/{chunk-F67F77IA.js → chunk-TQ24Y3IV.js} +2 -2
  35. package/dist/{chunk-2TTRW2TE.js → chunk-UM3M5PXS.js} +8 -8
  36. package/dist/{chunk-CJ7KS3DF.js → chunk-VSTX3XSX.js} +205 -15
  37. package/dist/{chunk-HQIAL7F2.js → chunk-XPDZ2LDR.js} +2 -2
  38. package/dist/{chunk-UUIKJJIK.js → chunk-Y7JM7GY2.js} +5 -7
  39. package/dist/{chunk-QS6GMWDD.js → chunk-YAFITBOK.js} +1269 -162
  40. package/dist/data.cjs +285 -33
  41. package/dist/data.js +6 -7
  42. package/dist/devtools.cjs +289 -39
  43. package/dist/devtools.js +5 -6
  44. package/dist/{dispose-EIHHHDC7.js → dispose-3WDBYJMH.js} +3 -1
  45. package/dist/ecosystem.cjs +345 -61
  46. package/dist/ecosystem.d.cts +1 -1
  47. package/dist/ecosystem.d.ts +1 -1
  48. package/dist/ecosystem.js +10 -10
  49. package/dist/extras.cjs +568 -248
  50. package/dist/extras.d.cts +1 -1
  51. package/dist/extras.d.ts +1 -1
  52. package/dist/extras.js +27 -27
  53. package/dist/index.cjs +2134 -515
  54. package/dist/index.d.cts +628 -211
  55. package/dist/index.d.ts +628 -211
  56. package/dist/index.js +22 -15
  57. package/dist/motion.cjs +286 -30
  58. package/dist/motion.js +4 -4
  59. package/dist/patterns.cjs +301 -43
  60. package/dist/patterns.js +6 -6
  61. package/dist/performance.cjs +286 -36
  62. package/dist/performance.js +9 -9
  63. package/dist/plugins.cjs +1237 -291
  64. package/dist/plugins.d.cts +3 -1
  65. package/dist/plugins.d.ts +3 -1
  66. package/dist/plugins.js +20 -19
  67. package/dist/{renderRoute-fxgsm2Ir.d.ts → renderRoute-B84MONaO.d.cts} +2 -2
  68. package/dist/{renderRoute-DP20XwMS.d.cts → renderRoute-_yxPuEQY.d.ts} +2 -2
  69. package/dist/{routeHead-CE9SV-cH.d.cts → routeHead-DLxlq15W.d.cts} +94 -0
  70. package/dist/{routeHead-DzVxPviY.d.ts → routeHead-w8nANZ3M.d.ts} +94 -0
  71. package/dist/{ssr-NECEU4X4.js → ssr-EF3IUHTE.js} +6 -6
  72. package/dist/ssr-dom.cjs +64 -9
  73. package/dist/ssr-dom.d.cts +2 -0
  74. package/dist/ssr-dom.d.ts +2 -0
  75. package/dist/ssr-dom.js +2 -1
  76. package/dist/ssr.cjs +850 -170
  77. package/dist/ssr.d.cts +5 -3
  78. package/dist/ssr.d.ts +5 -3
  79. package/dist/ssr.js +16 -15
  80. package/dist/{tagFactory-DkytnJws.d.cts → tagFactory-BfEh69VF.d.cts} +7 -0
  81. package/dist/{tagFactory-Bnd_Nph9.d.ts → tagFactory-pSYiLYyh.d.ts} +7 -0
  82. package/dist/testing.cjs +817 -132
  83. package/dist/testing.d.cts +4 -2
  84. package/dist/testing.d.ts +4 -2
  85. package/dist/testing.js +18 -17
  86. package/dist/track-core-0edROAF5.d.ts +187 -0
  87. package/dist/track-core-DN5fYLWi.d.cts +187 -0
  88. package/dist/ui.cjs +293 -43
  89. package/dist/ui.js +10 -12
  90. package/dist/widgets.cjs +285 -27
  91. package/dist/widgets.js +7 -7
  92. package/package.json +1 -1
  93. package/dist/chunk-7ZHH77QA.js +0 -9
package/dist/index.cjs CHANGED
@@ -135,6 +135,7 @@ __export(index_exports, {
135
135
  lazyIsland: () => lazyIsland,
136
136
  legend: () => legend,
137
137
  li: () => li,
138
+ lifecycleScope: () => lifecycleScope,
138
139
  line: () => line,
139
140
  linearGradient: () => linearGradient,
140
141
  link: () => link,
@@ -168,6 +169,7 @@ __export(index_exports, {
168
169
  param: () => param,
169
170
  path: () => path,
170
171
  pattern: () => pattern,
172
+ pendingContent: () => pendingContent,
171
173
  picture: () => picture,
172
174
  polygon: () => polygon,
173
175
  polyline: () => polyline,
@@ -194,6 +196,7 @@ __export(index_exports, {
194
196
  runInSSRContext: () => runInSSRContext,
195
197
  s: () => s,
196
198
  samp: () => samp,
199
+ scopeOwner: () => scopeOwner,
197
200
  script: () => script,
198
201
  section: () => section,
199
202
  select: () => select,
@@ -202,7 +205,7 @@ __export(index_exports, {
202
205
  setRuntimeErrorHandler: () => setRuntimeErrorHandler,
203
206
  show: () => show,
204
207
  signal: () => signal,
205
- slot: () => slot2,
208
+ slot: () => slot3,
206
209
  small: () => small,
207
210
  source: () => source,
208
211
  span: () => span,
@@ -360,6 +363,12 @@ function reportError(error, context2) {
360
363
  });
361
364
  }
362
365
 
366
+ // src/utils/globalSingleton.ts
367
+ function globalSingleton(key, create) {
368
+ const g2 = globalThis;
369
+ return g2[key] ?? (g2[key] = create());
370
+ }
371
+
363
372
  // src/core/dev.ts
364
373
  var DEV = typeof __SIBU_DEV__ !== "undefined" ? !!__SIBU_DEV__ : typeof globalThis.__SIBU_DEV__ !== "undefined" ? !!globalThis.__SIBU_DEV__ : (
365
374
  // safe default: off in browser, on in test/dev Node
@@ -460,7 +469,12 @@ function holdHydration(sessions, entry) {
460
469
  }
461
470
 
462
471
  // src/core/rendering/dispose.ts
463
- var elementDisposers = /* @__PURE__ */ new WeakMap();
472
+ var state2 = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.disposers.v1"), () => ({
473
+ disposers: /* @__PURE__ */ new WeakMap(),
474
+ captures: [],
475
+ bindings: { count: 0 }
476
+ }));
477
+ var elementDisposers = state2.disposers;
464
478
  var MAX_DRAIN_TEARDOWNS = 1e4;
465
479
  function reportDrainRunaway(label2, executed, remaining) {
466
480
  if (typeof console === "undefined") return;
@@ -469,13 +483,13 @@ function reportDrainRunaway(label2, executed, remaining) {
469
483
  { executed, remaining }
470
484
  );
471
485
  }
472
- var activeBindingCount = 0;
486
+ var bindings = state2.bindings;
473
487
  function resolveCapture(capture) {
474
488
  let frame = capture;
475
489
  while (frame?.closed) frame = frame.forwardTo;
476
490
  return frame ?? null;
477
491
  }
478
- var registrationCaptures = [];
492
+ var registrationCaptures = state2.captures;
479
493
  function currentDisposerCapture() {
480
494
  return resolveCapture(registrationCaptures[registrationCaptures.length - 1]);
481
495
  }
@@ -494,7 +508,7 @@ function registerDisposer(node, teardown) {
494
508
  elementDisposers.set(node, disposers);
495
509
  }
496
510
  disposers.push(teardown);
497
- if (DEV) activeBindingCount++;
511
+ if (DEV) bindings.count++;
498
512
  const capture = resolveCapture(registrationCaptures[registrationCaptures.length - 1]);
499
513
  if (capture) capture.entries.push([node, teardown]);
500
514
  }
@@ -547,7 +561,7 @@ function unregisterDisposer(node, teardown) {
547
561
  const index = disposers.indexOf(teardown);
548
562
  if (index === -1) return false;
549
563
  disposers.splice(index, 1);
550
- if (DEV) activeBindingCount--;
564
+ if (DEV) bindings.count--;
551
565
  if (disposers.length === 0) elementDisposers.delete(node);
552
566
  return true;
553
567
  }
@@ -571,17 +585,17 @@ function disposeNodeOwn(node) {
571
585
  let executed = 0;
572
586
  let runaway = false;
573
587
  while (!runaway) {
574
- const pending = elementDisposers.get(node);
575
- if (!pending || pending.length === 0) break;
576
- const snapshot = pending.slice();
588
+ const pending2 = elementDisposers.get(node);
589
+ if (!pending2 || pending2.length === 0) break;
590
+ const snapshot = pending2.slice();
577
591
  elementDisposers.delete(node);
578
- if (DEV) activeBindingCount -= snapshot.length;
592
+ if (DEV) bindings.count -= snapshot.length;
579
593
  for (let i2 = 0; i2 < snapshot.length; i2++) {
580
594
  if (executed >= MAX_DRAIN_TEARDOWNS) {
581
595
  const rest = snapshot.slice(i2);
582
596
  const added = elementDisposers.get(node);
583
597
  elementDisposers.set(node, added ? rest.concat(added) : rest);
584
- if (DEV) activeBindingCount += rest.length;
598
+ if (DEV) bindings.count += rest.length;
585
599
  reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
586
600
  runaway = true;
587
601
  break;
@@ -620,14 +634,51 @@ function replaceChildrenSafely(parent, ...next) {
620
634
  }
621
635
  parent.replaceChildren(...next);
622
636
  }
637
+ function stageReplaceChildren(parent, next) {
638
+ const done = /* @__PURE__ */ new Set();
639
+ const adopted = () => {
640
+ if (!isHydrating() || next.length === 0 || next[0] !== parent.firstChild) return false;
641
+ for (let i2 = 1; i2 < next.length; i2++) if (next[i2 - 1].nextSibling !== next[i2]) return false;
642
+ return true;
643
+ };
644
+ const outgoing = () => {
645
+ if (adopted()) {
646
+ const out = [];
647
+ for (let n = next[next.length - 1].nextSibling; n !== null; n = n.nextSibling) out.push(n);
648
+ return out;
649
+ }
650
+ for (let i2 = 0; i2 < next.length; i2++) next[i2].parentNode?.removeChild(next[i2]);
651
+ return Array.from(parent.childNodes);
652
+ };
653
+ return {
654
+ teardown: () => {
655
+ let ran = false;
656
+ for (const node of outgoing()) {
657
+ if (done.has(node)) continue;
658
+ done.add(node);
659
+ ran = true;
660
+ dispose(node);
661
+ }
662
+ return ran;
663
+ },
664
+ insert: () => {
665
+ if (!adopted()) {
666
+ parent.replaceChildren(...next);
667
+ return;
668
+ }
669
+ const last = next[next.length - 1];
670
+ while (last.nextSibling) parent.removeChild(last.nextSibling);
671
+ }
672
+ };
673
+ }
623
674
  function checkLeaks(warnThreshold = 0) {
624
675
  if (!DEV) return 0;
625
- if (warnThreshold > 0 && activeBindingCount > warnThreshold) {
676
+ if (warnThreshold > 0 && bindings.count > warnThreshold) {
626
677
  devWarn(
627
- `checkLeaks: ${activeBindingCount} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
678
+ `checkLeaks: ${bindings.count} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
628
679
  );
629
680
  }
630
- return activeBindingCount;
681
+ return bindings.count;
631
682
  }
632
683
 
633
684
  // src/utils/sanitize.ts
@@ -1228,8 +1279,8 @@ function commitSafeAttribute(el, name, value, options) {
1228
1279
  else el.removeAttribute(name);
1229
1280
  return false;
1230
1281
  }
1231
- const pending = value == null || value === false ? null : value === true ? "" : String(value);
1232
- const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
1282
+ const pending2 = value == null || value === false ? null : value === true ? "" : String(value);
1283
+ const refusal = contextualAttributeRefusal(el, name, pending2, options.reactive ? "reactive" : "runtime");
1233
1284
  if (refusal !== ContextualRefusal.None) {
1234
1285
  warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
1235
1286
  if (ns) el.removeAttributeNS(ns, localName);
@@ -1469,6 +1520,201 @@ function bindOwnerScope(fn) {
1469
1520
  return (...args) => runWithOwnerScope(scope, () => fn(...args));
1470
1521
  }
1471
1522
  var currentStructOwner = null;
1523
+ var frozenOwners = 0;
1524
+ var ACTIVE = 0;
1525
+ var PAUSED = 1;
1526
+ var ENDED = 2;
1527
+ var NOOP = () => {
1528
+ };
1529
+ var skippedWhileHeld = /* @__PURE__ */ new Set();
1530
+ var waiters = /* @__PURE__ */ new Set();
1531
+ var heldRoots = /* @__PURE__ */ new Set();
1532
+ function ownerState(tok) {
1533
+ let state4 = ACTIVE;
1534
+ for (let t = tok; t !== null; ) {
1535
+ const o = t.sub;
1536
+ if (o === null) return ENDED;
1537
+ if (o._frozen === true) state4 = PAUSED;
1538
+ t = o._owner ?? null;
1539
+ }
1540
+ return state4;
1541
+ }
1542
+ var endWatchers = /* @__PURE__ */ new Set();
1543
+ var stateWatchers = /* @__PURE__ */ new Set();
1544
+ var stateCheckQueued = false;
1545
+ function queueStateCheck() {
1546
+ if (stateCheckQueued || stateWatchers.size === 0) return;
1547
+ stateCheckQueued = true;
1548
+ queueMicrotask(() => {
1549
+ stateCheckQueued = false;
1550
+ for (const watcher of [...stateWatchers]) {
1551
+ if (!stateWatchers.has(watcher)) continue;
1552
+ const state4 = watcher.check.state();
1553
+ if (state4 === ENDED) stateWatchers.delete(watcher);
1554
+ if (state4 === ENDED || state4 === watcher.last) continue;
1555
+ watcher.last = state4;
1556
+ try {
1557
+ watcher.listener(state4);
1558
+ } catch (err) {
1559
+ reportError(err, { phase: "effect" });
1560
+ }
1561
+ }
1562
+ });
1563
+ }
1564
+ var ALWAYS_ACTIVE = Object.assign(() => false, {
1565
+ state: () => ACTIVE,
1566
+ wait: (onActive) => {
1567
+ onActive();
1568
+ return NOOP;
1569
+ },
1570
+ onEnd: () => NOOP,
1571
+ run: (fn) => fn(),
1572
+ onChange: () => NOOP,
1573
+ within: () => false
1574
+ });
1575
+ function captureFrozen() {
1576
+ const tok = currentStructOwner;
1577
+ if (tok === null) return ALWAYS_ACTIVE;
1578
+ const state4 = () => ownerState(tok);
1579
+ const check = Object.assign(() => state4() !== ACTIVE, {
1580
+ state: state4,
1581
+ wait: (onActive, onEnd) => {
1582
+ const now2 = state4();
1583
+ if (now2 !== PAUSED) {
1584
+ (now2 === ACTIVE ? onActive : onEnd)();
1585
+ return NOOP;
1586
+ }
1587
+ const waiter = { check, onActive, onEnd };
1588
+ waiters.add(waiter);
1589
+ return () => {
1590
+ waiters.delete(waiter);
1591
+ };
1592
+ },
1593
+ onEnd: (onEnd) => {
1594
+ if (state4() === ENDED) {
1595
+ onEnd();
1596
+ return NOOP;
1597
+ }
1598
+ const watcher = { check, onActive: NOOP, onEnd };
1599
+ endWatchers.add(watcher);
1600
+ return () => {
1601
+ endWatchers.delete(watcher);
1602
+ };
1603
+ },
1604
+ run: (fn) => {
1605
+ const prev = currentStructOwner;
1606
+ currentStructOwner = tok.sub === null ? null : tok;
1607
+ try {
1608
+ return fn();
1609
+ } finally {
1610
+ currentStructOwner = prev;
1611
+ }
1612
+ },
1613
+ onChange: (listener) => {
1614
+ const last = state4();
1615
+ if (last === ENDED) return NOOP;
1616
+ const watcher = { check, last, listener };
1617
+ stateWatchers.add(watcher);
1618
+ return () => {
1619
+ stateWatchers.delete(watcher);
1620
+ };
1621
+ },
1622
+ within: (owner) => {
1623
+ const target = owner.run(() => currentStructOwner);
1624
+ if (target === null) return false;
1625
+ for (let t = tok; t !== null; ) {
1626
+ if (t === target) return true;
1627
+ const o = t.sub;
1628
+ if (o === null) return false;
1629
+ t = o._owner ?? null;
1630
+ }
1631
+ return false;
1632
+ }
1633
+ });
1634
+ return check;
1635
+ }
1636
+ function holdSubtree(root) {
1637
+ heldRoots.add(root);
1638
+ return () => {
1639
+ if (heldRoots.delete(root)) settleHeld();
1640
+ };
1641
+ }
1642
+ function isHeld(sub2) {
1643
+ if (frozenOwners !== 0 && hasFrozenOwner(sub2)) return true;
1644
+ if (heldRoots.size !== 0) {
1645
+ const node = sub2._errorNode;
1646
+ if (node != null) {
1647
+ for (const root of heldRoots) if (root.contains(node)) return true;
1648
+ }
1649
+ }
1650
+ return false;
1651
+ }
1652
+ function notifyEnded() {
1653
+ for (const watcher of stateWatchers) if (watcher.check.state() === ENDED) stateWatchers.delete(watcher);
1654
+ let ended = null;
1655
+ for (const watcher of endWatchers) {
1656
+ if (watcher.check.state() !== ENDED) continue;
1657
+ endWatchers.delete(watcher);
1658
+ (ended ?? (ended = [])).push(watcher);
1659
+ }
1660
+ if (ended === null) return;
1661
+ for (const watcher of ended) {
1662
+ try {
1663
+ watcher.onEnd();
1664
+ } catch (err) {
1665
+ reportError(err, { phase: "cleanup" });
1666
+ }
1667
+ }
1668
+ }
1669
+ function dropReleasedSkipped() {
1670
+ for (const sub2 of skippedWhileHeld) {
1671
+ if (sub2._disposed === true || sub2.depsHead == null) skippedWhileHeld.delete(sub2);
1672
+ }
1673
+ }
1674
+ function settleHeld() {
1675
+ for (const sub2 of skippedWhileHeld) {
1676
+ if (sub2._disposed === true) skippedWhileHeld.delete(sub2);
1677
+ else if (!isHeld(sub2)) {
1678
+ skippedWhileHeld.delete(sub2);
1679
+ if (!pendingSet.has(sub2)) {
1680
+ pendingSet.add(sub2);
1681
+ pendingQueue.push(sub2);
1682
+ }
1683
+ }
1684
+ }
1685
+ if (frozenOwners === 0 && heldRoots.size === 0) skippedWhileHeld.clear();
1686
+ let ready = null;
1687
+ for (const waiter of waiters) {
1688
+ if (waiter.check.state() === PAUSED) continue;
1689
+ waiters.delete(waiter);
1690
+ (ready ?? (ready = [])).push(waiter);
1691
+ }
1692
+ if (ready !== null) {
1693
+ const settle = ready;
1694
+ queueMicrotask(() => {
1695
+ for (const waiter of settle) {
1696
+ const state4 = waiter.check.state();
1697
+ if (state4 === PAUSED) waiters.add(waiter);
1698
+ else
1699
+ try {
1700
+ (state4 === ACTIVE ? waiter.onActive : waiter.onEnd)();
1701
+ } catch (err) {
1702
+ reportError(err, { phase: "effect" });
1703
+ }
1704
+ }
1705
+ });
1706
+ }
1707
+ if (pendingQueue.length > 0) drainNotificationQueue();
1708
+ }
1709
+ function hasFrozenOwner(sub2) {
1710
+ for (let t = sub2._owner ?? null; t !== null; ) {
1711
+ const o = t.sub;
1712
+ if (o === null) return false;
1713
+ if (o._frozen === true) return true;
1714
+ t = o._owner ?? null;
1715
+ }
1716
+ return false;
1717
+ }
1472
1718
  var subscriberEpochCounter = 0;
1473
1719
  function retrack(effectFn, subscriber) {
1474
1720
  const prev = currentSubscriber;
@@ -1576,6 +1822,20 @@ function structuralBinding(commit, ownerNode) {
1576
1822
  } finally {
1577
1823
  currentStructOwner = prev;
1578
1824
  }
1825
+ },
1826
+ freeze: () => {
1827
+ const s2 = sub2;
1828
+ if (s2._disposed || s2._frozen) return;
1829
+ s2._frozen = true;
1830
+ frozenOwners++;
1831
+ queueStateCheck();
1832
+ },
1833
+ thaw: () => {
1834
+ if (!sub2._frozen) return;
1835
+ sub2._frozen = false;
1836
+ frozenOwners--;
1837
+ queueStateCheck();
1838
+ settleHeld();
1579
1839
  }
1580
1840
  };
1581
1841
  }
@@ -1604,20 +1864,34 @@ function createBinding(commit, ownerNode, structural) {
1604
1864
  subscriber._errorNode = ownerNode;
1605
1865
  subscriber._tok = null;
1606
1866
  subscriber._owner = null;
1867
+ subscriber._frozen = false;
1607
1868
  if (structural) subscriber._tok = { sub: subscriber };
1608
1869
  try {
1609
1870
  run();
1610
1871
  } catch (err) {
1611
1872
  subscriber._disposed = true;
1612
1873
  subscriber._errorNode = void 0;
1613
- if (subscriber._tok != null) subscriber._tok.sub = null;
1874
+ if (subscriber._tok != null) {
1875
+ subscriber._tok.sub = null;
1876
+ if (endWatchers.size !== 0 || stateWatchers.size !== 0) notifyEnded();
1877
+ }
1614
1878
  cleanup(subscriber);
1615
1879
  throw err;
1616
1880
  }
1617
1881
  subscriber._dispose = () => {
1618
1882
  subscriber._disposed = true;
1883
+ const wasFrozen = subscriber._frozen === true;
1884
+ if (wasFrozen) {
1885
+ subscriber._frozen = false;
1886
+ frozenOwners--;
1887
+ }
1619
1888
  subscriber._errorNode = void 0;
1620
- if (subscriber._tok != null) subscriber._tok.sub = null;
1889
+ if (subscriber._tok != null) {
1890
+ subscriber._tok.sub = null;
1891
+ if (endWatchers.size !== 0 || stateWatchers.size !== 0) notifyEnded();
1892
+ if (skippedWhileHeld.size !== 0) dropReleasedSkipped();
1893
+ if (wasFrozen || waiters.size !== 0) settleHeld();
1894
+ }
1621
1895
  cleanup(subscriber);
1622
1896
  };
1623
1897
  return subscriber;
@@ -1727,6 +2001,10 @@ function runPendingOwners(sub2) {
1727
2001
  }
1728
2002
  }
1729
2003
  function runQueued(sub2) {
2004
+ if ((frozenOwners !== 0 || heldRoots.size !== 0) && isHeld(sub2)) {
2005
+ skippedWhileHeld.add(sub2);
2006
+ return;
2007
+ }
1730
2008
  if (quarantined.size > 0 && quarantined.has(sub2)) return;
1731
2009
  if (sub2._hasComputedDep === true && !depsChanged(sub2)) return;
1732
2010
  if (tickRepeat(sub2)) {
@@ -1874,7 +2152,7 @@ function forEachSubscriber(signal2, visit) {
1874
2152
  }
1875
2153
 
1876
2154
  // src/reactivity/track.ts
1877
- var _runtimeVersion = true ? "4.14.0" : "dev";
2155
+ var _runtimeVersion = true ? "4.15.0" : "dev";
1878
2156
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
1879
2157
  function resolveReactiveApi() {
1880
2158
  const g2 = globalThis;
@@ -1910,6 +2188,8 @@ function resolveReactiveApi() {
1910
2188
  runWithOwnerScope,
1911
2189
  bindOwnerScope,
1912
2190
  structuralBinding,
2191
+ captureFrozen,
2192
+ holdSubtree,
1913
2193
  version: _runtimeVersion
1914
2194
  };
1915
2195
  g2[REGISTRY_KEY] = local;
@@ -1937,6 +2217,22 @@ var getOwnerScope2 = API.getOwnerScope ?? getOwnerScope;
1937
2217
  var runWithOwnerScope2 = API.runWithOwnerScope ?? runWithOwnerScope;
1938
2218
  var bindOwnerScope2 = API.bindOwnerScope ?? bindOwnerScope;
1939
2219
  var structuralBinding2 = API.structuralBinding ?? ((commit, ownerNode) => ({ stop: API.reactiveBinding(commit, ownerNode), run: (fn) => fn() }));
2220
+ var captureFrozen2 = API.captureFrozen ?? (() => Object.assign(() => false, {
2221
+ state: () => 0,
2222
+ wait: (onActive) => {
2223
+ onActive();
2224
+ return () => {
2225
+ };
2226
+ },
2227
+ onEnd: () => () => {
2228
+ },
2229
+ run: (fn) => fn(),
2230
+ onChange: () => () => {
2231
+ },
2232
+ within: () => false
2233
+ }));
2234
+ var holdSubtree2 = API.holdSubtree ?? (() => () => {
2235
+ });
1940
2236
 
1941
2237
  // src/reactivity/bindAttribute.ts
1942
2238
  function bindAttribute(el, attr, getter) {
@@ -2065,7 +2361,7 @@ function restoreFocusWithin(snapshot, nodes, where, policy) {
2065
2361
  const active = document.activeElement;
2066
2362
  if (active === snapshot.el) return;
2067
2363
  if (active && active !== document.body && active !== document.documentElement) return;
2068
- if (snapshot.el.isConnected) {
2364
+ if (snapshot.el.isConnected && !snapshot.el.closest("[inert]")) {
2069
2365
  refocus(snapshot.el, snapshot);
2070
2366
  return;
2071
2367
  }
@@ -2092,141 +2388,475 @@ function restoreFocusWithin(snapshot, nodes, where, policy) {
2092
2388
  });
2093
2389
  }
2094
2390
 
2095
- // src/reactivity/bindChildNode.ts
2096
- function bindChildNode(placeholder, getter) {
2097
- let lastNodes = [];
2098
- const scope = captureScope();
2099
- function commit() {
2100
- let result;
2101
- try {
2102
- result = inScope(scope, getter);
2103
- } catch (err) {
2104
- reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
2105
- return;
2106
- }
2107
- const focused = captureFocusWithin(lastNodes);
2108
- if (result == null || typeof result === "boolean") {
2109
- for (let i2 = 0; i2 < lastNodes.length; i2++) {
2110
- const node = lastNodes[i2];
2111
- dispose(node);
2112
- if (node.parentNode) node.parentNode.removeChild(node);
2113
- }
2114
- lastNodes.length = 0;
2115
- restoreFocusWithin(focused, lastNodes, "bindChildNode");
2116
- return;
2117
- }
2118
- const parent = placeholder.parentNode;
2119
- if (!parent) {
2120
- lastNodes.length = 0;
2121
- return;
2122
- }
2123
- let newNodes;
2124
- if (Array.isArray(result)) {
2125
- newNodes = [];
2126
- const seen = /* @__PURE__ */ new Set();
2127
- for (let i2 = 0; i2 < result.length; i2++) {
2128
- const item = result[i2];
2129
- if (item == null || typeof item === "boolean") continue;
2130
- const node = item instanceof Node ? item : document.createTextNode(String(item));
2131
- if (seen.has(node)) {
2132
- if (DEV) devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
2133
- continue;
2134
- }
2135
- seen.add(node);
2136
- newNodes.push(node);
2137
- }
2138
- } else {
2139
- const node = result instanceof Node ? result : document.createTextNode(String(result));
2140
- newNodes = [node];
2141
- }
2142
- let reused;
2143
- if (lastNodes.length > 0 && newNodes.length > 0) {
2144
- const lastSet = new Set(lastNodes);
2145
- reused = /* @__PURE__ */ new Set();
2146
- for (let i2 = 0; i2 < newNodes.length; i2++) {
2147
- if (lastSet.has(newNodes[i2])) reused.add(newNodes[i2]);
2148
- }
2149
- }
2150
- for (let i2 = 0; i2 < lastNodes.length; i2++) {
2151
- const node = lastNodes[i2];
2152
- if (reused?.has(node)) continue;
2153
- dispose(node);
2154
- if (node.parentNode) node.parentNode.removeChild(node);
2155
- }
2156
- let prev = placeholder;
2157
- for (let i2 = 0; i2 < newNodes.length; i2++) {
2158
- const node = newNodes[i2];
2159
- if (prev.nextSibling !== node) {
2160
- parent.insertBefore(node, prev.nextSibling);
2391
+ // src/core/rendering/streamBoundary.ts
2392
+ var _a2;
2393
+ var slot2 = globalThis[_a2 = /* @__PURE__ */ Symbol.for("sibujs.streamBoundary.v1")] ?? (globalThis[_a2] = { hook: null, current: null });
2394
+ function openBoundary(container) {
2395
+ return slot2.hook ? slot2.hook(container) : null;
2396
+ }
2397
+ function currentBoundary() {
2398
+ return slot2.current;
2399
+ }
2400
+
2401
+ // src/core/ssr-context.ts
2402
+ var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
2403
+ function detectSSRShared() {
2404
+ let detected = null;
2405
+ try {
2406
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
2407
+ let mod = null;
2408
+ const getBuiltin = process.getBuiltinModule;
2409
+ if (typeof getBuiltin === "function") {
2410
+ mod = getBuiltin("node:async_hooks");
2411
+ } else if (typeof require === "function") {
2412
+ mod = require("async_hooks");
2161
2413
  }
2162
- prev = node;
2414
+ if (mod) detected = new mod.AsyncLocalStorage();
2163
2415
  }
2164
- lastNodes = newNodes;
2165
- restoreFocusWithin(focused, newNodes, "bindChildNode");
2416
+ const globalAls = globalThis.AsyncLocalStorage;
2417
+ if (!detected && typeof globalAls === "function") detected = new globalAls();
2418
+ } catch {
2419
+ detected = null;
2166
2420
  }
2167
- return reactiveBinding2(commit, placeholder, true);
2421
+ return {
2422
+ als: detected,
2423
+ fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
2424
+ fallbackDepth: 0
2425
+ };
2168
2426
  }
2169
-
2170
- // src/core/rendering/requireDocument.ts
2171
- function noDocument() {
2172
- throw new Error(
2173
- "[SibuJS] renderToString needs a DOM: register happy-dom or jsdom globals first." + (DEV ? ' There is no global `document`, and SibuJS builds live DOM nodes, on the server too. For example: import { GlobalRegistrator } from "@happy-dom/global-registrator"; GlobalRegistrator.register(); See SSR in AGENTS.md \xA710.' : "")
2427
+ var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
2428
+ var als = _shared.als;
2429
+ var fallbackStore = _shared.fallbackStore;
2430
+ _shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
2431
+ var _alsWarned = false;
2432
+ function warnMissingAsyncLocalStorage() {
2433
+ if (_alsWarned || als) return;
2434
+ const isNode = typeof process !== "undefined" && !!process.versions?.node;
2435
+ if (!isNode) return;
2436
+ _alsWarned = true;
2437
+ const version = process.versions.node;
2438
+ devWarn(
2439
+ `SSR request isolation is UNAVAILABLE on this runtime (Node ${version}). AsyncLocalStorage could not be loaded, so concurrent requests share one SSR store: request state and the query cache can bleed between them. Node >= 22.3 is required for isolated SSR under ESM; the CommonJS build works on older versions. A fully synchronous render is unaffected.`
2174
2440
  );
2175
2441
  }
2176
- function requireDocument() {
2177
- if (typeof document === "undefined") noDocument();
2442
+ function getSSRStore() {
2443
+ if (als) {
2444
+ const s2 = als.getStore();
2445
+ if (s2) return s2;
2446
+ }
2447
+ return fallbackStore;
2178
2448
  }
2179
-
2180
- // src/core/rendering/tagFactory.ts
2181
- var SVG_NS3 = "http://www.w3.org/2000/svg";
2182
- var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
2183
- "config",
2184
- "location",
2185
- "history",
2186
- "document",
2187
- "window",
2188
- "navigator",
2189
- "name",
2190
- "top",
2191
- "parent",
2192
- "self",
2193
- "frames"
2194
- ]);
2195
- var warnedLoneStrings = /* @__PURE__ */ new Set();
2196
- var MAX_WARNED_LONE_STRINGS = 100;
2197
- var loneStringCapAnnounced = false;
2198
- var kebabCache = /* @__PURE__ */ new Map();
2199
- function toKebab(prop) {
2200
- let cached = kebabCache.get(prop);
2201
- if (cached !== void 0) return cached;
2202
- cached = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
2203
- kebabCache.set(prop, cached);
2204
- return cached;
2449
+ function getRequestStore() {
2450
+ if (als) return als.getStore() ?? null;
2451
+ return _shared.fallbackDepth > 0 ? fallbackStore : null;
2205
2452
  }
2206
- function applyStyle(el, style2) {
2207
- if (typeof style2 === "function") {
2208
- const getter = style2;
2209
- let written = [];
2210
- let wroteString = false;
2211
- const teardown = reactiveBinding2(() => {
2212
- const value = getter();
2213
- if (value === null || typeof value !== "object") {
2214
- written = [];
2215
- wroteString = true;
2216
- el.setAttribute("style", sanitizeStyleAttribute(String(value), { element: el }));
2217
- return;
2218
- }
2219
- const decl = el.style;
2220
- if (wroteString) {
2221
- el.removeAttribute("style");
2222
- wroteString = false;
2223
- }
2224
- const next = [];
2225
- for (const prop in value) {
2453
+ function isSSR() {
2454
+ return getSSRStore().ssr;
2455
+ }
2456
+ function getRequestScopedCache(name) {
2457
+ if (!isSSR()) return null;
2458
+ const store2 = getSSRStore();
2459
+ const caches = store2.caches ?? (store2.caches = /* @__PURE__ */ new Map());
2460
+ let c = caches.get(name);
2461
+ if (!c) {
2462
+ c = /* @__PURE__ */ new Map();
2463
+ caches.set(name, c);
2464
+ }
2465
+ return c;
2466
+ }
2467
+ var PRERENDER_HOST = /* @__PURE__ */ Symbol.for("sibujs.prerender.v1");
2468
+ function isServer() {
2469
+ return getSSRStore().ssr || globalThis[PRERENDER_HOST] !== void 0;
2470
+ }
2471
+ function isClient() {
2472
+ return !isServer();
2473
+ }
2474
+ function enableSSR() {
2475
+ getSSRStore().ssr = true;
2476
+ }
2477
+ function disableSSR() {
2478
+ getSSRStore().ssr = false;
2479
+ }
2480
+ function runInSSRContext(fn) {
2481
+ const store2 = {
2482
+ ssr: true,
2483
+ suspenseIdCounter: 0,
2484
+ idCounter: 0,
2485
+ locale: void 0,
2486
+ pending: /* @__PURE__ */ new Set(),
2487
+ wake: null
2488
+ };
2489
+ if (als) {
2490
+ return als.run(store2, fn);
2491
+ }
2492
+ warnMissingAsyncLocalStorage();
2493
+ const prev = { ...fallbackStore };
2494
+ Object.assign(fallbackStore, store2);
2495
+ _shared.fallbackDepth++;
2496
+ try {
2497
+ return fn();
2498
+ } finally {
2499
+ _shared.fallbackDepth--;
2500
+ for (const key of Object.keys(fallbackStore)) {
2501
+ if (!(key in prev)) delete fallbackStore[key];
2502
+ }
2503
+ Object.assign(fallbackStore, prev);
2504
+ }
2505
+ }
2506
+ function trackPending(promise, label2, hydration = true) {
2507
+ const store2 = getRequestStore();
2508
+ const pending2 = store2?.pending;
2509
+ const sessions = pending2 || !hydration ? [] : hydrationOwners();
2510
+ if (!pending2 && sessions.length === 0) return promise;
2511
+ const entry = { label: label2, since: Date.now(), boundary: currentBoundary() ?? void 0 };
2512
+ pending2?.add(entry);
2513
+ const release = holdHydration(sessions, entry);
2514
+ const done = () => {
2515
+ pending2?.delete(entry);
2516
+ store2?.wake?.();
2517
+ release();
2518
+ };
2519
+ try {
2520
+ Promise.resolve(promise).then(done, done);
2521
+ } catch {
2522
+ done();
2523
+ }
2524
+ return promise;
2525
+ }
2526
+ function withSSR(fn) {
2527
+ const store2 = getSSRStore();
2528
+ const wasSSR = store2.ssr;
2529
+ store2.ssr = true;
2530
+ try {
2531
+ return fn();
2532
+ } finally {
2533
+ if (!wasSSR) store2.ssr = false;
2534
+ }
2535
+ }
2536
+
2537
+ // src/core/rendering/range.ts
2538
+ var state3 = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.ranges.v1"), () => ({
2539
+ ends: /* @__PURE__ */ new WeakMap(),
2540
+ pending: /* @__PURE__ */ new WeakMap(),
2541
+ registrations: /* @__PURE__ */ new Set(),
2542
+ listeners: /* @__PURE__ */ new Set(),
2543
+ notice: { queued: false, batch: [] }
2544
+ }));
2545
+ var ends = state3.ends;
2546
+ function registerRange(start, last) {
2547
+ ends.set(start, last);
2548
+ }
2549
+ var pending = state3.pending;
2550
+ var NOTHING = () => {
2551
+ };
2552
+ function queueFirstRender(anchor, render, held) {
2553
+ if (held) {
2554
+ const unguarded = render;
2555
+ render = () => {
2556
+ held.wait(unguarded, NOTHING);
2557
+ };
2558
+ }
2559
+ pending.set(anchor, true);
2560
+ queueMicrotask(() => {
2561
+ if (pending.get(anchor) !== true) return;
2562
+ if (anchor.parentNode === null) {
2563
+ pending.set(anchor, render);
2564
+ return;
2565
+ }
2566
+ pending.delete(anchor);
2567
+ render();
2568
+ });
2569
+ }
2570
+ function resumePending(nodes) {
2571
+ for (const node of nodes) {
2572
+ const render = pending.get(node);
2573
+ if (typeof render !== "function") continue;
2574
+ pending.delete(node);
2575
+ render();
2576
+ }
2577
+ }
2578
+ function anyPending(nodes) {
2579
+ for (const node of nodes) if (pending.has(node)) return true;
2580
+ return false;
2581
+ }
2582
+ var registrations = state3.registrations;
2583
+ var loadListeners = state3.listeners;
2584
+ var notice = state3.notice;
2585
+ function notifyLoad(settled) {
2586
+ if (loadListeners.size === 0) return;
2587
+ if (settled !== null) notice.batch.push(settled);
2588
+ if (notice.queued) return;
2589
+ notice.queued = true;
2590
+ queueMicrotask(() => {
2591
+ notice.queued = false;
2592
+ const batch2 = notice.batch;
2593
+ notice.batch = [];
2594
+ for (const listener of [...loadListeners]) listener(batch2);
2595
+ });
2596
+ }
2597
+ function beginPending(at, held) {
2598
+ const entry = { at, held, settled: false, cancelled: false, committed: null };
2599
+ registrations.add(entry);
2600
+ notifyLoad(null);
2601
+ const settle = (cancelled, committed) => {
2602
+ if (entry.settled) return;
2603
+ entry.settled = true;
2604
+ entry.cancelled = cancelled;
2605
+ entry.committed = committed;
2606
+ registrations.delete(entry);
2607
+ notifyLoad(entry);
2608
+ };
2609
+ return {
2610
+ entry,
2611
+ done: (committed) => settle(false, committed ?? null),
2612
+ cancel: () => settle(true, null)
2613
+ };
2614
+ }
2615
+ var INERT = { done: NOTHING, cancel: NOTHING };
2616
+ function beginLoading(anchor) {
2617
+ if (isServer()) return INERT;
2618
+ const { done, cancel } = beginPending(anchor, null);
2619
+ return { done: () => done(), cancel };
2620
+ }
2621
+ function pendingWithin(entry, nodes, owner) {
2622
+ const at = entry.at;
2623
+ if (at !== null) {
2624
+ for (let i2 = 0; i2 < nodes.length; i2++) if (nodes[i2] === at || nodes[i2].contains(at)) return true;
2625
+ return false;
2626
+ }
2627
+ return owner !== null && entry.held?.within(owner) === true;
2628
+ }
2629
+ function loadingWithin(nodes, owner) {
2630
+ const found = [];
2631
+ if (registrations.size === 0) return found;
2632
+ for (const entry of registrations) if (pendingWithin(entry, nodes, owner)) found.push(entry);
2633
+ return found;
2634
+ }
2635
+ function settledContent(entry) {
2636
+ if (!entry.settled || entry.cancelled) return [];
2637
+ let nodes;
2638
+ if (entry.committed !== null) nodes = entry.committed;
2639
+ else if (entry.at === null) return [];
2640
+ else if (entry.at.nodeType === 1) nodes = Array.from(entry.at.childNodes);
2641
+ else nodes = collectRange([entry.at]);
2642
+ const out = [];
2643
+ for (let i2 = 0; i2 < nodes.length; i2++) if (nodes[i2].nodeType === 1) out.push(nodes[i2]);
2644
+ return out;
2645
+ }
2646
+ function onLoaded(listener) {
2647
+ loadListeners.add(listener);
2648
+ return () => {
2649
+ loadListeners.delete(listener);
2650
+ };
2651
+ }
2652
+ function settledSinceNotify() {
2653
+ return notice.batch;
2654
+ }
2655
+ function hasRange(node) {
2656
+ return ends.has(node);
2657
+ }
2658
+ function registerNodesRange(anchor, nodes) {
2659
+ registerRange(anchor, () => {
2660
+ const parent = anchor.parentNode;
2661
+ const wanted = nodes().filter((n) => n !== null && n.parentNode === parent);
2662
+ let last = null;
2663
+ let left = wanted.length;
2664
+ for (let n = anchor.nextSibling; n !== null && left > 0; n = n.nextSibling) {
2665
+ if (wanted.includes(n)) {
2666
+ last = n;
2667
+ left--;
2668
+ }
2669
+ }
2670
+ return last;
2671
+ });
2672
+ }
2673
+ function rangeEnd(node) {
2674
+ let cur = node;
2675
+ for (let get = ends.get(cur); get !== void 0; get = ends.get(cur)) {
2676
+ const next = get();
2677
+ if (next === null || next === cur || next.parentNode !== node.parentNode) break;
2678
+ cur = next;
2679
+ }
2680
+ return cur;
2681
+ }
2682
+ function collectRange(starts) {
2683
+ const out = [];
2684
+ const seen = /* @__PURE__ */ new Set();
2685
+ for (const start of starts) {
2686
+ if (start.parentNode === null) continue;
2687
+ const end = rangeEnd(start);
2688
+ let node = start;
2689
+ let span2 = [start];
2690
+ while (node !== end) {
2691
+ node = node.nextSibling;
2692
+ if (node === null) {
2693
+ span2 = [start];
2694
+ break;
2695
+ }
2696
+ span2.push(node);
2697
+ }
2698
+ for (const n of span2) {
2699
+ if (!seen.has(n)) {
2700
+ seen.add(n);
2701
+ out.push(n);
2702
+ }
2703
+ }
2704
+ }
2705
+ return out;
2706
+ }
2707
+
2708
+ // src/reactivity/bindChildNode.ts
2709
+ function bindChildNode(placeholder, getter, exposeNodes) {
2710
+ let lastNodes = [];
2711
+ const scope = captureScope();
2712
+ function commit() {
2713
+ let result;
2714
+ try {
2715
+ result = inScope(scope, getter);
2716
+ } catch (err) {
2717
+ reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
2718
+ return;
2719
+ }
2720
+ const focused = captureFocusWithin(lastNodes);
2721
+ if (result == null || typeof result === "boolean") {
2722
+ for (let i2 = 0; i2 < lastNodes.length; i2++) {
2723
+ const node = lastNodes[i2];
2724
+ dispose(node);
2725
+ if (node.parentNode) node.parentNode.removeChild(node);
2726
+ }
2727
+ lastNodes.length = 0;
2728
+ restoreFocusWithin(focused, lastNodes, "bindChildNode");
2729
+ return;
2730
+ }
2731
+ const parent = placeholder.parentNode;
2732
+ if (!parent) {
2733
+ lastNodes.length = 0;
2734
+ return;
2735
+ }
2736
+ let newNodes;
2737
+ if (Array.isArray(result)) {
2738
+ newNodes = [];
2739
+ const seen = /* @__PURE__ */ new Set();
2740
+ for (let i2 = 0; i2 < result.length; i2++) {
2741
+ const item = result[i2];
2742
+ if (item == null || typeof item === "boolean") continue;
2743
+ const node = item instanceof Node ? item : document.createTextNode(String(item));
2744
+ if (seen.has(node)) {
2745
+ if (DEV) devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
2746
+ continue;
2747
+ }
2748
+ seen.add(node);
2749
+ newNodes.push(node);
2750
+ }
2751
+ } else {
2752
+ const node = result instanceof Node ? result : document.createTextNode(String(result));
2753
+ newNodes = [node];
2754
+ }
2755
+ let reused;
2756
+ if (lastNodes.length > 0 && newNodes.length > 0) {
2757
+ const lastSet = new Set(lastNodes);
2758
+ reused = /* @__PURE__ */ new Set();
2759
+ for (let i2 = 0; i2 < newNodes.length; i2++) {
2760
+ if (lastSet.has(newNodes[i2])) reused.add(newNodes[i2]);
2761
+ }
2762
+ }
2763
+ for (let i2 = 0; i2 < lastNodes.length; i2++) {
2764
+ const node = lastNodes[i2];
2765
+ if (reused?.has(node)) continue;
2766
+ dispose(node);
2767
+ if (node.parentNode) node.parentNode.removeChild(node);
2768
+ }
2769
+ let prev = placeholder;
2770
+ for (let i2 = 0; i2 < newNodes.length; i2++) {
2771
+ const node = newNodes[i2];
2772
+ if (prev.nextSibling !== node) {
2773
+ parent.insertBefore(node, prev.nextSibling);
2774
+ }
2775
+ prev = node;
2776
+ }
2777
+ lastNodes = newNodes;
2778
+ restoreFocusWithin(focused, newNodes, "bindChildNode");
2779
+ }
2780
+ if (exposeNodes) {
2781
+ registerRange(placeholder, () => {
2782
+ for (let i2 = lastNodes.length - 1; i2 >= 0; i2--) if (lastNodes[i2].parentNode !== null) return lastNodes[i2];
2783
+ return null;
2784
+ });
2785
+ }
2786
+ return reactiveBinding2(commit, placeholder, true);
2787
+ }
2788
+
2789
+ // src/utils/styleKey.ts
2790
+ var EXCEPTIONS = { cssFloat: "float" };
2791
+ var VENDOR_PREFIX = /^(webkit|moz|ms|o)-/;
2792
+ var cache = /* @__PURE__ */ new Map();
2793
+ var CACHE_MAX = 1e3;
2794
+ function styleKeyToProperty(key) {
2795
+ let name = cache.get(key);
2796
+ if (name !== void 0) return name;
2797
+ if (key.startsWith("--")) name = key;
2798
+ else if (Object.hasOwn(EXCEPTIONS, key)) name = EXCEPTIONS[key];
2799
+ else {
2800
+ name = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
2801
+ if (VENDOR_PREFIX.test(name)) name = `-${name}`;
2802
+ }
2803
+ if (cache.size >= CACHE_MAX) cache.clear();
2804
+ cache.set(key, name);
2805
+ return name;
2806
+ }
2807
+
2808
+ // src/core/rendering/requireDocument.ts
2809
+ function noDocument() {
2810
+ throw new Error(
2811
+ "[SibuJS] renderToString needs a DOM: register happy-dom or jsdom globals first." + (DEV ? ' There is no global `document`, and SibuJS builds live DOM nodes, on the server too. For example: import { GlobalRegistrator } from "@happy-dom/global-registrator"; GlobalRegistrator.register(); See SSR in AGENTS.md \xA710.' : "")
2812
+ );
2813
+ }
2814
+ function requireDocument() {
2815
+ if (typeof document === "undefined") noDocument();
2816
+ }
2817
+
2818
+ // src/core/rendering/tagFactory.ts
2819
+ var SVG_NS3 = "http://www.w3.org/2000/svg";
2820
+ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
2821
+ "config",
2822
+ "location",
2823
+ "history",
2824
+ "document",
2825
+ "window",
2826
+ "navigator",
2827
+ "name",
2828
+ "top",
2829
+ "parent",
2830
+ "self",
2831
+ "frames"
2832
+ ]);
2833
+ var warnedLoneStrings = /* @__PURE__ */ new Set();
2834
+ var MAX_WARNED_LONE_STRINGS = 100;
2835
+ var loneStringCapAnnounced = false;
2836
+ function applyStyle(el, style2) {
2837
+ if (typeof style2 === "function") {
2838
+ const getter = style2;
2839
+ let written = [];
2840
+ let wroteString = false;
2841
+ const teardown = reactiveBinding2(() => {
2842
+ const value = getter();
2843
+ if (value === null || typeof value !== "object") {
2844
+ written = [];
2845
+ wroteString = true;
2846
+ el.setAttribute("style", sanitizeStyleAttribute(String(value), { element: el }));
2847
+ return;
2848
+ }
2849
+ const decl = el.style;
2850
+ if (wroteString) {
2851
+ el.removeAttribute("style");
2852
+ wroteString = false;
2853
+ }
2854
+ const next = [];
2855
+ for (const prop in value) {
2226
2856
  if (!Object.hasOwn(value, prop)) continue;
2227
2857
  const val = value[prop];
2228
2858
  if (val == null) continue;
2229
- const name = toKebab(prop);
2859
+ const name = styleKeyToProperty(prop);
2230
2860
  next.push(name);
2231
2861
  decl.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
2232
2862
  }
@@ -2246,7 +2876,7 @@ function applyStyle(el, style2) {
2246
2876
  for (const prop in style2) {
2247
2877
  if (!Object.hasOwn(style2, prop)) continue;
2248
2878
  const val = style2[prop];
2249
- const name = toKebab(prop);
2879
+ const name = styleKeyToProperty(prop);
2250
2880
  if (typeof val === "function") {
2251
2881
  const getter = val;
2252
2882
  const teardown = reactiveBinding2(() => {
@@ -2568,7 +3198,7 @@ var details = tagFactory("details");
2568
3198
  var dialog = tagFactory("dialog");
2569
3199
  var menu = tagFactory("menu");
2570
3200
  var summary = tagFactory("summary");
2571
- var slot2 = tagFactory("slot");
3201
+ var slot3 = tagFactory("slot");
2572
3202
  var template = tagFactory("template");
2573
3203
  var base = tagFactory("base");
2574
3204
  var link = tagFactory("link");
@@ -2597,152 +3227,63 @@ var marker = tagFactory("marker", SVG_NS3);
2597
3227
  var center = tagFactory("center");
2598
3228
  var font = tagFactory("font");
2599
3229
  var marquee = tagFactory("marquee");
2600
- var customElement = (tagName) => tagFactory(tagName);
2601
-
2602
- // src/core/rendering/streamBoundary.ts
2603
- var _a2;
2604
- var slot3 = globalThis[_a2 = /* @__PURE__ */ Symbol.for("sibujs.streamBoundary.v1")] ?? (globalThis[_a2] = { hook: null, current: null });
2605
- function openBoundary(container) {
2606
- return slot3.hook ? slot3.hook(container) : null;
2607
- }
2608
- function currentBoundary() {
2609
- return slot3.current;
2610
- }
2611
-
2612
- // src/core/ssr-context.ts
2613
- var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
2614
- function detectSSRShared() {
2615
- let detected = null;
2616
- try {
2617
- if (typeof process !== "undefined" && process.versions && process.versions.node) {
2618
- let mod = null;
2619
- const getBuiltin = process.getBuiltinModule;
2620
- if (typeof getBuiltin === "function") {
2621
- mod = getBuiltin("node:async_hooks");
2622
- } else if (typeof require === "function") {
2623
- mod = require("async_hooks");
2624
- }
2625
- if (mod) detected = new mod.AsyncLocalStorage();
2626
- }
2627
- const globalAls = globalThis.AsyncLocalStorage;
2628
- if (!detected && typeof globalAls === "function") detected = new globalAls();
2629
- } catch {
2630
- detected = null;
2631
- }
2632
- return {
2633
- als: detected,
2634
- fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
2635
- fallbackDepth: 0
3230
+ var customElement = (tagName) => tagFactory(tagName);
3231
+
3232
+ // src/core/rendering/heldCommit.ts
3233
+ var NOOP2 = () => {
3234
+ };
3235
+ function commitWhenActive(slot4, c) {
3236
+ let over = false;
3237
+ let unhold = null;
3238
+ let drop = NOOP2;
3239
+ const finish = () => {
3240
+ over = true;
3241
+ if (slot4.cancel === cancel) slot4.cancel = NOOP2;
3242
+ drop();
3243
+ drop = NOOP2;
2636
3244
  };
2637
- }
2638
- var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
2639
- var als = _shared.als;
2640
- var fallbackStore = _shared.fallbackStore;
2641
- _shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
2642
- var _alsWarned = false;
2643
- function warnMissingAsyncLocalStorage() {
2644
- if (_alsWarned || als) return;
2645
- const isNode = typeof process !== "undefined" && !!process.versions?.node;
2646
- if (!isNode) return;
2647
- _alsWarned = true;
2648
- const version = process.versions.node;
2649
- devWarn(
2650
- `SSR request isolation is UNAVAILABLE on this runtime (Node ${version}). AsyncLocalStorage could not be loaded, so concurrent requests share one SSR store: request state and the query cache can bleed between them. Node >= 22.3 is required for isolated SSR under ESM; the CommonJS build works on older versions. A fully synchronous render is unaffected.`
2651
- );
2652
- }
2653
- function getSSRStore() {
2654
- if (als) {
2655
- const s2 = als.getStore();
2656
- if (s2) return s2;
2657
- }
2658
- return fallbackStore;
2659
- }
2660
- function getRequestStore() {
2661
- if (als) return als.getStore() ?? null;
2662
- return _shared.fallbackDepth > 0 ? fallbackStore : null;
2663
- }
2664
- function isSSR() {
2665
- return getSSRStore().ssr;
2666
- }
2667
- function getRequestScopedCache(name) {
2668
- if (!isSSR()) return null;
2669
- const store2 = getSSRStore();
2670
- const caches = store2.caches ?? (store2.caches = /* @__PURE__ */ new Map());
2671
- let c = caches.get(name);
2672
- if (!c) {
2673
- c = /* @__PURE__ */ new Map();
2674
- caches.set(name, c);
2675
- }
2676
- return c;
2677
- }
2678
- var PRERENDER_HOST = /* @__PURE__ */ Symbol.for("sibujs.prerender.v1");
2679
- function isServer() {
2680
- return getSSRStore().ssr || globalThis[PRERENDER_HOST] !== void 0;
2681
- }
2682
- function isClient() {
2683
- return !isServer();
2684
- }
2685
- function enableSSR() {
2686
- getSSRStore().ssr = true;
2687
- }
2688
- function disableSSR() {
2689
- getSSRStore().ssr = false;
2690
- }
2691
- function runInSSRContext(fn) {
2692
- const store2 = {
2693
- ssr: true,
2694
- suspenseIdCounter: 0,
2695
- idCounter: 0,
2696
- locale: void 0,
2697
- pending: /* @__PURE__ */ new Set(),
2698
- wake: null
3245
+ const cancel = () => {
3246
+ if (over) return;
3247
+ finish();
3248
+ const release = unhold;
3249
+ unhold = null;
3250
+ try {
3251
+ c.discard();
3252
+ } finally {
3253
+ release?.();
3254
+ }
2699
3255
  };
2700
- if (als) {
2701
- return als.run(store2, fn);
2702
- }
2703
- warnMissingAsyncLocalStorage();
2704
- const prev = { ...fallbackStore };
2705
- Object.assign(fallbackStore, store2);
2706
- _shared.fallbackDepth++;
2707
- try {
2708
- return fn();
2709
- } finally {
2710
- _shared.fallbackDepth--;
2711
- for (const key of Object.keys(fallbackStore)) {
2712
- if (!(key in prev)) delete fallbackStore[key];
3256
+ const attempt = () => {
3257
+ drop = NOOP2;
3258
+ let clean = false;
3259
+ while (!over) {
3260
+ const state4 = c.held.state();
3261
+ if (state4 === 2 || c.owned !== void 0 && !c.owned()) {
3262
+ cancel();
3263
+ return;
3264
+ }
3265
+ if (state4 === 1) {
3266
+ if (c.node !== null && unhold === null) unhold = holdSubtree2(c.node);
3267
+ drop = c.held.wait(attempt, attempt);
3268
+ return;
3269
+ }
3270
+ if (unhold !== null) {
3271
+ const release = unhold;
3272
+ unhold = null;
3273
+ release();
3274
+ continue;
3275
+ }
3276
+ if (!clean) {
3277
+ clean = c.teardown?.() !== true;
3278
+ continue;
3279
+ }
3280
+ finish();
3281
+ c.insert();
3282
+ return;
2713
3283
  }
2714
- Object.assign(fallbackStore, prev);
2715
- }
2716
- }
2717
- function trackPending(promise, label2, hydration = true) {
2718
- const store2 = getRequestStore();
2719
- const pending = store2?.pending;
2720
- const sessions = pending || !hydration ? [] : hydrationOwners();
2721
- if (!pending && sessions.length === 0) return promise;
2722
- const entry = { label: label2, since: Date.now(), boundary: currentBoundary() ?? void 0 };
2723
- pending?.add(entry);
2724
- const release = holdHydration(sessions, entry);
2725
- const done = () => {
2726
- pending?.delete(entry);
2727
- store2?.wake?.();
2728
- release();
2729
3284
  };
2730
- try {
2731
- Promise.resolve(promise).then(done, done);
2732
- } catch {
2733
- done();
2734
- }
2735
- return promise;
2736
- }
2737
- function withSSR(fn) {
2738
- const store2 = getSSRStore();
2739
- const wasSSR = store2.ssr;
2740
- store2.ssr = true;
2741
- try {
2742
- return fn();
2743
- } finally {
2744
- if (!wasSSR) store2.ssr = false;
2745
- }
3285
+ slot4.cancel = cancel;
3286
+ attempt();
2746
3287
  }
2747
3288
 
2748
3289
  // src/core/rendering/lazy.ts
@@ -2768,100 +3309,296 @@ function takePendingError(node) {
2768
3309
  }
2769
3310
  return void 0;
2770
3311
  }
3312
+ var NOOP3 = () => {
3313
+ };
2771
3314
  function lazy(importFn) {
2772
3315
  let cached = null;
3316
+ const instance = (component) => {
3317
+ const own = structuralBinding2(NOOP3);
3318
+ try {
3319
+ return [withDisposerRollback(() => own.run(component)), own];
3320
+ } catch (err) {
3321
+ own.stop();
3322
+ throw err;
3323
+ }
3324
+ };
3325
+ const ending = (root, own) => root.nodeType === 11 ? () => {
3326
+ disposeNodeOwn(root);
3327
+ own.stop();
3328
+ } : own.stop;
2773
3329
  return function LazyComponent() {
2774
3330
  if (cached && !inAdoptScope()) {
2775
- return cached();
3331
+ const [root, own] = instance(cached);
3332
+ const type = root?.nodeType;
3333
+ if (type === 11) {
3334
+ const box = div({ class: "sibu-lazy" });
3335
+ registerDisposer(box, ending(root, own));
3336
+ box.appendChild(root);
3337
+ return box;
3338
+ }
3339
+ if (typeof type === "number") registerDisposer(root, own.stop);
3340
+ return root;
2776
3341
  }
2777
3342
  const container = div({ class: "sibu-lazy" });
2778
3343
  const scope = captureScope();
2779
3344
  const boundary = currentBoundary();
2780
- let disposed = false;
2781
3345
  const loading = inScope(null, () => span("sibu-lazy-loading", "Loading..."));
2782
3346
  if (cached) {
2783
3347
  const loaded = cached;
2784
- replaceChildrenSafely(container, inScope(scope, () => loaded()));
3348
+ let rendered;
3349
+ try {
3350
+ const [root, own] = instance(() => inScope(scope, () => loaded()));
3351
+ registerDisposer(container, ending(root, own));
3352
+ rendered = root;
3353
+ } catch (err) {
3354
+ dispose(container);
3355
+ throw err;
3356
+ }
3357
+ replaceChildrenSafely(container, rendered);
2785
3358
  return container;
2786
3359
  }
2787
- trackPending(importFn(), "lazy").then(
2788
- // The component renders after the import resolves, in the owner scope
2789
- // of whoever rendered the placeholder.
2790
- bindOwnerScope2((mod) => {
2791
- if (disposed) return;
2792
- cached = mod.default;
2793
- const component = cached;
2794
- const build = () => inScope(scope, () => component());
2795
- const rendered = boundary ? boundary.enter(build) : build();
2796
- replaceChildrenSafely(container, rendered);
2797
- })
2798
- ).catch((err) => {
2799
- if (disposed) return;
2800
- const errorObj = err instanceof Error ? err : new Error(String(err));
2801
- replaceChildrenSafely(
2802
- container,
2803
- div({ class: "sibu-lazy-error" }, `Failed to load component: ${errorObj.message}`)
2804
- );
2805
- dispatchPropagate(container, errorObj);
2806
- });
2807
- if (!(isHydrating() && container.firstChild)) container.appendChild(loading);
3360
+ const held = captureFrozen2();
3361
+ const inOwner = bindOwnerScope2((fn) => fn());
3362
+ const ready = beginLoading(container);
3363
+ let disposed = false;
3364
+ const live = () => !disposed;
3365
+ let owner = null;
3366
+ const waiting = { cancel: NOOP3 };
2808
3367
  registerDisposer(container, () => {
2809
3368
  disposed = true;
3369
+ waiting.cancel();
3370
+ ready.cancel();
3371
+ const end = owner;
3372
+ owner = null;
3373
+ end?.();
2810
3374
  });
3375
+ if (!(isHydrating() && container.firstChild)) container.appendChild(loading);
3376
+ const show2 = (view, release, claim, shown, failed) => {
3377
+ const swap = stageReplaceChildren(container, [view]);
3378
+ commitWhenActive(waiting, {
3379
+ held,
3380
+ node: view,
3381
+ owned: live,
3382
+ teardown: swap.teardown,
3383
+ insert: () => {
3384
+ claim();
3385
+ try {
3386
+ swap.insert();
3387
+ } catch (err) {
3388
+ release();
3389
+ failed(err);
3390
+ return;
3391
+ }
3392
+ if (!disposed) shown();
3393
+ },
3394
+ discard: () => {
3395
+ release();
3396
+ ready.cancel();
3397
+ }
3398
+ });
3399
+ };
3400
+ const later = (fn) => commitWhenActive(waiting, { held, node: null, owned: live, insert: () => inOwner(fn), discard: ready.cancel });
3401
+ const fail = (err) => {
3402
+ if (disposed) return;
3403
+ const error = err instanceof Error ? err : new Error(String(err));
3404
+ const view = div({ class: "sibu-lazy-error" }, `Failed to load component: ${error.message}`);
3405
+ show2(
3406
+ view,
3407
+ () => dispose(view),
3408
+ NOOP3,
3409
+ () => {
3410
+ ready.done();
3411
+ dispatchPropagate(container, error);
3412
+ },
3413
+ (insertError) => {
3414
+ ready.cancel();
3415
+ reportError(insertError, { phase: "render", name: "lazy" });
3416
+ }
3417
+ );
3418
+ };
3419
+ const build = (component) => {
3420
+ if (disposed) return;
3421
+ let rendered;
3422
+ let own;
3423
+ try {
3424
+ const render = () => held.run(() => instance(() => inScope(scope, () => component())));
3425
+ [rendered, own] = boundary ? boundary.enter(render) : render();
3426
+ } catch (err) {
3427
+ fail(err);
3428
+ return;
3429
+ }
3430
+ const end = ending(rendered, own);
3431
+ show2(
3432
+ rendered,
3433
+ () => {
3434
+ if (owner === end) owner = null;
3435
+ own.stop();
3436
+ dispose(rendered);
3437
+ },
3438
+ () => {
3439
+ owner = end;
3440
+ },
3441
+ () => ready.done(),
3442
+ fail
3443
+ );
3444
+ };
3445
+ let imported;
3446
+ try {
3447
+ imported = importFn();
3448
+ } catch (err) {
3449
+ dispose(container);
3450
+ throw err;
3451
+ }
3452
+ trackPending(imported, "lazy").then(
3453
+ (mod) => {
3454
+ if (disposed) return;
3455
+ cached = mod.default;
3456
+ const component = cached;
3457
+ later(() => build(component));
3458
+ },
3459
+ (err) => {
3460
+ if (!disposed) later(() => fail(err));
3461
+ }
3462
+ );
2811
3463
  return container;
2812
3464
  };
2813
3465
  }
2814
3466
  function Suspense({ nodes, fallback }) {
2815
3467
  const container = div({ class: "sibu-suspense" });
2816
3468
  const scope = captureScope();
3469
+ const held = captureFrozen2();
3470
+ const inOwner = bindOwnerScope2((fn) => fn());
2817
3471
  const boundary = openBoundary(container);
2818
- const commit = (el) => {
2819
- replaceChildrenSafely(container, el);
2820
- boundary?.done();
2821
- };
2822
- const fallbackEl = inScope(null, fallback);
2823
- if (isHydrating() && container.firstChild) dispose(fallbackEl);
2824
- else container.appendChild(fallbackEl);
3472
+ const ready = beginLoading(container);
2825
3473
  let suspenseDisposed = false;
3474
+ const live = () => !suspenseDisposed;
2826
3475
  let observer = null;
2827
3476
  let childEl = null;
3477
+ let contentOwner = null;
3478
+ const endContent = () => {
3479
+ const own = contentOwner;
3480
+ contentOwner = null;
3481
+ own?.stop();
3482
+ };
3483
+ const fallbackOwn = structuralBinding2(NOOP3);
3484
+ let fallbackOwner = fallbackOwn;
3485
+ const endFallback = () => {
3486
+ const own = fallbackOwner;
3487
+ fallbackOwner = null;
3488
+ own?.stop();
3489
+ };
3490
+ const waiting = { cancel: NOOP3 };
2828
3491
  registerDisposer(container, () => {
2829
3492
  suspenseDisposed = true;
3493
+ waiting.cancel();
3494
+ ready.cancel();
2830
3495
  if (observer) {
2831
3496
  observer.disconnect();
2832
3497
  observer = null;
2833
3498
  }
2834
3499
  if (childEl && !container.contains(childEl)) dispose(childEl);
3500
+ endFallback();
3501
+ endContent();
2835
3502
  });
2836
- const renderContent = bindOwnerScope2(() => {
2837
- if (suspenseDisposed) return;
2838
- try {
2839
- const el = boundary ? boundary.enter(() => inScope(scope, nodes)) : inScope(scope, nodes);
2840
- childEl = el;
2841
- if (el.classList.contains("sibu-lazy")) {
2842
- if (!el.querySelector(".sibu-lazy-loading")) {
2843
- commit(el);
3503
+ let fallbackEl;
3504
+ try {
3505
+ fallbackEl = inScope(null, () => withDisposerRollback(() => fallbackOwn.run(fallback)));
3506
+ } catch (err) {
3507
+ boundary?.done();
3508
+ dispose(container);
3509
+ throw err;
3510
+ }
3511
+ if (isHydrating() && container.firstChild) {
3512
+ dispose(fallbackEl);
3513
+ endFallback();
3514
+ } else container.appendChild(fallbackEl);
3515
+ const commit = (el) => {
3516
+ const swap = stageReplaceChildren(container, [el]);
3517
+ commitWhenActive(waiting, {
3518
+ held,
3519
+ node: el,
3520
+ owned: live,
3521
+ teardown: () => {
3522
+ if (swap.teardown()) return true;
3523
+ if (fallbackOwner === null) return false;
3524
+ endFallback();
3525
+ return true;
3526
+ },
3527
+ // `el` is the container's content already (`childEl`): disposing the
3528
+ // container from its `connectedCallback`, during the insertion,
3529
+ // disposes it — in the container, or as the orphan `childEl` is.
3530
+ insert: () => {
3531
+ try {
3532
+ swap.insert();
3533
+ } catch (err) {
3534
+ if (childEl === el) childEl = null;
3535
+ dispose(el);
3536
+ endContent();
3537
+ ready.cancel();
3538
+ boundary?.done();
3539
+ dispatchPropagate(container, err instanceof Error ? err : new Error(String(err)));
2844
3540
  return;
2845
3541
  }
2846
- observer = new MutationObserver(() => {
2847
- if (suspenseDisposed) return;
2848
- const loading = el.querySelector(".sibu-lazy-loading");
2849
- if (!loading) {
2850
- observer?.disconnect();
2851
- observer = null;
2852
- commit(el);
2853
- }
2854
- });
2855
- observer.observe(el, { childList: true, subtree: true });
2856
- } else {
2857
- commit(el);
3542
+ boundary?.done();
3543
+ ready.done();
3544
+ },
3545
+ discard: () => {
3546
+ if (childEl === el) childEl = null;
3547
+ dispose(el);
3548
+ endContent();
3549
+ ready.cancel();
2858
3550
  }
3551
+ });
3552
+ };
3553
+ const renderContent = () => {
3554
+ if (suspenseDisposed) return;
3555
+ const own = held.run(() => structuralBinding2(NOOP3));
3556
+ contentOwner = own;
3557
+ let el;
3558
+ try {
3559
+ const build = () => withDisposerRollback(() => own.run(() => inScope(scope, nodes)));
3560
+ el = boundary ? boundary.enter(build) : build();
2859
3561
  } catch (err) {
3562
+ endContent();
2860
3563
  const errorObj = err instanceof Error ? err : new Error(String(err));
3564
+ ready.cancel();
2861
3565
  dispatchPropagate(container, errorObj);
3566
+ return;
3567
+ }
3568
+ childEl = el;
3569
+ if (suspenseDisposed) {
3570
+ childEl = null;
3571
+ dispose(el);
3572
+ return;
3573
+ }
3574
+ if (el.classList.contains("sibu-lazy")) {
3575
+ if (!el.querySelector(".sibu-lazy-loading")) {
3576
+ commit(el);
3577
+ return;
3578
+ }
3579
+ observer = new MutationObserver(() => {
3580
+ if (suspenseDisposed) return;
3581
+ const loading = el.querySelector(".sibu-lazy-loading");
3582
+ if (!loading) {
3583
+ observer?.disconnect();
3584
+ observer = null;
3585
+ commit(el);
3586
+ }
3587
+ });
3588
+ observer.observe(el, { childList: true, subtree: true });
3589
+ } else {
3590
+ commit(el);
2862
3591
  }
3592
+ };
3593
+ queueMicrotask(() => {
3594
+ commitWhenActive(waiting, {
3595
+ held,
3596
+ node: null,
3597
+ owned: live,
3598
+ insert: () => inOwner(renderContent),
3599
+ discard: ready.cancel
3600
+ });
2863
3601
  });
2864
- queueMicrotask(renderContent);
2865
3602
  return container;
2866
3603
  }
2867
3604
 
@@ -3319,7 +4056,7 @@ var isBatching = API2.isBatching;
3319
4056
  // src/core/signals/signal.ts
3320
4057
  var _g2 = globalThis;
3321
4058
  function signal(initial, options) {
3322
- const state2 = {
4059
+ const state4 = {
3323
4060
  value: initial,
3324
4061
  __v: 0,
3325
4062
  __sc: 0,
@@ -3332,57 +4069,57 @@ function signal(initial, options) {
3332
4069
  };
3333
4070
  const debugName = DEV ? options?.name : void 0;
3334
4071
  const equalsFn = options?.equals;
3335
- if (debugName) state2.__name = debugName;
4072
+ if (debugName) state4.__name = debugName;
3336
4073
  function get() {
3337
- recordDependency2(state2);
3338
- return state2.value;
4074
+ recordDependency2(state4);
4075
+ return state4.value;
3339
4076
  }
3340
- get.__signal = state2;
4077
+ get.__signal = state4;
3341
4078
  if (debugName) get.__name = debugName;
3342
4079
  let set;
3343
4080
  if (equalsFn) {
3344
4081
  set = (next) => {
3345
- const prev = state2.value;
4082
+ const prev = state4.value;
3346
4083
  const newValue = typeof next === "function" ? next(prev) : next;
3347
4084
  if (equalsFn(prev, newValue)) return;
3348
- state2.value = newValue;
3349
- state2.__v++;
4085
+ state4.value = newValue;
4086
+ state4.__v++;
3350
4087
  if (DEV) {
3351
4088
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
3352
- if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
4089
+ if (hook) emitDevtools(hook, "signal:update", { signal: state4, name: debugName, oldValue: prev, newValue });
3353
4090
  }
3354
- if (!enqueueBatchedSignal(state2)) {
3355
- notifySubscribers2(state2);
4091
+ if (!enqueueBatchedSignal(state4)) {
4092
+ notifySubscribers2(state4);
3356
4093
  }
3357
4094
  };
3358
4095
  } else if (DEV) {
3359
4096
  set = (next) => {
3360
- const prev = state2.value;
4097
+ const prev = state4.value;
3361
4098
  const newValue = typeof next === "function" ? next(prev) : next;
3362
4099
  if (Object.is(newValue, prev)) return;
3363
- state2.value = newValue;
3364
- state2.__v++;
4100
+ state4.value = newValue;
4101
+ state4.__v++;
3365
4102
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
3366
- if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
3367
- if (!enqueueBatchedSignal(state2)) {
3368
- notifySubscribers2(state2);
4103
+ if (hook) emitDevtools(hook, "signal:update", { signal: state4, name: debugName, oldValue: prev, newValue });
4104
+ if (!enqueueBatchedSignal(state4)) {
4105
+ notifySubscribers2(state4);
3369
4106
  }
3370
4107
  };
3371
4108
  } else {
3372
4109
  set = (next) => {
3373
- const prev = state2.value;
4110
+ const prev = state4.value;
3374
4111
  const newValue = typeof next === "function" ? next(prev) : next;
3375
4112
  if (Object.is(newValue, prev)) return;
3376
- state2.value = newValue;
3377
- state2.__v++;
3378
- if (!enqueueBatchedSignal(state2)) {
3379
- notifySubscribers2(state2);
4113
+ state4.value = newValue;
4114
+ state4.__v++;
4115
+ if (!enqueueBatchedSignal(state4)) {
4116
+ notifySubscribers2(state4);
3380
4117
  }
3381
4118
  };
3382
4119
  }
3383
4120
  if (DEV) {
3384
4121
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
3385
- if (hook) emitDevtools(hook, "signal:create", { signal: state2, name: debugName, getter: get, initial });
4122
+ if (hook) emitDevtools(hook, "signal:create", { signal: state4, name: debugName, getter: get, initial });
3386
4123
  }
3387
4124
  return [get, set];
3388
4125
  }
@@ -4106,8 +4843,8 @@ function ErrorBoundary(optionsOrChildren, maybeChildren) {
4106
4843
  const collected = [];
4107
4844
  let node = walker.currentNode;
4108
4845
  while (node) {
4109
- const pending = takePendingError(node);
4110
- if (pending) collected.push(pending);
4846
+ const pending2 = takePendingError(node);
4847
+ if (pending2) collected.push(pending2);
4111
4848
  node = walker.nextNode();
4112
4849
  }
4113
4850
  if (collected.length === 1) {
@@ -4408,6 +5145,202 @@ function setGlobalErrorHandler(handler) {
4408
5145
  globalErrorHandler = handler;
4409
5146
  }
4410
5147
 
5148
+ // src/core/rendering/branchTransition.ts
5149
+ var HARD_CAP_MS = 5e3;
5150
+ function now() {
5151
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
5152
+ }
5153
+ var SLACK_MS = 50;
5154
+ var INSTANT_MS = 1;
5155
+ var FALLBACK_EVENTS = ["transitionend", "transitioncancel", "animationend", "animationcancel"];
5156
+ function parseList(list, fallback) {
5157
+ return (list?.trim() ? list : fallback).split(",").map((part) => part.trim());
5158
+ }
5159
+ function parseTimes(list) {
5160
+ return parseList(list, "0s").map((v) => (Number.parseFloat(v) || 0) * (v.endsWith("ms") ? 1 : 1e3));
5161
+ }
5162
+ function measure(el) {
5163
+ if (typeof getComputedStyle !== "function") return null;
5164
+ const cs = getComputedStyle(el);
5165
+ if (cs.display === "none") return null;
5166
+ const timing = { total: 0, transitions: /* @__PURE__ */ new Map(), animations: /* @__PURE__ */ new Map(), pending: 0 };
5167
+ const expect = (map2, names, durations, delays, iterations) => {
5168
+ for (let i2 = 0; i2 < names.length; i2++) {
5169
+ const duration = durations[i2 % durations.length];
5170
+ if (names[i2] === "none" || duration <= 0) continue;
5171
+ const count = iterations[i2 % iterations.length];
5172
+ const runs = count === "infinite" ? Number.POSITIVE_INFINITY : Number.parseFloat(count) || 1;
5173
+ timing.total = Math.max(timing.total, delays[i2 % delays.length] + duration * runs);
5174
+ map2.set(names[i2], (map2.get(names[i2]) ?? 0) + 1);
5175
+ timing.pending++;
5176
+ }
5177
+ };
5178
+ expect(
5179
+ timing.transitions,
5180
+ parseList(cs.transitionProperty, "all"),
5181
+ parseTimes(cs.transitionDuration),
5182
+ parseTimes(cs.transitionDelay),
5183
+ ["1"]
5184
+ );
5185
+ expect(
5186
+ timing.animations,
5187
+ parseList(cs.animationName, "none"),
5188
+ parseTimes(cs.animationDuration),
5189
+ parseTimes(cs.animationDelay),
5190
+ parseList(cs.animationIterationCount, "1")
5191
+ );
5192
+ return timing.total <= INSTANT_MS ? null : timing;
5193
+ }
5194
+ function matchEntry(map2, name) {
5195
+ if (typeof name !== "string" || name === "") return map2.keys().next().value;
5196
+ if (map2.has(name)) return name;
5197
+ for (const key of map2.keys()) if (name.startsWith(`${key}-`)) return key;
5198
+ return map2.has("all") ? "all" : void 0;
5199
+ }
5200
+ function insideAnimating(animating, el) {
5201
+ for (const a2 of animating) if (a2 !== el && a2.contains(el)) return true;
5202
+ return false;
5203
+ }
5204
+ function runPhase(nodes, cls, custom, maxDuration, onDone, name, open = 0) {
5205
+ const cap = Math.min(typeof maxDuration === "number" && maxDuration >= 0 ? maxDuration : HARD_CAP_MS, HARD_CAP_MS);
5206
+ const elements = [];
5207
+ for (let i2 = 0; i2 < nodes.length; i2++) if (nodes[i2].nodeType === 1) elements.push(nodes[i2]);
5208
+ let finished = false;
5209
+ let timer = null;
5210
+ const cleanups = [];
5211
+ const finish = (complete) => {
5212
+ if (finished) return;
5213
+ finished = true;
5214
+ if (timer !== null) clearTimeout(timer);
5215
+ for (let i2 = 0; i2 < cleanups.length; i2++) cleanups[i2]();
5216
+ if (complete) onDone();
5217
+ };
5218
+ const report = (error) => reportError(error, { phase: "async", name, node: elements[0] });
5219
+ if (custom) {
5220
+ let result;
5221
+ try {
5222
+ result = custom(nodes);
5223
+ } catch (error) {
5224
+ report(error);
5225
+ }
5226
+ const pending2 = adoptThenable(result);
5227
+ if (pending2 === null) {
5228
+ onDone();
5229
+ return null;
5230
+ }
5231
+ pending2.then(
5232
+ () => finish(true),
5233
+ (error) => {
5234
+ report(error);
5235
+ finish(true);
5236
+ }
5237
+ );
5238
+ timer = setTimeout(() => finish(true), cap);
5239
+ return { cancel: () => finish(false) };
5240
+ }
5241
+ let holding = open > 0;
5242
+ if (!cls || elements.length === 0 && !holding) {
5243
+ onDone();
5244
+ return null;
5245
+ }
5246
+ for (let i2 = 0; i2 < elements.length; i2++) elements[i2].classList.add(cls);
5247
+ cleanups.push(() => {
5248
+ for (let i2 = 0; i2 < elements.length; i2++) elements[i2].classList.remove(cls);
5249
+ });
5250
+ const capAt = now() + cap;
5251
+ let deadline = 0;
5252
+ const arm = (until) => {
5253
+ const at = Math.min(until, capAt);
5254
+ if (timer !== null && at <= deadline) return;
5255
+ if (timer !== null) clearTimeout(timer);
5256
+ deadline = at;
5257
+ timer = setTimeout(() => finish(true), Math.max(0, at - now()));
5258
+ };
5259
+ let waiting = 0;
5260
+ const animating = /* @__PURE__ */ new Set();
5261
+ const enroll = (el) => {
5262
+ const timing = measure(el);
5263
+ if (timing === null) return -1;
5264
+ const running = typeof el.getAnimations === "function" ? el.getAnimations() : null;
5265
+ if (running !== null) {
5266
+ if (running.length === 0) return -1;
5267
+ waiting++;
5268
+ animating.add(el);
5269
+ let left = running.length;
5270
+ const settle2 = () => {
5271
+ if (left === 0 || --left !== 0) return;
5272
+ animating.delete(el);
5273
+ if (!finished && --waiting === 0 && !holding) finish(true);
5274
+ };
5275
+ for (const animation of running) animation.finished.then(settle2, settle2);
5276
+ return timing.total;
5277
+ }
5278
+ waiting++;
5279
+ animating.add(el);
5280
+ let done = false;
5281
+ let estimate = null;
5282
+ const settle = () => {
5283
+ if (done) return;
5284
+ done = true;
5285
+ if (estimate !== null) clearTimeout(estimate);
5286
+ animating.delete(el);
5287
+ if (!finished && --waiting === 0 && !holding) finish(true);
5288
+ };
5289
+ const onEnd = (event) => {
5290
+ if (event.target !== el || done || timing.pending === 0) return;
5291
+ const transition2 = event.type === "transitionend" || event.type === "transitioncancel";
5292
+ const map2 = transition2 ? timing.transitions : timing.animations;
5293
+ const key = matchEntry(
5294
+ map2,
5295
+ event[transition2 ? "propertyName" : "animationName"]
5296
+ );
5297
+ if (key === void 0) return;
5298
+ const left = map2.get(key) - 1;
5299
+ if (left > 0) map2.set(key, left);
5300
+ else map2.delete(key);
5301
+ if (--timing.pending === 0) settle();
5302
+ };
5303
+ for (const type of FALLBACK_EVENTS) el.addEventListener(type, onEnd);
5304
+ if (Number.isFinite(timing.total)) estimate = setTimeout(settle, timing.total + SLACK_MS);
5305
+ cleanups.push(() => {
5306
+ if (estimate !== null) clearTimeout(estimate);
5307
+ for (const type of FALLBACK_EVENTS) el.removeEventListener(type, onEnd);
5308
+ });
5309
+ return timing.total;
5310
+ };
5311
+ let longest = -1;
5312
+ for (let i2 = 0; i2 < elements.length; i2++) longest = Math.max(longest, enroll(elements[i2]));
5313
+ if (waiting === 0 && !holding) {
5314
+ finish(true);
5315
+ return null;
5316
+ }
5317
+ if (waiting > 0) arm(now() + longest + SLACK_MS);
5318
+ const close = () => {
5319
+ holding = false;
5320
+ if (!finished && waiting === 0) finish(true);
5321
+ };
5322
+ if (holding) {
5323
+ arm(now() + open);
5324
+ const openTimer = setTimeout(close, Math.max(0, Math.min(now() + open, capAt) - now()));
5325
+ cleanups.push(() => clearTimeout(openTimer));
5326
+ }
5327
+ return {
5328
+ cancel: () => finish(false),
5329
+ close,
5330
+ add: (late) => {
5331
+ if (finished) return;
5332
+ for (let i2 = 0; i2 < late.length; i2++) {
5333
+ const el = late[i2];
5334
+ if (elements.includes(el) || insideAnimating(animating, el)) continue;
5335
+ el.classList.add(cls);
5336
+ elements.push(el);
5337
+ const total = enroll(el);
5338
+ if (total >= 0) arm(now() + total + SLACK_MS);
5339
+ }
5340
+ }
5341
+ };
5342
+ }
5343
+
4411
5344
  // src/core/rendering/directives.ts
4412
5345
  function show(condition, element) {
4413
5346
  const resolved = typeof element === "function" ? element() : element;
@@ -4420,9 +5353,15 @@ function show(condition, element) {
4420
5353
  function isDirectiveOptions(value) {
4421
5354
  return typeof value === "object" && value !== null && !(value instanceof Node);
4422
5355
  }
4423
- function attachBranch(parent, anchor, branch, attachedOnce, where) {
5356
+ var fragmentStarts = /* @__PURE__ */ new WeakMap();
5357
+ var detachedRanges = /* @__PURE__ */ new WeakMap();
5358
+ var parked = /* @__PURE__ */ new WeakMap();
5359
+ var ENTER_WAIT_TURNS = 8;
5360
+ var NOOP4 = () => {
5361
+ };
5362
+ function resolveBranch(branch, attachedOnce, where) {
4424
5363
  const result = typeof branch === "function" ? branch() : branch;
4425
- if (result == null || typeof result === "boolean") return { node: null, owned: false };
5364
+ if (result == null || typeof result === "boolean") return null;
4426
5365
  const node = result instanceof Node ? result : document.createTextNode(String(result));
4427
5366
  const handedIn = node === branch;
4428
5367
  const seenBefore = attachedOnce.has(node);
@@ -4433,64 +5372,603 @@ function attachBranch(parent, anchor, branch, attachedOnce, where) {
4433
5372
  () => `${where}: ${handedIn ? "a branch was given as an element rather than a function" : "a branch factory returned a node it had already returned"}, so the SAME node is being re-attached \u2014 any state it accumulated while detached (input value, scroll position, classes set imperatively) comes back with it. Its reactive bindings are left intact rather than disposed, because the node is not this directive's to tear down. Return a FRESH node per call (\`() => div(\u2026)\`) for rebuild semantics, or keep this form deliberately when the reuse is what you want.`
4434
5373
  );
4435
5374
  }
4436
- if (anchor.nextSibling !== node) parent.insertBefore(node, anchor.nextSibling);
4437
- return { node, owned };
5375
+ let starts;
5376
+ if (node.nodeType === 11) {
5377
+ if (node.firstChild) {
5378
+ starts = Array.from(node.childNodes);
5379
+ fragmentStarts.set(node, starts);
5380
+ } else {
5381
+ starts = fragmentStarts.get(node) ?? [];
5382
+ }
5383
+ } else {
5384
+ starts = [node];
5385
+ }
5386
+ const park = owned ? void 0 : parked.get(node);
5387
+ const nodes = park?.firstChild ? Array.from(park.childNodes) : !owned && starts.every((start) => start.parentNode === null) && detachedRanges.get(node) || attachedRanges(starts);
5388
+ if (nodes.length === 0 && !owned) return null;
5389
+ return {
5390
+ source: node,
5391
+ starts,
5392
+ nodes,
5393
+ owned,
5394
+ owner: null,
5395
+ phase: null,
5396
+ restore: null,
5397
+ unhold: null,
5398
+ waiting: false,
5399
+ released: false,
5400
+ inserting: false
5401
+ };
4438
5402
  }
4439
- function releaseBranchNode(node, owned) {
4440
- if (owned) dispose(node);
4441
- node.parentNode?.removeChild(node);
5403
+ function attachedRanges(starts) {
5404
+ if (!starts.some(hasRange)) return starts;
5405
+ return [...new Set(starts.flatMap((start) => start.parentNode === null ? [start] : collectRange([start])))];
4442
5406
  }
4443
- function when(condition, thenBranch, elseBranch, options) {
4444
- requireDocument();
4445
- if (isDirectiveOptions(elseBranch)) {
4446
- options = elseBranch;
4447
- elseBranch = void 0;
5407
+ function refreshNodes(branch) {
5408
+ const starts = branch.starts;
5409
+ if (starts.length === 1 && (!hasRange(starts[0]) || starts[0].parentNode === null)) return;
5410
+ const live = collectRange(starts);
5411
+ branch.nodes = branch.owned && branch.inserting ? [.../* @__PURE__ */ new Set([...branch.nodes, ...live])] : live;
5412
+ if (!branch.owned) detachedRanges.set(branch.source, branch.nodes);
5413
+ }
5414
+ function insertBranch(anchor, nodes, live) {
5415
+ let prev = anchor;
5416
+ for (let i2 = 0; i2 < nodes.length; i2++) {
5417
+ if (!live()) return false;
5418
+ const parent = anchor.parentNode;
5419
+ if (parent === null) return false;
5420
+ const node = nodes[i2];
5421
+ if (prev.parentNode !== parent) prev = anchor;
5422
+ if (prev.nextSibling !== node) parent.insertBefore(node, prev.nextSibling);
5423
+ prev = node;
5424
+ }
5425
+ return live();
5426
+ }
5427
+ function releaseBranch(branch) {
5428
+ if (branch.released) return;
5429
+ branch.released = true;
5430
+ refreshNodes(branch);
5431
+ if (branch.phase !== null) {
5432
+ branch.phase.cancel();
5433
+ branch.phase = null;
5434
+ }
5435
+ if (branch.restore !== null) {
5436
+ branch.restore();
5437
+ branch.restore = null;
5438
+ }
5439
+ const nodes = branch.nodes;
5440
+ let park;
5441
+ if (!branch.owned && (branch.source.nodeType === 11 || branch.starts.some(hasRange))) {
5442
+ park = parked.get(branch.source);
5443
+ if (park === void 0) parked.set(branch.source, park = document.createDocumentFragment());
4448
5444
  }
4449
- const elseNode = elseBranch;
5445
+ for (let i2 = 0; i2 < nodes.length; i2++) {
5446
+ const node = nodes[i2];
5447
+ if (branch.owned) dispose(node);
5448
+ if (park !== void 0) park.appendChild(node);
5449
+ else node.parentNode?.removeChild(node);
5450
+ }
5451
+ if (branch.owned && branch.source.nodeType === 11) dispose(branch.source);
5452
+ if (branch.owner !== null) {
5453
+ if (branch.owned) branch.owner.stop();
5454
+ else branch.owner.thaw?.();
5455
+ branch.owner = null;
5456
+ }
5457
+ if (branch.unhold !== null) {
5458
+ branch.unhold();
5459
+ branch.unhold = null;
5460
+ }
5461
+ }
5462
+ function makeInert(branch, onLate) {
5463
+ const saved = [];
5464
+ const marked = /* @__PURE__ */ new Set();
5465
+ const mark2 = (nodes) => {
5466
+ for (let i2 = 0; i2 < nodes.length; i2++) {
5467
+ if (nodes[i2].nodeType !== 1 || marked.has(nodes[i2])) continue;
5468
+ const el = nodes[i2];
5469
+ marked.add(el);
5470
+ saved.push([el, el.getAttribute("inert"), el.getAttribute("aria-hidden")]);
5471
+ el.setAttribute("inert", "");
5472
+ el.setAttribute("aria-hidden", "true");
5473
+ }
5474
+ };
5475
+ const active = typeof document !== "undefined" ? document.activeElement : null;
5476
+ mark2(branch.nodes);
5477
+ const initial = saved.length;
5478
+ for (let i2 = 0; i2 < initial; i2++) {
5479
+ const el = saved[i2][0];
5480
+ if (active && (el === active || el.contains(active))) {
5481
+ active.blur?.();
5482
+ break;
5483
+ }
5484
+ }
5485
+ const unwatch = watchRange(branch, (late) => {
5486
+ const before = saved.length;
5487
+ mark2(late);
5488
+ if (saved.length > before) onLate(saved.slice(before).map((entry) => entry[0]));
5489
+ });
5490
+ return () => {
5491
+ unwatch();
5492
+ for (let i2 = 0; i2 < saved.length; i2++) {
5493
+ const [el, inert, hidden] = saved[i2];
5494
+ if (inert === null) el.removeAttribute("inert");
5495
+ else el.setAttribute("inert", inert);
5496
+ if (hidden === null) el.removeAttribute("aria-hidden");
5497
+ else el.setAttribute("aria-hidden", hidden);
5498
+ }
5499
+ };
5500
+ }
5501
+ function watchRange(branch, onLate) {
5502
+ const parent = branch.nodes[0]?.parentNode;
5503
+ if (!parent || typeof MutationObserver !== "function" || !branch.starts.some(hasRange)) return NOOP4;
5504
+ const seen = new Set(branch.nodes);
5505
+ const observer = new MutationObserver(() => {
5506
+ refreshNodes(branch);
5507
+ const late = [];
5508
+ for (const node of branch.nodes) {
5509
+ if (seen.has(node)) continue;
5510
+ seen.add(node);
5511
+ if (node.nodeType === 1) late.push(node);
5512
+ }
5513
+ if (late.length > 0) onLate(late);
5514
+ });
5515
+ observer.observe(parent, { childList: true });
5516
+ return () => observer.disconnect();
5517
+ }
5518
+ function readyWindow(ms) {
5519
+ const endAt = now() + ms;
5520
+ const win = {
5521
+ expired: false,
5522
+ remaining: () => win.expired ? 0 : Math.max(0, Math.min(ms, endAt - now())),
5523
+ onExpire: null,
5524
+ stop: () => {
5525
+ clearTimeout(timer);
5526
+ win.onExpire = null;
5527
+ }
5528
+ };
5529
+ const timer = setTimeout(() => {
5530
+ win.expired = true;
5531
+ const expire = win.onExpire;
5532
+ win.onExpire = null;
5533
+ expire?.();
5534
+ }, ms);
5535
+ return win;
5536
+ }
5537
+ function watchMembership(branch, onChange) {
5538
+ if (typeof MutationObserver !== "function") return null;
5539
+ const observer = new MutationObserver(onChange);
5540
+ const watched = /* @__PURE__ */ new Set();
5541
+ const refresh = () => {
5542
+ const parent = branch.nodes[0]?.parentNode;
5543
+ if (parent && !watched.has(parent)) {
5544
+ watched.add(parent);
5545
+ observer.observe(parent, { childList: true });
5546
+ }
5547
+ for (const node of branch.nodes) {
5548
+ if (node.nodeType !== 1 || watched.has(node)) continue;
5549
+ watched.add(node);
5550
+ observer.observe(node, { childList: true, subtree: true });
5551
+ }
5552
+ };
5553
+ refresh();
5554
+ return {
5555
+ refresh,
5556
+ stop: () => {
5557
+ observer.disconnect();
5558
+ watched.clear();
5559
+ }
5560
+ };
5561
+ }
5562
+ function directive(name, read, pick, options) {
4450
5563
  const focusPolicy = options?.focus;
4451
- const anchor = document.createComment("when");
5564
+ const tr2 = options?.transition !== void 0 && !isServer() ? options.transition : void 0;
5565
+ const anchor = document.createComment(name);
4452
5566
  const scope = captureScope();
4453
- let currentNode = null;
4454
- let lastCondition;
5567
+ const frozen = captureFrozen2();
5568
+ let current2 = null;
5569
+ let last;
4455
5570
  let initialized = false;
4456
5571
  let disposed = false;
4457
5572
  const attachedOnce = /* @__PURE__ */ new WeakSet();
4458
- let currentNodeOwned = false;
5573
+ const leaving = [];
5574
+ let deferred = false;
5575
+ let deferredFocus = null;
5576
+ let dropDeferredWait = NOOP4;
5577
+ const build = (branch, owns) => {
5578
+ const owner = structuralBinding2(NOOP4, anchor);
5579
+ const inBranch = (fn) => owner.run(() => untracked2(() => inScope(scope, fn)));
5580
+ let built;
5581
+ try {
5582
+ built = inBranch(() => resolveBranch(branch, attachedOnce, name));
5583
+ } catch (err) {
5584
+ owner.stop();
5585
+ throw err;
5586
+ }
5587
+ if (built === null) {
5588
+ owner.stop();
5589
+ return null;
5590
+ }
5591
+ const ownsOwner = built.owned;
5592
+ if (ownsOwner) built.owner = owner;
5593
+ if (disposed || !owns() || current2 !== null) {
5594
+ releaseBranch(built);
5595
+ if (!ownsOwner) owner.stop();
5596
+ return null;
5597
+ }
5598
+ let reclaimed = null;
5599
+ if (tr2) {
5600
+ for (let i2 = 0; i2 < leaving.length; i2++) {
5601
+ if (leaving[i2].source !== built.source) continue;
5602
+ reclaimed = leaving.splice(i2, 1)[0];
5603
+ built.owner = reclaimed.owner;
5604
+ reclaimed.owner = null;
5605
+ break;
5606
+ }
5607
+ }
5608
+ current2 = built;
5609
+ built.inserting = true;
5610
+ let complete = false;
5611
+ try {
5612
+ if (reclaimed !== null) {
5613
+ const prev = reclaimed;
5614
+ if (prev.phase !== null) prev.phase.cancel();
5615
+ prev.phase = null;
5616
+ if (prev.restore !== null) prev.restore();
5617
+ prev.restore = null;
5618
+ const unhold = prev.unhold;
5619
+ prev.unhold = null;
5620
+ built.owner?.thaw?.();
5621
+ unhold?.();
5622
+ if (!built.released) refreshNodes(built);
5623
+ }
5624
+ const live = () => !disposed && owns() && current2 === built && !built.released;
5625
+ complete = live() && inBranch(() => insertBranch(anchor, built.nodes, live));
5626
+ } catch (err) {
5627
+ built.inserting = false;
5628
+ if (current2 === built) current2 = null;
5629
+ releaseBranch(built);
5630
+ if (!ownsOwner) owner.stop();
5631
+ throw err;
5632
+ }
5633
+ built.inserting = false;
5634
+ if (complete) inBranch(() => resumePending(built.nodes));
5635
+ if (!ownsOwner) owner.stop();
5636
+ return current2 === built && !built.released && owns() ? built : null;
5637
+ };
5638
+ const playPhase = (branch, start, onEnd, onCancel = NOOP4) => {
5639
+ let valid = true;
5640
+ let run = null;
5641
+ const invalidate = () => {
5642
+ if (!valid) return;
5643
+ valid = false;
5644
+ onCancel();
5645
+ };
5646
+ const handle = {
5647
+ cancel: () => {
5648
+ invalidate();
5649
+ run?.cancel();
5650
+ }
5651
+ };
5652
+ branch.phase = handle;
5653
+ run = start(() => {
5654
+ if (!valid || branch.phase !== handle) return;
5655
+ valid = false;
5656
+ branch.phase = null;
5657
+ onEnd();
5658
+ });
5659
+ if (valid && branch.phase === handle && !branch.released && !disposed && run !== null) {
5660
+ handle.add = run.add;
5661
+ handle.close = run.close;
5662
+ return handle;
5663
+ }
5664
+ invalidate();
5665
+ if (branch.phase === handle) branch.phase = null;
5666
+ run?.cancel();
5667
+ return null;
5668
+ };
5669
+ const startLeave = (branch) => {
5670
+ branch.waiting = false;
5671
+ if (branch.released || disposed) return;
5672
+ const t = tr2;
5673
+ playPhase(
5674
+ branch,
5675
+ (done) => runPhase(branch.nodes, t.leaveClass, t.leave, t.maxDuration, done, `${name}(leave)`),
5676
+ () => finishLeave(branch)
5677
+ );
5678
+ };
5679
+ const startWaitingLeaves = () => {
5680
+ for (const branch of [...leaving]) {
5681
+ if (disposed) return;
5682
+ if (branch.waiting) startLeave(branch);
5683
+ }
5684
+ };
5685
+ const beginLeave = (branch) => {
5686
+ if (branch.released) return;
5687
+ const t = tr2;
5688
+ if (branch.phase !== null) {
5689
+ branch.phase.cancel();
5690
+ branch.phase = null;
5691
+ }
5692
+ refreshNodes(branch);
5693
+ if (branch.owner !== null) {
5694
+ branch.owner.freeze?.();
5695
+ branch.unhold = holdSubtree2({
5696
+ contains: (node) => branch.nodes.some((n) => n === node || n.contains(node))
5697
+ });
5698
+ }
5699
+ const restore = makeInert(branch, (late) => branch.phase?.add?.(late));
5700
+ if (branch.released) {
5701
+ restore();
5702
+ return;
5703
+ }
5704
+ branch.restore = restore;
5705
+ if (t.mode === "in-out") {
5706
+ startWaitingLeaves();
5707
+ branch.waiting = true;
5708
+ leaving.push(branch);
5709
+ return;
5710
+ }
5711
+ leaving.push(branch);
5712
+ startLeave(branch);
5713
+ };
5714
+ const finishLeave = (branch) => {
5715
+ const index = leaving.indexOf(branch);
5716
+ if (index !== -1) leaving.splice(index, 1);
5717
+ releaseBranch(branch);
5718
+ if (deferred && leaving.length === 0 && !disposed) buildDeferred();
5719
+ };
5720
+ const afterInsert = (first, superseded) => {
5721
+ if (superseded()) return;
5722
+ const t = tr2;
5723
+ const entering = current2;
5724
+ if (entering !== null && (!first || t.appear === true)) {
5725
+ enterWhenReady(entering);
5726
+ if (superseded()) return;
5727
+ if (entering.phase !== null) return;
5728
+ }
5729
+ if (t.mode === "in-out") startWaitingLeaves();
5730
+ };
5731
+ const enterWhenReady = (entering) => {
5732
+ const t = tr2;
5733
+ const budget = typeof t.waitForContent === "number" && t.waitForContent > 0 ? t.waitForContent : 0;
5734
+ const ready = budget > 0 ? readyWindow(Math.min(budget, HARD_CAP_MS)) : null;
5735
+ const contentReady = () => t.enter === void 0 || ready === null || ready.expired || loadingWithin(entering.nodes, entering.owner).length === 0;
5736
+ if (!frozen() && !anyPending(entering.nodes) && contentReady()) {
5737
+ startEnter(entering, ready);
5738
+ return;
5739
+ }
5740
+ let cancelled = false;
5741
+ let waiting = false;
5742
+ let dropWait = NOOP4;
5743
+ let dropLoaded = NOOP4;
5744
+ let membership = null;
5745
+ let turns = 0;
5746
+ const stopWaiting = () => {
5747
+ dropWait();
5748
+ dropWait = NOOP4;
5749
+ dropLoaded();
5750
+ dropLoaded = NOOP4;
5751
+ membership?.stop();
5752
+ membership = null;
5753
+ if (ready !== null) ready.onExpire = null;
5754
+ };
5755
+ const placeholder = {
5756
+ cancel: () => {
5757
+ cancelled = true;
5758
+ stopWaiting();
5759
+ ready?.stop();
5760
+ }
5761
+ };
5762
+ entering.phase = placeholder;
5763
+ const step = () => {
5764
+ if (cancelled || disposed || current2 !== entering || entering.phase !== placeholder) return;
5765
+ if (frozen()) {
5766
+ dropWait();
5767
+ dropWait = frozen.wait(step, NOOP4);
5768
+ return;
5769
+ }
5770
+ refreshNodes(entering);
5771
+ if (anyPending(entering.nodes) && ++turns < ENTER_WAIT_TURNS) {
5772
+ queueMicrotask(step);
5773
+ return;
5774
+ }
5775
+ if (!contentReady()) {
5776
+ if (!waiting) {
5777
+ waiting = true;
5778
+ dropLoaded = onLoaded(() => {
5779
+ turns = 0;
5780
+ step();
5781
+ });
5782
+ membership = watchMembership(entering, step);
5783
+ ready.onExpire = step;
5784
+ } else membership?.refresh();
5785
+ return;
5786
+ }
5787
+ stopWaiting();
5788
+ entering.phase = null;
5789
+ startEnter(entering, ready);
5790
+ };
5791
+ if (frozen()) step();
5792
+ else queueMicrotask(step);
5793
+ };
5794
+ const startEnter = (entering, ready) => {
5795
+ const t = tr2;
5796
+ const open = t.enter === void 0 && ready !== null && !ready.expired ? ready.remaining() : 0;
5797
+ const waitingFor = open > 0 ? loadingWithin(entering.nodes, entering.owner) : [];
5798
+ if (waitingFor.length === 0) ready?.stop();
5799
+ let stopWatching = NOOP4;
5800
+ const run = playPhase(
5801
+ entering,
5802
+ (done) => runPhase(
5803
+ entering.nodes,
5804
+ t.enterClass,
5805
+ t.enter,
5806
+ t.maxDuration,
5807
+ done,
5808
+ `${name}(enter)`,
5809
+ waitingFor.length > 0 ? open : 0
5810
+ ),
5811
+ () => {
5812
+ stopWatching();
5813
+ if (t.mode === "in-out" && !disposed) startWaitingLeaves();
5814
+ },
5815
+ () => stopWatching()
5816
+ );
5817
+ const add = run?.add;
5818
+ if (run === null || add === void 0) {
5819
+ ready?.stop();
5820
+ return;
5821
+ }
5822
+ const unwatch = watchRange(entering, add);
5823
+ let dropLoaded = NOOP4;
5824
+ let membership = null;
5825
+ const stopLoading = () => {
5826
+ dropLoaded();
5827
+ dropLoaded = NOOP4;
5828
+ membership?.stop();
5829
+ membership = null;
5830
+ ready?.stop();
5831
+ };
5832
+ if (waitingFor.length > 0) {
5833
+ const win = ready;
5834
+ const reconcile = (settled) => {
5835
+ if (win.expired || dropLoaded === NOOP4) {
5836
+ stopLoading();
5837
+ return;
5838
+ }
5839
+ refreshNodes(entering);
5840
+ const inBranch = (el) => entering.nodes.some((n) => n === el || n.contains(el));
5841
+ for (const entry of settled) {
5842
+ if (entry.cancelled || !pendingWithin(entry, entering.nodes, entering.owner)) continue;
5843
+ const content = settledContent(entry).filter(inBranch);
5844
+ if (content.length > 0) add(content);
5845
+ }
5846
+ if (loadingWithin(entering.nodes, entering.owner).length === 0) {
5847
+ stopLoading();
5848
+ run.close?.();
5849
+ } else membership?.refresh();
5850
+ };
5851
+ dropLoaded = onLoaded(reconcile);
5852
+ membership = watchMembership(entering, () => reconcile(settledSinceNotify()));
5853
+ win.onExpire = stopLoading;
5854
+ }
5855
+ stopWatching = () => {
5856
+ unwatch();
5857
+ stopLoading();
5858
+ };
5859
+ };
5860
+ const buildDeferred = bindOwnerScope2(() => {
5861
+ if (disposed || !deferred) return;
5862
+ if (frozen()) {
5863
+ dropDeferredWait();
5864
+ dropDeferredWait = frozen.wait(() => {
5865
+ dropDeferredWait = NOOP4;
5866
+ if (deferred && !disposed) buildDeferred();
5867
+ }, NOOP4);
5868
+ return;
5869
+ }
5870
+ deferred = false;
5871
+ const focused = deferredFocus;
5872
+ deferredFocus = null;
5873
+ const gen = deferredGen;
5874
+ const superseded = () => disposed || gen !== generation;
5875
+ if (superseded() || !anchor.parentNode || current2 !== null) return;
5876
+ let built;
5877
+ try {
5878
+ built = binding.run(() => build(pick(last), () => !superseded()));
5879
+ } catch (err) {
5880
+ reportError(err, { phase: "render", name, node: anchor });
5881
+ return;
5882
+ }
5883
+ if (superseded()) return;
5884
+ restoreFocusWithin(focused, built !== null ? built.nodes : [], name, focusPolicy);
5885
+ afterInsert(false, superseded);
5886
+ });
5887
+ let generation = 0;
5888
+ let deferredGen = 0;
4459
5889
  const update = () => {
4460
5890
  if (disposed) return;
4461
- const show2 = condition();
4462
- const parent = anchor.parentNode;
4463
- if (!parent) return;
4464
- if (initialized && Object.is(show2, lastCondition)) return;
4465
- lastCondition = show2;
4466
- const focused = currentNode ? captureFocusWithin([currentNode]) : null;
4467
- if (currentNode?.parentNode) {
4468
- releaseBranchNode(currentNode, currentNodeOwned);
4469
- currentNode = null;
4470
- }
4471
- const branch = show2 ? thenBranch : elseNode !== void 0 ? elseNode : null;
4472
- const attached = untracked2(() => inScope(scope, () => attachBranch(parent, anchor, branch, attachedOnce, "when")));
4473
- currentNode = attached.node;
4474
- currentNodeOwned = attached.owned;
4475
- restoreFocusWithin(focused, currentNode ? [currentNode] : [], "when", focusPolicy);
5891
+ const value = read();
5892
+ if (!anchor.parentNode) return;
5893
+ if (initialized && Object.is(value, last)) return;
5894
+ last = value;
5895
+ const first = !initialized;
4476
5896
  initialized = true;
5897
+ const gen = ++generation;
5898
+ const superseded = () => disposed || gen !== generation;
5899
+ if (current2 !== null) refreshNodes(current2);
5900
+ const focused = current2 !== null ? captureFocusWithin(current2.nodes) : null;
5901
+ if (current2 !== null) {
5902
+ const outgoing = current2;
5903
+ if (tr2) beginLeave(outgoing);
5904
+ else releaseBranch(outgoing);
5905
+ if (current2 === outgoing) current2 = null;
5906
+ if (superseded()) return;
5907
+ }
5908
+ const branch = pick(value);
5909
+ if (tr2?.mode === "out-in" && leaving.length > 0) {
5910
+ let reclaim = false;
5911
+ for (let i2 = 0; i2 < leaving.length && !reclaim; i2++) reclaim = leaving[i2].source === branch;
5912
+ if (!reclaim) {
5913
+ deferred = true;
5914
+ deferredGen = gen;
5915
+ deferredFocus ?? (deferredFocus = focused);
5916
+ return;
5917
+ }
5918
+ }
5919
+ deferred = false;
5920
+ build(branch, () => !superseded());
5921
+ if (superseded()) return;
5922
+ restoreFocusWithin(focused, current2 !== null ? current2.nodes : [], name, focusPolicy);
5923
+ if (tr2) afterInsert(first, superseded);
4477
5924
  };
4478
5925
  const binding = structuralBinding2(update, anchor);
5926
+ registerRange(anchor, () => {
5927
+ for (let i2 = 0; i2 <= leaving.length; i2++) {
5928
+ const branch = i2 < leaving.length ? leaving[i2] : current2;
5929
+ if (branch === null) break;
5930
+ const nodes = collectRange(branch.starts);
5931
+ if (nodes.length > 0) return nodes[nodes.length - 1];
5932
+ }
5933
+ return null;
5934
+ });
4479
5935
  registerDisposer(anchor, () => {
4480
5936
  disposed = true;
5937
+ deferred = false;
5938
+ deferredFocus = null;
5939
+ dropDeferredWait();
5940
+ dropDeferredWait = NOOP4;
4481
5941
  binding.stop();
4482
- if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
4483
- currentNode = null;
5942
+ if (current2 !== null) releaseBranch(current2);
5943
+ current2 = null;
5944
+ const rest = leaving.splice(0);
5945
+ for (let i2 = 0; i2 < rest.length; i2++) releaseBranch(rest[i2]);
4484
5946
  });
4485
5947
  if (!initialized) {
4486
- queueMicrotask(
5948
+ queueFirstRender(
5949
+ anchor,
4487
5950
  bindOwnerScope2(() => {
4488
5951
  if (!disposed && !initialized && anchor.parentNode) binding.run(update);
4489
- })
5952
+ }),
5953
+ frozen
4490
5954
  );
4491
5955
  }
4492
5956
  return anchor;
4493
5957
  }
5958
+ function when(condition, thenBranch, elseBranch, options) {
5959
+ requireDocument();
5960
+ if (isDirectiveOptions(elseBranch)) {
5961
+ options = elseBranch;
5962
+ elseBranch = void 0;
5963
+ }
5964
+ const elseNode = elseBranch;
5965
+ return directive(
5966
+ "when",
5967
+ condition,
5968
+ (show2) => show2 ? thenBranch : elseNode !== void 0 ? elseNode : null,
5969
+ options
5970
+ );
5971
+ }
4494
5972
  function match(value, cases, fallback, options) {
4495
5973
  requireDocument();
4496
5974
  if (isDirectiveOptions(fallback)) {
@@ -4498,51 +5976,14 @@ function match(value, cases, fallback, options) {
4498
5976
  fallback = void 0;
4499
5977
  }
4500
5978
  const fallbackNode = fallback;
4501
- const focusPolicy = options?.focus;
4502
- const anchor = document.createComment("match");
4503
- const scope = captureScope();
4504
- let currentNode = null;
4505
- let lastKey;
4506
- let initialized = false;
4507
- let disposed = false;
4508
- const attachedOnce = /* @__PURE__ */ new WeakSet();
4509
- let currentNodeOwned = false;
4510
- const update = () => {
4511
- if (disposed) return;
4512
- const key = String(value());
4513
- const parent = anchor.parentNode;
4514
- if (!parent) return;
4515
- if (initialized && key === lastKey) return;
4516
- lastKey = key;
4517
- const focused = currentNode ? captureFocusWithin([currentNode]) : null;
4518
- if (currentNode?.parentNode) {
4519
- releaseBranchNode(currentNode, currentNodeOwned);
4520
- currentNode = null;
4521
- }
4522
- const branch = Object.hasOwn(cases, key) ? cases[key] : fallbackNode;
4523
- const attached = untracked2(
4524
- () => inScope(scope, () => attachBranch(parent, anchor, branch ?? null, attachedOnce, "match"))
4525
- );
4526
- currentNode = attached.node;
4527
- currentNodeOwned = attached.owned;
4528
- restoreFocusWithin(focused, currentNode ? [currentNode] : [], "match", focusPolicy);
4529
- initialized = true;
4530
- };
4531
- const binding = structuralBinding2(update, anchor);
4532
- registerDisposer(anchor, () => {
4533
- disposed = true;
4534
- binding.stop();
4535
- if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
4536
- currentNode = null;
4537
- });
4538
- if (!initialized) {
4539
- queueMicrotask(
4540
- bindOwnerScope2(() => {
4541
- if (!disposed && !initialized && anchor.parentNode) binding.run(update);
4542
- })
4543
- );
4544
- }
4545
- return anchor;
5979
+ return directive(
5980
+ "match",
5981
+ () => String(value()),
5982
+ // `Object.hasOwn` rather than `||` so a case whose value is legitimately
5983
+ // falsy (an empty string, 0) still wins over the fallback.
5984
+ (key) => Object.hasOwn(cases, key) ? cases[key] : fallbackNode ?? null,
5985
+ options
5986
+ );
4546
5987
  }
4547
5988
 
4548
5989
  // src/core/rendering/clientOnly.ts
@@ -4615,12 +6056,6 @@ function __resetIdCounter() {
4615
6056
  _counter.n = 0;
4616
6057
  }
4617
6058
 
4618
- // src/utils/globalSingleton.ts
4619
- function globalSingleton(key, create) {
4620
- const g2 = globalThis;
4621
- return g2[key] ?? (g2[key] = create());
4622
- }
4623
-
4624
6059
  // src/core/rendering/dynamic.ts
4625
6060
  var componentRegistry = globalSingleton(
4626
6061
  /* @__PURE__ */ Symbol.for("sibujs.components.registry.v1"),
@@ -4707,6 +6142,14 @@ function longestIncreasingSubsequence(arr, len) {
4707
6142
  }
4708
6143
  return result;
4709
6144
  }
6145
+ var renderingRow = null;
6146
+ var warnedReadSites = /* @__PURE__ */ new Set();
6147
+ function withPeek(get) {
6148
+ const state4 = get.__signal;
6149
+ const cell = get;
6150
+ cell.peek = () => state4.value;
6151
+ return cell;
6152
+ }
4710
6153
  function each(getArray, render, options) {
4711
6154
  devAssert(typeof getArray === "function", "each: first argument must be a function that returns an array.");
4712
6155
  devAssert(typeof render === "function", "each: second argument must be a render function.");
@@ -4785,13 +6228,40 @@ function each(getArray, render, options) {
4785
6228
  } else {
4786
6229
  const [itemGetter, setItem] = signal(arr[i2]);
4787
6230
  const [indexGetter, setIndex] = signal(i2);
6231
+ const item = withPeek(itemGetter);
6232
+ const index = withPeek(indexGetter);
6233
+ let reads = null;
6234
+ let renderItem = item;
6235
+ let renderIndex = index;
6236
+ let outerRow = null;
6237
+ devWarnLazy(() => {
6238
+ const rowReads = { item: null, index: null };
6239
+ const recording = (get, slot4) => {
6240
+ const read = (() => {
6241
+ if (renderingRow === rowReads && rowReads[slot4] === null && isTrackingSuspended2()) {
6242
+ rowReads[slot4] = new Error();
6243
+ }
6244
+ return get();
6245
+ });
6246
+ read.peek = get.peek;
6247
+ read.__signal = get.__signal;
6248
+ return read;
6249
+ };
6250
+ reads = rowReads;
6251
+ renderItem = recording(item, "item");
6252
+ renderIndex = recording(index, "index");
6253
+ return "";
6254
+ });
4788
6255
  let node;
4789
6256
  try {
4790
6257
  suspendTracking2();
6258
+ outerRow = renderingRow;
6259
+ renderingRow = reads;
4791
6260
  try {
4792
- node = resolveNodeChild(inScope(keyedScope(scope, key), () => render(itemGetter, indexGetter)));
6261
+ node = resolveNodeChild(inScope(keyedScope(scope, key), () => render(renderItem, renderIndex)));
4793
6262
  } finally {
4794
6263
  resumeTracking2();
6264
+ renderingRow = outerRow;
4795
6265
  }
4796
6266
  } catch (err) {
4797
6267
  const key2 = newKeys[i2];
@@ -4804,7 +6274,7 @@ function each(getArray, render, options) {
4804
6274
  });
4805
6275
  });
4806
6276
  }
4807
- row = { node, item: itemGetter, setItem, index: indexGetter, setIndex };
6277
+ row = { node, item, setItem, index, setIndex, reads };
4808
6278
  }
4809
6279
  workMap.set(key, row);
4810
6280
  newNodes[i2] = row.node;
@@ -4882,6 +6352,7 @@ function each(getArray, render, options) {
4882
6352
  batch(() => {
4883
6353
  for (let i2 = 0; i2 < count; i2++) {
4884
6354
  const row = pendingRows[i2];
6355
+ if (row.reads !== null) warnStaleRead(row, pendingItems[i2], pendingIndices[i2]);
4885
6356
  row.setItem(pendingItems[i2]);
4886
6357
  row.setIndex(pendingIndices[i2]);
4887
6358
  pendingRows[i2] = void 0;
@@ -4889,7 +6360,29 @@ function each(getArray, render, options) {
4889
6360
  }
4890
6361
  });
4891
6362
  }
4892
- const binding = structuralBinding2(update);
6363
+ function warnStaleRead(row, nextItem, nextIndex) {
6364
+ devWarnLazy(() => {
6365
+ const reads = row.reads;
6366
+ let site = null;
6367
+ let which = "";
6368
+ if (reads.item !== null && !Object.is(row.item.peek(), nextItem)) {
6369
+ site = reads.item;
6370
+ which = "item";
6371
+ reads.item = null;
6372
+ } else if (reads.index !== null && row.index.peek() !== nextIndex) {
6373
+ site = reads.index;
6374
+ which = "index";
6375
+ reads.index = null;
6376
+ }
6377
+ if (site === null) return "";
6378
+ const frames = (site.stack ?? "").split("\n").filter((line2) => /^\s*at\s|@/.test(line2));
6379
+ const at = (frames[1] ?? frames[0] ?? "").trim().replace(/^at\s+/, "") || "unknown location";
6380
+ if (warnedReadSites.has(at)) return "";
6381
+ if (warnedReadSites.size < 100) warnedReadSites.add(at);
6382
+ return `each(): the row for key "${String(keyFn(nextItem))}" read ${which}() directly while rendering, so it will not show the new value. Read it inside a binding (\`() => ${which}().x\`) or an effect, or include the changing field in the key. For an intentional one-time read, use ${which}.peek(). (render at ${at})`;
6383
+ });
6384
+ }
6385
+ const binding = structuralBinding2(update, anchor);
4893
6386
  const untrack = binding.stop;
4894
6387
  const disposeRange = () => {
4895
6388
  if (rangeDisposed) return;
@@ -4912,13 +6405,15 @@ function each(getArray, render, options) {
4912
6405
  pendingCount = 0;
4913
6406
  };
4914
6407
  registerDisposer(anchor, disposeRange);
6408
+ registerRange(anchor, () => sentinelInserted ? end : null);
4915
6409
  if (!initialized) {
4916
- queueMicrotask(
6410
+ const frozen = captureFrozen2();
6411
+ queueFirstRender(
6412
+ anchor,
4917
6413
  bindOwnerScope2(() => {
4918
- if (!initialized && !rangeDisposed && anchor.parentNode) {
4919
- binding.run(update);
4920
- }
4921
- })
6414
+ if (!initialized && !rangeDisposed && anchor.parentNode) binding.run(update);
6415
+ }),
6416
+ frozen
4922
6417
  );
4923
6418
  }
4924
6419
  return anchor;
@@ -4962,7 +6457,7 @@ function appendChild(frag, child) {
4962
6457
  if (typeof child === "function") {
4963
6458
  const placeholder = document.createComment("");
4964
6459
  frag.appendChild(placeholder);
4965
- registerDisposer(placeholder, bindChildNode(placeholder, child));
6460
+ registerDisposer(placeholder, bindChildNode(placeholder, child, true));
4966
6461
  return;
4967
6462
  }
4968
6463
  frag.appendChild(document.createTextNode(String(child)));
@@ -5008,7 +6503,7 @@ var SVG_TAGS = /* @__PURE__ */ new Set([
5008
6503
  "symbol",
5009
6504
  "marker"
5010
6505
  ]);
5011
- var cache = /* @__PURE__ */ new WeakMap();
6506
+ var cache2 = /* @__PURE__ */ new WeakMap();
5012
6507
  function parseTemplate(strings) {
5013
6508
  const exprCount = strings.length - 1;
5014
6509
  let template2 = strings[0];
@@ -5295,10 +6790,10 @@ function executeElement(tmpl, values) {
5295
6790
  return el;
5296
6791
  }
5297
6792
  function html2(strings, ...values) {
5298
- let tmpl = cache.get(strings);
6793
+ let tmpl = cache2.get(strings);
5299
6794
  if (!tmpl) {
5300
6795
  tmpl = parseTemplate(strings);
5301
- cache.set(strings, tmpl);
6796
+ cache2.set(strings, tmpl);
5302
6797
  }
5303
6798
  return renderTemplate(tmpl, values);
5304
6799
  }
@@ -5354,7 +6849,7 @@ function renderTemplate(tmpl, values) {
5354
6849
  function KeepAlive(activeKey, cases, options) {
5355
6850
  requireDocument();
5356
6851
  const anchor = document.createComment("keep-alive");
5357
- const cache2 = /* @__PURE__ */ new Map();
6852
+ const cache3 = /* @__PURE__ */ new Map();
5358
6853
  const lruOrder = [];
5359
6854
  const max = options?.max ?? 10;
5360
6855
  if (max === 0 && isDev()) {
@@ -5374,7 +6869,7 @@ function KeepAlive(activeKey, cases, options) {
5374
6869
  parent.removeChild(currentNode);
5375
6870
  }
5376
6871
  currentKey = key;
5377
- let node = cache2.get(key);
6872
+ let node = cache3.get(key);
5378
6873
  if (!node) {
5379
6874
  const factory = cases[key];
5380
6875
  if (!factory) {
@@ -5389,15 +6884,15 @@ function KeepAlive(activeKey, cases, options) {
5389
6884
  wrapper.appendChild(node);
5390
6885
  node = wrapper;
5391
6886
  }
5392
- cache2.set(key, node);
6887
+ cache3.set(key, node);
5393
6888
  lruOrder.push(key);
5394
6889
  if (max > 0 && lruOrder.length > max) {
5395
6890
  const evictKey = lruOrder.shift();
5396
- const evictNode = cache2.get(evictKey);
6891
+ const evictNode = cache3.get(evictKey);
5397
6892
  if (evictNode) {
5398
6893
  dispose(evictNode);
5399
6894
  if (evictNode.parentNode) evictNode.parentNode.removeChild(evictNode);
5400
- cache2.delete(evictKey);
6895
+ cache3.delete(evictKey);
5401
6896
  }
5402
6897
  }
5403
6898
  } else {
@@ -5411,23 +6906,27 @@ function KeepAlive(activeKey, cases, options) {
5411
6906
  currentNode = node;
5412
6907
  initialized = true;
5413
6908
  };
5414
- const binding = structuralBinding2(update);
6909
+ const binding = structuralBinding2(update, anchor);
6910
+ registerNodesRange(anchor, () => [currentNode]);
5415
6911
  const untrack = binding.stop;
5416
6912
  if (!initialized) {
5417
- queueMicrotask(
6913
+ const frozen = captureFrozen2();
6914
+ queueFirstRender(
6915
+ anchor,
5418
6916
  bindOwnerScope2(() => {
5419
6917
  if (!initialized && anchor.parentNode) binding.run(update);
5420
- })
6918
+ }),
6919
+ frozen
5421
6920
  );
5422
6921
  }
5423
6922
  registerDisposer(anchor, () => {
5424
6923
  disposed = true;
5425
6924
  untrack();
5426
- for (const node of cache2.values()) {
6925
+ for (const node of cache3.values()) {
5427
6926
  dispose(node);
5428
6927
  if (node.parentNode) node.parentNode.removeChild(node);
5429
6928
  }
5430
- cache2.clear();
6929
+ cache3.clear();
5431
6930
  lruOrder.length = 0;
5432
6931
  currentNode = null;
5433
6932
  });
@@ -5445,8 +6944,8 @@ function mount(component, container) {
5445
6944
  typeof component === "function" || component instanceof Node,
5446
6945
  "mount: first argument must be a component function or a DOM Node."
5447
6946
  );
5448
- const now = () => typeof performance !== "undefined" ? performance.now() : 0;
5449
- const startTime = now();
6947
+ const now2 = () => typeof performance !== "undefined" ? performance.now() : 0;
6948
+ const startTime = now2();
5450
6949
  let range = null;
5451
6950
  const attach = (built) => {
5452
6951
  if (built instanceof DocumentFragment) {
@@ -5469,7 +6968,7 @@ function mount(component, container) {
5469
6968
  node = component;
5470
6969
  attach(node);
5471
6970
  }
5472
- const duration = now() - startTime;
6971
+ const duration = now2() - startTime;
5473
6972
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
5474
6973
  if (hook) emitDevtools(hook, "app:init", { rootElement: node, container, duration });
5475
6974
  const mounted = range;
@@ -5517,6 +7016,153 @@ function unmountRange(start, end) {
5517
7016
  end.parentNode?.removeChild(end);
5518
7017
  }
5519
7018
 
7019
+ // src/core/signals/watch.ts
7020
+ function watch(getter, callback) {
7021
+ devAssert(typeof getter === "function", "watch: first argument must be a getter function.");
7022
+ devAssert(typeof callback === "function", "watch: second argument must be a callback function.");
7023
+ if (isSSR()) return () => {
7024
+ };
7025
+ let oldValue;
7026
+ let first = true;
7027
+ const subscriber = () => {
7028
+ const newValue = getter();
7029
+ if (first) {
7030
+ oldValue = newValue;
7031
+ first = false;
7032
+ return;
7033
+ }
7034
+ if (!Object.is(newValue, oldValue)) {
7035
+ const prev = oldValue;
7036
+ oldValue = newValue;
7037
+ suspendTracking2();
7038
+ try {
7039
+ callback(newValue, prev);
7040
+ } finally {
7041
+ resumeTracking2();
7042
+ }
7043
+ }
7044
+ };
7045
+ const teardown = track2(subscriber);
7046
+ return teardown;
7047
+ }
7048
+
7049
+ // src/core/signals/lifecycleScope.ts
7050
+ var STATES = ["active", "paused", "ended"];
7051
+ var ENDED2 = 2;
7052
+ var NOOP5 = () => {
7053
+ };
7054
+ var scopeOwners = globalSingleton(
7055
+ /* @__PURE__ */ Symbol.for("sibujs.lifecycleScope.owners.v1"),
7056
+ () => /* @__PURE__ */ new WeakMap()
7057
+ );
7058
+ function scopeOwner(scope) {
7059
+ return scopeOwners.get(scope);
7060
+ }
7061
+ function lifecycleScope() {
7062
+ const held = captureFrozen2();
7063
+ const inOwnerScope = bindOwnerScope2((fn) => fn());
7064
+ const ended = () => held.state() === ENDED2;
7065
+ const own = (register) => {
7066
+ let disposed = false;
7067
+ let stop2 = null;
7068
+ let dropWait = NOOP5;
7069
+ let dropEnd = NOOP5;
7070
+ const dispose2 = () => {
7071
+ if (disposed) return;
7072
+ disposed = true;
7073
+ dropWait();
7074
+ dropEnd();
7075
+ const running = stop2;
7076
+ stop2 = null;
7077
+ running?.();
7078
+ };
7079
+ const start = () => {
7080
+ dropWait = NOOP5;
7081
+ if (disposed) return;
7082
+ dropEnd = held.onEnd(dispose2);
7083
+ if (disposed) return;
7084
+ let created;
7085
+ try {
7086
+ created = held.run(() => inOwnerScope(register));
7087
+ } catch (err) {
7088
+ disposed = true;
7089
+ dropEnd();
7090
+ dropEnd = NOOP5;
7091
+ throw err;
7092
+ }
7093
+ if (disposed) created();
7094
+ else stop2 = created;
7095
+ };
7096
+ const state4 = held.state();
7097
+ if (state4 === ENDED2) disposed = true;
7098
+ else if (state4 === 1) dropWait = held.wait(start, dispose2);
7099
+ else start();
7100
+ return dispose2;
7101
+ };
7102
+ const onState = (want, callback) => held.onChange((state4) => {
7103
+ if (state4 === want) held.run(() => inOwnerScope(callback));
7104
+ });
7105
+ const scope = {
7106
+ state: () => STATES[held.state()],
7107
+ own,
7108
+ onPause: (callback) => onState(1, callback),
7109
+ onResume: (callback) => onState(0, callback),
7110
+ // The guards are the liveness check of a registration whose owner ended
7111
+ // while its own run was in progress (a body that ends its branch and
7112
+ // re-runs itself); `own` disposes it as soon as that run returns.
7113
+ effect: (fn, options) => own(
7114
+ () => effect((onCleanup2) => {
7115
+ if (!ended()) fn(onCleanup2);
7116
+ }, options)
7117
+ ),
7118
+ watch: (getter, callback) => own(
7119
+ () => watch(getter, (value, prev) => {
7120
+ if (!ended()) callback(value, prev);
7121
+ })
7122
+ )
7123
+ };
7124
+ scopeOwners.set(scope, held);
7125
+ return scope;
7126
+ }
7127
+
7128
+ // src/core/rendering/pendingContent.ts
7129
+ var INERT2 = { done: () => {
7130
+ }, cancel: () => {
7131
+ }, settled: true };
7132
+ function pendingContent(at) {
7133
+ if (isServer()) return INERT2;
7134
+ const isNode = typeof at.nodeType === "number";
7135
+ const held = isNode ? null : scopeOwner(at) ?? null;
7136
+ if (!isNode && (held === null || held.state() === 2)) return INERT2;
7137
+ const { entry, done, cancel: cancelEntry } = beginPending(isNode ? at : null, held);
7138
+ let drop = () => {
7139
+ };
7140
+ const cancel = () => {
7141
+ if (entry.settled) return;
7142
+ drop();
7143
+ cancelEntry();
7144
+ };
7145
+ if (isNode) {
7146
+ registerDisposer(at, cancel);
7147
+ drop = () => {
7148
+ unregisterDisposer(at, cancel);
7149
+ };
7150
+ } else drop = held.onEnd(cancel);
7151
+ return {
7152
+ done: (committed) => {
7153
+ if (entry.settled) return;
7154
+ drop();
7155
+ done(
7156
+ committed === void 0 ? null : typeof committed.nodeType === "number" ? [committed] : [...committed]
7157
+ );
7158
+ },
7159
+ cancel,
7160
+ get settled() {
7161
+ return entry.settled;
7162
+ }
7163
+ };
7164
+ }
7165
+
5520
7166
  // src/core/rendering/portal.ts
5521
7167
  function Portal(nodes, target) {
5522
7168
  requireDocument();
@@ -6145,36 +7791,6 @@ function store(initialState) {
6145
7791
  return [store2, { setState, reset, subscribe, subscribeKey, getSnapshot }];
6146
7792
  }
6147
7793
 
6148
- // src/core/signals/watch.ts
6149
- function watch(getter, callback) {
6150
- devAssert(typeof getter === "function", "watch: first argument must be a getter function.");
6151
- devAssert(typeof callback === "function", "watch: second argument must be a callback function.");
6152
- if (isSSR()) return () => {
6153
- };
6154
- let oldValue;
6155
- let first = true;
6156
- const subscriber = () => {
6157
- const newValue = getter();
6158
- if (first) {
6159
- oldValue = newValue;
6160
- first = false;
6161
- return;
6162
- }
6163
- if (!Object.is(newValue, oldValue)) {
6164
- const prev = oldValue;
6165
- oldValue = newValue;
6166
- suspendTracking2();
6167
- try {
6168
- callback(newValue, prev);
6169
- } finally {
6170
- resumeTracking2();
6171
- }
6172
- }
6173
- };
6174
- const teardown = track2(subscriber);
6175
- return teardown;
6176
- }
6177
-
6178
7794
  // src/core/signals/writable.ts
6179
7795
  function writable(get, set, options) {
6180
7796
  const getter = derived(get, options);
@@ -6428,10 +8044,10 @@ function enhance(target, setup) {
6428
8044
  });
6429
8045
  });
6430
8046
  },
6431
- model: (t, state2, options) => {
8047
+ model: (t, state4, options) => {
6432
8048
  bind("model", t, (el) => {
6433
8049
  const control = el;
6434
- const [get, set] = state2;
8050
+ const [get, set] = state4;
6435
8051
  const evt = options?.event ?? (control instanceof HTMLSelectElement || control instanceof HTMLInputElement && (control.type === "checkbox" || control.type === "radio") ? "change" : "input");
6436
8052
  teardowns.push(
6437
8053
  bindNode(el, () => {
@@ -6676,17 +8292,17 @@ var DEFAULT_MAX_SSR_BYTES = 1024 * 1024;
6676
8292
  // src/reactivity/concurrent.ts
6677
8293
  function defer(getter) {
6678
8294
  const [value, setValue] = signal(getter());
6679
- let pending = false;
8295
+ let pending2 = false;
6680
8296
  let disposed = false;
6681
8297
  let latest = value();
6682
8298
  const flush = () => {
6683
- pending = false;
8299
+ pending2 = false;
6684
8300
  if (disposed) return;
6685
8301
  setValue(latest);
6686
8302
  };
6687
8303
  const schedule2 = () => {
6688
- if (pending) return;
6689
- pending = true;
8304
+ if (pending2) return;
8305
+ pending2 = true;
6690
8306
  queueMicrotask(() => {
6691
8307
  if (typeof requestAnimationFrame === "function") {
6692
8308
  requestAnimationFrame(flush);
@@ -6721,7 +8337,7 @@ function scheduleIdle(fn) {
6721
8337
  setTimeout(fn, IDLE_FALLBACK_MS);
6722
8338
  }
6723
8339
  function transition() {
6724
- const [pending, setPending] = signal(false);
8340
+ const [pending2, setPending] = signal(false);
6725
8341
  let outstanding = 0;
6726
8342
  function start(fn) {
6727
8343
  outstanding++;
@@ -6746,7 +8362,7 @@ function transition() {
6746
8362
  }
6747
8363
  });
6748
8364
  }
6749
- return { pending, start };
8365
+ return { pending: pending2, start };
6750
8366
  }
6751
8367
 
6752
8368
  // src/reactivity/nextTick.ts
@@ -6878,6 +8494,7 @@ function nextTick() {
6878
8494
  lazyIsland,
6879
8495
  legend,
6880
8496
  li,
8497
+ lifecycleScope,
6881
8498
  line,
6882
8499
  linearGradient,
6883
8500
  link,
@@ -6911,6 +8528,7 @@ function nextTick() {
6911
8528
  param,
6912
8529
  path,
6913
8530
  pattern,
8531
+ pendingContent,
6914
8532
  picture,
6915
8533
  polygon,
6916
8534
  polyline,
@@ -6937,6 +8555,7 @@ function nextTick() {
6937
8555
  runInSSRContext,
6938
8556
  s,
6939
8557
  samp,
8558
+ scopeOwner,
6940
8559
  script,
6941
8560
  section,
6942
8561
  select,