sibujs 3.0.0 → 3.2.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 (78) hide show
  1. package/README.md +6 -0
  2. package/dist/browser.cjs +16 -8
  3. package/dist/browser.js +6 -5
  4. package/dist/build.cjs +276 -150
  5. package/dist/build.js +35 -24
  6. package/dist/cdn.global.js +7 -7
  7. package/dist/{chunk-RJIRT46U.js → chunk-2C4E3HBM.js} +5 -5
  8. package/dist/{chunk-XDKP4T7G.js → chunk-4JCAUOLN.js} +45 -23
  9. package/dist/{chunk-VSNLICTS.js → chunk-5N74TKLD.js} +1 -1
  10. package/dist/{chunk-XVYB3J6C.js → chunk-7XDYVJLE.js} +19 -9
  11. package/dist/{chunk-L52H775O.js → chunk-BGNLPNGV.js} +20 -12
  12. package/dist/{chunk-6QZO7MMG.js → chunk-C427DVQF.js} +1 -1
  13. package/dist/{chunk-5WD7BYTZ.js → chunk-FDY42FIU.js} +3 -2
  14. package/dist/{chunk-4YTVESDX.js → chunk-FOI23UJL.js} +11 -1
  15. package/dist/{chunk-2RA7SHDA.js → chunk-GOJMFRBL.js} +20 -4
  16. package/dist/{chunk-2KM2724A.js → chunk-GOUM4JCT.js} +6 -6
  17. package/dist/chunk-H3SRKIYX.js +17 -0
  18. package/dist/{chunk-NEWH4O5U.js → chunk-H6PCHJZQ.js} +2 -2
  19. package/dist/{chunk-UCS6AMJ7.js → chunk-HMJFCBRR.js} +26 -3
  20. package/dist/{chunk-JYD2PWXH.js → chunk-HXMS4SNP.js} +22 -15
  21. package/dist/{chunk-DF3GTP4Q.js → chunk-JYXOEYI4.js} +12 -18
  22. package/dist/{chunk-KZA7ANXP.js → chunk-NFYWLRUO.js} +11 -18
  23. package/dist/{chunk-KH4OE6WY.js → chunk-NPIEEKPT.js} +20 -11
  24. package/dist/{chunk-V65KTDZW.js → chunk-OYLPZO4N.js} +33 -15
  25. package/dist/{chunk-LYTCUZ7H.js → chunk-RDRSWYNP.js} +1 -1
  26. package/dist/{chunk-UKMXT5T6.js → chunk-RLUJL2MV.js} +7 -12
  27. package/dist/{chunk-INBOWHQ3.js → chunk-V2MTG5FT.js} +99 -36
  28. package/dist/{chunk-CNZ35WI2.js → chunk-VJE6DDYM.js} +2 -2
  29. package/dist/{chunk-2JQUV4Y3.js → chunk-VOCE4NNK.js} +157 -75
  30. package/dist/{chunk-STFTTMO2.js → chunk-X67UYC74.js} +31 -12
  31. package/dist/{chunk-YMOIAHWA.js → chunk-YFDGQWDA.js} +1 -1
  32. package/dist/{chunk-L4DAT4WU.js → chunk-Z2FWAE4B.js} +28 -1
  33. package/dist/data.cjs +211 -93
  34. package/dist/data.d.cts +7 -1
  35. package/dist/data.d.ts +7 -1
  36. package/dist/data.js +8 -8
  37. package/dist/devtools.cjs +38 -10
  38. package/dist/devtools.d.cts +1 -1
  39. package/dist/devtools.d.ts +1 -1
  40. package/dist/devtools.js +6 -6
  41. package/dist/ecosystem.cjs +163 -65
  42. package/dist/ecosystem.js +9 -9
  43. package/dist/extras.cjs +420 -198
  44. package/dist/extras.d.cts +2 -2
  45. package/dist/extras.d.ts +2 -2
  46. package/dist/extras.js +27 -24
  47. package/dist/index.cjs +255 -139
  48. package/dist/index.d.cts +15 -2
  49. package/dist/index.d.ts +15 -2
  50. package/dist/index.js +15 -13
  51. package/dist/{introspect-BZWKvQUZ.d.ts → introspect-DOZfmC-4.d.ts} +1 -1
  52. package/dist/{introspect-DsJlDD2T.d.cts → introspect-RjLfIFpL.d.cts} +1 -1
  53. package/dist/motion.cjs +10 -0
  54. package/dist/motion.js +3 -3
  55. package/dist/patterns.cjs +66 -39
  56. package/dist/patterns.js +8 -7
  57. package/dist/performance.cjs +101 -25
  58. package/dist/performance.d.cts +2 -2
  59. package/dist/performance.d.ts +2 -2
  60. package/dist/performance.js +8 -7
  61. package/dist/plugins.cjs +243 -138
  62. package/dist/plugins.d.cts +1 -1
  63. package/dist/plugins.d.ts +1 -1
  64. package/dist/plugins.js +96 -45
  65. package/dist/{ssr-FXD2PPMC.js → ssr-2QDQ27EV.js} +5 -3
  66. package/dist/{ssr-CrVNy6Pa.d.cts → ssr-D62yFwuw.d.cts} +8 -1
  67. package/dist/{ssr-CrVNy6Pa.d.ts → ssr-D62yFwuw.d.ts} +8 -1
  68. package/dist/ssr.cjs +185 -68
  69. package/dist/ssr.d.cts +1 -1
  70. package/dist/ssr.d.ts +1 -1
  71. package/dist/ssr.js +12 -10
  72. package/dist/testing.cjs +9 -4
  73. package/dist/testing.js +3 -3
  74. package/dist/ui.cjs +76 -39
  75. package/dist/ui.js +10 -9
  76. package/dist/widgets.cjs +61 -23
  77. package/dist/widgets.js +8 -8
  78. package/package.json +3 -1
