sibujs 4.12.0 → 4.13.1

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 (74) hide show
  1. package/dist/browser.cjs +71 -18
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +6618 -6178
  4. package/dist/build.d.cts +554 -415
  5. package/dist/build.d.ts +554 -415
  6. package/dist/build.js +2091 -1735
  7. package/dist/cdn.dev.global.js +12 -12
  8. package/dist/cdn.full.dev.global.js +13 -13
  9. package/dist/cdn.full.global.js +12 -12
  10. package/dist/cdn.global.js +12 -12
  11. package/dist/{chunk-WFRQ6D7H.js → chunk-22OPSWMF.js} +1 -1
  12. package/dist/{chunk-ZJCHY2IB.js → chunk-2NC56RGY.js} +1 -1
  13. package/dist/{chunk-NB7TFSJE.js → chunk-2O6JJCUR.js} +4 -4
  14. package/dist/{chunk-B2Y5BJSP.js → chunk-4UTGDVSA.js} +70 -16
  15. package/dist/{chunk-NAVLCP4S.js → chunk-5RIBLY2N.js} +4 -4
  16. package/dist/{chunk-T5O2CUHV.js → chunk-5XUGJM3J.js} +1 -1
  17. package/dist/{chunk-HXT2RNH5.js → chunk-ADZHPN2B.js} +1 -1
  18. package/dist/chunk-B36ADEIR.js +21 -0
  19. package/dist/{chunk-DFZL3AX7.js → chunk-C73VBPEF.js} +9 -5
  20. package/dist/{chunk-WH4U2VUE.js → chunk-CPQKWCJ2.js} +13 -5
  21. package/dist/{chunk-LEUEKK4G.js → chunk-EU7T7EB3.js} +2 -2
  22. package/dist/{chunk-QLG5IK7F.js → chunk-G3Z2FEBR.js} +4 -4
  23. package/dist/{chunk-ZPY2UAKM.js → chunk-J4X7ICH4.js} +3 -3
  24. package/dist/{chunk-XX4BRMWF.js → chunk-K4LNUT5L.js} +1 -1
  25. package/dist/{chunk-CI4W6XAU.js → chunk-KC62VURU.js} +3 -3
  26. package/dist/chunk-N5TBYXHW.js +17 -0
  27. package/dist/{chunk-653KGQS2.js → chunk-OIKD7YDY.js} +2 -2
  28. package/dist/{chunk-LYTUTXQP.js → chunk-PBJYCE2Z.js} +46 -4
  29. package/dist/{chunk-EMB5PG7V.js → chunk-QC3NP47A.js} +1 -1
  30. package/dist/{chunk-IHA62NGJ.js → chunk-QKFVMIAV.js} +1 -1
  31. package/dist/{chunk-LXBMVGVB.js → chunk-QZ47OZ25.js} +3 -3
  32. package/dist/{chunk-ZTYCCBU3.js → chunk-VFPLWUT7.js} +44 -26
  33. package/dist/{chunk-RK7EPQPG.js → chunk-YFTBCCVH.js} +1 -1
  34. package/dist/data.cjs +71 -18
  35. package/dist/data.js +5 -5
  36. package/dist/datePicker-DxuxWpgF.d.cts +285 -0
  37. package/dist/datePicker-DxuxWpgF.d.ts +285 -0
  38. package/dist/devtools.cjs +71 -18
  39. package/dist/devtools.js +4 -4
  40. package/dist/ecosystem.cjs +82 -21
  41. package/dist/ecosystem.js +7 -7
  42. package/dist/extras.cjs +131 -23
  43. package/dist/extras.d.cts +2 -2
  44. package/dist/extras.d.ts +2 -2
  45. package/dist/extras.js +21 -20
  46. package/dist/index.cjs +115 -37
  47. package/dist/index.d.cts +59 -5
  48. package/dist/index.d.ts +59 -5
  49. package/dist/index.js +10 -10
  50. package/dist/motion.cjs +69 -16
  51. package/dist/motion.js +3 -3
  52. package/dist/patterns.cjs +71 -18
  53. package/dist/patterns.js +5 -5
  54. package/dist/performance.cjs +69 -16
  55. package/dist/performance.js +4 -4
  56. package/dist/plugins.cjs +1421 -996
  57. package/dist/plugins.d.cts +132 -3
  58. package/dist/plugins.d.ts +132 -3
  59. package/dist/plugins.js +262 -11
  60. package/dist/routeMiddleware-B1sp4P7a.d.ts +688 -0
  61. package/dist/routeMiddleware-CedQTsLK.d.cts +688 -0
  62. package/dist/ssr.cjs +3607 -3524
  63. package/dist/ssr.d.cts +20 -671
  64. package/dist/ssr.d.ts +20 -671
  65. package/dist/ssr.js +15 -7
  66. package/dist/testing.cjs +71 -18
  67. package/dist/testing.js +2 -2
  68. package/dist/ui.cjs +78 -18
  69. package/dist/ui.js +8 -7
  70. package/dist/widgets.cjs +1352 -952
  71. package/dist/widgets.d.cts +100 -268
  72. package/dist/widgets.d.ts +100 -268
  73. package/dist/widgets.js +316 -7
  74. package/package.json +9 -1
