sibujs 2.1.0 → 2.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 (62) hide show
  1. package/dist/browser.cjs +324 -273
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +358 -328
  4. package/dist/build.js +10 -10
  5. package/dist/cdn.global.js +8 -8
  6. package/dist/{chunk-ZAQSMOED.js → chunk-2JQUV4Y3.js} +4 -4
  7. package/dist/{chunk-GWWURC5M.js → chunk-2KM2724A.js} +2 -2
  8. package/dist/{chunk-NASX6ST2.js → chunk-4YTVESDX.js} +1 -1
  9. package/dist/chunk-5WD7BYTZ.js +152 -0
  10. package/dist/{chunk-RDTDJCAB.js → chunk-6QZO7MMG.js} +48 -16
  11. package/dist/{chunk-DRUZZAK4.js → chunk-DF3GTP4Q.js} +7 -2
  12. package/dist/{chunk-AMK2TYNW.js → chunk-J63GPPCJ.js} +9 -9
  13. package/dist/{chunk-O6EFQ3KT.js → chunk-KH4OE6WY.js} +5 -5
  14. package/dist/{chunk-V6C4FADE.js → chunk-KZA7ANXP.js} +3 -3
  15. package/dist/chunk-L4DAT4WU.js +400 -0
  16. package/dist/{chunk-WANSMF2L.js → chunk-L52H775O.js} +4 -4
  17. package/dist/{chunk-45YP72ZQ.js → chunk-NEWH4O5U.js} +1 -1
  18. package/dist/{chunk-ON5MMR2J.js → chunk-RJIRT46U.js} +4 -4
  19. package/dist/{chunk-P2HSJDDN.js → chunk-STFTTMO2.js} +2 -2
  20. package/dist/{chunk-WIPZPFBQ.js → chunk-UKMXT5T6.js} +1 -1
  21. package/dist/{chunk-KGYT6UO6.js → chunk-V65KTDZW.js} +3 -3
  22. package/dist/{chunk-CWBVQML6.js → chunk-VSNLICTS.js} +1 -1
  23. package/dist/{chunk-3DZP6OIT.js → chunk-XDKP4T7G.js} +2 -2
  24. package/dist/{chunk-TH2ILCYW.js → chunk-XVYB3J6C.js} +27 -33
  25. package/dist/{chunk-OJ3P4ECI.js → chunk-YMOIAHWA.js} +1 -1
  26. package/dist/data.cjs +332 -298
  27. package/dist/data.js +6 -6
  28. package/dist/devtools.cjs +353 -296
  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 +332 -298
  33. package/dist/ecosystem.js +7 -7
  34. package/dist/extras.cjs +372 -328
  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 +358 -328
  39. package/dist/index.d.cts +13 -22
  40. package/dist/index.d.ts +13 -22
  41. package/dist/index.js +10 -10
  42. package/dist/{introspect-DnIpHQQz.d.ts → introspect-BZWKvQUZ.d.ts} +2 -3
  43. package/dist/{introspect-2TOlQ7oa.d.cts → introspect-DsJlDD2T.d.cts} +2 -3
  44. package/dist/motion.cjs +147 -123
  45. package/dist/motion.js +3 -3
  46. package/dist/patterns.cjs +332 -298
  47. package/dist/patterns.js +5 -5
  48. package/dist/performance.cjs +315 -268
  49. package/dist/performance.js +4 -4
  50. package/dist/plugins.cjs +332 -266
  51. package/dist/plugins.js +6 -6
  52. package/dist/ssr.cjs +340 -270
  53. package/dist/ssr.js +7 -7
  54. package/dist/testing.cjs +167 -146
  55. package/dist/testing.js +2 -2
  56. package/dist/ui.cjs +324 -294
  57. package/dist/ui.js +6 -6
  58. package/dist/widgets.cjs +332 -298
  59. package/dist/widgets.js +6 -6
  60. package/package.json +1 -1
  61. package/dist/chunk-QO3WC6FS.js +0 -384
  62. package/dist/chunk-WZA53FXU.js +0 -149
