sibujs 4.3.0 → 4.5.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 (77) hide show
  1. package/README.md +34 -4
  2. package/dist/browser.cjs +31 -2
  3. package/dist/browser.d.cts +15 -2
  4. package/dist/browser.d.ts +15 -2
  5. package/dist/browser.js +4 -4
  6. package/dist/build.cjs +92 -13
  7. package/dist/build.js +10 -10
  8. package/dist/cdn.dev.global.js +10 -10
  9. package/dist/cdn.full.dev.global.js +400 -0
  10. package/dist/cdn.full.global.js +398 -0
  11. package/dist/cdn.global.js +10 -10
  12. package/dist/{chunk-GZYQNIPS.js → chunk-2DCGACUU.js} +16 -9
  13. package/dist/{chunk-7BPN4MXR.js → chunk-3JZ4L5TJ.js} +10 -4
  14. package/dist/{chunk-R4EF7V3K.js → chunk-4PMLNECI.js} +4 -4
  15. package/dist/{chunk-IYHM4FWD.js → chunk-7LN645I6.js} +1 -1
  16. package/dist/{chunk-RE6KLGMV.js → chunk-B3WHI2QA.js} +1 -1
  17. package/dist/{chunk-ZVYNIUOG.js → chunk-FTIR4QW2.js} +13 -3
  18. package/dist/{chunk-G7GPNB6N.js → chunk-GW3SCCZG.js} +4 -4
  19. package/dist/{chunk-XGCZ45NH.js → chunk-KEISJXBU.js} +2 -2
  20. package/dist/{chunk-UD6YE2GW.js → chunk-OMJJM3KM.js} +2 -2
  21. package/dist/{chunk-7UBG6LDP.js → chunk-ONOHFDLG.js} +9 -1
  22. package/dist/{chunk-7UK6BSAT.js → chunk-PCT43HW3.js} +1 -1
  23. package/dist/{chunk-VJE6DDYM.js → chunk-R25EFXXC.js} +40 -26
  24. package/dist/{chunk-3E5YNK2F.js → chunk-RBTPLM32.js} +46 -8
  25. package/dist/{chunk-7BJLKDBI.js → chunk-RIXRAYIU.js} +1 -1
  26. package/dist/{chunk-7GQIRV27.js → chunk-RJE2BNI4.js} +3 -3
  27. package/dist/{chunk-2LSY4WDM.js → chunk-S373NSMK.js} +18 -13
  28. package/dist/{chunk-AAHT6AKT.js → chunk-TBYTO6BS.js} +2 -2
  29. package/dist/{chunk-TSL64O5L.js → chunk-UGRX3S57.js} +31 -2
  30. package/dist/{chunk-L4B3Y3OM.js → chunk-VUF4ALSW.js} +1 -1
  31. package/dist/{chunk-USS5ENJ2.js → chunk-VZKNK2V7.js} +9 -4
  32. package/dist/{chunk-MYA5HEK5.js → chunk-XZZOBQAY.js} +1 -1
  33. package/dist/{contracts-Hg6ITAEF.d.cts → contracts-DBdg9J_a.d.cts} +25 -4
  34. package/dist/{contracts-Hg6ITAEF.d.ts → contracts-DBdg9J_a.d.ts} +25 -4
  35. package/dist/{customElement-CNZxEB9G.d.ts → customElement-OB9CIsc5.d.cts} +38 -10
  36. package/dist/{customElement-CNZxEB9G.d.cts → customElement-OB9CIsc5.d.ts} +38 -10
  37. package/dist/data.cjs +81 -9
  38. package/dist/data.js +6 -6
  39. package/dist/devtools.cjs +41 -2
  40. package/dist/devtools.js +4 -4
  41. package/dist/ecosystem.cjs +83 -9
  42. package/dist/ecosystem.d.cts +13 -5
  43. package/dist/ecosystem.d.ts +13 -5
  44. package/dist/ecosystem.js +7 -7
  45. package/dist/extras.cjs +150 -40
  46. package/dist/extras.d.cts +3 -3
  47. package/dist/extras.d.ts +3 -3
  48. package/dist/extras.js +20 -20
  49. package/dist/index.cjs +92 -13
  50. package/dist/index.d.cts +24 -151
  51. package/dist/index.d.ts +24 -151
  52. package/dist/index.js +10 -10
  53. package/dist/motion.cjs +31 -2
  54. package/dist/motion.js +3 -3
  55. package/dist/patterns.cjs +116 -36
  56. package/dist/patterns.d.cts +6 -1
  57. package/dist/patterns.d.ts +6 -1
  58. package/dist/patterns.js +6 -6
  59. package/dist/performance.cjs +31 -2
  60. package/dist/performance.js +4 -4
  61. package/dist/plugins.cjs +39 -2
  62. package/dist/plugins.js +6 -6
  63. package/dist/ssr.cjs +39 -2
  64. package/dist/ssr.js +7 -7
  65. package/dist/tagFactory-DVoDpHye.d.cts +215 -0
  66. package/dist/tagFactory-DVoDpHye.d.ts +215 -0
  67. package/dist/testing.cjs +31 -2
  68. package/dist/testing.js +2 -2
  69. package/dist/ui.cjs +128 -39
  70. package/dist/ui.d.cts +2 -2
  71. package/dist/ui.d.ts +2 -2
  72. package/dist/ui.js +7 -7
  73. package/dist/widgets.cjs +75 -9
  74. package/dist/widgets.js +6 -6
  75. package/package.json +8 -2
  76. package/dist/tagFactory-Bzupt4Pj.d.cts +0 -55
  77. package/dist/tagFactory-Bzupt4Pj.d.ts +0 -55
