sibujs 2.0.0 → 2.1.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 (60) hide show
  1. package/dist/browser.cjs +144 -102
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +183 -102
  4. package/dist/build.js +10 -10
  5. package/dist/cdn.global.js +7 -7
  6. package/dist/{chunk-MIUAXB7K.js → chunk-3DZP6OIT.js} +2 -2
  7. package/dist/{chunk-ITX6OO3F.js → chunk-45YP72ZQ.js} +1 -1
  8. package/dist/{chunk-ND2664SF.js → chunk-AMK2TYNW.js} +13 -9
  9. package/dist/{chunk-R73P76YZ.js → chunk-CWBVQML6.js} +1 -1
  10. package/dist/{chunk-54EDRCEF.js → chunk-DRUZZAK4.js} +1 -1
  11. package/dist/{chunk-3NSGB5JN.js → chunk-GWWURC5M.js} +2 -2
  12. package/dist/{chunk-SAHNHTFC.js → chunk-KGYT6UO6.js} +3 -3
  13. package/dist/{chunk-52YJLLRO.js → chunk-NASX6ST2.js} +1 -1
  14. package/dist/{chunk-O2MNQFLP.js → chunk-O6EFQ3KT.js} +5 -5
  15. package/dist/{chunk-GTBNNBJ6.js → chunk-OJ3P4ECI.js} +1 -1
  16. package/dist/{chunk-7JDB7I65.js → chunk-ON5MMR2J.js} +4 -4
  17. package/dist/{chunk-KLRMB5ZS.js → chunk-P2HSJDDN.js} +2 -2
  18. package/dist/{chunk-VLPPXTYG.js → chunk-QO3WC6FS.js} +145 -93
  19. package/dist/{chunk-CC65Y57T.js → chunk-RDTDJCAB.js} +1 -1
  20. package/dist/{chunk-JXMMDLBY.js → chunk-TH2ILCYW.js} +8 -4
  21. package/dist/{chunk-3LR7GLWQ.js → chunk-V6C4FADE.js} +3 -3
  22. package/dist/{chunk-WOMYAHHI.js → chunk-WANSMF2L.js} +4 -4
  23. package/dist/{chunk-DFPFITST.js → chunk-WIPZPFBQ.js} +1 -1
  24. package/dist/{chunk-HB24TBAF.js → chunk-WZA53FXU.js} +38 -10
  25. package/dist/{chunk-JA6667UN.js → chunk-ZAQSMOED.js} +4 -4
  26. package/dist/data.cjs +176 -102
  27. package/dist/data.js +6 -6
  28. package/dist/devtools.cjs +148 -91
  29. package/dist/devtools.d.cts +1 -1
  30. package/dist/devtools.d.ts +1 -1
  31. package/dist/devtools.js +4 -4
  32. package/dist/ecosystem.cjs +176 -102
  33. package/dist/ecosystem.js +7 -7
  34. package/dist/extras.cjs +182 -104
  35. package/dist/extras.d.cts +1 -1
  36. package/dist/extras.d.ts +1 -1
  37. package/dist/extras.js +19 -19
  38. package/dist/index.cjs +185 -102
  39. package/dist/index.d.cts +15 -1
  40. package/dist/index.d.ts +15 -1
  41. package/dist/index.js +14 -10
  42. package/dist/{introspect-BWNjNw64.d.cts → introspect-2TOlQ7oa.d.cts} +3 -1
  43. package/dist/{introspect-cY2pg9pW.d.ts → introspect-DnIpHQQz.d.ts} +3 -1
  44. package/dist/motion.cjs +78 -62
  45. package/dist/motion.js +3 -3
  46. package/dist/patterns.cjs +176 -102
  47. package/dist/patterns.js +5 -5
  48. package/dist/performance.cjs +142 -89
  49. package/dist/performance.js +4 -4
  50. package/dist/plugins.cjs +142 -89
  51. package/dist/plugins.js +6 -6
  52. package/dist/ssr.cjs +144 -102
  53. package/dist/ssr.js +7 -7
  54. package/dist/testing.cjs +66 -28
  55. package/dist/testing.js +2 -2
  56. package/dist/ui.cjs +174 -89
  57. package/dist/ui.js +6 -6
  58. package/dist/widgets.cjs +176 -102
  59. package/dist/widgets.js +6 -6
  60. package/package.json +1 -1
