sibujs 3.3.1 → 3.3.3

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 (78) hide show
  1. package/dist/browser.cjs +41 -18
  2. package/dist/browser.js +5 -5
  3. package/dist/build.cjs +57 -22
  4. package/dist/build.js +14 -14
  5. package/dist/cdn.global.js +7 -7
  6. package/dist/{chunk-MHBCEJQO.js → chunk-23VT3KZB.js} +2 -2
  7. package/dist/{chunk-WL7BIR6O.js → chunk-25LY5SRH.js} +31 -24
  8. package/dist/{chunk-37BUKSLH.js → chunk-5K6RVA2S.js} +1 -1
  9. package/dist/{chunk-AMIKDMLP.js → chunk-5Y34FWED.js} +17 -6
  10. package/dist/chunk-7ZHH77QA.js +9 -0
  11. package/dist/chunk-CCSJMTRN.js +15 -0
  12. package/dist/{chunk-R3QEDXFS.js → chunk-EX77FXTT.js} +1 -1
  13. package/dist/{chunk-WW6DAGGR.js → chunk-F3HO2MP7.js} +1 -1
  14. package/dist/{chunk-ZUVLC7TM.js → chunk-F7HW2NI5.js} +2 -4
  15. package/dist/{chunk-ULLTNDRA.js → chunk-IEYFHN5V.js} +72 -25
  16. package/dist/{chunk-Z37APKBV.js → chunk-IQN5W7GE.js} +73 -16
  17. package/dist/{chunk-WZG2SZOT.js → chunk-IWFE4AHO.js} +1 -1
  18. package/dist/{chunk-IKLYI3RF.js → chunk-MYXEBADX.js} +53 -23
  19. package/dist/{chunk-6LTFHJQG.js → chunk-QCQQ2N5H.js} +41 -20
  20. package/dist/{chunk-VOVVTOEA.js → chunk-QTOOBABV.js} +22 -5
  21. package/dist/{chunk-LU2MQXQQ.js → chunk-RZKGMHH4.js} +6 -6
  22. package/dist/{chunk-GOJMFRBL.js → chunk-S3NFJO6L.js} +20 -14
  23. package/dist/{chunk-NHKQKKZU.js → chunk-SBPUXWCE.js} +1 -1
  24. package/dist/{chunk-SLMFA3ZZ.js → chunk-TBDTU7UO.js} +2 -2
  25. package/dist/{chunk-4UUMSLSL.js → chunk-TVCCXPU2.js} +5 -5
  26. package/dist/{chunk-TEFZT5PJ.js → chunk-UOMYIAG6.js} +1 -1
  27. package/dist/{chunk-XH2RTYEQ.js → chunk-WFUUT6TG.js} +15 -8
  28. package/dist/{chunk-M5KBNOSJ.js → chunk-WTFMV2RU.js} +70 -59
  29. package/dist/{chunk-3JHCYHWN.js → chunk-WWV3SJ3L.js} +19 -13
  30. package/dist/{chunk-RYMOSG5B.js → chunk-Y35NQNLG.js} +90 -60
  31. package/dist/{chunk-F7FXQ3QS.js → chunk-ZXCZWMZT.js} +1 -1
  32. package/dist/data.cjs +36 -16
  33. package/dist/data.js +8 -7
  34. package/dist/devtools.cjs +91 -35
  35. package/dist/devtools.d.cts +12 -5
  36. package/dist/devtools.d.ts +12 -5
  37. package/dist/devtools.js +7 -6
  38. package/dist/ecosystem.cjs +31 -16
  39. package/dist/ecosystem.js +11 -10
  40. package/dist/extras.cjs +485 -280
  41. package/dist/extras.d.cts +1 -1
  42. package/dist/extras.d.ts +1 -1
  43. package/dist/extras.js +28 -24
  44. package/dist/index.cjs +59 -22
  45. package/dist/index.d.cts +24 -8
  46. package/dist/index.d.ts +24 -8
  47. package/dist/index.js +25 -21
  48. package/dist/motion.cjs +223 -204
  49. package/dist/motion.d.cts +8 -1
  50. package/dist/motion.d.ts +8 -1
  51. package/dist/motion.js +6 -3
  52. package/dist/patterns.cjs +33 -20
  53. package/dist/patterns.d.cts +4 -1
  54. package/dist/patterns.d.ts +4 -1
  55. package/dist/patterns.js +6 -6
  56. package/dist/performance.cjs +90 -70
  57. package/dist/performance.js +8 -7
  58. package/dist/plugins.cjs +207 -144
  59. package/dist/plugins.d.cts +2 -1
  60. package/dist/plugins.d.ts +2 -1
  61. package/dist/plugins.js +178 -124
  62. package/dist/{ssr-6D67RAVB.js → ssr-2PPULEK2.js} +2 -2
  63. package/dist/ssr.cjs +132 -105
  64. package/dist/ssr.d.cts +8 -1
  65. package/dist/ssr.d.ts +8 -1
  66. package/dist/ssr.js +11 -10
  67. package/dist/testing.cjs +38 -18
  68. package/dist/testing.js +19 -8
  69. package/dist/ui.cjs +337 -294
  70. package/dist/ui.d.cts +0 -20
  71. package/dist/ui.d.ts +0 -20
  72. package/dist/ui.js +30 -24
  73. package/dist/widgets.cjs +95 -27
  74. package/dist/widgets.d.cts +6 -1
  75. package/dist/widgets.d.ts +6 -1
  76. package/dist/widgets.js +8 -7
  77. package/package.json +1 -1
  78. package/dist/chunk-YT6HQ6AM.js +0 -14
