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,6 +1,9 @@
1
+ import {
2
+ registerDisposer
3
+ } from "./chunk-5VGSK6D2.js";
1
4
  import {
2
5
  signal
3
- } from "./chunk-JCQG2I2G.js";
6
+ } from "./chunk-IWFE4AHO.js";
4
7
 
5
8
  // src/ui/transition.ts
6
9
  function transition(element, options = {}) {
@@ -74,6 +77,7 @@ function transition(element, options = {}) {
74
77
  }
75
78
  });
76
79
  }
80
+ registerDisposer(element, cancelPending);
77
81
  return { enter, leave };
78
82
  }
79
83
  function spring(element, keyframes, options = {}) {
@@ -89,8 +93,29 @@ function spring(element, keyframes, options = {}) {
89
93
  });
90
94
  }
91
95
 
96
+ // src/ui/reducedMotion.ts
97
+ function prefersReducedMotion() {
98
+ return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
99
+ }
100
+ function reducedMotion() {
101
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
102
+ const [reduced2] = signal(false);
103
+ return { reduced: reduced2, dispose: () => {
104
+ } };
105
+ }
106
+ const mql = window.matchMedia("(prefers-reduced-motion: reduce)");
107
+ const [reduced, setReduced] = signal(mql.matches);
108
+ const handler = (event) => {
109
+ setReduced(event.matches);
110
+ };
111
+ mql.addEventListener("change", handler);
112
+ function dispose() {
113
+ mql.removeEventListener("change", handler);
114
+ }
115
+ return { reduced, dispose };
116
+ }
117
+
92
118
  // src/ui/animationPresets.ts
