sibujs 4.5.0 → 4.6.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 (109) hide show
  1. package/dist/browser.cjs +309 -129
  2. package/dist/browser.d.cts +46 -14
  3. package/dist/browser.d.ts +46 -14
  4. package/dist/browser.js +8 -6
  5. package/dist/build.cjs +184 -72
  6. package/dist/build.js +15 -16
  7. package/dist/cdn.dev.global.js +12 -12
  8. package/dist/cdn.full.dev.global.js +11 -11
  9. package/dist/cdn.full.global.js +10 -10
  10. package/dist/cdn.global.js +12 -12
  11. package/dist/{chunk-IXKSNWV5.js → chunk-2INLLLMZ.js} +1 -1
  12. package/dist/chunk-3ISI6ACU.js +44 -0
  13. package/dist/{chunk-ONOHFDLG.js → chunk-47M47FOM.js} +3 -3
  14. package/dist/chunk-5HZXGZ6T.js +24 -0
  15. package/dist/{chunk-KKLW7YWL.js → chunk-5MT6SJ3P.js} +275 -144
  16. package/dist/{chunk-UGRX3S57.js → chunk-5Q4R7HCL.js} +12 -3
  17. package/dist/{chunk-S373NSMK.js → chunk-7GQCWFOE.js} +150 -59
  18. package/dist/{chunk-FTIR4QW2.js → chunk-7NCARGJW.js} +6 -8
  19. package/dist/{chunk-5DXA2J44.js → chunk-7XHATCIH.js} +5 -2
  20. package/dist/{chunk-VZKNK2V7.js → chunk-AIF3Z2T7.js} +296 -38
  21. package/dist/{chunk-4PMLNECI.js → chunk-BAAG6ZTI.js} +98 -29
  22. package/dist/{chunk-XZZOBQAY.js → chunk-D33YTSX5.js} +2 -2
  23. package/dist/{chunk-TBYTO6BS.js → chunk-DKGBBKOF.js} +136 -80
  24. package/dist/{chunk-NIOYEGBQ.js → chunk-HURREPU2.js} +27 -13
  25. package/dist/{chunk-GW3SCCZG.js → chunk-HYXDKS4N.js} +153 -110
  26. package/dist/chunk-J6FW5TV6.js +233 -0
  27. package/dist/{chunk-PCT43HW3.js → chunk-JSXPZCET.js} +1 -1
  28. package/dist/chunk-NYNYSPK7.js +318 -0
  29. package/dist/{chunk-RJE2BNI4.js → chunk-ORMZXBKQ.js} +108 -45
  30. package/dist/{chunk-OMJJM3KM.js → chunk-OXUY2A6L.js} +287 -130
  31. package/dist/{chunk-3JZ4L5TJ.js → chunk-PK6FK2G2.js} +181 -66
  32. package/dist/{chunk-RBTPLM32.js → chunk-QE4TTDU3.js} +2 -2
  33. package/dist/{chunk-2DCGACUU.js → chunk-SXXVZMKZ.js} +251 -66
  34. package/dist/{chunk-R25EFXXC.js → chunk-TUCPL2HB.js} +3 -3
  35. package/dist/{chunk-7LN645I6.js → chunk-UZQ6ALFS.js} +3 -3
  36. package/dist/{chunk-KEISJXBU.js → chunk-VVWPJ543.js} +6 -8
  37. package/dist/{chunk-RIXRAYIU.js → chunk-XC4MEKGA.js} +3 -3
  38. package/dist/{chunk-B3WHI2QA.js → chunk-XRRZKZYX.js} +55 -31
  39. package/dist/{contracts-DBdg9J_a.d.cts → contracts-DRIuclVT.d.cts} +10 -2
  40. package/dist/{contracts-DBdg9J_a.d.ts → contracts-DRIuclVT.d.ts} +10 -2
  41. package/dist/{customElement-OB9CIsc5.d.cts → customElement-MmInOW1U.d.cts} +21 -0
  42. package/dist/{customElement-OB9CIsc5.d.ts → customElement-MmInOW1U.d.ts} +21 -0
  43. package/dist/data.cjs +213 -117
  44. package/dist/data.d.cts +47 -9
  45. package/dist/data.d.ts +47 -9
  46. package/dist/data.js +12 -9
  47. package/dist/devtools.cjs +81 -57
  48. package/dist/devtools.js +7 -8
  49. package/dist/dispose-GEIG2KOF.js +28 -0
  50. package/dist/ecosystem.cjs +309 -104
  51. package/dist/ecosystem.d.cts +19 -3
  52. package/dist/ecosystem.d.ts +19 -3
  53. package/dist/ecosystem.js +12 -12
  54. package/dist/extras.cjs +2133 -863
  55. package/dist/extras.d.cts +10 -9
  56. package/dist/extras.d.ts +10 -9
  57. package/dist/extras.js +39 -28
  58. package/dist/index.cjs +184 -72
  59. package/dist/index.d.cts +22 -5
  60. package/dist/index.d.ts +22 -5
  61. package/dist/index.js +24 -27
  62. package/dist/motion.cjs +107 -41
  63. package/dist/motion.js +5 -5
  64. package/dist/patterns.cjs +317 -39
  65. package/dist/patterns.d.cts +27 -9
  66. package/dist/patterns.d.ts +27 -9
  67. package/dist/patterns.js +8 -8
  68. package/dist/performance.cjs +308 -216
  69. package/dist/performance.d.cts +2 -2
  70. package/dist/performance.d.ts +2 -2
  71. package/dist/performance.js +8 -9
  72. package/dist/plugin-DVgSnTfK.d.cts +112 -0
  73. package/dist/plugin-DVgSnTfK.d.ts +112 -0
  74. package/dist/plugins.cjs +549 -202
  75. package/dist/plugins.d.cts +3 -3
  76. package/dist/plugins.d.ts +3 -3
  77. package/dist/plugins.js +35 -23
  78. package/dist/signal-EotCj4hS.d.cts +110 -0
  79. package/dist/signal-EotCj4hS.d.ts +110 -0
  80. package/dist/{ssr-BiPRdZ6n.d.cts → ssr-Bli9XRW5.d.cts} +5 -0
  81. package/dist/{ssr-BiPRdZ6n.d.ts → ssr-Bli9XRW5.d.ts} +5 -0
  82. package/dist/{ssr-Y7XOEPEN.js → ssr-XOTUASDO.js} +4 -5
  83. package/dist/ssr.cjs +176 -72
  84. package/dist/ssr.d.cts +9 -3
  85. package/dist/ssr.d.ts +9 -3
  86. package/dist/ssr.js +11 -12
  87. package/dist/{startup-BMpaiMhP.d.ts → startup-BLfSeL15.d.cts} +73 -22
  88. package/dist/{startup-BMpaiMhP.d.cts → startup-BLfSeL15.d.ts} +73 -22
  89. package/dist/{tagFactory-DVoDpHye.d.ts → tagFactory-DFstCLQV.d.cts} +2 -100
  90. package/dist/{tagFactory-DVoDpHye.d.cts → tagFactory-DkaNVUNV.d.ts} +2 -100
  91. package/dist/testing.cjs +2484 -2185
  92. package/dist/testing.d.cts +56 -5
  93. package/dist/testing.d.ts +56 -5
  94. package/dist/testing.js +580 -307
  95. package/dist/ui.cjs +707 -317
  96. package/dist/ui.d.cts +40 -7
  97. package/dist/ui.d.ts +40 -7
  98. package/dist/ui.js +151 -56
  99. package/dist/widgets.cjs +246 -278
  100. package/dist/widgets.js +9 -10
  101. package/package.json +1 -1
  102. package/dist/chunk-2WLZ6757.js +0 -149
  103. package/dist/chunk-CCSJMTRN.js +0 -15
  104. package/dist/chunk-QKRPLZ2V.js +0 -108
  105. package/dist/chunk-VUF4ALSW.js +0 -60
  106. package/dist/chunk-WWV3SJ3L.js +0 -131
  107. package/dist/dispose-46BOMMQJ.js +0 -19
  108. package/dist/plugin-D30wlGW5.d.cts +0 -71
  109. package/dist/plugin-D30wlGW5.d.ts +0 -71
