sibujs 2.1.0 → 3.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 (62) hide show
  1. package/dist/browser.cjs +324 -273
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +363 -330
  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-INBOWHQ3.js} +14 -11
  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 +363 -330
  39. package/dist/index.d.cts +26 -36
  40. package/dist/index.d.ts +26 -36
  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
@@ -221,24 +221,88 @@ function devWarn(message) {
221
221
 
222
222
  // src/reactivity/track.ts
223
223
  var _isDev2 = isDev();
224
- var STACK_INITIAL = 32;
225
- var STACK_SHRINK_THRESHOLD = 128;
226
- var subscriberStack = new Array(STACK_INITIAL);
227
- var stackCapacity = STACK_INITIAL;
228
- var stackTop = -1;
229
- var currentSubscriber = null;
230
- var SUBS = "__s";
231
- function syncFastPath(signal2, subs) {
232
- const size = subs.size;
233
- if (size === 0) {
234
- signal2.__f = void 0;
235
- delete signal2[SUBS];
236
- } else if (size === 1) {
237
- signal2.__f = subs.values().next().value;
238
- } else {
239
- signal2.__f = void 0;
224
+ var POOL_MAX = 4096;
225
+ var nodePool = [];
226
+ function createNode() {
227
+ return {
228
+ sig: null,
229
+ sub: null,
230
+ epoch: 0,
231
+ sigPrev: null,
232
+ sigNext: null,
233
+ subPrev: null,
234
+ subNext: null,
235
+ prevActive: null
236
+ };
237
+ }
238
+ function allocNode(sig, sub, epoch) {
239
+ const n = nodePool.pop();
240
+ if (n) {
241
+ n.sig = sig;
242
+ n.sub = sub;
243
+ n.epoch = epoch;
244
+ return n;
245
+ }
246
+ const fresh = createNode();
247
+ fresh.sig = sig;
248
+ fresh.sub = sub;
249
+ fresh.epoch = epoch;
250
+ return fresh;
251
+ }
252
+ function freeNode(node) {
253
+ node.sig = null;
254
+ node.sub = null;
255
+ node.sigPrev = null;
256
+ node.sigNext = null;
257
+ node.subPrev = null;
258
+ node.subNext = null;
259
+ node.prevActive = null;
260
+ if (nodePool.length < POOL_MAX) nodePool.push(node);
261
+ }
262
+ function linkSignal(sig, node) {
263
+ const oldHead = sig.subsHead ?? null;
264
+ node.sigPrev = null;
265
+ node.sigNext = oldHead;
266
+ if (oldHead) oldHead.sigPrev = node;
267
+ else sig.subsTail = node;
268
+ sig.subsHead = node;
269
+ sig.__sc = (sig.__sc ?? 0) + 1;
270
+ }
271
+ function unlinkSignal(node) {
272
+ const sig = node.sig;
273
+ if (!sig) return;
274
+ const prev = node.sigPrev;
275
+ const next = node.sigNext;
276
+ if (prev) prev.sigNext = next;
277
+ else sig.subsHead = next;
278
+ if (next) next.sigPrev = prev;
279
+ else sig.subsTail = prev;
280
+ sig.__sc = (sig.__sc ?? 1) - 1;
281
+ if (sig.__activeNode === node) sig.__activeNode = node.prevActive;
282
+ if (sig.__sc === 0) {
283
+ sig.subsHead = null;
284
+ sig.subsTail = null;
240
285
  }
241
286
  }
287
+ function linkSub(sub, node) {
288
+ const oldTail = sub.depsTail ?? null;
289
+ node.subPrev = oldTail;
290
+ node.subNext = null;
291
+ if (oldTail) oldTail.subNext = node;
292
+ else sub.depsHead = node;
293
+ sub.depsTail = node;
294
+ }
295
+ function unlinkSub(node) {
296
+ const sub = node.sub;
297
+ if (!sub) return;
298
+ const prev = node.subPrev;
299
+ const next = node.subNext;
300
+ if (prev) prev.subNext = next;
301
+ else sub.depsHead = next;
302
+ if (next) next.subPrev = prev;
303
+ else sub.depsTail = prev;
304
+ }
305
+ var currentSubscriber = null;
242
306
  var notifyDepth = 0;
243
307
  var pendingQueue = [];
244
308
  var pendingSet = /* @__PURE__ */ new Set();
@@ -250,64 +314,65 @@ function safeInvoke(sub) {
250
314
  if (_isDev2) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
251
315
  }
252
316
  }
253
- function track(effectFn, subscriber) {
254
- if (!subscriber) subscriber = effectFn;
255
- cleanup(subscriber);
256
- ++stackTop;
257
- if (stackTop >= stackCapacity) {
258
- stackCapacity *= 2;
259
- subscriberStack.length = stackCapacity;
260
- }
261
- subscriberStack[stackTop] = subscriber;
317
+ var subscriberEpochCounter = 0;
318
+ function retrack(effectFn, subscriber) {
319
+ const prev = currentSubscriber;
262
320
  currentSubscriber = subscriber;
321
+ const sub = subscriber;
322
+ const epoch = ++subscriberEpochCounter;
323
+ sub._epoch = epoch;
324
+ sub._structDirty = false;
325
+ for (let n = sub.depsHead ?? null; n !== null; n = n.subNext) {
326
+ const sig = n.sig;
327
+ n.prevActive = sig.__activeNode ?? null;
328
+ sig.__activeNode = n;
329
+ }
263
330
  try {
264
331
  effectFn();
265
332
  } finally {
266
- stackTop--;
267
- currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
268
- if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
269
- stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
270
- subscriberStack.length = stackCapacity;
333
+ currentSubscriber = prev;
334
+ let node = sub.depsHead ?? null;
335
+ while (node !== null) {
336
+ const next = node.subNext;
337
+ const sig = node.sig;
338
+ sig.__activeNode = node.prevActive;
339
+ node.prevActive = null;
340
+ if (node.epoch !== epoch) {
341
+ unlinkSub(node);
342
+ unlinkSignal(node);
343
+ freeNode(node);
344
+ }
345
+ node = next;
271
346
  }
272
347
  }
273
- return () => cleanup(subscriber);
274
348
  }
275
349
  function recordDependency(signal2) {
276
350
  if (!currentSubscriber) return;
277
351
  const sub = currentSubscriber;
278
- const epoch = sub._epoch;
279
- if (sub._dep === signal2) {
280
- sub._depEpoch = epoch;
281
- return;
282
- }
283
- const deps = sub._deps;
284
- if (deps) {
285
- deps.set(signal2, epoch);
286
- } else if (sub._dep !== void 0) {
287
- const map = /* @__PURE__ */ new Map();
288
- map.set(sub._dep, sub._depEpoch);
289
- map.set(signal2, epoch);
290
- sub._deps = map;
291
- sub._dep = void 0;
292
- sub._depEpoch = void 0;
293
- } else {
294
- sub._dep = signal2;
295
- sub._depEpoch = epoch;
296
- }
297
352
  const sig = signal2;
298
- let subs = sig[SUBS];
299
- if (!subs) {
300
- subs = /* @__PURE__ */ new Set();
301
- sig[SUBS] = subs;
353
+ const epoch = sub._epoch ?? 0;
354
+ const active = sig.__activeNode ?? null;
355
+ if (active !== null && active.sub === sub) {
356
+ active.epoch = epoch;
357
+ return;
302
358
  }
303
- const prevSize = subs.size;
304
- subs.add(currentSubscriber);
305
- if (subs.size !== prevSize) {
306
- if (subs.size === 1) {
307
- sig.__f = currentSubscriber;
308
- } else if (sig.__f !== void 0) {
309
- sig.__f = void 0;
310
- }
359
+ const node = allocNode(signal2, sub, epoch);
360
+ node.prevActive = active;
361
+ sig.__activeNode = node;
362
+ linkSub(sub, node);
363
+ linkSignal(sig, node);
364
+ sub._structDirty = true;
365
+ }
366
+ function cleanup(subscriber) {
367
+ const sub = subscriber;
368
+ let node = sub.depsHead ?? null;
369
+ sub.depsHead = null;
370
+ sub.depsTail = null;
371
+ while (node) {
372
+ const next = node.subNext;
373
+ unlinkSignal(node);
374
+ freeNode(node);
375
+ node = next;
311
376
  }
312
377
  }
313
378
  var maxSubscriberRepeats = 50;
@@ -320,7 +385,8 @@ function tickRepeat(sub) {
320
385
  s._runs = 1;
321
386
  return false;
322
387
  }
323
- return ++s._runs > maxSubscriberRepeats;
388
+ s._runs = (s._runs ?? 0) + 1;
389
+ return s._runs > maxSubscriberRepeats;
324
390
  }
325
391
  function cycleError(sub) {
326
392
  if (typeof console !== "undefined") {
@@ -362,93 +428,64 @@ function propagateDirty(sub) {
362
428
  stack.push(rootSig);
363
429
  while (stack.length > baseLen) {
364
430
  const sig = stack.pop();
365
- const first = sig.__f;
366
- if (first) {
367
- if (first._c) {
368
- const nSig = first._sig;
369
- if (!nSig._d) {
370
- nSig._d = true;
371
- stack.push(nSig);
372
- }
373
- } else if (!pendingSet.has(first)) {
374
- pendingSet.add(first);
375
- pendingQueue.push(first);
376
- }
377
- continue;
378
- }
379
- const subs = sig[SUBS];
380
- if (!subs) continue;
381
- for (const s of subs) {
382
- if (s._c) {
383
- const nSig = s._sig;
384
- if (nSig && !nSig._d) {
385
- nSig._d = true;
386
- stack.push(nSig);
387
- } else if (!nSig) {
388
- s();
431
+ let node = sig.subsHead ?? null;
432
+ while (node) {
433
+ const s = node.sub;
434
+ if (s) {
435
+ if (s._c) {
436
+ const nSig = s._sig;
437
+ if (nSig) {
438
+ if (!nSig._d) {
439
+ nSig._d = true;
440
+ stack.push(nSig);
441
+ }
442
+ } else {
443
+ s();
444
+ }
445
+ } else if (!pendingSet.has(s)) {
446
+ pendingSet.add(s);
447
+ pendingQueue.push(s);
389
448
  }
390
- } else if (!pendingSet.has(s)) {
391
- pendingSet.add(s);
392
- pendingQueue.push(s);
393
449
  }
450
+ node = node.sigNext;
394
451
  }
395
452
  }
396
453
  }
397
454
  function notifySubscribers(signal2) {
398
- const first = signal2.__f;
399
- if (first) {
400
- if (notifyDepth > 0) {
401
- if (first._c) {
402
- propagateDirty(first);
403
- } else if (!pendingSet.has(first)) {
404
- pendingSet.add(first);
405
- pendingQueue.push(first);
406
- }
407
- return;
408
- }
409
- notifyDepth++;
410
- drainEpoch++;
411
- try {
412
- if (first._c) {
413
- propagateDirty(first);
414
- } else if (tickRepeat(first)) {
415
- cycleError(first);
416
- } else {
417
- safeInvoke(first);
418
- }
419
- drainQueue();
420
- } finally {
421
- notifyDepth--;
422
- if (notifyDepth === 0) {
423
- pendingQueue.length = 0;
424
- pendingSet.clear();
425
- }
426
- }
427
- return;
428
- }
429
- const subs = signal2[SUBS];
430
- if (!subs || subs.size === 0) return;
455
+ const sig = signal2;
456
+ const head = sig.subsHead;
457
+ if (!head) return;
431
458
  if (notifyDepth > 0) {
432
- for (const sub of subs) {
433
- if (sub._c) {
434
- propagateDirty(sub);
435
- } else if (!pendingSet.has(sub)) {
436
- pendingSet.add(sub);
437
- pendingQueue.push(sub);
459
+ let node = head;
460
+ while (node) {
461
+ const s = node.sub;
462
+ if (s) {
463
+ if (s._c) {
464
+ propagateDirty(s);
465
+ } else if (!pendingSet.has(s)) {
466
+ pendingSet.add(s);
467
+ pendingQueue.push(s);
468
+ }
438
469
  }
470
+ node = node.sigNext;
439
471
  }
440
472
  return;
441
473
  }
442
474
  notifyDepth++;
443
475
  drainEpoch++;
444
476
  try {
445
- for (const sub of subs) {
446
- if (sub._c) {
447
- propagateDirty(sub);
448
- } else if (!pendingSet.has(sub)) {
449
- pendingSet.add(sub);
450
- pendingQueue.push(sub);
477
+ let node = head;
478
+ while (node) {
479
+ const s = node.sub;
480
+ if (s) {
481
+ if (s._c) {
482
+ propagateDirty(s);
483
+ } else if (!pendingSet.has(s)) {
484
+ pendingSet.add(s);
485
+ pendingQueue.push(s);
486
+ }
451
487
  }
488
+ node = node.sigNext;
452
489
  }
453
490
  drainQueue();
454
491
  } finally {
@@ -459,30 +496,6 @@ function notifySubscribers(signal2) {
459
496
  }
460
497
  }
461
498
  }
462
- function cleanup(subscriber) {
463
- const sub = subscriber;
464
- const singleDep = sub._dep;
465
- if (singleDep !== void 0) {
466
- const sig = singleDep;
467
- const subs = sig[SUBS];
468
- if (subs?.delete(subscriber)) {
469
- syncFastPath(sig, subs);
470
- }
471
- sub._dep = void 0;
472
- sub._depEpoch = void 0;
473
- return;
474
- }
475
- const deps = sub._deps;
476
- if (!deps || deps.size === 0) return;
477
- for (const signal2 of deps.keys()) {
478
- const sig = signal2;
479
- const subs = sig[SUBS];
480
- if (subs?.delete(subscriber)) {
481
- syncFastPath(sig, subs);
482
- }
483
- }
484
- deps.clear();
485
- }
486
499
 
487
500
  // src/core/ssr-context.ts
488
501
  var als = null;
@@ -511,120 +524,122 @@ function isSSR() {
511
524
 
512
525
  // src/core/signals/effect.ts
513
526
  var _g = globalThis;
527
+ var MAX_RERUNS = 100;
528
+ function flushUserCleanups(ctx) {
529
+ const list = ctx.userCleanups;
530
+ if (list.length === 0) return;
531
+ ctx.userCleanups = [];
532
+ for (let i = list.length - 1; i >= 0; i--) {
533
+ try {
534
+ list[i]();
535
+ } catch (err) {
536
+ if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
537
+ }
538
+ }
539
+ }
540
+ function drainReruns(ctx) {
541
+ let reruns = 1;
542
+ do {
543
+ ctx.rerunPending = false;
544
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
545
+ retrack(ctx.bodyFn, ctx.subscriber);
546
+ } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
547
+ if (ctx.rerunPending) {
548
+ ctx.rerunPending = false;
549
+ if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
550
+ console.error(
551
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
552
+ );
553
+ }
554
+ }
555
+ }
556
+ function disposeEffect(ctx) {
557
+ if (ctx.disposed) return;
558
+ ctx.disposed = true;
559
+ const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
560
+ if (h) {
561
+ try {
562
+ h.emit("effect:destroy", { effectFn: ctx.fn });
563
+ } catch {
564
+ }
565
+ }
566
+ try {
567
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
568
+ } catch (err) {
569
+ if (typeof console !== "undefined") {
570
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
571
+ }
572
+ }
573
+ try {
574
+ cleanup(ctx.subscriber);
575
+ } catch (err) {
576
+ if (typeof console !== "undefined") {
577
+ console.warn("[SibuJS effect] dispose threw:", err);
578
+ }
579
+ }
580
+ }
514
581
  function effect(effectFn, options) {
515
582
  devAssert(typeof effectFn === "function", "effect: argument must be a function.");
516
583
  if (isSSR()) return () => {
517
584
  };
518
- const onError = options?.onError;
519
- let userCleanups = [];
520
- const onCleanup = (fn) => {
521
- userCleanups.push(fn);
585
+ const ctx = {
586
+ fn: effectFn,
587
+ onError: options?.onError,
588
+ userCleanups: [],
589
+ running: false,
590
+ rerunPending: false,
591
+ disposed: false,
592
+ onCleanup: null,
593
+ subscriber: null,
594
+ bodyFn: null
522
595
  };
523
- const runUserCleanups = () => {
524
- if (userCleanups.length === 0) return;
525
- const list = userCleanups;
526
- userCleanups = [];
527
- for (let i = list.length - 1; i >= 0; i--) {
528
- try {
529
- list[i]();
530
- } catch (err) {
531
- if (typeof console !== "undefined") {
532
- console.warn("[SibuJS effect] onCleanup threw:", err);
533
- }
534
- }
535
- }
596
+ ctx.onCleanup = (fn) => {
597
+ ctx.userCleanups.push(fn);
536
598
  };
537
- const invokeBody = () => effectFn(onCleanup);
538
- const wrappedFn = onError ? () => {
599
+ const onErrorCaptured = ctx.onError;
600
+ ctx.bodyFn = onErrorCaptured ? () => {
539
601
  try {
540
- invokeBody();
602
+ ctx.fn(ctx.onCleanup);
541
603
  } catch (err) {
542
- onError(err);
604
+ onErrorCaptured(err);
543
605
  }
544
- } : invokeBody;
545
- let cleanupHandle = () => {
606
+ } : () => {
607
+ ctx.fn(ctx.onCleanup);
546
608
  };
547
- let running = false;
548
- let rerunPending = false;
549
- const MAX_RERUNS = 100;
550
- const subscriber = () => {
551
- if (running) {
552
- rerunPending = true;
609
+ const sub = (() => {
610
+ if (ctx.running) {
611
+ ctx.rerunPending = true;
553
612
  return;
554
613
  }
555
- running = true;
614
+ ctx.running = true;
556
615
  try {
557
- let reruns = 0;
558
- do {
559
- rerunPending = false;
560
- runUserCleanups();
561
- cleanupHandle();
562
- cleanupHandle = track(wrappedFn, subscriber);
563
- if (++reruns > MAX_RERUNS) {
564
- if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
565
- console.error(
566
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
567
- );
568
- }
569
- rerunPending = false;
570
- break;
571
- }
572
- } while (rerunPending);
616
+ ctx.rerunPending = false;
617
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
618
+ retrack(ctx.bodyFn, sub);
619
+ if (ctx.rerunPending) drainReruns(ctx);
573
620
  } finally {
574
- running = false;
575
- rerunPending = false;
621
+ ctx.running = false;
622
+ ctx.rerunPending = false;
576
623
  }
577
- };
578
- running = true;
624
+ });
625
+ sub.depsHead = null;
626
+ sub.depsTail = null;
627
+ sub._epoch = 0;
628
+ sub._structDirty = false;
629
+ sub._runEpoch = 0;
630
+ sub._runs = 0;
631
+ ctx.subscriber = sub;
632
+ ctx.running = true;
579
633
  try {
580
- let reruns = 0;
581
- do {
582
- rerunPending = false;
583
- runUserCleanups();
584
- cleanupHandle();
585
- cleanupHandle = track(wrappedFn, subscriber);
586
- if (++reruns > MAX_RERUNS) {
587
- if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
588
- console.error(
589
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
590
- );
591
- }
592
- rerunPending = false;
593
- break;
594
- }
595
- } while (rerunPending);
634
+ retrack(ctx.bodyFn, ctx.subscriber);
635
+ if (ctx.rerunPending) drainReruns(ctx);
596
636
  } finally {
597
- running = false;
598
- rerunPending = false;
637
+ ctx.running = false;
638
+ ctx.rerunPending = false;
599
639
  }
600
640
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
601
641
  if (hook) hook.emit("effect:create", { effectFn });
602
- let disposed = false;
603
- return () => {
604
- if (disposed) return;
605
- disposed = true;
606
- const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
607
- if (h) {
608
- try {
609
- h.emit("effect:destroy", { effectFn });
610
- } catch {
611
- }
612
- }
613
- try {
614
- runUserCleanups();
615
- } catch (err) {
616
- if (typeof console !== "undefined") {
617
- console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
618
- }
619
- }
620
- try {
621
- cleanupHandle();
622
- } catch (err) {
623
- if (typeof console !== "undefined") {
624
- console.warn("[SibuJS effect] dispose threw:", err);
625
- }
626
- }
627
- };
642
+ return () => disposeEffect(ctx);
628
643
  }
629
644
 
630
645
  // src/reactivity/batch.ts
@@ -640,32 +655,64 @@ function enqueueBatchedSignal(signal2) {
640
655
  var _g2 = globalThis;
641
656
  var _isDev3 = isDev();
642
657
  function signal(initial, options) {
643
- const state = { value: initial };
658
+ const state = {
659
+ value: initial,
660
+ __v: 0,
661
+ __sc: 0,
662
+ subsHead: null,
663
+ subsTail: null,
664
+ __activeNode: null,
665
+ __name: void 0
666
+ };
644
667
  const debugName = _isDev3 ? options?.name : void 0;
645
668
  const equalsFn = options?.equals;
646
- if (debugName) {
647
- state.__name = debugName;
648
- }
669
+ if (debugName) state.__name = debugName;
649
670
  function get() {
650
671
  recordDependency(state);
651
672
  return state.value;
652
673
  }
653
674
  get.__signal = state;
654
675
  if (debugName) get.__name = debugName;
655
- function set(next) {
656
- const newValue = typeof next === "function" ? next(state.value) : next;
657
- if (equalsFn ? equalsFn(state.value, newValue) : Object.is(newValue, state.value)) return;
658
- if (_isDev3) {
659
- const oldValue = state.value;
676
+ let set;
677
+ if (equalsFn) {
678
+ set = (next) => {
679
+ const prev = state.value;
680
+ const newValue = typeof next === "function" ? next(prev) : next;
681
+ if (equalsFn(prev, newValue)) return;
660
682
  state.value = newValue;
683
+ state.__v++;
684
+ if (_isDev3) {
685
+ const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
686
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
687
+ }
688
+ if (!enqueueBatchedSignal(state)) {
689
+ notifySubscribers(state);
690
+ }
691
+ };
692
+ } else if (_isDev3) {
693
+ set = (next) => {
694
+ const prev = state.value;
695
+ const newValue = typeof next === "function" ? next(prev) : next;
696
+ if (Object.is(newValue, prev)) return;
697
+ state.value = newValue;
698
+ state.__v++;
661
699
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
662
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue, newValue });
663
- } else {
700
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
701
+ if (!enqueueBatchedSignal(state)) {
702
+ notifySubscribers(state);
703
+ }
704
+ };
705
+ } else {
706
+ set = (next) => {
707
+ const prev = state.value;
708
+ const newValue = typeof next === "function" ? next(prev) : next;
709
+ if (Object.is(newValue, prev)) return;
664
710
  state.value = newValue;
665
- }
666
- if (!enqueueBatchedSignal(state)) {
667
- notifySubscribers(state);
668
- }
711
+ state.__v++;
712
+ if (!enqueueBatchedSignal(state)) {
713
+ notifySubscribers(state);
714
+ }
715
+ };
669
716
  }
670
717
  if (_isDev3) {
671
718
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;