sibujs 1.4.0 → 2.0.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 (190) hide show
  1. package/README.md +105 -119
  2. package/dist/browser.cjs +288 -80
  3. package/dist/browser.d.cts +19 -9
  4. package/dist/browser.d.ts +19 -9
  5. package/dist/browser.js +6 -6
  6. package/dist/build.cjs +1019 -313
  7. package/dist/build.d.cts +1 -1
  8. package/dist/build.d.ts +1 -1
  9. package/dist/build.js +15 -13
  10. package/dist/cdn.global.js +17 -16
  11. package/dist/chunk-2RA7SHDA.js +65 -0
  12. package/dist/chunk-2UPRY23K.js +80 -0
  13. package/dist/chunk-3JHCYHWN.js +125 -0
  14. package/dist/{chunk-ZWKZCBO6.js → chunk-3LR7GLWQ.js} +154 -33
  15. package/dist/{chunk-3AIRKM3B.js → chunk-3NSGB5JN.js} +115 -34
  16. package/dist/{chunk-3ARAQO7B.js → chunk-52YJLLRO.js} +29 -6
  17. package/dist/chunk-54EDRCEF.js +93 -0
  18. package/dist/chunk-7JDB7I65.js +1327 -0
  19. package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
  20. package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
  21. package/dist/{chunk-WR5D4EGH.js → chunk-GTBNNBJ6.js} +14 -2
  22. package/dist/chunk-HB24TBAF.js +121 -0
  23. package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
  24. package/dist/{chunk-JAKHTMQU.js → chunk-JA6667UN.js} +206 -46
  25. package/dist/{chunk-77L6NL3X.js → chunk-JXMMDLBY.js} +306 -183
  26. package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
  27. package/dist/{chunk-F3FA4F32.js → chunk-KLRMB5ZS.js} +135 -79
  28. package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
  29. package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
  30. package/dist/{chunk-TSOKIX5Z.js → chunk-MIUAXB7K.js} +126 -74
  31. package/dist/{chunk-QWZG56ET.js → chunk-ND2664SF.js} +558 -190
  32. package/dist/{chunk-JCI5M6U6.js → chunk-O2MNQFLP.js} +261 -79
  33. package/dist/{chunk-EWFVA3TJ.js → chunk-R73P76YZ.js} +1 -1
  34. package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
  35. package/dist/chunk-UCS6AMJ7.js +79 -0
  36. package/dist/{chunk-ZD6OAMTH.js → chunk-VLPPXTYG.js} +90 -35
  37. package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
  38. package/dist/{contracts-xo5ckdRP.d.cts → contracts-ey_Qh8ef.d.cts} +7 -8
  39. package/dist/{contracts-xo5ckdRP.d.ts → contracts-ey_Qh8ef.d.ts} +7 -8
  40. package/dist/{customElement-D2DJp_xn.d.cts → customElement-CPfIrbvg.d.cts} +18 -9
  41. package/dist/{customElement-D2DJp_xn.d.ts → customElement-CPfIrbvg.d.ts} +18 -9
  42. package/dist/data.cjs +452 -100
  43. package/dist/data.d.cts +20 -2
  44. package/dist/data.d.ts +20 -2
  45. package/dist/data.js +11 -9
  46. package/dist/devtools.cjs +535 -247
  47. package/dist/devtools.d.cts +1 -1
  48. package/dist/devtools.d.ts +1 -1
  49. package/dist/devtools.js +34 -30
  50. package/dist/ecosystem.cjs +499 -143
  51. package/dist/ecosystem.d.cts +13 -11
  52. package/dist/ecosystem.d.ts +13 -11
  53. package/dist/ecosystem.js +12 -11
  54. package/dist/extras.cjs +3639 -1629
  55. package/dist/extras.d.cts +11 -11
  56. package/dist/extras.d.ts +11 -11
  57. package/dist/extras.js +58 -45
  58. package/dist/index.cjs +1023 -313
  59. package/dist/index.d.cts +128 -55
  60. package/dist/index.d.ts +128 -55
  61. package/dist/index.js +28 -16
  62. package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
  63. package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
  64. package/dist/motion.cjs +90 -36
  65. package/dist/motion.d.cts +1 -1
  66. package/dist/motion.d.ts +1 -1
  67. package/dist/motion.js +4 -4
  68. package/dist/patterns.cjs +414 -81
  69. package/dist/patterns.d.cts +53 -20
  70. package/dist/patterns.d.ts +53 -20
  71. package/dist/patterns.js +7 -7
  72. package/dist/performance.cjs +364 -108
  73. package/dist/performance.d.cts +29 -17
  74. package/dist/performance.d.ts +29 -17
  75. package/dist/performance.js +13 -6
  76. package/dist/plugin-D30wlGW5.d.cts +71 -0
  77. package/dist/plugin-D30wlGW5.d.ts +71 -0
  78. package/dist/plugins.cjs +652 -271
  79. package/dist/plugins.d.cts +13 -6
  80. package/dist/plugins.d.ts +13 -6
  81. package/dist/plugins.js +116 -50
  82. package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
  83. package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
  84. package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
  85. package/dist/ssr.cjs +648 -219
  86. package/dist/ssr.d.cts +27 -7
  87. package/dist/ssr.d.ts +27 -7
  88. package/dist/ssr.js +12 -11
  89. package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.cts} +9 -1
  90. package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.ts} +9 -1
  91. package/dist/testing.cjs +252 -63
  92. package/dist/testing.d.cts +17 -4
  93. package/dist/testing.d.ts +17 -4
  94. package/dist/testing.js +100 -44
  95. package/dist/ui.cjs +576 -168
  96. package/dist/ui.d.cts +13 -16
  97. package/dist/ui.d.ts +13 -16
  98. package/dist/ui.js +20 -17
  99. package/dist/widgets.cjs +1001 -93
  100. package/dist/widgets.d.cts +104 -2
  101. package/dist/widgets.d.ts +104 -2
  102. package/dist/widgets.js +9 -7
  103. package/package.json +8 -2
  104. package/dist/chunk-32DY64NT.js +0 -282
  105. package/dist/chunk-3CRQALYP.js +0 -877
  106. package/dist/chunk-4EI4AG32.js +0 -482
  107. package/dist/chunk-4MYMUBRS.js +0 -21
  108. package/dist/chunk-6HLLIF3K.js +0 -398
  109. package/dist/chunk-6LSNVCS2.js +0 -937
  110. package/dist/chunk-6SA3QQES.js +0 -61
  111. package/dist/chunk-7BF6TK55.js +0 -1097
  112. package/dist/chunk-7TQKR4PP.js +0 -294
  113. package/dist/chunk-7V26P53V.js +0 -712
  114. package/dist/chunk-AZ3ISID5.js +0 -298
  115. package/dist/chunk-B7SWRFUT.js +0 -332
  116. package/dist/chunk-BGN5ZMP4.js +0 -26
  117. package/dist/chunk-BTU3TJDS.js +0 -365
  118. package/dist/chunk-BW3WT46K.js +0 -937
  119. package/dist/chunk-C6KFWOFV.js +0 -616
  120. package/dist/chunk-CHF5OHIA.js +0 -61
  121. package/dist/chunk-CHJ27IGK.js +0 -26
  122. package/dist/chunk-CMBFNA7L.js +0 -27
  123. package/dist/chunk-DAHRH4ON.js +0 -331
  124. package/dist/chunk-DKOHBI74.js +0 -924
  125. package/dist/chunk-DTCOOBMX.js +0 -725
  126. package/dist/chunk-EBGIRKQY.js +0 -616
  127. package/dist/chunk-EUZND3CB.js +0 -27
  128. package/dist/chunk-EVCZO745.js +0 -365
  129. package/dist/chunk-FGOEVHY3.js +0 -60
  130. package/dist/chunk-G3BOQPVO.js +0 -365
  131. package/dist/chunk-GCOK2LC3.js +0 -282
  132. package/dist/chunk-HGMJFBC7.js +0 -654
  133. package/dist/chunk-K5ZUMYVS.js +0 -89
  134. package/dist/chunk-KQPDEVVS.js +0 -398
  135. package/dist/chunk-L6JRBDNS.js +0 -60
  136. package/dist/chunk-LA6KQEDU.js +0 -712
  137. package/dist/chunk-MDVXJWFN.js +0 -304
  138. package/dist/chunk-MEZVEBPN.js +0 -2008
  139. package/dist/chunk-MK4ERFYL.js +0 -2249
  140. package/dist/chunk-MLKGABMK.js +0 -9
  141. package/dist/chunk-MQ5GOYPH.js +0 -2249
  142. package/dist/chunk-N6IZB6KJ.js +0 -567
  143. package/dist/chunk-NEKUBFPT.js +0 -60
  144. package/dist/chunk-NHUC2QWH.js +0 -282
  145. package/dist/chunk-NMRUZALC.js +0 -1097
  146. package/dist/chunk-NYVAC6P5.js +0 -37
  147. package/dist/chunk-OF7UZIVB.js +0 -725
  148. package/dist/chunk-P6W3STU4.js +0 -2249
  149. package/dist/chunk-PBHF5WKN.js +0 -616
  150. package/dist/chunk-PTQJDMRT.js +0 -146
  151. package/dist/chunk-PZEGYCF5.js +0 -61
  152. package/dist/chunk-QBMDLBU2.js +0 -975
  153. package/dist/chunk-RQGQSLQK.js +0 -725
  154. package/dist/chunk-SDLZDHKP.js +0 -107
  155. package/dist/chunk-TNQWPPE6.js +0 -37
  156. package/dist/chunk-UHNL42EF.js +0 -2730
  157. package/dist/chunk-UNXCEF6S.js +0 -21
  158. package/dist/chunk-V2XTI523.js +0 -347
  159. package/dist/chunk-VAU366PN.js +0 -2241
  160. package/dist/chunk-VMVDTCXB.js +0 -712
  161. package/dist/chunk-VRW3FULF.js +0 -725
  162. package/dist/chunk-WADYRCO2.js +0 -304
  163. package/dist/chunk-WILQZRO4.js +0 -282
  164. package/dist/chunk-WUHJISPP.js +0 -298
  165. package/dist/chunk-XYU6TZOW.js +0 -182
  166. package/dist/chunk-Y6GP4QGG.js +0 -276
  167. package/dist/chunk-YECR7UIA.js +0 -347
  168. package/dist/chunk-YUTWTI4B.js +0 -654
  169. package/dist/chunk-Z65KYU7I.js +0 -26
  170. package/dist/chunk-Z6POF5YC.js +0 -975
  171. package/dist/chunk-ZBJP6WFL.js +0 -482
  172. package/dist/contracts-DDrwxvJ-.d.cts +0 -245
  173. package/dist/contracts-DDrwxvJ-.d.ts +0 -245
  174. package/dist/contracts-DOrhwbke.d.cts +0 -245
  175. package/dist/contracts-DOrhwbke.d.ts +0 -245
  176. package/dist/customElement-BKQfbSZQ.d.cts +0 -262
  177. package/dist/customElement-BKQfbSZQ.d.ts +0 -262
  178. package/dist/customElement-yz8uyk-0.d.cts +0 -308
  179. package/dist/customElement-yz8uyk-0.d.ts +0 -308
  180. package/dist/introspect-Cb0zgpi2.d.cts +0 -477
  181. package/dist/introspect-Y2xNXGSf.d.ts +0 -477
  182. package/dist/plugin-Bek4RhJY.d.cts +0 -43
  183. package/dist/plugin-Bek4RhJY.d.ts +0 -43
  184. package/dist/ssr-3RXHP5ES.js +0 -38
  185. package/dist/ssr-6GIMY5MX.js +0 -38
  186. package/dist/ssr-BA6sxxUd.d.cts +0 -135
  187. package/dist/ssr-BA6sxxUd.d.ts +0 -135
  188. package/dist/ssr-WKUPVSSK.js +0 -36
  189. package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
  190. package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