package/dist/ui.d.cts CHANGED
@@ -1,7 +1,8 @@
1
- export { A as AttributeSource, a as AttributeValue, B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, b as FocusTrap, c as FormConfig, d as FormField, e as FormReturn, I as IntersectionResult, M as MaskOptions, P as PaginationResult, T as Toast, f as ToastInstance, V as ValidatorFn, g as VirtualList, h as VirtualListProps, _ as __resetDialogStack, i as announce, j as aria, k as bindAttrs, l as bindBoolAttr, m as bindData, n as bindField, o as creditCardMask, p as custom, q as dateMask, r as defineElement, s as dialog, t as email, u as eventBus, v as focus, w as form, x as hotkey, y as infiniteScroll, z as inputMask, D as intersection, E as lazyLoad, G as matchesPattern, H as max, J as maxLength, K as min, L as minLength, N as pagination, O as phoneMask, Q as removeScopedStyle, R as required, S as scopedStyle, U as ssnMask, W as svgElement, X as timeMask, Y as toast, Z as withScopedStyle, $ as zipMask } from './customElement-OB9CIsc5.cjs';
2
- export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-DBdg9J_a.cjs';
1
+ export { A as AttributeSource, a as AttributeValue, B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, b as FocusTrap, c as FormConfig, d as FormField, e as FormReturn, I as IntersectionResult, M as MaskOptions, P as PaginationResult, T as Toast, f as ToastInstance, V as ValidatorFn, g as VirtualList, h as VirtualListProps, _ as __resetDialogStack, i as announce, j as aria, k as bindAttrs, l as bindBoolAttr, m as bindData, n as bindField, o as creditCardMask, p as custom, q as dateMask, r as defineElement, s as dialog, t as email, u as eventBus, v as focus, w as form, x as hotkey, y as infiniteScroll, z as inputMask, D as intersection, E as lazyLoad, G as matchesPattern, H as max, J as maxLength, K as min, L as minLength, N as pagination, O as phoneMask, Q as removeScopedStyle, R as required, S as scopedStyle, U as ssnMask, W as svgElement, X as timeMask, Y as toast, Z as withScopedStyle, $ as zipMask } from './customElement-MmInOW1U.cjs';
2
+ export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, W as WithDefaultsProps, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-DRIuclVT.cjs';
3
3
 
