sibujs 3.4.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +118 -15
  3. package/dist/browser.cjs +410 -101
  4. package/dist/browser.d.cts +50 -5
  5. package/dist/browser.d.ts +50 -5
  6. package/dist/browser.js +8 -6
  7. package/dist/build.cjs +777 -385
  8. package/dist/build.js +15 -15
  9. package/dist/cdn.global.js +11 -7
  10. package/dist/{chunk-JCO7AHNU.js → chunk-3EKJK5FZ.js} +73 -34
  11. package/dist/chunk-4MFZMLUU.js +147 -0
  12. package/dist/chunk-52XFPGSN.js +123 -0
  13. package/dist/chunk-5INI7D2L.js +194 -0
  14. package/dist/{chunk-OAVXAFAY.js → chunk-6LG2T7LO.js} +5 -5
  15. package/dist/{chunk-OOUQUCNN.js → chunk-ACBT6UZS.js} +57 -22
  16. package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
  17. package/dist/chunk-DHDZ7IVN.js +109 -0
  18. package/dist/{chunk-JNGGM2XE.js → chunk-DQVUBVNX.js} +16 -25
  19. package/dist/{chunk-AXFWGY32.js → chunk-DR7H6UGM.js} +232 -67
  20. package/dist/{chunk-WSGLJYFI.js → chunk-E62UADKL.js} +9 -3
  21. package/dist/{chunk-3Z2NGWQI.js → chunk-ES2GERY2.js} +1 -1
  22. package/dist/{chunk-S3V6ZXPI.js → chunk-EWEE7NBF.js} +115 -41
  23. package/dist/{chunk-3DVGCW7O.js → chunk-F64ZPCFE.js} +8 -8
  24. package/dist/{chunk-APFRCIRI.js → chunk-GCSGGA3Q.js} +295 -198
  25. package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
  26. package/dist/{chunk-ELXMRSVN.js → chunk-NF3LYCQH.js} +259 -124
  27. package/dist/chunk-O3QQ3XOL.js +61 -0
  28. package/dist/{chunk-BUKYCWHX.js → chunk-PBQEW5VW.js} +14 -10
  29. package/dist/{chunk-H5FI5WDP.js → chunk-RRIDJQ5C.js} +3 -3
  30. package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
  31. package/dist/{chunk-ODXVQ3CS.js → chunk-VFHIVEPF.js} +309 -188
  32. package/dist/chunk-VPP2FONR.js +142 -0
  33. package/dist/{chunk-KZBEVFXZ.js → chunk-W55YHPEP.js} +5 -3
  34. package/dist/{chunk-FKQG7FTY.js → chunk-WN6WDFCB.js} +4 -4
  35. package/dist/{chunk-CEBWDD63.js → chunk-WOOMUJFT.js} +228 -86
  36. package/dist/{chunk-ITWCTZYH.js → chunk-Z2CE42DB.js} +19 -25
  37. package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.cts} +6 -6
  38. package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.ts} +6 -6
  39. package/dist/{customElement-CPfIrbvg.d.ts → customElement-CKLoO63w.d.cts} +73 -11
  40. package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.ts} +73 -11
  41. package/dist/data.cjs +483 -205
  42. package/dist/data.d.cts +139 -7
  43. package/dist/data.d.ts +139 -7
  44. package/dist/data.js +9 -9
  45. package/dist/devtools.cjs +222 -87
  46. package/dist/devtools.js +8 -8
  47. package/dist/dispose-4FZ6OFXR.js +19 -0
  48. package/dist/ecosystem.cjs +419 -175
  49. package/dist/ecosystem.js +11 -11
  50. package/dist/extras.cjs +1981 -765
  51. package/dist/extras.d.cts +7 -7
  52. package/dist/extras.d.ts +7 -7
  53. package/dist/extras.js +29 -26
  54. package/dist/index.cjs +784 -385
  55. package/dist/index.d.cts +299 -28
  56. package/dist/index.d.ts +299 -28
  57. package/dist/index.js +33 -18
  58. package/dist/motion.cjs +180 -50
  59. package/dist/motion.d.cts +26 -0
  60. package/dist/motion.d.ts +26 -0
  61. package/dist/motion.js +5 -5
  62. package/dist/patterns.cjs +437 -170
  63. package/dist/patterns.d.cts +60 -13
  64. package/dist/patterns.d.ts +60 -13
  65. package/dist/patterns.js +7 -7
  66. package/dist/performance.cjs +333 -148
  67. package/dist/performance.d.cts +55 -7
  68. package/dist/performance.d.ts +55 -7
  69. package/dist/performance.js +9 -9
  70. package/dist/plugins.cjs +1374 -576
  71. package/dist/plugins.d.cts +227 -9
  72. package/dist/plugins.d.ts +227 -9
  73. package/dist/plugins.js +613 -321
  74. package/dist/{ssr-D62yFwuw.d.cts → ssr-BiPRdZ6n.d.cts} +44 -15
  75. package/dist/{ssr-D62yFwuw.d.ts → ssr-BiPRdZ6n.d.ts} +44 -15
  76. package/dist/{ssr-2PPULEK2.js → ssr-JFP5535P.js} +5 -4
  77. package/dist/ssr.cjs +1104 -443
  78. package/dist/ssr.d.cts +230 -20
  79. package/dist/ssr.d.ts +230 -20
  80. package/dist/ssr.js +15 -12
  81. package/dist/{startup-0Qv6aosO.d.cts → startup-BMpaiMhP.d.cts} +1 -1
  82. package/dist/{startup-0Qv6aosO.d.ts → startup-BMpaiMhP.d.ts} +1 -1
  83. package/dist/testing.cjs +205 -63
  84. package/dist/testing.d.cts +1 -1
  85. package/dist/testing.d.ts +1 -1
  86. package/dist/testing.js +8 -10
  87. package/dist/ui.cjs +640 -199
  88. package/dist/ui.d.cts +2 -2
  89. package/dist/ui.d.ts +2 -2
  90. package/dist/ui.js +10 -10
  91. package/dist/widgets.cjs +207 -82
  92. package/dist/widgets.js +9 -9
  93. package/package.json +12 -7
  94. package/dist/chunk-5VGSK6D2.js +0 -80
  95. package/dist/chunk-COY6PUD2.js +0 -34
  96. package/dist/chunk-K35BAR4P.js +0 -96
  97. package/dist/chunk-L3GAGWCC.js +0 -111
  98. package/dist/chunk-RT3IYFN2.js +0 -38
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  devWarn,
3
- isDev
4
- } from "./chunk-COY6PUD2.js";
3
+ isDev,
4
+ reportError
5
+ } from "./chunk-VPP2FONR.js";
5
6
 