package/dist/ui.cjs CHANGED
@@ -103,11 +103,24 @@ function devWarn(message) {
103
103
 
104
104
  // src/reactivity/track.ts
105
105
  var _isDev2 = isDev();
106
- var subscriberStack = new Array(32);
107
- var stackCapacity = 32;
106
+ var STACK_INITIAL = 32;
107
+ var STACK_SHRINK_THRESHOLD = 128;
108
+ var subscriberStack = new Array(STACK_INITIAL);
109
+ var stackCapacity = STACK_INITIAL;
108
110
  var stackTop = -1;
109
111
  var currentSubscriber = null;
110
112
  var SUBS = "__s";
113
+ function syncFastPath(signal2, subs) {
114
+ const size = subs.size;
115
+ if (size === 0) {
116
+ signal2.__f = void 0;
117
+ delete signal2[SUBS];
118
+ } else if (size === 1) {
119
+ signal2.__f = subs.values().next().value;
120
+ } else {
121
+ signal2.__f = void 0;
122
+ }
123
+ }
111
124
  var notifyDepth = 0;
112
125
  var pendingQueue = [];
113
126
  var pendingSet = /* @__PURE__ */ new Set();
@@ -120,13 +133,45 @@ function safeInvoke(sub) {
120
133
  }
121
134
  }
122
135
  var trackingSuspended = false;
136
+ var subscriberEpochCounter = 0;
123
137
  function retrack(effectFn, subscriber) {
124
138
  const prev = currentSubscriber;
125
139
  currentSubscriber = subscriber;
140
+ const sub = subscriber;
141
+ const epoch = ++subscriberEpochCounter;
142
+ sub._epoch = epoch;
126
143
  try {
127
144
  effectFn();
128
145
  } finally {
129
146
  currentSubscriber = prev;
147
+ pruneStaleDeps(sub, epoch);
148
+ }
149
+ }
150
+ function pruneStaleDeps(sub, currentEpoch) {
151
+ if (sub._dep !== void 0) {
152
+ if (sub._depEpoch !== currentEpoch) {
153
+ const sig = sub._dep;
154
+ const subs = sig[SUBS];
155
+ if (subs?.delete(sub)) syncFastPath(sig, subs);
156
+ sub._dep = void 0;
157
+ sub._depEpoch = void 0;
158
+ }
159
+ return;
160
+ }
161
+ const deps = sub._deps;
162
+ if (!deps || deps.size === 0) return;
163
+ let stales;
164
+ for (const [signal2, epoch] of deps) {
165
+ if (epoch !== currentEpoch) {
166
+ (stales ?? (stales = [])).push(signal2);
167
+ }
168
+ }
169
+ if (!stales) return;
170
+ for (const signal2 of stales) {
171
+ deps.delete(signal2);
172
+ const sig = signal2;
173
+ const subs = sig[SUBS];
174
+ if (subs?.delete(sub)) syncFastPath(sig, subs);
130
175
  }
131
176
  }
132
177
  function track(effectFn, subscriber) {
@@ -144,39 +189,94 @@ function track(effectFn, subscriber) {
144
189
  } finally {
145
190
  stackTop--;
146
191
  currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
192
+ if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
193
+ stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
194
+ subscriberStack.length = stackCapacity;
195
+ }
147
196
  }
148
197
  return () => cleanup(subscriber);
149
198
  }