@@ -182,6 +182,15 @@ declare function withProps<OuterProps extends object, InnerProps extends object>
182
182
  /**
183
183
  * Runtime prop validation and strict typing contracts for SibuJS.
184
184
  * Provides runtime type checking for component props in development mode.
185
+ *
186
+ * Both diagnostics here gate on `DEV`, the same foldable flag the rest of the
187
+ * framework uses, so a `__SIBU_DEV__: false` define removes them and their
188
+ * message text entirely. They used to test `process.env.NODE_ENV` directly,
189
+ * which is not a `define` target and does not exist in a browser at all — so
190
+ * every browser build treated itself as development: `validateProps` ran and
191
+ * warned, `assertType` threw, and the strings shipped. That went unnoticed
192
+ * while these functions were reachable only through a bundler; putting
193
+ * `patterns` on the CDN made them a production artifact.
185
194
  */
186
195
  /** Validator function: returns true if valid, or an error message string. */
187
196
  type Validator<T = unknown> = (value: T, propName: string) => true | string;
@@ -212,9 +221,19 @@ type PropSchema<Props> = {
212
221
  [K in keyof Props]: PropDef<Props[K]> | Validator<Props[K]>;
213
222
  };
214
223
  /**
215
- * Validate props against a schema. Returns validated props with defaults applied.
216
- * In production mode (process.env.NODE_ENV === 'production'), validation is skipped
217
- * and only defaults are applied for performance.
224
+ * Validate props against a schema, returning the props with defaults applied.
225
+ *
226
+ * Defaults are production behaviour; the checking is development-only and is
227
+ * compiled out of production builds. The two are not interchangeable when the
228
+ * schema's callbacks touch outside state: a validator that runs in development
229
+ * and not in production can leave a later property's default factory reading
230
+ * different state. Keep defaults and validators free of side effects if the
231
+ * two modes must agree exactly.
232
+ *
233
+ * @param props - The props to validate. Not mutated.
234
+ * @param schema - Per-property definitions, in either the shorthand
235
+ * (a bare {@link Validator}) or object form.
236
+ * @returns A new object: the props, plus any defaults that applied.
218
237
  */
219
238
  declare function validateProps<Props extends object>(props: Partial<Props>, schema: PropSchema<Props>): Props;
220
239
  /**
@@ -228,7 +247,9 @@ declare function defineStrictComponent<Props extends object>(config: {
228
247
  }): (props: Partial<Props>) => HTMLElement;
229
248
  /**
230
249
  * Assert that a value satisfies a contract at runtime.
231
- * No-op in production builds.
250
+ *
251
+ * No-op in production builds — genuinely, now. The previous guard returned early
252
+ * only when `process` existed, so in a browser it fell through and threw.
232
253
  */
233
254
  declare function assertType<T>(value: unknown, validator: Validator<T>, label?: string): asserts value is T;