package/dist/browser.cjs CHANGED
@@ -77,24 +77,88 @@ function devWarn(message) {
77
77
 
78
78
  // src/reactivity/track.ts
79
79
  var _isDev2 = isDev();
80
- var STACK_INITIAL = 32;
81
- var STACK_SHRINK_THRESHOLD = 128;
82
- var subscriberStack = new Array(STACK_INITIAL);
83
- var stackCapacity = STACK_INITIAL;
84
- var stackTop = -1;
85
- var currentSubscriber = null;
86
- var SUBS = "__s";
87
- function syncFastPath(signal2, subs) {
88
- const size = subs.size;
89
- if (size === 0) {
90
- signal2.__f = void 0;
91
- delete signal2[SUBS];
92
- } else if (size === 1) {
93
- signal2.__f = subs.values().next().value;
94
- } else {
95
- signal2.__f = void 0;
80
+ var POOL_MAX = 4096;
81
+ var nodePool = [];
82
+ function createNode() {
83
+ return {
84
+ sig: null,
85
+ sub: null,
86
+ epoch: 0,
87
+ sigPrev: null,
88
+ sigNext: null,
89
+ subPrev: null,
90
+ subNext: null,
91
+ prevActive: null
92
+ };
93
+ }
94
+ function allocNode(sig, sub, epoch) {
95
+ const n = nodePool.pop();
96
+ if (n) {
97
+ n.sig = sig;
98
+ n.sub = sub;
99
+ n.epoch = epoch;
100
+ return n;
101
+ }
102
+ const fresh = createNode();
103
+ fresh.sig = sig;
104
+ fresh.sub = sub;
105
+ fresh.epoch = epoch;
106
+ return fresh;
107
+ }
108
+ function freeNode(node) {
109
+ node.sig = null;
110
+ node.sub = null;
111
+ node.sigPrev = null;
112
+ node.sigNext = null;
113
+ node.subPrev = null;
114
+ node.subNext = null;
115
+ node.prevActive = null;
116
+ if (nodePool.length < POOL_MAX) nodePool.push(node);
117
+ }
118
+ function linkSignal(sig, node) {
119
+ const oldHead = sig.subsHead ?? null;
120
+ node.sigPrev = null;
121
+ node.sigNext = oldHead;
122
+ if (oldHead) oldHead.sigPrev = node;
123
+ else sig.subsTail = node;
124
+ sig.subsHead = node;
125
+ sig.__sc = (sig.__sc ?? 0) + 1;
126
+ }
127
+ function unlinkSignal(node) {
128
+ const sig = node.sig;
129
+ if (!sig) return;
130
+ const prev = node.sigPrev;
131
+ const next = node.sigNext;
132
+ if (prev) prev.sigNext = next;
133
+ else sig.subsHead = next;
134
+ if (next) next.sigPrev = prev;
135
+ else sig.subsTail = prev;
136
+ sig.__sc = (sig.__sc ?? 1) - 1;
137
+ if (sig.__activeNode === node) sig.__activeNode = node.prevActive;
138
+ if (sig.__sc === 0) {
139
+ sig.subsHead = null;
140
+ sig.subsTail = null;
96
141
  }
97
142
  }
143
+ function linkSub(sub, node) {
144
+ const oldTail = sub.depsTail ?? null;
145
+ node.subPrev = oldTail;
146
+ node.subNext = null;
147
+ if (oldTail) oldTail.subNext = node;
148
+ else sub.depsHead = node;
149
+ sub.depsTail = node;
150
+ }
151
+ function unlinkSub(node) {
152
+ const sub = node.sub;
153
+ if (!sub) return;
154
+ const prev = node.subPrev;
155
+ const next = node.subNext;
156
+ if (prev) prev.subNext = next;
157
+ else sub.depsHead = next;
158
+ if (next) next.subPrev = prev;
159
+ else sub.depsTail = prev;
160
+ }
161
+ var currentSubscriber = null;
98
162
  var notifyDepth = 0;
99
163
  var pendingQueue = [];
100
164
  var pendingSet = /* @__PURE__ */ new Set();
@@ -106,76 +170,65 @@ function safeInvoke(sub) {
106
170
  if (_isDev2) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
107
171
  }
108
172
  }
109
- function track(effectFn, subscriber) {
110
- if (!subscriber) subscriber = effectFn;
111
- cleanup(subscriber);
112
- ++stackTop;
113
- if (stackTop >= stackCapacity) {
114
- stackCapacity *= 2;
115
- subscriberStack.length = stackCapacity;
116
- }
117
- subscriberStack[stackTop] = subscriber;
173
+ var subscriberEpochCounter = 0;
174
+ function retrack(effectFn, subscriber) {
175
+ const prev = currentSubscriber;
118
176
  currentSubscriber = subscriber;
177
+ const sub = subscriber;
178
+ const epoch = ++subscriberEpochCounter;
179
+ sub._epoch = epoch;
180
+ sub._structDirty = false;
181
+ for (let n = sub.depsHead ?? null; n !== null; n = n.subNext) {
182
+ const sig = n.sig;
183
+ n.prevActive = sig.__activeNode ?? null;
184
+ sig.__activeNode = n;
185
+ }
119
186
  try {
120
187
  effectFn();
121
188
  } finally {
122
- stackTop--;
123
- currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
124
- if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
125
- stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
126
- subscriberStack.length = stackCapacity;
189
+ currentSubscriber = prev;
190
+ let node = sub.depsHead ?? null;
191
+ while (node !== null) {
192
+ const next = node.subNext;
193
+ const sig = node.sig;
194
+ sig.__activeNode = node.prevActive;
195
+ node.prevActive = null;
196
+ if (node.epoch !== epoch) {
197
+ unlinkSub(node);
198
+ unlinkSignal(node);
199
+ freeNode(node);
200
+ }
201
+ node = next;
127
202
  }
128
203
  }
129
- return () => cleanup(subscriber);
130
204
  }
131
205
  function recordDependency(signal2) {
132
206
  if (!currentSubscriber) return;
133
207
  const sub = currentSubscriber;
134
- const epoch = sub._epoch;
135
- if (sub._dep === signal2) {
136
- sub._depEpoch = epoch;
137
- return;
138
- }
139
- const deps = sub._deps;
140
- if (deps) {
141
- deps.set(signal2, epoch);
142
- } else if (sub._dep !== void 0) {
143
- const map = /* @__PURE__ */ new Map();
144
- map.set(sub._dep, sub._depEpoch);
145
- map.set(signal2, epoch);
146
- sub._deps = map;
147
- sub._dep = void 0;
148
- sub._depEpoch = void 0;
149
- } else {
150
- sub._dep = signal2;
151
- sub._depEpoch = epoch;
152
- }
153
208
  const sig = signal2;
154
- let subs = sig[SUBS];
155
- if (!subs) {
156
- subs = /* @__PURE__ */ new Set();
157
- sig[SUBS] = subs;
158
- }
159
- const prevSize = subs.size;
160
- subs.add(currentSubscriber);
161
- if (subs.size !== prevSize) {
162
- if (subs.size === 1) {
163
- sig.__f = currentSubscriber;
164
- } else if (sig.__f !== void 0) {
165
- sig.__f = void 0;
166
- }
209
+ const epoch = sub._epoch ?? 0;
210
+ const active = sig.__activeNode ?? null;
211
+ if (active !== null && active.sub === sub) {
212
+ active.epoch = epoch;
213
+ return;
167
214
  }
215
+ const node = allocNode(signal2, sub, epoch);
216
+ node.prevActive = active;
217
+ sig.__activeNode = node;
218
+ linkSub(sub, node);
219
+ linkSignal(sig, node);
220
+ sub._structDirty = true;
168
221
  }
169
- function queueSignalNotification(signal2) {
170
- const subs = signal2[SUBS];
171
- if (!subs) return;
172
- for (const sub of subs) {
173
- if (sub._c) {
174
- propagateDirty(sub);
175
- } else if (!pendingSet.has(sub)) {
176
- pendingSet.add(sub);
177
- pendingQueue.push(sub);
178
- }
222
+ function cleanup(subscriber) {
223
+ const sub = subscriber;
224
+ let node = sub.depsHead ?? null;
225
+ sub.depsHead = null;
226
+ sub.depsTail = null;
227
+ while (node) {
228
+ const next = node.subNext;
229
+ unlinkSignal(node);
230
+ freeNode(node);
231
+ node = next;
179
232
  }
180
233
  }
181
234
  var maxSubscriberRepeats = 50;
@@ -188,7 +241,8 @@ function tickRepeat(sub) {
188
241
  s._runs = 1;
189
242
  return false;
190
243
  }
191
- return ++s._runs > maxSubscriberRepeats;
244
+ s._runs = (s._runs ?? 0) + 1;
245
+ return s._runs > maxSubscriberRepeats;
192
246
  }
193
247
  function cycleError(sub) {
194
248
  if (typeof console !== "undefined") {
@@ -244,93 +298,80 @@ function propagateDirty(sub) {
244
298
  stack.push(rootSig);
245
299
  while (stack.length > baseLen) {
246
300
  const sig = stack.pop();
247
- const first = sig.__f;
248
- if (first) {
249
- if (first._c) {
250
- const nSig = first._sig;
251
- if (!nSig._d) {
252
- nSig._d = true;
253
- stack.push(nSig);
301
+ let node = sig.subsHead ?? null;
302
+ while (node) {
303
+ const s = node.sub;
304
+ if (s) {
305
+ if (s._c) {
306
+ const nSig = s._sig;
307
+ if (nSig) {
308
+ if (!nSig._d) {
309
+ nSig._d = true;
310
+ stack.push(nSig);
311
+ }
312
+ } else {
313
+ s();
314
+ }
315
+ } else if (!pendingSet.has(s)) {
316
+ pendingSet.add(s);
317
+ pendingQueue.push(s);
254
318
  }
255
- } else if (!pendingSet.has(first)) {
256
- pendingSet.add(first);
257
- pendingQueue.push(first);
258
319
  }
259
- continue;
320
+ node = node.sigNext;
260
321
  }
261
- const subs = sig[SUBS];
262
- if (!subs) continue;
263
- for (const s of subs) {
322
+ }
323
+ }
324
+ function queueSignalNotification(signal2) {
325
+ const sig = signal2;
326
+ let node = sig.subsHead ?? null;
327
+ while (node) {
328
+ const s = node.sub;
329
+ if (s) {
264
330
  if (s._c) {
265
- const nSig = s._sig;
266
- if (nSig && !nSig._d) {
267
- nSig._d = true;
268
- stack.push(nSig);
269
- } else if (!nSig) {
270
- s();
271
- }
331
+ propagateDirty(s);
272
332
  } else if (!pendingSet.has(s)) {
273
333
  pendingSet.add(s);
274
334
  pendingQueue.push(s);
275
335
  }
276
336
  }
337
+ node = node.sigNext;
277
338
  }
278
339
  }
279
340
  function notifySubscribers(signal2) {
280
- const first = signal2.__f;
281
- if (first) {
282
- if (notifyDepth > 0) {
283
- if (first._c) {
284
- propagateDirty(first);
285
- } else if (!pendingSet.has(first)) {
286
- pendingSet.add(first);
287
- pendingQueue.push(first);
288
- }
289
- return;
290
- }
291
- notifyDepth++;
292
- drainEpoch++;
293
- try {
294
- if (first._c) {
295
- propagateDirty(first);
296
- } else if (tickRepeat(first)) {
297
- cycleError(first);
298
- } else {
299
- safeInvoke(first);
300
- }
301
- drainQueue();
302
- } finally {
303
- notifyDepth--;
304
- if (notifyDepth === 0) {
305
- pendingQueue.length = 0;
306
- pendingSet.clear();
307
- }
308
- }
309
- return;
310
- }
311
- const subs = signal2[SUBS];
312
- if (!subs || subs.size === 0) return;
341
+ const sig = signal2;
342
+ const head = sig.subsHead;
343
+ if (!head) return;
313
344
  if (notifyDepth > 0) {
314
- for (const sub of subs) {
315
- if (sub._c) {
316
- propagateDirty(sub);
317
- } else if (!pendingSet.has(sub)) {
318
- pendingSet.add(sub);
319
- pendingQueue.push(sub);
345
+ let node = head;
346
+ while (node) {
347
+ const s = node.sub;
348
+ if (s) {
349
+ if (s._c) {
350
+ propagateDirty(s);
351
+ } else if (!pendingSet.has(s)) {
352
+ pendingSet.add(s);
353
+ pendingQueue.push(s);
354
+ }
320
355
  }
356
+ node = node.sigNext;
321
357
  }
322
358
  return;
323
359
  }
324
360
  notifyDepth++;
325
361
  drainEpoch++;
326
362
  try {
327
- for (const sub of subs) {
328
- if (sub._c) {
329
- propagateDirty(sub);
330
- } else if (!pendingSet.has(sub)) {
331
- pendingSet.add(sub);
332
- pendingQueue.push(sub);
363
+ let node = head;
364
+ while (node) {
365
+ const s = node.sub;
366
+ if (s) {
367
+ if (s._c) {
368
+ propagateDirty(s);
369
+ } else if (!pendingSet.has(s)) {
370
+ pendingSet.add(s);
371
+ pendingQueue.push(s);
372
+ }
333
373
  }
374
+ node = node.sigNext;
334
375
  }
335
376
  drainQueue();
336
377
  } finally {
@@ -341,30 +382,6 @@ function notifySubscribers(signal2) {
341
382
  }
342
383
  }
343
384
  }
344
- function cleanup(subscriber) {
345
- const sub = subscriber;
346
- const singleDep = sub._dep;
347
- if (singleDep !== void 0) {
348
- const sig = singleDep;
349
- const subs = sig[SUBS];
350
- if (subs?.delete(subscriber)) {
351
- syncFastPath(sig, subs);
352
- }
353
- sub._dep = void 0;
354
- sub._depEpoch = void 0;
355
- return;
356
- }
357
- const deps = sub._deps;
358
- if (!deps || deps.size === 0) return;
359
- for (const signal2 of deps.keys()) {
360
- const sig = signal2;
361
- const subs = sig[SUBS];
362
- if (subs?.delete(subscriber)) {
363
- syncFastPath(sig, subs);
364
- }
365
- }
366
- deps.clear();
367
- }
368
385
 
369
386
  // src/reactivity/batch.ts
370
387
  var batchDepth = 0;
@@ -400,32 +417,64 @@ function flushBatch() {
400
417
  var _g = globalThis;
401
418
  var _isDev3 = isDev();
402
419
  function signal(initial, options) {
403
- const state = { value: initial };
420
+ const state = {
421
+ value: initial,
422
+ __v: 0,
423
+ __sc: 0,
424
+ subsHead: null,
425
+ subsTail: null,
426
+ __activeNode: null,
427
+ __name: void 0
428
+ };
404
429
  const debugName = _isDev3 ? options?.name : void 0;
405
430
  const equalsFn = options?.equals;
406
- if (debugName) {
407
- state.__name = debugName;
408
- }
431
+ if (debugName) state.__name = debugName;
409
432
  function get() {
410
433
  recordDependency(state);
411
434
  return state.value;
412
435
  }
413
436
  get.__signal = state;
414
437
  if (debugName) get.__name = debugName;
415
- function set(next) {
416
- const newValue = typeof next === "function" ? next(state.value) : next;
417
- if (equalsFn ? equalsFn(state.value, newValue) : Object.is(newValue, state.value)) return;
418
- if (_isDev3) {
419
- const oldValue = state.value;
438
+ let set;
439
+ if (equalsFn) {
440
+ set = (next) => {
441
+ const prev = state.value;
442
+ const newValue = typeof next === "function" ? next(prev) : next;
443
+ if (equalsFn(prev, newValue)) return;
444
+ state.value = newValue;
445
+ state.__v++;
446
+ if (_isDev3) {
447
+ const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
448
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
449
+ }
450
+ if (!enqueueBatchedSignal(state)) {
451
+ notifySubscribers(state);
452
+ }
453
+ };
454
+ } else if (_isDev3) {
455
+ set = (next) => {
456
+ const prev = state.value;
457
+ const newValue = typeof next === "function" ? next(prev) : next;
458
+ if (Object.is(newValue, prev)) return;
420
459
  state.value = newValue;
460
+ state.__v++;
421
461
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
422
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue, newValue });
423
- } else {
462
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
463
+ if (!enqueueBatchedSignal(state)) {
464
+ notifySubscribers(state);
465
+ }
466
+ };
467
+ } else {
468
+ set = (next) => {
469
+ const prev = state.value;
470
+ const newValue = typeof next === "function" ? next(prev) : next;
471
+ if (Object.is(newValue, prev)) return;
424
472
  state.value = newValue;
425
- }
426
- if (!enqueueBatchedSignal(state)) {
427
- notifySubscribers(state);
428
- }
473
+ state.__v++;
474
+ if (!enqueueBatchedSignal(state)) {
475
+ notifySubscribers(state);
476
+ }
477
+ };
429
478
  }
430
479
  if (_isDev3) {
431
480
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
@@ -480,120 +529,122 @@ function isSSR() {
480
529
 
481
530
  // src/core/signals/effect.ts
482
531
  var _g2 = globalThis;
532
+ var MAX_RERUNS = 100;
533
+ function flushUserCleanups(ctx) {
534
+ const list = ctx.userCleanups;
535
+ if (list.length === 0) return;
536
+ ctx.userCleanups = [];
537
+ for (let i = list.length - 1; i >= 0; i--) {
538
+ try {
539
+ list[i]();
540
+ } catch (err) {
541
+ if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
542
+ }
543
+ }
544
+ }
545
+ function drainReruns(ctx) {
546
+ let reruns = 1;
547
+ do {
548
+ ctx.rerunPending = false;
549
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
550
+ retrack(ctx.bodyFn, ctx.subscriber);
551
+ } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
552
+ if (ctx.rerunPending) {
553
+ ctx.rerunPending = false;
554
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
555
+ console.error(
556
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
557
+ );
558
+ }
559
+ }
560
+ }
561
+ function disposeEffect(ctx) {
562
+ if (ctx.disposed) return;
563
+ ctx.disposed = true;
564
+ const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
565
+ if (h) {
566
+ try {
567
+ h.emit("effect:destroy", { effectFn: ctx.fn });
568
+ } catch {
569
+ }
570
+ }
571
+ try {
572
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
573
+ } catch (err) {
574
+ if (typeof console !== "undefined") {
575
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
576
+ }
577
+ }
578
+ try {
579
+ cleanup(ctx.subscriber);
580
+ } catch (err) {
581
+ if (typeof console !== "undefined") {
582
+ console.warn("[SibuJS effect] dispose threw:", err);
583
+ }
584
+ }
585
+ }
483
586
  function effect(effectFn, options) {
484
587
  devAssert(typeof effectFn === "function", "effect: argument must be a function.");
485
588
  if (isSSR()) return () => {
486
589
  };
487
- const onError = options?.onError;
488
- let userCleanups = [];
489
- const onCleanup = (fn) => {
490
- userCleanups.push(fn);
590
+ const ctx = {
591
+ fn: effectFn,
592
+ onError: options?.onError,
593
+ userCleanups: [],
594
+ running: false,
595
+ rerunPending: false,
596
+ disposed: false,
597
+ onCleanup: null,
598
+ subscriber: null,
599
+ bodyFn: null
491
600
  };
492
- const runUserCleanups = () => {
493
- if (userCleanups.length === 0) return;
494
- const list = userCleanups;
495
- userCleanups = [];
496
- for (let i = list.length - 1; i >= 0; i--) {
497
- try {
498
- list[i]();
499
- } catch (err) {
500
- if (typeof console !== "undefined") {
501
- console.warn("[SibuJS effect] onCleanup threw:", err);
502
- }
503
- }
504
- }
601
+ ctx.onCleanup = (fn) => {
602
+ ctx.userCleanups.push(fn);
505
603
  };
506
- const invokeBody = () => effectFn(onCleanup);
507
- const wrappedFn = onError ? () => {
604
+ const onErrorCaptured = ctx.onError;
605
+ ctx.bodyFn = onErrorCaptured ? () => {
508
606
  try {
509
- invokeBody();
607
+ ctx.fn(ctx.onCleanup);
510
608
  } catch (err) {
511
- onError(err);
609
+ onErrorCaptured(err);
512
610
  }
513
- } : invokeBody;
514
- let cleanupHandle = () => {
611
+ } : () => {
612
+ ctx.fn(ctx.onCleanup);
515
613
  };
516
- let running = false;
517
- let rerunPending = false;
518
- const MAX_RERUNS = 100;
519
- const subscriber = () => {
520
- if (running) {
521
- rerunPending = true;
614
+ const sub = (() => {
615
+ if (ctx.running) {
616
+ ctx.rerunPending = true;
522
617
  return;
523
618
  }
524
- running = true;
619
+ ctx.running = true;
525
620
  try {
526
- let reruns = 0;
527
- do {
528
- rerunPending = false;
529
- runUserCleanups();
530
- cleanupHandle();
531
- cleanupHandle = track(wrappedFn, subscriber);
532
- if (++reruns > MAX_RERUNS) {
533
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
534
- console.error(
535
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
536
- );
537
- }
538
- rerunPending = false;
539
- break;
540
- }
541
- } while (rerunPending);
621
+ ctx.rerunPending = false;
622
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
623
+ retrack(ctx.bodyFn, sub);
624
+ if (ctx.rerunPending) drainReruns(ctx);
542
625
  } finally {
543
- running = false;
544
- rerunPending = false;
626
+ ctx.running = false;
627
+ ctx.rerunPending = false;
545
628
  }
546
- };
547
- running = true;
629
+ });
630
+ sub.depsHead = null;
631
+ sub.depsTail = null;
632
+ sub._epoch = 0;
633
+ sub._structDirty = false;
634
+ sub._runEpoch = 0;
635
+ sub._runs = 0;
636
+ ctx.subscriber = sub;
637
+ ctx.running = true;
548
638
  try {
549
- let reruns = 0;
550
- do {
551
- rerunPending = false;
552
- runUserCleanups();
553
- cleanupHandle();
554
- cleanupHandle = track(wrappedFn, subscriber);
555
- if (++reruns > MAX_RERUNS) {
556
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
557
- console.error(
558
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
559
- );
560
- }
561
- rerunPending = false;
562
- break;
563
- }
564
- } while (rerunPending);
639
+ retrack(ctx.bodyFn, ctx.subscriber);
640
+ if (ctx.rerunPending) drainReruns(ctx);
565
641
  } finally {
566
- running = false;
567
- rerunPending = false;
642
+ ctx.running = false;
643
+ ctx.rerunPending = false;
568
644
  }
569
645
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
570
646
  if (hook) hook.emit("effect:create", { effectFn });
571
- let disposed = false;
572
- return () => {
573
- if (disposed) return;
574
- disposed = true;
575
- const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
576
- if (h) {
577
- try {
578
- h.emit("effect:destroy", { effectFn });
579
- } catch {
580
- }
581
- }
582
- try {
583
- runUserCleanups();
584
- } catch (err) {
585
- if (typeof console !== "undefined") {
586
- console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
587
- }
588
- }
589
- try {
590
- cleanupHandle();
591
- } catch (err) {
592
- if (typeof console !== "undefined") {
593
- console.warn("[SibuJS effect] dispose threw:", err);
594
- }
595
- }
596
- };
647
+ return () => disposeEffect(ctx);
597
648
  }
598
649
 
599
650
  // src/browser/resize.ts