package/dist/widgets.d.ts CHANGED
@@ -1,285 +1,117 @@
1
- interface ComboboxOptions<T> {
2
- items: T[];
3
- filterFn?: (item: T, query: string) => boolean;
4
- itemToString?: (item: T) => string;
5
- }
6
- declare function combobox<T>(options: ComboboxOptions<T>): {
7
- query: () => string;
8
- setQuery: (q: string) => void;
9
- filteredItems: () => T[];
10
- selectedItem: () => T | null;
11
- select: (item: T) => void;
12
- highlightedIndex: () => number;
13
- highlightNext: () => void;
14
- highlightPrev: () => void;
15
- selectHighlighted: () => void;
16
- isOpen: () => boolean;
17
- open: () => void;
18
- close: () => void;
19
- /** WAI-ARIA Combobox 1.2 wiring: `role=combobox` on input,
20
- * `aria-expanded`/`aria-controls`/`aria-activedescendant`, listbox option
21
- * ids, Down/Up/Enter/Escape/Home/End. Returns dispose. */
22
- bind: (els: {
23
- input: HTMLInputElement;
24
- listbox: HTMLElement;
25
- option: (item: T, index: number) => HTMLElement | null;
26
- }) => () => void;
27
- };
28
-
29
- interface TabsOptions {
30
- tabs: Array<{
31
- id: string;
32
- label: string;
33
- disabled?: boolean;
34
- }>;
35
- defaultTab?: string;
36
- }
37
- interface TabsAriaBinding {
38
- /** WAI-ARIA Tabs pattern — wires `role`/`aria-*` and arrow/Home/End keys
39
- * to the provided tablist + per-tab elements. Returns dispose. */
40
- bind: (els: {
41
- tablist: HTMLElement;
42
- tabs: Record<string, HTMLElement>;
43
- panels?: Record<string, HTMLElement>;
44
- }) => () => void;
45
- }
46
- declare function tabs(options: TabsOptions): {
47
- activeTab: () => string;
48
- setActiveTab: (id: string) => void;
49
- tabs: () => Array<{
50
- id: string;
51
- label: string;
52
- disabled?: boolean;
53
- isActive: boolean;
54
- }>;
55
- nextTab: () => void;
56
- prevTab: () => void;
57
- isActive: (id: string) => boolean;
58
- bind: TabsAriaBinding["bind"];
59
- };
60
-
61
- interface AccordionOptions {
62
- items: Array<{
63
- id: string;
64
- label: string;
65
- }>;
66
- multiple?: boolean;
67
- defaultExpanded?: string[];
68
- }
69
- interface AccordionAriaBinding {
70
- /** WAI-ARIA Accordion pattern — wires `aria-expanded`/`aria-controls`,
71
- * Enter/Space toggle, and panel `role=region`. Returns dispose.
72
- * Pass `root` (any stable container element) to anchor the WeakMap
73
- * idempotency key — without it, double-bind detection falls back to
74
- * the first trigger and breaks if items re-render. */
75
- bind: (els: {
76
- root?: HTMLElement;
77
- triggers: Record<string, HTMLElement>;
78
- panels: Record<string, HTMLElement>;
79
- }) => () => void;
80
- }
81
- declare function accordion(options: AccordionOptions): {
82
- items: () => Array<{
83
- id: string;
84
- label: string;
85
- isExpanded: boolean;
86
- }>;
87
- toggle: (id: string) => void;
88
- expand: (id: string) => void;
89
- collapse: (id: string) => void;
90
- expandAll: () => void;
91
- collapseAll: () => void;
92
- isExpanded: (id: string) => boolean;
93
- bind: AccordionAriaBinding["bind"];
94
- };
1
+ export { A as AccordionAriaBinding, a as AccordionOptions, C as ComboboxOptions, D as DatePickerOptions, F as FileUploadOptions, S as SelectOptions, b as SetContentOptions, T as TabsAriaBinding, c as TabsOptions, d as accordion, e as combobox, f as contentEditable, g as datePicker, h as fileUpload, p as popover, s as select, t as tabs, i as tooltip } from './datePicker-DxuxWpgF.js';
95
2
 