4
- interface FormActionHandle<TArgs extends unknown[], TResult> {
4
+ /** The parts of a form-action handle available for every action signature. */
5
+ interface FormActionState<TArgs extends unknown[], TResult> {
5
6
  /** Invoke the action. Rejections become `error()`, resolutions `result()`. */
6
7
  run: (...args: TArgs) => Promise<void>;
7
8
  /** True while the underlying promise is unresolved. */
@@ -12,13 +13,26 @@ interface FormActionHandle<TArgs extends unknown[], TResult> {
12
13
  result: () => TResult | null;
13
14
  /** Clear result and error without affecting an in-flight call. */
14
15
  reset: () => void;
16
+ }
17
+ /** The submit-handler part of a form-action handle. */
18
+ interface FormActionSubmit {
15
19
  /**
16
20
  * A ready-to-attach submit handler for `<form>` elements. Calls
17
21
  * `e.preventDefault()`, builds a `FormData`, and passes it to the
18
- * underlying action. Only available when `TArgs = [FormData]`.
22
+ * underlying action as its only argument.
19
23
  */
20
24
  onSubmit: (e: Event) => void;
21
25
  }
26
+ /**
27
+ * Handle returned by {@link formAction}.
28
+ *
29
+ * `onSubmit` calls the action with exactly one `FormData`, so it is part of the
30
+ * type only when that call is valid for the action — `(data: FormData) => …`
31
+ * or `(data?: FormData) => …`. For any other signature (numeric, zero- or
32
+ * multi-argument) it is omitted rather than silently handing the action a
33
+ * `FormData` it does not expect.
34
+ */
35
+ type FormActionHandle<TArgs extends unknown[], TResult> = FormActionState<TArgs, TResult> & ([FormData] extends TArgs ? FormActionSubmit : Record<never, never>);
22
36
  /**
23
37
  * Wrap an async function into a reactive form-action handle.
24
38
  *
@@ -78,10 +92,29 @@ interface ListboxOptions {
78
92
  interface ListboxHandle {
79
93
  /** Reactive value: the currently-active (highlighted) option value. */
80
94
  activeValue: () => string | null;
81
- /** Reactive value: the currently-selected option value (single-select) or CSV (multiple). */
95
+ /**
96
+ * Reactive value: the selected option values, in selection order. Holds at
97
+ * most one value in single-select mode. Every `data-value` string — including
98
+ * ones containing commas and the empty string — is represented exactly.
99
+ */
100
+ selectedValues: () => readonly string[];
101
+ /**
102
+ * Reactive value: the selected option value (single-select), or the selected
103
+ * values joined with `","` (multiple).
104
+ *
105
+ * @deprecated In multiple mode the CSV view is lossy — a value containing a
106
+ * comma cannot be told apart from two values. Use {@link selectedValues}.
107
+ */
82
108
  selectedValue: () => string | null;
83
109
  /** Stable id that can be used as `aria-activedescendant` on the trigger. */
84
110
  activeDescendantId: () => string | null;
111
+ /**
112
+ * Reconcile options added or removed since the last change: new options get a
113
+ * stable id and `aria-selected`, and a removed active option stops being the
114
+ * active descendant. Happens automatically (on DOM mutation and before every
115
+ * interaction); call it to reconcile synchronously.
116
+ */
117
+ refresh: () => void;
85
118
  /** Cleanup: removes listeners. */
86
119
  dispose: () => void;
87
120
  }
@@ -185,7 +218,7 @@ declare function lazyEffect(element: HTMLElement, effectFn: () => void, options?
185
218
  interface IntervalHandle {
186
219
  /** Stop the interval. Safe to call multiple times. */
187
220
  stop: () => void;
188
- /** Pause (preserving remaining ticks until `resume()`). */
221
+ /** Pause, preserving the time remaining until the next tick for `resume()`. */
189
222
  pause: () => void;
190
223
  /** Resume a paused interval. */
191
224
  resume: () => void;
@@ -258,4 +291,4 @@ interface ScrollLockHandle {
258
291
  */
259
292
  declare function scrollLock(): ScrollLockHandle;
260
293
 
261
- export { type DialogAriaHandle, type DialogAriaOptions, type FocusManagerHandle, type FocusManagerOptions, type FormActionHandle, type IntervalHandle, type ListboxHandle, type ListboxOptions, type ScrollLockHandle, type TimeoutHandle, createDialogAria, createFocusManager, createListbox, formAction, hover, interval, lazyEffect, scrollLock, timeout };
294
+ export { type DialogAriaHandle, type DialogAriaOptions, type FocusManagerHandle, type FocusManagerOptions, type FormActionHandle, type FormActionState, type FormActionSubmit, type IntervalHandle, type ListboxHandle, type ListboxOptions, type ScrollLockHandle, type TimeoutHandle, createDialogAria, createFocusManager, createListbox, formAction, hover, interval, lazyEffect, scrollLock, timeout };
package/dist/ui.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- export { A as AttributeSource, a as AttributeValue, B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, b as FocusTrap, c as FormConfig, d as FormField, e as FormReturn, I as IntersectionResult, M as MaskOptions, P as PaginationResult, T as Toast, f as ToastInstance, V as ValidatorFn, g as VirtualList, h as VirtualListProps, _ as __resetDialogStack, i as announce, j as aria, k as bindAttrs, l as bindBoolAttr, m as bindData, n as bindField, o as creditCardMask, p as custom, q as dateMask, r as defineElement, s as dialog, t as email, u as eventBus, v as focus, w as form, x as hotkey, y as infiniteScroll, z as inputMask, D as intersection, E as lazyLoad, G as matchesPattern, H as max, J as maxLength, K as min, L as minLength, N as pagination, O as phoneMask, Q as removeScopedStyle, R as required, S as scopedStyle, U as ssnMask, W as svgElement, X as timeMask, Y as toast, Z as withScopedStyle, $ as zipMask } from './customElement-OB9CIsc5.js';
2
- export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-DBdg9J_a.js';
1
+ export { A as AttributeSource, a as AttributeValue, B as BoundFieldProps, C as CustomElementOptions, F as FieldConfig, b as FocusTrap, c as FormConfig, d as FormField, e as FormReturn, I as IntersectionResult, M as MaskOptions, P as PaginationResult, T as Toast, f as ToastInstance, V as ValidatorFn, g as VirtualList, h as VirtualListProps, _ as __resetDialogStack, i as announce, j as aria, k as bindAttrs, l as bindBoolAttr, m as bindData, n as bindField, o as creditCardMask, p as custom, q as dateMask, r as defineElement, s as dialog, t as email, u as eventBus, v as focus, w as form, x as hotkey, y as infiniteScroll, z as inputMask, D as intersection, E as lazyLoad, G as matchesPattern, H as max, J as maxLength, K as min, L as minLength, N as pagination, O as phoneMask, Q as removeScopedStyle, R as required, S as scopedStyle, U as ssnMask, W as svgElement, X as timeMask, Y as toast, Z as withScopedStyle, $ as zipMask } from './customElement-MmInOW1U.js';
2
+ export { C as ComponentProps, P as PropDef, a as PropSchema, R as RenderProp, V as Validator, W as WithDefaultsProps, b as assertType, c as compose, d as createGuard, e as createSlots, f as defineComponent, g as defineSlottedComponent, h as defineStrictComponent, v as validateProps, i as validators, w as withBoundary, j as withDefaults, k as withProps, l as withWrapper } from './contracts-DRIuclVT.js';
3
3
 
4
- interface FormActionHandle<TArgs extends unknown[], TResult> {
4
+ /** The parts of a form-action handle available for every action signature. */
5
+ interface FormActionState<TArgs extends unknown[], TResult> {
5
6
  /** Invoke the action. Rejections become `error()`, resolutions `result()`. */
6
7
  run: (...args: TArgs) => Promise<void>;
7
8
  /** True while the underlying promise is unresolved. */
@@ -12,13 +13,26 @@ interface FormActionHandle<TArgs extends unknown[], TResult> {
12
13
  result: () => TResult | null;
13
14
  /** Clear result and error without affecting an in-flight call. */
14
15
  reset: () => void;
16
+ }
17
+ /** The submit-handler part of a form-action handle. */
18
+ interface FormActionSubmit {
15
19
  /**
16
20
  * A ready-to-attach submit handler for `<form>` elements. Calls
17
21
  * `e.preventDefault()`, builds a `FormData`, and passes it to the
18
- * underlying action. Only available when `TArgs = [FormData]`.
22
+ * underlying action as its only argument.
19
23
  */
20
24
  onSubmit: (e: Event) => void;
21
25
  }
26
+ /**
27
+ * Handle returned by {@link formAction}.
28
+ *
29
+ * `onSubmit` calls the action with exactly one `FormData`, so it is part of the
30
+ * type only when that call is valid for the action — `(data: FormData) => …`
31
+ * or `(data?: FormData) => …`. For any other signature (numeric, zero- or
32
+ * multi-argument) it is omitted rather than silently handing the action a
33
+ * `FormData` it does not expect.
34
+ */
35
+ type FormActionHandle<TArgs extends unknown[], TResult> = FormActionState<TArgs, TResult> & ([FormData] extends TArgs ? FormActionSubmit : Record<never, never>);
22
36
  /**
23
37
  * Wrap an async function into a reactive form-action handle.
24
38
  *
@@ -78,10 +92,29 @@ interface ListboxOptions {
78
92
  interface ListboxHandle {
79
93
  /** Reactive value: the currently-active (highlighted) option value. */
80
94
  activeValue: () => string | null;
81
- /** Reactive value: the currently-selected option value (single-select) or CSV (multiple). */
95
+ /**
96
+ * Reactive value: the selected option values, in selection order. Holds at
97
+ * most one value in single-select mode. Every `data-value` string — including
98
+ * ones containing commas and the empty string — is represented exactly.
99
+ */
100
+ selectedValues: () => readonly string[];
101
+ /**
102
+ * Reactive value: the selected option value (single-select), or the selected
103
+ * values joined with `","` (multiple).
104
+ *
105
+ * @deprecated In multiple mode the CSV view is lossy — a value containing a
106
+ * comma cannot be told apart from two values. Use {@link selectedValues}.
107
+ */
82
108
  selectedValue: () => string | null;
83
109
  /** Stable id that can be used as `aria-activedescendant` on the trigger. */
84
110
  activeDescendantId: () => string | null;
111
+ /**
112
+ * Reconcile options added or removed since the last change: new options get a
113
+ * stable id and `aria-selected`, and a removed active option stops being the
114
+ * active descendant. Happens automatically (on DOM mutation and before every
115
+ * interaction); call it to reconcile synchronously.
116
+ */
117
+ refresh: () => void;
85
118
  /** Cleanup: removes listeners. */
86
119
  dispose: () => void;
87
120
  }
@@ -185,7 +218,7 @@ declare function lazyEffect(element: HTMLElement, effectFn: () => void, options?
185
218
  interface IntervalHandle {
186
219
  /** Stop the interval. Safe to call multiple times. */
187
220
  stop: () => void;
188
- /** Pause (preserving remaining ticks until `resume()`). */
221
+ /** Pause, preserving the time remaining until the next tick for `resume()`. */
189
222
  pause: () => void;
190
223
  /** Resume a paused interval. */
191
224
  resume: () => void;
@@ -258,4 +291,4 @@ interface ScrollLockHandle {
258
291
  */
259
292
  declare function scrollLock(): ScrollLockHandle;
260
293
 
261
- export { type DialogAriaHandle, type DialogAriaOptions, type FocusManagerHandle, type FocusManagerOptions, type FormActionHandle, type IntervalHandle, type ListboxHandle, type ListboxOptions, type ScrollLockHandle, type TimeoutHandle, createDialogAria, createFocusManager, createListbox, formAction, hover, interval, lazyEffect, scrollLock, timeout };
294
+ export { type DialogAriaHandle, type DialogAriaOptions, type FocusManagerHandle, type FocusManagerOptions, type FormActionHandle, type FormActionState, type FormActionSubmit, type IntervalHandle, type ListboxHandle, type ListboxOptions, type ScrollLockHandle, type TimeoutHandle, createDialogAria, createFocusManager, createListbox, formAction, hover, interval, lazyEffect, scrollLock, timeout };
package/dist/ui.js CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  toast,
39
39
  withScopedStyle,
40
40
  zipMask
41
- } from "./chunk-2DCGACUU.js";
41
+ } from "./chunk-SXXVZMKZ.js";
42
42
  import {
43
43
  RenderProp,
44
44
  assertType,
@@ -54,28 +54,30 @@ import {
54
54
  withDefaults,
55
55
  withProps,
56
56
  withWrapper
57
- } from "./chunk-R25EFXXC.js";
57
+ } from "./chunk-TUCPL2HB.js";
58
58
  import {
59
59
  createId
60
- } from "./chunk-CCSJMTRN.js";
61
- import "./chunk-ONOHFDLG.js";
62
- import "./chunk-RBTPLM32.js";
63
- import "./chunk-IXKSNWV5.js";
60
+ } from "./chunk-3ISI6ACU.js";
61
+ import "./chunk-47M47FOM.js";
62
+ import "./chunk-QE4TTDU3.js";
63
+ import "./chunk-2INLLLMZ.js";
64
64
  import {
65
65
  globalSingleton
66
66
  } from "./chunk-7ZHH77QA.js";
67
67
  import {
68
68
  effect
69
- } from "./chunk-RIXRAYIU.js";
70
- import "./chunk-5DXA2J44.js";
71
- import {
72
- registerDisposer
73
- } from "./chunk-QKRPLZ2V.js";
69
+ } from "./chunk-XC4MEKGA.js";
70
+ import "./chunk-7XHATCIH.js";
71
+ import "./chunk-5HZXGZ6T.js";
74
72
  import {
73
+ batch,
75
74
  signal
76
- } from "./chunk-XZZOBQAY.js";
77
- import "./chunk-UGRX3S57.js";
78
- import "./chunk-2WLZ6757.js";
75
+ } from "./chunk-D33YTSX5.js";
76
+ import "./chunk-5Q4R7HCL.js";
77
+ import {
78
+ registerDisposer,
79
+ unregisterDisposer
80
+ } from "./chunk-NYNYSPK7.js";
79
81
 
80
82
  // src/ui/formAction.ts
81
83
  function formAction(fn) {
@@ -167,22 +169,43 @@ function createListbox(container, options = {}) {
167
169
  if (multiple) container.setAttribute("aria-multiselectable", "true");
168
170
  if (!container.hasAttribute("tabindex")) container.setAttribute("tabindex", "0");
169
171
  const [activeValue, setActiveValue] = signal(null);
172
+ const [selectedValues, setSelectedValues] = signal([]);
170
173
  const [selectedValue, setSelectedValue] = signal(null);
171
174
  const [activeDescendantId, setActiveDescendantId] = signal(null);
172
- function stampIds() {
175
+ let activeValueRef = null;
176
+ let currentSelection = [];
177
+ function reconcileOptions() {
173
178
  const opts = Array.from(container.querySelectorAll(optionSelector));
179
+ const selectedSet = new Set(currentSelection);
180
+ let activeStillPresent = false;
181
+ const active = activeValueRef;
174
182
  for (const opt of opts) {
175
183
  if (!opt.id) opt.id = createId("listbox-option");
176
- if (!opt.hasAttribute("aria-selected")) opt.setAttribute("aria-selected", "false");
184
+ const ov = opt.dataset.value;
185
+ if (!opt.hasAttribute("aria-selected")) {
186
+ opt.setAttribute("aria-selected", ov !== void 0 && selectedSet.has(ov) ? "true" : "false");
187
+ }
188
+ if (active !== null && ov === active) activeStillPresent = true;
177
189
  }
190
+ if (active !== null && !activeStillPresent) setActive(null, opts);
191
+ return opts;
178
192
  }
179
- stampIds();
180
193
  function getOptions() {
181
- return Array.from(container.querySelectorAll(optionSelector));
194
+ return reconcileOptions();
195
+ }
196
+ function isDisabled(opt) {
197
+ return opt.getAttribute("aria-disabled") === "true" || opt.hasAttribute("disabled");
198
+ }
199
+ function enabledOptions() {
200
+ return getOptions().filter((opt) => !isDisabled(opt) && opt.dataset.value !== void 0);
182
201
  }
183
- function setActive(value) {
202
+ function optionByValue(value) {
203
+ return getOptions().find((opt) => opt.dataset.value === value);
204
+ }
205
+ function setActive(value, known) {
206
+ activeValueRef = value;
184
207
  setActiveValue(value);
185
- const opts = getOptions();
208
+ const opts = known ?? getOptions();
186
209
  for (const opt of opts) {
187
210
  if (opt.dataset.value === value) {
188
211
  opt.setAttribute("data-highlighted", "");
@@ -198,29 +221,33 @@ function createListbox(container, options = {}) {
198
221
  }
199
222
  }
200
223
  function select(value) {
201
- const previous = selectedValue();
202
- let nextSelectedSet;
224
+ const target = optionByValue(value);
225
+ if (!target || isDisabled(target)) return;
226
+ const previous = selectedValues();
227
+ let next;
203
228
  if (multiple) {
204
- nextSelectedSet = new Set((previous ?? "").split(",").filter(Boolean));
205
- if (nextSelectedSet.has(value)) nextSelectedSet.delete(value);
206
- else nextSelectedSet.add(value);
207
- setSelectedValue(Array.from(nextSelectedSet).join(","));
229
+ next = previous.includes(value) ? previous.filter((v) => v !== value) : [...previous, value];
208
230
  } else {
209
- nextSelectedSet = /* @__PURE__ */ new Set([value]);
210
- setSelectedValue(value);
231
+ next = [value];
211
232
  }
233
+ currentSelection = next;
234
+ batch(() => {
235
+ setSelectedValues(next);
236
+ setSelectedValue(multiple ? next.join(",") : value);
237
+ });
212
238
  options.onSelect?.(value);
239
+ const nextSelectedSet = new Set(next);
213
240
  const opts = getOptions();
214
241
  for (const opt of opts) {
215
- const ov = opt.dataset.value ?? "";
216
- opt.setAttribute("aria-selected", nextSelectedSet.has(ov) ? "true" : "false");
242
+ const ov = opt.dataset.value;
243
+ opt.setAttribute("aria-selected", ov !== void 0 && nextSelectedSet.has(ov) ? "true" : "false");
217
244
  }
218
245
  }
219
246
  function moveActive(delta) {
220
- const opts = getOptions();
247
+ const opts = enabledOptions();
221
248
  if (opts.length === 0) return;
222
- const currentIdx = opts.findIndex((o) => o.dataset.value === activeValue());
223
- let next = currentIdx + delta;
249
+ const currentIdx = opts.findIndex((o) => o.dataset.value === activeValueRef);
250
+ let next = currentIdx === -1 ? delta > 0 ? 0 : opts.length - 1 : currentIdx + delta;
224
251
  if (next < 0) next = opts.length - 1;
225
252
  if (next >= opts.length) next = 0;
226
253
  const nextValue = opts[next].dataset.value ?? null;
@@ -241,13 +268,13 @@ function createListbox(container, options = {}) {
241
268
  break;
242
269
  case "Home": {
243
270
  e.preventDefault();
244
- const opts = getOptions();
271
+ const opts = enabledOptions();
245
272
  if (opts.length > 0) setActive(opts[0].dataset.value ?? null);
246
273
  break;
247
274
  }
248
275
  case "End": {
249
276
  e.preventDefault();
250
- const opts = getOptions();
277
+ const opts = enabledOptions();
251
278
  if (opts.length > 0) setActive(opts[opts.length - 1].dataset.value ?? null);
252
279
  break;
253
280
  }
@@ -262,7 +289,7 @@ function createListbox(container, options = {}) {
262
289
  }
263
290
  function onClick(e) {
264
291
  const target = e.target.closest(optionSelector);
265
- if (!target || !container.contains(target)) return;
292
+ if (!target || !container.contains(target) || isDisabled(target)) return;
266
293
  const value = target.dataset.value ?? null;
267
294
  if (value !== null) {
268
295
  setActive(value);
@@ -271,12 +298,26 @@ function createListbox(container, options = {}) {
271
298
  }
272
299
  container.addEventListener("keydown", onKeyDown);
273
300
  container.addEventListener("click", onClick);
301
+ reconcileOptions();
302
+ let observer = null;
303
+ if (typeof MutationObserver !== "undefined") {
304
+ observer = new MutationObserver(() => {
305
+ if (!disposed) reconcileOptions();
306
+ });
307
+ observer.observe(container, { childList: true, subtree: true });
308
+ }
309
+ let disposed = false;
274
310
  function dispose() {
311
+ if (disposed) return;
312
+ disposed = true;
313
+ unregisterDisposer(container, dispose);
314
+ observer?.disconnect();
315
+ observer = null;
275
316
  container.removeEventListener("keydown", onKeyDown);
276
317
  container.removeEventListener("click", onClick);
277
318
  }
278
319
  registerDisposer(container, dispose);
279
- return { activeValue, selectedValue, activeDescendantId, dispose };
320
+ return { activeValue, selectedValues, selectedValue, activeDescendantId, refresh: reconcileOptions, dispose };
280
321
  }
281
322
  function createDialogAria(element, options = {}) {
282
323
  const titleId = options.labelledBy ?? createId("dialog-title");
@@ -324,25 +365,59 @@ function lazyEffect(element, effectFn, options) {
324
365
 
325
366
  // src/ui/timers.ts
326
367
  function interval(fn, ms) {
327
- let id = null;
368
+ let intervalId = null;
369
+ let resumeId = null;
328
370
  let running = false;
329
- function start() {
371
+ let nextDue = 0;
372
+ let remaining = ms;
373
+ function tick() {
374
+ nextDue = Date.now() + ms;
375
+ fn();
376
+ }
377
+ function clearTimers() {
378
+ if (intervalId !== null) {
379
+ clearInterval(intervalId);
380
+ intervalId = null;
381
+ }
382
+ if (resumeId !== null) {
383
+ clearTimeout(resumeId);
384
+ resumeId = null;
385
+ }
386
+ }
387
+ function startRegular() {
388
+ nextDue = Date.now() + ms;
389
+ intervalId = setInterval(tick, ms);
390
+ }
391
+ function resume() {
330
392
  if (running) return;
331
- id = setInterval(fn, ms);
332
393
  running = true;
394
+ if (remaining >= ms) {
395
+ startRegular();
396
+ return;
397
+ }
398
+ nextDue = Date.now() + remaining;
399
+ resumeId = setTimeout(() => {
400
+ resumeId = null;
401
+ startRegular();
402
+ fn();
403
+ }, remaining);
404
+ }
405
+ function pause() {
406
+ if (!running) return;
407
+ remaining = Math.min(ms, Math.max(0, nextDue - Date.now()));
408
+ clearTimers();
409
+ running = false;
333
410
  }
334
411
  function stop() {
335
- if (id !== null) {
336
- clearInterval(id);
337
- id = null;
338
- }
412
+ clearTimers();
339
413
  running = false;
414
+ remaining = ms;
340
415
  }
341
- start();
416
+ resume();
342
417
  return {
343
418
  stop,
344
- pause: stop,
345
- resume: start,
419
+ pause,
420
+ resume,
346
421
  isRunning: () => running
347
422
  };
348
423
  }
@@ -374,7 +449,11 @@ function hover(target) {
374
449
  const onLeave = () => setHovered(false);
375
450
  target.addEventListener("pointerenter", onEnter);
376
451
  target.addEventListener("pointerleave", onLeave);
452
+ let disposed = false;
377
453
  function dispose() {
454
+ if (disposed) return;
455
+ disposed = true;
456
+ unregisterDisposer(target, dispose);
378
457
  target.removeEventListener("pointerenter", onEnter);
379
458
  target.removeEventListener("pointerleave", onLeave);
380
459
  }
@@ -388,21 +467,37 @@ var _lock = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.scrollLock.v1"),
388
467
  savedOverflow: null,
389
468
  savedPaddingRight: null
390
469
  }));
470
+ function applyBodyLock() {
471
+ const body = document.body;
472
+ if (!body) throw new Error("[scrollLock] document.body is not available yet");
473
+ const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth;
474
+ const savedOverflow = body.style.overflow;
475
+ const savedPaddingRight = body.style.paddingRight;
476
+ try {
477
+ body.style.overflow = "hidden";
478
+ if (scrollBarWidth > 0) {
479
+ body.style.paddingRight = `${scrollBarWidth}px`;
480
+ }
481
+ } catch (err) {
482
+ try {
483
+ body.style.overflow = savedOverflow;
484
+ body.style.paddingRight = savedPaddingRight;
485
+ } catch {
486
+ }
487
+ throw err;
488
+ }
489
+ _lock.savedOverflow = savedOverflow;
490
+ _lock.savedPaddingRight = savedPaddingRight;
491
+ }
391
492
  function scrollLock() {
392
493
  let owned = false;
393
494
  function lock() {
394
495
  if (owned) return;
496
+ if (_lock.count === 0 && typeof document !== "undefined") {
497
+ applyBodyLock();
498
+ }
395
499
  owned = true;
396
500
  _lock.count++;
397
- if (_lock.count !== 1 || typeof document === "undefined") return;
398
- const body = document.body;
399
- const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth;
400
- _lock.savedOverflow = body.style.overflow;
401
- _lock.savedPaddingRight = body.style.paddingRight;
402
- body.style.overflow = "hidden";
403
- if (scrollBarWidth > 0) {
404
- body.style.paddingRight = `${scrollBarWidth}px`;
405
- }
406
501
  }
407
502
  function unlock() {
408
503
  if (!owned) return;