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
@@ -1,3 +1,6 @@
1
+ import {
2
+ commitWhenActive
3
+ } from "./chunk-DS5V2PRE.js";
1
4
  import {
2
5
  a,
3
6
  abbr,
@@ -135,45 +138,56 @@ import {
135
138
  use,
136
139
  var_,
137
140
  video
138
- } from "./chunk-7ILEHTVX.js";
141
+ } from "./chunk-4AEFGRYW.js";
139
142
  import {
140
143
  trustHTML
141
- } from "./chunk-BOYKGGVD.js";
144
+ } from "./chunk-DRWOD7RZ.js";
142
145
  import {
143
146
  watch
144
- } from "./chunk-RVR5NPFL.js";
147
+ } from "./chunk-2VKTFA7C.js";
145
148
  import {
146
149
  __resetIdCounter,
147
150
  createId,
148
151
  domBinding
149
- } from "./chunk-CCKUNHVU.js";
152
+ } from "./chunk-DAEXQJQA.js";
150
153
  import {
151
154
  SVG_NS,
155
+ anyPending,
156
+ beginLoading,
157
+ beginPending,
152
158
  bindChildNode,
153
159
  captureFocusWithin,
160
+ collectRange,
161
+ hasRange,
162
+ loadingWithin,
163
+ onLoaded,
164
+ pendingWithin,
165
+ queueFirstRender,
166
+ registerNodesRange,
167
+ registerRange,
154
168
  restoreFocusWithin,
169
+ resumePending,
170
+ settledContent,
171
+ settledSinceNotify,
155
172
  tagFactory
156
- } from "./chunk-CJ7KS3DF.js";
173
+ } from "./chunk-VSTX3XSX.js";
157
174
  import {
158
175
  bindAttribute,
159
176
  bindDynamic,
160
177
  requireDocument,
161
178
  setSafeAttribute,
162
179
  setTrustedAttribute
163
- } from "./chunk-HQIAL7F2.js";
180
+ } from "./chunk-XPDZ2LDR.js";
164
181
  import {
165
182
  isCodeTextElement
166
183
  } from "./chunk-RVWJGWCL.js";
