sibujs 4.6.0 → 4.8.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 (94) hide show
  1. package/README.md +1 -1
  2. package/dist/browser.cjs +62 -8
  3. package/dist/browser.d.cts +23 -0
  4. package/dist/browser.d.ts +23 -0
  5. package/dist/browser.js +6 -5
  6. package/dist/build.cjs +2388 -1004
  7. package/dist/build.d.cts +147 -44
  8. package/dist/build.d.ts +147 -44
  9. package/dist/build.js +1410 -564
  10. package/dist/cdn.dev.global.js +14 -12
  11. package/dist/cdn.full.dev.global.js +15 -13
  12. package/dist/cdn.full.global.js +14 -12
  13. package/dist/cdn.global.js +12 -10
  14. package/dist/chunk-3ACAAQIN.js +224 -0
  15. package/dist/{chunk-7NCARGJW.js → chunk-44MTL7ED.js} +6 -6
  16. package/dist/{chunk-BAAG6ZTI.js → chunk-4WMSTZ7J.js} +8 -5
  17. package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
  18. package/dist/{chunk-DKGBBKOF.js → chunk-C5PEWEGH.js} +20 -5
  19. package/dist/{chunk-3ISI6ACU.js → chunk-C7AA2CZX.js} +1 -1
  20. package/dist/{chunk-UZQ6ALFS.js → chunk-CZPRSWSS.js} +1 -1
  21. package/dist/{chunk-D33YTSX5.js → chunk-DSID757X.js} +5 -4
  22. package/dist/{chunk-OXUY2A6L.js → chunk-EGUQLBHE.js} +22 -8
  23. package/dist/{chunk-2INLLLMZ.js → chunk-EXXSN3BW.js} +202 -26
  24. package/dist/{chunk-HURREPU2.js → chunk-FC6KCJSA.js} +87 -150
  25. package/dist/{chunk-HYXDKS4N.js → chunk-GSGNX35Q.js} +5 -5
  26. package/dist/{chunk-7GQCWFOE.js → chunk-J3YQ457H.js} +171 -85
  27. package/dist/{chunk-ORMZXBKQ.js → chunk-JUTFX2RM.js} +18 -10
  28. package/dist/{chunk-QE4TTDU3.js → chunk-KJ3UKABJ.js} +12 -11
  29. package/dist/{chunk-XRRZKZYX.js → chunk-LI4W3U6C.js} +1 -1
  30. package/dist/{chunk-47M47FOM.js → chunk-O6TRVMJI.js} +58 -6
  31. package/dist/{chunk-JSXPZCET.js → chunk-Q5J2LVKH.js} +1 -1
  32. package/dist/{chunk-5MT6SJ3P.js → chunk-QGMSESDD.js} +10 -5
  33. package/dist/{chunk-AIF3Z2T7.js → chunk-RGLPEBDE.js} +13 -10
  34. package/dist/{chunk-5Q4R7HCL.js → chunk-TQQUN4WR.js} +11 -2
  35. package/dist/{chunk-PK6FK2G2.js → chunk-UCNP3HVM.js} +183 -30
  36. package/dist/{chunk-XC4MEKGA.js → chunk-V3LHZSU5.js} +8 -2
  37. package/dist/{chunk-VVWPJ543.js → chunk-VWT3VXPL.js} +55 -20
  38. package/dist/{chunk-SXXVZMKZ.js → chunk-ZVLHNEEL.js} +17 -35
  39. package/dist/{contracts-DRIuclVT.d.cts → contracts-CLqzJnOV.d.ts} +28 -17
  40. package/dist/{contracts-DRIuclVT.d.ts → contracts-CTOJXu-x.d.cts} +28 -17
  41. package/dist/{customElement-MmInOW1U.d.ts → customElement-pYDKUzWl.d.cts} +11 -3
  42. package/dist/{customElement-MmInOW1U.d.cts → customElement-pYDKUzWl.d.ts} +11 -3
  43. package/dist/data.cjs +205 -39
  44. package/dist/data.d.cts +119 -3
  45. package/dist/data.d.ts +119 -3
  46. package/dist/data.js +6 -6
  47. package/dist/devtools.cjs +18 -5
  48. package/dist/devtools.js +5 -5
  49. package/dist/ecosystem.cjs +462 -58
  50. package/dist/ecosystem.d.cts +2 -1
  51. package/dist/ecosystem.d.ts +2 -1
  52. package/dist/ecosystem.js +9 -8
  53. package/dist/extras.cjs +852 -296
  54. package/dist/extras.d.cts +5 -4
  55. package/dist/extras.d.ts +5 -4
  56. package/dist/extras.js +24 -23
  57. package/dist/index.cjs +721 -176
  58. package/dist/index.d.cts +220 -169
  59. package/dist/index.d.ts +220 -169
  60. package/dist/index.js +16 -12
  61. package/dist/motion.cjs +12 -4
  62. package/dist/motion.js +3 -3
  63. package/dist/patterns.cjs +37 -21
  64. package/dist/patterns.d.cts +2 -1
  65. package/dist/patterns.d.ts +2 -1
  66. package/dist/patterns.js +6 -6
  67. package/dist/performance.cjs +48 -6
  68. package/dist/performance.d.cts +12 -2
  69. package/dist/performance.d.ts +12 -2
  70. package/dist/performance.js +8 -6
  71. package/dist/plugins.cjs +672 -261
  72. package/dist/plugins.d.cts +131 -13
  73. package/dist/plugins.d.ts +131 -13
  74. package/dist/plugins.js +83 -47
  75. package/dist/{ssr-XOTUASDO.js → ssr-5OWAH3U2.js} +4 -2
  76. package/dist/{ssr-Bli9XRW5.d.cts → ssr-C8hgIAw7.d.cts} +6 -0
  77. package/dist/{ssr-Bli9XRW5.d.ts → ssr-C8hgIAw7.d.ts} +6 -0
  78. package/dist/ssr.cjs +509 -142
  79. package/dist/ssr.d.cts +55 -5
  80. package/dist/ssr.d.ts +55 -5
  81. package/dist/ssr.js +11 -9
  82. package/dist/{tagFactory-DFstCLQV.d.cts → tagFactory-8qL9LCIx.d.cts} +58 -19
  83. package/dist/{tagFactory-DkaNVUNV.d.ts → tagFactory-BL2fymez.d.ts} +58 -19
  84. package/dist/testing.cjs +17 -4
  85. package/dist/testing.js +4 -4
  86. package/dist/types-CJFViL6Q.d.cts +26 -0
  87. package/dist/types-CJFViL6Q.d.ts +26 -0
  88. package/dist/ui.cjs +635 -254
  89. package/dist/ui.d.cts +3 -2
  90. package/dist/ui.d.ts +3 -2
  91. package/dist/ui.js +9 -8
  92. package/dist/widgets.cjs +22 -14
  93. package/dist/widgets.js +7 -7
  94. package/package.json +8 -5