234
255
  /**
@@ -148,6 +148,17 @@ interface VirtualListProps<T> {
148
148
  }
149
149
  /**
150
150
  * VirtualList renders only visible items for efficient large-list rendering.
151
+ *
152
+ * Scope — it virtualizes ONE axis:
153
+ * - vertical only, inside a container of fixed `containerHeight`;
154
+ * - every item has the same fixed `itemHeight`;
155
+ * - on each scroll or `items()` change the visible window is disposed and
156
+ * re-rendered through `renderItem` (no keyed reuse of item nodes);
157
+ * - no horizontal virtualization, frozen rows/columns or sticky headers.
158
+ *
159
+ * Two-axis content (spreadsheets, large grids with frozen headers) needs its
160
+ * own windowing, typically a keyed `each()` over the visible row indices with a
161
+ * nested keyed `each()` over the visible column indices.
151
162
  */
152
163
  declare function VirtualList<T>(props: VirtualListProps<T>): HTMLElement;
153
164
 
@@ -302,6 +313,12 @@ declare function bindAttrs(el: HTMLElement, attrs: Record<string, AttributeSourc
302
313
  * Reactively toggle a boolean attribute (like disabled, readonly, hidden).
303
314
  * When the value is truthy the attribute is present (set to ""),
304
315
  * when falsy the attribute is removed entirely.
316
+ *
317
+ * `aria-*` names are the exception, as in every attribute writer: ARIA states
318
+ * are "true"/"false" tokens, and a missing state means "not applicable" rather
319
+ * than `false`, so `bindBoolAttr(el, "aria-busy", false)` writes
320
+ * `aria-busy="false"`. This helper cannot remove an ARIA attribute; use
321
+ * `bindAttribute(el, "aria-busy", () => (busy() ? true : null))` for that.
305
322
  * Returns a teardown function to stop reactive tracking.
306
323
  *
307
324
  * The attribute NAME is policed too: `bindBoolAttr(el, "onclick", true)` would
@@ -403,14 +420,7 @@ declare function infiniteScroll(options: {
403
420
  dispose: () => void;
404
421
  };
405
422
 
406
- /**
407
- * pagination provides reactive pagination state and controls.
408
- */
409
- declare function pagination(options: {
410
- totalItems: () => number;
411
- pageSize?: number;
412
- initialPage?: number;
413
- }): {
423
+ interface PaginationResult {
414
424
  page: () => number;
415
425
  pageSize: () => number;
416
426
  totalPages: () => number;
@@ -419,7 +429,25 @@ declare function pagination(options: {
419
429
  goTo: (page: number) => void;
420
430
  startIndex: () => number;
421
431
  endIndex: () => number;
422
- };
432
+ /**
433
+ * Release the subscriptions to `totalItems`. Call it when the pagination is
434
+ * discarded before the state it reads. Afterwards the accessors return their
435
+ * last values and the controls no longer move the page. Idempotent.
436
+ */
437
+ dispose: () => void;
438
+ }
439
+ /**
440
+ * pagination provides reactive pagination state and controls.
441
+ *
442
+ * It subscribes to the caller's `totalItems` getter, which usually lives longer
443
+ * than the pagination itself (a store, a query result). Call `dispose()` when
444
+ * the pagination is no longer used, e.g. `onUnmount(pager.dispose, el)`.
445
+ */
446
+ declare function pagination(options: {
447
+ totalItems: () => number;
448
+ pageSize?: number;
449
+ initialPage?: number;
450
+ }): PaginationResult;
423
451
 
424
452
  /**
425
453
  * eventBus creates a typed publish/subscribe event system.
@@ -458,4 +486,4 @@ declare function defineElement(name: string, component: (props: Record<string, u
458
486
  */
459
487
  declare function svgElement(tag: string, props?: Record<string, unknown>, ...nodes: (SVGElement | string)[]): SVGElement;
460
488
 
461
- export { type AttributeSource as A, type BoundFieldProps as B, type CustomElementOptions as C, intersection as D, lazyLoad as E, type FieldConfig as F, matchesPattern as G, max as H, type IntersectionResult as I, maxLength as J, min as K, minLength as L, type MaskOptions as M, pagination as N, phoneMask as O, removeScopedStyle as P, required as Q, scopedStyle as R, ssnMask as S, type Toast as T, svgElement as U, type ValidatorFn as V, timeMask as W, toast as X, withScopedStyle as Y, zipMask as Z, __resetDialogStack as _, type AttributeValue as a, FocusTrap as b, type FormConfig as c, type FormField as d, type FormReturn as e, type ToastInstance as f, VirtualList as g, type VirtualListProps as h, announce as i, aria as j, bindAttrs as k, bindBoolAttr as l, bindData as m, bindField as n, creditCardMask as o, custom as p, dateMask as q, defineElement as r, dialog as s, email as t, eventBus as u, focus as v, form as w, hotkey as x, infiniteScroll as y, inputMask as z };
489
+ export { zipMask as $, type AttributeSource as A, type BoundFieldProps as B, type CustomElementOptions as C, intersection as D, lazyLoad as E, type FieldConfig as F, matchesPattern as G, max as H, type IntersectionResult as I, maxLength as J, min as K, minLength as L, type MaskOptions as M, pagination as N, phoneMask as O, type PaginationResult as P, removeScopedStyle as Q, required as R, scopedStyle as S, type Toast as T, ssnMask as U, type ValidatorFn as V, svgElement as W, timeMask as X, toast as Y, withScopedStyle as Z, __resetDialogStack as _, type AttributeValue as a, FocusTrap as b, type FormConfig as c, type FormField as d, type FormReturn as e, type ToastInstance as f, VirtualList as g, type VirtualListProps as h, announce as i, aria as j, bindAttrs as k, bindBoolAttr as l, bindData as m, bindField as n, creditCardMask as o, custom as p, dateMask as q, defineElement as r, dialog as s, email as t, eventBus as u, focus as v, form as w, hotkey as x, infiniteScroll as y, inputMask as z };
@@ -148,6 +148,17 @@ interface VirtualListProps<T> {
148
148
  }
149
149
  /**
150
150
  * VirtualList renders only visible items for efficient large-list rendering.
151
+ *
152
+ * Scope — it virtualizes ONE axis:
153
+ * - vertical only, inside a container of fixed `containerHeight`;
154
+ * - every item has the same fixed `itemHeight`;
155
+ * - on each scroll or `items()` change the visible window is disposed and
156
+ * re-rendered through `renderItem` (no keyed reuse of item nodes);
157
+ * - no horizontal virtualization, frozen rows/columns or sticky headers.
158
+ *
159
+ * Two-axis content (spreadsheets, large grids with frozen headers) needs its
160
+ * own windowing, typically a keyed `each()` over the visible row indices with a
161
+ * nested keyed `each()` over the visible column indices.
151
162
  */
152
163
  declare function VirtualList<T>(props: VirtualListProps<T>): HTMLElement;
153
164
 
@@ -302,6 +313,12 @@ declare function bindAttrs(el: HTMLElement, attrs: Record<string, AttributeSourc
302
313
  * Reactively toggle a boolean attribute (like disabled, readonly, hidden).
303
314
  * When the value is truthy the attribute is present (set to ""),
304
315
  * when falsy the attribute is removed entirely.
316
+ *
317
+ * `aria-*` names are the exception, as in every attribute writer: ARIA states
318
+ * are "true"/"false" tokens, and a missing state means "not applicable" rather
319
+ * than `false`, so `bindBoolAttr(el, "aria-busy", false)` writes
320
+ * `aria-busy="false"`. This helper cannot remove an ARIA attribute; use
321
+ * `bindAttribute(el, "aria-busy", () => (busy() ? true : null))` for that.
305
322
  * Returns a teardown function to stop reactive tracking.
306
323
  *
307
324
  * The attribute NAME is policed too: `bindBoolAttr(el, "onclick", true)` would
@@ -403,14 +420,7 @@ declare function infiniteScroll(options: {
403
420
  dispose: () => void;
404
421
  };
405
422
 
406
- /**
407
- * pagination provides reactive pagination state and controls.
408
- */
409
- declare function pagination(options: {
410
- totalItems: () => number;
411
- pageSize?: number;
412
- initialPage?: number;
413
- }): {
423
+ interface PaginationResult {
414
424
  page: () => number;
415
425
  pageSize: () => number;
416
426
  totalPages: () => number;
@@ -419,7 +429,25 @@ declare function pagination(options: {
419
429
  goTo: (page: number) => void;
420
430
  startIndex: () => number;
421
431
  endIndex: () => number;
422
- };
432
+ /**
433
+ * Release the subscriptions to `totalItems`. Call it when the pagination is
434
+ * discarded before the state it reads. Afterwards the accessors return their
435
+ * last values and the controls no longer move the page. Idempotent.
436
+ */
437
+ dispose: () => void;
438
+ }
439
+ /**
440
+ * pagination provides reactive pagination state and controls.
441
+ *
442
+ * It subscribes to the caller's `totalItems` getter, which usually lives longer
443
+ * than the pagination itself (a store, a query result). Call `dispose()` when
444
+ * the pagination is no longer used, e.g. `onUnmount(pager.dispose, el)`.
445
+ */
446
+ declare function pagination(options: {
447
+ totalItems: () => number;
448
+ pageSize?: number;
449
+ initialPage?: number;
450
+ }): PaginationResult;
423
451
 
424
452
  /**
425
453
  * eventBus creates a typed publish/subscribe event system.
@@ -458,4 +486,4 @@ declare function defineElement(name: string, component: (props: Record<string, u
458
486
  */
459
487
  declare function svgElement(tag: string, props?: Record<string, unknown>, ...nodes: (SVGElement | string)[]): SVGElement;
460
488
 
461
- export { type AttributeSource as A, type BoundFieldProps as B, type CustomElementOptions as C, intersection as D, lazyLoad as E, type FieldConfig as F, matchesPattern as G, max as H, type IntersectionResult as I, maxLength as J, min as K, minLength as L, type MaskOptions as M, pagination as N, phoneMask as O, removeScopedStyle as P, required as Q, scopedStyle as R, ssnMask as S, type Toast as T, svgElement as U, type ValidatorFn as V, timeMask as W, toast as X, withScopedStyle as Y, zipMask as Z, __resetDialogStack as _, type AttributeValue as a, FocusTrap as b, type FormConfig as c, type FormField as d, type FormReturn as e, type ToastInstance as f, VirtualList as g, type VirtualListProps as h, announce as i, aria as j, bindAttrs as k, bindBoolAttr as l, bindData as m, bindField as n, creditCardMask as o, custom as p, dateMask as q, defineElement as r, dialog as s, email as t, eventBus as u, focus as v, form as w, hotkey as x, infiniteScroll as y, inputMask as z };
489
+ export { zipMask as $, type AttributeSource as A, type BoundFieldProps as B, type CustomElementOptions as C, intersection as D, lazyLoad as E, type FieldConfig as F, matchesPattern as G, max as H, type IntersectionResult as I, maxLength as J, min as K, minLength as L, type MaskOptions as M, pagination as N, phoneMask as O, type PaginationResult as P, removeScopedStyle as Q, required as R, scopedStyle as S, type Toast as T, ssnMask as U, type ValidatorFn as V, svgElement as W, timeMask as X, toast as Y, withScopedStyle as Z, __resetDialogStack as _, type AttributeValue as a, FocusTrap as b, type FormConfig as c, type FormField as d, type FormReturn as e, type ToastInstance as f, VirtualList as g, type VirtualListProps as h, announce as i, aria as j, bindAttrs as k, bindBoolAttr as l, bindData as m, bindField as n, creditCardMask as o, custom as p, dateMask as q, defineElement as r, dialog as s, email as t, eventBus as u, focus as v, form as w, hotkey as x, infiniteScroll as y, inputMask as z };
package/dist/data.cjs CHANGED
@@ -295,6 +295,15 @@ function untracked(fn) {
295
295
  var subscriberEpochCounter = 0;
296
296
  function retrack(effectFn, subscriber) {
297
297
  const prev = currentSubscriber;
298
+ let savedDepth = 0;
299
+ let savedSuspendSub = null;
300
+ if (trackingSuspended) {
301
+ savedDepth = suspendDepth;
302
+ savedSuspendSub = suspendSavedSub;
303
+ suspendDepth = 0;
304
+ suspendSavedSub = null;
305
+ trackingSuspended = false;
306
+ }
298
307
  currentSubscriber = subscriber;
299
308
  const sub = subscriber;
300
309
  const epoch = ++subscriberEpochCounter;
@@ -309,6 +318,11 @@ function retrack(effectFn, subscriber) {
309
318
  effectFn();
310
319
  } finally {
311
320
  currentSubscriber = prev;
321
+ if (savedDepth !== 0) {
322
+ suspendDepth = savedDepth;
323
+ suspendSavedSub = savedSuspendSub;
324
+ trackingSuspended = true;
325
+ }
312
326
  let node = sub.depsHead ?? null;
313
327
  while (node !== null) {
314
328
  const next = node.subNext;
@@ -328,11 +342,25 @@ function track(effectFn, subscriber) {
328
342
  if (!subscriber) return reactiveBinding(effectFn);
329
343
  cleanup(subscriber);
330
344
  const prev = currentSubscriber;
345
+ let savedDepth = 0;
346
+ let savedSuspendSub = null;
347
+ if (trackingSuspended) {
348
+ savedDepth = suspendDepth;
349
+ savedSuspendSub = suspendSavedSub;
350
+ suspendDepth = 0;
351
+ suspendSavedSub = null;
352
+ trackingSuspended = false;
353
+ }
331
354
  currentSubscriber = subscriber;
332
355
  try {
333
356
  effectFn();
334
357
  } finally {
335
358
  currentSubscriber = prev;
359
+ if (savedDepth !== 0) {
360
+ suspendDepth = savedDepth;
361
+ suspendSavedSub = savedSuspendSub;
362
+ trackingSuspended = true;
363
+ }
336
364
  const sub2 = subscriber;
337
365
  for (let n = sub2.depsHead ?? null; n !== null; n = n.subNext) {
338
366
  const sig = n.sig;
@@ -503,8 +531,9 @@ function propagateDirty(sub) {
503
531
  if (s._c) {
504
532
  const nSig = s._sig;
505
533
  if (nSig) {
506
- if (!nSig._d) {
534
+ if (!nSig._d || nSig._f === true) {
507
535
  nSig._d = true;
536
+ nSig._f = false;
508
537
  stack.push(nSig);
509
538
  }
510
539
  } else {
@@ -604,7 +633,7 @@ function forEachSubscriber(signal2, visit) {
604
633
  }
605
634
 
606
635
  // src/reactivity/track.ts
607
- var _runtimeVersion = true ? "4.3.0" : "dev";
636
+ var _runtimeVersion = true ? "4.5.0" : "dev";
608
637
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
609
638
  function resolveReactiveApi() {
610
639
  const g = globalThis;
@@ -668,10 +697,14 @@ function derived(getter, options) {
668
697
  const cs = {};
669
698
  cs._d = false;
670
699
  cs._init = false;
700
+ cs._f = false;
671
701
  cs._g = getter;
672
702
  cs.__v = 0;
703
+ let evaluating = false;
704
+ let disposed = false;
705
+ let pendingError;
673
706
  const markDirty = () => {
674
- if (cs._d) return;
707
+ if (cs._d || disposed) return;
675
708
  cs._d = true;
676
709
  };
677
710
  markDirty._c = 1;
@@ -694,33 +727,53 @@ function derived(getter, options) {
694
727
  }
695
728
  }, markDirty);
696
729
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
697
- let evaluating = false;
698
730
  const validate = () => {
699
- if (!cs._d) return;
731
+ if (!cs._d || disposed || pendingError !== void 0) return;
700
732
  const oldValue = cs._v;
701
733
  evaluating = true;
702
734
  try {
703
735
  retrack2(recompute, markDirty);
704
736
  if (!Object.is(oldValue, cs._v)) cs.__v++;
737
+ } catch (err) {
738
+ pendingError = { error: err };
739
+ cs.__v++;
740
+ if (disposed) cs._d = true;
741
+ else cs._f = true;
705
742
  } finally {
706
743
  evaluating = false;
744
+ if (disposed) cleanup2(markDirty);
707
745
  }
708
- if (hook && !Object.is(oldValue, cs._v)) {
746
+ if (hook && !disposed && !Object.is(oldValue, cs._v)) {
709
747
  hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
710
748
  }
711
749
  };
712
750
  cs._validate = validate;
751
+ const throwPending = () => {
752
+ const { error } = pendingError;
753
+ pendingError = void 0;
754
+ if (disposed) cs._d = false;
755
+ throw error;
756
+ };
713
757
  function computedGetter() {
714
758
  if (evaluating) {
715
759
  throw new Error(
716
760
  `[SibuJS] Circular dependency detected in derived${debugName ? ` "${debugName}"` : ""}. A derived signal cannot read itself (directly or through a chain).`
717
761
  );
718
762
  }
719
- if (isTrackingSuspended2()) {
720
- if (cs._d) validate();
763
+ if (isTrackingSuspended2() || disposed) {
764
+ if (cs._d) {
765
+ validate();
766
+ if (pendingError !== void 0) throwPending();
767
+ }
721
768
  return cs._v;
722
769
  }
723
- if (cs._d) validate();
770
+ if (cs._d) {
771
+ validate();
772
+ if (pendingError !== void 0) {
773
+ recordDependency2(cs);
774
+ throwPending();
775
+ }
776
+ }
724
777
  recordDependency2(cs);
725
778
  return cs._v;
726
779
  }
@@ -729,6 +782,19 @@ function derived(getter, options) {
729
782
  cs.__name = debugName;
730
783
  }
731
784
  computedGetter.__signal = cs;
785
+ computedGetter.dispose = () => {
786
+ if (disposed) return;
787
+ disposed = true;
788
+ cs._d = pendingError !== void 0;
789
+ cleanup2(markDirty);
790
+ const h = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
791
+ if (h) {
792
+ try {
793
+ h.emit("computed:destroy", { signal: cs, getter: computedGetter });
794
+ } catch {
795
+ }
796
+ }
797
+ };
732
798
  if (hook) hook.emit("computed:create", { signal: cs, name: debugName, getter: computedGetter });
733
799
  return computedGetter;
734
800
  }
@@ -1402,6 +1468,8 @@ function query(key, fetcher, options = {}) {
1402
1468
  if (disposed) return;
1403
1469
  disposed = true;
1404
1470
  effectCleanup();
1471
+ loading.dispose();
1472
+ isStale.dispose();
1405
1473
  if (intervalTimer) clearInterval(intervalTimer);
1406
1474
  detachFromEntry();
1407
1475
  if (focusHandler && typeof globalThis.removeEventListener === "function") {
@@ -1691,6 +1759,10 @@ function infiniteQuery(key, fetcher, options) {
1691
1759
  disposed = true;
1692
1760
  abortController?.abort();
1693
1761
  effectCleanup();
1762
+ data.dispose();
1763
+ loading.dispose();
1764
+ hasNextPage.dispose();
1765
+ hasPreviousPage.dispose();
1694
1766
  }
1695
1767
  return {
1696
1768
  data,
package/dist/data.js CHANGED
@@ -20,15 +20,15 @@ import {
20
20
  syncAdapter,
21
21
  throttle,
22
22
  withRetry
23
- } from "./chunk-7BPN4MXR.js";
24
- import "./chunk-L4B3Y3OM.js";
25
- import "./chunk-3E5YNK2F.js";
23
+ } from "./chunk-3JZ4L5TJ.js";
24
+ import "./chunk-VUF4ALSW.js";
25
+ import "./chunk-RBTPLM32.js";
26
26
  import "./chunk-IXKSNWV5.js";
27
27
  import "./chunk-7ZHH77QA.js";
28
- import "./chunk-7BJLKDBI.js";
28
+ import "./chunk-RIXRAYIU.js";
29
29
  import "./chunk-5DXA2J44.js";
30
- import "./chunk-MYA5HEK5.js";
31
- import "./chunk-TSL64O5L.js";
30
+ import "./chunk-XZZOBQAY.js";
31
+ import "./chunk-UGRX3S57.js";
32
32
  import "./chunk-2WLZ6757.js";
33
33
  export {
34
34
  __resetQueryCache,
package/dist/devtools.cjs CHANGED
@@ -427,6 +427,15 @@ function untracked(fn) {
427
427
  var subscriberEpochCounter = 0;
428
428
  function retrack(effectFn, subscriber) {
429
429
  const prev = currentSubscriber;
430
+ let savedDepth = 0;
431
+ let savedSuspendSub = null;
432
+ if (trackingSuspended) {
433
+ savedDepth = suspendDepth;
434
+ savedSuspendSub = suspendSavedSub;
435
+ suspendDepth = 0;
436
+ suspendSavedSub = null;
437
+ trackingSuspended = false;
438
+ }
430
439
  currentSubscriber = subscriber;
431
440
  const sub = subscriber;
432
441
  const epoch = ++subscriberEpochCounter;
@@ -441,6 +450,11 @@ function retrack(effectFn, subscriber) {
441
450
  effectFn();
442
451
  } finally {
443
452
  currentSubscriber = prev;
453
+ if (savedDepth !== 0) {
454
+ suspendDepth = savedDepth;
455
+ suspendSavedSub = savedSuspendSub;
456
+ trackingSuspended = true;
457
+ }
444
458
  let node = sub.depsHead ?? null;
445
459
  while (node !== null) {
446
460
  const next = node.subNext;
@@ -460,11 +474,25 @@ function track(effectFn, subscriber) {
460
474
  if (!subscriber) return reactiveBinding(effectFn);
461
475
  cleanup(subscriber);
462
476
  const prev = currentSubscriber;
477
+ let savedDepth = 0;
478
+ let savedSuspendSub = null;
479
+ if (trackingSuspended) {
480
+ savedDepth = suspendDepth;
481
+ savedSuspendSub = suspendSavedSub;
482
+ suspendDepth = 0;
483
+ suspendSavedSub = null;
484
+ trackingSuspended = false;
485
+ }
463
486
  currentSubscriber = subscriber;
464
487
  try {
465
488
  effectFn();
466
489
  } finally {
467
490
  currentSubscriber = prev;
491
+ if (savedDepth !== 0) {
492
+ suspendDepth = savedDepth;
493
+ suspendSavedSub = savedSuspendSub;
494
+ trackingSuspended = true;
495
+ }
468
496
  const sub2 = subscriber;
469
497
  for (let n = sub2.depsHead ?? null; n !== null; n = n.subNext) {
470
498
  const sig = n.sig;
@@ -635,8 +663,9 @@ function propagateDirty(sub) {
635
663
  if (s._c) {
636
664
  const nSig = s._sig;
637
665
  if (nSig) {
638
- if (!nSig._d) {
666
+ if (!nSig._d || nSig._f === true) {
639
667
  nSig._d = true;
668
+ nSig._f = false;
640
669
  stack.push(nSig);
641
670
  }
642
671
  } else {
@@ -736,7 +765,7 @@ function forEachSubscriber(signal2, visit) {
736
765
  }
737
766
 
738
767
  // src/reactivity/track.ts
739
- var _runtimeVersion = true ? "4.3.0" : "dev";
768
+ var _runtimeVersion = true ? "4.5.0" : "dev";
740
769
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
741
770
  function resolveReactiveApi() {
742
771
  const g = globalThis;
@@ -1102,6 +1131,16 @@ function initDevTools(config) {
1102
1131
  });
1103
1132
  emit();
1104
1133
  });
1134
+ hook.on("computed:destroy", (payload) => {
1135
+ const p = payload;
1136
+ for (const [id, node] of hook.nodes) {
1137
+ if (node.ref === p.signal) {
1138
+ hook.nodes.delete(id);
1139
+ break;
1140
+ }
1141
+ }
1142
+ emit();
1143
+ });
1105
1144
  hook.on("effect:create", (payload) => {
1106
1145
  _dt.nextNodeId++;
1107
1146
  const name = inferName();
package/dist/devtools.js CHANGED
@@ -35,14 +35,14 @@ import {
35
35
  trackCleanup,
36
36
  walkDependencyGraph,
37
37
  withErrorTracking
38
- } from "./chunk-ZVYNIUOG.js";
38
+ } from "./chunk-FTIR4QW2.js";
39
39
  import "./chunk-IXKSNWV5.js";
40
40
  import "./chunk-7ZHH77QA.js";
41
- import "./chunk-7BJLKDBI.js";
41
+ import "./chunk-RIXRAYIU.js";
42
42
  import "./chunk-5DXA2J44.js";
43
43
  import "./chunk-QKRPLZ2V.js";
44
- import "./chunk-MYA5HEK5.js";
45
- import "./chunk-TSL64O5L.js";
44
+ import "./chunk-XZZOBQAY.js";
45
+ import "./chunk-UGRX3S57.js";
46
46
  import {
47
47
  isDev
48
48
  } from "./chunk-2WLZ6757.js";