96
3
  /**
97
- * popover provides simple state management for positioned floating content.
98
- * Manages open/close/toggle without any DOM coupling.
4
+ * Whether a `sibujs/widgets` widget already acted on this key event. Page-level
5
+ * shortcuts test it so a key the user pressed INSIDE a widget (an arrow in a
6
+ * select menu, Escape in a popover) does not also trigger the page's binding.
7
+ *
8
+ * @param event Any event; only key events are ever claimed.
9
+ * @returns `true` when a widget consumed the event.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * document.addEventListener("keydown", (e) => {
14
+ * if (isWidgetKeyEvent(e)) return; // the dropdown already handled it
15
+ * if (e.key === "ArrowLeft") nudgeSelectedLayer(-1, 0);
16
+ * if (e.key === "Escape") deselect();
17
+ * });
18
+ * ```
99
19
  */
100
- declare function popover(): {
101
- isOpen: () => boolean;
102
- open: () => void;
103
- close: () => void;
104
- toggle: () => void;
105
- /** WAI-ARIA non-modal dialog wiring: `role=dialog`, `aria-expanded` on
106
- * trigger, Escape closes, click-outside closes. Returns dispose. */
107
- bind: (els: {
108
- trigger: HTMLElement;
109
- popover: HTMLElement;
110
- labelledBy?: HTMLElement;
111
- }) => () => void;
112
- };
20
+ declare function isWidgetKeyEvent(event: Event): boolean;
21
+ /**
22
+ * Name of the widget that claimed `event` (`"selectMenu"`, `"tabs"`, …), or
23
+ * `null` when no widget did.
24
+ *
25
+ * @param event Any event.
26
+ * @returns The claiming widget's name, or `null`.
27
+ */
28
+ declare function widgetKeyOwner(event: Event): string | null;
113
29
 