167
184
  import {
168
185
  derived
169
- } from "./chunk-N7A6FKWW.js";
170
- import {
171
- globalSingleton
172
- } from "./chunk-7ZHH77QA.js";
186
+ } from "./chunk-D44TAGCT.js";
173
187
  import {
174
188
  effect,
175
189
  on
176
- } from "./chunk-AE32RGWX.js";
190
+ } from "./chunk-LGUXYHTZ.js";
177
191
  import {
178
192
  currentBoundary,
179
193
  disableSSR,
@@ -198,10 +212,13 @@ import {
198
212
  external,
199
213
  isBatching,
200
214
  signal
201
- } from "./chunk-4FJSAUKB.js";
215
+ } from "./chunk-IUBV5WO5.js";
202
216
  import {
203
217
  bindOwnerScope,
218
+ captureFrozen,
204
219
  getOwnerScope,
220
+ holdSubtree,
221
+ isTrackingSuspended,
205
222
  notifySubscribers,
206
223
  reactiveBinding,
207
224
  recordDependency,
@@ -213,21 +230,24 @@ import {
213
230
  suspendTracking,
214
231
  track,
215
232
  untracked
216
- } from "./chunk-MIRKTVH4.js";
233
+ } from "./chunk-GFM5WWPU.js";
217
234
  import {
218
235
  MAX_DRAIN_TEARDOWNS,
219
236
  checkLeaks,
220
237
  dispose,
238
+ disposeNodeOwn,
221
239
  getRuntimeErrorHandler,
240
+ globalSingleton,
222
241
  normalizeError,
223
242
  registerDisposer,
224
243
  replaceChildrenSafely,
225
244
  reportDrainRunaway,
226
245
  reportError,
227
246
  setRuntimeErrorHandler,
247
+ stageReplaceChildren,
228
248
  unregisterDisposer,
229
249
  withDisposerRollback
230
- } from "./chunk-S37PZD6I.js";
250
+ } from "./chunk-BF3WBJJQ.js";
231
251
  import {
232
252
  DEV,
233
253
  afterHydration,
@@ -364,6 +384,7 @@ __export(index_exports, {
364
384
  lazyIsland: () => lazyIsland,
365
385
  legend: () => legend,
366
386
  li: () => li,
387
+ lifecycleScope: () => lifecycleScope,
367
388
  line: () => line,
368
389
  linearGradient: () => linearGradient,
369
390
  link: () => link,
@@ -397,6 +418,7 @@ __export(index_exports, {
397
418
  param: () => param,
398
419
  path: () => path,
399
420
  pattern: () => pattern,
421
+ pendingContent: () => pendingContent,
400
422
  picture: () => picture,
401
423
  polygon: () => polygon,
402
424
  polyline: () => polyline,
@@ -423,6 +445,7 @@ __export(index_exports, {
423
445
  runInSSRContext: () => runInSSRContext,
424
446
  s: () => s,
425
447
  samp: () => samp,
448
+ scopeOwner: () => scopeOwner,
426
449
  script: () => script,
427
450
  section: () => section,
428
451
  select: () => select,
@@ -503,100 +526,296 @@ function takePendingError(node) {
503
526
  }
504
527
  return void 0;
505
528
  }
529
+ var NOOP = () => {
530
+ };
506
531
  function lazy(importFn) {
507
532
  let cached = null;
533
+ const instance = (component) => {
534
+ const own = structuralBinding(NOOP);
535
+ try {
536
+ return [withDisposerRollback(() => own.run(component)), own];
537
+ } catch (err) {
538
+ own.stop();
539
+ throw err;
540
+ }
541
+ };
542
+ const ending = (root, own) => root.nodeType === 11 ? () => {
543
+ disposeNodeOwn(root);
544
+ own.stop();
545
+ } : own.stop;
508
546
  return function LazyComponent() {
509
547
  if (cached && !inAdoptScope()) {
510
- return cached();
548
+ const [root, own] = instance(cached);
549
+ const type = root?.nodeType;
550
+ if (type === 11) {
551
+ const box = div({ class: "sibu-lazy" });
552
+ registerDisposer(box, ending(root, own));
553
+ box.appendChild(root);
554
+ return box;
555
+ }
556
+ if (typeof type === "number") registerDisposer(root, own.stop);
557
+ return root;
511
558
  }
512
559
  const container = div({ class: "sibu-lazy" });
513
560
  const scope = captureScope();
514
561
  const boundary = currentBoundary();
515
- let disposed = false;
516
562
  const loading = inScope(null, () => span("sibu-lazy-loading", "Loading..."));
517
563
  if (cached) {
518
564
  const loaded = cached;
519
- replaceChildrenSafely(container, inScope(scope, () => loaded()));
565
+ let rendered;
566
+ try {
567
+ const [root, own] = instance(() => inScope(scope, () => loaded()));
568
+ registerDisposer(container, ending(root, own));
569
+ rendered = root;
570
+ } catch (err) {
571
+ dispose(container);
572
+ throw err;
573
+ }
574
+ replaceChildrenSafely(container, rendered);
520
575
  return container;
521
576
  }
522
- trackPending(importFn(), "lazy").then(
523
- // The component renders after the import resolves, in the owner scope
524
- // of whoever rendered the placeholder.
525
- bindOwnerScope((mod) => {
526
- if (disposed) return;
527
- cached = mod.default;
528
- const component = cached;
529
- const build = () => inScope(scope, () => component());
530
- const rendered = boundary ? boundary.enter(build) : build();
531
- replaceChildrenSafely(container, rendered);
532
- })
533
- ).catch((err) => {
534
- if (disposed) return;
535
- const errorObj = err instanceof Error ? err : new Error(String(err));
536
- replaceChildrenSafely(
537
- container,
538
- div({ class: "sibu-lazy-error" }, `Failed to load component: ${errorObj.message}`)
539
- );
540
- dispatchPropagate(container, errorObj);
541
- });
542
- if (!(isHydrating() && container.firstChild)) container.appendChild(loading);
577
+ const held = captureFrozen();
578
+ const inOwner = bindOwnerScope((fn) => fn());
579
+ const ready = beginLoading(container);
580
+ let disposed = false;
581
+ const live = () => !disposed;
582
+ let owner = null;
583
+ const waiting = { cancel: NOOP };
543
584
  registerDisposer(container, () => {
544
585
  disposed = true;
586
+ waiting.cancel();
587
+ ready.cancel();
588
+ const end = owner;
589
+ owner = null;
590
+ end?.();
545
591
  });
592
+ if (!(isHydrating() && container.firstChild)) container.appendChild(loading);
593
+ const show2 = (view, release, claim, shown, failed) => {
594
+ const swap = stageReplaceChildren(container, [view]);
595
+ commitWhenActive(waiting, {
596
+ held,
597
+ node: view,
598
+ owned: live,
599
+ teardown: swap.teardown,
600
+ insert: () => {
601
+ claim();
602
+ try {
603
+ swap.insert();
604
+ } catch (err) {
605
+ release();
606
+ failed(err);
607
+ return;
608
+ }
609
+ if (!disposed) shown();
610
+ },
611
+ discard: () => {
612
+ release();
613
+ ready.cancel();
614
+ }
615
+ });
616
+ };
617
+ const later = (fn) => commitWhenActive(waiting, { held, node: null, owned: live, insert: () => inOwner(fn), discard: ready.cancel });
618
+ const fail = (err) => {
619
+ if (disposed) return;
620
+ const error = err instanceof Error ? err : new Error(String(err));
621
+ const view = div({ class: "sibu-lazy-error" }, `Failed to load component: ${error.message}`);
622
+ show2(
623
+ view,
624
+ () => dispose(view),
625
+ NOOP,
626
+ () => {
627
+ ready.done();
628
+ dispatchPropagate(container, error);
629
+ },
630
+ (insertError) => {
631
+ ready.cancel();
632
+ reportError(insertError, { phase: "render", name: "lazy" });
633
+ }
634
+ );
635
+ };
636
+ const build = (component) => {
637
+ if (disposed) return;
638
+ let rendered;
639
+ let own;
640
+ try {
641
+ const render = () => held.run(() => instance(() => inScope(scope, () => component())));
642
+ [rendered, own] = boundary ? boundary.enter(render) : render();
643
+ } catch (err) {
644
+ fail(err);
645
+ return;
646
+ }
647
+ const end = ending(rendered, own);
648
+ show2(
649
+ rendered,
650
+ () => {
651
+ if (owner === end) owner = null;
652
+ own.stop();
653
+ dispose(rendered);
654
+ },
655
+ () => {
656
+ owner = end;
657
+ },
658
+ () => ready.done(),
659
+ fail
660
+ );
661
+ };
662
+ let imported;
663
+ try {
664
+ imported = importFn();
665
+ } catch (err) {
666
+ dispose(container);
667
+ throw err;
668
+ }
669
+ trackPending(imported, "lazy").then(
670
+ (mod) => {
671
+ if (disposed) return;
672
+ cached = mod.default;
673
+ const component = cached;
674
+ later(() => build(component));
675
+ },
676
+ (err) => {
677
+ if (!disposed) later(() => fail(err));
678
+ }
679
+ );
546
680
  return container;
547
681
  };
548
682
  }
549
683
  function Suspense({ nodes, fallback }) {
550
684
  const container = div({ class: "sibu-suspense" });
551
685
  const scope = captureScope();
686
+ const held = captureFrozen();
687
+ const inOwner = bindOwnerScope((fn) => fn());
552
688
  const boundary = openBoundary(container);
553
- const commit = (el) => {
554
- replaceChildrenSafely(container, el);
555
- boundary?.done();
556
- };
557
- const fallbackEl = inScope(null, fallback);
558
- if (isHydrating() && container.firstChild) dispose(fallbackEl);
559
- else container.appendChild(fallbackEl);
689
+ const ready = beginLoading(container);
560
690
  let suspenseDisposed = false;
691
+ const live = () => !suspenseDisposed;
561
692
  let observer = null;
562
693
  let childEl = null;
694
+ let contentOwner = null;
695
+ const endContent = () => {
696
+ const own = contentOwner;
697
+ contentOwner = null;
698
+ own?.stop();
699
+ };
700
+ const fallbackOwn = structuralBinding(NOOP);
701
+ let fallbackOwner = fallbackOwn;
702
+ const endFallback = () => {
703
+ const own = fallbackOwner;
704
+ fallbackOwner = null;
705
+ own?.stop();
706
+ };
707
+ const waiting = { cancel: NOOP };
563
708
  registerDisposer(container, () => {
564
709
  suspenseDisposed = true;
710
+ waiting.cancel();
711
+ ready.cancel();
565
712
  if (observer) {
566
713
  observer.disconnect();
567
714
  observer = null;
568
715
  }
569
716
  if (childEl && !container.contains(childEl)) dispose(childEl);
717
+ endFallback();
718
+ endContent();
570
719
  });
571
- const renderContent = bindOwnerScope(() => {
572
- if (suspenseDisposed) return;
573
- try {
574
- const el = boundary ? boundary.enter(() => inScope(scope, nodes)) : inScope(scope, nodes);
575
- childEl = el;
576
- if (el.classList.contains("sibu-lazy")) {
577
- if (!el.querySelector(".sibu-lazy-loading")) {
578
- commit(el);
720
+ let fallbackEl;
721
+ try {
722
+ fallbackEl = inScope(null, () => withDisposerRollback(() => fallbackOwn.run(fallback)));
723
+ } catch (err) {
724
+ boundary?.done();
725
+ dispose(container);
726
+ throw err;
727
+ }
728
+ if (isHydrating() && container.firstChild) {
729
+ dispose(fallbackEl);
730
+ endFallback();
731
+ } else container.appendChild(fallbackEl);
732
+ const commit = (el) => {
733
+ const swap = stageReplaceChildren(container, [el]);
734
+ commitWhenActive(waiting, {
735
+ held,
736
+ node: el,
737
+ owned: live,
738
+ teardown: () => {
739
+ if (swap.teardown()) return true;
740
+ if (fallbackOwner === null) return false;
741
+ endFallback();
742
+ return true;
743
+ },
744
+ // `el` is the container's content already (`childEl`): disposing the
745
+ // container from its `connectedCallback`, during the insertion,
746
+ // disposes it — in the container, or as the orphan `childEl` is.
747
+ insert: () => {
748
+ try {
749
+ swap.insert();
750
+ } catch (err) {
751
+ if (childEl === el) childEl = null;
752
+ dispose(el);
753
+ endContent();
754
+ ready.cancel();
755
+ boundary?.done();
756
+ dispatchPropagate(container, err instanceof Error ? err : new Error(String(err)));
579
757
  return;
580
758
  }
581
- observer = new MutationObserver(() => {
582
- if (suspenseDisposed) return;
583
- const loading = el.querySelector(".sibu-lazy-loading");
584
- if (!loading) {
585
- observer?.disconnect();
586
- observer = null;
587
- commit(el);
588
- }
589
- });
590
- observer.observe(el, { childList: true, subtree: true });
591
- } else {
592
- commit(el);
759
+ boundary?.done();
760
+ ready.done();
761
+ },
762
+ discard: () => {
763
+ if (childEl === el) childEl = null;
764
+ dispose(el);
765
+ endContent();
766
+ ready.cancel();
593
767
  }
768
+ });
769
+ };
770
+ const renderContent = () => {
771
+ if (suspenseDisposed) return;
772
+ const own = held.run(() => structuralBinding(NOOP));
773
+ contentOwner = own;
774
+ let el;
775
+ try {
776
+ const build = () => withDisposerRollback(() => own.run(() => inScope(scope, nodes)));
777
+ el = boundary ? boundary.enter(build) : build();
594
778
  } catch (err) {
779
+ endContent();
595
780
  const errorObj = err instanceof Error ? err : new Error(String(err));
781
+ ready.cancel();
596
782
  dispatchPropagate(container, errorObj);
783
+ return;
784
+ }
785
+ childEl = el;
786
+ if (suspenseDisposed) {
787
+ childEl = null;
788
+ dispose(el);
789
+ return;
597
790
  }
791
+ if (el.classList.contains("sibu-lazy")) {
792
+ if (!el.querySelector(".sibu-lazy-loading")) {
793
+ commit(el);
794
+ return;
795
+ }
796
+ observer = new MutationObserver(() => {
797
+ if (suspenseDisposed) return;
798
+ const loading = el.querySelector(".sibu-lazy-loading");
799
+ if (!loading) {
800
+ observer?.disconnect();
801
+ observer = null;
802
+ commit(el);
803
+ }
804
+ });
805
+ observer.observe(el, { childList: true, subtree: true });
806
+ } else {
807
+ commit(el);
808
+ }
809
+ };
810
+ queueMicrotask(() => {
811
+ commitWhenActive(waiting, {
812
+ held,
813
+ node: null,
814
+ owned: live,
815
+ insert: () => inOwner(renderContent),
816
+ discard: ready.cancel
817
+ });
598
818
  });
599
- queueMicrotask(renderContent);
600
819
  return container;
601
820
  }
602
821
 
@@ -1832,6 +2051,202 @@ function setGlobalErrorHandler(handler) {
1832
2051
  globalErrorHandler = handler;
1833
2052
  }
1834
2053
 
2054
+ // src/core/rendering/branchTransition.ts
2055
+ var HARD_CAP_MS = 5e3;
2056
+ function now() {
2057
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
2058
+ }
2059
+ var SLACK_MS = 50;
2060
+ var INSTANT_MS = 1;
2061
+ var FALLBACK_EVENTS = ["transitionend", "transitioncancel", "animationend", "animationcancel"];
2062
+ function parseList(list, fallback) {
2063
+ return (list?.trim() ? list : fallback).split(",").map((part) => part.trim());
2064
+ }
2065
+ function parseTimes(list) {
2066
+ return parseList(list, "0s").map((v) => (Number.parseFloat(v) || 0) * (v.endsWith("ms") ? 1 : 1e3));
2067
+ }
2068
+ function measure(el) {
2069
+ if (typeof getComputedStyle !== "function") return null;
2070
+ const cs = getComputedStyle(el);
2071
+ if (cs.display === "none") return null;
2072
+ const timing = { total: 0, transitions: /* @__PURE__ */ new Map(), animations: /* @__PURE__ */ new Map(), pending: 0 };
2073
+ const expect = (map2, names, durations, delays, iterations) => {
2074
+ for (let i2 = 0; i2 < names.length; i2++) {
2075
+ const duration = durations[i2 % durations.length];
2076
+ if (names[i2] === "none" || duration <= 0) continue;
2077
+ const count = iterations[i2 % iterations.length];
2078
+ const runs = count === "infinite" ? Number.POSITIVE_INFINITY : Number.parseFloat(count) || 1;
2079
+ timing.total = Math.max(timing.total, delays[i2 % delays.length] + duration * runs);
2080
+ map2.set(names[i2], (map2.get(names[i2]) ?? 0) + 1);
2081
+ timing.pending++;
2082
+ }
2083
+ };
2084
+ expect(
2085
+ timing.transitions,
2086
+ parseList(cs.transitionProperty, "all"),
2087
+ parseTimes(cs.transitionDuration),
2088
+ parseTimes(cs.transitionDelay),
2089
+ ["1"]
2090
+ );
2091
+ expect(
2092
+ timing.animations,
2093
+ parseList(cs.animationName, "none"),
2094
+ parseTimes(cs.animationDuration),
2095
+ parseTimes(cs.animationDelay),
2096
+ parseList(cs.animationIterationCount, "1")
2097
+ );
2098
+ return timing.total <= INSTANT_MS ? null : timing;
2099
+ }
2100
+ function matchEntry(map2, name) {
2101
+ if (typeof name !== "string" || name === "") return map2.keys().next().value;
2102
+ if (map2.has(name)) return name;
2103
+ for (const key of map2.keys()) if (name.startsWith(`${key}-`)) return key;
2104
+ return map2.has("all") ? "all" : void 0;
2105
+ }
2106
+ function insideAnimating(animating, el) {
2107
+ for (const a2 of animating) if (a2 !== el && a2.contains(el)) return true;
2108
+ return false;
2109
+ }
2110
+ function runPhase(nodes, cls, custom, maxDuration, onDone, name, open = 0) {
2111
+ const cap = Math.min(typeof maxDuration === "number" && maxDuration >= 0 ? maxDuration : HARD_CAP_MS, HARD_CAP_MS);
2112
+ const elements = [];
2113
+ for (let i2 = 0; i2 < nodes.length; i2++) if (nodes[i2].nodeType === 1) elements.push(nodes[i2]);
2114
+ let finished = false;
2115
+ let timer = null;
2116
+ const cleanups = [];
2117
+ const finish = (complete) => {
2118
+ if (finished) return;
2119
+ finished = true;
2120
+ if (timer !== null) clearTimeout(timer);
2121
+ for (let i2 = 0; i2 < cleanups.length; i2++) cleanups[i2]();
2122
+ if (complete) onDone();
2123
+ };
2124
+ const report = (error) => reportError(error, { phase: "async", name, node: elements[0] });
2125
+ if (custom) {
2126
+ let result;
2127
+ try {
2128
+ result = custom(nodes);
2129
+ } catch (error) {
2130
+ report(error);
2131
+ }
2132
+ const pending = adoptThenable(result);
2133
+ if (pending === null) {
2134
+ onDone();
2135
+ return null;
2136
+ }
2137
+ pending.then(
2138
+ () => finish(true),
2139
+ (error) => {
2140
+ report(error);
2141
+ finish(true);
2142
+ }
2143
+ );
2144
+ timer = setTimeout(() => finish(true), cap);
2145
+ return { cancel: () => finish(false) };
2146
+ }
2147
+ let holding = open > 0;
2148
+ if (!cls || elements.length === 0 && !holding) {
2149
+ onDone();
2150
+ return null;
2151
+ }
2152
+ for (let i2 = 0; i2 < elements.length; i2++) elements[i2].classList.add(cls);
2153
+ cleanups.push(() => {
2154
+ for (let i2 = 0; i2 < elements.length; i2++) elements[i2].classList.remove(cls);
2155
+ });
2156
+ const capAt = now() + cap;
2157
+ let deadline = 0;
2158
+ const arm = (until) => {
2159
+ const at = Math.min(until, capAt);
2160
+ if (timer !== null && at <= deadline) return;
2161
+ if (timer !== null) clearTimeout(timer);
2162
+ deadline = at;
2163
+ timer = setTimeout(() => finish(true), Math.max(0, at - now()));
2164
+ };
2165
+ let waiting = 0;
2166
+ const animating = /* @__PURE__ */ new Set();
2167
+ const enroll = (el) => {
2168
+ const timing = measure(el);
2169
+ if (timing === null) return -1;
2170
+ const running = typeof el.getAnimations === "function" ? el.getAnimations() : null;
2171
+ if (running !== null) {
2172
+ if (running.length === 0) return -1;
2173
+ waiting++;
2174
+ animating.add(el);
2175
+ let left = running.length;
2176
+ const settle2 = () => {
2177
+ if (left === 0 || --left !== 0) return;
2178
+ animating.delete(el);
2179
+ if (!finished && --waiting === 0 && !holding) finish(true);
2180
+ };
2181
+ for (const animation of running) animation.finished.then(settle2, settle2);
2182
+ return timing.total;
2183
+ }
2184
+ waiting++;
2185
+ animating.add(el);
2186
+ let done = false;
2187
+ let estimate = null;
2188
+ const settle = () => {
2189
+ if (done) return;
2190
+ done = true;
2191
+ if (estimate !== null) clearTimeout(estimate);
2192
+ animating.delete(el);
2193
+ if (!finished && --waiting === 0 && !holding) finish(true);
2194
+ };
2195
+ const onEnd = (event) => {
2196
+ if (event.target !== el || done || timing.pending === 0) return;
2197
+ const transition2 = event.type === "transitionend" || event.type === "transitioncancel";
2198
+ const map2 = transition2 ? timing.transitions : timing.animations;
2199
+ const key = matchEntry(
2200
+ map2,
2201
+ event[transition2 ? "propertyName" : "animationName"]
2202
+ );
2203
+ if (key === void 0) return;
2204
+ const left = map2.get(key) - 1;
2205
+ if (left > 0) map2.set(key, left);
2206
+ else map2.delete(key);
2207
+ if (--timing.pending === 0) settle();
2208
+ };
2209
+ for (const type of FALLBACK_EVENTS) el.addEventListener(type, onEnd);
2210
+ if (Number.isFinite(timing.total)) estimate = setTimeout(settle, timing.total + SLACK_MS);
2211
+ cleanups.push(() => {
2212
+ if (estimate !== null) clearTimeout(estimate);
2213
+ for (const type of FALLBACK_EVENTS) el.removeEventListener(type, onEnd);
2214
+ });
2215
+ return timing.total;
2216
+ };
2217
+ let longest = -1;
2218
+ for (let i2 = 0; i2 < elements.length; i2++) longest = Math.max(longest, enroll(elements[i2]));
2219
+ if (waiting === 0 && !holding) {
2220
+ finish(true);
2221
+ return null;
2222
+ }
2223
+ if (waiting > 0) arm(now() + longest + SLACK_MS);
2224
+ const close = () => {
2225
+ holding = false;
2226
+ if (!finished && waiting === 0) finish(true);
2227
+ };
2228
+ if (holding) {
2229
+ arm(now() + open);
2230
+ const openTimer = setTimeout(close, Math.max(0, Math.min(now() + open, capAt) - now()));
2231
+ cleanups.push(() => clearTimeout(openTimer));
2232
+ }
2233
+ return {
2234
+ cancel: () => finish(false),
2235
+ close,
2236
+ add: (late) => {
2237
+ if (finished) return;
2238
+ for (let i2 = 0; i2 < late.length; i2++) {
2239
+ const el = late[i2];
2240
+ if (elements.includes(el) || insideAnimating(animating, el)) continue;
2241
+ el.classList.add(cls);
2242
+ elements.push(el);
2243
+ const total = enroll(el);
2244
+ if (total >= 0) arm(now() + total + SLACK_MS);
2245
+ }
2246
+ }
2247
+ };
2248
+ }
2249
+
1835
2250
  // src/core/rendering/directives.ts
1836
2251
  function show(condition, element) {
1837
2252
  const resolved = typeof element === "function" ? element() : element;
@@ -1844,9 +2259,15 @@ function show(condition, element) {
1844
2259
  function isDirectiveOptions(value) {
1845
2260
  return typeof value === "object" && value !== null && !(value instanceof Node);
1846
2261
  }
1847
- function attachBranch(parent, anchor, branch, attachedOnce, where) {
2262
+ var fragmentStarts = /* @__PURE__ */ new WeakMap();
2263
+ var detachedRanges = /* @__PURE__ */ new WeakMap();
2264
+ var parked = /* @__PURE__ */ new WeakMap();
2265
+ var ENTER_WAIT_TURNS = 8;
2266
+ var NOOP2 = () => {
2267
+ };
2268
+ function resolveBranch(branch, attachedOnce, where) {
1848
2269
  const result = typeof branch === "function" ? branch() : branch;
1849
- if (result == null || typeof result === "boolean") return { node: null, owned: false };
2270
+ if (result == null || typeof result === "boolean") return null;
1850
2271
  const node = result instanceof Node ? result : document.createTextNode(String(result));
1851
2272
  const handedIn = node === branch;
1852
2273
  const seenBefore = attachedOnce.has(node);
@@ -1857,64 +2278,603 @@ function attachBranch(parent, anchor, branch, attachedOnce, where) {
1857
2278
  () => `${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.`
1858
2279
  );
1859
2280
  }
1860
- if (anchor.nextSibling !== node) parent.insertBefore(node, anchor.nextSibling);
1861
- return { node, owned };
2281
+ let starts;
2282
+ if (node.nodeType === 11) {
2283
+ if (node.firstChild) {
2284
+ starts = Array.from(node.childNodes);
2285
+ fragmentStarts.set(node, starts);
2286
+ } else {
2287
+ starts = fragmentStarts.get(node) ?? [];
2288
+ }
2289
+ } else {
2290
+ starts = [node];
2291
+ }
2292
+ const park = owned ? void 0 : parked.get(node);
2293
+ const nodes = park?.firstChild ? Array.from(park.childNodes) : !owned && starts.every((start) => start.parentNode === null) && detachedRanges.get(node) || attachedRanges(starts);
2294
+ if (nodes.length === 0 && !owned) return null;
2295
+ return {
2296
+ source: node,
2297
+ starts,
2298
+ nodes,
2299
+ owned,
2300
+ owner: null,
2301
+ phase: null,
2302
+ restore: null,
2303
+ unhold: null,
2304
+ waiting: false,
2305
+ released: false,
2306
+ inserting: false
2307
+ };
1862
2308
  }
1863
- function releaseBranchNode(node, owned) {
1864
- if (owned) dispose(node);
1865
- node.parentNode?.removeChild(node);
2309
+ function attachedRanges(starts) {
2310
+ if (!starts.some(hasRange)) return starts;
2311
+ return [...new Set(starts.flatMap((start) => start.parentNode === null ? [start] : collectRange([start])))];
1866
2312
  }
1867
- function when(condition, thenBranch, elseBranch, options) {
1868
- requireDocument();
1869
- if (isDirectiveOptions(elseBranch)) {
1870
- options = elseBranch;
1871
- elseBranch = void 0;
2313
+ function refreshNodes(branch) {
2314
+ const starts = branch.starts;
2315
+ if (starts.length === 1 && (!hasRange(starts[0]) || starts[0].parentNode === null)) return;
2316
+ const live = collectRange(starts);
2317
+ branch.nodes = branch.owned && branch.inserting ? [.../* @__PURE__ */ new Set([...branch.nodes, ...live])] : live;
2318
+ if (!branch.owned) detachedRanges.set(branch.source, branch.nodes);
2319
+ }
2320
+ function insertBranch(anchor, nodes, live) {
2321
+ let prev = anchor;
2322
+ for (let i2 = 0; i2 < nodes.length; i2++) {
2323
+ if (!live()) return false;
2324
+ const parent = anchor.parentNode;
2325
+ if (parent === null) return false;
2326
+ const node = nodes[i2];
2327
+ if (prev.parentNode !== parent) prev = anchor;
2328
+ if (prev.nextSibling !== node) parent.insertBefore(node, prev.nextSibling);
2329
+ prev = node;
1872
2330
  }
1873
- const elseNode = elseBranch;
2331
+ return live();
2332
+ }
2333
+ function releaseBranch(branch) {
2334
+ if (branch.released) return;
2335
+ branch.released = true;
2336
+ refreshNodes(branch);
2337
+ if (branch.phase !== null) {
2338
+ branch.phase.cancel();
2339
+ branch.phase = null;
2340
+ }
2341
+ if (branch.restore !== null) {
2342
+ branch.restore();
2343
+ branch.restore = null;
2344
+ }
2345
+ const nodes = branch.nodes;
2346
+ let park;
2347
+ if (!branch.owned && (branch.source.nodeType === 11 || branch.starts.some(hasRange))) {
2348
+ park = parked.get(branch.source);
2349
+ if (park === void 0) parked.set(branch.source, park = document.createDocumentFragment());
2350
+ }
2351
+ for (let i2 = 0; i2 < nodes.length; i2++) {
2352
+ const node = nodes[i2];
2353
+ if (branch.owned) dispose(node);
2354
+ if (park !== void 0) park.appendChild(node);
2355
+ else node.parentNode?.removeChild(node);
2356
+ }
2357
+ if (branch.owned && branch.source.nodeType === 11) dispose(branch.source);
2358
+ if (branch.owner !== null) {
2359
+ if (branch.owned) branch.owner.stop();
2360
+ else branch.owner.thaw?.();
2361
+ branch.owner = null;
2362
+ }
2363
+ if (branch.unhold !== null) {
2364
+ branch.unhold();
2365
+ branch.unhold = null;
2366
+ }
2367
+ }
2368
+ function makeInert(branch, onLate) {
2369
+ const saved = [];
2370
+ const marked = /* @__PURE__ */ new Set();
2371
+ const mark2 = (nodes) => {
2372
+ for (let i2 = 0; i2 < nodes.length; i2++) {
2373
+ if (nodes[i2].nodeType !== 1 || marked.has(nodes[i2])) continue;
2374
+ const el = nodes[i2];
2375
+ marked.add(el);
2376
+ saved.push([el, el.getAttribute("inert"), el.getAttribute("aria-hidden")]);
2377
+ el.setAttribute("inert", "");
2378
+ el.setAttribute("aria-hidden", "true");
2379
+ }
2380
+ };
2381
+ const active = typeof document !== "undefined" ? document.activeElement : null;
2382
+ mark2(branch.nodes);
2383
+ const initial = saved.length;
2384
+ for (let i2 = 0; i2 < initial; i2++) {
2385
+ const el = saved[i2][0];
2386
+ if (active && (el === active || el.contains(active))) {
2387
+ active.blur?.();
2388
+ break;
2389
+ }
2390
+ }
2391
+ const unwatch = watchRange(branch, (late) => {
2392
+ const before = saved.length;
2393
+ mark2(late);
2394
+ if (saved.length > before) onLate(saved.slice(before).map((entry) => entry[0]));
2395
+ });
2396
+ return () => {
2397
+ unwatch();
2398
+ for (let i2 = 0; i2 < saved.length; i2++) {
2399
+ const [el, inert, hidden] = saved[i2];
2400
+ if (inert === null) el.removeAttribute("inert");
2401
+ else el.setAttribute("inert", inert);
2402
+ if (hidden === null) el.removeAttribute("aria-hidden");
2403
+ else el.setAttribute("aria-hidden", hidden);
2404
+ }
2405
+ };
2406
+ }
2407
+ function watchRange(branch, onLate) {
2408
+ const parent = branch.nodes[0]?.parentNode;
2409
+ if (!parent || typeof MutationObserver !== "function" || !branch.starts.some(hasRange)) return NOOP2;
2410
+ const seen = new Set(branch.nodes);
2411
+ const observer = new MutationObserver(() => {
2412
+ refreshNodes(branch);
2413
+ const late = [];
2414
+ for (const node of branch.nodes) {
2415
+ if (seen.has(node)) continue;
2416
+ seen.add(node);
2417
+ if (node.nodeType === 1) late.push(node);
2418
+ }
2419
+ if (late.length > 0) onLate(late);
2420
+ });
2421
+ observer.observe(parent, { childList: true });
2422
+ return () => observer.disconnect();
2423
+ }
2424
+ function readyWindow(ms) {
2425
+ const endAt = now() + ms;
2426
+ const win = {
2427
+ expired: false,
2428
+ remaining: () => win.expired ? 0 : Math.max(0, Math.min(ms, endAt - now())),
2429
+ onExpire: null,
2430
+ stop: () => {
2431
+ clearTimeout(timer);
2432
+ win.onExpire = null;
2433
+ }
2434
+ };
2435
+ const timer = setTimeout(() => {
2436
+ win.expired = true;
2437
+ const expire = win.onExpire;
2438
+ win.onExpire = null;
2439
+ expire?.();
2440
+ }, ms);
2441
+ return win;
2442
+ }
2443
+ function watchMembership(branch, onChange) {
2444
+ if (typeof MutationObserver !== "function") return null;
2445
+ const observer = new MutationObserver(onChange);
2446
+ const watched = /* @__PURE__ */ new Set();
2447
+ const refresh = () => {
2448
+ const parent = branch.nodes[0]?.parentNode;
2449
+ if (parent && !watched.has(parent)) {
2450
+ watched.add(parent);
2451
+ observer.observe(parent, { childList: true });
2452
+ }
2453
+ for (const node of branch.nodes) {
2454
+ if (node.nodeType !== 1 || watched.has(node)) continue;
2455
+ watched.add(node);
2456
+ observer.observe(node, { childList: true, subtree: true });
2457
+ }
2458
+ };
2459
+ refresh();
2460
+ return {
2461
+ refresh,
2462
+ stop: () => {
2463
+ observer.disconnect();
2464
+ watched.clear();
2465
+ }
2466
+ };
2467
+ }
2468
+ function directive(name, read, pick, options) {
1874
2469
  const focusPolicy = options?.focus;
1875
- const anchor = document.createComment("when");
2470
+ const tr2 = options?.transition !== void 0 && !isServer() ? options.transition : void 0;
2471
+ const anchor = document.createComment(name);
1876
2472
  const scope = captureScope();
1877
- let currentNode = null;
1878
- let lastCondition;
2473
+ const frozen = captureFrozen();
2474
+ let current = null;
2475
+ let last;
1879
2476
  let initialized = false;
1880
2477
  let disposed = false;
1881
2478
  const attachedOnce = /* @__PURE__ */ new WeakSet();
1882
- let currentNodeOwned = false;
2479
+ const leaving = [];
2480
+ let deferred = false;
2481
+ let deferredFocus = null;
2482
+ let dropDeferredWait = NOOP2;
2483
+ const build = (branch, owns) => {
2484
+ const owner = structuralBinding(NOOP2, anchor);
2485
+ const inBranch = (fn) => owner.run(() => untracked(() => inScope(scope, fn)));
2486
+ let built;
2487
+ try {
2488
+ built = inBranch(() => resolveBranch(branch, attachedOnce, name));
2489
+ } catch (err) {
2490
+ owner.stop();
2491
+ throw err;
2492
+ }
2493
+ if (built === null) {
2494
+ owner.stop();
2495
+ return null;
2496
+ }
2497
+ const ownsOwner = built.owned;
2498
+ if (ownsOwner) built.owner = owner;
2499
+ if (disposed || !owns() || current !== null) {
2500
+ releaseBranch(built);
2501
+ if (!ownsOwner) owner.stop();
2502
+ return null;
2503
+ }
2504
+ let reclaimed = null;
2505
+ if (tr2) {
2506
+ for (let i2 = 0; i2 < leaving.length; i2++) {
2507
+ if (leaving[i2].source !== built.source) continue;
2508
+ reclaimed = leaving.splice(i2, 1)[0];
2509
+ built.owner = reclaimed.owner;
2510
+ reclaimed.owner = null;
2511
+ break;
2512
+ }
2513
+ }
2514
+ current = built;
2515
+ built.inserting = true;
2516
+ let complete = false;
2517
+ try {
2518
+ if (reclaimed !== null) {
2519
+ const prev = reclaimed;
2520
+ if (prev.phase !== null) prev.phase.cancel();
2521
+ prev.phase = null;
2522
+ if (prev.restore !== null) prev.restore();
2523
+ prev.restore = null;
2524
+ const unhold = prev.unhold;
2525
+ prev.unhold = null;
2526
+ built.owner?.thaw?.();
2527
+ unhold?.();
2528
+ if (!built.released) refreshNodes(built);
2529
+ }
2530
+ const live = () => !disposed && owns() && current === built && !built.released;
2531
+ complete = live() && inBranch(() => insertBranch(anchor, built.nodes, live));
2532
+ } catch (err) {
2533
+ built.inserting = false;
2534
+ if (current === built) current = null;
2535
+ releaseBranch(built);
2536
+ if (!ownsOwner) owner.stop();
2537
+ throw err;
2538
+ }
2539
+ built.inserting = false;
2540
+ if (complete) inBranch(() => resumePending(built.nodes));
2541
+ if (!ownsOwner) owner.stop();
2542
+ return current === built && !built.released && owns() ? built : null;
2543
+ };
2544
+ const playPhase = (branch, start, onEnd, onCancel = NOOP2) => {
2545
+ let valid = true;
2546
+ let run = null;
2547
+ const invalidate = () => {
2548
+ if (!valid) return;
2549
+ valid = false;
2550
+ onCancel();
2551
+ };
2552
+ const handle = {
2553
+ cancel: () => {
2554
+ invalidate();
2555
+ run?.cancel();
2556
+ }
2557
+ };
2558
+ branch.phase = handle;
2559
+ run = start(() => {
2560
+ if (!valid || branch.phase !== handle) return;
2561
+ valid = false;
2562
+ branch.phase = null;
2563
+ onEnd();
2564
+ });
2565
+ if (valid && branch.phase === handle && !branch.released && !disposed && run !== null) {
2566
+ handle.add = run.add;
2567
+ handle.close = run.close;
2568
+ return handle;
2569
+ }
2570
+ invalidate();
2571
+ if (branch.phase === handle) branch.phase = null;
2572
+ run?.cancel();
2573
+ return null;
2574
+ };
2575
+ const startLeave = (branch) => {
2576
+ branch.waiting = false;
2577
+ if (branch.released || disposed) return;
2578
+ const t = tr2;
2579
+ playPhase(
2580
+ branch,
2581
+ (done) => runPhase(branch.nodes, t.leaveClass, t.leave, t.maxDuration, done, `${name}(leave)`),
2582
+ () => finishLeave(branch)
2583
+ );
2584
+ };
2585
+ const startWaitingLeaves = () => {
2586
+ for (const branch of [...leaving]) {
2587
+ if (disposed) return;
2588
+ if (branch.waiting) startLeave(branch);
2589
+ }
2590
+ };
2591
+ const beginLeave = (branch) => {
2592
+ if (branch.released) return;
2593
+ const t = tr2;
2594
+ if (branch.phase !== null) {
2595
+ branch.phase.cancel();
2596
+ branch.phase = null;
2597
+ }
2598
+ refreshNodes(branch);
2599
+ if (branch.owner !== null) {
2600
+ branch.owner.freeze?.();
2601
+ branch.unhold = holdSubtree({
2602
+ contains: (node) => branch.nodes.some((n) => n === node || n.contains(node))
2603
+ });
2604
+ }
2605
+ const restore = makeInert(branch, (late) => branch.phase?.add?.(late));
2606
+ if (branch.released) {
2607
+ restore();
2608
+ return;
2609
+ }
2610
+ branch.restore = restore;
2611
+ if (t.mode === "in-out") {
2612
+ startWaitingLeaves();
2613
+ branch.waiting = true;
2614
+ leaving.push(branch);
2615
+ return;
2616
+ }
2617
+ leaving.push(branch);
2618
+ startLeave(branch);
2619
+ };
2620
+ const finishLeave = (branch) => {
2621
+ const index = leaving.indexOf(branch);
2622
+ if (index !== -1) leaving.splice(index, 1);
2623
+ releaseBranch(branch);
2624
+ if (deferred && leaving.length === 0 && !disposed) buildDeferred();
2625
+ };
2626
+ const afterInsert = (first, superseded) => {
2627
+ if (superseded()) return;
2628
+ const t = tr2;
2629
+ const entering = current;
2630
+ if (entering !== null && (!first || t.appear === true)) {
2631
+ enterWhenReady(entering);
2632
+ if (superseded()) return;
2633
+ if (entering.phase !== null) return;
2634
+ }
2635
+ if (t.mode === "in-out") startWaitingLeaves();
2636
+ };
2637
+ const enterWhenReady = (entering) => {
2638
+ const t = tr2;
2639
+ const budget = typeof t.waitForContent === "number" && t.waitForContent > 0 ? t.waitForContent : 0;
2640
+ const ready = budget > 0 ? readyWindow(Math.min(budget, HARD_CAP_MS)) : null;
2641
+ const contentReady = () => t.enter === void 0 || ready === null || ready.expired || loadingWithin(entering.nodes, entering.owner).length === 0;
2642
+ if (!frozen() && !anyPending(entering.nodes) && contentReady()) {
2643
+ startEnter(entering, ready);
2644
+ return;
2645
+ }
2646
+ let cancelled = false;
2647
+ let waiting = false;
2648
+ let dropWait = NOOP2;
2649
+ let dropLoaded = NOOP2;
2650
+ let membership = null;
2651
+ let turns = 0;
2652
+ const stopWaiting = () => {
2653
+ dropWait();
2654
+ dropWait = NOOP2;
2655
+ dropLoaded();
2656
+ dropLoaded = NOOP2;
2657
+ membership?.stop();
2658
+ membership = null;
2659
+ if (ready !== null) ready.onExpire = null;
2660
+ };
2661
+ const placeholder = {
2662
+ cancel: () => {
2663
+ cancelled = true;
2664
+ stopWaiting();
2665
+ ready?.stop();
2666
+ }
2667
+ };
2668
+ entering.phase = placeholder;
2669
+ const step = () => {
2670
+ if (cancelled || disposed || current !== entering || entering.phase !== placeholder) return;
2671
+ if (frozen()) {
2672
+ dropWait();
2673
+ dropWait = frozen.wait(step, NOOP2);
2674
+ return;
2675
+ }
2676
+ refreshNodes(entering);
2677
+ if (anyPending(entering.nodes) && ++turns < ENTER_WAIT_TURNS) {
2678
+ queueMicrotask(step);
2679
+ return;
2680
+ }
2681
+ if (!contentReady()) {
2682
+ if (!waiting) {
2683
+ waiting = true;
2684
+ dropLoaded = onLoaded(() => {
2685
+ turns = 0;
2686
+ step();
2687
+ });
2688
+ membership = watchMembership(entering, step);
2689
+ ready.onExpire = step;
2690
+ } else membership?.refresh();
2691
+ return;
2692
+ }
2693
+ stopWaiting();
2694
+ entering.phase = null;
2695
+ startEnter(entering, ready);
2696
+ };
2697
+ if (frozen()) step();
2698
+ else queueMicrotask(step);
2699
+ };
2700
+ const startEnter = (entering, ready) => {
2701
+ const t = tr2;
2702
+ const open = t.enter === void 0 && ready !== null && !ready.expired ? ready.remaining() : 0;
2703
+ const waitingFor = open > 0 ? loadingWithin(entering.nodes, entering.owner) : [];
2704
+ if (waitingFor.length === 0) ready?.stop();
2705
+ let stopWatching = NOOP2;
2706
+ const run = playPhase(
2707
+ entering,
2708
+ (done) => runPhase(
2709
+ entering.nodes,
2710
+ t.enterClass,
2711
+ t.enter,
2712
+ t.maxDuration,
2713
+ done,
2714
+ `${name}(enter)`,
2715
+ waitingFor.length > 0 ? open : 0
2716
+ ),
2717
+ () => {
2718
+ stopWatching();
2719
+ if (t.mode === "in-out" && !disposed) startWaitingLeaves();
2720
+ },
2721
+ () => stopWatching()
2722
+ );
2723
+ const add = run?.add;
2724
+ if (run === null || add === void 0) {
2725
+ ready?.stop();
2726
+ return;
2727
+ }
2728
+ const unwatch = watchRange(entering, add);
2729
+ let dropLoaded = NOOP2;
2730
+ let membership = null;
2731
+ const stopLoading = () => {
2732
+ dropLoaded();
2733
+ dropLoaded = NOOP2;
2734
+ membership?.stop();
2735
+ membership = null;
2736
+ ready?.stop();
2737
+ };
2738
+ if (waitingFor.length > 0) {
2739
+ const win = ready;
2740
+ const reconcile = (settled) => {
2741
+ if (win.expired || dropLoaded === NOOP2) {
2742
+ stopLoading();
2743
+ return;
2744
+ }
2745
+ refreshNodes(entering);
2746
+ const inBranch = (el) => entering.nodes.some((n) => n === el || n.contains(el));
2747
+ for (const entry of settled) {
2748
+ if (entry.cancelled || !pendingWithin(entry, entering.nodes, entering.owner)) continue;
2749
+ const content = settledContent(entry).filter(inBranch);
2750
+ if (content.length > 0) add(content);
2751
+ }
2752
+ if (loadingWithin(entering.nodes, entering.owner).length === 0) {
2753
+ stopLoading();
2754
+ run.close?.();
2755
+ } else membership?.refresh();
2756
+ };
2757
+ dropLoaded = onLoaded(reconcile);
2758
+ membership = watchMembership(entering, () => reconcile(settledSinceNotify()));
2759
+ win.onExpire = stopLoading;
2760
+ }
2761
+ stopWatching = () => {
2762
+ unwatch();
2763
+ stopLoading();
2764
+ };
2765
+ };
2766
+ const buildDeferred = bindOwnerScope(() => {
2767
+ if (disposed || !deferred) return;
2768
+ if (frozen()) {
2769
+ dropDeferredWait();
2770
+ dropDeferredWait = frozen.wait(() => {
2771
+ dropDeferredWait = NOOP2;
2772
+ if (deferred && !disposed) buildDeferred();
2773
+ }, NOOP2);
2774
+ return;
2775
+ }
2776
+ deferred = false;
2777
+ const focused = deferredFocus;
2778
+ deferredFocus = null;
2779
+ const gen = deferredGen;
2780
+ const superseded = () => disposed || gen !== generation;
2781
+ if (superseded() || !anchor.parentNode || current !== null) return;
2782
+ let built;
2783
+ try {
2784
+ built = binding.run(() => build(pick(last), () => !superseded()));
2785
+ } catch (err) {
2786
+ reportError(err, { phase: "render", name, node: anchor });
2787
+ return;
2788
+ }
2789
+ if (superseded()) return;
2790
+ restoreFocusWithin(focused, built !== null ? built.nodes : [], name, focusPolicy);
2791
+ afterInsert(false, superseded);
2792
+ });
2793
+ let generation = 0;
2794
+ let deferredGen = 0;
1883
2795
  const update = () => {
1884
2796
  if (disposed) return;
1885
- const show2 = condition();
1886
- const parent = anchor.parentNode;
1887
- if (!parent) return;
1888
- if (initialized && Object.is(show2, lastCondition)) return;
1889
- lastCondition = show2;
1890
- const focused = currentNode ? captureFocusWithin([currentNode]) : null;
1891
- if (currentNode?.parentNode) {
1892
- releaseBranchNode(currentNode, currentNodeOwned);
1893
- currentNode = null;
1894
- }
1895
- const branch = show2 ? thenBranch : elseNode !== void 0 ? elseNode : null;
1896
- const attached = untracked(() => inScope(scope, () => attachBranch(parent, anchor, branch, attachedOnce, "when")));
1897
- currentNode = attached.node;
1898
- currentNodeOwned = attached.owned;
1899
- restoreFocusWithin(focused, currentNode ? [currentNode] : [], "when", focusPolicy);
2797
+ const value = read();
2798
+ if (!anchor.parentNode) return;
2799
+ if (initialized && Object.is(value, last)) return;
2800
+ last = value;
2801
+ const first = !initialized;
1900
2802
  initialized = true;
2803
+ const gen = ++generation;
2804
+ const superseded = () => disposed || gen !== generation;
2805
+ if (current !== null) refreshNodes(current);
2806
+ const focused = current !== null ? captureFocusWithin(current.nodes) : null;
2807
+ if (current !== null) {
2808
+ const outgoing = current;
2809
+ if (tr2) beginLeave(outgoing);
2810
+ else releaseBranch(outgoing);
2811
+ if (current === outgoing) current = null;
2812
+ if (superseded()) return;
2813
+ }
2814
+ const branch = pick(value);
2815
+ if (tr2?.mode === "out-in" && leaving.length > 0) {
2816
+ let reclaim = false;
2817
+ for (let i2 = 0; i2 < leaving.length && !reclaim; i2++) reclaim = leaving[i2].source === branch;
2818
+ if (!reclaim) {
2819
+ deferred = true;
2820
+ deferredGen = gen;
2821
+ deferredFocus ?? (deferredFocus = focused);
2822
+ return;
2823
+ }
2824
+ }
2825
+ deferred = false;
2826
+ build(branch, () => !superseded());
2827
+ if (superseded()) return;
2828
+ restoreFocusWithin(focused, current !== null ? current.nodes : [], name, focusPolicy);
2829
+ if (tr2) afterInsert(first, superseded);
1901
2830
  };
1902
2831
  const binding = structuralBinding(update, anchor);
2832
+ registerRange(anchor, () => {
2833
+ for (let i2 = 0; i2 <= leaving.length; i2++) {
2834
+ const branch = i2 < leaving.length ? leaving[i2] : current;
2835
+ if (branch === null) break;
2836
+ const nodes = collectRange(branch.starts);
2837
+ if (nodes.length > 0) return nodes[nodes.length - 1];
2838
+ }
2839
+ return null;
2840
+ });
1903
2841
  registerDisposer(anchor, () => {
1904
2842
  disposed = true;
2843
+ deferred = false;
2844
+ deferredFocus = null;
2845
+ dropDeferredWait();
2846
+ dropDeferredWait = NOOP2;
1905
2847
  binding.stop();
1906
- if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
1907
- currentNode = null;
2848
+ if (current !== null) releaseBranch(current);
2849
+ current = null;
2850
+ const rest = leaving.splice(0);
2851
+ for (let i2 = 0; i2 < rest.length; i2++) releaseBranch(rest[i2]);
1908
2852
  });
1909
2853
  if (!initialized) {
1910
- queueMicrotask(
2854
+ queueFirstRender(
2855
+ anchor,
1911
2856
  bindOwnerScope(() => {
1912
2857
  if (!disposed && !initialized && anchor.parentNode) binding.run(update);
1913
- })
2858
+ }),
2859
+ frozen
1914
2860
  );
1915
2861
  }
1916
2862
  return anchor;
1917
2863
  }
2864
+ function when(condition, thenBranch, elseBranch, options) {
2865
+ requireDocument();
2866
+ if (isDirectiveOptions(elseBranch)) {
2867
+ options = elseBranch;
2868
+ elseBranch = void 0;
2869
+ }
2870
+ const elseNode = elseBranch;
2871
+ return directive(
2872
+ "when",
2873
+ condition,
2874
+ (show2) => show2 ? thenBranch : elseNode !== void 0 ? elseNode : null,
2875
+ options
2876
+ );
2877
+ }
1918
2878
  function match(value, cases, fallback, options) {
1919
2879
  requireDocument();
1920
2880
  if (isDirectiveOptions(fallback)) {
@@ -1922,51 +2882,14 @@ function match(value, cases, fallback, options) {
1922
2882
  fallback = void 0;
1923
2883
  }
1924
2884
  const fallbackNode = fallback;
1925
- const focusPolicy = options?.focus;
1926
- const anchor = document.createComment("match");
1927
- const scope = captureScope();
1928
- let currentNode = null;
1929
- let lastKey;
1930
- let initialized = false;
1931
- let disposed = false;
1932
- const attachedOnce = /* @__PURE__ */ new WeakSet();
1933
- let currentNodeOwned = false;
1934
- const update = () => {
1935
- if (disposed) return;
1936
- const key = String(value());
1937
- const parent = anchor.parentNode;
1938
- if (!parent) return;
1939
- if (initialized && key === lastKey) return;
1940
- lastKey = key;
1941
- const focused = currentNode ? captureFocusWithin([currentNode]) : null;
1942
- if (currentNode?.parentNode) {
1943
- releaseBranchNode(currentNode, currentNodeOwned);
1944
- currentNode = null;
1945
- }
1946
- const branch = Object.hasOwn(cases, key) ? cases[key] : fallbackNode;
1947
- const attached = untracked(
1948
- () => inScope(scope, () => attachBranch(parent, anchor, branch ?? null, attachedOnce, "match"))
1949
- );
1950
- currentNode = attached.node;
1951
- currentNodeOwned = attached.owned;
1952
- restoreFocusWithin(focused, currentNode ? [currentNode] : [], "match", focusPolicy);
1953
- initialized = true;
1954
- };
1955
- const binding = structuralBinding(update, anchor);
1956
- registerDisposer(anchor, () => {
1957
- disposed = true;
1958
- binding.stop();
1959
- if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
1960
- currentNode = null;
1961
- });
1962
- if (!initialized) {
1963
- queueMicrotask(
1964
- bindOwnerScope(() => {
1965
- if (!disposed && !initialized && anchor.parentNode) binding.run(update);
1966
- })
1967
- );
1968
- }
1969
- return anchor;
2885
+ return directive(
2886
+ "match",
2887
+ () => String(value()),
2888
+ // `Object.hasOwn` rather than `||` so a case whose value is legitimately
2889
+ // falsy (an empty string, 0) still wins over the fallback.
2890
+ (key) => Object.hasOwn(cases, key) ? cases[key] : fallbackNode ?? null,
2891
+ options
2892
+ );
1970
2893
  }
1971
2894
 
1972
2895
  // src/core/rendering/clientOnly.ts
@@ -2109,6 +3032,14 @@ function longestIncreasingSubsequence(arr, len) {
2109
3032
  }
2110
3033
  return result;
2111
3034
  }
3035
+ var renderingRow = null;
3036
+ var warnedReadSites = /* @__PURE__ */ new Set();
3037
+ function withPeek(get) {
3038
+ const state = get.__signal;
3039
+ const cell = get;
3040
+ cell.peek = () => state.value;
3041
+ return cell;
3042
+ }
2112
3043
  function each(getArray, render, options) {
2113
3044
  devAssert(typeof getArray === "function", "each: first argument must be a function that returns an array.");
2114
3045
  devAssert(typeof render === "function", "each: second argument must be a render function.");
@@ -2187,13 +3118,40 @@ function each(getArray, render, options) {
2187
3118
  } else {
2188
3119
  const [itemGetter, setItem] = signal(arr[i2]);
2189
3120
  const [indexGetter, setIndex] = signal(i2);
3121
+ const item = withPeek(itemGetter);
3122
+ const index = withPeek(indexGetter);
3123
+ let reads = null;
3124
+ let renderItem = item;
3125
+ let renderIndex = index;
3126
+ let outerRow = null;
3127
+ devWarnLazy(() => {
3128
+ const rowReads = { item: null, index: null };
3129
+ const recording = (get, slot2) => {
3130
+ const read = (() => {
3131
+ if (renderingRow === rowReads && rowReads[slot2] === null && isTrackingSuspended()) {
3132
+ rowReads[slot2] = new Error();
3133
+ }
3134
+ return get();
3135
+ });
3136
+ read.peek = get.peek;
3137
+ read.__signal = get.__signal;
3138
+ return read;
3139
+ };
3140
+ reads = rowReads;
3141
+ renderItem = recording(item, "item");
3142
+ renderIndex = recording(index, "index");
3143
+ return "";
3144
+ });
2190
3145
  let node;
2191
3146
  try {
2192
3147
  suspendTracking();
3148
+ outerRow = renderingRow;
3149
+ renderingRow = reads;
2193
3150
  try {
2194
- node = resolveNodeChild(inScope(keyedScope(scope, key), () => render(itemGetter, indexGetter)));
3151
+ node = resolveNodeChild(inScope(keyedScope(scope, key), () => render(renderItem, renderIndex)));
2195
3152
  } finally {
2196
3153
  resumeTracking();
3154
+ renderingRow = outerRow;
2197
3155
  }
2198
3156
  } catch (err) {
2199
3157
  const key2 = newKeys[i2];
@@ -2206,7 +3164,7 @@ function each(getArray, render, options) {
2206
3164
  });
2207
3165
  });
2208
3166
  }
2209
- row = { node, item: itemGetter, setItem, index: indexGetter, setIndex };
3167
+ row = { node, item, setItem, index, setIndex, reads };
2210
3168
  }
2211
3169
  workMap.set(key, row);
2212
3170
  newNodes[i2] = row.node;
@@ -2284,6 +3242,7 @@ function each(getArray, render, options) {
2284
3242
  batch(() => {
2285
3243
  for (let i2 = 0; i2 < count; i2++) {
2286
3244
  const row = pendingRows[i2];
3245
+ if (row.reads !== null) warnStaleRead(row, pendingItems[i2], pendingIndices[i2]);
2287
3246
  row.setItem(pendingItems[i2]);
2288
3247
  row.setIndex(pendingIndices[i2]);
2289
3248
  pendingRows[i2] = void 0;
@@ -2291,7 +3250,29 @@ function each(getArray, render, options) {
2291
3250
  }
2292
3251
  });
2293
3252
  }
2294
- const binding = structuralBinding(update);
3253
+ function warnStaleRead(row, nextItem, nextIndex) {
3254
+ devWarnLazy(() => {
3255
+ const reads = row.reads;
3256
+ let site = null;
3257
+ let which = "";
3258
+ if (reads.item !== null && !Object.is(row.item.peek(), nextItem)) {
3259
+ site = reads.item;
3260
+ which = "item";
3261
+ reads.item = null;
3262
+ } else if (reads.index !== null && row.index.peek() !== nextIndex) {
3263
+ site = reads.index;
3264
+ which = "index";
3265
+ reads.index = null;
3266
+ }
3267
+ if (site === null) return "";
3268
+ const frames = (site.stack ?? "").split("\n").filter((line2) => /^\s*at\s|@/.test(line2));
3269
+ const at = (frames[1] ?? frames[0] ?? "").trim().replace(/^at\s+/, "") || "unknown location";
3270
+ if (warnedReadSites.has(at)) return "";
3271
+ if (warnedReadSites.size < 100) warnedReadSites.add(at);
3272
+ 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})`;
3273
+ });
3274
+ }
3275
+ const binding = structuralBinding(update, anchor);
2295
3276
  const untrack = binding.stop;
2296
3277
  const disposeRange = () => {
2297
3278
  if (rangeDisposed) return;
@@ -2314,13 +3295,15 @@ function each(getArray, render, options) {
2314
3295
  pendingCount = 0;
2315
3296
  };
2316
3297
  registerDisposer(anchor, disposeRange);
3298
+ registerRange(anchor, () => sentinelInserted ? end : null);
2317
3299
  if (!initialized) {
2318
- queueMicrotask(
3300
+ const frozen = captureFrozen();
3301
+ queueFirstRender(
3302
+ anchor,
2319
3303
  bindOwnerScope(() => {
2320
- if (!initialized && !rangeDisposed && anchor.parentNode) {
2321
- binding.run(update);
2322
- }
2323
- })
3304
+ if (!initialized && !rangeDisposed && anchor.parentNode) binding.run(update);
3305
+ }),
3306
+ frozen
2324
3307
  );
2325
3308
  }
2326
3309
  return anchor;
@@ -2364,7 +3347,7 @@ function appendChild(frag, child) {
2364
3347
  if (typeof child === "function") {
2365
3348
  const placeholder = document.createComment("");
2366
3349
  frag.appendChild(placeholder);
2367
- registerDisposer(placeholder, bindChildNode(placeholder, child));
3350
+ registerDisposer(placeholder, bindChildNode(placeholder, child, true));
2368
3351
  return;
2369
3352
  }
2370
3353
  frag.appendChild(document.createTextNode(String(child)));
@@ -2813,13 +3796,17 @@ function KeepAlive(activeKey, cases, options) {
2813
3796
  currentNode = node;
2814
3797
  initialized = true;
2815
3798
  };
2816
- const binding = structuralBinding(update);
3799
+ const binding = structuralBinding(update, anchor);
3800
+ registerNodesRange(anchor, () => [currentNode]);
2817
3801
  const untrack = binding.stop;
2818
3802
  if (!initialized) {
2819
- queueMicrotask(
3803
+ const frozen = captureFrozen();
3804
+ queueFirstRender(
3805
+ anchor,
2820
3806
  bindOwnerScope(() => {
2821
3807
  if (!initialized && anchor.parentNode) binding.run(update);
2822
- })
3808
+ }),
3809
+ frozen
2823
3810
  );
2824
3811
  }
2825
3812
  registerDisposer(anchor, () => {
@@ -2847,8 +3834,8 @@ function mount(component, container) {
2847
3834
  typeof component === "function" || component instanceof Node,
2848
3835
  "mount: first argument must be a component function or a DOM Node."
2849
3836
  );
2850
- const now = () => typeof performance !== "undefined" ? performance.now() : 0;
2851
- const startTime = now();
3837
+ const now2 = () => typeof performance !== "undefined" ? performance.now() : 0;
3838
+ const startTime = now2();
2852
3839
  let range = null;
2853
3840
  const attach = (built) => {
2854
3841
  if (built instanceof DocumentFragment) {
@@ -2871,7 +3858,7 @@ function mount(component, container) {
2871
3858
  node = component;
2872
3859
  attach(node);
2873
3860
  }
2874
- const duration = now() - startTime;
3861
+ const duration = now2() - startTime;
2875
3862
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2876
3863
  if (hook) emitDevtools(hook, "app:init", { rootElement: node, container, duration });
2877
3864
  const mounted = range;
@@ -2919,6 +3906,123 @@ function unmountRange(start, end) {
2919
3906
  end.parentNode?.removeChild(end);
2920
3907
  }
2921
3908
 
3909
+ // src/core/signals/lifecycleScope.ts
3910
+ var STATES = ["active", "paused", "ended"];
3911
+ var ENDED = 2;
3912
+ var NOOP3 = () => {
3913
+ };
3914
+ var scopeOwners = globalSingleton(
3915
+ /* @__PURE__ */ Symbol.for("sibujs.lifecycleScope.owners.v1"),
3916
+ () => /* @__PURE__ */ new WeakMap()
3917
+ );
3918
+ function scopeOwner(scope) {
3919
+ return scopeOwners.get(scope);
3920
+ }
3921
+ function lifecycleScope() {
3922
+ const held = captureFrozen();
3923
+ const inOwnerScope = bindOwnerScope((fn) => fn());
3924
+ const ended = () => held.state() === ENDED;
3925
+ const own = (register) => {
3926
+ let disposed = false;
3927
+ let stop2 = null;
3928
+ let dropWait = NOOP3;
3929
+ let dropEnd = NOOP3;
3930
+ const dispose2 = () => {
3931
+ if (disposed) return;
3932
+ disposed = true;
3933
+ dropWait();
3934
+ dropEnd();
3935
+ const running = stop2;
3936
+ stop2 = null;
3937
+ running?.();
3938
+ };
3939
+ const start = () => {
3940
+ dropWait = NOOP3;
3941
+ if (disposed) return;
3942
+ dropEnd = held.onEnd(dispose2);
3943
+ if (disposed) return;
3944
+ let created;
3945
+ try {
3946
+ created = held.run(() => inOwnerScope(register));
3947
+ } catch (err) {
3948
+ disposed = true;
3949
+ dropEnd();
3950
+ dropEnd = NOOP3;
3951
+ throw err;
3952
+ }
3953
+ if (disposed) created();
3954
+ else stop2 = created;
3955
+ };
3956
+ const state = held.state();
3957
+ if (state === ENDED) disposed = true;
3958
+ else if (state === 1) dropWait = held.wait(start, dispose2);
3959
+ else start();
3960
+ return dispose2;
3961
+ };
3962
+ const onState = (want, callback) => held.onChange((state) => {
3963
+ if (state === want) held.run(() => inOwnerScope(callback));
3964
+ });
3965
+ const scope = {
3966
+ state: () => STATES[held.state()],
3967
+ own,
3968
+ onPause: (callback) => onState(1, callback),
3969
+ onResume: (callback) => onState(0, callback),
3970
+ // The guards are the liveness check of a registration whose owner ended
3971
+ // while its own run was in progress (a body that ends its branch and
3972
+ // re-runs itself); `own` disposes it as soon as that run returns.
3973
+ effect: (fn, options) => own(
3974
+ () => effect((onCleanup2) => {
3975
+ if (!ended()) fn(onCleanup2);
3976
+ }, options)
3977
+ ),
3978
+ watch: (getter, callback) => own(
3979
+ () => watch(getter, (value, prev) => {
3980
+ if (!ended()) callback(value, prev);
3981
+ })
3982
+ )
3983
+ };
3984
+ scopeOwners.set(scope, held);
3985
+ return scope;
3986
+ }
3987
+
3988
+ // src/core/rendering/pendingContent.ts
3989
+ var INERT = { done: () => {
3990
+ }, cancel: () => {
3991
+ }, settled: true };
3992
+ function pendingContent(at) {
3993
+ if (isServer()) return INERT;
3994
+ const isNode = typeof at.nodeType === "number";
3995
+ const held = isNode ? null : scopeOwner(at) ?? null;
3996
+ if (!isNode && (held === null || held.state() === 2)) return INERT;
3997
+ const { entry, done, cancel: cancelEntry } = beginPending(isNode ? at : null, held);
3998
+ let drop = () => {
3999
+ };
4000
+ const cancel = () => {
4001
+ if (entry.settled) return;
4002
+ drop();
4003
+ cancelEntry();
4004
+ };
4005
+ if (isNode) {
4006
+ registerDisposer(at, cancel);
4007
+ drop = () => {
4008
+ unregisterDisposer(at, cancel);
4009
+ };
4010
+ } else drop = held.onEnd(cancel);
4011
+ return {
4012
+ done: (committed) => {
4013
+ if (entry.settled) return;
4014
+ drop();
4015
+ done(
4016
+ committed === void 0 ? null : typeof committed.nodeType === "number" ? [committed] : [...committed]
4017
+ );
4018
+ },
4019
+ cancel,
4020
+ get settled() {
4021
+ return entry.settled;
4022
+ }
4023
+ };
4024
+ }
4025
+
2922
4026
  // src/core/rendering/portal.ts
2923
4027
  function Portal(nodes, target) {
2924
4028
  requireDocument();
@@ -4047,6 +5151,9 @@ export {
4047
5151
  __renderParsedTemplate,
4048
5152
  KeepAlive,
4049
5153
  mount,
5154
+ scopeOwner,
5155
+ lifecycleScope,
5156
+ pendingContent,
4050
5157
  Portal,
4051
5158
  getSlot,
4052
5159
  array,