package/dist/data.d.ts CHANGED
@@ -133,7 +133,7 @@ interface MutationResult<TData, TVariables> {
133
133
  /** Reset state to idle */
134
134
  reset: () => void;
135
135
  }
136
- declare function mutation<TData, TVariables = void, TContext = unknown>(mutationFn: (variables: TVariables) => Promise<TData>, options?: MutationOptions<TData, TVariables, TContext>): MutationResult<TData, TVariables>;
136
+ declare function mutation<TData, TVariables = void, TContext = unknown>(mutationFn: (variables: TVariables, signal?: AbortSignal) => Promise<TData>, options?: MutationOptions<TData, TVariables, TContext>): MutationResult<TData, TVariables>;
137
137
 
138
138
  interface InfiniteQueryOptions<TData, TPageParam = number> {
139
139
  /** Get the param for the next page. Return undefined to signal end. */
@@ -142,6 +142,12 @@ interface InfiniteQueryOptions<TData, TPageParam = number> {
142
142
  getPreviousPageParam?: (firstPage: TData, allPages: TData[]) => TPageParam | undefined;
143
143
  /** Initial page param. Default: 0 (for number) */
144
144
  initialPageParam?: TPageParam;
145
+ /**
146
+ * Maximum number of pages to retain. When exceeded, the oldest page is
147
+ * dropped from the opposite end (sliding window) to bound memory. Unset =
148
+ * unbounded.
149
+ */
150
+ maxPages?: number;
145
151
  /** Whether to fetch on creation. Default: true */
146
152
  enabled?: boolean;
147
153
  /** Retry options */
package/dist/data.js CHANGED
@@ -20,14 +20,14 @@ import {
20
20
  syncAdapter,
21
21
  throttle,
22
22
  withRetry
23
- } from "./chunk-2JQUV4Y3.js";
24
- import "./chunk-YMOIAHWA.js";
25
- import "./chunk-DF3GTP4Q.js";
26
- import "./chunk-UCS6AMJ7.js";
27
- import "./chunk-5WD7BYTZ.js";
28
- import "./chunk-2RA7SHDA.js";
29
- import "./chunk-6QZO7MMG.js";
30
- import "./chunk-L4DAT4WU.js";
23
+ } from "./chunk-VOCE4NNK.js";
24
+ import "./chunk-YFDGQWDA.js";
25
+ import "./chunk-JYXOEYI4.js";
26
+ import "./chunk-HMJFCBRR.js";
27
+ import "./chunk-FDY42FIU.js";
28
+ import "./chunk-GOJMFRBL.js";
29
+ import "./chunk-C427DVQF.js";
30
+ import "./chunk-Z2FWAE4B.js";
31
31
  import "./chunk-LMLD24FC.js";
32
32
  export {
33
33
  __resetQueryCache,
package/dist/devtools.cjs CHANGED
@@ -65,6 +65,7 @@ module.exports = __toCommonJS(devtools_exports);
65
65
  // src/devtools/debug.ts
66
66
  var debugEnabled = false;
67
67
  var perfMarks = /* @__PURE__ */ new Map();
68
+ var MAX_PERF_SAMPLES = 1e3;
68
69
  function enableDebug() {
69
70
  debugEnabled = true;
70
71
  console.log("[SibuJS] Debug mode enabled");
@@ -89,7 +90,11 @@ function perfTracker(label) {
89
90
  }
90
91
  function endMeasure() {
91
92
  const elapsed = globalThis.performance.now() - startTime;
92
- perfMarks.get(label)?.push(elapsed);
93
+ const marks = perfMarks.get(label);
94
+ if (marks) {
95
+ marks.push(elapsed);
96
+ if (marks.length > MAX_PERF_SAMPLES) marks.shift();
97
+ }
93
98
  if (debugEnabled) {
94
99
  debugLog("Perf", `${label}: ${elapsed.toFixed(2)}ms`);
95
100
  }
@@ -562,7 +567,20 @@ function signal(initial, options) {
562
567
 
563
568
  // src/utils/sanitize.ts
564
569
  function stripHtml(html) {
565
- return String(html).replace(/<[^>]*>/g, "");
570
+ const input = String(html);
571
+ if (typeof DOMParser !== "undefined") {
572
+ try {
573
+ return new DOMParser().parseFromString(input, "text/html").body.textContent ?? "";
574
+ } catch {
575
+ }
576
+ }
577
+ let prev;
578
+ let out = input;
579
+ do {
580
+ prev = out;
581
+ out = out.replace(/<[^>]*>/g, "");
582
+ } while (out !== prev);
583
+ return out.replace(/<[^>]*$/, "");
566
584
  }
567
585
 
568
586
  // src/devtools/devtools.ts
@@ -1494,7 +1512,7 @@ function withErrorTracking(name, component, reporter) {
1494
1512
  }
1495
1513
  };
1496
1514
  }
1497
- function formatError(error, context) {
1515
+ function formatError(error, context, seen = /* @__PURE__ */ new Set([error])) {
1498
1516
  const lines = [];
1499
1517
  const componentLabel = context?.component ?? (error instanceof SibuError ? error.component : void 0);
1500
1518
  if (componentLabel) {
@@ -1519,10 +1537,11 @@ function formatError(error, context) {
1519
1537
  lines.push(stackBody);
1520
1538
  }
1521
1539
  const cause = error.cause;
1522
- if (cause instanceof Error) {
1540
+ if (cause instanceof Error && !seen.has(cause)) {
1541
+ seen.add(cause);
1523
1542
  lines.push("");
1524
1543
  lines.push("Caused by:");
1525
- lines.push(formatError(cause));
1544
+ lines.push(formatError(cause, context, seen));
1526
1545
  }
1527
1546
  return lines.join("\n");
1528
1547
  }
@@ -1531,11 +1550,15 @@ function formatError(error, context) {
1531
1550
  var als = null;
1532
1551
  try {
1533
1552
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
1534
- const req = Function("return typeof require==='function'?require:null")();
1535
- if (req) {
1536
- const mod = req("node:async_hooks");
1537
- als = new mod.AsyncLocalStorage();
1553
+ let mod = null;
1554
+ const getBuiltin = process.getBuiltinModule;
1555
+ if (typeof getBuiltin === "function") {
1556
+ mod = getBuiltin("node:async_hooks");
1557
+ } else {
1558
+ const req = Function("return typeof require==='function'?require:null")();
1559
+ if (req) mod = req("node:async_hooks");
1538
1560
  }
1561
+ if (mod) als = new mod.AsyncLocalStorage();
1539
1562
  }
1540
1563
  } catch {
1541
1564
  als = null;
@@ -1637,6 +1660,7 @@ function effect(effectFn, options) {
1637
1660
  ctx.fn(ctx.onCleanup);
1638
1661
  };
1639
1662
  const sub = (() => {
1663
+ if (ctx.disposed) return;
1640
1664
  if (ctx.running) {
1641
1665
  ctx.rerunPending = true;
1642
1666
  return;
@@ -1681,7 +1705,11 @@ function debugValue(value, formatter) {
1681
1705
  const dispose2 = effect(() => {
1682
1706
  const resolved = value();
1683
1707
  entry.value = resolved;
1684
- entry.label = format(resolved);
1708
+ try {
1709
+ entry.label = format(resolved);
1710
+ } catch (err) {
1711
+ entry.label = `<format error: ${err instanceof Error ? err.message : String(err)}>`;
1712
+ }
1685
1713
  });
1686
1714
  return () => {
1687
1715
  dispose2();
@@ -1,4 +1,4 @@
1
- export { D as DevToolsEvent, a as DevtoolsOverlayOptions, P as ProfilerResult, R as ReactiveNodeInfo, S as SibuError, c as checkLeaks, b as clearDebugValues, d as clearHMRModule, e as clearHMRState, f as clearPerformanceData, g as createDevtoolsOverlay, h as createErrorReporter, i as createHMRBoundary, j as createProfiler, k as debugLog, l as debugValue, m as devState, n as disableDebug, o as enableDebug, p as exposeHMR, q as formatError, r as getActiveDevTools, s as getDebugValues, t as getDependencies, u as getPerformanceReport, v as getSignalName, w as getSubscriberCount, x as hmrState, y as initDevTools, z as inspectSignal, A as isDebugEnabled, B as isHMRAvailable, C as measureRender, E as perfTracker, F as registerHMR, G as runCleanups, H as startMeasure, I as trackCleanup, J as walkDependencyGraph, K as withErrorTracking } from './introspect-DsJlDD2T.cjs';
1
+ export { D as DevToolsEvent, a as DevtoolsOverlayOptions, P as ProfilerResult, R as ReactiveNodeInfo, S as SibuError, c as checkLeaks, b as clearDebugValues, d as clearHMRModule, e as clearHMRState, f as clearPerformanceData, g as createDevtoolsOverlay, h as createErrorReporter, i as createHMRBoundary, j as createProfiler, k as debugLog, l as debugValue, m as devState, n as disableDebug, o as enableDebug, p as exposeHMR, q as formatError, r as getActiveDevTools, s as getDebugValues, t as getDependencies, u as getPerformanceReport, v as getSignalName, w as getSubscriberCount, x as hmrState, y as initDevTools, z as inspectSignal, A as isDebugEnabled, B as isHMRAvailable, C as measureRender, E as perfTracker, F as registerHMR, G as runCleanups, H as startMeasure, I as trackCleanup, J as walkDependencyGraph, K as withErrorTracking } from './introspect-RjLfIFpL.cjs';
2
2
  import './signal-BnWpq6WB.cjs';
3
3
 
4
4
  interface SignalNodeSnapshot {
@@ -1,4 +1,4 @@
1
- export { D as DevToolsEvent, a as DevtoolsOverlayOptions, P as ProfilerResult, R as ReactiveNodeInfo, S as SibuError, c as checkLeaks, b as clearDebugValues, d as clearHMRModule, e as clearHMRState, f as clearPerformanceData, g as createDevtoolsOverlay, h as createErrorReporter, i as createHMRBoundary, j as createProfiler, k as debugLog, l as debugValue, m as devState, n as disableDebug, o as enableDebug, p as exposeHMR, q as formatError, r as getActiveDevTools, s as getDebugValues, t as getDependencies, u as getPerformanceReport, v as getSignalName, w as getSubscriberCount, x as hmrState, y as initDevTools, z as inspectSignal, A as isDebugEnabled, B as isHMRAvailable, C as measureRender, E as perfTracker, F as registerHMR, G as runCleanups, H as startMeasure, I as trackCleanup, J as walkDependencyGraph, K as withErrorTracking } from './introspect-BZWKvQUZ.js';
1
+ export { D as DevToolsEvent, a as DevtoolsOverlayOptions, P as ProfilerResult, R as ReactiveNodeInfo, S as SibuError, c as checkLeaks, b as clearDebugValues, d as clearHMRModule, e as clearHMRState, f as clearPerformanceData, g as createDevtoolsOverlay, h as createErrorReporter, i as createHMRBoundary, j as createProfiler, k as debugLog, l as debugValue, m as devState, n as disableDebug, o as enableDebug, p as exposeHMR, q as formatError, r as getActiveDevTools, s as getDebugValues, t as getDependencies, u as getPerformanceReport, v as getSignalName, w as getSubscriberCount, x as hmrState, y as initDevTools, z as inspectSignal, A as isDebugEnabled, B as isHMRAvailable, C as measureRender, E as perfTracker, F as registerHMR, G as runCleanups, H as startMeasure, I as trackCleanup, J as walkDependencyGraph, K as withErrorTracking } from './introspect-DOZfmC-4.js';
2
2
  import './signal-BnWpq6WB.js';
3
3
 
4
4
  interface SignalNodeSnapshot {
package/dist/devtools.js CHANGED
@@ -35,13 +35,13 @@ import {
35
35
  trackCleanup,
36
36
  walkDependencyGraph,
37
37
  withErrorTracking
38
- } from "./chunk-XVYB3J6C.js";
38
+ } from "./chunk-7XDYVJLE.js";
39
39
  import "./chunk-2UPRY23K.js";
40
- import "./chunk-UCS6AMJ7.js";
41
- import "./chunk-5WD7BYTZ.js";
42
- import "./chunk-2RA7SHDA.js";
43
- import "./chunk-6QZO7MMG.js";
44
- import "./chunk-L4DAT4WU.js";
40
+ import "./chunk-HMJFCBRR.js";
41
+ import "./chunk-FDY42FIU.js";
42
+ import "./chunk-GOJMFRBL.js";
43
+ import "./chunk-C427DVQF.js";
44
+ import "./chunk-Z2FWAE4B.js";
45
45
  import {
46
46
  isDev
47
47
  } from "./chunk-LMLD24FC.js";
@@ -176,7 +176,7 @@ function retrack(effectFn, subscriber) {
176
176
  }
177
177
  }
178
178
  function track(effectFn, subscriber) {
179
- if (!subscriber) subscriber = effectFn;
179
+ if (!subscriber) return reactiveBinding(effectFn);
180
180
  cleanup(subscriber);
181
181
  const prev = currentSubscriber;
182
182
  currentSubscriber = subscriber;
@@ -194,6 +194,32 @@ function track(effectFn, subscriber) {
194
194
  const sub = subscriber;
195
195
  return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
196
196
  }
197
+ function reactiveBinding(commit) {
198
+ const run = () => {
199
+ const s = subscriber;
200
+ if (s._disposed || s._reentrant) return;
201
+ s._reentrant = true;
202
+ try {
203
+ retrack(commit, subscriber);
204
+ } finally {
205
+ s._reentrant = false;
206
+ }
207
+ };
208
+ const subscriber = run;
209
+ subscriber.depsHead = null;
210
+ subscriber.depsTail = null;
211
+ subscriber._epoch = 0;
212
+ subscriber._structDirty = false;
213
+ subscriber._runEpoch = 0;
214
+ subscriber._runs = 0;
215
+ subscriber._reentrant = false;
216
+ subscriber._disposed = false;
217
+ run();
218
+ return subscriber._dispose ?? (subscriber._dispose = () => {
219
+ subscriber._disposed = true;
220
+ cleanup(subscriber);
221
+ });
222
+ }
197
223
  function recordDependency(signal2) {
198
224
  if (!currentSubscriber) return;
199
225
  const sub = currentSubscriber;
@@ -379,11 +405,15 @@ function notifySubscribers(signal2) {
379
405
  var als = null;
380
406
  try {
381
407
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
382
- const req = Function("return typeof require==='function'?require:null")();
383
- if (req) {
384
- const mod = req("node:async_hooks");
385
- als = new mod.AsyncLocalStorage();
408
+ let mod = null;
409
+ const getBuiltin = process.getBuiltinModule;
410
+ if (typeof getBuiltin === "function") {
411
+ mod = getBuiltin("node:async_hooks");
412
+ } else {
413
+ const req = Function("return typeof require==='function'?require:null")();
414
+ if (req) mod = req("node:async_hooks");
386
415
  }
416
+ if (mod) als = new mod.AsyncLocalStorage();
387
417
  }
388
418
  } catch {
389
419
  als = null;
@@ -485,6 +515,7 @@ function effect(effectFn, options) {
485
515
  ctx.fn(ctx.onCleanup);
486
516
  };
487
517
  const sub = (() => {
518
+ if (ctx.disposed) return;
488
519
  if (ctx.running) {
489
520
  ctx.rerunPending = true;
490
521
  return;
@@ -709,6 +740,18 @@ function mobXAdapter(options) {
709
740
  return createPlugin("sibu-mobx", (ctx) => {
710
741
  const { autorun } = options;
711
742
  const disposers = [];
743
+ function trackDisposer(rawDispose) {
744
+ let done = false;
745
+ const wrapped = () => {
746
+ if (done) return;
747
+ done = true;
748
+ const i = disposers.indexOf(wrapped);
749
+ if (i >= 0) disposers.splice(i, 1);
750
+ rawDispose();
751
+ };
752
+ disposers.push(wrapped);
753
+ return wrapped;
754
+ }
712
755
  function fromMobX(expression) {
713
756
  const [getValue, setValue] = signal(void 0);
714
757
  const disposer = autorun(() => {
@@ -717,22 +760,18 @@ function mobXAdapter(options) {
717
760
  setValue(newValue);
718
761
  });
719
762
  });
720
- disposers.push(disposer);
721
763
  const getter = (() => getValue());
722
- getter.dispose = () => {
723
- const i = disposers.indexOf(disposer);
724
- if (i >= 0) disposers.splice(i, 1);
725
- disposer();
726
- };
764
+ getter.dispose = trackDisposer(disposer);
727
765
  return getter;
728
766
  }
729
767
  function toMobX(sibuGetter, callback) {
730
- return effect(() => {
768
+ const stop = effect(() => {
731
769
  callback(sibuGetter());
732
770
  });
771
+ return trackDisposer(stop);
733
772
  }
734
773
  function destroy() {
735
- for (const disposer of disposers) {
774
+ for (const disposer of [...disposers]) {
736
775
  disposer();
737
776
  }
738
777
  disposers.length = 0;
@@ -749,6 +788,7 @@ function derived(getter, options) {
749
788
  const equals = options?.equals;
750
789
  const cs = {};
751
790
  cs._d = false;
791
+ cs._init = false;
752
792
  cs._g = getter;
753
793
  cs.__v = 0;
754
794
  const markDirty = () => {
@@ -757,11 +797,18 @@ function derived(getter, options) {
757
797
  };
758
798
  markDirty._c = 1;
759
799
  markDirty._sig = cs;
800
+ const recompute = () => {
801
+ const next = getter();
802
+ cs._v = equals && cs._init ? equals(cs._v, next) ? cs._v : next : next;
803
+ cs._d = false;
804
+ cs._init = true;
805
+ };
760
806
  track(() => {
761
807
  let threw = true;
762
808
  try {
763
809
  cs._v = getter();
764
810
  cs._d = false;
811
+ cs._init = true;
765
812
  threw = false;
766
813
  } finally {
767
814
  if (threw) cs._d = true;
@@ -777,20 +824,13 @@ function derived(getter, options) {
777
824
  }
778
825
  if (trackingSuspended) {
779
826
  if (cs._d) {
827
+ const prev = cs._v;
780
828
  evaluating = true;
781
- let threw = true;
782
829
  try {
783
- const prev = cs._v;
784
- retrack(() => {
785
- const next = getter();
786
- cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
787
- cs._d = false;
788
- threw = false;
789
- }, markDirty);
830
+ retrack(recompute, markDirty);
790
831
  if (!Object.is(prev, cs._v)) cs.__v++;
791
832
  } finally {
792
833
  evaluating = false;
793
- if (threw) cs._d = true;
794
834
  }
795
835
  }
796
836
  return cs._v;
@@ -799,18 +839,11 @@ function derived(getter, options) {
799
839
  if (cs._d) {
800
840
  const oldValue = cs._v;
801
841
  evaluating = true;
802
- let threw = true;
803
842
  try {
804
- retrack(() => {
805
- const next = getter();
806
- cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
807
- cs._d = false;
808
- threw = false;
809
- }, markDirty);
843
+ retrack(recompute, markDirty);
810
844
  if (!Object.is(oldValue, cs._v)) cs.__v++;
811
845
  } finally {
812
846
  evaluating = false;
813
- if (threw) cs._d = true;
814
847
  }
815
848
  if (hook && oldValue !== cs._v) {
816
849
  hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
@@ -877,9 +910,17 @@ function zustandAdapter(options) {
877
910
  }
878
911
 
879
912
  // src/utils/sanitize.ts
913
+ function stripControlChars(value) {
914
+ return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
915
+ }
916
+ function isEventHandlerAttr(name) {
917
+ if (name.length < 3) return false;
918
+ const lower = name.toLowerCase();
919
+ return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
920
+ }
880
921
  var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
881
922
  function sanitizeUrl(url) {
882
- const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
923
+ const trimmed = stripControlChars(url).trim();
883
924
  if (!trimmed) return "";
884
925
  const lower = trimmed.toLowerCase();
885
926
  let schemeEnd = -1;
@@ -942,7 +983,7 @@ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
942
983
  "data"
943
984
  ]);
944
985
  function isUrlAttribute(attr) {
945
- return URL_ATTRIBUTES.has(attr);
986
+ return URL_ATTRIBUTES.has(attr.toLowerCase());
946
987
  }
947
988
 
948
989
  // src/reactivity/bindAttribute.ts
@@ -950,11 +991,6 @@ var _isDev4 = isDev();
950
991
  function setProp(el, key, val) {
951
992
  el[key] = val;
952
993
  }
953
- function isEventHandlerAttr(name) {
954
- if (name.length < 3) return false;
955
- const lower = name.toLowerCase();
956
- return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
957
- }
958
994
  function bindAttribute(el, attr, getter) {
959
995
  if (isEventHandlerAttr(attr)) {
960
996
  if (_isDev4)
@@ -990,12 +1026,72 @@ function bindAttribute(el, attr, getter) {
990
1026
  el.setAttribute(attr, isUrlAttribute(attr) ? sanitizeUrl(str) : str);
991
1027
  }
992
1028
  }
993
- const teardown = track(commit);
994
- return teardown;
1029
+ return reactiveBinding(commit);
995
1030
  }
996
1031
 
997
- // src/reactivity/bindChildNode.ts
1032
+ // src/core/rendering/dispose.ts
1033
+ var elementDisposers = /* @__PURE__ */ new WeakMap();
998
1034
  var _isDev5 = isDev();
1035
+ var activeBindingCount = 0;
1036
+ function registerDisposer(node, teardown) {
1037
+ let disposers = elementDisposers.get(node);
1038
+ if (!disposers) {
1039
+ disposers = [];
1040
+ elementDisposers.set(node, disposers);
1041
+ }
1042
+ disposers.push(teardown);
1043
+ if (_isDev5) activeBindingCount++;
1044
+ }
1045
+ function dispose(node) {
1046
+ const stack = [node];
1047
+ const order = [];
1048
+ while (stack.length > 0) {
1049
+ const current = stack.pop();
1050
+ order.push(current);
1051
+ const children = Array.from(current.childNodes);
1052
+ for (let i = 0; i < children.length; i++) {
1053
+ stack.push(children[i]);
1054
+ }
1055
+ }
1056
+ for (let i = order.length - 1; i >= 0; i--) {
1057
+ const current = order[i];
1058
+ const disposers = elementDisposers.get(current);
1059
+ if (disposers) {
1060
+ const snapshot = disposers.slice();
1061
+ elementDisposers.delete(current);
1062
+ if (_isDev5) activeBindingCount -= snapshot.length;
1063
+ for (const d of snapshot) {
1064
+ try {
1065
+ d();
1066
+ } catch (err) {
1067
+ if (_isDev5 && typeof console !== "undefined") {
1068
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
1069
+ }
1070
+ }
1071
+ }
1072
+ let extraPasses = 0;
1073
+ while (extraPasses++ < 8) {
1074
+ const added = elementDisposers.get(current);
1075
+ if (!added || added.length === 0) break;
1076
+ const moreSnapshot = added.slice();
1077
+ elementDisposers.delete(current);
1078
+ if (_isDev5) activeBindingCount -= moreSnapshot.length;
1079
+ for (const d of moreSnapshot) {
1080
+ try {
1081
+ d();
1082
+ } catch (err) {
1083
+ if (_isDev5 && typeof console !== "undefined") {
1084
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
1085
+ }
1086
+ }
1087
+ }
1088
+ }
1089
+ }
1090
+ }
1091
+ }
1092
+
1093
+ // src/reactivity/bindChildNode.ts
1094
+ var _isDev6 = isDev();
999
1095
  function bindChildNode(placeholder, getter) {
1000
1096
  let lastNodes = [];
1001
1097
  function commit() {
@@ -1003,12 +1099,13 @@ function bindChildNode(placeholder, getter) {
1003
1099
  try {
1004
1100
  result = getter();
1005
1101
  } catch (err) {
1006
- if (_isDev5) devWarn(`bindChildNode: getter threw: ${err instanceof Error ? err.message : String(err)}`);
1102
+ if (_isDev6) devWarn(`bindChildNode: getter threw: ${err instanceof Error ? err.message : String(err)}`);
1007
1103
  return;
1008
1104
  }
1009
1105
  if (result == null || typeof result === "boolean") {
1010
1106
  for (let i = 0; i < lastNodes.length; i++) {
1011
1107
  const node = lastNodes[i];
1108
+ dispose(node);
1012
1109
  if (node.parentNode) node.parentNode.removeChild(node);
1013
1110
  }
1014
1111
  lastNodes.length = 0;
@@ -1028,7 +1125,7 @@ function bindChildNode(placeholder, getter) {
1028
1125
  if (item == null || typeof item === "boolean") continue;
1029
1126
  const node = item instanceof Node ? item : document.createTextNode(String(item));
1030
1127
  if (seen.has(node)) {
1031
- if (_isDev5)
1128
+ if (_isDev6)
1032
1129
  devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
1033
1130
  continue;
1034
1131
  }
@@ -1050,36 +1147,20 @@ function bindChildNode(placeholder, getter) {
1050
1147
  for (let i = 0; i < lastNodes.length; i++) {
1051
1148
  const node = lastNodes[i];
1052
1149
  if (reused?.has(node)) continue;
1150
+ dispose(node);
1053
1151
  if (node.parentNode) node.parentNode.removeChild(node);
1054
1152
  }
1055
- const anchor = placeholder.nextSibling;
1153
+ let prev = placeholder;
1056
1154
  for (let i = 0; i < newNodes.length; i++) {
1057
1155
  const node = newNodes[i];
1058
- if (reused?.has(node) && node.parentNode === parent) {
1059
- if (node.nextSibling !== anchor) {
1060
- parent.insertBefore(node, anchor);
1061
- }
1062
- } else {
1063
- parent.insertBefore(node, anchor);
1156
+ if (prev.nextSibling !== node) {
1157
+ parent.insertBefore(node, prev.nextSibling);
1064
1158
  }
1159
+ prev = node;
1065
1160
  }
1066
1161
  lastNodes = newNodes;
1067
1162
  }
1068
- return track(commit);
1069
- }
1070
-
1071
- // src/core/rendering/dispose.ts
1072
- var elementDisposers = /* @__PURE__ */ new WeakMap();
1073
- var _isDev6 = isDev();
1074
- var activeBindingCount = 0;
1075
- function registerDisposer(node, teardown) {
1076
- let disposers = elementDisposers.get(node);
1077
- if (!disposers) {
1078
- disposers = [];
1079
- elementDisposers.set(node, disposers);
1080
- }
1081
- disposers.push(teardown);
1082
- if (_isDev6) activeBindingCount++;
1163
+ return reactiveBinding(commit);
1083
1164
  }
1084
1165
 
1085
1166
  // src/core/rendering/tagFactory.ts
@@ -1107,6 +1188,18 @@ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
1107
1188
  function setProp2(el, key, val) {
1108
1189
  el[key] = val;
1109
1190
  }
1191
+ function looksLikeClassList(s) {
1192
+ const t = s.trim();
1193
+ if (!t) return false;
1194
+ const tokens = t.split(/\s+/);
1195
+ let sawClassish = false;
1196
+ for (let i = 0; i < tokens.length; i++) {
1197
+ const tok = tokens[i];
1198
+ if (!/^-?[A-Za-z_][A-Za-z0-9_:/.-]*$/.test(tok)) return false;
1199
+ if (/[-:/0-9]/.test(tok)) sawClassish = true;
1200
+ }
1201
+ return sawClassish;
1202
+ }
1110
1203
  var kebabCache = /* @__PURE__ */ new Map();
1111
1204
  function toKebab(prop) {
1112
1205
  let cached = kebabCache.get(prop);
@@ -1242,6 +1335,11 @@ var tagFactory = (tag, ns) => {
1242
1335
  appendChildren(el, second);
1243
1336
  return el;
1244
1337
  }
1338
+ if (_isDev7 && looksLikeClassList(first)) {
1339
+ devWarn(
1340
+ `tagFactory: lone string "${first}" looks like a class list but is being rendered as TEXT. For a class, use ${tag}({ class: "${first}" }) \u2014 or ${tag}("${first}", children) to set the class AND add children.`
1341
+ );
1342
+ }
1245
1343
  el.textContent = first;
1246
1344
  return el;
1247
1345
  }
@@ -1299,7 +1397,7 @@ var tagFactory = (tag, ns) => {
1299
1397
  const value = props[key];
1300
1398
  if (value == null) continue;
1301
1399
  const lkey = key.toLowerCase();
1302
- if (lkey[0] === "o" && lkey[1] === "n") continue;
1400
+ if (isEventHandlerAttr(key)) continue;
1303
1401
  if (typeof value === "function") {
1304
1402
  registerDisposer(el, bindAttribute(el, key, value));
1305
1403
  } else if (typeof value === "boolean") {
package/dist/ecosystem.js CHANGED
@@ -7,17 +7,17 @@ import {
7
7
  mobXAdapter,
8
8
  reduxAdapter,
9
9
  zustandAdapter
10
- } from "./chunk-L52H775O.js";
10
+ } from "./chunk-BGNLPNGV.js";
11
11
  import "./chunk-3JHCYHWN.js";
12
- import "./chunk-STFTTMO2.js";
13
- import "./chunk-UKMXT5T6.js";
14
- import "./chunk-DF3GTP4Q.js";
12
+ import "./chunk-X67UYC74.js";
13
+ import "./chunk-RLUJL2MV.js";
14
+ import "./chunk-JYXOEYI4.js";
15
15
  import "./chunk-2UPRY23K.js";
16
- import "./chunk-UCS6AMJ7.js";
17
- import "./chunk-5WD7BYTZ.js";
18
- import "./chunk-2RA7SHDA.js";
19
- import "./chunk-6QZO7MMG.js";
20
- import "./chunk-L4DAT4WU.js";
16
+ import "./chunk-HMJFCBRR.js";
17
+ import "./chunk-FDY42FIU.js";
18
+ import "./chunk-GOJMFRBL.js";
19
+ import "./chunk-C427DVQF.js";
20
+ import "./chunk-Z2FWAE4B.js";
21
21
  import "./chunk-LMLD24FC.js";
22
22
  export {
23
23
  antdAdapter,