sibujs 4.6.0 → 4.7.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 (79) hide show
  1. package/README.md +1 -1
  2. package/dist/browser.cjs +18 -5
  3. package/dist/browser.js +4 -4
  4. package/dist/build.cjs +1956 -1007
  5. package/dist/build.d.cts +133 -44
  6. package/dist/build.d.ts +133 -44
  7. package/dist/build.js +1368 -569
  8. package/dist/cdn.dev.global.js +12 -12
  9. package/dist/cdn.full.dev.global.js +11 -11
  10. package/dist/cdn.full.global.js +10 -10
  11. package/dist/cdn.global.js +12 -12
  12. package/dist/{chunk-SXXVZMKZ.js → chunk-2BPG2XDA.js} +5 -5
  13. package/dist/{chunk-BAAG6ZTI.js → chunk-3QWBSL5R.js} +4 -4
  14. package/dist/{chunk-5MT6SJ3P.js → chunk-4AWA2PVD.js} +2 -2
  15. package/dist/{chunk-JSXPZCET.js → chunk-7LUJQAOJ.js} +1 -1
  16. package/dist/{chunk-3ISI6ACU.js → chunk-BC2SECJD.js} +1 -1
  17. package/dist/{chunk-DKGBBKOF.js → chunk-BSY63EM6.js} +2 -2
  18. package/dist/{chunk-7NCARGJW.js → chunk-DKXRACVN.js} +3 -3
  19. package/dist/{chunk-47M47FOM.js → chunk-FNJXNGYZ.js} +1 -1
  20. package/dist/{chunk-D33YTSX5.js → chunk-FQRUXCEE.js} +5 -4
  21. package/dist/{chunk-5Q4R7HCL.js → chunk-JWKYU5GV.js} +11 -2
  22. package/dist/{chunk-QE4TTDU3.js → chunk-RUSSKG6G.js} +12 -11
  23. package/dist/{chunk-UZQ6ALFS.js → chunk-SLM3IA34.js} +1 -1
  24. package/dist/{chunk-XRRZKZYX.js → chunk-UNWRJRKC.js} +1 -1
  25. package/dist/{chunk-VVWPJ543.js → chunk-UOL2ECCS.js} +40 -11
  26. package/dist/{chunk-ORMZXBKQ.js → chunk-VZSG24LS.js} +3 -3
  27. package/dist/{chunk-XC4MEKGA.js → chunk-WEQ3DMVL.js} +8 -2
  28. package/dist/{chunk-PK6FK2G2.js → chunk-WOLJZUFQ.js} +176 -27
  29. package/dist/{chunk-7GQCWFOE.js → chunk-XYV3EDB7.js} +143 -74
  30. package/dist/{chunk-AIF3Z2T7.js → chunk-XZR4PXRE.js} +3 -3
  31. package/dist/{chunk-HYXDKS4N.js → chunk-Z3OHK6QT.js} +4 -4
  32. package/dist/{chunk-OXUY2A6L.js → chunk-ZVL7TY4K.js} +2 -2
  33. package/dist/{contracts-DRIuclVT.d.ts → contracts-CLqzJnOV.d.ts} +28 -17
  34. package/dist/{contracts-DRIuclVT.d.cts → contracts-CTOJXu-x.d.cts} +28 -17
  35. package/dist/data.cjs +198 -39
  36. package/dist/data.d.cts +119 -3
  37. package/dist/data.d.ts +119 -3
  38. package/dist/data.js +5 -5
  39. package/dist/devtools.cjs +18 -5
  40. package/dist/devtools.js +4 -4
  41. package/dist/ecosystem.cjs +64 -23
  42. package/dist/ecosystem.d.cts +2 -1
  43. package/dist/ecosystem.d.ts +2 -1
  44. package/dist/ecosystem.js +7 -7
  45. package/dist/extras.cjs +236 -49
  46. package/dist/extras.d.cts +3 -2
  47. package/dist/extras.d.ts +3 -2
  48. package/dist/extras.js +20 -20
  49. package/dist/index.cjs +259 -108
  50. package/dist/index.d.cts +193 -168
  51. package/dist/index.d.ts +193 -168
  52. package/dist/index.js +10 -10
  53. package/dist/motion.cjs +12 -4
  54. package/dist/motion.js +3 -3
  55. package/dist/patterns.cjs +28 -15
  56. package/dist/patterns.d.cts +2 -1
  57. package/dist/patterns.d.ts +2 -1
  58. package/dist/patterns.js +5 -5
  59. package/dist/performance.cjs +18 -5
  60. package/dist/performance.js +4 -4
  61. package/dist/plugins.cjs +118 -34
  62. package/dist/plugins.d.cts +124 -11
  63. package/dist/plugins.d.ts +124 -11
  64. package/dist/plugins.js +68 -26
  65. package/dist/ssr.cjs +54 -13
  66. package/dist/ssr.js +7 -7
  67. package/dist/{tagFactory-DFstCLQV.d.cts → tagFactory-8qL9LCIx.d.cts} +58 -19
  68. package/dist/{tagFactory-DkaNVUNV.d.ts → tagFactory-BL2fymez.d.ts} +58 -19
  69. package/dist/testing.cjs +15 -2
  70. package/dist/testing.js +2 -2
  71. package/dist/types-CJFViL6Q.d.cts +26 -0
  72. package/dist/types-CJFViL6Q.d.ts +26 -0
  73. package/dist/ui.cjs +28 -15
  74. package/dist/ui.d.cts +2 -1
  75. package/dist/ui.d.ts +2 -1
  76. package/dist/ui.js +7 -7
  77. package/dist/widgets.cjs +22 -14
  78. package/dist/widgets.js +6 -6
  79. package/package.json +4 -2