package/dist/ssr.d.cts CHANGED
@@ -1,10 +1,40 @@
1
- export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-Bli9XRW5.cjs';
1
+ export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-C8hgIAw7.cjs';
2
+ import { C as Component } from './types-CJFViL6Q.cjs';
2
3
 
3
4
  interface HeadProps {
4
5
  title?: string | (() => string);
5
6
  meta?: Record<string, string | (() => string)>[];
7
+ /**
8
+ * `<link>` elements to add to `<head>`.
9
+ *
10
+ * TRUST BOUNDARY for stylesheets: `{ rel: "stylesheet", href }` is the
11
+ * framework's explicit API for a stylesheet whose URL is a runtime value.
12
+ * The generic writers refuse to let a runtime `href` become an applied
13
+ * stylesheet at all (see `utils/elementPolicy.ts`), because a well-formed
14
+ * URL is not trusted CSS. Naming it here is the trust decision: first-party
15
+ * or pinned URLs only, and a CSP `style-src` as the second layer.
16
+ */
6
17
  link?: Record<string, string>[];
18
+ /**
19
+ * External scripts to add to `<head>`.
20
+ *
21
+ * TRUST BOUNDARY: this is the framework's explicit API for loading a script
22
+ * whose URL is a runtime value, and naming it here IS the trust decision —
23
+ * the URL passes the scheme allowlist, but an allowed `https:` URL is still a
24
+ * program that runs with the page's full authority. Pass only URLs you
25
+ * control or pin (a first-party path, a CDN URL with `integrity`). The
26
+ * generic writers refuse to let a runtime value choose a `<script>` source
27
+ * at all; see `docs/architecture/attribute-security.md` § Trust model.
28
+ */
7
29
  script?: Record<string, string>[];
30
+ /**
31
+ * The document `<base>`.
32
+ *
33
+ * TRUST BOUNDARY: `href` passes the scheme allowlist, but an allowed `https:`
34
+ * base still re-homes every relative URL on the page — relative `<script
35
+ * src>`, stylesheets, form actions and `fetch("/api")` alike. Treat it like a
36
+ * script URL: first-party values only.
37
+ */
8
38
  base?: {
9
39
  href?: string;
10
40
  target?: string;
@@ -94,6 +124,10 @@ interface UseWorkerFnReturn<TArgs extends unknown[], TResult> {
94
124
  * The function must be self-contained -- it cannot reference variables
95
125
  * from the outer scope. Arguments are serialized via postMessage.
96
126
  *
127
+ * **Trust boundary:** the function's source is evaluated in a `blob:` worker,
128
+ * which is equivalent to `eval()`. Only a function object is accepted — never
129
+ * a string, and never a function built from untrusted input.
130
+ *
97
131
  * @param fn A pure function to execute in a worker thread.
98
132
  * @returns An object with run, loading, and terminate.
99
133
  */
@@ -108,6 +142,9 @@ interface WorkerPool<TInput, TOutput> {
108
142
  * Tasks are distributed across workers using round-robin scheduling.
109
143
  * Each worker is created from the same inline function.
110
144
  *
145
+ * **Trust boundary:** as with `worker()`, the function's source is evaluated in
146
+ * a `blob:` worker. Only a function object is accepted, never a string.
147
+ *
111
148
  * @param workerFn The function body to run inside each worker.
112
149
  * @param poolSize Number of workers in the pool (defaults to navigator.hardwareConcurrency or 4).
113
150
  * @returns An object with execute and terminate.
@@ -362,9 +399,13 @@ interface LoadRemoteModuleOptions {
362
399
  unsafelyAllowAnyOrigin?: boolean;
363
400
  }
364
401
  declare function loadRemoteModule(url: string, optionsOrAllowedOrigins?: string[] | LoadRemoteModuleOptions): Promise<unknown>;
365
- type Component = () => HTMLElement;
366
- type RemoteLoader = () => Promise<{
367
- default: Component;
402
+ /**
403
+ * Loads the remote module whose `default` export is the component. Its root may
404
+ * be any `Element` — an SVG root included — using the public `Component` type
405
+ * rather than a private `() => HTMLElement` that forced a cast.
406
+ */
407
+ type RemoteLoader<R extends Element = HTMLElement> = () => Promise<{
408
+ default: Component<void, R>;
368
409
  }>;
369
410
  /**
370
411
  * Register a remote component that loads on demand.
@@ -392,7 +433,7 @@ type RemoteLoader = () => Promise<{
392
433
  * document.body.appendChild(RemoteHeader());
393
434
  * ```
394
435
  */
395
- declare function defineRemoteComponent(name: string, loader: RemoteLoader): Component;
436
+ declare function defineRemoteComponent<R extends Element = HTMLElement>(name: string, loader: RemoteLoader<R>): Component<void, R | HTMLElement>;
396
437
  /**
397
438
  * Create a shared state scope that enables communication between independent
398
439
  * micro-frontend instances.
@@ -430,6 +471,15 @@ interface ServiceWorkerState {
430
471
  /**
431
472
  * serviceWorker registers and manages a service worker.
432
473
  *
474
+ * TRUST BOUNDARY: `scriptUrl` is CODE. A service worker runs with authority
475
+ * over every page in its scope and persists across reloads, so this is the
476
+ * strongest code-loading primitive in the framework. The browser enforces
477
+ * same-origin, a secure context and a JavaScript MIME type — it does NOT
478
+ * protect against a same-origin URL that serves attacker-influenced content
479
+ * (a JSONP endpoint, an upload directory). Pass only a literal path to a worker
480
+ * script you ship; never a value derived from the URL, storage or an API
481
+ * response.
482
+ *
433
483
  * LIFECYCLE CONTRACT
434
484
  * ------------------
435
485
  * Registration is asynchronous and `unregister()` can be called at any point
package/dist/ssr.d.ts CHANGED
@@ -1,10 +1,40 @@
1
- export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-Bli9XRW5.js';
1
+ export { H as HydrateOptions, a as HydrationMismatch, T as TrustedHTML, c as collectStream, d as deserializeState, e as escapeScriptJson, h as hydrate, b as hydrateIslands, f as hydrateProgressively, i as isDangerousMetaRefresh, g as island, r as renderToDocument, j as renderToReadableStream, k as renderToStream, l as renderToString, m as renderToSuspenseStream, n as resetSSRState, s as serializeState, o as ssrSuspense, p as suspenseSwapScript, t as trustHTML } from './ssr-C8hgIAw7.js';
2
+ import { C as Component } from './types-CJFViL6Q.js';
2
3
 
3
4
  interface HeadProps {
4
5
  title?: string | (() => string);
5
6
  meta?: Record<string, string | (() => string)>[];
7
+ /**
8
+ * `<link>` elements to add to `<head>`.
9
+ *
10
+ * TRUST BOUNDARY for stylesheets: `{ rel: "stylesheet", href }` is the
11
+ * framework's explicit API for a stylesheet whose URL is a runtime value.
12
+ * The generic writers refuse to let a runtime `href` become an applied
13
+ * stylesheet at all (see `utils/elementPolicy.ts`), because a well-formed
14
+ * URL is not trusted CSS. Naming it here is the trust decision: first-party
15
+ * or pinned URLs only, and a CSP `style-src` as the second layer.
16
+ */
6
17
  link?: Record<string, string>[];
18
+ /**
19
+ * External scripts to add to `<head>`.
20
+ *
21
+ * TRUST BOUNDARY: this is the framework's explicit API for loading a script
22
+ * whose URL is a runtime value, and naming it here IS the trust decision —
23
+ * the URL passes the scheme allowlist, but an allowed `https:` URL is still a
24
+ * program that runs with the page's full authority. Pass only URLs you
25
+ * control or pin (a first-party path, a CDN URL with `integrity`). The
26
+ * generic writers refuse to let a runtime value choose a `<script>` source
27
+ * at all; see `docs/architecture/attribute-security.md` § Trust model.
28
+ */
7
29
  script?: Record<string, string>[];
30
+ /**
31
+ * The document `<base>`.
32
+ *
33
+ * TRUST BOUNDARY: `href` passes the scheme allowlist, but an allowed `https:`
34
+ * base still re-homes every relative URL on the page — relative `<script
35
+ * src>`, stylesheets, form actions and `fetch("/api")` alike. Treat it like a
36
+ * script URL: first-party values only.
37
+ */
8
38
  base?: {
9
39
  href?: string;
10
40
  target?: string;
@@ -94,6 +124,10 @@ interface UseWorkerFnReturn<TArgs extends unknown[], TResult> {
94
124
  * The function must be self-contained -- it cannot reference variables
95
125
  * from the outer scope. Arguments are serialized via postMessage.
96
126
  *
127
+ * **Trust boundary:** the function's source is evaluated in a `blob:` worker,
128
+ * which is equivalent to `eval()`. Only a function object is accepted — never
129
+ * a string, and never a function built from untrusted input.
130
+ *
97
131
  * @param fn A pure function to execute in a worker thread.
98
132
  * @returns An object with run, loading, and terminate.
99
133
  */
@@ -108,6 +142,9 @@ interface WorkerPool<TInput, TOutput> {
108
142
  * Tasks are distributed across workers using round-robin scheduling.
109
143
  * Each worker is created from the same inline function.
110
144
  *
145
+ * **Trust boundary:** as with `worker()`, the function's source is evaluated in
146
+ * a `blob:` worker. Only a function object is accepted, never a string.
147
+ *
111
148
  * @param workerFn The function body to run inside each worker.
112
149
  * @param poolSize Number of workers in the pool (defaults to navigator.hardwareConcurrency or 4).
113
150
  * @returns An object with execute and terminate.
@@ -362,9 +399,13 @@ interface LoadRemoteModuleOptions {
362
399
  unsafelyAllowAnyOrigin?: boolean;
363
400
  }
364
401
  declare function loadRemoteModule(url: string, optionsOrAllowedOrigins?: string[] | LoadRemoteModuleOptions): Promise<unknown>;
365
- type Component = () => HTMLElement;
366
- type RemoteLoader = () => Promise<{
367
- default: Component;
402
+ /**
403
+ * Loads the remote module whose `default` export is the component. Its root may
404
+ * be any `Element` — an SVG root included — using the public `Component` type
405
+ * rather than a private `() => HTMLElement` that forced a cast.
406
+ */
407
+ type RemoteLoader<R extends Element = HTMLElement> = () => Promise<{
408
+ default: Component<void, R>;
368
409
  }>;
369
410
  /**
370
411
  * Register a remote component that loads on demand.
@@ -392,7 +433,7 @@ type RemoteLoader = () => Promise<{
392
433
  * document.body.appendChild(RemoteHeader());
393
434
  * ```
394
435
  */
395
- declare function defineRemoteComponent(name: string, loader: RemoteLoader): Component;
436
+ declare function defineRemoteComponent<R extends Element = HTMLElement>(name: string, loader: RemoteLoader<R>): Component<void, R | HTMLElement>;
396
437
  /**
397
438
  * Create a shared state scope that enables communication between independent
398
439
  * micro-frontend instances.
@@ -430,6 +471,15 @@ interface ServiceWorkerState {
430
471
  /**
431
472
  * serviceWorker registers and manages a service worker.
432
473
  *
474
+ * TRUST BOUNDARY: `scriptUrl` is CODE. A service worker runs with authority
475
+ * over every page in its scope and persists across reloads, so this is the
476
+ * strongest code-loading primitive in the framework. The browser enforces
477
+ * same-origin, a secure context and a JavaScript MIME type — it does NOT
478
+ * protect against a same-origin URL that serves attacker-influenced content
479
+ * (a JSONP endpoint, an upload directory). Pass only a literal path to a worker
480
+ * script you ship; never a value derived from the URL, storage or an API
481
+ * response.
482
+ *
433
483
  * LIFECYCLE CONTRACT
434
484
  * ------------------
435
485
  * Registration is asynchronous and `unregister()` can be called at any point
package/dist/ssr.js CHANGED
@@ -23,9 +23,9 @@ import {
23
23
  wasm,
24
24
  worker,
25
25
  workerFn
26
- } from "./chunk-ORMZXBKQ.js";
26
+ } from "./chunk-JUTFX2RM.js";
27
27
  import "./chunk-52XFPGSN.js";
28
- import "./chunk-JSXPZCET.js";
28
+ import "./chunk-Q5J2LVKH.js";
29
29
  import {
30
30
  collectStream,
31
31
  deserializeState,
@@ -45,15 +45,17 @@ import {
45
45
  ssrSuspense,
46
46
  suspenseSwapScript,
47
47
  trustHTML
48
- } from "./chunk-HURREPU2.js";
49
- import "./chunk-VVWPJ543.js";
50
- import "./chunk-47M47FOM.js";
51
- import "./chunk-2INLLLMZ.js";
48
+ } from "./chunk-FC6KCJSA.js";
49
+ import "./chunk-62BDYGAG.js";
50
+ import "./chunk-VWT3VXPL.js";
51
+ import "./chunk-O6TRVMJI.js";
52
+ import "./chunk-3ACAAQIN.js";
52
53
  import "./chunk-7ZHH77QA.js";
53
- import "./chunk-XC4MEKGA.js";
54
+ import "./chunk-V3LHZSU5.js";
55
+ import "./chunk-EXXSN3BW.js";
54
56
  import "./chunk-7XHATCIH.js";
55
- import "./chunk-D33YTSX5.js";
56
- import "./chunk-5Q4R7HCL.js";
57
+ import "./chunk-DSID757X.js";
58
+ import "./chunk-TQQUN4WR.js";
57
59
  import "./chunk-NYNYSPK7.js";
58
60
  export {
59
61
  Head,
@@ -1,4 +1,5 @@
1
1
  import { A as Accessor } from './signal-EotCj4hS.cjs';
2
+ import { N as NodeChildren } from './types-CJFViL6Q.cjs';
2
3
 
3
4
  /**
4
5
  * derived creates a derived reactive signal whose value updates when dependencies change.
@@ -60,31 +61,60 @@ type DerivedAccessor<T> = Accessor<T> & {
60
61
  dispose: () => void;
61
62
  };
62
63
 
64
+ declare const SVG_NS = "http://www.w3.org/2000/svg";
63
65
  /**
64
- * Canonical disposer/teardown signature used across the framework.
65
- *
66
- * Returned by `effect()`, `track()`, widget `bind()` methods, and other
67
- * subscription/lifecycle helpers. All disposers MUST be idempotent — calling
68
- * twice should be a no-op rather than an error.
66
+ * A style declaration map: camelCase or kebab-case property names to values.
67
+ * Each value may be a getter, which binds that one property reactively.
69
68
  */
70
- type Dispose = () => void;
71
- type NodeChild = Node | Element | Text | Comment | string | number | boolean | (() => NodeChild) | null | undefined;
72
- type NodeChildren = NodeChild | NodeChild[] | NodeChild[][] | (() => NodeChild | NodeChild[]);
73
-
74
- declare const SVG_NS = "http://www.w3.org/2000/svg";
75
- interface TagProps {
76
- id?: string;
77
- class?: string | (() => string) | Record<string, boolean | (() => boolean)>;
78
- style?: Record<string, string | number | (() => string | number)> | string | (() => string);
69
+ type StyleMap = Record<string, string | number | (() => string | number)>;
70
+ /**
71
+ * A style map produced by a whole-`style` getter. The getter already runs
72
+ * reactively, so its values are plain; a `null` / `undefined` value leaves the
73
+ * property unset (and removes it if an earlier run set it).
74
+ */
75
+ type StyleObject = Record<string, string | number | null | undefined>;
76
+ /**
77
+ * Listeners for the `on` prop. Known DOM event names get their specific event
78
+ * type from the DOM lib (`keydown` → `KeyboardEvent`, `click` → the lib's
79
+ * `MouseEvent` / `PointerEvent`), so a handler may declare it without a cast;
80
+ * any other name (custom events) receives an `Event`. That fallback is
81
+ * method-typed, so a handler declaring a narrower event
82
+ * (`(e: CustomEvent<Detail>) => …`) is still accepted for a custom name.
83
+ */
84
+ type TagEventHandlers = {
85
+ [K in keyof HTMLElementEventMap]?: (ev: HTMLElementEventMap[K]) => void;
86
+ } & {
87
+ [event: string]: {
88
+ handle(ev: Event): void;
89
+ }["handle"] | undefined;
90
+ };
91
+ /**
92
+ * Props accepted by a tag factory. `El` is the element the factory creates;
93
+ * it types `onElement`.
94
+ */
95
+ interface TagProps<El extends Element = HTMLElement> {
96
+ id?: string | (() => string);
97
+ class?: string | (() => string | null | undefined | false) | Record<string, boolean | (() => boolean)>;
98
+ style?: StyleMap | string | (() => string | StyleObject);
99
+ /**
100
+ * Receives the created element. Accepts what `ref()` returns under `strict`
101
+ * (`ref<HTMLInputElement>()` is a `Ref<HTMLInputElement | undefined>`) as
102
+ * well as a `{ current: Element | null }` box.
103
+ */
79
104
  ref?: {
80
- current: Element | null;
105
+ current: Element | null | undefined;
81
106
  };
82
107
  nodes?: NodeChildren;
83
- on?: Record<string, (ev: Event) => void>;
108
+ on?: TagEventHandlers;
84
109
  /** Called with the element after creation — useful for imperative bindings */
85
- onElement?: (el: HTMLElement) => void;
110
+ onElement?(el: El): void;
86
111
  [attr: string]: unknown;
87
112
  }
113
+ /**
114
+ * A tag factory: builds one `El` per call. See {@link tagFactory} for the
115
+ * accepted calling conventions.
116
+ */
117
+ type TagFunction<El extends Element, Props extends TagProps<El> = TagProps<El>> = (first?: Props | NodeChildren, second?: NodeChildren) => El;
88
118
  /**
89
119
  * Factory for creating HTML or SVG elements with reactive props and nodes.
90
120
  *
@@ -111,7 +141,16 @@ interface TagProps {
111
141
  * ])
112
142
  *
113
143
  * `children` overrides `props.nodes` when both are present.
144
+ *
145
+ * The returned factory is typed by the tag: `tagFactory("div")` builds
146
+ * `HTMLDivElement`s, `tagFactory("circle", SVG_NS)` builds `SVGCircleElement`s.
147
+ * A tag name TypeScript does not know builds `HTMLElement`s (which is what
148
+ * `document.createElement` returns for it), or `Element`s in another namespace.
114
149
  */
115
- declare const tagFactory: (tag: string, ns?: string) => (first?: TagProps | NodeChildren, second?: NodeChildren) => Element;
150
+ declare function tagFactory<K extends keyof HTMLElementTagNameMap>(tag: K, ns?: undefined): TagFunction<HTMLElementTagNameMap[K]>;
151
+ declare function tagFactory<K extends keyof SVGElementTagNameMap>(tag: K, ns: typeof SVG_NS): TagFunction<SVGElementTagNameMap[K]>;
152
+ declare function tagFactory(tag: string, ns?: undefined): TagFunction<HTMLElement>;
153
+ declare function tagFactory(tag: string, ns: typeof SVG_NS): TagFunction<SVGElement>;
154
+ declare function tagFactory(tag: string, ns?: string): TagFunction<Element>;
116
155
 
117
- export { type DerivedAccessor as D, type NodeChild as N, SVG_NS as S, type TagProps as T, type NodeChildren as a, type Dispose as b, derived as d, tagFactory as t };
156
+ export { type DerivedAccessor as D, SVG_NS as S, type TagProps as T, type TagFunction as a, type StyleMap as b, type StyleObject as c, type TagEventHandlers as d, derived as e, tagFactory as t };
@@ -1,4 +1,5 @@
1
1
  import { A as Accessor } from './signal-EotCj4hS.js';
2
+ import { N as NodeChildren } from './types-CJFViL6Q.js';
2
3
 
3
4
  /**
4
5
  * derived creates a derived reactive signal whose value updates when dependencies change.
@@ -60,31 +61,60 @@ type DerivedAccessor<T> = Accessor<T> & {
60
61
  dispose: () => void;
61
62
  };
62
63
 
64
+ declare const SVG_NS = "http://www.w3.org/2000/svg";
63
65
  /**
64
- * Canonical disposer/teardown signature used across the framework.
65
- *
66
- * Returned by `effect()`, `track()`, widget `bind()` methods, and other
67
- * subscription/lifecycle helpers. All disposers MUST be idempotent — calling
68
- * twice should be a no-op rather than an error.
66
+ * A style declaration map: camelCase or kebab-case property names to values.
67
+ * Each value may be a getter, which binds that one property reactively.
69
68
  */
70
- type Dispose = () => void;
71
- type NodeChild = Node | Element | Text | Comment | string | number | boolean | (() => NodeChild) | null | undefined;
72
- type NodeChildren = NodeChild | NodeChild[] | NodeChild[][] | (() => NodeChild | NodeChild[]);
73
-
74
- declare const SVG_NS = "http://www.w3.org/2000/svg";
75
- interface TagProps {
76
- id?: string;
77
- class?: string | (() => string) | Record<string, boolean | (() => boolean)>;
78
- style?: Record<string, string | number | (() => string | number)> | string | (() => string);
69
+ type StyleMap = Record<string, string | number | (() => string | number)>;
70
+ /**
71
+ * A style map produced by a whole-`style` getter. The getter already runs
72
+ * reactively, so its values are plain; a `null` / `undefined` value leaves the
73
+ * property unset (and removes it if an earlier run set it).
74
+ */
75
+ type StyleObject = Record<string, string | number | null | undefined>;
76
+ /**
77
+ * Listeners for the `on` prop. Known DOM event names get their specific event
78
+ * type from the DOM lib (`keydown` → `KeyboardEvent`, `click` → the lib's
79
+ * `MouseEvent` / `PointerEvent`), so a handler may declare it without a cast;
80
+ * any other name (custom events) receives an `Event`. That fallback is
81
+ * method-typed, so a handler declaring a narrower event
82
+ * (`(e: CustomEvent<Detail>) => …`) is still accepted for a custom name.
83
+ */
84
+ type TagEventHandlers = {
85
+ [K in keyof HTMLElementEventMap]?: (ev: HTMLElementEventMap[K]) => void;
86
+ } & {
87
+ [event: string]: {
88
+ handle(ev: Event): void;
89
+ }["handle"] | undefined;
90
+ };
91
+ /**
92
+ * Props accepted by a tag factory. `El` is the element the factory creates;
93
+ * it types `onElement`.
94
+ */
95
+ interface TagProps<El extends Element = HTMLElement> {
96
+ id?: string | (() => string);
97
+ class?: string | (() => string | null | undefined | false) | Record<string, boolean | (() => boolean)>;
98
+ style?: StyleMap | string | (() => string | StyleObject);
99
+ /**
100
+ * Receives the created element. Accepts what `ref()` returns under `strict`
101
+ * (`ref<HTMLInputElement>()` is a `Ref<HTMLInputElement | undefined>`) as
102
+ * well as a `{ current: Element | null }` box.
103
+ */
79
104
  ref?: {
80
- current: Element | null;
105
+ current: Element | null | undefined;
81
106
  };
82
107
  nodes?: NodeChildren;
83
- on?: Record<string, (ev: Event) => void>;
108
+ on?: TagEventHandlers;
84
109
  /** Called with the element after creation — useful for imperative bindings */
85
- onElement?: (el: HTMLElement) => void;
110
+ onElement?(el: El): void;
86
111
  [attr: string]: unknown;
87
112
  }
113
+ /**
114
+ * A tag factory: builds one `El` per call. See {@link tagFactory} for the
115
+ * accepted calling conventions.
116
+ */
117
+ type TagFunction<El extends Element, Props extends TagProps<El> = TagProps<El>> = (first?: Props | NodeChildren, second?: NodeChildren) => El;
88
118
  /**
89
119
  * Factory for creating HTML or SVG elements with reactive props and nodes.
90
120
  *
@@ -111,7 +141,16 @@ interface TagProps {
111
141
  * ])
112
142
  *
113
143
  * `children` overrides `props.nodes` when both are present.
144
+ *
145
+ * The returned factory is typed by the tag: `tagFactory("div")` builds
146
+ * `HTMLDivElement`s, `tagFactory("circle", SVG_NS)` builds `SVGCircleElement`s.
147
+ * A tag name TypeScript does not know builds `HTMLElement`s (which is what
148
+ * `document.createElement` returns for it), or `Element`s in another namespace.
114
149
  */
115
- declare const tagFactory: (tag: string, ns?: string) => (first?: TagProps | NodeChildren, second?: NodeChildren) => Element;
150
+ declare function tagFactory<K extends keyof HTMLElementTagNameMap>(tag: K, ns?: undefined): TagFunction<HTMLElementTagNameMap[K]>;
151
+ declare function tagFactory<K extends keyof SVGElementTagNameMap>(tag: K, ns: typeof SVG_NS): TagFunction<SVGElementTagNameMap[K]>;
152
+ declare function tagFactory(tag: string, ns?: undefined): TagFunction<HTMLElement>;
153
+ declare function tagFactory(tag: string, ns: typeof SVG_NS): TagFunction<SVGElement>;
154
+ declare function tagFactory(tag: string, ns?: string): TagFunction<Element>;
116
155
 
117
- export { type DerivedAccessor as D, type NodeChild as N, SVG_NS as S, type TagProps as T, type NodeChildren as a, type Dispose as b, derived as d, tagFactory as t };
156
+ export { type DerivedAccessor as D, SVG_NS as S, type TagProps as T, type TagFunction as a, type StyleMap as b, type StyleObject as c, type TagEventHandlers as d, derived as e, tagFactory as t };
package/dist/testing.cjs CHANGED
@@ -754,7 +754,7 @@ function forEachSubscriber(signal, visit) {
754
754
  }
755
755
 
756
756
  // src/reactivity/track.ts
757
- var _runtimeVersion = true ? "4.6.0" : "dev";
757
+ var _runtimeVersion = true ? "4.8.0" : "dev";
758
758
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
759
759
  function resolveReactiveApi() {
760
760
  const g = globalThis;
@@ -810,6 +810,14 @@ var getSubscriberCount2 = API.getSubscriberCount;
810
810
  var getSubscriberDeps2 = API.getSubscriberDeps;
811
811
  var forEachSubscriber2 = API.forEachSubscriber;
812
812
 
813
+ // src/core/devtoolsHook.ts
814
+ function emitDevtools(hook, event, payload) {
815
+ try {
816
+ hook.emit(event, payload);
817
+ } catch {
818
+ }
819
+ }
820
+
813
821
  // src/core/ssr-context.ts
814
822
  var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
815
823
  function detectSSRShared() {
@@ -964,12 +972,17 @@ function effect(effectFn, options) {
964
972
  try {
965
973
  retrack2(ctx.bodyFn, ctx.subscriber);
966
974
  if (ctx.rerunPending) drainReruns(ctx);
975
+ } catch (err) {
976
+ ctx.disposed = true;
977
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
978
+ cleanup2(ctx.subscriber);
979
+ throw err;
967
980
  } finally {
968
981
  ctx.running = false;
969
982
  ctx.rerunPending = false;
970
983
  }
971
984
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
972
- if (hook) hook.emit("effect:create", { effectFn });
985
+ if (hook) emitDevtools(hook, "effect:create", { effectFn });
973
986
  return () => disposeEffect(ctx);
974
987
  }
975
988
 
@@ -1150,8 +1163,8 @@ function enableListenerTracking() {
1150
1163
  if (opts?.signal) {
1151
1164
  const signal = opts.signal;
1152
1165
  const onAbort = () => drop(this, type2, entry);
1153
- add.call(signal, "abort", onAbort, { once: true });
1154
- releases.push(() => remove.call(signal, "abort", onAbort));
1166
+ signal.addEventListener("abort", onAbort, { once: true });
1167
+ releases.push(() => signal.removeEventListener("abort", onAbort));
1155
1168
  }
1156
1169
  if (releases.length > 0) {
1157
1170
  entry.release = () => {
package/dist/testing.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  } from "./chunk-7ZHH77QA.js";
4
4
  import {
5
5
  effect
6
- } from "./chunk-XC4MEKGA.js";
6
+ } from "./chunk-V3LHZSU5.js";
7
7
  import "./chunk-7XHATCIH.js";
8
- import "./chunk-5Q4R7HCL.js";
8
+ import "./chunk-TQQUN4WR.js";
9
9
  import {
10
10
  dispose,
11
11
  replaceChildrenSafely,
@@ -189,8 +189,8 @@ function enableListenerTracking() {
189
189
  if (opts?.signal) {
190
190
  const signal = opts.signal;
191
191
  const onAbort = () => drop(this, type2, entry);
192
- add.call(signal, "abort", onAbort, { once: true });
193
- releases.push(() => remove.call(signal, "abort", onAbort));
192
+ signal.addEventListener("abort", onAbort, { once: true });
193
+ releases.push(() => signal.removeEventListener("abort", onAbort));
194
194
  }
195
195
  if (releases.length > 0) {
196
196
  entry.release = () => {
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Canonical disposer/teardown signature used across the framework.
3
+ *
4
+ * Returned by `effect()`, `track()`, widget `bind()` methods, and other
5
+ * subscription/lifecycle helpers. All disposers MUST be idempotent — calling
6
+ * twice should be a no-op rather than an error.
7
+ */
8
+ type Dispose = () => void;
9
+ /**
10
+ * A component: a function from its props to the DOM node it renders.
11
+ *
12
+ * `P` defaults to `void`, so a prop-less component is written and called
13
+ * without arguments (`const App: Component = () => div("hi")`, then `App()`).
14
+ * `R` is the root the component returns. It defaults to `Element`, so HTML and
15
+ * SVG roots both fit; narrow it (`Component<Props, HTMLDivElement>`) to expose
16
+ * the specific root type to callers.
17
+ *
18
+ * Every framework API that takes a component (`mount`, `lazy`, `Suspense`,
19
+ * `Portal`, `registerComponent`, `DynamicComponent`, the HOC helpers) accepts
20
+ * a `Component`, and every tag factory's result fits its return type.
21
+ */
22
+ type Component<P = void, R extends Node = Element> = (props: P) => R;
23
+ type NodeChild = Node | Element | Text | Comment | string | number | boolean | (() => NodeChild) | null | undefined;
24
+ type NodeChildren = NodeChild | NodeChild[] | NodeChild[][] | (() => NodeChild | NodeChild[]);
25
+
26
+ export type { Component as C, Dispose as D, NodeChildren as N, NodeChild as a };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Canonical disposer/teardown signature used across the framework.
3
+ *
4
+ * Returned by `effect()`, `track()`, widget `bind()` methods, and other
5
+ * subscription/lifecycle helpers. All disposers MUST be idempotent — calling
6
+ * twice should be a no-op rather than an error.
7
+ */
8
+ type Dispose = () => void;
9
+ /**
10
+ * A component: a function from its props to the DOM node it renders.
11
+ *
12
+ * `P` defaults to `void`, so a prop-less component is written and called
13
+ * without arguments (`const App: Component = () => div("hi")`, then `App()`).
14
+ * `R` is the root the component returns. It defaults to `Element`, so HTML and
15
+ * SVG roots both fit; narrow it (`Component<Props, HTMLDivElement>`) to expose
16
+ * the specific root type to callers.
17
+ *
18
+ * Every framework API that takes a component (`mount`, `lazy`, `Suspense`,
19
+ * `Portal`, `registerComponent`, `DynamicComponent`, the HOC helpers) accepts
20
+ * a `Component`, and every tag factory's result fits its return type.
21
+ */
22
+ type Component<P = void, R extends Node = Element> = (props: P) => R;
23
+ type NodeChild = Node | Element | Text | Comment | string | number | boolean | (() => NodeChild) | null | undefined;
24
+ type NodeChildren = NodeChild | NodeChild[] | NodeChild[][] | (() => NodeChild | NodeChild[]);
25
+
26
+ export type { Component as C, Dispose as D, NodeChildren as N, NodeChild as a };