- import { T as TagProps, N as NodeChildren, a as NodeChild } from './tagFactory-DaJ0YWX6.cjs';
2
- export { S as SVG_NS, t as tagFactory } from './tagFactory-DaJ0YWX6.cjs';
1
+ import { T as TagProps, N as NodeChildren, a as NodeChild } from './tagFactory-S17H2qxu.cjs';
2
+ export { D as Dispose, S as SVG_NS, t as tagFactory } from './tagFactory-S17H2qxu.cjs';
3
3
  import { R as ReactiveSignal } from './signal-BnWpq6WB.cjs';
4
+ export { T as TrustedHTML, t as trustHTML } from './ssr-CrVNy6Pa.cjs';
4
5
 
5
6
  type reactive<T> = T | (() => T);
6
7
  interface AnchorProps extends TagProps {
@@ -319,14 +320,12 @@ declare function each<T>(getArray: () => T[], render: (item: () => T, index: ()
319
320
  *
320
321
  * @example
321
322
  * ```ts
322
- * div({
323
- * nodes: [
324
- * Fragment([
325
- * p({ nodes: "First" }),
326
- * p({ nodes: "Second" }),
327
- * ])
328
- * ]
329
- * });
323
+ * div([
324
+ * Fragment([
325
+ * p("First"),
326
+ * p("Second"),
327
+ * ])
328
+ * ]);
330
329
  * ```
331
330
  *
332
331
  * @param nodes Array of child nodes to include in the fragment
@@ -338,6 +337,10 @@ declare function Fragment(nodes: NodeChildren[]): DocumentFragment;
338
337
  * Portal renders nodes into a DOM node outside the parent component hierarchy.
339
338
  * Useful for modals, tooltips, dropdowns, and overlays.
340
339
  *
340
+ * Cleanup integrates with `dispose()` / `registerDisposer()` so portals
341
+ * are properly torn down when the anchor is disposed by `when()`, `match()`,
342
+ * `each()`, or manual `dispose(anchor)`.
343
+ *
341
344
  * @param nodes Function that returns the content to render
342
345
  * @param target Target DOM element (defaults to document.body)
343
346
  * @returns A Comment anchor node in the original position
@@ -345,11 +348,11 @@ declare function Fragment(nodes: NodeChildren[]): DocumentFragment;
345
348
  * @example
346
349
  * ```ts
347
350
  * // Render modal at document.body
348
- * Portal(() => div({ class: "modal", nodes: "Modal content" }));
351
+ * Portal(() => div("modal", "Modal content"));
349
352
  *
350
353
  * // Render into specific container
351
354
  * const overlay = document.getElementById("overlay-root")!;
352
- * Portal(() => div({ nodes: "Tooltip" }), overlay);
355
+ * Portal(() => div("Tooltip"), overlay);
353
356
  * ```
354
357
  */
355
358
  declare function Portal(nodes: () => HTMLElement, target?: HTMLElement): Comment;
@@ -382,7 +385,7 @@ declare function unregisterComponent(name: string): void;
382
385
  * @example
383
386
  * ```ts
384
387
  * registerComponent("Widget", MyWidget);
385
- * div({ nodes: [resolveComponent("Widget")] });
388
+ * div([resolveComponent("Widget")]);
386
389
  * ```
387
390
  */
388
391
  declare function resolveComponent(name: string): HTMLElement;
@@ -418,7 +421,7 @@ declare function getSlot(slots: Slots | undefined, name?: string): SlotFn | unde
418
421
  * @example
419
422
  * ```ts
420
423
  * const [visible, setVisible] = signal(true);
421
- * div({ nodes: [show(() => visible(), span({ nodes: "I toggle!" }))] });
424
+ * div([show(() => visible(), span("I toggle!"))]);
422
425
  * ```
423
426
  */
424
427
  declare function show<T extends Element>(condition: () => boolean, element: T): T;
@@ -435,8 +438,8 @@ declare function show<T extends Element>(condition: () => boolean, element: T):
435
438
  * ```ts
436
439
  * when(
437
440
  * () => isLoggedIn(),
438
- * () => div({ nodes: "Welcome!" }),
439
- * () => div({ nodes: "Please log in" })
441
+ * () => div("Welcome!"),
442
+ * () => div("Please log in")
440
443
  * );
441
444
  * ```
442
445
  */
@@ -459,7 +462,7 @@ declare function when<T>(condition: () => T, thenBranch: () => NodeChild, elseBr
459
462
  * error: () => ErrorMessage(),
460
463
  * success: () => Content(),
461
464
  * },
462
- * () => div({ nodes: "Unknown status" })
465
+ * () => div("Unknown status")
463
466
  * );
464
467
  * ```
465
468
  */
@@ -527,8 +530,7 @@ type ActionFn<T = void> = (element: HTMLElement, param: T) => (() => void) | und
527
530
  * action(el, clickOutside, () => setOpen(false));
528
531
  * action(el, longPress, { duration: 500, callback: onLongPress });
529
532
  * },
530
- * nodes: "Content",
531
- * });
533
+ * }, "Content");
532
534
  * ```
533
535
  */
534
536
  declare function action<T>(element: HTMLElement, actionFn: ActionFn<T>, param: T): void;
@@ -636,10 +638,10 @@ declare function setGlobalErrorHandler(handler: ErrorHandler): void;
636
638
  * ```ts
637
639
  * function Field(labelText: string) {
638
640
  * const id = createId("field");
639
- * return div({ nodes: [
640
- * label({ for: id, nodes: labelText }),
641
+ * return div([
642
+ * label({ for: id }, labelText),
641
643
  * input({ id }),
642
- * ]});
644
+ * ]);
643
645
  * }
644
646
  * ```
645
647
  */
@@ -681,9 +683,9 @@ declare const __accessor: unique symbol;
681
683
  * ```ts
682
684
  * const [count, setCount] = signal(0);
683
685
  *
684
- * div({ nodes: count }) // ✓ reactive — Accessor passed directly
685
- * div({ nodes: () => count() }) // ✓ reactive — explicit arrow wrapper
686
- * div({ nodes: count() }) // ✗ static — evaluated once, not reactive
686
+ * div(count) // ✓ reactive — Accessor passed directly
687
+ * div(() => count()) // ✓ reactive — explicit arrow wrapper
688
+ * div(count()) // ✗ static — evaluated once, not reactive
687
689
  * ```
688
690
  */
689
691
  type Accessor<T> = (() => T) & {
@@ -733,14 +735,29 @@ interface EffectOptions {
733
735
  * ```
734
736
  */
735
737
  declare function on<T>(deps: () => T, handler: (value: T, prev: T | undefined) => void): () => void;
738
+ /** Registers a function to run before the effect re-runs or is disposed.
739
+ * Called with the same signature inside every invocation. */
740
+ type OnCleanup = (fn: () => void) => void;
741
+ /** The user's effect body — may accept an `onCleanup` callback to register
742
+ * teardown that runs before the next re-run or on dispose. */
743
+ type EffectBody = (onCleanup: OnCleanup) => void;
736
744
  /**
737
745
  * effect runs the provided effectFn immediately and re-runs it whenever
738
746
  * any reactive dependency changes.
739
747
  * Returns a cleanup function to stop further executions.
740
748
  *
741
749
  * In SSR mode, effect is a no-op — side effects should not run on the server.
750
+ *
751
+ * @example addEventListener pattern with built-in teardown:
752
+ * ```ts
753
+ * effect((onCleanup) => {
754
+ * const handler = (e: Event) => { ... };
755
+ * window.addEventListener("resize", handler);
756
+ * onCleanup(() => window.removeEventListener("resize", handler));
757
+ * });
758
+ * ```
742
759
  */
743
- declare function effect(effectFn: () => void, options?: EffectOptions): () => void;
760
+ declare function effect(effectFn: EffectBody | (() => void), options?: EffectOptions): () => void;
744
761
 
745
762
  /**
746
763
  * derived creates a derived reactive signal whose value updates when dependencies change.
@@ -754,6 +771,9 @@ declare function effect(effectFn: () => void, options?: EffectOptions): () => vo
754
771
  */
755
772
  declare function derived<T>(getter: () => T, options?: {
756
773
  name?: string;
774
+ /** Custom equality — when the recomputed value equals the previous,
775
+ * downstream subscribers are not notified. Defaults to `Object.is`. */
776
+ equals?: (a: T, b: T) => boolean;
757
777
  }): Accessor<T>;
758
778
 
759
779
  /**
@@ -903,16 +923,23 @@ declare function reactiveArray<T>(initial?: T[]): [Accessor<readonly T[]>, Array
903
923
  /**
904
924
  * Deep equality comparison for objects and arrays.
905
925
  * Falls back to Object.is for primitives.
906
- * Handles circular references and common built-in types (Date, RegExp).
926
+ * Handles circular references, shared sub-references, and common
927
+ * built-in types (Date, RegExp, Map, Set, ArrayBuffer, TypedArrays).
928
+ *
929
+ * The `seen` parameter tracks `(a, b)` pairs — not just `a` — so that
930
+ * a shared sub-object compared against two different partners is always
931
+ * fully checked, while genuine cycles (same a-with-same-b revisited)
932
+ * still terminate.
907
933
  */
908
- declare function deepEqual(a: unknown, b: unknown, seen?: Set<unknown>): boolean;
934
+ declare function deepEqual(a: unknown, b: unknown, seen?: Map<object, Set<object>>): boolean;
909
935
  /**
910
936
  * Like signal but uses deep equality comparison instead of Object.is.
911
937
  * This prevents unnecessary re-renders when setting an object/array
912
938
  * to a structurally identical value.
913
939
  *
914
940
  * @param initial Initial value
915
- * @returns Tuple [getter, setter]
941
+ * @returns Tuple [getter, setter] — same shape as `signal()`, preserving
942
+ * the `Accessor<T>` brand on the getter.
916
943
  *
917
944
  * @example
918
945
  * ```ts
@@ -921,7 +948,7 @@ declare function deepEqual(a: unknown, b: unknown, seen?: Set<unknown>): boolean
921
948
  * setUser({ name: "Bob", age: 25 }); // Notifies — different value
922
949
  * ```
923
950
  */
924
- declare function deepSignal<T>(initial: T): [() => T, (next: T | ((prev: T) => T)) => void];
951
+ declare function deepSignal<T>(initial: T): [Accessor<T>, (next: T | ((prev: T) => T)) => void];
925
952
 
926
953
  /**
927
954
  * Creates a writable computed value — a derived getter paired with
@@ -1017,7 +1044,7 @@ declare function asyncDerived<T>(factory: () => Promise<T>, initial: T): AsyncDe
1017
1044
  * console.log("Component was removed");
1018
1045
  * });
1019
1046
  *
1020
- * return div({ nodes: "Hello" });
1047
+ * return div("Hello");
1021
1048
  * }
1022
1049
  * ```
1023
1050
  */
@@ -1036,7 +1063,8 @@ type CleanupFn = () => void;
1036
1063
  declare function onMount(callback: () => undefined | CleanupFn, element?: HTMLElement): void;
1037
1064
  /**
1038
1065
  * Runs a callback when the given element is removed from the DOM.
1039
- * Uses MutationObserver to watch for disconnection.
1066
+ * Uses a shared MutationObserver to watch for disconnection, plus
1067
+ * `registerDisposer` so explicit dispose() paths also trigger the callback.
1040
1068
  *
1041
1069
  * @param callback Function to run on unmount
1042
1070
  * @param element The element to watch for removal
@@ -1054,7 +1082,7 @@ declare function onUnmount(callback: CleanupFn, element: HTMLElement): void;
1054
1082
  * ```ts
1055
1083
  * function RealtimeBar(siteId: string) {
1056
1084
  * const ws = new WebSocket(`/ws/sites/${siteId}/realtime`);
1057
- * const root = div({ nodes: "Realtime data..." });
1085
+ * const root = div("Realtime data...");
1058
1086
  * onCleanup(() => ws.close(), root);
1059
1087
  * return root;
1060
1088
  * }
@@ -1063,36 +1091,56 @@ declare function onUnmount(callback: CleanupFn, element: HTMLElement): void;
1063
1091
  declare function onCleanup(callback: CleanupFn, element: Node): void;
1064
1092
 
1065
1093
  /**
1066
- * Context API for SibuJS — provides dependency injection across
1067
- * component trees without prop drilling.
1094
+ * Context API for SibuJS — a reactive global value that any component
1095
+ * can read without prop drilling.
1096
+ *
1097
+ * Note: this is a **global reactive store**, not a subtree-scoped DI
1098
+ * system. Calling `provide()` sets the value for ALL consumers, not
1099
+ * just descendants of the provider. For most apps this is sufficient
1100
+ * — use separate `context()` instances for independent scopes.
1068
1101
  *
1069
1102
  * @example
1070
1103
  * ```ts
1071
1104
  * // Create a context with a default value
1072
1105
  * const ThemeContext = context("light");
1073
1106
  *
1074
- * // Provide a value at a parent level
1075
- * function App() {
1076
- * ThemeContext.provide("dark");
1077
- * return div({ nodes: [Child()] });
1078
- * }
1107
+ * // Set the value (global affects all consumers)
1108
+ * ThemeContext.provide("dark");
1079
1109
  *
1080
- * // Consume the value anywhere below
1110
+ * // Read reactively from any component
1081
1111
  * function Child() {
1082
1112
  * const theme = ThemeContext.use(); // reactive getter
1083
- * return div({ nodes: () => `Theme: ${theme()}` });
1113
+ * return div(() => `Theme: ${theme()}`);
1084
1114
  * }
1085
1115
  * ```
1086
1116
  */
1087
1117
  interface Context<T> {
1088
- /** Provide a value for this context. Overrides any parent provider. */
1089
- provide(value: T): void;
1118
+ /**
1119
+ * Set the context value globally. Affects all consumers.
1120
+ *
1121
+ * Returns a `restore` function that re-sets the context to the value it
1122
+ * had *before* this `provide` call. Useful for scoped overrides:
1123
+ *
1124
+ * ```ts
1125
+ * const restore = Theme.provide("dark");
1126
+ * try { renderChild(); } finally { restore(); }
1127
+ * ```
1128
+ *
1129
+ * Callers that don't need scoping can ignore the return value — existing
1130
+ * semantics are preserved.
1131
+ */
1132
+ provide(value: T): () => void;
1090
1133
  /** Get a reactive getter for the current context value. */
1091
1134
  use(): () => T;
1092
1135
  /** Get the current value directly (non-reactive). */
1093
1136
  get(): T;
1094
1137
  /** Update the provided value reactively. */
1095
1138
  set(value: T): void;
1139
+ /**
1140
+ * Run `fn` with the context temporarily set to `value`, then restore the
1141
+ * previous value (even if `fn` throws). Returns the result of `fn`.
1142
+ */
1143
+ withContext<R>(value: T, fn: () => R): R;
1096
1144
  }
1097
1145
  /**
1098
1146
  * Creates a new context with an optional default value.
@@ -1148,6 +1196,11 @@ declare function strictEffect(fn: () => void): () => void;
1148
1196
  * During server-side rendering, side effects (effect, watch, onMount)
1149
1197
  * should not run. This module provides a flag to enable/disable SSR mode.
1150
1198
  *
1199
+ * Concurrency: on Node we back the flag with AsyncLocalStorage so
1200
+ * simultaneous requests get independent SSR scopes. On runtimes without
1201
+ * AsyncLocalStorage (browser, some edge runtimes) we fall back to a
1202
+ * module-global boolean.
1203
+ *
1151
1204
  * Usage:
1152
1205
  * enableSSR(); // Call before rendering on the server
1153
1206
  * renderToString(...);
@@ -1155,13 +1208,30 @@ declare function strictEffect(fn: () => void): () => void;
1155
1208
  *
1156
1209
  * Or use the scoped helper:
1157
1210
  * withSSR(() => renderToString(...));
1211
+ * runInSSRContext(() => renderToString(...));
1212
+ */
1213
+ /**
1214
+ * Per-request SSR store. Currently holds the SSR flag plus a
1215
+ * suspense-id counter so concurrent streaming renders never collide.
1158
1216
  */
1217
+ interface SSRStore {
1218
+ ssr: boolean;
1219
+ suspenseIdCounter: number;
1220
+ }
1221
+ /** Returns the active store (ALS or fallback). */
1222
+ declare function getSSRStore(): SSRStore;
1159
1223
  /** Returns true when running in SSR mode. */
1160
1224
  declare function isSSR(): boolean;
1161
1225
  /** Enable SSR mode. Side effects (effect, watch, onMount) become no-ops. */
1162
1226
  declare function enableSSR(): void;
1163
1227
  /** Disable SSR mode. Side effects resume normal behavior. */
1164
1228
  declare function disableSSR(): void;
1229
+ /**
1230
+ * Run `fn` inside a fresh request-scoped SSR context. On Node this uses
1231
+ * AsyncLocalStorage so concurrent requests never share state; elsewhere
1232
+ * it falls back to mutating the module-global store.
1233
+ */
1234
+ declare function runInSSRContext<T>(fn: () => T): T;
1165
1235
  /**
1166
1236
  * Run a function in SSR mode. Automatically enables/disables SSR around the callback.
1167
1237
  * Returns whatever the callback returns.
@@ -1243,10 +1313,12 @@ declare function nextTick(): Promise<void>;
1243
1313
  * input({ on: { input: e => setQuery(e.target.value) } });
1244
1314
  *
1245
1315
  * // heavy list reads deferredQuery() and updates one frame later
1246
- * each(() => heavyFilter(items, deferredQuery()), row => li({ nodes: row.name }));
1316
+ * each(() => heavyFilter(items, deferredQuery()), row => li(row.name));
1247
1317
  * ```
1248
1318
  */
1249
- declare function defer<T>(getter: () => T): () => T;
1319
+ declare function defer<T>(getter: () => T): (() => T) & {
1320
+ dispose: () => void;
1321
+ };
1250
1322
  interface TransitionState {
1251
1323
  pending: () => boolean;
1252
1324
  start: (fn: () => void | Promise<void>) => void;
@@ -1296,6 +1368,7 @@ declare function untracked<T>(fn: () => T): T;
1296
1368
  */
1297
1369
  declare function bindDynamic(el: HTMLElement, nameGetter: string | (() => string), valueGetter: string | (() => unknown)): () => void;
1298
1370
 
1371
+ declare function takePendingError(node: Element): Error | undefined;
1299
1372
  type Component = () => HTMLElement;
1300
1373
  type LazyImport = () => Promise<{
1301
1374
  default: Component;
@@ -1312,7 +1385,7 @@ type LazyImport = () => Promise<{
1312
1385
  * // Use inside Suspense for custom loading UI
1313
1386
  * Suspense({
1314
1387
  * nodes: () => LazyDashboard(),
1315
- * fallback: () => div({ nodes: "Loading dashboard..." }),
1388
+ * fallback: () => div("Loading dashboard..."),
1316
1389
  * });
1317
1390
  *
1318
1391
  * // Or use standalone — shows default "Loading..." text
@@ -1330,7 +1403,7 @@ declare function lazy(importFn: LazyImport): Component;
1330
1403
  * ```ts
1331
1404
  * Suspense({
1332
1405
  * nodes: () => LazyChart(),
1333
- * fallback: () => div({ nodes: "Loading chart..." }),
1406
+ * fallback: () => div("Loading chart..."),
1334
1407
  * });
1335
1408
  * ```
1336
1409
  *
@@ -1370,7 +1443,7 @@ interface ErrorBoundaryProps {
1370
1443
  * const [route, setRoute] = signal("/");
1371
1444
  * ErrorBoundary({
1372
1445
  * resetKeys: [route],
1373
- * nodes: () => div({ nodes: riskyPageFor(route()) }),
1446
+ * nodes: () => div(riskyPageFor(route())),
1374
1447
  * });
1375
1448
  * ```
1376
1449
  */
@@ -1429,13 +1502,13 @@ interface ErrorDisplayProps {
1429
1502
  *
1430
1503
  * @example
1431
1504
  * ```ts
1432
- * button({
1433
- * on: { click: async () => {
1505
+ * button(
1506
+ * { on: { click: async () => {
1434
1507
  * try { await save(); }
1435
1508
  * catch (err) { mount(ErrorDisplay({ error: err, onRetry: save }), errorHost); }
1436
- * }},
1437
- * nodes: "Save",
1438
- * });
1509
+ * }}},
1510
+ * "Save",
1511
+ * );
1439
1512
  * ```
1440
1513
  */
1441
1514
  declare function ErrorDisplay(props: ErrorDisplayProps): Element;
@@ -1461,4 +1534,4 @@ interface LoadingProps {
1461
1534
  */
1462
1535
  declare function Loading(props?: LoadingProps): HTMLElement;
1463
1536
 
1464
- export { type Accessor, type ActionFn, type AnchorProps, type ArrayActions, type AsyncDerivedState, type AudioProps, type ButtonProps, type Context, DynamicComponent, type EffectOptions, ErrorBoundary, type ErrorBoundaryProps, ErrorDisplay, type ErrorDisplayProps, type ErrorSeverity, type FormProps, Fragment, type ImgProps, type InputProps, type InputType, KeepAlive, type KeepAliveOptions, type LabelProps, Loading, type LoadingProps, type LongPressOptions, type MediaProps, NodeChild, NodeChildren, type OptionProps, Portal, type Ref, type SelectProps, type SignalOptions, type SlotFn, type Slots, type StoreActions, Suspense, type SuspenseProps, TagProps, type TextareaProps, type TypedTagFunction, type VideoProps, __resetIdCounter, a, abbr, action, address, area, array, article, aside, asyncDerived, audio, autoResize, b, base, batch, bdi, bdo, bindDynamic, blockquote, body, br, button, canvas, caption, catchError, catchErrorAsync, center, checkLeaks, circle, cite, clickOutside, clipPath, code, col, colgroup, context, copyOnClick, createId, customElement, data, datalist, dd, deepEqual, deepSignal, defer, defs, del, derived, details, dfn, dialog, disableSSR, dispose, div, dl, dt, each, effect, ellipse, em, embed, enableSSR, enqueueBatchedSignal, fieldset, figcaption, figure, font, footer, form, g, getSlot, h1, h2, h3, h4, h5, h6, head, header, hr, html, i, iframe, img, input, ins, isBatching, isSSR, kbd, label, lazy, legend, li, line, linearGradient, link, longPress, main, map, mark, marker, marquee, mask, match, math, menu, meta, meter, mount, nav, nextTick, noscript, object, ol, on, onCleanup, onMount, onUnmount, optgroup, option, output, p, param, path, pattern, picture, polygon, polyline, portal, pre, progress, q, radialGradient, reactiveArray, rect, ref, registerComponent, registerDisposer, resolveComponent, rp, rt, ruby, s, samp, script, section, select, setGlobalErrorHandler, show, signal, slot, small, source, span, stop, store, strict, strictEffect, strong, style, sub, summary, sup, svg, symbol, table, tbody, td, template, text, textarea, tfoot, th, thead, time, title, tr, track, transition, trapFocus, tspan, u, ul, unregisterComponent, untracked, use, var_, video, watch, when, withSSR, writable };
1537
+ export { type Accessor, type ActionFn, type AnchorProps, type ArrayActions, type AsyncDerivedState, type AudioProps, type ButtonProps, type Context, DynamicComponent, type EffectBody, type EffectOptions, ErrorBoundary, type ErrorBoundaryProps, ErrorDisplay, type ErrorDisplayProps, type ErrorSeverity, type FormProps, Fragment, type ImgProps, type InputProps, type InputType, KeepAlive, type KeepAliveOptions, type LabelProps, Loading, type LoadingProps, type LongPressOptions, type MediaProps, NodeChild, NodeChildren, type OnCleanup, type OptionProps, Portal, type Ref, type SSRStore, type SelectProps, type SignalOptions, type SlotFn, type Slots, type StoreActions, Suspense, type SuspenseProps, TagProps, type TextareaProps, type TypedTagFunction, type VideoProps, __resetIdCounter, a, abbr, action, address, area, array, article, aside, asyncDerived, audio, autoResize, b, base, batch, bdi, bdo, bindDynamic, blockquote, body, br, button, canvas, caption, catchError, catchErrorAsync, center, checkLeaks, circle, cite, clickOutside, clipPath, code, col, colgroup, context, copyOnClick, createId, customElement, data, datalist, dd, deepEqual, deepSignal, defer, defs, del, derived, details, dfn, dialog, disableSSR, dispose, div, dl, dt, each, effect, ellipse, em, embed, enableSSR, enqueueBatchedSignal, fieldset, figcaption, figure, font, footer, form, g, getSSRStore, getSlot, h1, h2, h3, h4, h5, h6, head, header, hr, html, i, iframe, img, input, ins, isBatching, isSSR, kbd, label, lazy, legend, li, line, linearGradient, link, longPress, main, map, mark, marker, marquee, mask, match, math, menu, meta, meter, mount, nav, nextTick, noscript, object, ol, on, onCleanup, onMount, onUnmount, optgroup, option, output, p, param, path, pattern, picture, polygon, polyline, portal, pre, progress, q, radialGradient, reactiveArray, rect, ref, registerComponent, registerDisposer, resolveComponent, rp, rt, ruby, runInSSRContext, s, samp, script, section, select, setGlobalErrorHandler, show, signal, slot, small, source, span, stop, store, strict, strictEffect, strong, style, sub, summary, sup, svg, symbol, table, takePendingError, tbody, td, template, text, textarea, tfoot, th, thead, time, title, tr, track, transition, trapFocus, tspan, u, ul, unregisterComponent, untracked, use, var_, video, watch, when, withSSR, writable };