sibujs 3.3.2 → 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 (73) hide show
  1. package/dist/browser.cjs +21 -4
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +10 -3
  4. package/dist/build.js +11 -11
  5. package/dist/cdn.global.js +7 -7
  6. package/dist/{chunk-N5TQVEKE.js → chunk-23VT3KZB.js} +1 -1
  7. package/dist/{chunk-IQJ36UTJ.js → chunk-25LY5SRH.js} +31 -24
  8. package/dist/{chunk-6TCOWMGY.js → chunk-5K6RVA2S.js} +1 -1
  9. package/dist/{chunk-YUBEOWII.js → chunk-5Y34FWED.js} +16 -5
  10. package/dist/chunk-7ZHH77QA.js +9 -0
  11. package/dist/{chunk-G6N3LMO2.js → chunk-F3HO2MP7.js} +1 -1
  12. package/dist/{chunk-FJIRS3FM.js → chunk-F7HW2NI5.js} +1 -3
  13. package/dist/{chunk-AEOLHSSQ.js → chunk-IEYFHN5V.js} +72 -25
  14. package/dist/{chunk-FJO2ZL4Q.js → chunk-IQN5W7GE.js} +73 -16
  15. package/dist/{chunk-JCQG2I2G.js → chunk-IWFE4AHO.js} +1 -1
  16. package/dist/{chunk-2ARSB7NG.js → chunk-MYXEBADX.js} +27 -20
  17. package/dist/{chunk-A7CZH3GN.js → chunk-QCQQ2N5H.js} +41 -20
  18. package/dist/{chunk-Q46YIQYW.js → chunk-QTOOBABV.js} +22 -5
  19. package/dist/{chunk-ZEUP4TUD.js → chunk-RZKGMHH4.js} +6 -6
  20. package/dist/{chunk-QCFBIVIQ.js → chunk-SBPUXWCE.js} +1 -1
  21. package/dist/{chunk-RLTFJYDN.js → chunk-TBDTU7UO.js} +1 -1
  22. package/dist/{chunk-P7C7SEJV.js → chunk-TVCCXPU2.js} +5 -5
  23. package/dist/{chunk-4NJEAPLI.js → chunk-UOMYIAG6.js} +1 -1
  24. package/dist/{chunk-655B7MMR.js → chunk-WFUUT6TG.js} +15 -8
  25. package/dist/{chunk-YUR5SX7F.js → chunk-WTFMV2RU.js} +70 -59
  26. package/dist/{chunk-3JHCYHWN.js → chunk-WWV3SJ3L.js} +19 -13
  27. package/dist/{chunk-62V653X2.js → chunk-Y35NQNLG.js} +79 -44
  28. package/dist/{chunk-5VH3GIDX.js → chunk-ZXCZWMZT.js} +1 -1
  29. package/dist/data.cjs +16 -2
  30. package/dist/data.js +7 -6
  31. package/dist/devtools.cjs +71 -21
  32. package/dist/devtools.d.cts +12 -5
  33. package/dist/devtools.d.ts +12 -5
  34. package/dist/devtools.js +6 -5
  35. package/dist/ecosystem.cjs +11 -2
  36. package/dist/ecosystem.js +10 -9
  37. package/dist/extras.cjs +454 -250
  38. package/dist/extras.d.cts +1 -1
  39. package/dist/extras.d.ts +1 -1
  40. package/dist/extras.js +26 -22
  41. package/dist/index.cjs +10 -3
  42. package/dist/index.d.cts +4 -1
  43. package/dist/index.d.ts +4 -1
  44. package/dist/index.js +19 -19
  45. package/dist/motion.cjs +223 -204
  46. package/dist/motion.d.cts +8 -1
  47. package/dist/motion.d.ts +8 -1
  48. package/dist/motion.js +6 -3
  49. package/dist/patterns.cjs +13 -6
  50. package/dist/patterns.d.cts +4 -1
  51. package/dist/patterns.d.ts +4 -1
  52. package/dist/patterns.js +5 -5
  53. package/dist/performance.cjs +70 -56
  54. package/dist/performance.js +6 -5
  55. package/dist/plugins.cjs +98 -42
  56. package/dist/plugins.d.cts +2 -1
  57. package/dist/plugins.d.ts +2 -1
  58. package/dist/plugins.js +90 -37
  59. package/dist/ssr.cjs +112 -91
  60. package/dist/ssr.d.cts +8 -1
  61. package/dist/ssr.d.ts +8 -1
  62. package/dist/ssr.js +9 -8
  63. package/dist/testing.cjs +18 -4
  64. package/dist/testing.js +18 -7
  65. package/dist/ui.cjs +322 -281
  66. package/dist/ui.d.cts +0 -20
  67. package/dist/ui.d.ts +0 -20
  68. package/dist/ui.js +28 -22
  69. package/dist/widgets.cjs +75 -13
  70. package/dist/widgets.d.cts +6 -1
  71. package/dist/widgets.d.ts +6 -1
  72. package/dist/widgets.js +7 -6
  73. package/package.json +1 -1