@@ -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.7.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
 
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-WEQ3DMVL.js";
7
7
  import "./chunk-7XHATCIH.js";
8
- import "./chunk-5Q4R7HCL.js";
8
+ import "./chunk-JWKYU5GV.js";
9
9
  import {
10
10
  dispose,
11
11
  replaceChildrenSafely,
@@ -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 };
package/dist/ui.cjs CHANGED
@@ -834,7 +834,7 @@ function forEachSubscriber(signal2, visit) {
834
834
  }
835
835
 
836
836
  // src/reactivity/track.ts
837
- var _runtimeVersion = true ? "4.6.0" : "dev";
837
+ var _runtimeVersion = true ? "4.7.0" : "dev";
838
838
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
839
839
  function resolveReactiveApi() {
840
840
  const g = globalThis;
@@ -890,6 +890,14 @@ var getSubscriberCount2 = API.getSubscriberCount;
890
890
  var getSubscriberDeps2 = API.getSubscriberDeps;
891
891
  var forEachSubscriber2 = API.forEachSubscriber;
892
892
 
893
+ // src/core/devtoolsHook.ts
894
+ function emitDevtools(hook, event, payload) {
895
+ try {
896
+ hook.emit(event, payload);
897
+ } catch {
898
+ }
899
+ }
900
+
893
901
  // src/core/signals/derived.ts
894
902
  function derived(getter, options) {
895
903
  devAssert(typeof getter === "function", "derived: argument must be a getter function.");
@@ -916,17 +924,17 @@ function derived(getter, options) {
916
924
  cs._d = false;
917
925
  cs._init = true;
918
926
  };
919
- track2(() => {
920
- let threw = true;
921
- try {
927
+ try {
928
+ track2(() => {
922
929
  cs._v = getter();
923
930
  cs._d = false;
924
931
  cs._init = true;
925
- threw = false;
926
- } finally {
927
- if (threw) cs._d = true;
928
- }
929
- }, markDirty);
932
+ }, markDirty);
933
+ } catch (err) {
934
+ disposed = true;
935
+ cleanup2(markDirty);
936
+ throw err;
937
+ }
930
938
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
931
939
  const validate = () => {
932
940
  if (!cs._d || disposed || pendingError !== void 0) return;
@@ -945,7 +953,7 @@ function derived(getter, options) {
945
953
  if (disposed) cleanup2(markDirty);
946
954
  }
947
955
  if (hook && !disposed && !Object.is(oldValue, cs._v)) {
948
- hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
956
+ emitDevtools(hook, "computed:update", { signal: cs, oldValue, newValue: cs._v });
949
957
  }
950
958
  };
951
959
  cs._validate = validate;
@@ -996,7 +1004,7 @@ function derived(getter, options) {
996
1004
  }
997
1005
  }
998
1006
  };
999
- if (hook) hook.emit("computed:create", { signal: cs, name: debugName, getter: computedGetter });
1007
+ if (hook) emitDevtools(hook, "computed:create", { signal: cs, name: debugName, getter: computedGetter });
1000
1008
  return computedGetter;