114
- interface SelectOptions<T> {
115
- items: T[];
116
- multiple?: boolean;
30
+ interface SelectMenuOptions<T> {
31
+ /** The options, in display order. A getter makes the list reactive. */
32
+ items: T[] | (() => T[]);
33
+ /**
34
+ * The selected item, CONTROLLED: read through this getter, changed only by
35
+ * the app in response to `onChange`. Omit it for an uncontrolled menu that
36
+ * keeps its own selection (seeded by `defaultValue`).
37
+ */
38
+ value?: () => T | null | undefined;
39
+ /** Initial selection of an uncontrolled menu. */
40
+ defaultValue?: T | null;
41
+ /** Called when the user commits an option (Enter, Space, click, Tab, Alt+Up). */
42
+ onChange?: (item: T) => void;
43
+ /** Text used by typeahead. Defaults to `String(item)`. */
117
44
  itemToString?: (item: T) => string;
118
- /** Optional predicate marking items as disabled — such items are skipped
119
- * by `highlightNext`/`highlightPrev`/typeahead and rejected by `select`. */
45
+ /** Disabled options are skipped by navigation and typeahead and cannot be committed. */
120
46
  isDisabled?: (item: T) => boolean;
47
+ /** Identity of two items, used to find the selected one. Defaults to `Object.is`. */
48
+ isEqual?: (a: T, b: T) => boolean;
49
+ /** How far PageUp / PageDown move the active option. Defaults to 10. */
50
+ pageSize?: number;
121
51
  }
122
- /**
123
- * Selection state for a list — single or multiple, with keyboard-friendly
124
- * helpers. Headless: it owns state, not markup.
125
- *
126
- * @param options Item list, selection mode, and comparison strategy.
127
- * @returns A handle exposing `selectedItem`/`selectedItems` accessors and the
128
- * `select`, `deselect`, `toggle` and `clear` operations.
129
- */
130
- declare function select<T>(options: SelectOptions<T>): {
131
- selectedItems: () => T[];
132
- selectedItem: () => T | null;
133
- select: (item: T) => void;
134
- deselect: (item: T) => void;
135
- toggle: (item: T) => void;
136
- isSelected: (item: T) => boolean;
52
+ interface SelectMenuElements<T> {
53
+ /** The element that shows the value and opens the list — usually a `<button>`. */
54
+ trigger: HTMLElement;
55
+ /** The popup list. Hidden while the menu is closed. */
56
+ listbox: HTMLElement;
57
+ /** The element rendering `item`, or null when it is not in the DOM. */
58
+ option: (item: T, index: number) => HTMLElement | null;
59
+ }
60
+ interface SelectMenu<T> {
61
+ /** The committed selection. */
62
+ value: () => T | null;
63
+ /** Whether the popup list is showing. */
137
64
  isOpen: () => boolean;
138
- open: () => void;
65
+ /**
66
+ * Show the list. The active option is the selected one (or the first enabled
67
+ * option); pass `"first"` or `"last"` to start from an end instead.
68
+ */
69
+ open: (activeAt?: "selected" | "first" | "last") => void;
70
+ /** Hide the list without changing the selection. */
139
71
  close: () => void;
140
- highlightedIndex: () => number;
141
- highlightNext: () => void;
142
- highlightPrev: () => void;
143
- selectHighlighted: () => void;
144
- clear: () => void;
145
- /** WAI-ARIA Listbox wiring: `role=listbox`, `aria-multiselectable`,
146
- * `aria-selected`/`aria-activedescendant`, arrow + Home/End/Enter/Space
147
- * + typeahead. Returns dispose. */
148
- bind: (els: {
149
- listbox: HTMLElement;
150
- option: (item: T, index: number) => HTMLElement | null;
151
- itemToString?: (item: T) => string;
152
- }) => () => void;
153
- };
154
-
155
- /**
156
- * tooltip manages tooltip visibility with optional show delay.
157
- * Timer cleanup is handled via closure variables per the framework convention.
158
- */
159
- declare function tooltip(options?: {
160
- delay?: number;
161
- hideDelay?: number;
162
- }): {
163
- isVisible: () => boolean;
164
- show: () => void;
165
- hide: () => void;
166
- content: () => string;
167
- setContent: (text: string) => void;
168
- /** WAI-ARIA Tooltip pattern — wires `role=tooltip`, `aria-describedby`,
169
- * Escape-to-dismiss, and pointer hover-grace per WCAG 1.4.13. */
170
- bind: (els: {
171
- trigger: HTMLElement;
172
- tooltip: HTMLElement;
173
- }) => () => void;
174
- };
175
-
176
- interface FileUploadOptions {
177
- accept?: string;
178
- multiple?: boolean;
179
- maxSize?: number;
180
- onFiles?: (files: File[]) => void;
181
- }
182
- declare function fileUpload(options?: FileUploadOptions): {
183
- files: () => File[];
184
- addFiles: (fileList: FileList | File[]) => void;
185
- removeFile: (index: number) => void;
186
- clear: () => void;
187
- errors: () => string[];
188
- isDragOver: () => boolean;
189
- setDragOver: (v: boolean) => void;
190
- /** Wires native file input + drop zone with proper labeling, hint
191
- * description, and keyboard activation. Returns dispose. */
192
- bind: (els: {
193
- input: HTMLInputElement;
194
- dropZone?: HTMLElement;
195
- hint?: HTMLElement;
196
- errorRegion?: HTMLElement;
197
- }) => () => void;
198
- };
199
-
200
- /**
201
- * Options for `setContent`.
202
- *
203
- * WARNING: passing `sanitize: false` bypasses the built-in protection and
204
- * requires the caller to guarantee the HTML has already been sanitized with
205
- * a trusted library. Any untrusted input that reaches `setContent` with
206
- * `sanitize: false` is an XSS vector.
207
- */
208
- interface SetContentOptions {
209
- /** Raw HTML to assign. Sanitized by default (tags are stripped). */
210
- html?: string;
211
- /** Plain text. Always safe — assigned via `textContent`. */
212
- text?: string;
72
+ /** Open when closed, close when open. */
73
+ toggle: () => void;
74
+ /** Index of the option the keyboard is on (visual focus), or -1. */
75
+ active: () => number;
76
+ /** The item at {@link active}, or null. */
77
+ activeItem: () => T | null;
78
+ /** Move visual focus to `index` (ignored for a disabled or missing option). */
79
+ setActive: (index: number) => void;
80
+ /** Commit `item` as if the user picked it: calls `onChange`, closes the list. */
81
+ select: (item: T) => void;
213
82
  /**
214
- * When true (default), `html` is run through the framework's HTML
215
- * stripper before assignment — tags are removed, only text content is
216
- * preserved. Set to `false` ONLY when `html` has already been sanitized
217
- * with a dedicated library (e.g. DOMPurify).
83
+ * WAI-ARIA APG "select-only combobox" wiring. The trigger gets
84
+ * `role=combobox`, `aria-haspopup=listbox`, `aria-expanded`, `aria-controls`
85
+ * and `aria-activedescendant`; the listbox and options get their roles,
86
+ * ids, `aria-selected` and `aria-disabled`. Keyboard, pointer, outside click
87
+ * and focus return are handled. Returns dispose, which restores every
88
+ * attribute it touched.
218
89
  */
219
- sanitize?: boolean;
90
+ bind: (els: SelectMenuElements<T>) => () => void;
220
91
  }
221
92
  /**
222
- * contentEditable provides reactive binding for contenteditable elements.
93
+ * Headless "select-only combobox": a button that opens a popup list of options
94
+ * whose content is arbitrary DOM — a font name in its own typeface, a swatch,
95
+ * an icon — which a native `<select>` cannot render.
96
+ *
97
+ * Follows the WAI-ARIA APG select-only combobox pattern: focus stays on the
98
+ * trigger and the list is navigated through `aria-activedescendant`.
223
99
  *
224
- * Uses the modern Selection/Range API instead of the deprecated
225
- * document.execCommand. Formatting is applied by wrapping the current
226
- * selection in the appropriate inline element.
100
+ * Keys it acts on are claimed (see `isWidgetKeyEvent`), so a page-level
101
+ * shortcut handler can leave them alone.
227
102
  *
228
- * @param element Optional editor element to scope formatting to. When provided,
229
- * `bold()`/`italic()`/`underline()` ignore any selection that lives outside it
230
- * — otherwise a selection elsewhere on the page could be mutated, since the
231
- * Selection API is global.
103
+ * @param options Items, selection (controlled or not) and item helpers.
104
+ * @returns Menu state and a `bind()` that wires it to your markup.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * const menu = selectMenu({ items: FONTS, value: () => font(), onChange: setFont, itemToString: (f) => f.label });
109
+ * const optionEls = FONTS.map((f) => li({ style: { fontFamily: f.css } }, f.label));
110
+ * const list = ul(optionEls);
111
+ * const trigger = button(() => menu.value()?.label ?? "Choose a font");
112
+ * menu.bind({ trigger, listbox: list, option: (_f, i) => optionEls[i] });
113
+ * ```
232
114
  */
233
- declare function contentEditable(element?: HTMLElement): {
234
- content: () => string;
235
- /**
236
- * Update the reactive content value.
237
- *
238
- * - `setContent("<b>x</b>")` — LEGACY: treated as `{ html, sanitize: true }`.
239
- * The HTML is stripped to text by default to prevent XSS. Prefer the
240
- * options form below.
241
- * - `setContent({ text: "hello" })` — plain text, always safe.
242
- * - `setContent({ html, sanitize: true })` — sanitized HTML (default).
243
- * - `setContent({ html, sanitize: false })` — raw HTML; the caller MUST
244
- * have pre-sanitized it with a trusted library (e.g. DOMPurify).
245
- */
246
- setContent: (input: string | SetContentOptions) => void;
247
- isFocused: () => boolean;
248
- setFocused: (v: boolean) => void;
249
- bold: () => void;
250
- italic: () => void;
251
- underline: () => void;
252
- };
253
-
254
- interface DatePickerOptions {
255
- initialDate?: Date;
256
- minDate?: Date;
257
- maxDate?: Date;
258
- }
259
- declare function datePicker(options?: DatePickerOptions): {
260
- selectedDate: () => Date | null;
261
- select: (date: Date) => void;
262
- viewDate: () => Date;
263
- setViewDate: (date: Date) => void;
264
- nextMonth: () => void;
265
- prevMonth: () => void;
266
- nextYear: () => void;
267
- prevYear: () => void;
268
- daysInMonth: () => Array<{
269
- date: Date;
270
- isCurrentMonth: boolean;
271
- isToday: boolean;
272
- isSelected: boolean;
273
- isDisabled: boolean;
274
- }>;
275
- isDateDisabled: (date: Date) => boolean;
276
- isSelected: (date: Date) => boolean;
277
- /** WAI-ARIA Date Picker dialog grid wiring: `role=grid`, arrow nav,
278
- * PageUp/Down (month), Shift+PageUp/Down (year), Home/End. */
279
- bind: (els: {
280
- grid: HTMLElement;
281
- cell: (date: Date) => HTMLElement | null;
282
- }) => () => void;
283
- };
115
+ declare function selectMenu<T>(options: SelectMenuOptions<T>): SelectMenu<T>;
284
116
 
285
- export { type AccordionAriaBinding, type AccordionOptions, type ComboboxOptions, type DatePickerOptions, type FileUploadOptions, type SelectOptions, type SetContentOptions, type TabsAriaBinding, type TabsOptions, accordion, combobox, contentEditable, datePicker, fileUpload, popover, select, tabs, tooltip };
117
+ export { type SelectMenu, type SelectMenuElements, type SelectMenuOptions, isWidgetKeyEvent, selectMenu, widgetKeyOwner };