@@ -1,15 +1,18 @@
1
1
  import {
2
- dispose
3
- } from "./chunk-5VGSK6D2.js";
2
+ globalSingleton
3
+ } from "./chunk-7ZHH77QA.js";
4
4
  import {
5
5
  sanitizeUrl
6
6
  } from "./chunk-L3GAGWCC.js";
7
7
  import {
8
8
  effect
9
- } from "./chunk-N5TQVEKE.js";
9
+ } from "./chunk-23VT3KZB.js";
10
+ import {
11
+ dispose
12
+ } from "./chunk-5VGSK6D2.js";
10
13
  import {
11
14
  signal
12
- } from "./chunk-JCQG2I2G.js";
15
+ } from "./chunk-IWFE4AHO.js";
13
16
  import {
14
17
  devWarn,
15
18
  isDev
@@ -23,12 +26,15 @@ var Priority = {
23
26
  LOW: 3,
24
27
  IDLE: 4
25
28
  };
26
- var taskIdCounter = 0;
27
- var taskQueue = [];
28
- var isProcessing = false;
29
- var scheduledKind = null;
30
- var scheduledHandle = null;
31
- var microtaskScheduled = false;
29
+ var _sched = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.scheduler.v1"), () => ({
30
+ taskIdCounter: 0,
31
+ taskQueue: [],
32
+ isProcessing: false,
33
+ scheduledKind: null,
34
+ scheduledHandle: null,
35
+ microtaskScheduled: false
36
+ }));
37
+ var taskQueue = _sched.taskQueue;
32
38
  function insertTask(task) {
33
39
  let i = taskQueue.length;
34
40
  while (i > 0 && taskQueue[i - 1].priority > task.priority) {
@@ -37,8 +43,8 @@ function insertTask(task) {
37
43
  taskQueue.splice(i, 0, task);
38
44
  }
39
45
  function processQueue() {
40
- if (isProcessing || taskQueue.length === 0) return;
41
- isProcessing = true;
46
+ if (_sched.isProcessing || taskQueue.length === 0) return;
47
+ _sched.isProcessing = true;
42
48
  const startTime = performance.now();
43
49
  const timeSlice = 5;
44
50
  while (taskQueue.length > 0) {
@@ -57,64 +63,69 @@ function processQueue() {
57
63
  console.error("[Scheduler] Task error:", e);
58
64
  }
59
65
  }
60
- isProcessing = false;
66
+ _sched.isProcessing = false;
61
67
  if (taskQueue.length > 0) {
62
68
  scheduleFrame();
63
69
  }
64
70
  }
65
71
  var TIER_SPEED = { microtask: 0, frame: 1, timeout: 2, idle: 3 };
66
72
  function cancelScheduled() {
67
- if (scheduledHandle !== null) {
68
- if (scheduledKind === "frame") cancelAnimationFrame(scheduledHandle);
69
- else if (scheduledKind === "idle" && typeof cancelIdleCallback !== "undefined") cancelIdleCallback(scheduledHandle);
70
- else if (scheduledKind === "timeout") clearTimeout(scheduledHandle);
73
+ if (_sched.scheduledHandle !== null) {
74
+ if (_sched.scheduledKind === "frame") cancelAnimationFrame(_sched.scheduledHandle);
75
+ else if (_sched.scheduledKind === "idle" && typeof cancelIdleCallback !== "undefined")
76
+ cancelIdleCallback(_sched.scheduledHandle);
77
+ else if (_sched.scheduledKind === "timeout") clearTimeout(_sched.scheduledHandle);
71
78
  }
72
- scheduledHandle = null;
73
- scheduledKind = null;
79
+ _sched.scheduledHandle = null;
80
+ _sched.scheduledKind = null;
74
81
  }
75
82
  function scheduleFrame() {
76
83
  const nextTask = taskQueue.find((t) => !t.cancelled);
77
84
  if (!nextTask) return;
78
- const desired = nextTask.priority <= Priority.USER_BLOCKING ? "microtask" : nextTask.priority === Priority.IDLE ? typeof requestIdleCallback !== "undefined" ? "idle" : "timeout" : "frame";
79
- if (microtaskScheduled) return;
80
- if (scheduledKind !== null) {
81
- if (TIER_SPEED[scheduledKind] <= TIER_SPEED[desired]) return;
85
+ const desired = nextTask.priority <= Priority.USER_BLOCKING ? "microtask" : nextTask.priority === Priority.IDLE ? typeof requestIdleCallback !== "undefined" ? "idle" : "timeout" : (
86
+ // NORMAL/LOW prefer a frame, but rAF is absent under SSR — fall back
87
+ // to a timeout so startTransition()/deferredValue() don't throw.
88
+ typeof requestAnimationFrame !== "undefined" ? "frame" : "timeout"
89
+ );
90
+ if (_sched.microtaskScheduled) return;
91
+ if (_sched.scheduledKind !== null) {
92
+ if (TIER_SPEED[_sched.scheduledKind] <= TIER_SPEED[desired]) return;
82
93
  cancelScheduled();
83
94
  }
84
95
  if (desired === "microtask") {
85
- microtaskScheduled = true;
86
- scheduledKind = "microtask";
96
+ _sched.microtaskScheduled = true;
97
+ _sched.scheduledKind = "microtask";
87
98
  queueMicrotask(() => {
88
- microtaskScheduled = false;
89
- scheduledKind = null;
99
+ _sched.microtaskScheduled = false;
100
+ _sched.scheduledKind = null;
90
101
  processQueue();
91
102
  });
92
103
  } else if (desired === "idle") {
93
- scheduledKind = "idle";
94
- scheduledHandle = requestIdleCallback(() => {
95
- scheduledKind = null;
96
- scheduledHandle = null;
104
+ _sched.scheduledKind = "idle";
105
+ _sched.scheduledHandle = requestIdleCallback(() => {
106
+ _sched.scheduledKind = null;
107
+ _sched.scheduledHandle = null;
97
108
  processQueue();
98
109
  });
99
110
  } else if (desired === "timeout") {
100
- scheduledKind = "timeout";
101
- scheduledHandle = setTimeout(() => {
102
- scheduledKind = null;
103
- scheduledHandle = null;
111
+ _sched.scheduledKind = "timeout";
112
+ _sched.scheduledHandle = setTimeout(() => {
113
+ _sched.scheduledKind = null;
114
+ _sched.scheduledHandle = null;
104
115
  processQueue();
105
116
  }, 50);
106
117
  } else {
107
- scheduledKind = "frame";
108
- scheduledHandle = requestAnimationFrame(() => {
109
- scheduledKind = null;
110
- scheduledHandle = null;
118
+ _sched.scheduledKind = "frame";
119
+ _sched.scheduledHandle = requestAnimationFrame(() => {
120
+ _sched.scheduledKind = null;
121
+ _sched.scheduledHandle = null;
111
122
  processQueue();
112
123
  });
113
124
  }
114
125
  }
115
126
  function scheduleUpdate(priority, callback) {
116
127
  const task = {
117
- id: taskIdCounter++,
128
+ id: _sched.taskIdCounter++,
118
129
  priority,
119
130
  callback,
120
131
  cancelled: false
@@ -135,15 +146,15 @@ function scheduleUpdate(priority, callback) {
135
146
  };
136
147
  }
137
148
  function flushScheduler() {
138
- if (scheduledHandle !== null) {
139
- if (scheduledKind === "frame") cancelAnimationFrame(scheduledHandle);
140
- else if (scheduledKind === "idle" && typeof cancelIdleCallback !== "undefined") {
141
- cancelIdleCallback(scheduledHandle);
142
- } else if (scheduledKind === "timeout") clearTimeout(scheduledHandle);
143
- }
144
- scheduledHandle = null;
145
- scheduledKind = null;
146
- microtaskScheduled = false;
149
+ if (_sched.scheduledHandle !== null) {
150
+ if (_sched.scheduledKind === "frame") cancelAnimationFrame(_sched.scheduledHandle);
151
+ else if (_sched.scheduledKind === "idle" && typeof cancelIdleCallback !== "undefined") {
152
+ cancelIdleCallback(_sched.scheduledHandle);
153
+ } else if (_sched.scheduledKind === "timeout") clearTimeout(_sched.scheduledHandle);
154
+ }
155
+ _sched.scheduledHandle = null;
156
+ _sched.scheduledKind = null;
157
+ _sched.microtaskScheduled = false;
147
158
  while (taskQueue.length > 0) {
148
159
  const task = taskQueue.shift();
149
160
  if (!task) break;
@@ -151,7 +162,7 @@ function flushScheduler() {
151
162
  task.callback();
152
163
  }
153
164
  }
154
- isProcessing = false;
165
+ _sched.isProcessing = false;
155
166
  }
156
167
  function pendingTasks() {
157
168
  return taskQueue.filter((t) => !t.cancelled).length;
@@ -199,16 +210,18 @@ function transitionState() {
199
210
  }
200
211
  return [isPending, transition];
201
212
  }
202
- var idCounter = 0;
203
- var idPrefix = "sibu";
213
+ var _ids = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.uniqueId.v1"), () => ({
214
+ counter: 0,
215
+ prefix: "sibu"
216
+ }));
204
217
  function resetIdCounter() {
205
- idCounter = 0;
218
+ _ids.counter = 0;
206
219
  }
207
220
  function setIdPrefix(prefix) {
208
- idPrefix = prefix;
221
+ _ids.prefix = prefix;
209
222
  }
210
223
  function uniqueId(suffix) {
211
- const id = `${idPrefix}-${idCounter++}`;
224
+ const id = `${_ids.prefix}-${_ids.counter++}`;
212
225
  return suffix ? `${id}-${suffix}` : id;
213
226
  }
214
227
 
@@ -446,7 +459,6 @@ function normalizedStore(schema) {
446
459
  }
447
460
  function normalize(data, schema) {
448
461
  const entities = {};
449
- const idKey = schema.idKey || "id";
450
462
  function ensureTable(name) {
451
463
  if (!entities[name]) {
452
464
  entities[name] = {};
@@ -462,7 +474,7 @@ function normalize(data, schema) {
462
474
  for (const [field, relationType] of Object.entries(entitySchema.relations)) {
463
475
  const value = entity[field];
464
476
  if (value == null) continue;
465
- const relSchema = { name: relationType, idKey };
477
+ const relSchema = { name: relationType };
466
478
  if (Array.isArray(value)) {
467
479
  flat[field] = value.map((item) => normalizeEntity(item, relSchema));
468
480
  } else if (typeof value === "object") {
@@ -485,13 +497,12 @@ function denormalize(id, entities, schema) {
485
497
  if (!table) return void 0;
486
498
  const entity = table[id];
487
499
  if (!entity) return void 0;
488
- const idKey = schema.idKey || "id";
489
500
  const result = { ...entity };
490
501
  if (schema.relations) {
491
502
  for (const [field, relationType] of Object.entries(schema.relations)) {
492
503
  const value = entity[field];
493
504
  if (value == null) continue;
494
- const relSchema = { name: relationType, idKey };
505
+ const relSchema = { name: relationType };
495
506
  if (Array.isArray(value)) {
496
507
  result[field] = value.map((relId) => denormalize(relId, entities, relSchema));
497
508
  } else if (typeof value === "string") {
@@ -1,3 +1,7 @@
1
+ import {
2
+ globalSingleton
3
+ } from "./chunk-7ZHH77QA.js";
4
+
1
5
  // src/plugins/plugin.ts
2
6
  function createPluginRegistry() {
3
7
  const installedPlugins = /* @__PURE__ */ new Set();
@@ -77,39 +81,41 @@ function createPluginRegistry() {
77
81
  };
78
82
  return registry;
79
83
  }
80
- var defaultRegistry = createPluginRegistry();
81
- var defaultRegistryTouched = false;
84
+ var _defaults = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.plugins.defaultRegistry.v1"), () => ({
85
+ registry: createPluginRegistry(),
86
+ touched: false
87
+ }));
82
88
  function createPlugin(name, install) {
83
89
  return { name, install };
84
90
  }
85
91
  function plugin(plugin2, options) {
86
- defaultRegistryTouched = true;
87
- defaultRegistry.plugin(plugin2, options);
92
+ _defaults.touched = true;
93
+ _defaults.registry.plugin(plugin2, options);
88
94
  }
89
95
  function inject(key, defaultValue) {
90
- return defaultRegistry.inject(key, defaultValue);
96
+ return _defaults.registry.inject(key, defaultValue);
91
97
  }
92
98
  function triggerPluginMount(element) {
93
- defaultRegistry.triggerMount(element);
99
+ _defaults.registry.triggerMount(element);
94
100
  }
95
101
  function triggerPluginUnmount(element) {
96
- defaultRegistry.triggerUnmount(element);
102
+ _defaults.registry.triggerUnmount(element);
97
103
  }
98
104
  function triggerPluginError(error) {
99
- defaultRegistry.triggerError(error);
105
+ _defaults.registry.triggerError(error);
100
106
  }
101
107
  function resetPlugins() {
102
- defaultRegistry.reset();
103
- defaultRegistryTouched = false;
108
+ _defaults.registry.reset();
109
+ _defaults.touched = false;
104
110
  }
105
111
  function setDefaultPluginRegistry(registry) {
106
- if (defaultRegistryTouched && defaultRegistry.installedPlugins.size > 0) {
112
+ if (_defaults.touched && _defaults.registry.installedPlugins.size > 0) {
107
113
  console.warn(
108
114
  "[Plugin] Replacing default plugin registry while plugins are already installed on the singleton. This may indicate mixed singleton/registry usage."
109
115
  );
110
116
  }
111
- defaultRegistry = registry;
112
- defaultRegistryTouched = true;
117
+ _defaults.registry = registry;
118
+ _defaults.touched = true;
113
119
  }
114
120
 
115
121
  export {
@@ -1,22 +1,25 @@
1
+ import {
2
+ globalSingleton
3
+ } from "./chunk-7ZHH77QA.js";
1
4
  import {
2
5
  bindAttribute
3
- } from "./chunk-QCFBIVIQ.js";
6
+ } from "./chunk-SBPUXWCE.js";
4
7
  import {
5
8
  derived
6
- } from "./chunk-G6N3LMO2.js";
9
+ } from "./chunk-F3HO2MP7.js";
10
+ import {
11
+ effect
12
+ } from "./chunk-23VT3KZB.js";
7
13
  import {
8
14
  dispose,
9
15
  registerDisposer
10
16
  } from "./chunk-5VGSK6D2.js";
11
- import {
12
- effect
13
- } from "./chunk-N5TQVEKE.js";
14
17
  import {
15
18
  signal
16
- } from "./chunk-JCQG2I2G.js";
19
+ } from "./chunk-IWFE4AHO.js";
17
20
  import {
18
21
  track
19
- } from "./chunk-4NJEAPLI.js";
22
+ } from "./chunk-UOMYIAG6.js";
20
23
 
21
24
  // src/ui/form.ts
22
25
  function required(message = "This field is required") {
@@ -88,11 +91,32 @@ function bindField(field, extras) {
88
91
  change: (e) => field.set(readControlValue(e.target)),
89
92
  blur: () => field.touch()
90
93
  };
91
- const { on: extraOn, value: _ignoreValue, ...restExtras } = extras ?? {};
94
+ const {
95
+ on: extraOn,
96
+ value: _ignoreValue,
97
+ onElement: extraOnElement,
98
+ ...restExtras
99
+ } = extras ?? {};
92
100
  const mergedOn = extraOn && typeof extraOn === "object" ? { ...extraOn, ...fieldOn } : fieldOn;
101
+ const onElement = (el) => {
102
+ if (el instanceof HTMLSelectElement && el.multiple) {
103
+ const stop = effect(() => {
104
+ const v = field.value();
105
+ const selected = Array.isArray(v) ? v.map(String) : [];
106
+ for (const opt of Array.from(el.options)) {
107
+ opt.selected = selected.includes(opt.value);
108
+ }
109
+ });
110
+ registerDisposer(el, stop);
111
+ }
112
+ if (typeof extraOnElement === "function") {
113
+ extraOnElement(el);
114
+ }
115
+ };
93
116
  return {
94
117
  value: field.value,
95
118
  on: mergedOn,
119
+ onElement,
96
120
  ...restExtras
97
121
  };
98
122
  }
@@ -149,9 +173,21 @@ function form(config) {
149
173
  }
150
174
  return true;
151
175
  });
176
+ const valueEquals = (a, b) => {
177
+ if (Object.is(a, b)) return true;
178
+ if (Array.isArray(a) && Array.isArray(b)) {
179
+ return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));
180
+ }
181
+ if (a && b && typeof a === "object" && typeof b === "object") {
182
+ const ak = Object.keys(a);
183
+ const bk = Object.keys(b);
184
+ return ak.length === bk.length && ak.every((k) => Object.is(a[k], b[k]));
185
+ }
186
+ return false;
187
+ };
152
188
  const isDirty = derived(() => {
153
189
  for (const [name, cfg] of fieldEntries) {
154
- if (!Object.is(fieldMap[name].value(), cfg.initial)) return true;
190
+ if (!valueEquals(fieldMap[name].value(), cfg.initial)) return true;
155
191
  }
156
192
  return false;
157
193
  });
@@ -367,7 +403,6 @@ function inputMask(options) {
367
403
  return /[^a-zA-Z0-9]/g;
368
404
  }
369
405
  const stripRegex = buildStripRegex();
370
- const rawCharTest = options.pattern.includes("*") ? () => true : (c) => /[a-zA-Z0-9]/.test(c);
371
406
  function bind(input) {
372
407
  const onInput = () => {
373
408
  const cursorBefore = input.selectionStart ?? input.value.length;
@@ -377,20 +412,14 @@ function inputMask(options) {
377
412
  setValue(masked);
378
413
  setRawValue(extractRaw(masked));
379
414
  input.value = masked;
380
- let rawBefore = 0;
381
- for (let i = 0; i < cursorBefore && i < oldValue.length; i++) {
382
- if (rawCharTest(oldValue[i])) rawBefore++;
383
- }
415
+ const rawBefore = oldValue.slice(0, cursorBefore).replace(stripRegex, "").length;
384
416
  let newCursor = 0;
385
417
  let counted = 0;
386
- for (; newCursor < masked.length; newCursor++) {
418
+ while (newCursor < masked.length && counted < rawBefore) {
387
419
  if (newCursor < options.pattern.length && isSlot(options.pattern[newCursor])) {
388
420
  counted++;
389
- if (counted >= rawBefore) {
390
- newCursor++;
391
- break;
392
- }
393
421
  }
422
+ newCursor++;
394
423
  }
395
424
  try {
396
425
  input.setSelectionRange(newCursor, newCursor);
@@ -589,14 +618,12 @@ function hotkey(combo, handler, options = {}) {
589
618
  document.addEventListener("keydown", listener);
590
619
  return () => document.removeEventListener("keydown", listener);
591
620
  }
592
- var announceQueues = {
593
- polite: [],
594
- assertive: []
595
- };
596
- var announceDraining = {
597
- polite: false,
598
- assertive: false
599
- };
621
+ var _announce = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.a11y.announce.v1"), () => ({
622
+ queues: { polite: [], assertive: [] },
623
+ draining: { polite: false, assertive: false }
624
+ }));
625
+ var announceQueues = _announce.queues;
626
+ var announceDraining = _announce.draining;
600
627
  var ANNOUNCE_INTERVAL_MS = 150;
601
628
  function ensureLiveRegion(priority) {
602
629
  let region = document.getElementById(`sibu-announce-${priority}`);
@@ -638,7 +665,7 @@ function announce(message, priority = "polite") {
638
665
  }
639
666
 
640
667
  // src/ui/scopedStyle.ts
641
- var scopeCounter = 0;
668
+ var _scope = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.scopedStyle.v1"), () => ({ n: 0 }));
642
669
  function decodeCssEscapes(css) {
643
670
  return css.replace(/\\([0-9a-f]{1,6})[ \t\n\r\f]?|\\([^\n])/gi, (_match, hex, ch) => {
644
671
  if (hex) {
@@ -665,7 +692,7 @@ function sanitizeCSS(css) {
665
692
  return sanitized;
666
693
  }
667
694
  function scopedStyle(css) {
668
- const id = `sibu-s${scopeCounter++}`;
695
+ const id = `sibu-s${_scope.n++}`;
669
696
  const attr = `data-${id}`;
670
697
  const safeCss = sanitizeCSS(css);
671
698
  const scopedCSS = safeCss.replace(/([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g, (match, selector, delimiter) => {
@@ -772,13 +799,16 @@ function bindData(el, key, getter) {
772
799
  }
773
800
 
774
801
  // src/ui/dialog.ts
775
- var dialogStack = [];
776
- var globalListenerAttached = false;
802
+ var _dlg = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.dialog.v1"), () => ({
803
+ stack: [],
804
+ listenerAttached: false
805
+ }));
806
+ var dialogStack = _dlg.stack;
777
807
  function __resetDialogStack() {
778
808
  while (dialogStack.length > 0) dialogStack.pop();
779
- if (typeof window !== "undefined" && globalListenerAttached) {
809
+ if (typeof window !== "undefined" && _dlg.listenerAttached) {
780
810
  window.removeEventListener("keydown", handleGlobalKeydown);
781
- globalListenerAttached = false;
811
+ _dlg.listenerAttached = false;
782
812
  }
783
813
  }
784
814
  function handleGlobalKeydown(event) {
@@ -787,16 +817,16 @@ function handleGlobalKeydown(event) {
787
817
  if (top) top.close();
788
818
  }
789
819
  function ensureGlobalListener() {
790
- if (typeof window === "undefined" || globalListenerAttached) return;
820
+ if (typeof window === "undefined" || _dlg.listenerAttached) return;
791
821
  window.addEventListener("keydown", handleGlobalKeydown);
792
- globalListenerAttached = true;
822
+ _dlg.listenerAttached = true;
793
823
  }
794
824
  function removeGlobalListenerIfIdle() {
795
825
  if (typeof window === "undefined") return;
796
- if (!globalListenerAttached) return;
826
+ if (!_dlg.listenerAttached) return;
797
827
  if (dialogStack.length > 0) return;
798
828
  window.removeEventListener("keydown", handleGlobalKeydown);
799
- globalListenerAttached = false;
829
+ _dlg.listenerAttached = false;
800
830
  }
801
831
  function dialog() {
802
832
  const [isOpen, setIsOpen] = signal(false);
@@ -922,6 +952,10 @@ function infiniteScroll(options) {
922
952
  await onLoadMore();
923
953
  } finally {
924
954
  setLoading(false);
955
+ if (!disposed && observer && _current && hasMore()) {
956
+ observer.unobserve(_current);
957
+ observer.observe(_current);
958
+ }
925
959
  }
926
960
  }
927
961
  const originalRef = sentinelRef;
@@ -961,29 +995,30 @@ function pagination(options) {
961
995
  const total = options.totalItems();
962
996
  return Math.max(1, Math.ceil(total / pageSizeValue));
963
997
  });
998
+ const currentPage = derived(() => Math.min(Math.max(1, page()), totalPages()));
964
999
  const startIndex = derived(() => {
965
- return (page() - 1) * pageSizeValue;
1000
+ return (currentPage() - 1) * pageSizeValue;
966
1001
  });
967
1002
  const endIndex = derived(() => {
968
- const end = page() * pageSizeValue;
1003
+ const end = currentPage() * pageSizeValue;
969
1004
  const total = options.totalItems();
970
1005
  return Math.min(end, total);
971
1006
  });
972
1007
  function next() {
973
- if (page() < totalPages()) {
974
- setPage((p) => p + 1);
1008
+ if (currentPage() < totalPages()) {
1009
+ setPage(currentPage() + 1);
975
1010
  }
976
1011
  }
977
1012
  function prev() {
978
- if (page() > 1) {
979
- setPage((p) => p - 1);
1013
+ if (currentPage() > 1) {
1014
+ setPage(currentPage() - 1);
980
1015
  }
981
1016
  }
982
1017
  function goTo(target) {
983
1018
  const clamped = Math.max(1, Math.min(target, totalPages()));
984
1019
  setPage(clamped);
985
1020
  }
986
- return { page, pageSize, totalPages, next, prev, goTo, startIndex, endIndex };
1021
+ return { page: currentPage, pageSize, totalPages, next, prev, goTo, startIndex, endIndex };
987
1022
  }
988
1023
 
989
1024
  // src/ui/eventBus.ts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  signal
3
- } from "./chunk-JCQG2I2G.js";
3
+ } from "./chunk-IWFE4AHO.js";
4
4
 
5
5
  // src/core/rendering/context.ts
6
6
  function context(defaultValue) {
package/dist/data.cjs CHANGED
@@ -482,7 +482,7 @@ function forEachSubscriber(signal2, visit) {
482
482
 
483
483
  // src/reactivity/track.ts
484
484
  var _isDev3 = isDev();
485
- var _runtimeVersion = true ? "3.3.2" : "dev";
485
+ var _runtimeVersion = true ? "3.3.3" : "dev";
486
486
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
487
487
  function resolveReactiveApi() {
488
488
  const g = globalThis;
@@ -904,6 +904,12 @@ function signal(initial, options) {
904
904
  return [get, set];
905
905
  }
906
906
 
907
+ // src/utils/globalSingleton.ts
908
+ function globalSingleton(key, create) {
909
+ const g = globalThis;
910
+ return g[key] ?? (g[key] = create());
911
+ }
912
+
907
913
  // src/data/retry.ts
908
914
  function calculateDelay(attempt, strategy, baseDelay, maxDelay, jitter) {
909
915
  let delay;
@@ -965,7 +971,7 @@ async function withRetry(fn, options, onRetry, signal2) {
965
971
  }
966
972
 
967
973
  // src/data/query.ts
968
- var globalQueryCache = /* @__PURE__ */ new Map();
974
+ var globalQueryCache = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.query.cache.v1"), () => /* @__PURE__ */ new Map());
969
975
  function getActiveQueryCache() {
970
976
  return getRequestScopedCache("query") ?? globalQueryCache;
971
977
  }
@@ -1987,6 +1993,10 @@ function socket(url, options) {
1987
1993
  }
1988
1994
  function connect() {
1989
1995
  if (disposed) return;
1996
+ if (typeof WebSocket === "undefined") {
1997
+ setStatus("closed");
1998
+ return;
1999
+ }
1990
2000
  const safeUrl = validateWsUrl(getUrl());
1991
2001
  if (safeUrl === null) {
1992
2002
  setStatus("closed");
@@ -2107,6 +2117,10 @@ function stream(url, options) {
2107
2117
  let attempts = 0;
2108
2118
  function connect() {
2109
2119
  if (disposed) return;
2120
+ if (typeof EventSource === "undefined") {
2121
+ setStatus("closed");
2122
+ return;
2123
+ }
2110
2124
  const safeUrl = validateSseUrl(url);
2111
2125
  if (safeUrl === null) {
2112
2126
  setStatus("closed");
package/dist/data.js CHANGED
@@ -20,14 +20,15 @@ import {
20
20
  syncAdapter,
21
21
  throttle,
22
22
  withRetry
23
- } from "./chunk-YUBEOWII.js";
24
- import "./chunk-5VH3GIDX.js";
25
- import "./chunk-G6N3LMO2.js";
23
+ } from "./chunk-5Y34FWED.js";
24
+ import "./chunk-7ZHH77QA.js";
25
+ import "./chunk-ZXCZWMZT.js";
26
+ import "./chunk-F3HO2MP7.js";
26
27
  import "./chunk-L3GAGWCC.js";
27
- import "./chunk-N5TQVEKE.js";
28
+ import "./chunk-23VT3KZB.js";
28
29
  import "./chunk-S3NFJO6L.js";
29
- import "./chunk-JCQG2I2G.js";
30
- import "./chunk-4NJEAPLI.js";
30
+ import "./chunk-IWFE4AHO.js";
31
+ import "./chunk-UOMYIAG6.js";
31
32
  import "./chunk-COY6PUD2.js";
32
33
  export {
33
34
  __resetQueryCache,