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/index.cjs CHANGED
@@ -318,24 +318,89 @@ function isUrlAttribute(attr) {
318
318
 
319
319
  // src/reactivity/track.ts
320
320
  var _isDev2 = isDev();
321
- var STACK_INITIAL = 32;
322
- var STACK_SHRINK_THRESHOLD = 128;
323
- var subscriberStack = new Array(STACK_INITIAL);
324
- var stackCapacity = STACK_INITIAL;
325
- var stackTop = -1;
326
- var currentSubscriber = null;
327
- var SUBS = "__s";
328
- function syncFastPath(signal2, subs) {
329
- const size = subs.size;
330
- if (size === 0) {
331
- signal2.__f = void 0;
332
- delete signal2[SUBS];
333
- } else if (size === 1) {
334
- signal2.__f = subs.values().next().value;
335
- } else {
336
- signal2.__f = void 0;
337
- }
321
+ var POOL_MAX = 4096;
322
+ var nodePool = [];
323
+ function createNode() {
324
+ return {
325
+ sig: null,
326
+ sub: null,
327
+ epoch: 0,
328
+ sigPrev: null,
329
+ sigNext: null,
330
+ subPrev: null,
331
+ subNext: null,
332
+ prevActive: null
333
+ };
334
+ }
335
+ function allocNode(sig, sub2, epoch) {
336
+ const n = nodePool.pop();
337
+ if (n) {
338
+ n.sig = sig;
339
+ n.sub = sub2;
340
+ n.epoch = epoch;
341
+ return n;
342
+ }
343
+ const fresh = createNode();
344
+ fresh.sig = sig;
345
+ fresh.sub = sub2;
346
+ fresh.epoch = epoch;
347
+ return fresh;
348
+ }
349
+ function freeNode(node) {
350
+ node.sig = null;
351
+ node.sub = null;
352
+ node.sigPrev = null;
353
+ node.sigNext = null;
354
+ node.subPrev = null;
355
+ node.subNext = null;
356
+ node.prevActive = null;
357
+ if (nodePool.length < POOL_MAX) nodePool.push(node);
358
+ }
359
+ function linkSignal(sig, node) {
360
+ const oldHead = sig.subsHead ?? null;
361
+ node.sigPrev = null;
362
+ node.sigNext = oldHead;
363
+ if (oldHead) oldHead.sigPrev = node;
364
+ else sig.subsTail = node;
365
+ sig.subsHead = node;
366
+ sig.__sc = (sig.__sc ?? 0) + 1;
367
+ }
368
+ function unlinkSignal(node) {
369
+ const sig = node.sig;
370
+ if (!sig) return;
371
+ const prev = node.sigPrev;
372
+ const next = node.sigNext;
373
+ if (prev) prev.sigNext = next;
374
+ else sig.subsHead = next;
375
+ if (next) next.sigPrev = prev;
376
+ else sig.subsTail = prev;
377
+ sig.__sc = (sig.__sc ?? 1) - 1;
378
+ if (sig.__activeNode === node) sig.__activeNode = node.prevActive;
379
+ if (sig.__sc === 0) {
380
+ sig.subsHead = null;
381
+ sig.subsTail = null;
382
+ }
383
+ }
384
+ function linkSub(sub2, node) {
385
+ const oldTail = sub2.depsTail ?? null;
386
+ node.subPrev = oldTail;
387
+ node.subNext = null;
388
+ if (oldTail) oldTail.subNext = node;
389
+ else sub2.depsHead = node;
390
+ sub2.depsTail = node;
391
+ }
392
+ function unlinkSub(node) {
393
+ const sub2 = node.sub;
394
+ if (!sub2) return;
395
+ const prev = node.subPrev;
396
+ const next = node.subNext;
397
+ if (prev) prev.subNext = next;
398
+ else sub2.depsHead = next;
399
+ if (next) next.subPrev = prev;
400
+ else sub2.depsTail = prev;
338
401
  }
402
+ var currentSubscriber = null;
403
+ var suspendSavedSub = null;
339
404
  var notifyDepth = 0;
340
405
  var pendingQueue = [];
341
406
  var pendingSet = /* @__PURE__ */ new Set();
@@ -349,6 +414,30 @@ function safeInvoke(sub2) {
349
414
  }
350
415
  var suspendDepth = 0;
351
416
  var trackingSuspended = false;
417
+ function suspendTracking() {
418
+ if (suspendDepth === 0) {
419
+ suspendSavedSub = currentSubscriber;
420
+ currentSubscriber = null;
421
+ trackingSuspended = true;
422
+ }
423
+ suspendDepth++;
424
+ }
425
+ function resumeTracking() {
426
+ suspendDepth--;
427
+ if (suspendDepth === 0) {
428
+ currentSubscriber = suspendSavedSub;
429
+ suspendSavedSub = null;
430
+ trackingSuspended = false;
431
+ }
432
+ }
433
+ function untracked(fn) {
434
+ suspendTracking();
435
+ try {
436
+ return fn();
437
+ } finally {
438
+ resumeTracking();
439
+ }
440
+ }
352
441
  var subscriberEpochCounter = 0;
353
442
  function retrack(effectFn, subscriber) {
354
443
  const prev = currentSubscriber;
@@ -356,139 +445,77 @@ function retrack(effectFn, subscriber) {
356
445
  const sub2 = subscriber;
357
446
  const epoch = ++subscriberEpochCounter;
358
447
  sub2._epoch = epoch;
448
+ sub2._structDirty = false;
449
+ for (let n = sub2.depsHead ?? null; n !== null; n = n.subNext) {
450
+ const sig = n.sig;
451
+ n.prevActive = sig.__activeNode ?? null;
452
+ sig.__activeNode = n;
453
+ }
359
454
  try {
360
455
  effectFn();
361
456
  } finally {
362
457
  currentSubscriber = prev;
363
- pruneStaleDeps(sub2, epoch);
364
- }
365
- }
366
- function pruneStaleDeps(sub2, currentEpoch) {
367
- if (sub2._dep !== void 0) {
368
- if (sub2._depEpoch !== currentEpoch) {
369
- const sig = sub2._dep;
370
- const subs = sig[SUBS];
371
- if (subs?.delete(sub2)) syncFastPath(sig, subs);
372
- sub2._dep = void 0;
373
- sub2._depEpoch = void 0;
374
- }
375
- return;
376
- }
377
- const deps = sub2._deps;
378
- if (!deps || deps.size === 0) return;
379
- let stales;
380
- for (const [signal2, epoch] of deps) {
381
- if (epoch !== currentEpoch) {
382
- (stales ?? (stales = [])).push(signal2);
458
+ let node = sub2.depsHead ?? null;
459
+ while (node !== null) {
460
+ const next = node.subNext;
461
+ const sig = node.sig;
462
+ sig.__activeNode = node.prevActive;
463
+ node.prevActive = null;
464
+ if (node.epoch !== epoch) {
465
+ unlinkSub(node);
466
+ unlinkSignal(node);
467
+ freeNode(node);
468
+ }
469
+ node = next;
383
470
  }
384
471
  }
385
- if (!stales) return;
386
- for (const signal2 of stales) {
387
- deps.delete(signal2);
388
- const sig = signal2;
389
- const subs = sig[SUBS];
390
- if (subs?.delete(sub2)) syncFastPath(sig, subs);
391
- }
392
472
  }
393
473
  function track(effectFn, subscriber) {
394
474
  if (!subscriber) subscriber = effectFn;
395
475
  cleanup(subscriber);
396
- ++stackTop;
397
- if (stackTop >= stackCapacity) {
398
- stackCapacity *= 2;
399
- subscriberStack.length = stackCapacity;
400
- }
401
- subscriberStack[stackTop] = subscriber;
476
+ const prev = currentSubscriber;
402
477
  currentSubscriber = subscriber;
403
478
  try {
404
479
  effectFn();
405
480
  } finally {
406
- stackTop--;
407
- currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
408
- if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
409
- stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
410
- subscriberStack.length = stackCapacity;
481
+ currentSubscriber = prev;
482
+ const sub3 = subscriber;
483
+ for (let n = sub3.depsHead ?? null; n !== null; n = n.subNext) {
484
+ const sig = n.sig;
485
+ sig.__activeNode = n.prevActive;
486
+ n.prevActive = null;
411
487
  }
412
488
  }
413
- return () => cleanup(subscriber);
414
- }
415
- function suspendTracking() {
416
- if (suspendDepth === 0) {
417
- ++stackTop;
418
- if (stackTop >= stackCapacity) {
419
- stackCapacity *= 2;
420
- subscriberStack.length = stackCapacity;
421
- }
422
- subscriberStack[stackTop] = null;
423
- currentSubscriber = null;
424
- trackingSuspended = true;
425
- }
426
- suspendDepth++;
427
- }
428
- function resumeTracking() {
429
- suspendDepth--;
430
- if (suspendDepth === 0) {
431
- stackTop--;
432
- currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
433
- trackingSuspended = false;
434
- }
435
- }
436
- function untracked(fn) {
437
- suspendTracking();
438
- try {
439
- return fn();
440
- } finally {
441
- resumeTracking();
442
- }
489
+ const sub2 = subscriber;
490
+ return sub2._dispose ?? (sub2._dispose = () => cleanup(subscriber));
443
491
  }
444
492
  function recordDependency(signal2) {
445
493
  if (!currentSubscriber) return;
446
494
  const sub2 = currentSubscriber;
447
- const epoch = sub2._epoch;
448
- if (sub2._dep === signal2) {
449
- sub2._depEpoch = epoch;
450
- return;
451
- }
452
- const deps = sub2._deps;
453
- if (deps) {
454
- deps.set(signal2, epoch);
455
- } else if (sub2._dep !== void 0) {
456
- const map2 = /* @__PURE__ */ new Map();
457
- map2.set(sub2._dep, sub2._depEpoch);
458
- map2.set(signal2, epoch);
459
- sub2._deps = map2;
460
- sub2._dep = void 0;
461
- sub2._depEpoch = void 0;
462
- } else {
463
- sub2._dep = signal2;
464
- sub2._depEpoch = epoch;
465
- }
466
495
  const sig = signal2;
467
- let subs = sig[SUBS];
468
- if (!subs) {
469
- subs = /* @__PURE__ */ new Set();
470
- sig[SUBS] = subs;
471
- }
472
- const prevSize = subs.size;
473
- subs.add(currentSubscriber);
474
- if (subs.size !== prevSize) {
475
- if (subs.size === 1) {
476
- sig.__f = currentSubscriber;
477
- } else if (sig.__f !== void 0) {
478
- sig.__f = void 0;
479
- }
496
+ const epoch = sub2._epoch ?? 0;
497
+ const active = sig.__activeNode ?? null;
498
+ if (active !== null && active.sub === sub2) {
499
+ active.epoch = epoch;
500
+ return;
480
501
  }
502
+ const node = allocNode(signal2, sub2, epoch);
503
+ node.prevActive = active;
504
+ sig.__activeNode = node;
505
+ linkSub(sub2, node);
506
+ linkSignal(sig, node);
507
+ sub2._structDirty = true;
481
508
  }
482
- function queueSignalNotification(signal2) {
483
- const subs = signal2[SUBS];
484
- if (!subs) return;
485
- for (const sub2 of subs) {
486
- if (sub2._c) {
487
- propagateDirty(sub2);
488
- } else if (!pendingSet.has(sub2)) {
489
- pendingSet.add(sub2);
490
- pendingQueue.push(sub2);
491
- }
509
+ function cleanup(subscriber) {
510
+ const sub2 = subscriber;
511
+ let node = sub2.depsHead ?? null;
512
+ sub2.depsHead = null;
513
+ sub2.depsTail = null;
514
+ while (node) {
515
+ const next = node.subNext;
516
+ unlinkSignal(node);
517
+ freeNode(node);
518
+ node = next;
492
519
  }
493
520
  }
494
521
  var maxSubscriberRepeats = 50;
@@ -506,7 +533,8 @@ function tickRepeat(sub2) {
506
533
  s2._runs = 1;
507
534
  return false;
508
535
  }
509
- return ++s2._runs > maxSubscriberRepeats;
536
+ s2._runs = (s2._runs ?? 0) + 1;
537
+ return s2._runs > maxSubscriberRepeats;
510
538
  }
511
539
  function cycleError(sub2) {
512
540
  if (typeof console !== "undefined") {
@@ -562,93 +590,80 @@ function propagateDirty(sub2) {
562
590
  stack.push(rootSig);
563
591
  while (stack.length > baseLen) {
564
592
  const sig = stack.pop();
565
- const first = sig.__f;
566
- if (first) {
567
- if (first._c) {
568
- const nSig = first._sig;
569
- if (!nSig._d) {
570
- nSig._d = true;
571
- stack.push(nSig);
593
+ let node = sig.subsHead ?? null;
594
+ while (node) {
595
+ const s2 = node.sub;
596
+ if (s2) {
597
+ if (s2._c) {
598
+ const nSig = s2._sig;
599
+ if (nSig) {
600
+ if (!nSig._d) {
601
+ nSig._d = true;
602
+ stack.push(nSig);
603
+ }
604
+ } else {
605
+ s2();
606
+ }
607
+ } else if (!pendingSet.has(s2)) {
608
+ pendingSet.add(s2);
609
+ pendingQueue.push(s2);
572
610
  }
573
- } else if (!pendingSet.has(first)) {
574
- pendingSet.add(first);
575
- pendingQueue.push(first);
576
611
  }
577
- continue;
612
+ node = node.sigNext;
578
613
  }
579
- const subs = sig[SUBS];
580
- if (!subs) continue;
581
- for (const s2 of subs) {
614
+ }
615
+ }
616
+ function queueSignalNotification(signal2) {
617
+ const sig = signal2;
618
+ let node = sig.subsHead ?? null;
619
+ while (node) {
620
+ const s2 = node.sub;
621
+ if (s2) {
582
622
  if (s2._c) {
583
- const nSig = s2._sig;
584
- if (nSig && !nSig._d) {
585
- nSig._d = true;
586
- stack.push(nSig);
587
- } else if (!nSig) {
588
- s2();
589
- }
623
+ propagateDirty(s2);
590
624
  } else if (!pendingSet.has(s2)) {
591
625
  pendingSet.add(s2);
592
626
  pendingQueue.push(s2);
593
627
  }
594
628
  }
629
+ node = node.sigNext;
595
630
  }
596
631
  }
597
632
  function notifySubscribers(signal2) {
598
- const first = signal2.__f;
599
- if (first) {
600
- if (notifyDepth > 0) {
601
- if (first._c) {
602
- propagateDirty(first);
603
- } else if (!pendingSet.has(first)) {
604
- pendingSet.add(first);
605
- pendingQueue.push(first);
606
- }
607
- return;
608
- }
609
- notifyDepth++;
610
- drainEpoch++;
611
- try {
612
- if (first._c) {
613
- propagateDirty(first);
614
- } else if (tickRepeat(first)) {
615
- cycleError(first);
616
- } else {
617
- safeInvoke(first);
618
- }
619
- drainQueue();
620
- } finally {
621
- notifyDepth--;
622
- if (notifyDepth === 0) {
623
- pendingQueue.length = 0;
624
- pendingSet.clear();
625
- }
626
- }
627
- return;
628
- }
629
- const subs = signal2[SUBS];
630
- if (!subs || subs.size === 0) return;
633
+ const sig = signal2;
634
+ const head2 = sig.subsHead;
635
+ if (!head2) return;
631
636
  if (notifyDepth > 0) {
632
- for (const sub2 of subs) {
633
- if (sub2._c) {
634
- propagateDirty(sub2);
635
- } else if (!pendingSet.has(sub2)) {
636
- pendingSet.add(sub2);
637
- pendingQueue.push(sub2);
637
+ let node = head2;
638
+ while (node) {
639
+ const s2 = node.sub;
640
+ if (s2) {
641
+ if (s2._c) {
642
+ propagateDirty(s2);
643
+ } else if (!pendingSet.has(s2)) {
644
+ pendingSet.add(s2);
645
+ pendingQueue.push(s2);
646
+ }
638
647
  }
648
+ node = node.sigNext;
639
649
  }
640
650
  return;
641
651
  }
642
652
  notifyDepth++;
643
653
  drainEpoch++;
644
654
  try {
645
- for (const sub2 of subs) {
646
- if (sub2._c) {
647
- propagateDirty(sub2);
648
- } else if (!pendingSet.has(sub2)) {
649
- pendingSet.add(sub2);
650
- pendingQueue.push(sub2);
655
+ let node = head2;
656
+ while (node) {
657
+ const s2 = node.sub;
658
+ if (s2) {
659
+ if (s2._c) {
660
+ propagateDirty(s2);
661
+ } else if (!pendingSet.has(s2)) {
662
+ pendingSet.add(s2);
663
+ pendingQueue.push(s2);
664
+ }
651
665
  }
666
+ node = node.sigNext;
652
667
  }
653
668
  drainQueue();
654
669
  } finally {
@@ -659,30 +674,6 @@ function notifySubscribers(signal2) {
659
674
  }
660
675
  }
661
676
  }
662
- function cleanup(subscriber) {
663
- const sub2 = subscriber;
664
- const singleDep = sub2._dep;
665
- if (singleDep !== void 0) {
666
- const sig = singleDep;
667
- const subs = sig[SUBS];
668
- if (subs?.delete(subscriber)) {
669
- syncFastPath(sig, subs);
670
- }
671
- sub2._dep = void 0;
672
- sub2._depEpoch = void 0;
673
- return;
674
- }
675
- const deps = sub2._deps;
676
- if (!deps || deps.size === 0) return;
677
- for (const signal2 of deps.keys()) {
678
- const sig = signal2;
679
- const subs = sig[SUBS];
680
- if (subs?.delete(subscriber)) {
681
- syncFastPath(sig, subs);
682
- }
683
- }
684
- deps.clear();
685
- }
686
677
 
687
678
  // src/reactivity/bindAttribute.ts
688
679
  var _isDev3 = isDev();
@@ -2322,32 +2313,64 @@ function flushBatch() {
2322
2313
  var _g = globalThis;
2323
2314
  var _isDev9 = isDev();
2324
2315
  function signal(initial, options) {
2325
- const state = { value: initial };
2316
+ const state = {
2317
+ value: initial,
2318
+ __v: 0,
2319
+ __sc: 0,
2320
+ subsHead: null,
2321
+ subsTail: null,
2322
+ __activeNode: null,
2323
+ __name: void 0
2324
+ };
2326
2325
  const debugName = _isDev9 ? options?.name : void 0;
2327
2326
  const equalsFn = options?.equals;
2328
- if (debugName) {
2329
- state.__name = debugName;
2330
- }
2327
+ if (debugName) state.__name = debugName;
2331
2328
  function get() {
2332
2329
  recordDependency(state);
2333
2330
  return state.value;
2334
2331
  }
2335
2332
  get.__signal = state;
2336
2333
  if (debugName) get.__name = debugName;
2337
- function set(next) {
2338
- const newValue = typeof next === "function" ? next(state.value) : next;
2339
- if (equalsFn ? equalsFn(state.value, newValue) : Object.is(newValue, state.value)) return;
2340
- if (_isDev9) {
2341
- const oldValue = state.value;
2334
+ let set;
2335
+ if (equalsFn) {
2336
+ set = (next) => {
2337
+ const prev = state.value;
2338
+ const newValue = typeof next === "function" ? next(prev) : next;
2339
+ if (equalsFn(prev, newValue)) return;
2340
+ state.value = newValue;
2341
+ state.__v++;
2342
+ if (_isDev9) {
2343
+ const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2344
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
2345
+ }
2346
+ if (!enqueueBatchedSignal(state)) {
2347
+ notifySubscribers(state);
2348
+ }
2349
+ };
2350
+ } else if (_isDev9) {
2351
+ set = (next) => {
2352
+ const prev = state.value;
2353
+ const newValue = typeof next === "function" ? next(prev) : next;
2354
+ if (Object.is(newValue, prev)) return;
2342
2355
  state.value = newValue;
2356
+ state.__v++;
2343
2357
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2344
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue, newValue });
2345
- } else {
2358
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
2359
+ if (!enqueueBatchedSignal(state)) {
2360
+ notifySubscribers(state);
2361
+ }
2362
+ };
2363
+ } else {
2364
+ set = (next) => {
2365
+ const prev = state.value;
2366
+ const newValue = typeof next === "function" ? next(prev) : next;
2367
+ if (Object.is(newValue, prev)) return;
2346
2368
  state.value = newValue;
2347
- }
2348
- if (!enqueueBatchedSignal(state)) {
2349
- notifySubscribers(state);
2350
- }
2369
+ state.__v++;
2370
+ if (!enqueueBatchedSignal(state)) {
2371
+ notifySubscribers(state);
2372
+ }
2373
+ };
2351
2374
  }
2352
2375
  if (_isDev9) {
2353
2376
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
@@ -2431,120 +2454,122 @@ function on(deps, handler) {
2431
2454
  }
2432
2455
  };
2433
2456
  }
2457
+ var MAX_RERUNS = 100;
2458
+ function flushUserCleanups(ctx) {
2459
+ const list = ctx.userCleanups;
2460
+ if (list.length === 0) return;
2461
+ ctx.userCleanups = [];
2462
+ for (let i2 = list.length - 1; i2 >= 0; i2--) {
2463
+ try {
2464
+ list[i2]();
2465
+ } catch (err) {
2466
+ if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
2467
+ }
2468
+ }
2469
+ }
2470
+ function drainReruns(ctx) {
2471
+ let reruns = 1;
2472
+ do {
2473
+ ctx.rerunPending = false;
2474
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
2475
+ retrack(ctx.bodyFn, ctx.subscriber);
2476
+ } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
2477
+ if (ctx.rerunPending) {
2478
+ ctx.rerunPending = false;
2479
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
2480
+ console.error(
2481
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
2482
+ );
2483
+ }
2484
+ }
2485
+ }
2486
+ function disposeEffect(ctx) {
2487
+ if (ctx.disposed) return;
2488
+ ctx.disposed = true;
2489
+ const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2490
+ if (h) {
2491
+ try {
2492
+ h.emit("effect:destroy", { effectFn: ctx.fn });
2493
+ } catch {
2494
+ }
2495
+ }
2496
+ try {
2497
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
2498
+ } catch (err) {
2499
+ if (typeof console !== "undefined") {
2500
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
2501
+ }
2502
+ }
2503
+ try {
2504
+ cleanup(ctx.subscriber);
2505
+ } catch (err) {
2506
+ if (typeof console !== "undefined") {
2507
+ console.warn("[SibuJS effect] dispose threw:", err);
2508
+ }
2509
+ }
2510
+ }
2434
2511
  function effect(effectFn, options) {
2435
2512
  devAssert(typeof effectFn === "function", "effect: argument must be a function.");
2436
2513
  if (isSSR()) return () => {
2437
2514
  };
2438
- const onError = options?.onError;
2439
- let userCleanups = [];
2440
- const onCleanup2 = (fn) => {
2441
- userCleanups.push(fn);
2515
+ const ctx = {
2516
+ fn: effectFn,
2517
+ onError: options?.onError,
2518
+ userCleanups: [],
2519
+ running: false,
2520
+ rerunPending: false,
2521
+ disposed: false,
2522
+ onCleanup: null,
2523
+ subscriber: null,
2524
+ bodyFn: null
2442
2525
  };
2443
- const runUserCleanups = () => {
2444
- if (userCleanups.length === 0) return;
2445
- const list = userCleanups;
2446
- userCleanups = [];
2447
- for (let i2 = list.length - 1; i2 >= 0; i2--) {
2448
- try {
2449
- list[i2]();
2450
- } catch (err) {
2451
- if (typeof console !== "undefined") {
2452
- console.warn("[SibuJS effect] onCleanup threw:", err);
2453
- }
2454
- }
2455
- }
2526
+ ctx.onCleanup = (fn) => {
2527
+ ctx.userCleanups.push(fn);
2456
2528
  };
2457
- const invokeBody = () => effectFn(onCleanup2);
2458
- const wrappedFn = onError ? () => {
2529
+ const onErrorCaptured = ctx.onError;
2530
+ ctx.bodyFn = onErrorCaptured ? () => {
2459
2531
  try {
2460
- invokeBody();
2532
+ ctx.fn(ctx.onCleanup);
2461
2533
  } catch (err) {
2462
- onError(err);
2534
+ onErrorCaptured(err);
2463
2535
  }
2464
- } : invokeBody;
2465
- let cleanupHandle = () => {
2536
+ } : () => {
2537
+ ctx.fn(ctx.onCleanup);
2466
2538
  };
2467
- let running = false;
2468
- let rerunPending = false;
2469
- const MAX_RERUNS = 100;
2470
- const subscriber = () => {
2471
- if (running) {
2472
- rerunPending = true;
2539
+ const sub2 = (() => {
2540
+ if (ctx.running) {
2541
+ ctx.rerunPending = true;
2473
2542
  return;
2474
2543
  }
2475
- running = true;
2544
+ ctx.running = true;
2476
2545
  try {
2477
- let reruns = 0;
2478
- do {
2479
- rerunPending = false;
2480
- runUserCleanups();
2481
- cleanupHandle();
2482
- cleanupHandle = track(wrappedFn, subscriber);
2483
- if (++reruns > MAX_RERUNS) {
2484
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
2485
- console.error(
2486
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
2487
- );
2488
- }
2489
- rerunPending = false;
2490
- break;
2491
- }
2492
- } while (rerunPending);
2546
+ ctx.rerunPending = false;
2547
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
2548
+ retrack(ctx.bodyFn, sub2);
2549
+ if (ctx.rerunPending) drainReruns(ctx);
2493
2550
  } finally {
2494
- running = false;
2495
- rerunPending = false;
2551
+ ctx.running = false;
2552
+ ctx.rerunPending = false;
2496
2553
  }
2497
- };
2498
- running = true;
2554
+ });
2555
+ sub2.depsHead = null;
2556
+ sub2.depsTail = null;
2557
+ sub2._epoch = 0;
2558
+ sub2._structDirty = false;
2559
+ sub2._runEpoch = 0;
2560
+ sub2._runs = 0;
2561
+ ctx.subscriber = sub2;
2562
+ ctx.running = true;
2499
2563
  try {
2500
- let reruns = 0;
2501
- do {
2502
- rerunPending = false;
2503
- runUserCleanups();
2504
- cleanupHandle();
2505
- cleanupHandle = track(wrappedFn, subscriber);
2506
- if (++reruns > MAX_RERUNS) {
2507
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
2508
- console.error(
2509
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
2510
- );
2511
- }
2512
- rerunPending = false;
2513
- break;
2514
- }
2515
- } while (rerunPending);
2564
+ retrack(ctx.bodyFn, ctx.subscriber);
2565
+ if (ctx.rerunPending) drainReruns(ctx);
2516
2566
  } finally {
2517
- running = false;
2518
- rerunPending = false;
2567
+ ctx.running = false;
2568
+ ctx.rerunPending = false;
2519
2569
  }
2520
2570
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2521
2571
  if (hook) hook.emit("effect:create", { effectFn });
2522
- let disposed = false;
2523
- return () => {
2524
- if (disposed) return;
2525
- disposed = true;
2526
- const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
2527
- if (h) {
2528
- try {
2529
- h.emit("effect:destroy", { effectFn });
2530
- } catch {
2531
- }
2532
- }
2533
- try {
2534
- runUserCleanups();
2535
- } catch (err) {
2536
- if (typeof console !== "undefined") {
2537
- console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
2538
- }
2539
- }
2540
- try {
2541
- cleanupHandle();
2542
- } catch (err) {
2543
- if (typeof console !== "undefined") {
2544
- console.warn("[SibuJS effect] dispose threw:", err);
2545
- }
2546
- }
2547
- };
2572
+ return () => disposeEffect(ctx);
2548
2573
  }
2549
2574
 
2550
2575
  // src/core/signals/derived.ts
@@ -2555,6 +2580,7 @@ function derived(getter, options) {
2555
2580
  const cs = {};
2556
2581
  cs._d = false;
2557
2582
  cs._g = getter;
2583
+ cs.__v = 0;
2558
2584
  const markDirty = () => {
2559
2585
  if (cs._d) return;
2560
2586
  cs._d = true;
@@ -2584,11 +2610,14 @@ function derived(getter, options) {
2584
2610
  evaluating = true;
2585
2611
  let threw = true;
2586
2612
  try {
2613
+ const prev = cs._v;
2587
2614
  retrack(() => {
2588
- cs._v = getter();
2615
+ const next = getter();
2616
+ cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
2589
2617
  cs._d = false;
2590
2618
  threw = false;
2591
2619
  }, markDirty);
2620
+ if (!Object.is(prev, cs._v)) cs.__v++;
2592
2621
  } finally {
2593
2622
  evaluating = false;
2594
2623
  if (threw) cs._d = true;
@@ -2608,6 +2637,7 @@ function derived(getter, options) {
2608
2637
  cs._d = false;
2609
2638
  threw = false;
2610
2639
  }, markDirty);
2640
+ if (!Object.is(oldValue, cs._v)) cs.__v++;
2611
2641
  } finally {
2612
2642
  evaluating = false;
2613
2643
  if (threw) cs._d = true;