6
7
  // src/reactivity/track-core.ts
7
- var _isDev = isDev();
8
8
  var POOL_MAX = 4096;
9
9
  var nodePool = [];
10
10
  function createNode() {
@@ -12,6 +12,7 @@ function createNode() {
12
12
  sig: null,
13
13
  sub: null,
14
14
  epoch: 0,
15
+ depVersion: 0,
15
16
  sigPrev: null,
16
17
  sigNext: null,
17
18
  subPrev: null,
@@ -96,8 +97,27 @@ function safeInvoke(sub) {
96
97
  try {
97
98
  sub();
98
99
  } catch (err) {
99
- if (_isDev) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
100
+ const s = sub;
101
+ reportError(err, { phase: s._errorPhase ?? "effect", name: s.__name, node: s._errorNode });
102
+ }
103
+ }
104
+ function depsChanged(sub) {
105
+ let node = sub.depsHead ?? null;
106
+ if (node === null) return true;
107
+ while (node !== null) {
108
+ const sig = node.sig;
109
+ if (sig === null) return true;
110
+ if (sig._d === true && sig._validate !== void 0) {
111
+ try {
112
+ sig._validate();
113
+ } catch {
114
+ return true;
115
+ }
116
+ }
117
+ if (node.depVersion !== sig.__v) return true;
118
+ node = node.subNext;
100
119
  }
120
+ return false;
101
121
  }
102
122
  var suspendDepth = 0;
103
123
  var trackingSuspended = false;
@@ -179,7 +199,7 @@ function track(effectFn, subscriber) {
179
199
  const sub = subscriber;
180
200
  return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
181
201
  }
182
- function reactiveBinding(commit) {
202
+ function reactiveBinding(commit, ownerNode) {
183
203
  const run = () => {
184
204
  const s = subscriber;
185
205
  if (s._disposed || s._reentrant) return;
@@ -195,13 +215,17 @@ function reactiveBinding(commit) {
195
215
  subscriber.depsTail = null;
196
216
  subscriber._epoch = 0;
197
217
  subscriber._structDirty = false;
218
+ subscriber._hasComputedDep = false;
198
219
  subscriber._runEpoch = 0;
199
220
  subscriber._runs = 0;
200
221
  subscriber._reentrant = false;
201
222
  subscriber._disposed = false;
223
+ subscriber._errorPhase = "binding";
224
+ subscriber._errorNode = ownerNode;
202
225
  run();
203
226
  return subscriber._dispose ?? (subscriber._dispose = () => {
204
227
  subscriber._disposed = true;
228
+ subscriber._errorNode = void 0;
205
229
  cleanup(subscriber);
206
230
  });
207
231
  }
@@ -213,9 +237,12 @@ function recordDependency(signal) {
213
237
  const active = sig.__activeNode ?? null;
214
238
  if (active !== null && active.sub === sub) {
215
239
  active.epoch = epoch;
240
+ active.depVersion = sig.__v ?? Number.NaN;
216
241
  return;
217
242
  }
243
+ if (sig._validate !== void 0) sub._hasComputedDep = true;
218
244
  const node = allocNode(signal, sub, epoch);
245
+ node.depVersion = sig.__v ?? Number.NaN;
219
246
  node.prevActive = active;
220
247
  sig.__activeNode = node;
221
248
  linkSub(sub, node);
@@ -234,9 +261,10 @@ function cleanup(subscriber) {
234
261
  node = next;
235
262
  }
236
263
  }
237
- var maxSubscriberRepeats = 50;
264
+ var maxSubscriberRepeats = 1e3;
238
265
  var maxDrainIterations = 1e6;
239
266
  var drainEpoch = 0;
267
+ var quarantined = /* @__PURE__ */ new Set();
240
268
  function setMaxSubscriberRepeats(n) {
241
269
  const prev = maxSubscriberRepeats;
242
270
  if (Number.isFinite(n) && n > 0) maxSubscriberRepeats = Math.floor(n);
@@ -258,19 +286,21 @@ function tickRepeat(sub) {
258
286
  return s._runs > maxSubscriberRepeats;
259
287
  }
260
288
  function cycleError(sub) {
261
- if (typeof console !== "undefined") {
262
- const name = sub.__name ?? "<unnamed>";
263
- console.error(
264
- `[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
265
- );
266
- }
289
+ const name = sub.__name ?? "<unnamed>";
290
+ reportError(
291
+ new Error(
292
+ `subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. This subscriber is quarantined for the rest of this update; other pending work still runs.`
293
+ ),
294
+ { phase: "scheduler", name }
295
+ );
267
296
  }
268
297
  function absoluteDrainError() {
269
- if (typeof console !== "undefined") {
270
- console.error(
271
- `[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
272
- );
273
- }
298
+ reportError(
299
+ new Error(
300
+ `Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
301
+ ),
302
+ { phase: "scheduler" }
303
+ );
274
304
  }
275
305
  function drainQueue() {
276
306
  let i = 0;
@@ -280,11 +310,14 @@ function drainQueue() {
280
310
  break;
281
311
  }
282
312
  const sub = pendingQueue[i++];
313
+ pendingSet.delete(sub);
314
+ if (quarantined.size > 0 && quarantined.has(sub)) continue;
315
+ if (sub._hasComputedDep === true && !depsChanged(sub)) continue;
283
316
  if (tickRepeat(sub)) {
284
317
  cycleError(sub);
285
- break;
318
+ quarantined.add(sub);
319
+ continue;
286
320
  }
287
- pendingSet.delete(sub);
288
321
  safeInvoke(sub);
289
322
  }
290
323
  }
@@ -299,6 +332,7 @@ function drainNotificationQueue() {
299
332
  if (notifyDepth === 0) {
300
333
  pendingQueue.length = 0;
301
334
  pendingSet.clear();
335
+ if (quarantined.size > 0) quarantined.clear();
302
336
  }
303
337
  }
304
338
  }
@@ -392,6 +426,7 @@ function notifySubscribers(signal) {
392
426
  if (notifyDepth === 0) {
393
427
  pendingQueue.length = 0;
394
428
  pendingSet.clear();
429
+ if (quarantined.size > 0) quarantined.clear();
395
430
  }
396
431
  }
397
432
  }
@@ -418,14 +453,14 @@ function forEachSubscriber(signal, visit) {
418
453
  }
419
454
 
420
455
  // src/reactivity/track.ts
421
- var _isDev2 = isDev();
422
- var _runtimeVersion = true ? "3.4.0" : "dev";
456
+ var _isDev = isDev();
457
+ var _runtimeVersion = true ? "4.0.0" : "dev";
423
458
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
424
459
  function resolveReactiveApi() {
425
460
  const g = globalThis;
426
461
  const existing = g[REGISTRY_KEY];
427
462
  if (existing) {
428
- if (_isDev2 && !existing.__dupWarned) {
463
+ if (_isDev && !existing.__dupWarned) {
429
464
  existing.__dupWarned = true;
430
465
  devWarn(
431
466
  `Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity still works \u2014 all copies share the first one \u2014 but de-duplicate sibujs in your bundler (e.g. Vite optimizeDeps.exclude: ['sibujs'] or resolve.dedupe: ['sibujs']).`
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  renderToString
3
- } from "./chunk-EX77FXTT.js";
3
+ } from "./chunk-HYCCIYNS.js";
4
4
 
5
5
  // src/plugins/modular.ts
6
6
  function createModuleRegistry() {
@@ -0,0 +1,109 @@
1
+ import {
2
+ devWarn,
3
+ isDev,
4
+ reportError
5
+ } from "./chunk-VPP2FONR.js";
6
+
7
+ // src/core/rendering/dispose.ts
8
+ var elementDisposers = /* @__PURE__ */ new WeakMap();
9
+ var MAX_DRAIN_TEARDOWNS = 1e4;
10
+ function reportDrainRunaway(label, executed, remaining) {
11
+ if (typeof console === "undefined") return;
12
+ console.error(
13
+ `[SibuJS ${label}] runaway cleanup: stopped after running ${executed} teardowns with ${remaining} still queued. Cleanup production did not stabilize before the teardown safety ceiling was reached \u2014 the remaining work was NOT run.`,
14
+ { executed, remaining }
15
+ );
16
+ }
17
+ var _isDev = isDev();
18
+ var activeBindingCount = 0;
19
+ function registerDisposer(node, teardown) {
20
+ let disposers = elementDisposers.get(node);
21
+ if (!disposers) {
22
+ disposers = [];
23
+ elementDisposers.set(node, disposers);
24
+ }
25
+ disposers.push(teardown);
26
+ if (_isDev) activeBindingCount++;
27
+ }
28
+ function unregisterDisposer(node, teardown) {
29
+ const disposers = elementDisposers.get(node);
30
+ if (!disposers) return;
31
+ const index = disposers.indexOf(teardown);
32
+ if (index === -1) return;
33
+ disposers.splice(index, 1);
34
+ if (_isDev) activeBindingCount--;
35
+ if (disposers.length === 0) elementDisposers.delete(node);
36
+ }
37
+ function dispose(node) {
38
+ const stack = [node];
39
+ const order = [];
40
+ while (stack.length > 0) {
41
+ const current = stack.pop();
42
+ order.push(current);
43
+ const children = Array.from(current.childNodes);
44
+ for (let i = 0; i < children.length; i++) {
45
+ stack.push(children[i]);
46
+ }
47
+ }
48
+ for (let i = order.length - 1; i >= 0; i--) {
49
+ const current = order[i];
50
+ if (elementDisposers.has(current)) {
51
+ let executed = 0;
52
+ let runaway = false;
53
+ while (!runaway) {
54
+ const pending = elementDisposers.get(current);
55
+ if (!pending || pending.length === 0) break;
56
+ const snapshot = pending.slice();
57
+ elementDisposers.delete(current);
58
+ if (_isDev) activeBindingCount -= snapshot.length;
59
+ for (let i2 = 0; i2 < snapshot.length; i2++) {
60
+ if (executed >= MAX_DRAIN_TEARDOWNS) {
61
+ const rest = snapshot.slice(i2);
62
+ const added = elementDisposers.get(current);
63
+ elementDisposers.set(current, added ? rest.concat(added) : rest);
64
+ if (_isDev) activeBindingCount += rest.length;
65
+ reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
66
+ runaway = true;
67
+ break;
68
+ }
69
+ executed++;
70
+ try {
71
+ snapshot[i2]();
72
+ } catch (err) {
73
+ reportError(err, { phase: "cleanup", name: "disposer" });
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ function replaceChildrenSafely(parent, ...next) {
81
+ for (let i = 0; i < next.length; i++) {
82
+ const node = next[i];
83
+ node.parentNode?.removeChild(node);
84
+ }
85
+ const current = Array.from(parent.childNodes);
86
+ for (let i = 0; i < current.length; i++) {
87
+ dispose(current[i]);
88
+ }
89
+ parent.replaceChildren(...next);
90
+ }
91
+ function checkLeaks(warnThreshold = 0) {
92
+ if (!_isDev) return 0;
93
+ if (warnThreshold > 0 && activeBindingCount > warnThreshold) {
94
+ devWarn(
95
+ `checkLeaks: ${activeBindingCount} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
96
+ );
97
+ }
98
+ return activeBindingCount;
99
+ }
100
+
101
+ export {
102
+ MAX_DRAIN_TEARDOWNS,
103
+ reportDrainRunaway,
104
+ registerDisposer,
105
+ unregisterDisposer,
106
+ dispose,
107
+ replaceChildrenSafely,
108
+ checkLeaks
109
+ };
@@ -1,23 +1,25 @@
1
1
  import {
2
- bindAttribute
3
- } from "./chunk-K35BAR4P.js";
2
+ bindAttribute,
3
+ setSafeAttribute
4
+ } from "./chunk-4MFZMLUU.js";
4
5
  import {
5
6
  isEventHandlerAttr,
6
- sanitizeAttributeString,
7
- sanitizeCSSValue
8
- } from "./chunk-L3GAGWCC.js";
7
+ sanitizeCSSValue,
8
+ sanitizeStyleAttribute
9
+ } from "./chunk-5INI7D2L.js";
9
10
  import {
10
11
  dispose,
11
12
  registerDisposer
12
- } from "./chunk-5VGSK6D2.js";
13
+ } from "./chunk-DHDZ7IVN.js";
13
14
  import {
14
15
  reactiveBinding,
15
16
  track
16
- } from "./chunk-OOUQUCNN.js";
17
+ } from "./chunk-ACBT6UZS.js";
17
18
  import {
18
19
  devWarn,
19
- isDev
20
- } from "./chunk-COY6PUD2.js";
20
+ isDev,
21
+ reportError
22
+ } from "./chunk-VPP2FONR.js";
21
23
 
22
24
  // src/reactivity/bindChildNode.ts
23
25
  var _isDev = isDev();
@@ -28,7 +30,7 @@ function bindChildNode(placeholder, getter) {
28
30
  try {
29
31
  result = getter();
30
32
  } catch (err) {
31
- if (_isDev) devWarn(`bindChildNode: getter threw: ${err instanceof Error ? err.message : String(err)}`);
33
+ reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
32
34
  return;
33
35
  }
34
36
  if (result == null || typeof result === "boolean") {
@@ -89,7 +91,7 @@ function bindChildNode(placeholder, getter) {
89
91
  }
90
92
  lastNodes = newNodes;
91
93
  }
92
- return reactiveBinding(commit);
94
+ return reactiveBinding(commit, placeholder);
93
95
  }
94
96
 
95
97
  // src/core/rendering/tagFactory.ts
@@ -112,9 +114,6 @@ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
112
114
  "self",
113
115
  "frames"
114
116
  ]);