1001
1009
  }
1002
1010
 
@@ -1083,7 +1091,7 @@ function signal(initial, options) {
1083
1091
  state2.__v++;
1084
1092
  if (DEV) {
1085
1093
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1086
- if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
1094
+ if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
1087
1095
  }
1088
1096
  if (!enqueueBatchedSignal(state2)) {
1089
1097
  notifySubscribers2(state2);
@@ -1097,7 +1105,7 @@ function signal(initial, options) {
1097
1105
  state2.value = newValue;
1098
1106
  state2.__v++;
1099
1107
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1100
- if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
1108
+ if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
1101
1109
  if (!enqueueBatchedSignal(state2)) {
1102
1110
  notifySubscribers2(state2);
1103
1111
  }
@@ -1116,7 +1124,7 @@ function signal(initial, options) {
1116
1124
  }
1117
1125
  if (DEV) {
1118
1126
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1119
- if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
1127
+ if (hook) emitDevtools(hook, "signal:create", { signal: state2, name: debugName, getter: get, initial });
1120
1128
  }
1121
1129
  return [get, set];
1122
1130
  }
@@ -3182,12 +3190,17 @@ function effect(effectFn, options) {
3182
3190
  try {
3183
3191
  retrack2(ctx.bodyFn, ctx.subscriber);
3184
3192
  if (ctx.rerunPending) drainReruns(ctx);
3193
+ } catch (err) {
3194
+ ctx.disposed = true;
3195
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
3196
+ cleanup2(ctx.subscriber);
3197
+ throw err;
3185
3198
  } finally {
3186
3199
  ctx.running = false;
3187
3200
  ctx.rerunPending = false;
3188
3201
  }
3189
3202
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
3190
- if (hook) hook.emit("effect:create", { effectFn });
3203
+ if (hook) emitDevtools(hook, "effect:create", { effectFn });
3191
3204
  return () => disposeEffect(ctx);
3192
3205
  }
3193
3206
 
package/dist/ui.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { A as AttributeSource, a as AttributeValue, B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, b as FocusTrap, c as FormConfig, d as FormField, e as FormReturn, I as IntersectionResult, M as MaskOptions, P as PaginationResult, T as Toast, f as ToastInstance, V as ValidatorFn, g as VirtualList, h as VirtualListProps, _ as __resetDialogStack, i as announce, j as aria, k as bindAttrs, l as bindBoolAttr, m as bindData, n as bindField, o as creditCardMask, p as custom, q as dateMask, r as defineElement, s as dialog, t as email, u as eventBus, v as focus, w as form, x as hotkey, y as infiniteScroll, z as inputMask, D as intersection, E as lazyLoad, G as matchesPattern, H as max, J as maxLength, K as min, L as minLength, N as pagination, O as phoneMask, Q as removeScopedStyle, R as required, S as scopedStyle, U as ssnMask, W as svgElement, X as timeMask, Y as toast, Z as withScopedStyle, $ as zipMask } from './customElement-MmInOW1U.cjs';
2
- export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, W as WithDefaultsProps, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-DRIuclVT.cjs';
2
+ export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, W as WithDefaultsProps, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-CTOJXu-x.cjs';
3
+ import './types-CJFViL6Q.cjs';
3
4
 
4
5
  /** The parts of a form-action handle available for every action signature. */
5
6
  interface FormActionState<TArgs extends unknown[], TResult> {
package/dist/ui.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { A as AttributeSource, a as AttributeValue, B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, b as FocusTrap, c as FormConfig, d as FormField, e as FormReturn, I as IntersectionResult, M as MaskOptions, P as PaginationResult, T as Toast, f as ToastInstance, V as ValidatorFn, g as VirtualList, h as VirtualListProps, _ as __resetDialogStack, i as announce, j as aria, k as bindAttrs, l as bindBoolAttr, m as bindData, n as bindField, o as creditCardMask, p as custom, q as dateMask, r as defineElement, s as dialog, t as email, u as eventBus, v as focus, w as form, x as hotkey, y as infiniteScroll, z as inputMask, D as intersection, E as lazyLoad, G as matchesPattern, H as max, J as maxLength, K as min, L as minLength, N as pagination, O as phoneMask, Q as removeScopedStyle, R as required, S as scopedStyle, U as ssnMask, W as svgElement, X as timeMask, Y as toast, Z as withScopedStyle, $ as zipMask } from './customElement-MmInOW1U.js';
2
- export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, W as WithDefaultsProps, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-DRIuclVT.js';
2
+ export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, W as WithDefaultsProps, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-CLqzJnOV.js';
3
+ import './types-CJFViL6Q.js';
3
4
 
4
5
  /** The parts of a form-action handle available for every action signature. */
5
6
  interface FormActionState<TArgs extends unknown[], TResult> {
package/dist/ui.js CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  toast,
39
39
  withScopedStyle,
40
40
  zipMask
41
- } from "./chunk-SXXVZMKZ.js";
41
+ } from "./chunk-2BPG2XDA.js";
42
42
  import {
43
43
  RenderProp,
44
44
  assertType,
@@ -57,23 +57,23 @@ import {
57
57
  } from "./chunk-TUCPL2HB.js";
58
58
  import {
59
59
  createId
60
- } from "./chunk-3ISI6ACU.js";
61
- import "./chunk-47M47FOM.js";
62
- import "./chunk-QE4TTDU3.js";
60
+ } from "./chunk-BC2SECJD.js";
61
+ import "./chunk-FNJXNGYZ.js";
62
+ import "./chunk-RUSSKG6G.js";
63
63
  import "./chunk-2INLLLMZ.js";
64
64
  import {
65
65
  globalSingleton
66
66
  } from "./chunk-7ZHH77QA.js";
67
67
  import {
68
68
  effect
69
- } from "./chunk-XC4MEKGA.js";
69
+ } from "./chunk-WEQ3DMVL.js";
70
70
  import "./chunk-7XHATCIH.js";
71
71
  import "./chunk-5HZXGZ6T.js";
72
72
  import {
73
73
  batch,
74
74
  signal
75
- } from "./chunk-D33YTSX5.js";
76
- import "./chunk-5Q4R7HCL.js";
75
+ } from "./chunk-FQRUXCEE.js";
76
+ import "./chunk-JWKYU5GV.js";
77
77
  import {
78
78
  registerDisposer,
79
79
  unregisterDisposer
package/dist/widgets.cjs CHANGED
@@ -709,7 +709,7 @@ function forEachSubscriber(signal2, visit) {
709
709
  }
710
710
 
711
711
  // src/reactivity/track.ts
712
- var _runtimeVersion = true ? "4.6.0" : "dev";
712
+ var _runtimeVersion = true ? "4.7.0" : "dev";
713
713
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
714
714
  function resolveReactiveApi() {
715
715
  const g = globalThis;
@@ -765,6 +765,14 @@ var getSubscriberCount2 = API.getSubscriberCount;
765
765
  var getSubscriberDeps2 = API.getSubscriberDeps;
766
766
  var forEachSubscriber2 = API.forEachSubscriber;
767
767
 
768
+ // src/core/devtoolsHook.ts
769
+ function emitDevtools(hook, event, payload) {
770
+ try {
771
+ hook.emit(event, payload);
772
+ } catch {
773
+ }
774
+ }
775
+
768
776
  // src/core/signals/derived.ts
769
777
  function derived(getter, options) {
770
778
  devAssert(typeof getter === "function", "derived: argument must be a getter function.");
@@ -791,17 +799,17 @@ function derived(getter, options) {
791
799
  cs._d = false;
792
800
  cs._init = true;
793
801
  };
794
- track2(() => {
795
- let threw = true;
796
- try {
802
+ try {
803
+ track2(() => {
797
804
  cs._v = getter();
798
805
  cs._d = false;
799
806
  cs._init = true;
800
- threw = false;
801
- } finally {
802
- if (threw) cs._d = true;
803
- }
804
- }, markDirty);
807
+ }, markDirty);
808
+ } catch (err) {
809
+ disposed = true;
810
+ cleanup2(markDirty);
811
+ throw err;
812
+ }
805
813
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
806
814
  const validate = () => {
807
815
  if (!cs._d || disposed || pendingError !== void 0) return;
@@ -820,7 +828,7 @@ function derived(getter, options) {
820
828
  if (disposed) cleanup2(markDirty);
821
829
  }
822
830
  if (hook && !disposed && !Object.is(oldValue, cs._v)) {
823
- hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
831
+ emitDevtools(hook, "computed:update", { signal: cs, oldValue, newValue: cs._v });
824
832
  }
825
833
  };
826
834
  cs._validate = validate;
@@ -871,7 +879,7 @@ function derived(getter, options) {
871
879
  }
872
880
  }
873
881
  };
874
- if (hook) hook.emit("computed:create", { signal: cs, name: debugName, getter: computedGetter });
882
+ if (hook) emitDevtools(hook, "computed:create", { signal: cs, name: debugName, getter: computedGetter });
875
883
  return computedGetter;
876
884
  }