package/dist/ui.cjs CHANGED
@@ -107,8 +107,69 @@ function devWarn(message) {
107
107
  }
108
108
  }
109
109
 
110
- // src/reactivity/track-core.ts
110
+ // src/core/rendering/dispose.ts
111
+ var elementDisposers = /* @__PURE__ */ new WeakMap();
111
112
  var _isDev2 = isDev();
113
+ var activeBindingCount = 0;
114
+ function registerDisposer(node, teardown) {
115
+ let disposers = elementDisposers.get(node);
116
+ if (!disposers) {
117
+ disposers = [];
118
+ elementDisposers.set(node, disposers);
119
+ }
120
+ disposers.push(teardown);
121
+ if (_isDev2) activeBindingCount++;
122
+ }
123
+ function dispose(node) {
124
+ const stack = [node];
125
+ const order = [];
126
+ while (stack.length > 0) {
127
+ const current = stack.pop();
128
+ order.push(current);
129
+ const children = Array.from(current.childNodes);
130
+ for (let i = 0; i < children.length; i++) {
131
+ stack.push(children[i]);
132
+ }
133
+ }
134
+ for (let i = order.length - 1; i >= 0; i--) {
135
+ const current = order[i];
136
+ const disposers = elementDisposers.get(current);
137
+ if (disposers) {
138
+ const snapshot = disposers.slice();
139
+ elementDisposers.delete(current);
140
+ if (_isDev2) activeBindingCount -= snapshot.length;
141
+ for (const d of snapshot) {
142
+ try {
143
+ d();
144
+ } catch (err) {
145
+ if (_isDev2 && typeof console !== "undefined") {
146
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
147
+ }
148
+ }
149
+ }
150
+ let extraPasses = 0;
151
+ while (extraPasses++ < 8) {
152
+ const added = elementDisposers.get(current);
153
+ if (!added || added.length === 0) break;
154
+ const moreSnapshot = added.slice();
155
+ elementDisposers.delete(current);
156
+ if (_isDev2) activeBindingCount -= moreSnapshot.length;
157
+ for (const d of moreSnapshot) {
158
+ try {
159
+ d();
160
+ } catch (err) {
161
+ if (_isDev2 && typeof console !== "undefined") {
162
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ // src/reactivity/track-core.ts
172
+ var _isDev3 = isDev();
112
173
  var POOL_MAX = 4096;
113
174
  var nodePool = [];
114
175
  function createNode() {
@@ -200,7 +261,7 @@ function safeInvoke(sub) {
200
261
  try {
201
262
  sub();
202
263
  } catch (err) {
203
- if (_isDev2) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
264
+ if (_isDev3) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
204
265
  }
205
266
  }
206
267
  var suspendDepth = 0;
@@ -522,14 +583,14 @@ function forEachSubscriber(signal2, visit) {
522
583
  }
523
584
 
524
585
  // src/reactivity/track.ts
525
- var _isDev3 = isDev();
526
- var _runtimeVersion = typeof __SIBU_VERSION__ !== "undefined" ? __SIBU_VERSION__ : "dev";
586
+ var _isDev4 = isDev();
587
+ var _runtimeVersion = true ? "3.3.3" : "dev";
527
588
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
528
589
  function resolveReactiveApi() {
529
590
  const g = globalThis;
530
591
  const existing = g[REGISTRY_KEY];
531
592
  if (existing) {
532
- if (_isDev3 && !existing.__dupWarned) {
593
+ if (_isDev4 && !existing.__dupWarned) {
533
594
  existing.__dupWarned = true;
534
595
  devWarn(
535
596
  `Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity still works \u2014 all copies share the first one \u2014 but de-duplicate sibujs in your bundler (e.g. Vite optimizeDeps.exclude: ['sibujs'] or resolve.dedupe: ['sibujs']).`
@@ -658,6 +719,162 @@ function derived(getter, options) {
658
719
  return computedGetter;
659
720
  }
660
721
 
722
+ // src/core/ssr-context.ts
723
+ var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
724
+ function detectSSRShared() {
725
+ let detected = null;
726
+ try {
727
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
728
+ let mod = null;
729
+ const getBuiltin = process.getBuiltinModule;
730
+ if (typeof getBuiltin === "function") {
731
+ mod = getBuiltin("node:async_hooks");
732
+ } else {
733
+ const req = Function("return typeof require==='function'?require:null")();
734
+ if (req) mod = req("node:async_hooks");
735
+ }
736
+ if (mod) detected = new mod.AsyncLocalStorage();
737
+ }
738
+ } catch {
739
+ detected = null;
740
+ }
741
+ return { als: detected, fallbackStore: { ssr: false, suspenseIdCounter: 0 } };
742
+ }
743
+ var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
744
+ var als = _shared.als;
745
+ var fallbackStore = _shared.fallbackStore;
746
+ function getSSRStore() {
747
+ if (als) {
748
+ const s = als.getStore();
749
+ if (s) return s;
750
+ }
751
+ return fallbackStore;
752
+ }
753
+ function isSSR() {
754
+ return getSSRStore().ssr;
755
+ }
756
+
757
+ // src/core/signals/effect.ts
758
+ var _g = globalThis;
759
+ var MAX_RERUNS = 100;
760
+ function flushUserCleanups(ctx) {
761
+ const list = ctx.userCleanups;
762
+ if (list.length === 0) return;
763
+ ctx.userCleanups = [];
764
+ for (let i = list.length - 1; i >= 0; i--) {
765
+ try {
766
+ list[i]();
767
+ } catch (err) {
768
+ if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
769
+ }
770
+ }
771
+ }
772
+ function drainReruns(ctx) {
773
+ let reruns = 1;
774
+ do {
775
+ ctx.rerunPending = false;
776
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
777
+ retrack2(ctx.bodyFn, ctx.subscriber);
778
+ } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
779
+ if (ctx.rerunPending) {
780
+ ctx.rerunPending = false;
781
+ if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
782
+ console.error(
783
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
784
+ );
785
+ }
786
+ }
787
+ }
788
+ function disposeEffect(ctx) {
789
+ if (ctx.disposed) return;
790
+ ctx.disposed = true;
791
+ const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
792
+ if (h) {
793
+ try {
794
+ h.emit("effect:destroy", { effectFn: ctx.fn });
795
+ } catch {
796
+ }
797
+ }
798
+ try {
799
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
800
+ } catch (err) {
801
+ if (typeof console !== "undefined") {
802
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
803
+ }
804
+ }
805
+ try {
806
+ cleanup2(ctx.subscriber);
807
+ } catch (err) {
808
+ if (typeof console !== "undefined") {
809
+ console.warn("[SibuJS effect] dispose threw:", err);
810
+ }
811
+ }
812
+ }
813
+ function effect(effectFn, options) {
814
+ devAssert(typeof effectFn === "function", "effect: argument must be a function.");
815
+ if (isSSR()) return () => {
816
+ };
817
+ const ctx = {
818
+ fn: effectFn,
819
+ onError: options?.onError,
820
+ userCleanups: [],
821
+ running: false,
822
+ rerunPending: false,
823
+ disposed: false,
824
+ onCleanup: null,
825
+ subscriber: null,
826
+ bodyFn: null
827
+ };
828
+ ctx.onCleanup = (fn) => {
829
+ ctx.userCleanups.push(fn);
830
+ };
831
+ const onErrorCaptured = ctx.onError;
832
+ ctx.bodyFn = onErrorCaptured ? () => {
833
+ try {
834
+ ctx.fn(ctx.onCleanup);
835
+ } catch (err) {
836
+ onErrorCaptured(err);
837
+ }
838
+ } : () => {
839
+ ctx.fn(ctx.onCleanup);
840
+ };
841
+ const sub = (() => {
842
+ if (ctx.disposed) return;
843
+ if (ctx.running) {
844
+ ctx.rerunPending = true;
845
+ return;
846
+ }
847
+ ctx.running = true;
848
+ try {
849
+ ctx.rerunPending = false;
850
+ if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
851
+ retrack2(ctx.bodyFn, sub);
852
+ if (ctx.rerunPending) drainReruns(ctx);
853
+ } finally {
854
+ ctx.running = false;
855
+ ctx.rerunPending = false;
856
+ }
857
+ });
858
+ sub.depsHead = null;
859
+ sub.depsTail = null;
860
+ sub._epoch = 0;
861
+ sub._structDirty = false;
862
+ sub._runEpoch = 0;
863
+ sub._runs = 0;
864
+ ctx.subscriber = sub;
865
+ ctx.running = true;
866
+ try {
867
+ retrack2(ctx.bodyFn, ctx.subscriber);
868
+ if (ctx.rerunPending) drainReruns(ctx);
869
+ } finally {
870
+ ctx.running = false;
871
+ ctx.rerunPending = false;
872
+ }
873
+ const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
874
+ if (hook) hook.emit("effect:create", { effectFn });
875
+ return () => disposeEffect(ctx);
876
+ }
877
+
661
878
  // src/reactivity/batch.ts
662
879
  var batchDepth = 0;
663
880
  var pendingSignals = /* @__PURE__ */ new Set();
@@ -709,8 +926,8 @@ var enqueueBatchedSignal = API2.enqueueBatchedSignal;
709
926
  var isBatching = API2.isBatching;
710
927
 
711
928
  // src/core/signals/signal.ts
712
- var _g = globalThis;
713
- var _isDev4 = isDev();
929
+ var _g2 = globalThis;
930
+ var _isDev5 = isDev();
714
931
  function signal(initial, options) {
715
932
  const state = {
716
933
  value: initial,
@@ -721,7 +938,7 @@ function signal(initial, options) {
721
938
  __activeNode: null,
722
939
  __name: void 0
723
940
  };
724
- const debugName = _isDev4 ? options?.name : void 0;
941
+ const debugName = _isDev5 ? options?.name : void 0;
725
942
  const equalsFn = options?.equals;
726
943
  if (debugName) state.__name = debugName;
727
944
  function get() {
@@ -738,22 +955,22 @@ function signal(initial, options) {
738
955
  if (equalsFn(prev, newValue)) return;
739
956
  state.value = newValue;
740
957
  state.__v++;
741
- if (_isDev4) {
742
- const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
958
+ if (_isDev5) {
959
+ const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
743
960
  if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
744
961
  }
745
962
  if (!enqueueBatchedSignal(state)) {
746
963
  notifySubscribers2(state);
747
964
  }
748
965
  };
749
- } else if (_isDev4) {
966
+ } else if (_isDev5) {
750
967
  set = (next) => {
751
968
  const prev = state.value;
752
969
  const newValue = typeof next === "function" ? next(prev) : next;
753
970
  if (Object.is(newValue, prev)) return;
754
971
  state.value = newValue;
755
972
  state.__v++;
756
- const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
973
+ const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
757
974
  if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
758
975
  if (!enqueueBatchedSignal(state)) {
759
976
  notifySubscribers2(state);
@@ -771,8 +988,8 @@ function signal(initial, options) {
771
988
  }
772
989
  };
773
990
  }
774
- if (_isDev4) {
775
- const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
991
+ if (_isDev5) {
992
+ const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
776
993
  if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
777
994
  }
778
995
  return [get, set];
@@ -834,30 +1051,46 @@ function custom(fn, message) {
834
1051
  return (value) => fn(value) ? null : message;
835
1052
  }
836
1053
  function bindField(field, extras) {
1054
+ const readControlValue = (target) => {
1055
+ if ("checked" in target && target.type === "checkbox") {
1056
+ return target.checked;
1057
+ }
1058
+ if (target instanceof HTMLSelectElement && target.multiple) {
1059
+ return Array.from(target.selectedOptions, (o) => o.value);
1060
+ }
1061
+ return target.value;
1062
+ };
837
1063
  const fieldOn = {
838
- input: (e) => {
839
- const target = e.target;
840
- if (target.type === "checkbox") {
841
- field.set(target.checked);
842
- } else {
843
- field.set(target.value);
844
- }
845
- },
846
- change: (e) => {
847
- const target = e.target;
848
- if ("checked" in target && target.type === "checkbox") {
849
- field.set(target.checked);
850
- } else {
851
- field.set(target.value);
852
- }
853
- },
1064
+ input: (e) => field.set(readControlValue(e.target)),
1065
+ change: (e) => field.set(readControlValue(e.target)),
854
1066
  blur: () => field.touch()
855
1067
  };
856
- const { on: extraOn, value: _ignoreValue, ...restExtras } = extras ?? {};
1068
+ const {
1069
+ on: extraOn,
1070
+ value: _ignoreValue,
1071
+ onElement: extraOnElement,
1072
+ ...restExtras
1073
+ } = extras ?? {};
857
1074
  const mergedOn = extraOn && typeof extraOn === "object" ? { ...extraOn, ...fieldOn } : fieldOn;
1075
+ const onElement = (el) => {
1076
+ if (el instanceof HTMLSelectElement && el.multiple) {
1077
+ const stop = effect(() => {
1078
+ const v = field.value();
1079
+ const selected = Array.isArray(v) ? v.map(String) : [];
1080
+ for (const opt of Array.from(el.options)) {
1081
+ opt.selected = selected.includes(opt.value);
1082
+ }
1083
+ });
1084
+ registerDisposer(el, stop);
1085
+ }
1086
+ if (typeof extraOnElement === "function") {
1087
+ extraOnElement(el);
1088
+ }
1089
+ };
858
1090
  return {
859
1091
  value: field.value,
860
1092
  on: mergedOn,
1093
+ onElement,
861
1094
  ...restExtras
862
1095
  };
863
1096
  }
@@ -914,9 +1147,21 @@ function form(config) {
914
1147
  }
915
1148
  return true;
916
1149
  });
1150
+ const valueEquals = (a, b) => {
1151
+ if (Object.is(a, b)) return true;
1152
+ if (Array.isArray(a) && Array.isArray(b)) {
1153
+ return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));
1154
+ }
1155
+ if (a && b && typeof a === "object" && typeof b === "object") {
1156
+ const ak = Object.keys(a);
1157
+ const bk = Object.keys(b);
1158
+ return ak.length === bk.length && ak.every((k) => Object.is(a[k], b[k]));
1159
+ }
1160
+ return false;
1161
+ };
917
1162
  const isDirty = derived(() => {
918
1163
  for (const [name, cfg] of fieldEntries) {
919
- if (!Object.is(fieldMap[name].value(), cfg.initial)) return true;
1164
+ if (!valueEquals(fieldMap[name].value(), cfg.initial)) return true;
920
1165
  }
921
1166
  return false;
922
1167
  });
@@ -1011,217 +1256,6 @@ function formAction(fn) {
1011
1256
  return { run, pending, error, result, reset, onSubmit };
1012
1257
  }
1013
1258
 
1014
- // src/core/rendering/dispose.ts
1015
- var elementDisposers = /* @__PURE__ */ new WeakMap();
1016
- var _isDev5 = isDev();
1017
- var activeBindingCount = 0;
1018
- function registerDisposer(node, teardown) {
1019
- let disposers = elementDisposers.get(node);
1020
- if (!disposers) {
1021
- disposers = [];
1022
- elementDisposers.set(node, disposers);
1023
- }
1024
- disposers.push(teardown);
1025
- if (_isDev5) activeBindingCount++;
1026
- }
1027
- function dispose(node) {
1028
- const stack = [node];
1029
- const order = [];
1030
- while (stack.length > 0) {
1031
- const current = stack.pop();
1032
- order.push(current);
1033
- const children = Array.from(current.childNodes);
1034
- for (let i = 0; i < children.length; i++) {
1035
- stack.push(children[i]);
1036
- }
1037
- }
1038
- for (let i = order.length - 1; i >= 0; i--) {
1039
- const current = order[i];
1040
- const disposers = elementDisposers.get(current);
1041
- if (disposers) {
1042
- const snapshot = disposers.slice();
1043
- elementDisposers.delete(current);
1044
- if (_isDev5) activeBindingCount -= snapshot.length;
1045
- for (const d of snapshot) {
1046
- try {
1047
- d();
1048
- } catch (err) {
1049
- if (_isDev5 && typeof console !== "undefined") {
1050
- console.warn("[SibuJS] Disposer threw during cleanup:", err);
1051
- }
1052
- }
1053
- }
1054
- let extraPasses = 0;
1055
- while (extraPasses++ < 8) {
1056
- const added = elementDisposers.get(current);
1057
- if (!added || added.length === 0) break;
1058
- const moreSnapshot = added.slice();
1059
- elementDisposers.delete(current);
1060
- if (_isDev5) activeBindingCount -= moreSnapshot.length;
1061
- for (const d of moreSnapshot) {
1062
- try {
1063
- d();
1064
- } catch (err) {
1065
- if (_isDev5 && typeof console !== "undefined") {
1066
- console.warn("[SibuJS] Disposer threw during cleanup:", err);
1067
- }
1068
- }
1069
- }
1070
- }
1071
- }
1072
- }
1073
- }
1074
-
1075
- // src/core/ssr-context.ts
1076
- var als = null;
1077
- try {
1078
- if (typeof process !== "undefined" && process.versions && process.versions.node) {
1079
- let mod = null;
1080
- const getBuiltin = process.getBuiltinModule;
1081
- if (typeof getBuiltin === "function") {
1082
- mod = getBuiltin("node:async_hooks");
1083
- } else {
1084
- const req = Function("return typeof require==='function'?require:null")();
1085
- if (req) mod = req("node:async_hooks");
1086
- }
1087
- if (mod) als = new mod.AsyncLocalStorage();
1088
- }
1089
- } catch {
1090
- als = null;
1091
- }
1092
- var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
1093
- function getSSRStore() {
1094
- if (als) {
1095
- const s = als.getStore();
1096
- if (s) return s;
1097
- }
1098
- return fallbackStore;
1099
- }
1100
- function isSSR() {
1101
- return getSSRStore().ssr;
1102
- }
1103
-
1104
- // src/core/signals/effect.ts
1105
- var _g2 = globalThis;
1106
- var MAX_RERUNS = 100;
1107
- function flushUserCleanups(ctx) {
1108
- const list = ctx.userCleanups;
1109
- if (list.length === 0) return;
1110
- ctx.userCleanups = [];
1111
- for (let i = list.length - 1; i >= 0; i--) {
1112
- try {
1113
- list[i]();
1114
- } catch (err) {
1115
- if (typeof console !== "undefined") console.warn("[SibuJS effect] onCleanup threw:", err);
1116
- }
1117
- }
1118
- }
1119
- function drainReruns(ctx) {
1120
- let reruns = 1;
1121
- do {
1122
- ctx.rerunPending = false;
1123
- if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1124
- retrack2(ctx.bodyFn, ctx.subscriber);
1125
- } while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
1126
- if (ctx.rerunPending) {
1127
- ctx.rerunPending = false;
1128
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
1129
- console.error(
1130
- `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
1131
- );
1132
- }
1133
- }
1134
- }
1135
- function disposeEffect(ctx) {
1136
- if (ctx.disposed) return;
1137
- ctx.disposed = true;
1138
- const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1139
- if (h) {
1140
- try {
1141
- h.emit("effect:destroy", { effectFn: ctx.fn });
1142
- } catch {
1143
- }
1144
- }
1145
- try {
1146
- if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1147
- } catch (err) {
1148
- if (typeof console !== "undefined") {
1149
- console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
1150
- }
1151
- }
1152
- try {
1153
- cleanup2(ctx.subscriber);
1154
- } catch (err) {
1155
- if (typeof console !== "undefined") {
1156
- console.warn("[SibuJS effect] dispose threw:", err);
1157
- }
1158
- }
1159
- }
1160
- function effect(effectFn, options) {
1161
- devAssert(typeof effectFn === "function", "effect: argument must be a function.");
1162
- if (isSSR()) return () => {
1163
- };
1164
- const ctx = {
1165
- fn: effectFn,
1166
- onError: options?.onError,
1167
- userCleanups: [],
1168
- running: false,
1169
- rerunPending: false,
1170
- disposed: false,
1171
- onCleanup: null,
1172
- subscriber: null,
1173
- bodyFn: null
1174
- };
1175
- ctx.onCleanup = (fn) => {
1176
- ctx.userCleanups.push(fn);
1177
- };
1178
- const onErrorCaptured = ctx.onError;
1179
- ctx.bodyFn = onErrorCaptured ? () => {
1180
- try {
1181
- ctx.fn(ctx.onCleanup);
1182
- } catch (err) {
1183
- onErrorCaptured(err);
1184
- }
1185
- } : () => {
1186
- ctx.fn(ctx.onCleanup);
1187
- };
1188
- const sub = (() => {
1189
- if (ctx.disposed) return;
1190
- if (ctx.running) {
1191
- ctx.rerunPending = true;
1192
- return;
1193
- }
1194
- ctx.running = true;
1195
- try {
1196
- ctx.rerunPending = false;
1197
- if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
1198
- retrack2(ctx.bodyFn, sub);
1199
- if (ctx.rerunPending) drainReruns(ctx);
1200
- } finally {
1201
- ctx.running = false;
1202
- ctx.rerunPending = false;
1203
- }
1204
- });
1205
- sub.depsHead = null;
1206
- sub.depsTail = null;
1207
- sub._epoch = 0;
1208
- sub._structDirty = false;
1209
- sub._runEpoch = 0;
1210
- sub._runs = 0;
1211
- ctx.subscriber = sub;
1212
- ctx.running = true;
1213
- try {
1214
- retrack2(ctx.bodyFn, ctx.subscriber);
1215
- if (ctx.rerunPending) drainReruns(ctx);
1216
- } finally {
1217
- ctx.running = false;
1218
- ctx.rerunPending = false;
1219
- }
1220
- const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
1221
- if (hook) hook.emit("effect:create", { effectFn });
1222
- return () => disposeEffect(ctx);
1223
- }
1224
-
1225
1259
  // src/ui/virtualList.ts
1226
1260
  function VirtualList(props) {
1227
1261
  const overscan = props.overscan ?? 3;
@@ -1378,7 +1412,6 @@ function inputMask(options) {
1378
1412
  return /[^a-zA-Z0-9]/g;
1379
1413
  }
1380
1414
  const stripRegex = buildStripRegex();
1381
- const rawCharTest = options.pattern.includes("*") ? () => true : (c) => /[a-zA-Z0-9]/.test(c);
1382
1415
  function bind(input) {
1383
1416
  const onInput = () => {
1384
1417
  const cursorBefore = input.selectionStart ?? input.value.length;
@@ -1388,20 +1421,14 @@ function inputMask(options) {
1388
1421
  setValue(masked);
1389
1422
  setRawValue(extractRaw(masked));
1390
1423
  input.value = masked;
1391
- let rawBefore = 0;
1392
- for (let i = 0; i < cursorBefore && i < oldValue.length; i++) {
1393
- if (rawCharTest(oldValue[i])) rawBefore++;
1394
- }
1424
+ const rawBefore = oldValue.slice(0, cursorBefore).replace(stripRegex, "").length;
1395
1425
  let newCursor = 0;
1396
1426
  let counted = 0;
1397
- for (; newCursor < masked.length; newCursor++) {
1427
+ while (newCursor < masked.length && counted < rawBefore) {
1398
1428
  if (newCursor < options.pattern.length && isSlot(options.pattern[newCursor])) {
1399
1429
  counted++;
1400
- if (counted >= rawBefore) {
1401
- newCursor++;
1402
- break;
1403
- }
1404
1430
  }
1431
+ newCursor++;
1405
1432
  }
1406
1433
  try {
1407
1434
  input.setSelectionRange(newCursor, newCursor);
@@ -1442,6 +1469,12 @@ function zipMask() {
1442
1469
  return { pattern: "99999" };
1443
1470
  }
1444
1471
 
1472
+ // src/utils/globalSingleton.ts
1473
+ function globalSingleton(key, create) {
1474
+ const g = globalThis;
1475
+ return g[key] ?? (g[key] = create());
1476
+ }
1477
+
1445
1478
  // src/ui/a11y.ts
1446
1479
  function aria(element, attrs) {
1447
1480
  for (const [key, value] of Object.entries(attrs)) {
@@ -1600,14 +1633,12 @@ function hotkey(combo, handler, options = {}) {
1600
1633
  document.addEventListener("keydown", listener);
1601
1634
  return () => document.removeEventListener("keydown", listener);
1602
1635
  }
1603
- var announceQueues = {
1604
- polite: [],
1605
- assertive: []
1606
- };
1607
- var announceDraining = {
1608
- polite: false,
1609
- assertive: false
1610
- };
1636
+ var _announce = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.a11y.announce.v1"), () => ({
1637
+ queues: { polite: [], assertive: [] },
1638
+ draining: { polite: false, assertive: false }
1639
+ }));
1640
+ var announceQueues = _announce.queues;
1641
+ var announceDraining = _announce.draining;
1611
1642
  var ANNOUNCE_INTERVAL_MS = 150;
1612
1643
  function ensureLiveRegion(priority) {
1613
1644
  let region = document.getElementById(`sibu-announce-${priority}`);
@@ -1649,10 +1680,11 @@ function announce(message, priority = "polite") {
1649
1680
  }
1650
1681
 
1651
1682
  // src/core/rendering/createId.ts
1652
- var idCounter = 0;
1683
+ var COUNTER_KEY = /* @__PURE__ */ Symbol.for("sibujs.createId.v1");
1684
+ var _counter = globalThis[COUNTER_KEY] ?? (globalThis[COUNTER_KEY] = { n: 0 });
1653
1685
  function createId(prefix = "sibu") {
1654
- idCounter++;
1655
- return `${prefix}-${idCounter}`;
1686
+ _counter.n++;
1687
+ return `${prefix}-${_counter.n}`;
1656
1688
  }
1657
1689
 
1658
1690
  // src/ui/a11yPrimitives.ts
@@ -1833,7 +1865,7 @@ function createDialogAria(element, options = {}) {
1833
1865
  }
1834
1866
 
1835
1867
  // src/ui/scopedStyle.ts
1836
- var scopeCounter = 0;
1868
+ var _scope = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.scopedStyle.v1"), () => ({ n: 0 }));
1837
1869
  function decodeCssEscapes(css) {
1838
1870
  return css.replace(/\\([0-9a-f]{1,6})[ \t\n\r\f]?|\\([^\n])/gi, (_match, hex, ch) => {
1839
1871
  if (hex) {
@@ -1860,7 +1892,7 @@ function sanitizeCSS(css) {
1860
1892
  return sanitized;
1861
1893
  }
1862
1894
  function scopedStyle(css) {
1863
- const id = `sibu-s${scopeCounter++}`;
1895
+ const id = `sibu-s${_scope.n++}`;
1864
1896
  const attr = `data-${id}`;
1865
1897
  const safeCss = sanitizeCSS(css);
1866
1898
  const scopedCSS = safeCss.replace(/([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g, (match, selector, delimiter) => {
@@ -2074,13 +2106,16 @@ function bindData(el, key, getter) {
2074
2106
  }
2075
2107
 
2076
2108
  // src/ui/dialog.ts
2077
- var dialogStack = [];
2078
- var globalListenerAttached = false;
2109
+ var _dlg = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.dialog.v1"), () => ({
2110
+ stack: [],
2111
+ listenerAttached: false
2112
+ }));
2113
+ var dialogStack = _dlg.stack;
2079
2114
  function __resetDialogStack() {
2080
2115
  while (dialogStack.length > 0) dialogStack.pop();
2081
- if (typeof window !== "undefined" && globalListenerAttached) {
2116
+ if (typeof window !== "undefined" && _dlg.listenerAttached) {
2082
2117
  window.removeEventListener("keydown", handleGlobalKeydown);
2083
- globalListenerAttached = false;
2118
+ _dlg.listenerAttached = false;
2084
2119
  }
2085
2120
  }
2086
2121
  function handleGlobalKeydown(event) {
@@ -2089,16 +2124,16 @@ function handleGlobalKeydown(event) {
2089
2124
  if (top) top.close();
2090
2125
  }
2091
2126
  function ensureGlobalListener() {
2092
- if (typeof window === "undefined" || globalListenerAttached) return;
2127
+ if (typeof window === "undefined" || _dlg.listenerAttached) return;
2093
2128
  window.addEventListener("keydown", handleGlobalKeydown);
2094
- globalListenerAttached = true;
2129
+ _dlg.listenerAttached = true;
2095
2130
  }
2096
2131
  function removeGlobalListenerIfIdle() {
2097
2132
  if (typeof window === "undefined") return;
2098
- if (!globalListenerAttached) return;
2133
+ if (!_dlg.listenerAttached) return;
2099
2134
  if (dialogStack.length > 0) return;
2100
2135
  window.removeEventListener("keydown", handleGlobalKeydown);
2101
- globalListenerAttached = false;
2136
+ _dlg.listenerAttached = false;
2102
2137
  }
2103
2138
  function dialog() {
2104
2139
  const [isOpen, setIsOpen] = signal(false);
@@ -2224,6 +2259,10 @@ function infiniteScroll(options) {
2224
2259
  await onLoadMore();
2225
2260
  } finally {
2226
2261
  setLoading(false);
2262
+ if (!disposed && observer && _current && hasMore()) {
2263
+ observer.unobserve(_current);
2264
+ observer.observe(_current);
2265
+ }
2227
2266
  }
2228
2267
  }
2229
2268
  const originalRef = sentinelRef;
@@ -2263,29 +2302,30 @@ function pagination(options) {
2263
2302
  const total = options.totalItems();
2264
2303
  return Math.max(1, Math.ceil(total / pageSizeValue));
2265
2304
  });
2305
+ const currentPage = derived(() => Math.min(Math.max(1, page()), totalPages()));
2266
2306
  const startIndex = derived(() => {
2267
- return (page() - 1) * pageSizeValue;
2307
+ return (currentPage() - 1) * pageSizeValue;
2268
2308
  });
2269
2309
  const endIndex = derived(() => {
2270
- const end = page() * pageSizeValue;
2310
+ const end = currentPage() * pageSizeValue;
2271
2311
  const total = options.totalItems();
2272
2312
  return Math.min(end, total);
2273
2313
  });
2274
2314
  function next() {
2275
- if (page() < totalPages()) {
2276
- setPage((p) => p + 1);
2315
+ if (currentPage() < totalPages()) {
2316
+ setPage(currentPage() + 1);
2277
2317
  }
2278
2318
  }
2279
2319
  function prev() {
2280
- if (page() > 1) {
2281
- setPage((p) => p - 1);
2320
+ if (currentPage() > 1) {
2321
+ setPage(currentPage() - 1);
2282
2322
  }
2283
2323
  }
2284
2324
  function goTo(target) {
2285
2325
  const clamped = Math.max(1, Math.min(target, totalPages()));
2286
2326
  setPage(clamped);
2287
2327
  }
2288
- return { page, pageSize, totalPages, next, prev, goTo, startIndex, endIndex };
2328
+ return { page: currentPage, pageSize, totalPages, next, prev, goTo, startIndex, endIndex };
2289
2329
  }
2290
2330
 
2291
2331
  // src/ui/eventBus.ts
@@ -2412,24 +2452,27 @@ function hover(target) {
2412
2452
  target.removeEventListener("pointerenter", onEnter);
2413
2453
  target.removeEventListener("pointerleave", onLeave);
2414
2454
  }
2455
+ registerDisposer(target, dispose2);
2415
2456
  return { hovered, dispose: dispose2 };
2416
2457
  }
2417
2458
 
2418
2459
  // src/ui/scrollLock.ts
2419
- var lockCount = 0;
2420
- var savedOverflow = null;
2421
- var savedPaddingRight = null;
2460
+ var _lock = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.scrollLock.v1"), () => ({
2461
+ count: 0,
2462
+ savedOverflow: null,
2463
+ savedPaddingRight: null
2464
+ }));
2422
2465
  function scrollLock() {
2423
2466
  let owned = false;
2424
2467
  function lock() {
2425
2468
  if (owned) return;
2426
2469
  owned = true;
2427
- lockCount++;
2428
- if (lockCount !== 1 || typeof document === "undefined") return;
2470
+ _lock.count++;
2471
+ if (_lock.count !== 1 || typeof document === "undefined") return;
2429
2472
  const body = document.body;
2430
2473
  const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth;
2431
- savedOverflow = body.style.overflow;
2432
- savedPaddingRight = body.style.paddingRight;
2474
+ _lock.savedOverflow = body.style.overflow;
2475
+ _lock.savedPaddingRight = body.style.paddingRight;
2433
2476
  body.style.overflow = "hidden";
2434
2477
  if (scrollBarWidth > 0) {
2435
2478
  body.style.paddingRight = `${scrollBarWidth}px`;
@@ -2438,13 +2481,13 @@ function scrollLock() {
2438
2481
  function unlock() {
2439
2482
  if (!owned) return;
2440
2483
  owned = false;
2441
- lockCount = Math.max(0, lockCount - 1);
2442
- if (lockCount !== 0 || typeof document === "undefined") return;
2484
+ _lock.count = Math.max(0, _lock.count - 1);
2485
+ if (_lock.count !== 0 || typeof document === "undefined") return;
2443
2486
  const body = document.body;
2444
- body.style.overflow = savedOverflow ?? "";
2445
- body.style.paddingRight = savedPaddingRight ?? "";
2446
- savedOverflow = null;
2447
- savedPaddingRight = null;
2487
+ body.style.overflow = _lock.savedOverflow ?? "";
2488
+ body.style.paddingRight = _lock.savedPaddingRight ?? "";
2489
+ _lock.savedOverflow = null;
2490
+ _lock.savedPaddingRight = null;
2448
2491
  }
2449
2492
  return { lock, unlock };
2450
2493
  }