115
- function setProp(el, key, val) {
116
- el[key] = val;
117
- }
118
117
  function looksLikeClassList(s) {
119
118
  const t = s.trim();
120
119
  if (!t) return false;
@@ -138,13 +137,13 @@ function toKebab(prop) {
138
137
  function applyStyle(el, style) {
139
138
  if (typeof style === "function") {
140
139
  const teardown = track(() => {
141
- el.setAttribute("style", style());
140
+ el.setAttribute("style", sanitizeStyleAttribute(String(style())));
142
141
  });
143
142
  registerDisposer(el, teardown);
144
143
  return;
145
144
  }
146
145
  if (typeof style === "string") {
147
- el.setAttribute("style", style);
146
+ el.setAttribute("style", sanitizeStyleAttribute(style));
148
147
  return;
149
148
  }
150
149
  const htmlEl = el;
@@ -329,16 +328,8 @@ var tagFactory = (tag, ns) => {
329
328
  if (isEventHandlerAttr(key)) continue;
330
329
  if (typeof value === "function") {
331
330
  registerDisposer(el, bindAttribute(el, key, value));
332
- } else if (typeof value === "boolean") {
333
- if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
334
- setProp(el, key, value);
335
- } else if (value) {
336
- el.setAttribute(key, "");
337
- } else {
338
- el.removeAttribute(key);
339
- }
340
331
  } else {
341
- el.setAttribute(key, sanitizeAttributeString(key, String(value)));
332
+ setSafeAttribute(el, key, value, { syncValueProperty: false, label: "tagFactory" });
342
333
  }
343
334
  }
344
335
  }