93
- var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
94
119
  function createPreset(keyframes, defaults, overrides) {
95
120
  const opts = {
96
121
  ...defaults,
@@ -259,6 +284,7 @@ function TransitionGroup(options) {
259
284
  if (options.leave) {
260
285
  await options.leave(el);
261
286
  }
287
+ positions.delete(el);
262
288
  setElements((prev) => prev.filter((e) => e !== el));
263
289
  }
264
290
  function track(newElements) {
@@ -325,27 +351,7 @@ function viewTransition(callback) {
325
351
  return { start, isTransitioning };
326
352
  }
327
353
 
328
- // src/ui/reducedMotion.ts
329
- function reducedMotion() {
330
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
331
- const [reduced2] = signal(false);
332
- return { reduced: reduced2, dispose: () => {
333
- } };
334
- }
335
- const mql = window.matchMedia("(prefers-reduced-motion: reduce)");
336
- const [reduced, setReduced] = signal(mql.matches);
337
- const handler = (event) => {
338
- setReduced(event.matches);
339
- };
340
- mql.addEventListener("change", handler);
341
- function dispose() {
342
- mql.removeEventListener("change", handler);
343
- }
344
- return { reduced, dispose };
345
- }
346
-
347
354
  // src/ui/springSignal.ts
348
- var prefersReducedMotion2 = () => typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
349
355
  function springSignal(initial, options) {
350
356
  const stiffness = options?.stiffness ?? 0.15;
351
357
  const damping = options?.damping ?? 0.8;
@@ -381,7 +387,7 @@ function springSignal(initial, options) {
381
387
  }
382
388
  function set(newTarget) {
383
389
  target = newTarget;
384
- if (prefersReducedMotion2()) {
390
+ if (prefersReducedMotion()) {
385
391
  current = newTarget;
386
392
  velocity = 0;
387
393
  if (rafId !== null) {
@@ -410,6 +416,8 @@ function springSignal(initial, options) {
410
416
  export {
411
417
  transition,
412
418
  spring,
419
+ prefersReducedMotion,
420
+ reducedMotion,
413
421
  fadeIn,
414
422
  fadeOut,
415
423
  slideIn,
@@ -426,6 +434,5 @@ export {
426
434
  sequence,
427
435
  TransitionGroup,
428
436
  viewTransition,
429
- reducedMotion,
430
437
  springSignal
431
438
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SVG_NS,
3
3
  tagFactory
4
- } from "./chunk-ZEUP4TUD.js";
4
+ } from "./chunk-RZKGMHH4.js";
5
5
 
6
6
  // src/core/rendering/html.ts
7
7
  var html = tagFactory("html");
@@ -1,22 +1,25 @@
1
+ import {
2
+ globalSingleton
3
+ } from "./chunk-7ZHH77QA.js";
1
4
  import {
2
5
  context
3
- } from "./chunk-5VH3GIDX.js";
6
+ } from "./chunk-ZXCZWMZT.js";
4
7
  import {
5
8
  derived
6
- } from "./chunk-G6N3LMO2.js";
9
+ } from "./chunk-F3HO2MP7.js";
7
10
  import {
8
11
  sanitizeUrl
9
12
  } from "./chunk-L3GAGWCC.js";
10
13
  import {
11
14
  effect
12
- } from "./chunk-N5TQVEKE.js";
15
+ } from "./chunk-23VT3KZB.js";
13
16
  import {
14
17
  getRequestScopedCache
15
18
  } from "./chunk-S3NFJO6L.js";
16
19
  import {
17
20
  batch,
18
21
  signal
19
- } from "./chunk-JCQG2I2G.js";
22
+ } from "./chunk-IWFE4AHO.js";
20
23
 
21
24
  // src/data/retry.ts
22
25
  function calculateDelay(attempt, strategy, baseDelay, maxDelay, jitter) {
@@ -79,7 +82,7 @@ async function withRetry(fn, options, onRetry, signal2) {
79
82
  }
80
83
 
81
84
  // src/data/query.ts
82
- var globalQueryCache = /* @__PURE__ */ new Map();
85
+ var globalQueryCache = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.query.cache.v1"), () => /* @__PURE__ */ new Map());
83
86
  function getActiveQueryCache() {
84
87
  return getRequestScopedCache("query") ?? globalQueryCache;
85
88
  }
@@ -1070,6 +1073,10 @@ function socket(url, options) {
1070
1073
  }
1071
1074
  function connect() {
1072
1075
  if (disposed) return;
1076
+ if (typeof WebSocket === "undefined") {
1077
+ setStatus("closed");
1078
+ return;
1079
+ }
1073
1080
  const safeUrl = validateWsUrl(getUrl());
1074
1081
  if (safeUrl === null) {
1075
1082
  setStatus("closed");
@@ -1165,6 +1172,10 @@ function stream(url, options) {
1165
1172
  let attempts = 0;
1166
1173
  function connect() {
1167
1174
  if (disposed) return;
1175
+ if (typeof EventSource === "undefined") {
1176
+ setStatus("closed");
1177
+ return;
1178
+ }
1168
1179
  const safeUrl = validateSseUrl(url);
1169
1180
  if (safeUrl === null) {
1170
1181
  setStatus("closed");
@@ -0,0 +1,9 @@
1
+ // src/utils/globalSingleton.ts
2
+ function globalSingleton(key, create) {
3
+ const g = globalThis;
4
+ return g[key] ?? (g[key] = create());
5
+ }
6
+
7
+ export {
8
+ globalSingleton
9
+ };
@@ -3,7 +3,7 @@ import {
3
3
  recordDependency,
4
4
  retrack,
5
5
  track
6
- } from "./chunk-4NJEAPLI.js";
6
+ } from "./chunk-UOMYIAG6.js";
7
7
  import {
8
8
  devAssert
9
9
  } from "./chunk-COY6PUD2.js";
@@ -101,9 +101,7 @@ function lazyModule(loader) {
101
101
  return loadedFlag;
102
102
  },
103
103
  async get() {
104
- if (loadedFlag && cached !== void 0) {
105
- return cached;
106
- }
104
+ if (loadedFlag) return cached;
107
105
  cached = await loader();
108
106
  loadedFlag = true;
109
107
  return cached;
@@ -1,20 +1,23 @@
1
1
  import {
2
- dispose
3
- } from "./chunk-5VGSK6D2.js";
2
+ globalSingleton
3
+ } from "./chunk-7ZHH77QA.js";
4
4
  import {
5
5
  stripHtml
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
  forEachSubscriber,
15
18
  getSubscriberCount,
16
19
  getSubscriberDeps
17
- } from "./chunk-4NJEAPLI.js";
20
+ } from "./chunk-UOMYIAG6.js";
18
21
  import {
19
22
  isDev
20
23
  } from "./chunk-COY6PUD2.js";
@@ -147,10 +150,50 @@ function createGlobalHook() {
147
150
  listeners.set(event, set);
148
151
  }
149
152
  set.add(fn);
153
+ return () => {
154
+ set?.delete(fn);
155
+ };
150
156
  },
151
157
  off(event, fn) {
152
158
  listeners.get(event)?.delete(fn);
153
159
  },
160
+ getSignalNodes() {
161
+ const out = [];
162
+ for (const [, node] of nodes) {
163
+ let value = "";
164
+ try {
165
+ const ref = node.ref;
166
+ let raw;
167
+ if (node.type === "effect") {
168
+ raw = void 0;
169
+ } else if (node.type === "computed" && ref) {
170
+ raw = ref._v;
171
+ } else if (ref && "value" in ref) {
172
+ raw = ref.value;
173
+ }
174
+ if (raw === void 0) value = "undefined";
175
+ else if (raw === null) value = "null";
176
+ else if (typeof raw === "object") value = JSON.stringify(raw);
177
+ else value = String(raw);
178
+ } catch {
179
+ value = "?";
180
+ }
181
+ if (value.length > 200) value = `${value.slice(0, 200)}...`;
182
+ out.push({
183
+ id: String(node.id),
184
+ name: node.name || null,
185
+ kind: node.type === "computed" ? "derived" : node.type,
186
+ value,
187
+ // Edge identities aren't tracked by this registry (only a subscriber
188
+ // count, via node.ref.__sc) — left empty until the core exposes the
189
+ // dependency graph. The node inventory itself is real.
190
+ subscribers: [],
191
+ dependencies: [],
192
+ evalCount: 0
193
+ });
194
+ }
195
+ return out;
196
+ },
154
197
  emit(event, payload) {
155
198
  events.push({ event, payload, ts: Date.now() });
156
199
  if (events.length > 2e3) events.splice(0, events.length - 2e3);
@@ -176,34 +219,38 @@ function getOrCreateHook() {
176
219
  }
177
220
  return g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
178
221
  }
179
- var activeDevTools = null;
180
- var nextNodeId = 0;
181
- var inferNameArmed = false;
222
+ var _dt = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.devtools.state.v1"), () => ({
223
+ active: null,
224
+ nextNodeId: 0,
225
+ // Gate for inferName(): only `true` while devtools are initialized AND in dev
226
+ // mode — otherwise skip the Error-stack walk so prod hot paths don't allocate.
227
+ inferNameArmed: false
228
+ }));
182
229
  function getActiveDevTools() {
183
- return activeDevTools;
230
+ return _dt.active;
184
231
  }
185
232
  function initDevTools(config) {
186
233
  const maxEvents = config?.maxEvents ?? 1e3;
187
234
  const enabled = config?.enabled ?? isDev();
188
235
  const expose = config?.expose ?? isDev();
189
236
  if (!enabled) return createNoopApi();
190
- inferNameArmed = true;
237
+ _dt.inferNameArmed = true;
191
238
  const hook = getOrCreateHook();
192
- nextNodeId = 0;
239
+ _dt.nextNodeId = 0;
193
240
  const eventLog = [];
194
241
  hook.on("signal:create", (payload) => {
195
242
  const p = payload;
196
- nextNodeId++;
243
+ _dt.nextNodeId++;
197
244
  const name = inferName();
198
245
  const node = {
199
- id: nextNodeId,
246
+ id: _dt.nextNodeId,
200
247
  type: "signal",
201
248
  name,
202
249
  ref: p.signal,
203
250
  getter: p.getter,
204
251
  createdAt: Date.now()
205
252
  };
206
- hook.nodes.set(nextNodeId, node);
253
+ hook.nodes.set(_dt.nextNodeId, node);
207
254
  emit();
208
255
  });
209
256
  hook.on("signal:update", (payload) => {
@@ -223,17 +270,17 @@ function initDevTools(config) {
223
270
  });
224
271
  hook.on("computed:create", (payload) => {
225
272
  const p = payload;
226
- nextNodeId++;
273
+ _dt.nextNodeId++;
227
274
  const name = inferName();
228
275
  const node = {
229
- id: nextNodeId,
276
+ id: _dt.nextNodeId,
230
277
  type: "computed",
231
278
  name,
232
279
  ref: p.signal,
233
280
  getter: p.getter,
234
281
  createdAt: Date.now()
235
282
  };
236
- hook.nodes.set(nextNodeId, node);
283
+ hook.nodes.set(_dt.nextNodeId, node);
237
284
  emit();
238
285
  });
239
286
  hook.on("computed:update", (payload) => {
@@ -250,11 +297,11 @@ function initDevTools(config) {
250
297
  emit();
251
298
  });
252
299
  hook.on("effect:create", (payload) => {
253
- nextNodeId++;
300
+ _dt.nextNodeId++;
254
301
  const name = inferName();
255
302
  const p = payload;
256
- const node = { id: nextNodeId, type: "effect", name, ref: p.effectFn, createdAt: Date.now() };
257
- hook.nodes.set(nextNodeId, node);
303
+ const node = { id: _dt.nextNodeId, type: "effect", name, ref: p.effectFn, createdAt: Date.now() };
304
+ hook.nodes.set(_dt.nextNodeId, node);
258
305
  emit();
259
306
  });
260
307
  hook.on("effect:run", (payload) => {
@@ -411,8 +458,8 @@ function initDevTools(config) {
411
458
  hook.components.clear();
412
459
  hook.events.length = 0;
413
460
  isActive = false;
414
- inferNameArmed = false;
415
- activeDevTools = null;
461
+ _dt.inferNameArmed = false;
462
+ _dt.active = null;
416
463
  const g = globalThis;
417
464
  if (g.__SIBU__) {
418
465
  delete g.__SIBU__.devtools;
@@ -580,7 +627,7 @@ function initDevTools(config) {
580
627
  w.__SIBU_DEVTOOLS_VERSION__ = () => changeVersion;
581
628
  w.__SIBU_DEVTOOLS_DATA__ = buildData;
582
629
  }
583
- activeDevTools = api;
630
+ _dt.active = api;
584
631
  if (typeof document !== "undefined") {
585
632
  domObserver = new MutationObserver((mutations) => {
586
633
  let changed = false;
@@ -656,7 +703,7 @@ function initDevTools(config) {
656
703
  return api;
657
704
  }
658
705
  function inferName() {
659
- if (!inferNameArmed || !isDev()) return "anonymous";
706
+ if (!_dt.inferNameArmed || !isDev()) return "anonymous";
660
707
  try {
661
708
  const stack = new Error().stack || "";
662
709
  for (const line of stack.split("\n")) {
@@ -737,7 +784,7 @@ function devState(name, initial) {
737
784
  const oldValue = get();
738
785
  set(next);
739
786
  const newValue = get();
740
- const dt = activeDevTools;
787
+ const dt = _dt.active;
741
788
  if (dt?.isEnabled() && !Object.is(oldValue, newValue)) {
742
789
  dt.record({ type: "state-change", component, key, oldValue, newValue, timestamp: Date.now() });
743
790
  }
@@ -1,22 +1,24 @@
1
1
  import {
2
2
  watch
3
- } from "./chunk-RLTFJYDN.js";
3
+ } from "./chunk-TBDTU7UO.js";
4
+ import {
5
+ createId
6
+ } from "./chunk-CCSJMTRN.js";
4
7
  import {
5
8
  derived
6
- } from "./chunk-G6N3LMO2.js";
9
+ } from "./chunk-F3HO2MP7.js";
7
10
  import {
8
11
  stripHtml
9
12
  } from "./chunk-L3GAGWCC.js";
10
13
  import {
11
14
  effect
12
- } from "./chunk-N5TQVEKE.js";
15
+ } from "./chunk-23VT3KZB.js";
13
16
  import {
14
17
  batch,
15
18
  signal
16
- } from "./chunk-JCQG2I2G.js";
19
+ } from "./chunk-IWFE4AHO.js";
17
20
 
18
21
  // src/widgets/Combobox.ts
19
- var comboboxIdCounter = 0;
20
22
  var boundComboboxes = /* @__PURE__ */ new WeakMap();
21
23
  function combobox(options) {
22
24
  const { items, filterFn, itemToString } = options;
@@ -77,7 +79,13 @@ function combobox(options) {
77
79
  function bind(els) {
78
80
  const existing = boundComboboxes.get(els.input);
79
81
  if (existing) return existing;
80
- const listboxId = `sibu-combobox-listbox-${++comboboxIdCounter}`;
82
+ const prevListboxId = els.listbox.id;
83
+ const prevListboxRole = els.listbox.getAttribute("role");
84
+ const prevListboxHidden = els.listbox.hidden;
85
+ const prevInputRole = els.input.getAttribute("role");
86
+ const prevInputAutocomplete = els.input.getAttribute("aria-autocomplete");
87
+ const prevInputControls = els.input.getAttribute("aria-controls");
88
+ const listboxId = createId("sibu-combobox-listbox");
81
89
  els.listbox.id = listboxId;
82
90
  els.listbox.setAttribute("role", "listbox");
83
91
  els.input.setAttribute("role", "combobox");
@@ -141,10 +149,14 @@ function combobox(options) {
141
149
  if (document.activeElement !== els.input) close();
142
150
  }, 100);
143
151
  };
152
+ const onListboxPointerDown = (e) => {
153
+ e.preventDefault();
154
+ };
144
155
  els.input.addEventListener("input", onInput);
145
156
  els.input.addEventListener("keydown", onKey);
146
157
  els.input.addEventListener("focus", onFocus);
147
158
  els.input.addEventListener("blur", onBlur);
159
+ els.listbox.addEventListener("mousedown", onListboxPointerDown);
148
160
  const teardown = () => {
149
161
  boundComboboxes.delete(els.input);
150
162
  fxTeardown();
@@ -152,10 +164,24 @@ function combobox(options) {
152
164
  els.input.removeEventListener("keydown", onKey);
153
165
  els.input.removeEventListener("focus", onFocus);
154
166
  els.input.removeEventListener("blur", onBlur);
167
+ els.listbox.removeEventListener("mousedown", onListboxPointerDown);
155
168
  if (blurTimer !== null) {
156
169
  clearTimeout(blurTimer);
157
170
  blurTimer = null;
158
171
  }
172
+ if (prevListboxId === "") els.listbox.removeAttribute("id");
173
+ else els.listbox.id = prevListboxId;
174
+ if (prevListboxRole === null) els.listbox.removeAttribute("role");
175
+ else els.listbox.setAttribute("role", prevListboxRole);
176
+ els.listbox.hidden = prevListboxHidden;
177
+ if (prevInputRole === null) els.input.removeAttribute("role");
178
+ else els.input.setAttribute("role", prevInputRole);
179
+ if (prevInputAutocomplete === null) els.input.removeAttribute("aria-autocomplete");
180
+ else els.input.setAttribute("aria-autocomplete", prevInputAutocomplete);
181
+ if (prevInputControls === null) els.input.removeAttribute("aria-controls");
182
+ else els.input.setAttribute("aria-controls", prevInputControls);
183
+ els.input.removeAttribute("aria-expanded");
184
+ els.input.removeAttribute("aria-activedescendant");
159
185
  };
160
186
  boundComboboxes.set(els.input, teardown);
161
187
  return teardown;
@@ -491,7 +517,6 @@ function accordion(options) {
491
517
  }
492
518
 
493
519
  // src/widgets/Popover.ts
494
- var popoverIdCounter = 0;
495
520
  var boundPopovers = /* @__PURE__ */ new WeakMap();
496
521
  function popover() {
497
522
  const [isOpen, setIsOpen] = signal(false);
@@ -507,7 +532,7 @@ function popover() {
507
532
  function bind(els) {
508
533
  const existing = boundPopovers.get(els.trigger);
509
534
  if (existing) return existing;
510
- const id = `sibu-popover-${++popoverIdCounter}`;
535
+ const id = createId("sibu-popover");
511
536
  const prevPopoverRole = els.popover.getAttribute("role");
512
537
  const prevPopoverId = els.popover.id;
513
538
  const prevLabelledBy = els.popover.getAttribute("aria-labelledby");
@@ -581,7 +606,6 @@ function popover() {
581
606
  }
582
607
 
583
608
  // src/widgets/Select.ts
584
- var selectIdCounter = 0;
585
609
  var boundSelects = /* @__PURE__ */ new WeakMap();
586
610
  function select(options) {
587
611
  const { items, multiple = false, itemToString, isDisabled } = options;
@@ -662,7 +686,11 @@ function select(options) {
662
686
  function bind(els) {
663
687
  const existing = boundSelects.get(els.listbox);
664
688
  if (existing) return existing;
665
- const listboxId = `sibu-select-${++selectIdCounter}`;
689
+ const prevId = els.listbox.id;
690
+ const prevRole = els.listbox.getAttribute("role");
691
+ const prevMultiselectable = els.listbox.getAttribute("aria-multiselectable");
692
+ const prevTabIndex = els.listbox.getAttribute("tabindex");
693
+ const listboxId = createId("sibu-select");
666
694
  els.listbox.id = listboxId;
667
695
  els.listbox.setAttribute("role", "listbox");
668
696
  els.listbox.setAttribute("aria-multiselectable", multiple ? "true" : "false");
@@ -722,6 +750,15 @@ function select(options) {
722
750
  fxTeardown();
723
751
  els.listbox.removeEventListener("keydown", onKey);
724
752
  if (typeTimer !== null) clearTimeout(typeTimer);
753
+ if (prevId === "") els.listbox.removeAttribute("id");
754
+ else els.listbox.id = prevId;
755
+ if (prevRole === null) els.listbox.removeAttribute("role");
756
+ else els.listbox.setAttribute("role", prevRole);
757
+ if (prevMultiselectable === null) els.listbox.removeAttribute("aria-multiselectable");
758
+ else els.listbox.setAttribute("aria-multiselectable", prevMultiselectable);
759
+ if (prevTabIndex === null) els.listbox.removeAttribute("tabindex");
760
+ else els.listbox.setAttribute("tabindex", prevTabIndex);
761
+ els.listbox.removeAttribute("aria-activedescendant");
725
762
  };
726
763
  boundSelects.set(els.listbox, teardown);
727
764
  return teardown;
@@ -746,7 +783,6 @@ function select(options) {
746
783
  }
747
784
 
748
785
  // src/widgets/Tooltip.ts
749
- var tooltipIdCounter = 0;
750
786
  var boundTriggers = /* @__PURE__ */ new WeakMap();
751
787
  function tooltip(options) {
752
788
  const delay = options?.delay ?? 0;
@@ -791,7 +827,7 @@ function tooltip(options) {
791
827
  function bind(els) {
792
828
  const existing = boundTriggers.get(els.trigger);
793
829
  if (existing) return existing;
794
- const id = `sibu-tooltip-${++tooltipIdCounter}`;
830
+ const id = createId("sibu-tooltip");
795
831
  els.tooltip.setAttribute("role", "tooltip");
796
832
  els.tooltip.id = id;
797
833
  const prevDescribedBy = els.trigger.getAttribute("aria-describedby");
@@ -851,7 +887,6 @@ function tooltip(options) {
851
887
  }
852
888
 
853
889
  // src/widgets/FileUpload.ts
854
- var fileUploadIdCounter = 0;
855
890
  var boundFileUploads = /* @__PURE__ */ new WeakMap();
856
891
  function fileUpload(options) {
857
892
  const accept = options?.accept;
@@ -923,7 +958,7 @@ function fileUpload(options) {
923
958
  function bind(els) {
924
959
  const existing = boundFileUploads.get(els.input);
925
960
  if (existing) return existing;
926
- const id = `sibu-fileupload-${++fileUploadIdCounter}`;
961
+ const id = createId("sibu-fileupload");
927
962
  const restore = [];
928
963
  if (accept) els.input.accept = accept;
929
964
  els.input.multiple = multiple;
@@ -1034,7 +1069,7 @@ function fileUpload(options) {
1034
1069
  }
1035
1070
 
1036
1071
  // src/widgets/contentEditable.ts
1037
- function contentEditable() {
1072
+ function contentEditable(element) {
1038
1073
  const [content, setContentInternal] = signal("");
1039
1074
  const [isFocused, setFocused] = signal(false);
1040
1075
  function setContent(input) {
@@ -1058,6 +1093,7 @@ function contentEditable() {
1058
1093
  const selection = window.getSelection();
1059
1094
  if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return;
1060
1095
  const range = selection.getRangeAt(0);
1096
+ if (element && !element.contains(range.commonAncestorContainer)) return;
1061
1097
  const ancestor = range.commonAncestorContainer;
1062
1098
  const existingWrap = findAncestorByTag(
1063
1099
  ancestor instanceof HTMLElement ? ancestor : ancestor.parentElement,
@@ -1237,12 +1273,18 @@ function datePicker(options) {
1237
1273
  function bind(els) {
1238
1274
  const existing = boundDatePickers.get(els.grid);
1239
1275
  if (existing) return existing;
1276
+ const prevGridRole = els.grid.getAttribute("role");
1277
+ const prevGridTabIndex = els.grid.getAttribute("tabindex");
1278
+ const prevGridLabel = els.grid.getAttribute("aria-label");
1240
1279
  els.grid.setAttribute("role", "grid");
1241
1280
  if (els.grid.tabIndex < 0) els.grid.tabIndex = 0;
1281
+ let pendingFocus = false;
1242
1282
  const fxTeardown = effect(() => {
1243
1283
  const sel = selectedDate();
1244
1284
  const view = viewDate();
1245
1285
  const days = daysInMonth();
1286
+ els.grid.setAttribute("aria-label", view.toLocaleDateString(void 0, { month: "long", year: "numeric" }));
1287
+ let viewCell = null;
1246
1288
  for (const d of days) {
1247
1289
  const cell = els.cell(d.date);
1248
1290
  if (!cell) continue;
@@ -1250,7 +1292,13 @@ function datePicker(options) {
1250
1292
  cell.setAttribute("aria-selected", sel && isSameCalendarDay(sel, d.date) ? "true" : "false");
1251
1293
  if (d.isDisabled) cell.setAttribute("aria-disabled", "true");
1252
1294
  else cell.removeAttribute("aria-disabled");
1253
- cell.tabIndex = isSameCalendarDay(view, d.date) ? 0 : -1;
1295
+ const isView = isSameCalendarDay(view, d.date);
1296
+ cell.tabIndex = isView ? 0 : -1;
1297
+ if (isView) viewCell = cell;
1298
+ }
1299
+ if (pendingFocus && viewCell && typeof viewCell.focus === "function") {
1300
+ pendingFocus = false;
1301
+ viewCell.focus();
1254
1302
  }
1255
1303
  });
1256
1304
  function isSameCalendarDay(a, b) {
@@ -1260,6 +1308,9 @@ function datePicker(options) {
1260
1308
  setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth(), prev.getDate() + delta));
1261
1309
  }
1262
1310
  const onKey = (e) => {
1311
+ if (e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Home" || e.key === "End" || e.key === "PageUp" || e.key === "PageDown") {
1312
+ pendingFocus = true;
1313
+ }
1263
1314
  switch (e.key) {
1264
1315
  case "ArrowLeft":
1265
1316
  e.preventDefault();
@@ -1308,6 +1359,12 @@ function datePicker(options) {
1308
1359
  boundDatePickers.delete(els.grid);
1309
1360
  fxTeardown();
1310
1361
  els.grid.removeEventListener("keydown", onKey);
1362
+ if (prevGridRole === null) els.grid.removeAttribute("role");
1363
+ else els.grid.setAttribute("role", prevGridRole);
1364
+ if (prevGridTabIndex === null) els.grid.removeAttribute("tabindex");
1365
+ else els.grid.setAttribute("tabindex", prevGridTabIndex);
1366
+ if (prevGridLabel === null) els.grid.removeAttribute("aria-label");
1367
+ else els.grid.setAttribute("aria-label", prevGridLabel);
1311
1368
  };
1312
1369
  boundDatePickers.set(els.grid, teardown);
1313
1370
  return teardown;
@@ -3,7 +3,7 @@ import {
3
3
  notifySubscribers,
4
4
  queueSignalNotification,
5
5
  recordDependency
6
- } from "./chunk-4NJEAPLI.js";
6
+ } from "./chunk-UOMYIAG6.js";
7
7
  import {
8
8
  isDev
9
9
  } from "./chunk-COY6PUD2.js";