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
package/dist/ssr.cjs CHANGED
@@ -682,24 +682,88 @@ function escapeAttr(str) {
682
682
 
683
683
  // src/reactivity/track.ts
684
684
  var _isDev3 = isDev();
685
- var STACK_INITIAL = 32;
686
- var STACK_SHRINK_THRESHOLD = 128;
687
- var subscriberStack = new Array(STACK_INITIAL);
688
- var stackCapacity = STACK_INITIAL;
689
- var stackTop = -1;
690
- var currentSubscriber = null;
691
- var SUBS = "__s";
692
- function syncFastPath(signal2, subs) {
693
- const size = subs.size;
694
- if (size === 0) {
695
- signal2.__f = void 0;
696
- delete signal2[SUBS];
697
- } else if (size === 1) {
698
- signal2.__f = subs.values().next().value;
699
- } else {
700
- signal2.__f = void 0;
701
- }
685
+ var POOL_MAX = 4096;
686
+ var nodePool = [];
687
+ function createNode() {
688
+ return {
689
+ sig: null,
690
+ sub: null,
691
+ epoch: 0,
692
+ sigPrev: null,
693
+ sigNext: null,
694
+ subPrev: null,
695
+ subNext: null,
696
+ prevActive: null
697
+ };
698
+ }
699
+ function allocNode(sig, sub2, epoch) {
700
+ const n = nodePool.pop();
701
+ if (n) {
702
+ n.sig = sig;
703
+ n.sub = sub2;
704
+ n.epoch = epoch;
705
+ return n;
706
+ }
707
+ const fresh = createNode();
708
+ fresh.sig = sig;
709
+ fresh.sub = sub2;
710
+ fresh.epoch = epoch;
711
+ return fresh;
712
+ }
713
+ function freeNode(node) {
714
+ node.sig = null;
715
+ node.sub = null;
716
+ node.sigPrev = null;
717
+ node.sigNext = null;
718
+ node.subPrev = null;
719
+ node.subNext = null;
720
+ node.prevActive = null;
721
+ if (nodePool.length < POOL_MAX) nodePool.push(node);
722
+ }
723
+ function linkSignal(sig, node) {
724
+ const oldHead = sig.subsHead ?? null;
725
+ node.sigPrev = null;
726
+ node.sigNext = oldHead;
727
+ if (oldHead) oldHead.sigPrev = node;
728
+ else sig.subsTail = node;
729
+ sig.subsHead = node;
730
+ sig.__sc = (sig.__sc ?? 0) + 1;
731
+ }
732
+ function unlinkSignal(node) {
733
+ const sig = node.sig;
734
+ if (!sig) return;
735
+ const prev = node.sigPrev;
736
+ const next = node.sigNext;
737
+ if (prev) prev.sigNext = next;
738
+ else sig.subsHead = next;
739
+ if (next) next.sigPrev = prev;
740
+ else sig.subsTail = prev;
741
+ sig.__sc = (sig.__sc ?? 1) - 1;
742
+ if (sig.__activeNode === node) sig.__activeNode = node.prevActive;
743
+ if (sig.__sc === 0) {
744
+ sig.subsHead = null;
745
+ sig.subsTail = null;
746
+ }
747
+ }
748
+ function linkSub(sub2, node) {
749
+ const oldTail = sub2.depsTail ?? null;
750
+ node.subPrev = oldTail;
751
+ node.subNext = null;
752
+ if (oldTail) oldTail.subNext = node;
753
+ else sub2.depsHead = node;
754
+ sub2.depsTail = node;
755
+ }
756
+ function unlinkSub(node) {
757
+ const sub2 = node.sub;
758
+ if (!sub2) return;
759
+ const prev = node.subPrev;
760
+ const next = node.subNext;
761
+ if (prev) prev.subNext = next;
762
+ else sub2.depsHead = next;
763
+ if (next) next.subPrev = prev;
764
+ else sub2.depsTail = prev;
702
765
  }
766
+ var currentSubscriber = null;
703
767
  var notifyDepth = 0;
704
768
  var pendingQueue = [];
705
769
  var pendingSet = /* @__PURE__ */ new Set();
@@ -711,76 +775,84 @@ function safeInvoke(sub2) {
711
775
  if (_isDev3) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
712
776
  }
713
777
  }
778
+ var subscriberEpochCounter = 0;
779
+ function retrack(effectFn, subscriber) {
780
+ const prev = currentSubscriber;
781
+ currentSubscriber = subscriber;
782
+ const sub2 = subscriber;
783
+ const epoch = ++subscriberEpochCounter;
784
+ sub2._epoch = epoch;
785
+ sub2._structDirty = false;
786
+ for (let n = sub2.depsHead ?? null; n !== null; n = n.subNext) {
787
+ const sig = n.sig;
788
+ n.prevActive = sig.__activeNode ?? null;
789
+ sig.__activeNode = n;
790
+ }
791
+ try {
792
+ effectFn();
793
+ } finally {
794
+ currentSubscriber = prev;
795
+ let node = sub2.depsHead ?? null;
796
+ while (node !== null) {
797
+ const next = node.subNext;
798
+ const sig = node.sig;
799
+ sig.__activeNode = node.prevActive;
800
+ node.prevActive = null;
801
+ if (node.epoch !== epoch) {
802
+ unlinkSub(node);
803
+ unlinkSignal(node);
804
+ freeNode(node);
805
+ }
806
+ node = next;
807
+ }
808
+ }
809
+ }
714
810
  function track(effectFn, subscriber) {
715
811
  if (!subscriber) subscriber = effectFn;
716
812
  cleanup(subscriber);
717
- ++stackTop;
718
- if (stackTop >= stackCapacity) {
719
- stackCapacity *= 2;
720
- subscriberStack.length = stackCapacity;
721
- }
722
- subscriberStack[stackTop] = subscriber;
813
+ const prev = currentSubscriber;
723
814
  currentSubscriber = subscriber;
724
815
  try {
725
816
  effectFn();
726
817
  } finally {
727
- stackTop--;
728
- currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
729
- if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
730
- stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
731
- subscriberStack.length = stackCapacity;
818
+ currentSubscriber = prev;
819
+ const sub3 = subscriber;
820
+ for (let n = sub3.depsHead ?? null; n !== null; n = n.subNext) {
821
+ const sig = n.sig;
822
+ sig.__activeNode = n.prevActive;
823
+ n.prevActive = null;
732
824
  }
733
825
  }
734
- return () => cleanup(subscriber);
826
+ const sub2 = subscriber;
827
+ return sub2._dispose ?? (sub2._dispose = () => cleanup(subscriber));
735
828
  }
736
829
  function recordDependency(signal2) {
737
830
  if (!currentSubscriber) return;
738
831
  const sub2 = currentSubscriber;
739
- const epoch = sub2._epoch;
740
- if (sub2._dep === signal2) {
741
- sub2._depEpoch = epoch;
742
- return;
743
- }
744
- const deps = sub2._deps;
745
- if (deps) {
746
- deps.set(signal2, epoch);
747
- } else if (sub2._dep !== void 0) {
748
- const map2 = /* @__PURE__ */ new Map();
749
- map2.set(sub2._dep, sub2._depEpoch);
750
- map2.set(signal2, epoch);
751
- sub2._deps = map2;
752
- sub2._dep = void 0;
753
- sub2._depEpoch = void 0;
754
- } else {
755
- sub2._dep = signal2;
756
- sub2._depEpoch = epoch;
757
- }
758
832
  const sig = signal2;
759
- let subs = sig[SUBS];
760
- if (!subs) {
761
- subs = /* @__PURE__ */ new Set();
762
- sig[SUBS] = subs;
763
- }
764
- const prevSize = subs.size;
765
- subs.add(currentSubscriber);
766
- if (subs.size !== prevSize) {
767
- if (subs.size === 1) {
768
- sig.__f = currentSubscriber;
769
- } else if (sig.__f !== void 0) {
770
- sig.__f = void 0;
771
- }
833
+ const epoch = sub2._epoch ?? 0;
834
+ const active = sig.__activeNode ?? null;
835
+ if (active !== null && active.sub === sub2) {
836
+ active.epoch = epoch;
837
+ return;
772
838
  }
839
+ const node = allocNode(signal2, sub2, epoch);
840
+ node.prevActive = active;
841
+ sig.__activeNode = node;
842
+ linkSub(sub2, node);
843
+ linkSignal(sig, node);
844
+ sub2._structDirty = true;
773
845
  }
774
- function queueSignalNotification(signal2) {
775
- const subs = signal2[SUBS];
776
- if (!subs) return;
777
- for (const sub2 of subs) {
778
- if (sub2._c) {
779
- propagateDirty(sub2);
780
- } else if (!pendingSet.has(sub2)) {
781
- pendingSet.add(sub2);
782
- pendingQueue.push(sub2);
783
- }
846
+ function cleanup(subscriber) {
847
+ const sub2 = subscriber;
848
+ let node = sub2.depsHead ?? null;
849
+ sub2.depsHead = null;
850
+ sub2.depsTail = null;
851
+ while (node) {
852
+ const next = node.subNext;
853
+ unlinkSignal(node);
854
+ freeNode(node);
855
+ node = next;
784
856
  }
785
857
  }
786
858
  var maxSubscriberRepeats = 50;
@@ -793,7 +865,8 @@ function tickRepeat(sub2) {
793
865
  s2._runs = 1;
794
866
  return false;
795
867
  }
796
- return ++s2._runs > maxSubscriberRepeats;
868
+ s2._runs = (s2._runs ?? 0) + 1;
869
+ return s2._runs > maxSubscriberRepeats;
797
870
  }
798
871
  function cycleError(sub2) {
799
872
  if (typeof console !== "undefined") {
@@ -849,93 +922,80 @@ function propagateDirty(sub2) {
849
922
  stack.push(rootSig);
850
923
  while (stack.length > baseLen) {
851
924
  const sig = stack.pop();
852
- const first = sig.__f;
853
- if (first) {
854
- if (first._c) {
855
- const nSig = first._sig;
856
- if (!nSig._d) {
857
- nSig._d = true;
858
- stack.push(nSig);
925
+ let node = sig.subsHead ?? null;
926
+ while (node) {
927
+ const s2 = node.sub;
928
+ if (s2) {
929
+ if (s2._c) {
930
+ const nSig = s2._sig;
931
+ if (nSig) {
932
+ if (!nSig._d) {
933
+ nSig._d = true;
934
+ stack.push(nSig);
935
+ }
936
+ } else {
937
+ s2();
938
+ }
939
+ } else if (!pendingSet.has(s2)) {
940
+ pendingSet.add(s2);
941
+ pendingQueue.push(s2);
859
942
  }
860
- } else if (!pendingSet.has(first)) {
861
- pendingSet.add(first);
862
- pendingQueue.push(first);
863
943
  }
864
- continue;
944
+ node = node.sigNext;
865
945
  }
866
- const subs = sig[SUBS];
867
- if (!subs) continue;
868
- for (const s2 of subs) {
946
+ }
947
+ }
948
+ function queueSignalNotification(signal2) {
949
+ const sig = signal2;
950
+ let node = sig.subsHead ?? null;
951
+ while (node) {
952
+ const s2 = node.sub;
953
+ if (s2) {
869
954
  if (s2._c) {
870
- const nSig = s2._sig;
871
- if (nSig && !nSig._d) {
872
- nSig._d = true;
873
- stack.push(nSig);
874
- } else if (!nSig) {
875
- s2();
876
- }
955
+ propagateDirty(s2);
877
956
  } else if (!pendingSet.has(s2)) {
878
957
  pendingSet.add(s2);
879
958
  pendingQueue.push(s2);
880
959
  }
881
960
  }
961
+ node = node.sigNext;
882
962
  }
883
963
  }
884
964
  function notifySubscribers(signal2) {
885
- const first = signal2.__f;
886
- if (first) {
887
- if (notifyDepth > 0) {
888
- if (first._c) {
889
- propagateDirty(first);
890
- } else if (!pendingSet.has(first)) {
891
- pendingSet.add(first);
892
- pendingQueue.push(first);
893
- }
894
- return;
895
- }
896
- notifyDepth++;
897
- drainEpoch++;
898
- try {
899
- if (first._c) {
900
- propagateDirty(first);
901
- } else if (tickRepeat(first)) {
902
- cycleError(first);
903
- } else {
904
- safeInvoke(first);
905
- }
906
- drainQueue();
907
- } finally {
908
- notifyDepth--;
909
- if (notifyDepth === 0) {
910
- pendingQueue.length = 0;
911
- pendingSet.clear();
912
- }
913
- }
914
- return;
915
- }
916
- const subs = signal2[SUBS];
917
- if (!subs || subs.size === 0) return;
965
+ const sig = signal2;
966
+ const head2 = sig.subsHead;
967
+ if (!head2) return;
918
968
  if (notifyDepth > 0) {
919
- for (const sub2 of subs) {
920
- if (sub2._c) {
921
- propagateDirty(sub2);
922
- } else if (!pendingSet.has(sub2)) {
923
- pendingSet.add(sub2);
924
- pendingQueue.push(sub2);
969
+ let node = head2;
970
+ while (node) {
971
+ const s2 = node.sub;
972
+ if (s2) {
973
+ if (s2._c) {
974
+ propagateDirty(s2);
975
+ } else if (!pendingSet.has(s2)) {
976
+ pendingSet.add(s2);
977
+ pendingQueue.push(s2);
978
+ }
925
979
  }
980
+ node = node.sigNext;
926
981
  }
927
982
  return;
928
983
  }
929
984
  notifyDepth++;
930
985
  drainEpoch++;
931
986
  try {
932
- for (const sub2 of subs) {
933
- if (sub2._c) {
934
- propagateDirty(sub2);
935
- } else if (!pendingSet.has(sub2)) {
936
- pendingSet.add(sub2);
937
- pendingQueue.push(sub2);
987
+ let node = head2;
988
+ while (node) {
989
+ const s2 = node.sub;
990
+ if (s2) {
991
+ if (s2._c) {
992
+ propagateDirty(s2);
993
+ } else if (!pendingSet.has(s2)) {
994
+ pendingSet.add(s2);
995
+ pendingQueue.push(s2);
996
+ }
938
997
  }
998
+ node = node.sigNext;
939
999
  }
940
1000
  drainQueue();
941
1001
  } finally {
@@ -946,147 +1006,125 @@ function notifySubscribers(signal2) {
946
1006
  }
947
1007
  }
948
1008
  }
949
- function cleanup(subscriber) {
950
- const sub2 = subscriber;
951
- const singleDep = sub2._dep;
952
- if (singleDep !== void 0) {
953
- const sig = singleDep;
954
- const subs = sig[SUBS];
955
- if (subs?.delete(subscriber)) {
956
- syncFastPath(sig, subs);
957
- }
958
- sub2._dep = void 0;
959
- sub2._depEpoch = void 0;
960
- return;
1009
+
1010
+ // src/core/signals/effect.ts
1011
+ var _g = globalThis;
1012
+ var MAX_RERUNS = 100;
1013
+ function flushUserCleanups(ctx) {
1014
+ const list = ctx.userCleanups;
1015
+ if (list.length === 0) return;
1016
+ ctx.userCleanups = [];
1017
+ for (let i2 = list.length - 1; i2 >= 0; i2--) {
1018
+ try {
1019
+ list[i2]();
1020
+ } catch (err) {
1021
+ if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
1022
+ }
1023
+ }
1024
+ }
1025
+ function drainReruns(ctx) {
1026
+ let reruns = 1;
1027
+ do {
1028
+ ctx.rerunPending = false;
1029
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1030
+ retrack(ctx.bodyFn, ctx.subscriber);
1031
+ } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
1032
+ if (ctx.rerunPending) {
1033
+ ctx.rerunPending = false;
1034
+ if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
1035
+ console.error(
1036
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
1037
+ );
1038
+ }
961
1039
  }
962
- const deps = sub2._deps;
963
- if (!deps || deps.size === 0) return;
964
- for (const signal2 of deps.keys()) {
965
- const sig = signal2;
966
- const subs = sig[SUBS];
967
- if (subs?.delete(subscriber)) {
968
- syncFastPath(sig, subs);
1040
+ }
1041
+ function disposeEffect(ctx) {
1042
+ if (ctx.disposed) return;
1043
+ ctx.disposed = true;
1044
+ const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1045
+ if (h) {
1046
+ try {
1047
+ h.emit("effect:destroy", { effectFn: ctx.fn });
1048
+ } catch {
1049
+ }
1050
+ }
1051
+ try {
1052
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1053
+ } catch (err) {
1054
+ if (typeof console !== "undefined") {
1055
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
1056
+ }
1057
+ }
1058
+ try {
1059
+ cleanup(ctx.subscriber);
1060
+ } catch (err) {
1061
+ if (typeof console !== "undefined") {
1062
+ console.warn("[SibuJS effect] dispose threw:", err);
969
1063
  }
970
1064
  }
971
- deps.clear();
972
1065
  }
973
-
974
- // src/core/signals/effect.ts
975
- var _g = globalThis;
976
1066
  function effect(effectFn, options) {
977
1067
  devAssert(typeof effectFn === "function", "effect: argument must be a function.");
978
1068
  if (isSSR()) return () => {
979
1069
  };
980
- const onError = options?.onError;
981
- let userCleanups = [];
982
- const onCleanup = (fn) => {
983
- userCleanups.push(fn);
1070
+ const ctx = {
1071
+ fn: effectFn,
1072
+ onError: options?.onError,
1073
+ userCleanups: [],
1074
+ running: false,
1075
+ rerunPending: false,
1076
+ disposed: false,
1077
+ onCleanup: null,
1078
+ subscriber: null,
1079
+ bodyFn: null
984
1080
  };
985
- const runUserCleanups = () => {
986
- if (userCleanups.length === 0) return;
987
- const list = userCleanups;
988
- userCleanups = [];
989
- for (let i2 = list.length - 1; i2 >= 0; i2--) {
990
- try {
991
- list[i2]();
992
- } catch (err) {
993
- if (typeof console !== "undefined") {
994
- console.warn("[SibuJS effect] onCleanup threw:", err);
995
- }
996
- }
997
- }
1081
+ ctx.onCleanup = (fn) => {
1082
+ ctx.userCleanups.push(fn);
998
1083
  };
999
- const invokeBody = () => effectFn(onCleanup);
1000
- const wrappedFn = onError ? () => {
1084
+ const onErrorCaptured = ctx.onError;
1085
+ ctx.bodyFn = onErrorCaptured ? () => {
1001
1086
  try {
1002
- invokeBody();
1087
+ ctx.fn(ctx.onCleanup);
1003
1088
  } catch (err) {
1004
- onError(err);
1089
+ onErrorCaptured(err);
1005
1090
  }
1006
- } : invokeBody;
1007
- let cleanupHandle = () => {
1091
+ } : () => {
1092
+ ctx.fn(ctx.onCleanup);
1008
1093
  };
1009
- let running = false;
1010
- let rerunPending = false;
1011
- const MAX_RERUNS = 100;
1012
- const subscriber = () => {
1013
- if (running) {
1014
- rerunPending = true;
1094
+ const sub2 = (() => {
1095
+ if (ctx.running) {
1096
+ ctx.rerunPending = true;
1015
1097
  return;
1016
1098
  }
1017
- running = true;
1099
+ ctx.running = true;
1018
1100
  try {
1019
- let reruns = 0;
1020
- do {
1021
- rerunPending = false;
1022
- runUserCleanups();
1023
- cleanupHandle();
1024
- cleanupHandle = track(wrappedFn, subscriber);
1025
- if (++reruns > MAX_RERUNS) {
1026
- if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
1027
- console.error(
1028
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
1029
- );
1030
- }
1031
- rerunPending = false;
1032
- break;
1033
- }
1034
- } while (rerunPending);
1101
+ ctx.rerunPending = false;
1102
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1103
+ retrack(ctx.bodyFn, sub2);
1104
+ if (ctx.rerunPending) drainReruns(ctx);
1035
1105
  } finally {
1036
- running = false;
1037
- rerunPending = false;
1106
+ ctx.running = false;
1107
+ ctx.rerunPending = false;
1038
1108
  }
1039
- };
1040
- running = true;
1109
+ });
1110
+ sub2.depsHead = null;
1111
+ sub2.depsTail = null;
1112
+ sub2._epoch = 0;
1113
+ sub2._structDirty = false;
1114
+ sub2._runEpoch = 0;
1115
+ sub2._runs = 0;
1116
+ ctx.subscriber = sub2;
1117
+ ctx.running = true;
1041
1118
  try {
1042
- let reruns = 0;
1043
- do {
1044
- rerunPending = false;
1045
- runUserCleanups();
1046
- cleanupHandle();
1047
- cleanupHandle = track(wrappedFn, subscriber);
1048
- if (++reruns > MAX_RERUNS) {
1049
- if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
1050
- console.error(
1051
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
1052
- );
1053
- }
1054
- rerunPending = false;
1055
- break;
1056
- }
1057
- } while (rerunPending);
1119
+ retrack(ctx.bodyFn, ctx.subscriber);
1120
+ if (ctx.rerunPending) drainReruns(ctx);
1058
1121
  } finally {
1059
- running = false;
1060
- rerunPending = false;
1122
+ ctx.running = false;
1123
+ ctx.rerunPending = false;
1061
1124
  }
1062
1125
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1063
1126
  if (hook) hook.emit("effect:create", { effectFn });
1064
- let disposed = false;
1065
- return () => {
1066
- if (disposed) return;
1067
- disposed = true;
1068
- const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1069
- if (h) {
1070
- try {
1071
- h.emit("effect:destroy", { effectFn });
1072
- } catch {
1073
- }
1074
- }
1075
- try {
1076
- runUserCleanups();
1077
- } catch (err) {
1078
- if (typeof console !== "undefined") {
1079
- console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
1080
- }
1081
- }
1082
- try {
1083
- cleanupHandle();
1084
- } catch (err) {
1085
- if (typeof console !== "undefined") {
1086
- console.warn("[SibuJS effect] dispose threw:", err);
1087
- }
1088
- }
1089
- };
1127
+ return () => disposeEffect(ctx);
1090
1128
  }
1091
1129
 
1092
1130
  // src/platform/head.ts
@@ -1271,32 +1309,64 @@ function flushBatch() {
1271
1309
  var _g2 = globalThis;
1272
1310
  var _isDev4 = isDev();
1273
1311
  function signal(initial, options) {
1274
- const state = { value: initial };
1312
+ const state = {
1313
+ value: initial,
1314
+ __v: 0,
1315
+ __sc: 0,
1316
+ subsHead: null,
1317
+ subsTail: null,
1318
+ __activeNode: null,
1319
+ __name: void 0
1320
+ };
1275
1321
  const debugName = _isDev4 ? options?.name : void 0;
1276
1322
  const equalsFn = options?.equals;
1277
- if (debugName) {
1278
- state.__name = debugName;
1279
- }
1323
+ if (debugName) state.__name = debugName;
1280
1324
  function get() {
1281
1325
  recordDependency(state);
1282
1326
  return state.value;
1283
1327
  }
1284
1328
  get.__signal = state;
1285
1329
  if (debugName) get.__name = debugName;
1286
- function set(next) {
1287
- const newValue = typeof next === "function" ? next(state.value) : next;
1288
- if (equalsFn ? equalsFn(state.value, newValue) : Object.is(newValue, state.value)) return;
1289
- if (_isDev4) {
1290
- const oldValue = state.value;
1330
+ let set;
1331
+ if (equalsFn) {
1332
+ set = (next) => {
1333
+ const prev = state.value;
1334
+ const newValue = typeof next === "function" ? next(prev) : next;
1335
+ if (equalsFn(prev, newValue)) return;
1291
1336
  state.value = newValue;
1337
+ state.__v++;
1338
+ if (_isDev4) {
1339
+ const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1340
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
1341
+ }
1342
+ if (!enqueueBatchedSignal(state)) {
1343
+ notifySubscribers(state);
1344
+ }
1345
+ };
1346
+ } else if (_isDev4) {
1347
+ set = (next) => {
1348
+ const prev = state.value;
1349
+ const newValue = typeof next === "function" ? next(prev) : next;
1350
+ if (Object.is(newValue, prev)) return;
1351
+ state.value = newValue;
1352
+ state.__v++;
1292
1353
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1293
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue, newValue });
1294
- } else {
1354
+ if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
1355
+ if (!enqueueBatchedSignal(state)) {
1356
+ notifySubscribers(state);
1357
+ }
1358
+ };
1359
+ } else {
1360
+ set = (next) => {
1361
+ const prev = state.value;
1362
+ const newValue = typeof next === "function" ? next(prev) : next;
1363
+ if (Object.is(newValue, prev)) return;
1295
1364
  state.value = newValue;
1296
- }
1297
- if (!enqueueBatchedSignal(state)) {
1298
- notifySubscribers(state);
1299
- }
1365
+ state.__v++;
1366
+ if (!enqueueBatchedSignal(state)) {
1367
+ notifySubscribers(state);
1368
+ }
1369
+ };
1300
1370
  }
1301
1371
  if (_isDev4) {
1302
1372
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;