150
199
  function recordDependency(signal2) {
151
200
  if (!currentSubscriber) return;
152
201
  const sub = currentSubscriber;
153
- if (sub._dep === signal2) return;
202
+ const epoch = sub._epoch;
203
+ if (sub._dep === signal2) {
204
+ sub._depEpoch = epoch;
205
+ return;
206
+ }
154
207
  const deps = sub._deps;
155
208
  if (deps) {
156
- if (deps.has(signal2)) return;
157
- deps.add(signal2);
209
+ deps.set(signal2, epoch);
158
210
  } else if (sub._dep !== void 0) {
159
- const set = /* @__PURE__ */ new Set();
160
- set.add(sub._dep);
161
- set.add(signal2);
162
- sub._deps = set;
211
+ const map = /* @__PURE__ */ new Map();
212
+ map.set(sub._dep, sub._depEpoch);
213
+ map.set(signal2, epoch);
214
+ sub._deps = map;
163
215
  sub._dep = void 0;
216
+ sub._depEpoch = void 0;
164
217
  } else {
165
218
  sub._dep = signal2;
219
+ sub._depEpoch = epoch;
166
220
  }
167
- let subs = signal2[SUBS];
221
+ const sig = signal2;
222
+ let subs = sig[SUBS];
168
223
  if (!subs) {
169
224
  subs = /* @__PURE__ */ new Set();
170
- signal2[SUBS] = subs;
225
+ sig[SUBS] = subs;
171
226
  }
227
+ const prevSize = subs.size;
172
228
  subs.add(currentSubscriber);
173
- if (subs.size === 1) {
174
- signal2.__f = currentSubscriber;
175
- } else if (signal2.__f !== void 0) {
176
- signal2.__f = void 0;
229
+ if (subs.size !== prevSize) {
230
+ if (subs.size === 1) {
231
+ sig.__f = currentSubscriber;
232
+ } else if (sig.__f !== void 0) {
233
+ sig.__f = void 0;
234
+ }
235
+ }
236
+ }
237
+ var maxSubscriberRepeats = 50;
238
+ var maxDrainIterations = 1e6;
239
+ var drainEpoch = 0;
240
+ function tickRepeat(sub) {
241
+ const s = sub;
242
+ if (s._runEpoch !== drainEpoch) {
243
+ s._runEpoch = drainEpoch;
244
+ s._runs = 1;
245
+ return false;
246
+ }
247
+ return ++s._runs > maxSubscriberRepeats;
248
+ }
249
+ function cycleError(sub) {
250
+ if (typeof console !== "undefined") {
251
+ const name = sub.__name ?? "<unnamed>";
252
+ console.error(
253
+ `[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
254
+ );
255
+ }
256
+ }
257
+ function absoluteDrainError() {
258
+ if (typeof console !== "undefined") {
259
+ console.error(
260
+ `[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
261
+ );
262
+ }
263
+ }
264
+ function drainQueue() {
265
+ let i = 0;
266
+ while (i < pendingQueue.length) {
267
+ if (i >= maxDrainIterations) {
268
+ absoluteDrainError();
269
+ break;
270
+ }
271
+ const sub = pendingQueue[i++];
272
+ if (tickRepeat(sub)) {
273
+ cycleError(sub);
274
+ break;
275
+ }
276
+ pendingSet.delete(sub);
277
+ safeInvoke(sub);
177
278
  }
178
279
  }
179
- var maxDrainIterations = 1e5;
180
280
  function propagateDirty(sub) {
181
281
  sub();
182
282
  const rootSig = sub._sig;
@@ -231,25 +331,16 @@ function notifySubscribers(signal2) {
231
331
  return;
232
332
  }
233
333
  notifyDepth++;
334
+ drainEpoch++;
234
335
  try {
235
336
  if (first._c) {
236
337
  propagateDirty(first);
338
+ } else if (tickRepeat(first)) {
339
+ cycleError(first);
237
340
  } else {
238
341
  safeInvoke(first);
239
342
  }
240
- let i = 0;
241
- while (i < pendingQueue.length) {
242
- if (i >= maxDrainIterations) {
243
- if (typeof console !== "undefined") {
244
- console.error(
245
- `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
246
- );
247
- }
248
- break;
249
- }
250
- safeInvoke(pendingQueue[i]);
251
- i++;
252
- }
343
+ drainQueue();
253
344
  } finally {
254
345
  notifyDepth--;
255
346
  if (notifyDepth === 0) {
@@ -273,44 +364,17 @@ function notifySubscribers(signal2) {
273
364
  return;
274
365
  }
275
366
  notifyDepth++;
367
+ drainEpoch++;
276
368
  try {
277
- let directCount = 0;
278
- let hasComputedSub = false;
279
369
  for (const sub of subs) {
280
- if (sub._c) hasComputedSub = true;
281
- pendingQueue[directCount++] = sub;
282
- }
283
- if (!hasComputedSub) {
284
- for (let i2 = 0; i2 < directCount; i2++) {
285
- safeInvoke(pendingQueue[i2]);
286
- }
287
- } else {
288
- for (let i2 = 0; i2 < directCount; i2++) {
289
- if (pendingQueue[i2]._c) {
290
- propagateDirty(pendingQueue[i2]);
291
- }
292
- }
293
- for (let i2 = 0; i2 < directCount; i2++) {
294
- const sub = pendingQueue[i2];
295
- if (!sub._c && !pendingSet.has(sub)) {
296
- pendingSet.add(sub);
297
- safeInvoke(sub);
298
- }
299
- }
300
- }
301
- let i = directCount;
302
- while (i < pendingQueue.length) {
303
- if (i - directCount >= maxDrainIterations) {
304
- if (typeof console !== "undefined") {
305
- console.error(
306
- `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
307
- );
308
- }
309
- break;
370
+ if (sub._c) {
371
+ propagateDirty(sub);
372
+ } else if (!pendingSet.has(sub)) {
373
+ pendingSet.add(sub);
374
+ pendingQueue.push(sub);
310
375
  }
311
- safeInvoke(pendingQueue[i]);
312
- i++;
313
376
  }
377
+ drainQueue();
314
378
  } finally {
315
379
  notifyDepth--;
316
380
  if (notifyDepth === 0) {
@@ -323,29 +387,22 @@ function cleanup(subscriber) {
323
387
  const sub = subscriber;
324
388
  const singleDep = sub._dep;
325
389
  if (singleDep !== void 0) {
326
- const subs = singleDep[SUBS];
327
- if (subs) {
328
- subs.delete(subscriber);
329
- if (singleDep.__f === subscriber) {
330
- singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
331
- } else if (subs.size === 1 && singleDep.__f === void 0) {
332
- singleDep.__f = subs.values().next().value;
333
- }
390
+ const sig = singleDep;
391
+ const subs = sig[SUBS];
392
+ if (subs?.delete(subscriber)) {
393
+ syncFastPath(sig, subs);
334
394
  }
335
395
  sub._dep = void 0;
396
+ sub._depEpoch = void 0;
336
397
  return;
337
398
  }
338
399
  const deps = sub._deps;
339
400
  if (!deps || deps.size === 0) return;
340
- for (const signal2 of deps) {
341
- const subs = signal2[SUBS];
342
- if (subs) {
343
- subs.delete(subscriber);
344
- if (signal2.__f === subscriber) {
345
- signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
346
- } else if (subs.size === 1 && signal2.__f === void 0) {
347
- signal2.__f = subs.values().next().value;
348
- }
401
+ for (const signal2 of deps.keys()) {
402
+ const sig = signal2;
403
+ const subs = sig[SUBS];
404
+ if (subs?.delete(subscriber)) {
405
+ syncFastPath(sig, subs);
349
406
  }
350
407
  }
351
408
  deps.clear();
@@ -833,29 +890,57 @@ function effect(effectFn, options) {
833
890
  let cleanupHandle = () => {
834
891
  };
835
892
  let running = false;
893
+ let rerunPending = false;
894
+ const MAX_RERUNS = 100;
836
895
  const subscriber = () => {
837
896
  if (running) {
838
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
839
- console.warn(
840
- "[SibuJS] effect re-entered itself while running \u2014 the triggering update will be ignored. Wrap mutual writes in `batch()` or split the effect to avoid this."
841
- );
842
- }
897
+ rerunPending = true;
843
898
  return;
844
899
  }
845
900
  running = true;
846
901
  try {
847
- runUserCleanups();
848
- cleanupHandle();
849
- cleanupHandle = track(wrappedFn, subscriber);
902
+ let reruns = 0;
903
+ do {
904
+ rerunPending = false;
905
+ runUserCleanups();
906
+ cleanupHandle();
907
+ cleanupHandle = track(wrappedFn, subscriber);
908
+ if (++reruns > MAX_RERUNS) {
909
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
910
+ console.error(
911
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
912
+ );
913
+ }
914
+ rerunPending = false;
915
+ break;
916
+ }
917
+ } while (rerunPending);
850
918
  } finally {
851
919
  running = false;
920
+ rerunPending = false;
852
921
  }
853
922
  };
854
923
  running = true;
855
924
  try {
856
- cleanupHandle = track(wrappedFn, subscriber);
925
+ let reruns = 0;
926
+ do {
927
+ rerunPending = false;
928
+ runUserCleanups();
929
+ cleanupHandle();
930
+ cleanupHandle = track(wrappedFn, subscriber);
931
+ if (++reruns > MAX_RERUNS) {
932
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
933
+ console.error(
934
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
935
+ );
936
+ }
937
+ rerunPending = false;
938
+ break;
939
+ }
940
+ } while (rerunPending);
857
941
  } finally {
858
942
  running = false;
943
+ rerunPending = false;
859
944
  }
860
945
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
861
946
  if (hook) hook.emit("effect:create", { effectFn });
package/dist/ui.js CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  toast,
39
39
  withScopedStyle,
40
40
  zipMask
41
- } from "./chunk-O2MNQFLP.js";
41
+ } from "./chunk-O6EFQ3KT.js";
42
42
  import {
43
43
  RenderProp,
44
44
  assertType,
@@ -58,20 +58,20 @@ import {
58
58
  import {
59
59
  createId
60
60
  } from "./chunk-YT6HQ6AM.js";
61
- import "./chunk-DFPFITST.js";
62
- import "./chunk-54EDRCEF.js";
61
+ import "./chunk-WIPZPFBQ.js";
62
+ import "./chunk-DRUZZAK4.js";
63
63
  import {
64
64
  registerDisposer
65
65
  } from "./chunk-2UPRY23K.js";
66
66
  import "./chunk-UCS6AMJ7.js";
67
67
  import {
68
68
  effect
69
- } from "./chunk-HB24TBAF.js";
69
+ } from "./chunk-WZA53FXU.js";
70
70
  import "./chunk-2RA7SHDA.js";
71
71
  import {
72
72
  signal
73
- } from "./chunk-CC65Y57T.js";
74
- import "./chunk-VLPPXTYG.js";
73
+ } from "./chunk-RDTDJCAB.js";
74
+ import "./chunk-QO3WC6FS.js";
75
75
  import "./chunk-LMLD24FC.js";
76
76
 
77
77
  // src/ui/formAction.ts