877
885
 
@@ -958,7 +966,7 @@ function signal(initial, options) {
958
966
  state2.__v++;
959
967
  if (DEV) {
960
968
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
961
- if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
969
+ if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
962
970
  }
963
971
  if (!enqueueBatchedSignal(state2)) {
964
972
  notifySubscribers2(state2);
@@ -972,7 +980,7 @@ function signal(initial, options) {
972
980
  state2.value = newValue;
973
981
  state2.__v++;
974
982
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
975
- if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
983
+ if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
976
984
  if (!enqueueBatchedSignal(state2)) {
977
985
  notifySubscribers2(state2);
978
986
  }
@@ -991,7 +999,7 @@ function signal(initial, options) {
991
999
  }
992
1000
  if (DEV) {
993
1001
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
994
- if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
1002
+ if (hook) emitDevtools(hook, "signal:create", { signal: state2, name: debugName, getter: get, initial });
995
1003
  }
996
1004
  return [get, set];
997
1005
  }
package/dist/widgets.js CHANGED
@@ -8,14 +8,14 @@ import {
8
8
  select,
9
9
  tabs,
10
10
  tooltip
11
- } from "./chunk-HYXDKS4N.js";
12
- import "./chunk-UZQ6ALFS.js";
13
- import "./chunk-3ISI6ACU.js";
14
- import "./chunk-QE4TTDU3.js";
11
+ } from "./chunk-Z3OHK6QT.js";
12
+ import "./chunk-SLM3IA34.js";
13
+ import "./chunk-BC2SECJD.js";
14
+ import "./chunk-RUSSKG6G.js";
15
15
  import "./chunk-2INLLLMZ.js";
16
16
  import "./chunk-7XHATCIH.js";
17
- import "./chunk-D33YTSX5.js";
18
- import "./chunk-5Q4R7HCL.js";
17
+ import "./chunk-FQRUXCEE.js";
18
+ import "./chunk-JWKYU5GV.js";
19
19
  import "./chunk-NYNYSPK7.js";
20
20
  export {
21
21
  accordion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sibujs",
3
- "version": "4.6.0",
3
+ "version": "4.7.0",
4
4
  "description": "A function-based frontend framework with fine-grained reactivity and no virtual DOM. Tag factories return live DOM nodes you can hold and mutate, signals update only what changed, and nothing needs a compiler — it runs from a script tag or a bundler.",
5
5
  "keywords": [
6
6
  "frontend",
@@ -39,6 +39,7 @@
39
39
  "test:soak:gc": "node --expose-gc ./node_modules/vitest/vitest.mjs run -c vitest.soak.config.ts",
40
40
  "typecheck": "tsc --noEmit",
41
41
  "typecheck:tests": "tsc -p tsconfig.test.json",
42
+ "hooks:install": "node scripts/hooks/install.mjs",
42
43
  "certify:rc": "node scripts/certify/run.mjs",
43
44
  "build": "tsup index.ts data.ts browser.ts patterns.ts motion.ts ui.ts widgets.ts ssr.ts devtools.ts performance.ts ecosystem.ts plugins.ts build.ts testing.ts extras.ts --dts --format esm,cjs --out-dir dist --clean && tsup --config tsup.cdn.config.ts",
44
45
  "example:chess:build": "node scripts/build-example-chess.mjs",
@@ -49,7 +50,8 @@
49
50
  "bench:save": "node bench.mjs --save",
50
51
  "bench:check": "node bench.mjs --compare",
51
52
  "publish:npm": "node publish.mjs",
52
- "prepublishOnly": "npm run build"
53
+ "prepublishOnly": "npm run build",
54
+ "prepare": "node scripts/hooks/install.mjs"
53
55
  },
54
56
  "types": "dist/index.d.ts",
55
57
  "exports": {