@openwarelabs/ui 0.0.0-stage → 0.1.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 (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +100 -2
  3. package/dist/components/Accordion/Accordion.d.cts +54 -0
  4. package/dist/components/Accordion/Accordion.d.ts +54 -0
  5. package/dist/components/Alert/Alert.d.cts +18 -0
  6. package/dist/components/Alert/Alert.d.ts +18 -0
  7. package/dist/components/Avatar/Avatar.d.cts +14 -0
  8. package/dist/components/Avatar/Avatar.d.ts +14 -0
  9. package/dist/components/Avatar/AvatarGroup.d.cts +28 -0
  10. package/dist/components/Avatar/AvatarGroup.d.ts +28 -0
  11. package/dist/components/Badge/Badge.d.cts +13 -0
  12. package/dist/components/Badge/Badge.d.ts +13 -0
  13. package/dist/components/Breadcrumbs/Breadcrumbs.d.cts +33 -0
  14. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +33 -0
  15. package/dist/components/Button/Button.d.cts +42 -0
  16. package/dist/components/Button/Button.d.ts +42 -0
  17. package/dist/components/Button/ButtonGroup.d.cts +33 -0
  18. package/dist/components/Button/ButtonGroup.d.ts +33 -0
  19. package/dist/components/Calendar/Calendar.d.cts +31 -0
  20. package/dist/components/Calendar/Calendar.d.ts +31 -0
  21. package/dist/components/Calendar/DatePicker.d.cts +21 -0
  22. package/dist/components/Calendar/DatePicker.d.ts +21 -0
  23. package/dist/components/Calendar/dates.d.cts +15 -0
  24. package/dist/components/Calendar/dates.d.ts +15 -0
  25. package/dist/components/Card/Card.d.cts +18 -0
  26. package/dist/components/Card/Card.d.ts +18 -0
  27. package/dist/components/Checkbox/Checkbox.d.cts +59 -0
  28. package/dist/components/Checkbox/Checkbox.d.ts +59 -0
  29. package/dist/components/ChoiceCard/ChoiceCard.d.cts +14 -0
  30. package/dist/components/ChoiceCard/ChoiceCard.d.ts +14 -0
  31. package/dist/components/CodeBlock/CodeBlock.d.cts +50 -0
  32. package/dist/components/CodeBlock/CodeBlock.d.ts +50 -0
  33. package/dist/components/ColorPicker/ColorPicker.d.cts +62 -0
  34. package/dist/components/ColorPicker/ColorPicker.d.ts +62 -0
  35. package/dist/components/Combobox/Combobox.d.cts +42 -0
  36. package/dist/components/Combobox/Combobox.d.ts +42 -0
  37. package/dist/components/CommandPalette/CommandPalette.d.cts +27 -0
  38. package/dist/components/CommandPalette/CommandPalette.d.ts +27 -0
  39. package/dist/components/CommandPalette/filterCommands.d.cts +3 -0
  40. package/dist/components/CommandPalette/filterCommands.d.ts +3 -0
  41. package/dist/components/Dialog/Dialog.d.cts +42 -0
  42. package/dist/components/Dialog/Dialog.d.ts +42 -0
  43. package/dist/components/Drawer/Drawer.d.cts +23 -0
  44. package/dist/components/Drawer/Drawer.d.ts +23 -0
  45. package/dist/components/EmptyState/EmptyState.d.cts +18 -0
  46. package/dist/components/EmptyState/EmptyState.d.ts +18 -0
  47. package/dist/components/Field/Field.d.cts +18 -0
  48. package/dist/components/Field/Field.d.ts +18 -0
  49. package/dist/components/FileDropZone/FileDropZone.d.cts +29 -0
  50. package/dist/components/FileDropZone/FileDropZone.d.ts +29 -0
  51. package/dist/components/FileTree/FileTree.d.cts +29 -0
  52. package/dist/components/FileTree/FileTree.d.ts +29 -0
  53. package/dist/components/Input/Input.d.cts +18 -0
  54. package/dist/components/Input/Input.d.ts +18 -0
  55. package/dist/components/InputOTP/InputOTP.d.cts +31 -0
  56. package/dist/components/InputOTP/InputOTP.d.ts +31 -0
  57. package/dist/components/Kbd/Kbd.d.cts +5 -0
  58. package/dist/components/Kbd/Kbd.d.ts +5 -0
  59. package/dist/components/Layout/Layout.d.cts +50 -0
  60. package/dist/components/Layout/Layout.d.ts +50 -0
  61. package/dist/components/Marketing/Marketing.d.cts +39 -0
  62. package/dist/components/Marketing/Marketing.d.ts +39 -0
  63. package/dist/components/Menu/Menu.d.cts +43 -0
  64. package/dist/components/Menu/Menu.d.ts +43 -0
  65. package/dist/components/NavList/NavList.d.cts +27 -0
  66. package/dist/components/NavList/NavList.d.ts +27 -0
  67. package/dist/components/NumberField/NumberField.d.cts +23 -0
  68. package/dist/components/NumberField/NumberField.d.ts +23 -0
  69. package/dist/components/Pagination/Pagination.d.cts +24 -0
  70. package/dist/components/Pagination/Pagination.d.ts +24 -0
  71. package/dist/components/Popover/Popover.d.cts +30 -0
  72. package/dist/components/Popover/Popover.d.ts +30 -0
  73. package/dist/components/Progress/Progress.d.cts +41 -0
  74. package/dist/components/Progress/Progress.d.ts +41 -0
  75. package/dist/components/RadioGroup/RadioGroup.d.cts +36 -0
  76. package/dist/components/RadioGroup/RadioGroup.d.ts +36 -0
  77. package/dist/components/SearchField/SearchField.d.cts +17 -0
  78. package/dist/components/SearchField/SearchField.d.ts +17 -0
  79. package/dist/components/SegmentedControl/SegmentedControl.d.cts +32 -0
  80. package/dist/components/SegmentedControl/SegmentedControl.d.ts +32 -0
  81. package/dist/components/Select/Select.d.cts +40 -0
  82. package/dist/components/Select/Select.d.ts +40 -0
  83. package/dist/components/Skeleton/Skeleton.d.cts +26 -0
  84. package/dist/components/Skeleton/Skeleton.d.ts +26 -0
  85. package/dist/components/Slider/Slider.d.cts +33 -0
  86. package/dist/components/Slider/Slider.d.ts +33 -0
  87. package/dist/components/Spinner/Spinner.d.cts +14 -0
  88. package/dist/components/Spinner/Spinner.d.ts +14 -0
  89. package/dist/components/Stat/Stat.d.cts +20 -0
  90. package/dist/components/Stat/Stat.d.ts +20 -0
  91. package/dist/components/Steps/Steps.d.cts +27 -0
  92. package/dist/components/Steps/Steps.d.ts +27 -0
  93. package/dist/components/Switch/Switch.d.cts +9 -0
  94. package/dist/components/Switch/Switch.d.ts +9 -0
  95. package/dist/components/Table/Table.d.cts +55 -0
  96. package/dist/components/Table/Table.d.ts +55 -0
  97. package/dist/components/Tabs/Tabs.d.cts +35 -0
  98. package/dist/components/Tabs/Tabs.d.ts +35 -0
  99. package/dist/components/Tag/Tag.d.cts +40 -0
  100. package/dist/components/Tag/Tag.d.ts +40 -0
  101. package/dist/components/Textarea/Textarea.d.cts +12 -0
  102. package/dist/components/Textarea/Textarea.d.ts +12 -0
  103. package/dist/components/Toast/Toast.d.cts +41 -0
  104. package/dist/components/Toast/Toast.d.ts +41 -0
  105. package/dist/components/Tooltip/Tooltip.d.cts +19 -0
  106. package/dist/components/Tooltip/Tooltip.d.ts +19 -0
  107. package/dist/components.css +5236 -0
  108. package/dist/fonts.css +3 -0
  109. package/dist/hooks/useControllableState.d.cts +5 -0
  110. package/dist/hooks/useControllableState.d.ts +5 -0
  111. package/dist/hooks/useFloating.d.cts +26 -0
  112. package/dist/hooks/useFloating.d.ts +26 -0
  113. package/dist/hooks/useIndicator.d.cts +8 -0
  114. package/dist/hooks/useIndicator.d.ts +8 -0
  115. package/dist/hooks/useMenuKeyboard.d.cts +12 -0
  116. package/dist/hooks/useMenuKeyboard.d.ts +12 -0
  117. package/dist/hooks/useModalDialog.d.cts +9 -0
  118. package/dist/hooks/useModalDialog.d.ts +9 -0
  119. package/dist/hooks/usePresence.d.cts +13 -0
  120. package/dist/hooks/usePresence.d.ts +13 -0
  121. package/dist/icons.d.cts +33 -0
  122. package/dist/icons.d.ts +33 -0
  123. package/dist/index.cjs +4622 -0
  124. package/dist/index.cjs.map +7 -0
  125. package/dist/index.d.cts +114 -0
  126. package/dist/index.d.ts +114 -0
  127. package/dist/index.js +4650 -0
  128. package/dist/index.js.map +7 -0
  129. package/dist/openware-ui.iife.js +8 -0
  130. package/dist/styles.css +5664 -0
  131. package/dist/tailwind.css +145 -0
  132. package/dist/tokens.css +427 -0
  133. package/dist/tokens.json +1163 -0
  134. package/dist/utils/brand.d.cts +30 -0
  135. package/dist/utils/brand.d.ts +30 -0
  136. package/dist/utils/copyText.d.cts +2 -0
  137. package/dist/utils/copyText.d.ts +2 -0
  138. package/dist/utils/cx.d.cts +4 -0
  139. package/dist/utils/cx.d.ts +4 -0
  140. package/dist/utils/resizeTextArea.d.cts +2 -0
  141. package/dist/utils/resizeTextArea.d.ts +2 -0
  142. package/dist/utils/text.d.cts +4 -0
  143. package/dist/utils/text.d.ts +4 -0
  144. package/package.json +83 -4
package/dist/index.cjs ADDED
@@ -0,0 +1,4622 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Accordion: () => Accordion,
24
+ AccordionItem: () => AccordionItem,
25
+ Alert: () => Alert,
26
+ Avatar: () => Avatar,
27
+ AvatarGroup: () => AvatarGroup,
28
+ Badge: () => Badge,
29
+ Breadcrumbs: () => Breadcrumbs,
30
+ Button: () => Button,
31
+ ButtonGroup: () => ButtonGroup,
32
+ Calendar: () => Calendar,
33
+ Card: () => Card,
34
+ Checkbox: () => Checkbox,
35
+ CheckboxGroup: () => CheckboxGroup,
36
+ Chip: () => Chip,
37
+ ChoiceCard: () => ChoiceCard,
38
+ CloseButton: () => CloseButton,
39
+ Code: () => Code,
40
+ CodeBlock: () => CodeBlock,
41
+ ColorField: () => ColorField,
42
+ ColorPicker: () => ColorPicker,
43
+ ColorSwatch: () => ColorSwatch,
44
+ Combobox: () => Combobox,
45
+ CommandPalette: () => CommandPalette,
46
+ ConfirmDialog: () => ConfirmDialog,
47
+ CopyButton: () => CopyButton,
48
+ DatePicker: () => DatePicker,
49
+ Dialog: () => Dialog,
50
+ Disclosure: () => Disclosure,
51
+ DotGrid: () => DotGrid,
52
+ Drawer: () => Drawer,
53
+ EmptyState: () => EmptyState,
54
+ Field: () => Field,
55
+ Fieldset: () => Fieldset,
56
+ FileDropZone: () => FileDropZone,
57
+ FileTree: () => FileTree,
58
+ Input: () => Input,
59
+ InputOTP: () => InputOTP,
60
+ Kbd: () => Kbd,
61
+ Link: () => Link,
62
+ Menu: () => Menu,
63
+ MenuItem: () => MenuItem,
64
+ MenuLabel: () => MenuLabel,
65
+ MenuSeparator: () => MenuSeparator,
66
+ NavItem: () => NavItem,
67
+ NavList: () => NavList,
68
+ NumberField: () => NumberField,
69
+ Pagination: () => Pagination,
70
+ Popover: () => Popover,
71
+ ProgressBar: () => ProgressBar,
72
+ ProgressCircle: () => ProgressCircle,
73
+ Radio: () => Radio,
74
+ RadioGroup: () => RadioGroup,
75
+ ScrollShadow: () => ScrollShadow,
76
+ SearchField: () => SearchField,
77
+ SectionHeading: () => SectionHeading,
78
+ SegmentedControl: () => SegmentedControl,
79
+ Select: () => Select,
80
+ Separator: () => Separator,
81
+ SettingsRow: () => SettingsRow,
82
+ SiteHeader: () => SiteHeader,
83
+ Skeleton: () => Skeleton,
84
+ SkeletonRows: () => SkeletonRows,
85
+ Slider: () => Slider,
86
+ Snippet: () => Snippet,
87
+ Spinner: () => Spinner,
88
+ Stack: () => Stack,
89
+ Stat: () => Stat,
90
+ Steps: () => Steps,
91
+ Switch: () => Switch,
92
+ Tab: () => Tab,
93
+ TabList: () => TabList,
94
+ TabPanel: () => TabPanel,
95
+ Table: () => Table,
96
+ Tabs: () => Tabs,
97
+ Tag: () => Tag,
98
+ TagGroup: () => TagGroup,
99
+ Textarea: () => Textarea,
100
+ Toaster: () => Toaster,
101
+ ToggleButton: () => ToggleButton,
102
+ Tooltip: () => Tooltip,
103
+ User: () => User,
104
+ VisuallyHidden: () => VisuallyHidden,
105
+ addDays: () => addDays,
106
+ addMonths: () => addMonths,
107
+ applyBrand: () => applyBrand,
108
+ brandCss: () => brandCss,
109
+ brandPresets: () => brandPresets,
110
+ brandScale: () => brandScale,
111
+ brandSteps: () => brandSteps,
112
+ brandVariables: () => brandVariables,
113
+ buttonClassName: () => buttonClassName,
114
+ copyText: () => copyText,
115
+ cx: () => cx,
116
+ filterCommands: () => filterCommands,
117
+ formatDate: () => formatDate,
118
+ getInitials: () => getInitials,
119
+ linkClassName: () => linkClassName,
120
+ paginationItems: () => paginationItems,
121
+ parseISO: () => parseISO,
122
+ toISO: () => toISO,
123
+ toast: () => import_sonner.toast,
124
+ todayISO: () => todayISO,
125
+ useControllableState: () => useControllableState,
126
+ useDismiss: () => useDismiss,
127
+ useFloating: () => useFloating,
128
+ useMenuKeyboard: () => useMenuKeyboard,
129
+ useModalDialog: () => useModalDialog,
130
+ usePresence: () => usePresence,
131
+ weekday: () => weekday
132
+ });
133
+ module.exports = __toCommonJS(index_exports);
134
+
135
+ // src/components/Button/Button.tsx
136
+ var import_react = require("react");
137
+
138
+ // src/utils/cx.ts
139
+ function cx(...values) {
140
+ const classes = [];
141
+ for (const value of values) {
142
+ if (!value) continue;
143
+ if (typeof value === "string") {
144
+ classes.push(value);
145
+ continue;
146
+ }
147
+ for (const [name, on] of Object.entries(value)) if (on) classes.push(name);
148
+ }
149
+ return classes.join(" ");
150
+ }
151
+
152
+ // src/utils/text.ts
153
+ function getInitials(name) {
154
+ const words = name.trim().split(/\s+/).filter(Boolean);
155
+ const first = words[0]?.[0] ?? "";
156
+ const last = words.length > 1 ? words[words.length - 1]?.[0] ?? "" : "";
157
+ return `${first}${last}`.toUpperCase();
158
+ }
159
+ function toAriaShortcut(shortcut) {
160
+ return shortcut.replace("\u2318", "Meta+").replace("Ctrl+", "Control+");
161
+ }
162
+
163
+ // src/components/Spinner/Spinner.tsx
164
+ var import_jsx_runtime = require("react/jsx-runtime");
165
+ function Spinner({ size = "md", tone = "primary", label = "Loading", className }) {
166
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
167
+ "span",
168
+ {
169
+ className: cx("ow-spinner", `ow-spinner--${size}`, `ow-spinner--${tone}`, className),
170
+ ...label ? { role: "status", "aria-label": label } : { "aria-hidden": true }
171
+ }
172
+ );
173
+ }
174
+
175
+ // src/components/Button/Button.tsx
176
+ var import_jsx_runtime2 = require("react/jsx-runtime");
177
+ function buttonClassName({
178
+ variant = "secondary",
179
+ size = "md",
180
+ shape = "rounded",
181
+ iconOnly = false
182
+ } = {}) {
183
+ return cx(
184
+ "ow-button",
185
+ `ow-button--${variant}`,
186
+ `ow-button--${size}`,
187
+ shape === "pill" && "ow-button--pill",
188
+ iconOnly && "ow-button--icon-only"
189
+ );
190
+ }
191
+ var Button = (0, import_react.forwardRef)(function Button2({
192
+ children,
193
+ className,
194
+ disabled,
195
+ endIcon,
196
+ fullWidth = false,
197
+ iconOnly = false,
198
+ loading = false,
199
+ shape = "rounded",
200
+ shortcut,
201
+ size = "md",
202
+ startIcon,
203
+ type = "button",
204
+ variant = "secondary",
205
+ ...buttonProps
206
+ }, ref) {
207
+ const leading = loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Spinner, { size: "sm", tone: "current", label: "" }) : startIcon;
208
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
209
+ "button",
210
+ {
211
+ ref,
212
+ className: cx(
213
+ buttonClassName({ variant, size, shape, iconOnly }),
214
+ shortcut && !iconOnly && "ow-button--with-shortcut",
215
+ loading && "ow-button--loading",
216
+ fullWidth && "ow-button--full",
217
+ className
218
+ ),
219
+ type,
220
+ disabled: disabled || loading,
221
+ "aria-busy": loading || void 0,
222
+ "aria-keyshortcuts": shortcut ? toAriaShortcut(shortcut) : void 0,
223
+ ...buttonProps,
224
+ children: [
225
+ leading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ow-button__icon", children: leading }) : null,
226
+ iconOnly && loading ? null : children,
227
+ endIcon && !iconOnly ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ow-button__icon", children: endIcon }) : null,
228
+ shortcut && !iconOnly ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("kbd", { "aria-hidden": "true", className: "ow-button__shortcut", children: shortcut }) : null
229
+ ]
230
+ }
231
+ );
232
+ });
233
+
234
+ // src/components/Button/ButtonGroup.tsx
235
+ var import_react3 = require("react");
236
+
237
+ // src/hooks/useControllableState.ts
238
+ var import_react2 = require("react");
239
+ function useControllableState(value, defaultValue, onChange) {
240
+ const [internal, setInternal] = (0, import_react2.useState)(defaultValue);
241
+ const isControlled = value !== void 0;
242
+ const current = isControlled ? value : internal;
243
+ const currentRef = (0, import_react2.useRef)(current);
244
+ currentRef.current = current;
245
+ const onChangeRef = (0, import_react2.useRef)(onChange);
246
+ onChangeRef.current = onChange;
247
+ const setValue = (0, import_react2.useCallback)(
248
+ (next) => {
249
+ const resolved = typeof next === "function" ? next(currentRef.current) : next;
250
+ if (Object.is(resolved, currentRef.current)) return;
251
+ if (!isControlled) setInternal(resolved);
252
+ onChangeRef.current?.(resolved);
253
+ },
254
+ [isControlled]
255
+ );
256
+ return [current, setValue];
257
+ }
258
+
259
+ // src/icons.tsx
260
+ var import_jsx_runtime3 = require("react/jsx-runtime");
261
+ function icon(paths) {
262
+ return function Icon({ size = 16, strokeWidth = 2, ...props }) {
263
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
264
+ "svg",
265
+ {
266
+ xmlns: "http://www.w3.org/2000/svg",
267
+ width: size,
268
+ height: size,
269
+ viewBox: "0 0 24 24",
270
+ fill: "none",
271
+ stroke: "currentColor",
272
+ strokeWidth,
273
+ strokeLinecap: "round",
274
+ strokeLinejoin: "round",
275
+ "aria-hidden": "true",
276
+ focusable: "false",
277
+ ...props,
278
+ children: paths
279
+ }
280
+ );
281
+ };
282
+ }
283
+ var CheckIcon = icon(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M20 6 9 17l-5-5" }));
284
+ var ChevronDownIcon = icon(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 9 6 6 6-6" }));
285
+ var SearchIcon = icon(
286
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
287
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "11", cy: "11", r: "8" }),
288
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m21 21-4.3-4.3" })
289
+ ] })
290
+ );
291
+ var CornerDownLeftIcon = icon(
292
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
293
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "9 10 4 15 9 20" }),
294
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M20 4v7a4 4 0 0 1-4 4H4" })
295
+ ] })
296
+ );
297
+ var XIcon = icon(
298
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
299
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M18 6 6 18" }),
300
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 6 12 12" })
301
+ ] })
302
+ );
303
+ var UserIcon = icon(
304
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
305
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }),
306
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "7", r: "4" })
307
+ ] })
308
+ );
309
+ var TrashIcon = icon(
310
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
311
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M3 6h18" }),
312
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
313
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }),
314
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "10", x2: "10", y1: "11", y2: "17" }),
315
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "14", x2: "14", y1: "11", y2: "17" })
316
+ ] })
317
+ );
318
+ var CircleCheckIcon = icon(
319
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
320
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
321
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m9 12 2 2 4-4" })
322
+ ] })
323
+ );
324
+ var CircleAlertIcon = icon(
325
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
326
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
327
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12", x2: "12", y1: "8", y2: "12" }),
328
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12", x2: "12.01", y1: "16", y2: "16" })
329
+ ] })
330
+ );
331
+ var ChevronRightIcon = icon(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m9 18 6-6-6-6" }));
332
+ var ChevronLeftIcon = icon(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m15 18-6-6 6-6" }));
333
+ var ChevronUpIcon = icon(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m18 15-6-6-6 6" }));
334
+ var MinusIcon = icon(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M5 12h14" }));
335
+ var PlusIcon = icon(
336
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
337
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M5 12h14" }),
338
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 5v14" })
339
+ ] })
340
+ );
341
+ var InfoIcon = icon(
342
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
343
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
344
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 16v-4" }),
345
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 8h.01" })
346
+ ] })
347
+ );
348
+ var TriangleAlertIcon = icon(
349
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
350
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
351
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 9v4" }),
352
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 17h.01" })
353
+ ] })
354
+ );
355
+ var PipetteIcon = icon(
356
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
357
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m2 22 1-1h3l9-9" }),
358
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M3 21v-3l9-9" }),
359
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m15 6 3.4-3.4a2.1 2.1 0 1 1 3 3L18 9l.4.4a2.1 2.1 0 1 1-3 3l-3.8-3.8a2.1 2.1 0 1 1 3-3l.4.4Z" })
360
+ ] })
361
+ );
362
+ var CopyIcon = icon(
363
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
364
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
365
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
366
+ ] })
367
+ );
368
+ var CalendarIcon = icon(
369
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M8 2v4" }),
371
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M16 2v4" }),
372
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { width: "18", height: "18", x: "3", y: "4", rx: "2" }),
373
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M3 10h18" })
374
+ ] })
375
+ );
376
+ var FileIcon = icon(
377
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
378
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
379
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
380
+ ] })
381
+ );
382
+ var FolderIcon = icon(
383
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" })
384
+ );
385
+ var FolderOpenIcon = icon(
386
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2" })
387
+ );
388
+ var UploadIcon = icon(
389
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
390
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
391
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "17 8 12 3 7 8" }),
392
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
393
+ ] })
394
+ );
395
+ var ArrowUpRightIcon = icon(
396
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
397
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M7 7h10v10" }),
398
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M7 17 17 7" })
399
+ ] })
400
+ );
401
+ var ArrowUpIcon = icon(
402
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
403
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m5 12 7-7 7 7" }),
404
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 19V5" })
405
+ ] })
406
+ );
407
+ var ArrowDownIcon = icon(
408
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
409
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 5v14" }),
410
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m19 12-7 7-7-7" })
411
+ ] })
412
+ );
413
+ var ChevronsUpDownIcon = icon(
414
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
415
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m7 15 5 5 5-5" }),
416
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m7 9 5-5 5 5" })
417
+ ] })
418
+ );
419
+ var InboxIcon = icon(
420
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
421
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "22 12 16 12 14 15 10 15 8 12 2 12" }),
422
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" })
423
+ ] })
424
+ );
425
+ var EllipsisIcon = icon(
426
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
427
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "1" }),
428
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "19", cy: "12", r: "1" }),
429
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "5", cy: "12", r: "1" })
430
+ ] })
431
+ );
432
+
433
+ // src/components/Button/ButtonGroup.tsx
434
+ var import_jsx_runtime4 = require("react/jsx-runtime");
435
+ function ButtonGroup({ attached = true, orientation = "horizontal", className, ...props }) {
436
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
437
+ "div",
438
+ {
439
+ role: "group",
440
+ className: cx(
441
+ "ow-button-group",
442
+ attached && "ow-button-group--attached",
443
+ orientation === "vertical" && "ow-button-group--vertical",
444
+ className
445
+ ),
446
+ ...props
447
+ }
448
+ );
449
+ }
450
+ var CloseButton = (0, import_react3.forwardRef)(function CloseButton2({ size = "md", label = "Close", className, type = "button", ...buttonProps }, ref) {
451
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
452
+ "button",
453
+ {
454
+ ref,
455
+ type,
456
+ "aria-label": label,
457
+ className: cx("ow-close-button", `ow-close-button--${size}`, className),
458
+ ...buttonProps,
459
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(XIcon, { size: size === "sm" ? 14 : 17 })
460
+ }
461
+ );
462
+ });
463
+ var ToggleButton = (0, import_react3.forwardRef)(function ToggleButton2({ pressed, defaultPressed = false, onPressedChange, onClick, className, variant = "secondary", ...buttonProps }, ref) {
464
+ const [isPressed, setPressed] = useControllableState(pressed, defaultPressed, onPressedChange);
465
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
466
+ Button,
467
+ {
468
+ ref,
469
+ variant,
470
+ "aria-pressed": isPressed,
471
+ className: cx(isPressed && "ow-button--pressed", className),
472
+ onClick: (event) => {
473
+ onClick?.(event);
474
+ if (!event.defaultPrevented) setPressed(!isPressed);
475
+ },
476
+ ...buttonProps
477
+ }
478
+ );
479
+ });
480
+
481
+ // src/components/SegmentedControl/SegmentedControl.tsx
482
+ var import_react5 = require("react");
483
+
484
+ // src/hooks/useIndicator.ts
485
+ var import_react4 = require("react");
486
+ function useIndicator(containerRef, selector, key) {
487
+ (0, import_react4.useLayoutEffect)(() => {
488
+ const container = containerRef.current;
489
+ if (!container) return void 0;
490
+ let frame = 0;
491
+ const measure = () => {
492
+ const selected = container.querySelector(selector);
493
+ if (!selected) {
494
+ delete container.dataset.indicator;
495
+ return;
496
+ }
497
+ container.style.setProperty("--ow-indicator-x", `${selected.offsetLeft}px`);
498
+ container.style.setProperty("--ow-indicator-y", `${selected.offsetTop}px`);
499
+ container.style.setProperty("--ow-indicator-w", `${selected.offsetWidth}px`);
500
+ container.style.setProperty("--ow-indicator-h", `${selected.offsetHeight}px`);
501
+ if (!container.dataset.indicator) {
502
+ container.dataset.indicator = "placed";
503
+ frame = requestAnimationFrame(() => {
504
+ frame = requestAnimationFrame(() => {
505
+ if (container.dataset.indicator) container.dataset.indicator = "ready";
506
+ });
507
+ });
508
+ }
509
+ };
510
+ measure();
511
+ if (typeof ResizeObserver === "undefined") return () => cancelAnimationFrame(frame);
512
+ const observer = new ResizeObserver(measure);
513
+ observer.observe(container);
514
+ for (const child of container.children) observer.observe(child);
515
+ return () => {
516
+ cancelAnimationFrame(frame);
517
+ observer.disconnect();
518
+ };
519
+ }, [containerRef, selector, key]);
520
+ }
521
+
522
+ // src/components/SegmentedControl/SegmentedControl.tsx
523
+ var import_jsx_runtime5 = require("react/jsx-runtime");
524
+ function SegmentedControl({
525
+ options,
526
+ value,
527
+ defaultValue,
528
+ onChange,
529
+ size = "md",
530
+ fullWidth = false,
531
+ disabled = false,
532
+ className,
533
+ ...aria
534
+ }) {
535
+ const [current, setCurrent] = useControllableState(value, defaultValue ?? options[0]?.value ?? "", onChange);
536
+ const refs = (0, import_react5.useRef)([]);
537
+ const groupRef = (0, import_react5.useRef)(null);
538
+ useIndicator(groupRef, '[aria-checked="true"]', current);
539
+ const enabled = options.map((option, index) => ({ option, index })).filter(({ option }) => !option.disabled);
540
+ function onKeyDown(event, index) {
541
+ const keys = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 };
542
+ let target;
543
+ if (event.key in keys) {
544
+ const position = enabled.findIndex((entry) => entry.index === index);
545
+ target = enabled[(position + keys[event.key] + enabled.length) % enabled.length]?.index;
546
+ } else if (event.key === "Home") target = enabled[0]?.index;
547
+ else if (event.key === "End") target = enabled[enabled.length - 1]?.index;
548
+ if (target === void 0) return;
549
+ event.preventDefault();
550
+ refs.current[target]?.focus();
551
+ setCurrent(options[target].value);
552
+ }
553
+ const focusable = options.some((option) => option.value === current && !option.disabled) ? current : enabled[0]?.option.value;
554
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
555
+ "div",
556
+ {
557
+ ref: groupRef,
558
+ role: "radiogroup",
559
+ className: cx("ow-segmented", `ow-segmented--${size}`, fullWidth && "ow-segmented--full", disabled && "ow-segmented--disabled", className),
560
+ ...aria,
561
+ children: [
562
+ options.map((option, index) => {
563
+ const isSelected = option.value === current;
564
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
565
+ "button",
566
+ {
567
+ ref: (element) => {
568
+ refs.current[index] = element;
569
+ },
570
+ type: "button",
571
+ role: "radio",
572
+ "aria-checked": isSelected,
573
+ "aria-label": option["aria-label"],
574
+ tabIndex: option.value === focusable ? 0 : -1,
575
+ disabled: disabled || option.disabled,
576
+ className: cx("ow-segmented__item", isSelected && "ow-segmented__item--selected"),
577
+ onClick: () => setCurrent(option.value),
578
+ onKeyDown: (event) => onKeyDown(event, index),
579
+ children: [
580
+ option.icon ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ow-segmented__icon", children: option.icon }) : null,
581
+ option.label
582
+ ]
583
+ },
584
+ option.value
585
+ );
586
+ }),
587
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ow-indicator", "aria-hidden": "true" })
588
+ ]
589
+ }
590
+ );
591
+ }
592
+
593
+ // src/components/ChoiceCard/ChoiceCard.tsx
594
+ var import_react6 = require("react");
595
+ var import_jsx_runtime6 = require("react/jsx-runtime");
596
+ var ChoiceCard = (0, import_react6.forwardRef)(function ChoiceCard2({ className, description, icon: icon2, recommended = false, shortcut, title, type = "button", ...buttonProps }, ref) {
597
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
598
+ "button",
599
+ {
600
+ ref,
601
+ className: cx("ow-choice", recommended && "ow-choice--recommended", className),
602
+ type,
603
+ "aria-keyshortcuts": shortcut ? toAriaShortcut(shortcut) : void 0,
604
+ ...buttonProps,
605
+ children: [
606
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ow-choice__top", children: [
607
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ow-choice__icon", children: icon2 }),
608
+ shortcut ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("kbd", { "aria-hidden": "true", className: "ow-choice__shortcut", children: shortcut }) : null
609
+ ] }),
610
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ow-choice__text", children: [
611
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ow-choice__title", children: title }),
612
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ow-choice__description", children: description })
613
+ ] })
614
+ ]
615
+ }
616
+ );
617
+ });
618
+
619
+ // src/components/CodeBlock/CodeBlock.tsx
620
+ var import_react7 = require("react");
621
+
622
+ // src/utils/copyText.ts
623
+ async function copyText(text) {
624
+ try {
625
+ await navigator.clipboard.writeText(text);
626
+ return true;
627
+ } catch {
628
+ const area = document.createElement("textarea");
629
+ area.value = text;
630
+ area.setAttribute("readonly", "");
631
+ area.style.position = "fixed";
632
+ area.style.opacity = "0";
633
+ document.body.appendChild(area);
634
+ area.select();
635
+ let ok = false;
636
+ try {
637
+ ok = document.execCommand("copy");
638
+ } catch {
639
+ ok = false;
640
+ }
641
+ area.remove();
642
+ return ok;
643
+ }
644
+ }
645
+
646
+ // src/components/CodeBlock/CodeBlock.tsx
647
+ var import_jsx_runtime7 = require("react/jsx-runtime");
648
+ function CopyButton({ value, label = "Copy", copiedLabel = "Copied", iconOnly = false, tone = "default", onCopy, className }) {
649
+ const [copied, setCopied] = (0, import_react7.useState)(false);
650
+ const timer = (0, import_react7.useRef)(0);
651
+ (0, import_react7.useEffect)(() => () => window.clearTimeout(timer.current), []);
652
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
653
+ "button",
654
+ {
655
+ type: "button",
656
+ className: cx(
657
+ "ow-copy-button",
658
+ tone === "onDark" && "ow-copy-button--on-dark",
659
+ iconOnly && "ow-copy-button--icon-only",
660
+ copied && "ow-copy-button--copied",
661
+ className
662
+ ),
663
+ "aria-label": iconOnly ? copied ? copiedLabel : label : void 0,
664
+ onClick: async () => {
665
+ if (await copyText(value)) {
666
+ setCopied(true);
667
+ onCopy?.();
668
+ window.clearTimeout(timer.current);
669
+ timer.current = window.setTimeout(() => setCopied(false), 2e3);
670
+ }
671
+ },
672
+ children: [
673
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ow-copy-button__icon", "aria-hidden": "true", children: [
674
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CopyIcon, { size: 14 }),
675
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckIcon, { size: 14 })
676
+ ] }),
677
+ iconOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: copied ? copiedLabel : label }),
678
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ow-visually-hidden", "aria-live": "polite", children: copied ? copiedLabel : "" })
679
+ ]
680
+ }
681
+ );
682
+ }
683
+ function CodeBlock({ code, html, title, language, showLineNumbers = false, copyable = true, maxHeight, className }) {
684
+ const hasHeader = title !== void 0 || language !== void 0;
685
+ const lines = code.replace(/\n$/, "").split("\n");
686
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cx("ow-code-block", showLineNumbers && "ow-code-block--numbered", className), children: [
687
+ hasHeader ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "ow-code-block__header", children: [
688
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ow-code-block__title", children: title }),
689
+ language ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ow-code-block__language", children: language }) : null,
690
+ copyable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CopyButton, { value: code, tone: "onDark", iconOnly: true, label: "Copy code" }) : null
691
+ ] }) : copyable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CopyButton, { value: code, tone: "onDark", iconOnly: true, label: "Copy code", className: "ow-code-block__floating-copy" }) : null,
692
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("pre", { className: "ow-code-block__pre", style: maxHeight ? { maxHeight } : void 0, tabIndex: 0, children: [
693
+ showLineNumbers ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ow-code-block__numbers", "aria-hidden": "true", children: lines.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: index + 1 }, index)) }) : null,
694
+ html ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { className: "ow-code-block__code", dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { className: "ow-code-block__code", children: code.replace(/\n$/, "") })
695
+ ] })
696
+ ] });
697
+ }
698
+ function Snippet({ value, prompt = "$", className }) {
699
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cx("ow-snippet", className), children: [
700
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("code", { className: "ow-snippet__code", children: [
701
+ prompt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ow-snippet__prompt", "aria-hidden": "true", children: prompt }) : null,
702
+ value
703
+ ] }),
704
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CopyButton, { value, iconOnly: true, label: `Copy ${value}` })
705
+ ] });
706
+ }
707
+
708
+ // src/components/Field/Field.tsx
709
+ var import_react8 = require("react");
710
+ var import_jsx_runtime8 = require("react/jsx-runtime");
711
+ function Field({ label, children, hint, error, className }) {
712
+ const generatedId = (0, import_react8.useId)();
713
+ const hintId = `${generatedId}-hint`;
714
+ const errorId = `${generatedId}-error`;
715
+ const child = (0, import_react8.isValidElement)(children) ? children : null;
716
+ const controlId = child?.props.id ?? `${generatedId}-control`;
717
+ const describedBy = [child?.props["aria-describedby"], hint ? hintId : void 0, error ? errorId : void 0].filter(Boolean).join(" ") || void 0;
718
+ const invalidProp = child && typeof child.type !== "string" ? { isInvalid: child.props.isInvalid ?? Boolean(error) } : { "aria-invalid": error ? true : void 0 };
719
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: cx("ow-field", className), children: [
720
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "ow-field__label", htmlFor: controlId, children: label }),
721
+ child ? (0, import_react8.cloneElement)(child, { id: controlId, "aria-describedby": describedBy, ...invalidProp }) : children,
722
+ hint ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { id: hintId, className: "ow-field__hint", children: hint }) : null,
723
+ error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { id: errorId, role: "alert", className: "ow-field__error", children: error }) : null
724
+ ] });
725
+ }
726
+
727
+ // src/components/Input/Input.tsx
728
+ var import_react9 = require("react");
729
+ var import_jsx_runtime9 = require("react/jsx-runtime");
730
+ var Input = (0, import_react9.forwardRef)(function Input2({ className, isInvalid = false, size = "md", startContent, endContent, ...inputProps }, ref) {
731
+ const invalid = isInvalid || void 0;
732
+ if (startContent === void 0 && endContent === void 0) {
733
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
734
+ "input",
735
+ {
736
+ ref,
737
+ className: cx("ow-input", size === "sm" && "ow-input--sm", isInvalid && "ow-input--invalid", className),
738
+ "aria-invalid": invalid,
739
+ ...inputProps
740
+ }
741
+ );
742
+ }
743
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
744
+ "div",
745
+ {
746
+ className: cx(
747
+ "ow-input-group",
748
+ size === "sm" && "ow-input-group--sm",
749
+ isInvalid && "ow-input-group--invalid",
750
+ inputProps.disabled && "ow-input-group--disabled",
751
+ className
752
+ ),
753
+ children: [
754
+ startContent !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ow-input-group__addon", children: startContent }) : null,
755
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref, className: "ow-input-group__input", "aria-invalid": invalid, ...inputProps }),
756
+ endContent !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ow-input-group__addon", children: endContent }) : null
757
+ ]
758
+ }
759
+ );
760
+ });
761
+
762
+ // src/components/SearchField/SearchField.tsx
763
+ var import_react10 = require("react");
764
+ var import_jsx_runtime10 = require("react/jsx-runtime");
765
+ function assignRef(ref, value) {
766
+ if (typeof ref === "function") ref(value);
767
+ else if (ref) ref.current = value;
768
+ }
769
+ var SearchField = (0, import_react10.forwardRef)(function SearchField2({
770
+ value,
771
+ defaultValue = "",
772
+ onChange,
773
+ onSubmit,
774
+ loading = false,
775
+ placeholder = "Search",
776
+ "aria-label": ariaLabel = "Search",
777
+ size = "md",
778
+ onKeyDown,
779
+ ...inputProps
780
+ }, ref) {
781
+ const [text, setText] = useControllableState(value, defaultValue, onChange);
782
+ const inputRef = (0, import_react10.useRef)(null);
783
+ function handleKeyDown(event) {
784
+ onKeyDown?.(event);
785
+ if (event.defaultPrevented) return;
786
+ if (event.key === "Escape" && text) {
787
+ event.preventDefault();
788
+ event.stopPropagation();
789
+ setText("");
790
+ } else if (event.key === "Enter") {
791
+ onSubmit?.(text);
792
+ }
793
+ }
794
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
795
+ Input,
796
+ {
797
+ ref: (element) => {
798
+ inputRef.current = element;
799
+ assignRef(ref, element);
800
+ },
801
+ type: "search",
802
+ size,
803
+ placeholder,
804
+ "aria-label": ariaLabel,
805
+ value: text,
806
+ onChange: (event) => setText(event.target.value),
807
+ onKeyDown: handleKeyDown,
808
+ startContent: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SearchIcon, { size: size === "sm" ? 14 : 16 }),
809
+ endContent: loading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner, { size: "sm", label: "Searching" }) : text ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
810
+ CloseButton,
811
+ {
812
+ size: "sm",
813
+ label: "Clear search",
814
+ onClick: () => {
815
+ setText("");
816
+ inputRef.current?.focus();
817
+ }
818
+ }
819
+ ) : null,
820
+ ...inputProps
821
+ }
822
+ );
823
+ });
824
+
825
+ // src/components/NumberField/NumberField.tsx
826
+ var import_react11 = require("react");
827
+ var import_jsx_runtime11 = require("react/jsx-runtime");
828
+ var decimals = (step) => (String(step).split(".")[1] ?? "").length;
829
+ var NumberField = (0, import_react11.forwardRef)(function NumberField2({
830
+ value,
831
+ defaultValue = null,
832
+ onChange,
833
+ min,
834
+ max,
835
+ step = 1,
836
+ formatOptions,
837
+ size = "md",
838
+ isInvalid = false,
839
+ disabled,
840
+ className,
841
+ onBlur,
842
+ onFocus,
843
+ onKeyDown,
844
+ ...inputProps
845
+ }, ref) {
846
+ const [number, setNumber] = useControllableState(value, defaultValue, onChange);
847
+ const [draft, setDraft] = (0, import_react11.useState)(null);
848
+ const format = (n) => n === null ? "" : formatOptions ? new Intl.NumberFormat(void 0, formatOptions).format(n) : String(n);
849
+ const clamp = (n) => {
850
+ const rounded = Number(n.toFixed(decimals(step)));
851
+ return Math.min(max ?? Infinity, Math.max(min ?? -Infinity, rounded));
852
+ };
853
+ function commit(text, keepEditing = false) {
854
+ setDraft(keepEditing ? text : null);
855
+ const cleaned = text.replace(/[^\d.,-]/g, "").replace(",", ".");
856
+ if (cleaned === "" || cleaned === "-") {
857
+ setNumber(null);
858
+ return;
859
+ }
860
+ const parsed = Number(cleaned);
861
+ if (Number.isNaN(parsed)) return;
862
+ const next = clamp(parsed);
863
+ setNumber(next);
864
+ if (keepEditing) setDraft(String(next));
865
+ }
866
+ function stepBy(multiple) {
867
+ const base = draft !== null && draft !== "" && !Number.isNaN(Number(draft)) ? Number(draft) : number ?? min ?? 0;
868
+ const next = clamp(base + step * multiple);
869
+ setNumber(next);
870
+ if (draft !== null) setDraft(String(next));
871
+ }
872
+ function handleKeyDown(event) {
873
+ onKeyDown?.(event);
874
+ if (event.defaultPrevented) return;
875
+ const moves = {
876
+ ArrowUp: () => stepBy(1),
877
+ ArrowDown: () => stepBy(-1),
878
+ PageUp: () => stepBy(10),
879
+ PageDown: () => stepBy(-10),
880
+ Home: () => min !== void 0 && commit(String(min), draft !== null),
881
+ End: () => max !== void 0 && commit(String(max), draft !== null),
882
+ Enter: () => draft !== null && commit(draft, true)
883
+ };
884
+ const move = moves[event.key];
885
+ if (!move) return;
886
+ event.preventDefault();
887
+ move();
888
+ }
889
+ const atMin = min !== void 0 && number !== null && number <= min;
890
+ const atMax = max !== void 0 && number !== null && number >= max;
891
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
892
+ "div",
893
+ {
894
+ className: cx(
895
+ "ow-number-field",
896
+ size === "sm" && "ow-number-field--sm",
897
+ isInvalid && "ow-number-field--invalid",
898
+ disabled && "ow-number-field--disabled",
899
+ className
900
+ ),
901
+ children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
903
+ "button",
904
+ {
905
+ type: "button",
906
+ className: "ow-number-field__step",
907
+ "aria-label": "Decrease",
908
+ tabIndex: -1,
909
+ disabled: disabled || atMin,
910
+ onClick: () => stepBy(-1),
911
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MinusIcon, { size: 14 })
912
+ }
913
+ ),
914
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
915
+ "input",
916
+ {
917
+ ref,
918
+ type: "text",
919
+ inputMode: decimals(step) > 0 || (min ?? 0) < 0 ? "decimal" : "numeric",
920
+ role: "spinbutton",
921
+ autoComplete: "off",
922
+ className: "ow-number-field__input",
923
+ "aria-valuenow": number ?? void 0,
924
+ "aria-valuemin": min,
925
+ "aria-valuemax": max,
926
+ "aria-valuetext": number === null ? void 0 : format(number),
927
+ "aria-invalid": isInvalid || void 0,
928
+ disabled,
929
+ value: draft ?? format(number),
930
+ onFocus: (event) => {
931
+ onFocus?.(event);
932
+ setDraft(number === null ? "" : String(number));
933
+ },
934
+ onChange: (event) => setDraft(event.target.value),
935
+ onBlur: (event) => {
936
+ onBlur?.(event);
937
+ commit(event.target.value);
938
+ },
939
+ onKeyDown: handleKeyDown,
940
+ ...inputProps
941
+ }
942
+ ),
943
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
944
+ "button",
945
+ {
946
+ type: "button",
947
+ className: "ow-number-field__step",
948
+ "aria-label": "Increase",
949
+ tabIndex: -1,
950
+ disabled: disabled || atMax,
951
+ onClick: () => stepBy(1),
952
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PlusIcon, { size: 14 })
953
+ }
954
+ )
955
+ ]
956
+ }
957
+ );
958
+ });
959
+
960
+ // src/components/InputOTP/InputOTP.tsx
961
+ var import_react12 = require("react");
962
+ var import_jsx_runtime12 = require("react/jsx-runtime");
963
+ function InputOTP({
964
+ length = 6,
965
+ value,
966
+ defaultValue = "",
967
+ onChange,
968
+ onComplete,
969
+ type = "numeric",
970
+ groupSize,
971
+ isInvalid = false,
972
+ disabled,
973
+ autoFocus,
974
+ "aria-label": ariaLabel = "Verification code",
975
+ name,
976
+ className
977
+ }) {
978
+ const [code, setCode] = useControllableState(value, defaultValue, onChange);
979
+ const refs = (0, import_react12.useRef)([]);
980
+ const latest = (0, import_react12.useRef)(code);
981
+ latest.current = code;
982
+ const allowed = type === "numeric" ? /\d/ : /[a-z0-9]/i;
983
+ const clean = (text) => [...text].filter((char) => allowed.test(char)).join("").toUpperCase();
984
+ const chars = Array.from({ length }, (_, index) => code[index] ?? "");
985
+ function update(next, focusIndex) {
986
+ const trimmed = next.slice(0, length);
987
+ latest.current = trimmed;
988
+ setCode(trimmed);
989
+ refs.current[Math.min(focusIndex, length - 1)]?.focus();
990
+ if (trimmed.length === length && !trimmed.includes(" ")) onComplete?.(trimmed);
991
+ }
992
+ function setAt(index, char) {
993
+ const next = chars.map((existing, i) => i === index ? char : existing);
994
+ const firstGap = next.indexOf("");
995
+ return (firstGap === -1 ? next : next.slice(0, firstGap)).join("");
996
+ }
997
+ function onInput(index, text) {
998
+ const typed = clean(text);
999
+ if (!typed) return;
1000
+ if (typed.length > 1) {
1001
+ update(chars.slice(0, index).join("") + typed, index + typed.length);
1002
+ return;
1003
+ }
1004
+ update(setAt(index, typed), index + 1);
1005
+ }
1006
+ function onKeyDown(index, event) {
1007
+ if (event.key === "Backspace") {
1008
+ event.preventDefault();
1009
+ if (chars[index]) update(code.slice(0, index) + code.slice(index + 1), index);
1010
+ else if (index > 0) update(code.slice(0, index - 1) + code.slice(index), index - 1);
1011
+ } else if (event.key === "ArrowLeft") {
1012
+ event.preventDefault();
1013
+ refs.current[Math.max(0, index - 1)]?.focus();
1014
+ } else if (event.key === "ArrowRight") {
1015
+ event.preventDefault();
1016
+ refs.current[Math.min(length - 1, index + 1, code.length)]?.focus();
1017
+ }
1018
+ }
1019
+ function onPaste(index, event) {
1020
+ event.preventDefault();
1021
+ const pasted = clean(event.clipboardData.getData("text"));
1022
+ if (pasted) update(chars.slice(0, index).join("") + pasted, index + pasted.length);
1023
+ }
1024
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { role: "group", "aria-label": ariaLabel, className: cx("ow-otp", isInvalid && "ow-otp--invalid", className), children: [
1025
+ chars.map((char, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "ow-otp__slot", children: [
1026
+ groupSize && index > 0 && index % groupSize === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ow-otp__separator", "aria-hidden": "true" }) : null,
1027
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1028
+ "input",
1029
+ {
1030
+ ref: (element) => {
1031
+ refs.current[index] = element;
1032
+ },
1033
+ className: "ow-otp__input",
1034
+ type: "text",
1035
+ inputMode: type === "numeric" ? "numeric" : "text",
1036
+ autoComplete: index === 0 ? "one-time-code" : "off",
1037
+ autoCapitalize: "characters",
1038
+ maxLength: length,
1039
+ "aria-label": `Character ${index + 1} of ${length}`,
1040
+ "aria-invalid": isInvalid || void 0,
1041
+ disabled,
1042
+ autoFocus: autoFocus && index === 0,
1043
+ value: char,
1044
+ onFocus: (event) => {
1045
+ const filled = latest.current.length;
1046
+ if (index > filled) refs.current[filled]?.focus();
1047
+ else event.target.select();
1048
+ },
1049
+ onChange: (event) => onInput(index, event.target.value.replace(char, "") || event.target.value),
1050
+ onKeyDown: (event) => onKeyDown(index, event),
1051
+ onPaste: (event) => onPaste(index, event)
1052
+ }
1053
+ )
1054
+ ] }, index)),
1055
+ name ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "hidden", name, value: code }) : null
1056
+ ] });
1057
+ }
1058
+
1059
+ // src/components/Textarea/Textarea.tsx
1060
+ var import_react13 = require("react");
1061
+
1062
+ // src/utils/resizeTextArea.ts
1063
+ var surelyOverflowingLength = 2e4;
1064
+ function surelyOverflows(textArea, maxHeight) {
1065
+ const text = textArea.value;
1066
+ if (text.length > surelyOverflowingLength) return true;
1067
+ const style = window.getComputedStyle(textArea);
1068
+ const lineHeight = Number.parseFloat(style.lineHeight) || Number.parseFloat(style.fontSize) * 1.2;
1069
+ if (!lineHeight) return false;
1070
+ const needed = Math.ceil(maxHeight / lineHeight) + 1;
1071
+ let lines = 1;
1072
+ for (let index = text.indexOf("\n"); index !== -1 && lines < needed; index = text.indexOf("\n", index + 1))
1073
+ lines += 1;
1074
+ return lines >= needed;
1075
+ }
1076
+ function resizeTextArea(textArea) {
1077
+ const maxHeight = Number.parseFloat(window.getComputedStyle(textArea).maxHeight);
1078
+ if (Number.isFinite(maxHeight) && surelyOverflows(textArea, maxHeight)) {
1079
+ textArea.style.height = `${maxHeight.toString()}px`;
1080
+ textArea.style.overflowY = "auto";
1081
+ return;
1082
+ }
1083
+ textArea.style.height = "auto";
1084
+ const shouldScroll = Number.isFinite(maxHeight) && textArea.scrollHeight > maxHeight;
1085
+ textArea.style.height = `${textArea.scrollHeight}px`;
1086
+ textArea.style.overflowY = shouldScroll ? "auto" : "hidden";
1087
+ }
1088
+
1089
+ // src/components/Textarea/Textarea.tsx
1090
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1091
+ var defaultAutoGrowMaxHeight = 180;
1092
+ function assignRef2(ref, element) {
1093
+ if (typeof ref === "function") ref(element);
1094
+ else if (ref) ref.current = element;
1095
+ }
1096
+ var Textarea = (0, import_react13.forwardRef)(function Textarea2({
1097
+ autoGrow = false,
1098
+ autoGrowMaxHeight = defaultAutoGrowMaxHeight,
1099
+ bare = false,
1100
+ className,
1101
+ isInvalid = false,
1102
+ onChange,
1103
+ style,
1104
+ value,
1105
+ ...textareaProps
1106
+ }, ref) {
1107
+ const textAreaRef = (0, import_react13.useRef)(null);
1108
+ (0, import_react13.useLayoutEffect)(() => {
1109
+ if (autoGrow && textAreaRef.current) resizeTextArea(textAreaRef.current);
1110
+ }, [autoGrow, autoGrowMaxHeight, value]);
1111
+ function setTextAreaRef(element) {
1112
+ textAreaRef.current = element;
1113
+ assignRef2(ref, element);
1114
+ if (autoGrow && element) resizeTextArea(element);
1115
+ }
1116
+ function handleChange(event) {
1117
+ if (autoGrow && value === void 0) resizeTextArea(event.currentTarget);
1118
+ onChange?.(event);
1119
+ }
1120
+ const textareaStyle = autoGrow ? {
1121
+ ...style,
1122
+ maxHeight: typeof autoGrowMaxHeight === "number" ? `${autoGrowMaxHeight}px` : autoGrowMaxHeight
1123
+ } : style;
1124
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1125
+ "textarea",
1126
+ {
1127
+ ...textareaProps,
1128
+ ref: setTextAreaRef,
1129
+ className: cx(
1130
+ "ow-textarea",
1131
+ bare && "ow-textarea--bare",
1132
+ isInvalid && !bare && "ow-textarea--invalid",
1133
+ autoGrow && "ow-textarea--auto-grow",
1134
+ className
1135
+ ),
1136
+ "aria-invalid": isInvalid || void 0,
1137
+ style: textareaStyle,
1138
+ value,
1139
+ onChange: handleChange
1140
+ }
1141
+ );
1142
+ });
1143
+
1144
+ // src/components/Select/Select.tsx
1145
+ var import_react16 = require("react");
1146
+
1147
+ // src/hooks/useFloating.ts
1148
+ var import_react14 = require("react");
1149
+ var margin = 8;
1150
+ function useFloating({
1151
+ open,
1152
+ anchorRef,
1153
+ floatingRef,
1154
+ placement = "bottom-start",
1155
+ offset = 4,
1156
+ matchWidth = false,
1157
+ maxHeight = 360
1158
+ }) {
1159
+ const [style, setStyle] = (0, import_react14.useState)({
1160
+ position: "fixed",
1161
+ inset: "auto",
1162
+ left: 0,
1163
+ right: "auto",
1164
+ top: 0,
1165
+ bottom: "auto",
1166
+ visibility: "hidden"
1167
+ });
1168
+ const place = (0, import_react14.useCallback)(() => {
1169
+ const anchor = anchorRef.current;
1170
+ const floating = floatingRef.current;
1171
+ if (!anchor || !floating) return;
1172
+ const rect = anchor.getBoundingClientRect();
1173
+ const width = Math.max(floating.offsetWidth, matchWidth ? rect.width : 0);
1174
+ const height = floating.scrollHeight;
1175
+ const below = window.innerHeight - rect.bottom - offset - margin;
1176
+ const above = rect.top - offset - margin;
1177
+ const wantsTop = placement.startsWith("top");
1178
+ const fitsBelow = height <= below;
1179
+ const fitsAbove = height <= above;
1180
+ const top = wantsTop ? fitsAbove || above > below : !fitsBelow && above > below;
1181
+ const align = placement.endsWith("start") ? "start" : placement.endsWith("end") ? "end" : "center";
1182
+ let left = align === "start" ? rect.left : align === "end" ? rect.right - width : rect.left + rect.width / 2 - width / 2;
1183
+ left = Math.min(Math.max(margin, left), window.innerWidth - width - margin);
1184
+ floating.dataset.side = top ? "top" : "bottom";
1185
+ setStyle({
1186
+ position: "fixed",
1187
+ inset: "auto",
1188
+ margin: 0,
1189
+ left,
1190
+ right: "auto",
1191
+ top: top ? "auto" : rect.bottom + offset,
1192
+ bottom: top ? window.innerHeight - rect.top + offset : "auto",
1193
+ minWidth: matchWidth ? rect.width : void 0,
1194
+ maxHeight: Math.max(120, Math.min(maxHeight, top ? above : below)),
1195
+ ["--ow-floating-origin"]: `${top ? "bottom" : "top"} ${align === "start" ? "left" : align === "end" ? "right" : "center"}`
1196
+ });
1197
+ }, [anchorRef, floatingRef, placement, offset, matchWidth, maxHeight]);
1198
+ (0, import_react14.useLayoutEffect)(() => {
1199
+ const floating = floatingRef.current;
1200
+ if (!open || !floating) return;
1201
+ try {
1202
+ if (!floating.matches(":popover-open")) floating.showPopover();
1203
+ } catch {
1204
+ }
1205
+ place();
1206
+ return () => {
1207
+ try {
1208
+ if (floating.matches(":popover-open")) floating.hidePopover();
1209
+ } catch {
1210
+ }
1211
+ };
1212
+ }, [open, floatingRef, place]);
1213
+ (0, import_react14.useEffect)(() => {
1214
+ if (!open) return;
1215
+ const onScroll = (event) => {
1216
+ if (floatingRef.current?.contains(event.target)) return;
1217
+ place();
1218
+ };
1219
+ const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(() => place());
1220
+ if (floatingRef.current) observer?.observe(floatingRef.current);
1221
+ window.addEventListener("scroll", onScroll, true);
1222
+ window.addEventListener("resize", place);
1223
+ return () => {
1224
+ observer?.disconnect();
1225
+ window.removeEventListener("scroll", onScroll, true);
1226
+ window.removeEventListener("resize", place);
1227
+ };
1228
+ }, [open, place, floatingRef]);
1229
+ return style;
1230
+ }
1231
+ function useDismiss(open, refs, onDismiss) {
1232
+ (0, import_react14.useEffect)(() => {
1233
+ if (!open) return;
1234
+ const onPointerDown = (event) => {
1235
+ const target = event.target;
1236
+ if (refs.every((ref) => !ref.current?.contains(target))) onDismiss("outside");
1237
+ };
1238
+ const onKeyDown = (event) => {
1239
+ if (event.key !== "Escape" || event.defaultPrevented) return;
1240
+ event.preventDefault();
1241
+ event.stopPropagation();
1242
+ onDismiss("escape");
1243
+ };
1244
+ document.addEventListener("pointerdown", onPointerDown, true);
1245
+ document.addEventListener("keydown", onKeyDown, true);
1246
+ return () => {
1247
+ document.removeEventListener("pointerdown", onPointerDown, true);
1248
+ document.removeEventListener("keydown", onKeyDown, true);
1249
+ };
1250
+ }, [open, onDismiss]);
1251
+ }
1252
+ var manualPopover = { popover: "manual" };
1253
+
1254
+ // src/hooks/usePresence.ts
1255
+ var import_react15 = require("react");
1256
+ var exitDuration = 140;
1257
+ function usePresence(open, exitMs = exitDuration) {
1258
+ const [mounted, setMounted] = (0, import_react15.useState)(open);
1259
+ if (open && !mounted) setMounted(true);
1260
+ (0, import_react15.useEffect)(() => {
1261
+ if (open || !mounted) return void 0;
1262
+ const reduceMotion = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
1263
+ const timer = window.setTimeout(() => setMounted(false), reduceMotion ? 0 : exitMs);
1264
+ return () => window.clearTimeout(timer);
1265
+ }, [open, mounted, exitMs]);
1266
+ return { mounted: open || mounted, state: open ? "open" : "closed" };
1267
+ }
1268
+
1269
+ // src/components/Select/Select.tsx
1270
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1271
+ var menuGap = 4;
1272
+ var menuMaxHeight = 288;
1273
+ var typeaheadResetMs = 600;
1274
+ function isGroup(item) {
1275
+ return "options" in item;
1276
+ }
1277
+ function textOf(option) {
1278
+ return option.textValue ?? (typeof option.label === "string" ? option.label : option.value);
1279
+ }
1280
+ function Select({
1281
+ value,
1282
+ options,
1283
+ onChange,
1284
+ "aria-label": ariaLabel,
1285
+ "aria-labelledby": ariaLabelledBy,
1286
+ "aria-describedby": ariaDescribedBy,
1287
+ id,
1288
+ disabled = false,
1289
+ placeholder = "Select\u2026",
1290
+ size = "md",
1291
+ isInvalid = false,
1292
+ className,
1293
+ valueClassName
1294
+ }) {
1295
+ const listboxId = (0, import_react16.useId)();
1296
+ const optionIdPrefix = (0, import_react16.useId)();
1297
+ const triggerRef = (0, import_react16.useRef)(null);
1298
+ const menuRef = (0, import_react16.useRef)(null);
1299
+ const typeahead = (0, import_react16.useRef)({ text: "", timer: 0 });
1300
+ const [isOpen, setIsOpen] = (0, import_react16.useState)(false);
1301
+ const [activeIndex, setActiveIndex] = (0, import_react16.useState)(-1);
1302
+ const flat = (0, import_react16.useMemo)(() => options.flatMap((item) => isGroup(item) ? item.options : [item]), [options]);
1303
+ const selectedIndex = flat.findIndex((option) => option.value === value);
1304
+ const selected = flat[selectedIndex];
1305
+ const optionId = (index) => `${optionIdPrefix}-${index}`;
1306
+ const enabledFrom = (0, import_react16.useCallback)(
1307
+ (start, step) => {
1308
+ for (let index = start; index >= 0 && index < flat.length; index += step) {
1309
+ if (!flat[index].disabled) return index;
1310
+ }
1311
+ return -1;
1312
+ },
1313
+ [flat]
1314
+ );
1315
+ const { mounted, state } = usePresence(isOpen);
1316
+ const floatingStyle = useFloating({
1317
+ open: mounted,
1318
+ anchorRef: triggerRef,
1319
+ floatingRef: menuRef,
1320
+ offset: menuGap,
1321
+ matchWidth: true,
1322
+ maxHeight: menuMaxHeight
1323
+ });
1324
+ function open(startAt) {
1325
+ if (disabled || isOpen) return;
1326
+ setActiveIndex(
1327
+ startAt === "first" ? enabledFrom(0, 1) : startAt === "last" ? enabledFrom(flat.length - 1, -1) : selectedIndex >= 0 && !flat[selectedIndex].disabled ? selectedIndex : enabledFrom(0, 1)
1328
+ );
1329
+ setIsOpen(true);
1330
+ }
1331
+ function close() {
1332
+ setIsOpen(false);
1333
+ }
1334
+ function choose(index) {
1335
+ const option = flat[index];
1336
+ if (!option || option.disabled) return;
1337
+ close();
1338
+ triggerRef.current?.focus();
1339
+ if (option.value !== value) onChange(option.value);
1340
+ }
1341
+ (0, import_react16.useEffect)(() => {
1342
+ if (!isOpen || activeIndex < 0) return;
1343
+ document.getElementById(optionId(activeIndex))?.scrollIntoView({ block: "nearest" });
1344
+ }, [isOpen, activeIndex]);
1345
+ (0, import_react16.useEffect)(() => {
1346
+ if (!isOpen) return;
1347
+ const onPointerDown = (event) => {
1348
+ const target = event.target;
1349
+ if (!menuRef.current?.contains(target) && !triggerRef.current?.contains(target)) close();
1350
+ };
1351
+ document.addEventListener("pointerdown", onPointerDown, true);
1352
+ return () => document.removeEventListener("pointerdown", onPointerDown, true);
1353
+ }, [isOpen]);
1354
+ (0, import_react16.useEffect)(() => {
1355
+ if (disabled) setIsOpen(false);
1356
+ }, [disabled]);
1357
+ (0, import_react16.useEffect)(() => () => window.clearTimeout(typeahead.current.timer), []);
1358
+ function findByTyping(key) {
1359
+ const state2 = typeahead.current;
1360
+ window.clearTimeout(state2.timer);
1361
+ state2.text += key.toLowerCase();
1362
+ state2.timer = window.setTimeout(() => {
1363
+ state2.text = "";
1364
+ }, typeaheadResetMs);
1365
+ const from = isOpen ? activeIndex : selectedIndex;
1366
+ const repeated = state2.text.length > 1 && [...state2.text].every((letter) => letter === state2.text[0]);
1367
+ const search = repeated ? state2.text[0] : state2.text;
1368
+ const start = repeated || state2.text.length === 1 ? from + 1 : from;
1369
+ for (let offset = 0; offset < flat.length; offset += 1) {
1370
+ const index = (Math.max(start, 0) + offset) % flat.length;
1371
+ const option = flat[index];
1372
+ if (!option.disabled && textOf(option).toLowerCase().startsWith(search)) {
1373
+ if (isOpen) setActiveIndex(index);
1374
+ else if (option.value !== value) onChange(option.value);
1375
+ return;
1376
+ }
1377
+ }
1378
+ }
1379
+ function onKeyDown(event) {
1380
+ if (disabled) return;
1381
+ const { key } = event;
1382
+ if (!isOpen) {
1383
+ if (key === "ArrowDown" || key === "ArrowUp" || key === "Enter" || key === " ") {
1384
+ event.preventDefault();
1385
+ open(key === "ArrowUp" && selectedIndex < 0 ? "last" : void 0);
1386
+ } else if (key.length === 1 && !event.metaKey && !event.ctrlKey) {
1387
+ findByTyping(key);
1388
+ }
1389
+ return;
1390
+ }
1391
+ switch (key) {
1392
+ case "ArrowDown": {
1393
+ event.preventDefault();
1394
+ const next = enabledFrom(activeIndex + 1, 1);
1395
+ if (next >= 0) setActiveIndex(next);
1396
+ return;
1397
+ }
1398
+ case "ArrowUp": {
1399
+ event.preventDefault();
1400
+ const previous = enabledFrom(activeIndex - 1, -1);
1401
+ if (previous >= 0) setActiveIndex(previous);
1402
+ return;
1403
+ }
1404
+ case "Home":
1405
+ case "PageUp":
1406
+ event.preventDefault();
1407
+ setActiveIndex(enabledFrom(0, 1));
1408
+ return;
1409
+ case "End":
1410
+ case "PageDown":
1411
+ event.preventDefault();
1412
+ setActiveIndex(enabledFrom(flat.length - 1, -1));
1413
+ return;
1414
+ case "Enter":
1415
+ event.preventDefault();
1416
+ choose(activeIndex);
1417
+ return;
1418
+ case " ":
1419
+ event.preventDefault();
1420
+ if (typeahead.current.text) findByTyping(" ");
1421
+ else choose(activeIndex);
1422
+ return;
1423
+ case "Escape":
1424
+ event.preventDefault();
1425
+ event.stopPropagation();
1426
+ close();
1427
+ return;
1428
+ case "Tab":
1429
+ close();
1430
+ return;
1431
+ default:
1432
+ if (key.length === 1 && !event.metaKey && !event.ctrlKey) findByTyping(key);
1433
+ }
1434
+ }
1435
+ let flatIndex = -1;
1436
+ const renderOption = (option) => {
1437
+ flatIndex += 1;
1438
+ const index = flatIndex;
1439
+ const isSelected = index === selectedIndex;
1440
+ const isActive = index === activeIndex;
1441
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1442
+ "div",
1443
+ {
1444
+ id: optionId(index),
1445
+ role: "option",
1446
+ "aria-selected": isSelected,
1447
+ "aria-disabled": option.disabled || void 0,
1448
+ className: cx("ow-option", {
1449
+ "ow-option--active": isActive && !option.disabled,
1450
+ "ow-option--selected": isSelected,
1451
+ "ow-option--disabled": Boolean(option.disabled)
1452
+ }),
1453
+ onPointerMove: () => {
1454
+ if (!option.disabled && activeIndex !== index) setActiveIndex(index);
1455
+ },
1456
+ onMouseDown: (event) => event.preventDefault(),
1457
+ onClick: () => choose(index),
1458
+ children: [
1459
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ow-option__check", children: isSelected ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CheckIcon, { size: 14 }) : null }),
1460
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ow-option__text", children: [
1461
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: cx("ow-option__label", valueClassName), children: option.label }),
1462
+ option.description ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ow-option__description", children: option.description }) : null
1463
+ ] })
1464
+ ]
1465
+ },
1466
+ `${option.value}-${index}`
1467
+ );
1468
+ };
1469
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1470
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1471
+ "button",
1472
+ {
1473
+ ref: triggerRef,
1474
+ id,
1475
+ type: "button",
1476
+ role: "combobox",
1477
+ "aria-haspopup": "listbox",
1478
+ "aria-expanded": isOpen,
1479
+ "aria-controls": isOpen ? listboxId : void 0,
1480
+ "aria-activedescendant": isOpen && activeIndex >= 0 ? optionId(activeIndex) : void 0,
1481
+ "aria-label": ariaLabel,
1482
+ "aria-labelledby": ariaLabelledBy,
1483
+ "aria-describedby": ariaDescribedBy,
1484
+ "aria-invalid": isInvalid || void 0,
1485
+ disabled,
1486
+ title: selected ? textOf(selected) : void 0,
1487
+ className: cx("ow-select", `ow-select--${size}`, { "ow-select--open": isOpen, "ow-select--invalid": isInvalid && !isOpen }, className),
1488
+ onClick: () => isOpen ? close() : open(),
1489
+ onKeyDown,
1490
+ onBlur: (event) => {
1491
+ if (!menuRef.current?.contains(event.relatedTarget)) close();
1492
+ },
1493
+ children: [
1494
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: cx("ow-select__value", !selected && "ow-select__value--placeholder", valueClassName), children: selected ? selected.label : placeholder }),
1495
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronDownIcon, { size: size === "sm" ? 14 : 16, className: "ow-select__chevron" })
1496
+ ]
1497
+ }
1498
+ ),
1499
+ mounted ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1500
+ "div",
1501
+ {
1502
+ ref: menuRef,
1503
+ ...manualPopover,
1504
+ "data-state": state,
1505
+ id: listboxId,
1506
+ role: "listbox",
1507
+ "aria-label": ariaLabel,
1508
+ "aria-labelledby": ariaLabelledBy,
1509
+ tabIndex: -1,
1510
+ className: cx("ow-listbox", "ow-floating", `ow-listbox--${size}`),
1511
+ style: floatingStyle,
1512
+ children: [
1513
+ options.map(
1514
+ (item, groupIndex) => isGroup(item) ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { role: "group", "aria-label": item.label, className: "ow-listbox__group", children: [
1515
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ow-listbox__group-label", "aria-hidden": "true", children: item.label }),
1516
+ item.options.map(renderOption)
1517
+ ] }, `group-${item.label}-${groupIndex}`) : renderOption(item)
1518
+ ),
1519
+ flat.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ow-listbox__empty", children: "No options" }) : null
1520
+ ]
1521
+ }
1522
+ ) : null
1523
+ ] });
1524
+ }
1525
+
1526
+ // src/components/Combobox/Combobox.tsx
1527
+ var import_react17 = require("react");
1528
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1529
+ function assignRef3(ref, value) {
1530
+ if (typeof ref === "function") ref(value);
1531
+ else if (ref) ref.current = value;
1532
+ }
1533
+ var Combobox = (0, import_react17.forwardRef)(function Combobox2({
1534
+ options,
1535
+ value,
1536
+ defaultValue = "",
1537
+ onChange,
1538
+ onInputChange,
1539
+ placeholder = "Search\u2026",
1540
+ emptyMessage = "No matches",
1541
+ allowCustomValue = false,
1542
+ size = "md",
1543
+ isInvalid = false,
1544
+ disabled = false,
1545
+ id,
1546
+ className,
1547
+ ...aria
1548
+ }, ref) {
1549
+ const [selected, setSelected] = useControllableState(value, defaultValue, onChange);
1550
+ const labelOf = (v) => options.find((option) => option.value === v)?.label ?? (allowCustomValue ? v : "");
1551
+ const [text, setText] = (0, import_react17.useState)(() => labelOf(selected));
1552
+ const [isOpen, setOpen] = (0, import_react17.useState)(false);
1553
+ const [typed, setTyped] = (0, import_react17.useState)(false);
1554
+ const [active, setActive] = (0, import_react17.useState)(-1);
1555
+ const inputRef = (0, import_react17.useRef)(null);
1556
+ const fieldRef = (0, import_react17.useRef)(null);
1557
+ const listRef = (0, import_react17.useRef)(null);
1558
+ const listId = (0, import_react17.useId)();
1559
+ const optionId = (index) => `${listId}-${index}`;
1560
+ const results = (0, import_react17.useMemo)(() => {
1561
+ const query = text.trim().toLowerCase();
1562
+ if (!typed || !query) return options;
1563
+ return options.filter(
1564
+ (option) => option.label.toLowerCase().includes(query) || typeof option.description === "string" && option.description.toLowerCase().includes(query)
1565
+ );
1566
+ }, [options, text, typed]);
1567
+ (0, import_react17.useEffect)(() => {
1568
+ if (!isOpen) setText(labelOf(selected));
1569
+ }, [selected, options]);
1570
+ const { mounted, state } = usePresence(isOpen);
1571
+ const style = useFloating({ open: mounted, anchorRef: fieldRef, floatingRef: listRef, matchWidth: true, maxHeight: 288 });
1572
+ function open() {
1573
+ if (disabled || isOpen) return;
1574
+ setOpen(true);
1575
+ const index = results.findIndex((option) => option.value === selected);
1576
+ setActive(index >= 0 ? index : results.findIndex((option) => !option.disabled));
1577
+ }
1578
+ function close(restore = true) {
1579
+ setOpen(false);
1580
+ setTyped(false);
1581
+ if (!restore) return;
1582
+ if (allowCustomValue) {
1583
+ if (text !== labelOf(selected)) {
1584
+ const match = options.find((option) => option.label.toLowerCase() === text.trim().toLowerCase());
1585
+ setSelected(match ? match.value : text);
1586
+ }
1587
+ } else if (text.trim() === "") setSelected("");
1588
+ else setText(labelOf(selected));
1589
+ }
1590
+ useDismiss(isOpen, [fieldRef, listRef], () => close());
1591
+ function choose(option) {
1592
+ if (!option || option.disabled) return;
1593
+ setSelected(option.value);
1594
+ setText(option.label);
1595
+ setOpen(false);
1596
+ setTyped(false);
1597
+ }
1598
+ function move(step) {
1599
+ if (!results.length) return;
1600
+ let next = active;
1601
+ for (let tries = 0; tries < results.length; tries += 1) {
1602
+ next = (next + step + results.length) % results.length;
1603
+ if (!results[next].disabled) break;
1604
+ }
1605
+ setActive(next);
1606
+ }
1607
+ (0, import_react17.useEffect)(() => {
1608
+ if (isOpen && active >= 0) document.getElementById(optionId(active))?.scrollIntoView({ block: "nearest" });
1609
+ }, [active, isOpen]);
1610
+ function onKeyDown(event) {
1611
+ switch (event.key) {
1612
+ case "ArrowDown":
1613
+ event.preventDefault();
1614
+ if (!isOpen) open();
1615
+ else move(1);
1616
+ break;
1617
+ case "ArrowUp":
1618
+ event.preventDefault();
1619
+ if (!isOpen) open();
1620
+ else move(-1);
1621
+ break;
1622
+ case "Enter":
1623
+ if (isOpen && active >= 0) {
1624
+ event.preventDefault();
1625
+ choose(results[active]);
1626
+ } else if (isOpen) close();
1627
+ break;
1628
+ case "Escape":
1629
+ if (isOpen) return;
1630
+ if (text) {
1631
+ event.preventDefault();
1632
+ setText("");
1633
+ setSelected("");
1634
+ }
1635
+ break;
1636
+ case "Tab":
1637
+ if (isOpen) close();
1638
+ break;
1639
+ }
1640
+ }
1641
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1642
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1643
+ "div",
1644
+ {
1645
+ ref: fieldRef,
1646
+ className: cx(
1647
+ "ow-input-group",
1648
+ "ow-combobox",
1649
+ size === "sm" && "ow-input-group--sm",
1650
+ isInvalid && "ow-input-group--invalid",
1651
+ disabled && "ow-input-group--disabled",
1652
+ className
1653
+ ),
1654
+ children: [
1655
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1656
+ "input",
1657
+ {
1658
+ ref: (element) => {
1659
+ inputRef.current = element;
1660
+ assignRef3(ref, element);
1661
+ },
1662
+ id,
1663
+ className: "ow-input-group__input",
1664
+ role: "combobox",
1665
+ "aria-autocomplete": "list",
1666
+ "aria-expanded": isOpen,
1667
+ "aria-controls": isOpen ? listId : void 0,
1668
+ "aria-activedescendant": isOpen && active >= 0 ? optionId(active) : void 0,
1669
+ "aria-invalid": isInvalid || void 0,
1670
+ autoComplete: "off",
1671
+ disabled,
1672
+ placeholder,
1673
+ value: text,
1674
+ onChange: (event) => {
1675
+ setText(event.target.value);
1676
+ setTyped(true);
1677
+ onInputChange?.(event.target.value);
1678
+ if (!isOpen) setOpen(true);
1679
+ setActive(0);
1680
+ },
1681
+ onClick: open,
1682
+ onKeyDown,
1683
+ ...aria
1684
+ }
1685
+ ),
1686
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1687
+ "button",
1688
+ {
1689
+ type: "button",
1690
+ className: "ow-combobox__toggle",
1691
+ tabIndex: -1,
1692
+ "aria-label": isOpen ? "Hide options" : "Show options",
1693
+ disabled,
1694
+ onMouseDown: (event) => event.preventDefault(),
1695
+ onClick: () => {
1696
+ if (isOpen) close();
1697
+ else {
1698
+ open();
1699
+ inputRef.current?.focus();
1700
+ }
1701
+ },
1702
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ChevronDownIcon, { size: size === "sm" ? 14 : 16, className: cx("ow-select__chevron", isOpen && "ow-combobox__chevron--open") })
1703
+ }
1704
+ )
1705
+ ]
1706
+ }
1707
+ ),
1708
+ mounted ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1709
+ "div",
1710
+ {
1711
+ ref: listRef,
1712
+ ...manualPopover,
1713
+ "data-state": state,
1714
+ id: listId,
1715
+ role: "listbox",
1716
+ "aria-label": aria["aria-label"],
1717
+ "aria-labelledby": aria["aria-labelledby"],
1718
+ className: cx("ow-listbox", "ow-floating", `ow-listbox--${size}`),
1719
+ style,
1720
+ children: [
1721
+ results.map((option, index) => {
1722
+ const isSelected = option.value === selected;
1723
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1724
+ "div",
1725
+ {
1726
+ id: optionId(index),
1727
+ role: "option",
1728
+ "aria-selected": isSelected,
1729
+ "aria-disabled": option.disabled || void 0,
1730
+ className: cx("ow-option", {
1731
+ "ow-option--active": index === active && !option.disabled,
1732
+ "ow-option--selected": isSelected,
1733
+ "ow-option--disabled": Boolean(option.disabled)
1734
+ }),
1735
+ onPointerMove: () => !option.disabled && setActive(index),
1736
+ onMouseDown: (event) => event.preventDefault(),
1737
+ onClick: () => choose(option),
1738
+ children: [
1739
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ow-option__check", children: isSelected ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CheckIcon, { size: 14 }) : null }),
1740
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ow-option__text", children: [
1741
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ow-option__label", children: option.label }),
1742
+ option.description ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ow-option__description", children: option.description }) : null
1743
+ ] })
1744
+ ]
1745
+ },
1746
+ option.value
1747
+ );
1748
+ }),
1749
+ results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "ow-listbox__empty", role: "presentation", children: emptyMessage }) : null
1750
+ ]
1751
+ }
1752
+ ) : null
1753
+ ] });
1754
+ });
1755
+
1756
+ // src/components/Checkbox/Checkbox.tsx
1757
+ var import_react18 = require("react");
1758
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1759
+ var CheckboxGroupContext = (0, import_react18.createContext)(null);
1760
+ function assignRef4(ref, value) {
1761
+ if (typeof ref === "function") ref(value);
1762
+ else if (ref) ref.current = value;
1763
+ }
1764
+ var Checkbox = (0, import_react18.forwardRef)(function Checkbox2({
1765
+ className,
1766
+ size = "md",
1767
+ tone = "primary",
1768
+ indeterminate = false,
1769
+ children,
1770
+ description,
1771
+ value,
1772
+ checked,
1773
+ onChange,
1774
+ disabled,
1775
+ name,
1776
+ "aria-describedby": describedBy,
1777
+ ...inputProps
1778
+ }, ref) {
1779
+ const group = (0, import_react18.useContext)(CheckboxGroupContext);
1780
+ const innerRef = (0, import_react18.useRef)(null);
1781
+ const descriptionId = (0, import_react18.useId)();
1782
+ const inGroup = group !== null && value !== void 0;
1783
+ (0, import_react18.useEffect)(() => {
1784
+ if (innerRef.current) innerRef.current.indeterminate = indeterminate;
1785
+ }, [indeterminate]);
1786
+ const box = /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1787
+ "span",
1788
+ {
1789
+ className: cx(
1790
+ "ow-checkbox",
1791
+ `ow-checkbox--${size}`,
1792
+ tone === "danger" && "ow-checkbox--danger",
1793
+ children === void 0 && className
1794
+ ),
1795
+ children: [
1796
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1797
+ "input",
1798
+ {
1799
+ ref: (element) => {
1800
+ innerRef.current = element;
1801
+ assignRef4(ref, element);
1802
+ },
1803
+ type: "checkbox",
1804
+ className: "ow-checkbox__input",
1805
+ value,
1806
+ name: inGroup ? group.name : name,
1807
+ checked: inGroup ? group.value.includes(String(value)) : checked,
1808
+ disabled: disabled || inGroup && group.disabled,
1809
+ "aria-describedby": [describedBy, description ? descriptionId : void 0].filter(Boolean).join(" ") || void 0,
1810
+ onChange: (event) => {
1811
+ onChange?.(event);
1812
+ if (inGroup) group.toggle(String(value), event.target.checked);
1813
+ },
1814
+ ...inputProps
1815
+ }
1816
+ ),
1817
+ indeterminate ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MinusIcon, { className: "ow-checkbox__check ow-checkbox__check--dash", size: size === "sm" ? 10 : 12, strokeWidth: 3 }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CheckIcon, { className: "ow-checkbox__check", size: size === "sm" ? 10 : 12, strokeWidth: 3 })
1818
+ ]
1819
+ }
1820
+ );
1821
+ if (children === void 0) return box;
1822
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: cx("ow-check-label", (disabled || inGroup && group.disabled) && "ow-check-label--disabled", className), children: [
1823
+ box,
1824
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "ow-check-label__text", children: [
1825
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children }),
1826
+ description ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { id: descriptionId, className: "ow-check-label__description", children: description }) : null
1827
+ ] })
1828
+ ] });
1829
+ });
1830
+ function CheckboxGroup({
1831
+ label,
1832
+ description,
1833
+ value,
1834
+ defaultValue = [],
1835
+ onChange,
1836
+ orientation = "vertical",
1837
+ error,
1838
+ disabled = false,
1839
+ name,
1840
+ children,
1841
+ className
1842
+ }) {
1843
+ const [current, setCurrent] = useControllableState(value, defaultValue, onChange);
1844
+ const generatedName = (0, import_react18.useId)();
1845
+ const errorId = (0, import_react18.useId)();
1846
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1847
+ CheckboxGroupContext.Provider,
1848
+ {
1849
+ value: {
1850
+ value: current,
1851
+ name: name ?? generatedName,
1852
+ disabled,
1853
+ toggle(item, checked) {
1854
+ setCurrent(checked ? [...current.filter((v) => v !== item), item] : current.filter((v) => v !== item));
1855
+ }
1856
+ },
1857
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1858
+ Fieldset,
1859
+ {
1860
+ legend: label,
1861
+ description,
1862
+ error,
1863
+ errorId,
1864
+ className: cx(orientation === "horizontal" && "ow-fieldset--horizontal", className),
1865
+ children
1866
+ }
1867
+ )
1868
+ }
1869
+ );
1870
+ }
1871
+ function Fieldset({ legend, description, error, errorId, disabled, children, className }) {
1872
+ const generatedId = (0, import_react18.useId)();
1873
+ const descriptionId = `${generatedId}-description`;
1874
+ const resolvedErrorId = errorId ?? `${generatedId}-error`;
1875
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1876
+ "fieldset",
1877
+ {
1878
+ className: cx("ow-fieldset", className),
1879
+ disabled,
1880
+ "aria-describedby": [description ? descriptionId : "", error ? resolvedErrorId : ""].filter(Boolean).join(" ") || void 0,
1881
+ children: [
1882
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("legend", { className: "ow-fieldset__legend", children: legend }),
1883
+ description ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { id: descriptionId, className: "ow-fieldset__description", children: description }) : null,
1884
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ow-fieldset__content", children }),
1885
+ error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { id: resolvedErrorId, role: "alert", className: "ow-field__error", children: error }) : null
1886
+ ]
1887
+ }
1888
+ );
1889
+ }
1890
+
1891
+ // src/components/RadioGroup/RadioGroup.tsx
1892
+ var import_react19 = require("react");
1893
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1894
+ var RadioGroupContext = (0, import_react19.createContext)(null);
1895
+ function RadioGroup({
1896
+ label,
1897
+ description,
1898
+ value,
1899
+ defaultValue = "",
1900
+ onChange,
1901
+ orientation = "vertical",
1902
+ variant = "default",
1903
+ error,
1904
+ disabled = false,
1905
+ name,
1906
+ children,
1907
+ className
1908
+ }) {
1909
+ const [current, select] = useControllableState(value, defaultValue, onChange);
1910
+ const generatedName = (0, import_react19.useId)();
1911
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(RadioGroupContext.Provider, { value: { name: name ?? generatedName, value: current, select, disabled }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1912
+ Fieldset,
1913
+ {
1914
+ legend: label,
1915
+ description,
1916
+ error,
1917
+ className: cx(
1918
+ "ow-radio-group",
1919
+ orientation === "horizontal" && "ow-fieldset--horizontal",
1920
+ variant === "cards" && "ow-radio-group--cards",
1921
+ className
1922
+ ),
1923
+ children
1924
+ }
1925
+ ) });
1926
+ }
1927
+ function Radio({ value, children, description, disabled, className, ...inputProps }) {
1928
+ const group = (0, import_react19.useContext)(RadioGroupContext);
1929
+ const descriptionId = (0, import_react19.useId)();
1930
+ if (!group) throw new Error("Radio must be inside <RadioGroup>.");
1931
+ const isDisabled = disabled || group.disabled;
1932
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: cx("ow-check-label", "ow-radio-label", isDisabled && "ow-check-label--disabled", className), children: [
1933
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ow-radio", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1934
+ "input",
1935
+ {
1936
+ type: "radio",
1937
+ className: "ow-radio__input",
1938
+ name: group.name,
1939
+ value,
1940
+ checked: group.value === value,
1941
+ disabled: isDisabled,
1942
+ "aria-describedby": description ? descriptionId : void 0,
1943
+ onChange: () => group.select(value),
1944
+ ...inputProps
1945
+ }
1946
+ ) }),
1947
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ow-check-label__text", children: [
1948
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children }),
1949
+ description ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { id: descriptionId, className: "ow-check-label__description", children: description }) : null
1950
+ ] })
1951
+ ] });
1952
+ }
1953
+
1954
+ // src/components/Switch/Switch.tsx
1955
+ var import_react20 = require("react");
1956
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1957
+ var Switch = (0, import_react20.forwardRef)(function Switch2({ checked, onChange, label, className, disabled, ...buttonProps }, ref) {
1958
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1959
+ "button",
1960
+ {
1961
+ ref,
1962
+ type: "button",
1963
+ role: "switch",
1964
+ "aria-checked": checked,
1965
+ "aria-label": label,
1966
+ disabled,
1967
+ className: cx("ow-switch", checked && "ow-switch--on", className),
1968
+ onClick: () => onChange(!checked),
1969
+ ...buttonProps,
1970
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ow-switch__knob" })
1971
+ }
1972
+ );
1973
+ });
1974
+
1975
+ // src/components/Slider/Slider.tsx
1976
+ var import_react21 = require("react");
1977
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1978
+ function Slider({
1979
+ value,
1980
+ defaultValue,
1981
+ onChange,
1982
+ onChangeEnd,
1983
+ min = 0,
1984
+ max = 100,
1985
+ step = 1,
1986
+ label,
1987
+ showValue = true,
1988
+ formatValue = String,
1989
+ "aria-label": ariaLabel,
1990
+ disabled,
1991
+ className
1992
+ }) {
1993
+ const [current, setCurrent] = useControllableState(value, defaultValue ?? min, onChange);
1994
+ const labelId = (0, import_react21.useId)();
1995
+ const isRange = Array.isArray(current);
1996
+ const [low, high] = isRange ? current : [min, current];
1997
+ const pct = (n) => (n - min) / (max - min || 1) * 100;
1998
+ const style = { "--ow-slider-from": `${isRange ? pct(low) : 0}%`, "--ow-slider-to": `${pct(high)}%` };
1999
+ const display = isRange ? `${formatValue(low)} \u2013 ${formatValue(high)}` : formatValue(high);
2000
+ const end = () => onChangeEnd?.(current);
2001
+ const input = (which) => {
2002
+ const own = which === "low" ? low : high;
2003
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2004
+ "input",
2005
+ {
2006
+ type: "range",
2007
+ className: cx("ow-slider__input", isRange && `ow-slider__input--${which}`),
2008
+ style: which === "low" && low === high && pct(low) > 50 ? { zIndex: 3 } : void 0,
2009
+ min,
2010
+ max,
2011
+ step,
2012
+ value: own,
2013
+ disabled,
2014
+ "aria-labelledby": label ? labelId : void 0,
2015
+ "aria-label": label ? void 0 : isRange ? `${ariaLabel ?? "Range"}, ${which === "low" ? "minimum" : "maximum"}` : ariaLabel,
2016
+ "aria-valuetext": formatValue(own),
2017
+ onChange: (event) => {
2018
+ const n = Number(event.target.value);
2019
+ if (!isRange) setCurrent(n);
2020
+ else if (which === "low") setCurrent([Math.min(n, high), high]);
2021
+ else setCurrent([low, Math.max(n, low)]);
2022
+ },
2023
+ onPointerUp: end,
2024
+ onKeyUp: end
2025
+ }
2026
+ );
2027
+ };
2028
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: cx("ow-slider", disabled && "ow-slider--disabled", className), children: [
2029
+ label || showValue ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ow-slider__header", children: [
2030
+ label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { id: labelId, className: "ow-slider__label", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", {}),
2031
+ showValue ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("output", { className: "ow-slider__value", "aria-hidden": "true", children: display }) : null
2032
+ ] }) : null,
2033
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ow-slider__control", style, children: [
2034
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ow-slider__track", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ow-slider__fill" }) }),
2035
+ isRange ? input("low") : null,
2036
+ input("high")
2037
+ ] })
2038
+ ] });
2039
+ }
2040
+
2041
+ // src/components/FileDropZone/FileDropZone.tsx
2042
+ var import_react22 = require("react");
2043
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2044
+ function matches(file, accept) {
2045
+ if (!accept) return true;
2046
+ return accept.split(",").some((rule) => {
2047
+ const pattern = rule.trim().toLowerCase();
2048
+ if (!pattern) return false;
2049
+ if (pattern.startsWith(".")) return file.name.toLowerCase().endsWith(pattern);
2050
+ if (pattern.endsWith("/*")) return file.type.toLowerCase().startsWith(pattern.slice(0, -1));
2051
+ return file.type.toLowerCase() === pattern;
2052
+ });
2053
+ }
2054
+ var formatSize = (bytes) => bytes >= 1048576 ? `${Math.round(bytes / 104857.6) / 10} MB` : `${Math.round(bytes / 1024)} KB`;
2055
+ function FileDropZone({
2056
+ onFiles,
2057
+ accept,
2058
+ multiple = false,
2059
+ maxSize,
2060
+ label = "Drop files here, or browse",
2061
+ hint,
2062
+ error,
2063
+ icon: icon2,
2064
+ disabled = false,
2065
+ name,
2066
+ className
2067
+ }) {
2068
+ const inputRef = (0, import_react22.useRef)(null);
2069
+ const depth = (0, import_react22.useRef)(0);
2070
+ const [isDragging, setIsDragging] = (0, import_react22.useState)(false);
2071
+ const [problem, setProblem] = (0, import_react22.useState)();
2072
+ const hintId = (0, import_react22.useId)();
2073
+ function take(list) {
2074
+ if (!list || disabled) return;
2075
+ const files = [...list].slice(0, multiple ? void 0 : 1);
2076
+ const wrongType = files.find((file) => !matches(file, accept));
2077
+ const tooBig = maxSize ? files.find((file) => file.size > maxSize) : void 0;
2078
+ if (!multiple && list.length > 1) setProblem("Drop one file at a time.");
2079
+ else if (wrongType) setProblem(`\u201C${wrongType.name}\u201D isn't a file this accepts.`);
2080
+ else if (tooBig && maxSize) setProblem(`\u201C${tooBig.name}\u201D is over ${formatSize(maxSize)}.`);
2081
+ else {
2082
+ setProblem(void 0);
2083
+ if (files.length) onFiles(files);
2084
+ }
2085
+ }
2086
+ const hasFiles = (event) => event.dataTransfer.types.includes("Files");
2087
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2088
+ "label",
2089
+ {
2090
+ className: cx(
2091
+ "ow-dropzone",
2092
+ isDragging && "ow-dropzone--dragging",
2093
+ Boolean(error || problem) && "ow-dropzone--invalid",
2094
+ disabled && "ow-dropzone--disabled",
2095
+ className
2096
+ ),
2097
+ onDragEnter: (event) => {
2098
+ if (!hasFiles(event) || disabled) return;
2099
+ event.preventDefault();
2100
+ depth.current += 1;
2101
+ setIsDragging(true);
2102
+ },
2103
+ onDragOver: (event) => {
2104
+ if (!hasFiles(event) || disabled) return;
2105
+ event.preventDefault();
2106
+ event.dataTransfer.dropEffect = "copy";
2107
+ },
2108
+ onDragLeave: () => {
2109
+ depth.current = Math.max(0, depth.current - 1);
2110
+ if (depth.current === 0) setIsDragging(false);
2111
+ },
2112
+ onDrop: (event) => {
2113
+ if (!hasFiles(event)) return;
2114
+ event.preventDefault();
2115
+ depth.current = 0;
2116
+ setIsDragging(false);
2117
+ take(event.dataTransfer.files);
2118
+ },
2119
+ children: [
2120
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2121
+ "input",
2122
+ {
2123
+ ref: inputRef,
2124
+ type: "file",
2125
+ className: "ow-visually-hidden",
2126
+ accept,
2127
+ multiple,
2128
+ disabled,
2129
+ name,
2130
+ "aria-describedby": hintId,
2131
+ onChange: (event) => {
2132
+ take(event.target.files);
2133
+ event.target.value = "";
2134
+ }
2135
+ }
2136
+ ),
2137
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ow-dropzone__icon", children: icon2 ?? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(UploadIcon, { size: 20 }) }),
2138
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ow-dropzone__label", children: isDragging ? "Drop to add" : label }),
2139
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { id: hintId, className: "ow-dropzone__hint", "aria-live": "polite", children: error ?? problem ?? hint })
2140
+ ]
2141
+ }
2142
+ );
2143
+ }
2144
+
2145
+ // src/components/Calendar/Calendar.tsx
2146
+ var import_react23 = require("react");
2147
+
2148
+ // src/components/Calendar/dates.ts
2149
+ var pad = (n) => String(n).padStart(2, "0");
2150
+ function toISO(year, month, day) {
2151
+ const date = new Date(Date.UTC(year, month, day));
2152
+ return `${date.getUTCFullYear()}-${pad(date.getUTCMonth() + 1)}-${pad(date.getUTCDate())}`;
2153
+ }
2154
+ function parseISO(iso) {
2155
+ const [year, month, day] = iso.split("-").map(Number);
2156
+ return { year, month: month - 1, day };
2157
+ }
2158
+ function todayISO() {
2159
+ const now = /* @__PURE__ */ new Date();
2160
+ return toISO(now.getFullYear(), now.getMonth(), now.getDate());
2161
+ }
2162
+ function addDays(iso, days) {
2163
+ const { year, month, day } = parseISO(iso);
2164
+ return toISO(year, month, day + days);
2165
+ }
2166
+ function addMonths(iso, months) {
2167
+ const { year, month, day } = parseISO(iso);
2168
+ const lastDay = new Date(Date.UTC(year, month + months + 1, 0)).getUTCDate();
2169
+ return toISO(year, month + months, Math.min(day, lastDay));
2170
+ }
2171
+ function weekday(iso) {
2172
+ const { year, month, day } = parseISO(iso);
2173
+ return new Date(Date.UTC(year, month, day)).getUTCDay();
2174
+ }
2175
+ function toDate(iso) {
2176
+ const { year, month, day } = parseISO(iso);
2177
+ return new Date(Date.UTC(year, month, day));
2178
+ }
2179
+ function formatDate(iso, locale, options) {
2180
+ return new Intl.DateTimeFormat(locale, { ...options, timeZone: "UTC" }).format(toDate(iso));
2181
+ }
2182
+
2183
+ // src/components/Calendar/Calendar.tsx
2184
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2185
+ var Calendar = (0, import_react23.forwardRef)(function Calendar2({ value, defaultValue = "", onChange, min, max, isDateDisabled, locale, weekStartsOn = 1, autoFocus = false, className }, ref) {
2186
+ const [selected, setSelected] = useControllableState(value, defaultValue, onChange);
2187
+ const today = todayISO();
2188
+ const [focused, setFocused] = (0, import_react23.useState)(() => selected || clampDate(today, min, max));
2189
+ const [shouldFocus, setShouldFocus] = (0, import_react23.useState)(autoFocus);
2190
+ const gridRef = (0, import_react23.useRef)(null);
2191
+ (0, import_react23.useImperativeHandle)(ref, () => ({ focus: () => setShouldFocus(true) }), []);
2192
+ (0, import_react23.useEffect)(() => {
2193
+ if (selected) setFocused(selected);
2194
+ }, [selected]);
2195
+ (0, import_react23.useEffect)(() => {
2196
+ if (!shouldFocus) return;
2197
+ gridRef.current?.querySelector('button[tabindex="0"]')?.focus();
2198
+ setShouldFocus(false);
2199
+ }, [shouldFocus, focused]);
2200
+ const { year, month } = parseISO(focused);
2201
+ const first = toISO(year, month, 1);
2202
+ const monthIndex = year * 12 + month;
2203
+ const slide = (0, import_react23.useRef)({ month: monthIndex });
2204
+ if (slide.current.month !== monthIndex) {
2205
+ slide.current = { month: monthIndex, direction: monthIndex > slide.current.month ? "next" : "previous" };
2206
+ }
2207
+ const offset = (weekday(first) - weekStartsOn + 7) % 7;
2208
+ const gridStart = addDays(first, -offset);
2209
+ const weeks = (0, import_react23.useMemo)(() => Array.from({ length: 6 }, (_, w) => Array.from({ length: 7 }, (_2, d) => addDays(gridStart, w * 7 + d))), [gridStart]);
2210
+ const weekdayNames = weeks[0].map((date) => ({
2211
+ short: formatDate(date, locale, { weekday: "short" }),
2212
+ long: formatDate(date, locale, { weekday: "long" })
2213
+ }));
2214
+ const isDisabled = (date) => min !== void 0 && date < min || max !== void 0 && date > max || Boolean(isDateDisabled?.(date));
2215
+ function moveTo(date) {
2216
+ setFocused(clampDate(date, min, max));
2217
+ setShouldFocus(true);
2218
+ }
2219
+ function choose(date) {
2220
+ if (isDisabled(date)) return;
2221
+ setSelected(date);
2222
+ setFocused(date);
2223
+ }
2224
+ function onKeyDown(event, date) {
2225
+ const day = (weekday(date) - weekStartsOn + 7) % 7;
2226
+ const moves = {
2227
+ ArrowLeft: () => addDays(date, -1),
2228
+ ArrowRight: () => addDays(date, 1),
2229
+ ArrowUp: () => addDays(date, -7),
2230
+ ArrowDown: () => addDays(date, 7),
2231
+ Home: () => addDays(date, -day),
2232
+ End: () => addDays(date, 6 - day),
2233
+ PageUp: () => addMonths(date, event.shiftKey ? -12 : -1),
2234
+ PageDown: () => addMonths(date, event.shiftKey ? 12 : 1)
2235
+ };
2236
+ const move = moves[event.key];
2237
+ if (move) {
2238
+ event.preventDefault();
2239
+ moveTo(move());
2240
+ }
2241
+ }
2242
+ const monthLabel = formatDate(first, locale, { month: "long", year: "numeric" });
2243
+ const prevMonth = addMonths(first, -1);
2244
+ const nextMonth = addMonths(first, 1);
2245
+ const canGoBack = !min || toISO(year, month, 0) >= min;
2246
+ const canGoForward = !max || nextMonth <= max;
2247
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: cx("ow-calendar", className), children: [
2248
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ow-calendar__header", children: [
2249
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2250
+ "button",
2251
+ {
2252
+ type: "button",
2253
+ className: "ow-calendar__nav",
2254
+ "aria-label": `Previous month, ${formatDate(prevMonth, locale, { month: "long", year: "numeric" })}`,
2255
+ disabled: !canGoBack,
2256
+ onClick: () => setFocused(clampDate(addMonths(focused, -1), min, max)),
2257
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChevronLeftIcon, { size: 16 })
2258
+ }
2259
+ ),
2260
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { className: "ow-calendar__title", "aria-live": "polite", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2261
+ "span",
2262
+ {
2263
+ className: cx("ow-calendar__title-text", slide.current.direction && `ow-calendar__slide--${slide.current.direction}`),
2264
+ children: monthLabel
2265
+ },
2266
+ monthIndex
2267
+ ) }),
2268
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2269
+ "button",
2270
+ {
2271
+ type: "button",
2272
+ className: "ow-calendar__nav",
2273
+ "aria-label": `Next month, ${formatDate(nextMonth, locale, { month: "long", year: "numeric" })}`,
2274
+ disabled: !canGoForward,
2275
+ onClick: () => setFocused(clampDate(addMonths(focused, 1), min, max)),
2276
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChevronRightIcon, { size: 16 })
2277
+ }
2278
+ )
2279
+ ] }),
2280
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("table", { ref: gridRef, role: "grid", className: "ow-calendar__grid", "aria-label": monthLabel, children: [
2281
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tr", { children: weekdayNames.map((name) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("th", { scope: "col", abbr: name.long, className: "ow-calendar__weekday", children: name.short.slice(0, 2) }, name.long)) }) }),
2282
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tbody", { className: cx(slide.current.direction && `ow-calendar__slide--${slide.current.direction}`), children: weeks.map((week) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tr", { children: week.map((date) => {
2283
+ const inMonth = parseISO(date).month === month;
2284
+ const isSelected = date === selected;
2285
+ const disabled = isDisabled(date);
2286
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { role: "gridcell", "aria-selected": isSelected, className: "ow-calendar__cell", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2287
+ "button",
2288
+ {
2289
+ type: "button",
2290
+ tabIndex: date === focused ? 0 : -1,
2291
+ "aria-label": formatDate(date, locale, { dateStyle: "full" }),
2292
+ "aria-current": date === today ? "date" : void 0,
2293
+ "aria-disabled": disabled || void 0,
2294
+ className: cx("ow-calendar__day", {
2295
+ "ow-calendar__day--outside": !inMonth,
2296
+ "ow-calendar__day--selected": isSelected,
2297
+ "ow-calendar__day--today": date === today,
2298
+ "ow-calendar__day--disabled": disabled
2299
+ }),
2300
+ onClick: () => choose(date),
2301
+ onKeyDown: (event) => onKeyDown(event, date),
2302
+ onFocus: () => date !== focused && setFocused(date),
2303
+ children: parseISO(date).day
2304
+ }
2305
+ ) }, date);
2306
+ }) }, week[0])) }, monthIndex)
2307
+ ] })
2308
+ ] });
2309
+ });
2310
+ function clampDate(date, min, max) {
2311
+ if (min && date < min) return min;
2312
+ if (max && date > max) return max;
2313
+ return date;
2314
+ }
2315
+
2316
+ // src/components/Calendar/DatePicker.tsx
2317
+ var import_react24 = require("react");
2318
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2319
+ function assignRef5(ref, value) {
2320
+ if (typeof ref === "function") ref(value);
2321
+ else if (ref) ref.current = value;
2322
+ }
2323
+ var DatePicker = (0, import_react24.forwardRef)(function DatePicker2({
2324
+ value,
2325
+ defaultValue = "",
2326
+ onChange,
2327
+ placeholder = "Pick a date",
2328
+ formatOptions = { dateStyle: "medium" },
2329
+ size = "md",
2330
+ isInvalid = false,
2331
+ disabled = false,
2332
+ id,
2333
+ className,
2334
+ locale,
2335
+ "aria-label": ariaLabel,
2336
+ "aria-labelledby": ariaLabelledBy,
2337
+ "aria-describedby": ariaDescribedBy,
2338
+ ...calendarProps
2339
+ }, ref) {
2340
+ const [date, setDate] = useControllableState(value, defaultValue, onChange);
2341
+ const [isOpen, setOpen] = (0, import_react24.useState)(false);
2342
+ const triggerRef = (0, import_react24.useRef)(null);
2343
+ const panelRef = (0, import_react24.useRef)(null);
2344
+ const panelId = (0, import_react24.useId)();
2345
+ const { mounted, state } = usePresence(isOpen);
2346
+ const style = useFloating({ open: mounted, anchorRef: triggerRef, floatingRef: panelRef, placement: "bottom-start", offset: 6 });
2347
+ const close = (0, import_react24.useCallback)((reason) => {
2348
+ setOpen(false);
2349
+ if (reason !== "outside") triggerRef.current?.focus();
2350
+ }, []);
2351
+ useDismiss(isOpen, [panelRef, triggerRef], close);
2352
+ const label = date ? formatDate(date, locale, formatOptions) : placeholder;
2353
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2354
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2355
+ "button",
2356
+ {
2357
+ ref: (element) => {
2358
+ triggerRef.current = element;
2359
+ assignRef5(ref, element);
2360
+ },
2361
+ id,
2362
+ type: "button",
2363
+ "aria-haspopup": "dialog",
2364
+ "aria-expanded": isOpen,
2365
+ "aria-controls": isOpen ? panelId : void 0,
2366
+ "aria-label": ariaLabel,
2367
+ "aria-labelledby": ariaLabelledBy,
2368
+ "aria-describedby": [`${panelId}-value`, ariaDescribedBy].filter(Boolean).join(" "),
2369
+ "aria-invalid": isInvalid || void 0,
2370
+ disabled,
2371
+ className: cx(
2372
+ "ow-select",
2373
+ "ow-date-picker",
2374
+ `ow-select--${size}`,
2375
+ { "ow-select--open": isOpen, "ow-select--invalid": isInvalid && !isOpen },
2376
+ className
2377
+ ),
2378
+ onClick: () => setOpen(!isOpen),
2379
+ onKeyDown: (event) => {
2380
+ if (event.key === "ArrowDown" && !isOpen) {
2381
+ event.preventDefault();
2382
+ setOpen(true);
2383
+ }
2384
+ },
2385
+ children: [
2386
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CalendarIcon, { size: size === "sm" ? 14 : 16, className: "ow-date-picker__icon" }),
2387
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { id: `${panelId}-value`, className: cx("ow-select__value", !date && "ow-select__value--placeholder"), children: label })
2388
+ ]
2389
+ }
2390
+ ),
2391
+ mounted ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2392
+ "div",
2393
+ {
2394
+ ref: panelRef,
2395
+ ...manualPopover,
2396
+ "data-state": state,
2397
+ id: panelId,
2398
+ role: "dialog",
2399
+ "aria-label": "Choose a date",
2400
+ className: "ow-popover ow-floating ow-date-picker__panel",
2401
+ style,
2402
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2403
+ Calendar,
2404
+ {
2405
+ ...calendarProps,
2406
+ locale,
2407
+ value: date,
2408
+ autoFocus: true,
2409
+ onChange: (next) => {
2410
+ setDate(next);
2411
+ close();
2412
+ }
2413
+ }
2414
+ )
2415
+ }
2416
+ ) : null
2417
+ ] });
2418
+ });
2419
+
2420
+ // src/components/Alert/Alert.tsx
2421
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2422
+ var icons = {
2423
+ info: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InfoIcon, { size: 16 }),
2424
+ success: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CircleCheckIcon, { size: 16 }),
2425
+ warning: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TriangleAlertIcon, { size: 16 }),
2426
+ danger: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CircleAlertIcon, { size: 16 }),
2427
+ neutral: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InfoIcon, { size: 16 })
2428
+ };
2429
+ function Alert({
2430
+ variant = "info",
2431
+ title,
2432
+ icon: icon2,
2433
+ actions,
2434
+ onClose,
2435
+ children,
2436
+ className,
2437
+ role,
2438
+ ...props
2439
+ }) {
2440
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2441
+ "div",
2442
+ {
2443
+ role: role ?? (variant === "danger" || variant === "warning" ? "alert" : "status"),
2444
+ className: cx("ow-alert", `ow-alert--${variant}`, className),
2445
+ ...props,
2446
+ children: [
2447
+ icon2 === false ? null : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ow-alert__icon", children: icon2 ?? icons[variant] }),
2448
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ow-alert__body", children: [
2449
+ title ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ow-alert__title", children: title }) : null,
2450
+ children ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ow-alert__description", children }) : null,
2451
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ow-alert__actions", children: actions }) : null
2452
+ ] }),
2453
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CloseButton, { size: "sm", label: "Dismiss", className: "ow-alert__close", onClick: onClose }) : null
2454
+ ]
2455
+ }
2456
+ );
2457
+ }
2458
+
2459
+ // src/components/Badge/Badge.tsx
2460
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2461
+ function Badge({ children, className, icon: icon2, size = "md", variant = "neutral", ...spanProps }) {
2462
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: cx("ow-badge", `ow-badge--${size}`, `ow-badge--${variant}`, className), ...spanProps, children: [
2463
+ icon2 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ow-badge__icon", children: icon2 }) : null,
2464
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children })
2465
+ ] });
2466
+ }
2467
+
2468
+ // src/components/Progress/Progress.tsx
2469
+ var import_react25 = require("react");
2470
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2471
+ function ProgressBar({
2472
+ value,
2473
+ max = 100,
2474
+ label,
2475
+ showValue = true,
2476
+ valueLabel,
2477
+ size = "sm",
2478
+ tone = "primary",
2479
+ "aria-label": ariaLabel,
2480
+ className
2481
+ }) {
2482
+ const labelId = (0, import_react25.useId)();
2483
+ const indeterminate = value === void 0;
2484
+ const pct = indeterminate ? 0 : Math.min(100, Math.max(0, value / max * 100));
2485
+ const text = valueLabel ?? `${Math.round(pct)}%`;
2486
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cx("ow-progress", `ow-progress--${size}`, `ow-progress--${tone}`, className), children: [
2487
+ label || showValue && !indeterminate ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "ow-progress__header", children: [
2488
+ label ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { id: labelId, className: "ow-progress__label", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", {}),
2489
+ showValue && !indeterminate ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "ow-progress__value", children: text }) : null
2490
+ ] }) : null,
2491
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2492
+ "div",
2493
+ {
2494
+ role: "progressbar",
2495
+ "aria-labelledby": label ? labelId : void 0,
2496
+ "aria-label": label ? void 0 : ariaLabel,
2497
+ "aria-valuemin": 0,
2498
+ "aria-valuemax": max,
2499
+ "aria-valuenow": indeterminate ? void 0 : value,
2500
+ "aria-valuetext": indeterminate ? void 0 : text,
2501
+ className: cx("ow-progress__track", indeterminate && "ow-progress__track--indeterminate"),
2502
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ow-progress__fill", style: indeterminate ? void 0 : { width: `${pct}%` } })
2503
+ }
2504
+ )
2505
+ ] });
2506
+ }
2507
+ var circleSizes = { sm: { box: 16, stroke: 2.5 }, md: { box: 24, stroke: 3 }, lg: { box: 48, stroke: 4 } };
2508
+ function ProgressCircle({
2509
+ value,
2510
+ max = 100,
2511
+ size = "md",
2512
+ tone = "primary",
2513
+ "aria-label": ariaLabel = "Progress",
2514
+ className
2515
+ }) {
2516
+ const { box, stroke } = circleSizes[size];
2517
+ const radius = (box - stroke) / 2;
2518
+ const circumference = 2 * Math.PI * radius;
2519
+ const indeterminate = value === void 0;
2520
+ const pct = indeterminate ? 25 : Math.min(100, Math.max(0, value / max * 100));
2521
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
2522
+ "span",
2523
+ {
2524
+ role: "progressbar",
2525
+ "aria-label": ariaLabel,
2526
+ "aria-valuemin": 0,
2527
+ "aria-valuemax": max,
2528
+ "aria-valuenow": indeterminate ? void 0 : value,
2529
+ className: cx(
2530
+ "ow-progress-circle",
2531
+ `ow-progress--${tone}`,
2532
+ indeterminate && "ow-progress-circle--indeterminate",
2533
+ className
2534
+ ),
2535
+ style: { width: box, height: box },
2536
+ children: [
2537
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("svg", { width: box, height: box, viewBox: `0 0 ${box} ${box}`, "aria-hidden": "true", children: [
2538
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("circle", { className: "ow-progress-circle__track", cx: box / 2, cy: box / 2, r: radius, strokeWidth: stroke, fill: "none" }),
2539
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2540
+ "circle",
2541
+ {
2542
+ className: "ow-progress-circle__fill",
2543
+ cx: box / 2,
2544
+ cy: box / 2,
2545
+ r: radius,
2546
+ strokeWidth: stroke,
2547
+ fill: "none",
2548
+ strokeLinecap: "round",
2549
+ strokeDasharray: circumference,
2550
+ strokeDashoffset: circumference * (1 - pct / 100),
2551
+ transform: `rotate(-90 ${box / 2} ${box / 2})`
2552
+ }
2553
+ )
2554
+ ] }),
2555
+ size === "lg" && !indeterminate ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "ow-progress-circle__value", children: [
2556
+ Math.round(pct),
2557
+ "%"
2558
+ ] }) : null
2559
+ ]
2560
+ }
2561
+ );
2562
+ }
2563
+
2564
+ // src/components/Skeleton/Skeleton.tsx
2565
+ var import_react26 = require("react");
2566
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2567
+ function Skeleton({ width = "100%", height = 14, soft = false, shape = "bar", className }) {
2568
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2569
+ "span",
2570
+ {
2571
+ className: cx("ow-skeleton", soft && "ow-skeleton--soft", shape === "block" && "ow-skeleton--block", className),
2572
+ style: { width, height },
2573
+ "aria-hidden": "true"
2574
+ }
2575
+ );
2576
+ }
2577
+ function SkeletonRows({ label = "Loading", rows = 4, delayMs = 150 }) {
2578
+ const [isVisible, setIsVisible] = (0, import_react26.useState)(delayMs === 0);
2579
+ (0, import_react26.useEffect)(() => {
2580
+ if (delayMs === 0) return;
2581
+ const timer = window.setTimeout(() => setIsVisible(true), delayMs);
2582
+ return () => window.clearTimeout(timer);
2583
+ }, [delayMs]);
2584
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "status", "aria-label": label, "aria-busy": "true", children: isVisible ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ow-skeleton-rows", "aria-hidden": "true", children: Array.from({ length: rows }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "ow-skeleton-rows__row", children: [
2585
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "ow-skeleton-rows__text", children: [
2586
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Skeleton, { width: `${28 + index * 17 % 22}%`, height: 14 }),
2587
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Skeleton, { width: `${46 + index * 23 % 30}%`, height: 12, soft: true })
2588
+ ] }),
2589
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Skeleton, { width: 96, height: 32, soft: true, shape: "block" })
2590
+ ] }, index)) }) : null });
2591
+ }
2592
+
2593
+ // src/components/Toast/Toast.tsx
2594
+ var import_react27 = require("react");
2595
+ var import_sonner = require("sonner");
2596
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2597
+ var icons2 = {
2598
+ success: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CircleCheckIcon, { size: 16 }),
2599
+ error: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CircleAlertIcon, { size: 16 }),
2600
+ warning: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TriangleAlertIcon, { size: 16 }),
2601
+ info: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(InfoIcon, { size: 16 }),
2602
+ loading: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, { size: "sm", label: "" }),
2603
+ close: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(XIcon, { size: 12 })
2604
+ };
2605
+ function Toaster({
2606
+ position = "bottom-center",
2607
+ expand = false,
2608
+ visibleToasts = 3,
2609
+ duration = 6e3,
2610
+ closeButton = true,
2611
+ offset = 16,
2612
+ gap = 10,
2613
+ id,
2614
+ className
2615
+ }) {
2616
+ const layerRef = (0, import_react27.useRef)(null);
2617
+ (0, import_react27.useEffect)(() => {
2618
+ const layer = layerRef.current;
2619
+ if (!layer || typeof layer.showPopover !== "function") return void 0;
2620
+ const raise = () => {
2621
+ try {
2622
+ if (layer.matches(":popover-open")) layer.hidePopover();
2623
+ layer.showPopover();
2624
+ } catch {
2625
+ }
2626
+ };
2627
+ raise();
2628
+ const observer = new MutationObserver((records) => {
2629
+ if (records.some((record) => record.target instanceof HTMLDialogElement && record.target.open)) raise();
2630
+ });
2631
+ observer.observe(document.body, { subtree: true, attributes: true, attributeFilter: ["open"] });
2632
+ return () => observer.disconnect();
2633
+ }, []);
2634
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { ref: layerRef, ...manualPopover, className: "ow-toaster-layer", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2635
+ import_sonner.Toaster,
2636
+ {
2637
+ id,
2638
+ position,
2639
+ expand,
2640
+ visibleToasts,
2641
+ duration,
2642
+ closeButton,
2643
+ offset,
2644
+ mobileOffset: offset,
2645
+ gap,
2646
+ icons: icons2,
2647
+ className: cx("ow-toaster", className),
2648
+ containerAriaLabel: "Notifications",
2649
+ toastOptions: { className: "ow-toast" }
2650
+ }
2651
+ ) });
2652
+ }
2653
+
2654
+ // src/components/Tooltip/Tooltip.tsx
2655
+ var import_react28 = require("react");
2656
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2657
+ var lastClosedAt = 0;
2658
+ var warmWindow = 500;
2659
+ function Tooltip({ children, label, placement = "top", delay = 400 }) {
2660
+ const anchorRef = (0, import_react28.useRef)(null);
2661
+ const bubbleRef = (0, import_react28.useRef)(null);
2662
+ const timer = (0, import_react28.useRef)(0);
2663
+ const [open, setOpen] = (0, import_react28.useState)(false);
2664
+ const { mounted, state } = usePresence(open, 100);
2665
+ const style = useFloating({ open: mounted, anchorRef, floatingRef: bubbleRef, placement, offset: 6 });
2666
+ const show = (immediately = false) => {
2667
+ window.clearTimeout(timer.current);
2668
+ if (immediately || Date.now() - lastClosedAt < warmWindow) setOpen(true);
2669
+ else timer.current = window.setTimeout(() => setOpen(true), delay);
2670
+ };
2671
+ const hide = () => {
2672
+ window.clearTimeout(timer.current);
2673
+ setOpen((current) => {
2674
+ if (current) lastClosedAt = Date.now();
2675
+ return false;
2676
+ });
2677
+ };
2678
+ (0, import_react28.useEffect)(() => () => window.clearTimeout(timer.current), []);
2679
+ (0, import_react28.useEffect)(() => {
2680
+ if (!open) return void 0;
2681
+ const onKeyDown = (event) => {
2682
+ if (event.key === "Escape") hide();
2683
+ };
2684
+ document.addEventListener("keydown", onKeyDown);
2685
+ return () => document.removeEventListener("keydown", onKeyDown);
2686
+ }, [open]);
2687
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
2688
+ "span",
2689
+ {
2690
+ ref: anchorRef,
2691
+ className: "ow-tooltip",
2692
+ onPointerEnter: (event) => {
2693
+ if (event.pointerType === "mouse") show();
2694
+ },
2695
+ onPointerLeave: hide,
2696
+ onPointerDown: hide,
2697
+ onFocus: (event) => {
2698
+ if (event.target.matches(":focus-visible")) show(true);
2699
+ },
2700
+ onBlur: hide,
2701
+ children: [
2702
+ children,
2703
+ mounted ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { ref: bubbleRef, ...manualPopover, "data-state": state, className: "ow-tooltip__bubble ow-floating", style, "aria-hidden": "true", children: label }) : null
2704
+ ]
2705
+ }
2706
+ );
2707
+ }
2708
+
2709
+ // src/components/Dialog/Dialog.tsx
2710
+ var import_react30 = require("react");
2711
+
2712
+ // src/hooks/useModalDialog.ts
2713
+ var import_react29 = require("react");
2714
+ var closeAnimationMs = 160;
2715
+ function useModalDialog(open, onCancel) {
2716
+ const dialogRef = (0, import_react29.useRef)(null);
2717
+ const onCancelRef = (0, import_react29.useRef)(onCancel);
2718
+ const [mounted, setMounted] = (0, import_react29.useState)(open);
2719
+ onCancelRef.current = onCancel;
2720
+ (0, import_react29.useEffect)(() => {
2721
+ if (open) setMounted(true);
2722
+ }, [open]);
2723
+ (0, import_react29.useEffect)(() => {
2724
+ const dialog = dialogRef.current;
2725
+ if (!dialog) return;
2726
+ if (open) {
2727
+ if (!dialog.open) dialog.showModal();
2728
+ return;
2729
+ }
2730
+ if (dialog.open) dialog.close();
2731
+ const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2732
+ const timer = window.setTimeout(() => setMounted(false), reduceMotion ? 0 : closeAnimationMs);
2733
+ return () => window.clearTimeout(timer);
2734
+ }, [open, mounted]);
2735
+ (0, import_react29.useEffect)(() => {
2736
+ const dialog = dialogRef.current;
2737
+ if (!dialog || !mounted) return;
2738
+ const onCancelEvent = (event) => {
2739
+ event.preventDefault();
2740
+ onCancelRef.current();
2741
+ };
2742
+ const isOutside = (event) => {
2743
+ const rect = dialog.getBoundingClientRect();
2744
+ return event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom;
2745
+ };
2746
+ let pressedOutside = false;
2747
+ const onPointerDown = (event) => {
2748
+ pressedOutside = event.target === dialog && isOutside(event);
2749
+ };
2750
+ const onClick = (event) => {
2751
+ if (pressedOutside && event.target === dialog && isOutside(event) && // Clicks from the keyboard (Enter on a button) report 0,0.
2752
+ event.detail > 0)
2753
+ dialog.dispatchEvent(new Event("cancel", { cancelable: true }));
2754
+ pressedOutside = false;
2755
+ };
2756
+ dialog.addEventListener("cancel", onCancelEvent);
2757
+ dialog.addEventListener("pointerdown", onPointerDown);
2758
+ dialog.addEventListener("click", onClick);
2759
+ return () => {
2760
+ dialog.removeEventListener("cancel", onCancelEvent);
2761
+ dialog.removeEventListener("pointerdown", onPointerDown);
2762
+ dialog.removeEventListener("click", onClick);
2763
+ };
2764
+ }, [mounted]);
2765
+ return { dialogRef, mounted };
2766
+ }
2767
+
2768
+ // src/components/Dialog/Dialog.tsx
2769
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2770
+ function Dialog({
2771
+ open,
2772
+ onClose,
2773
+ title,
2774
+ description,
2775
+ children,
2776
+ actions,
2777
+ width = 420,
2778
+ dismissible = true,
2779
+ onSubmit,
2780
+ className
2781
+ }) {
2782
+ const titleId = (0, import_react30.useId)();
2783
+ const descriptionId = (0, import_react30.useId)();
2784
+ const { dialogRef, mounted } = useModalDialog(open, () => {
2785
+ if (dismissible) onClose();
2786
+ });
2787
+ if (!mounted) return null;
2788
+ const body = /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
2789
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "ow-dialog__header", children: [
2790
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("h2", { id: titleId, className: "ow-dialog__title", children: title }),
2791
+ description ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { id: descriptionId, className: "ow-dialog__description", children: description }) : null
2792
+ ] }),
2793
+ children,
2794
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "ow-dialog__actions", children: actions }) : null
2795
+ ] });
2796
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2797
+ "dialog",
2798
+ {
2799
+ ref: dialogRef,
2800
+ className: cx("ow-dialog", className),
2801
+ style: { width: `min(${width}px, calc(100% - 32px))` },
2802
+ "aria-labelledby": titleId,
2803
+ "aria-describedby": description ? descriptionId : void 0,
2804
+ children: onSubmit ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2805
+ "form",
2806
+ {
2807
+ className: "ow-dialog__body",
2808
+ onSubmit: (event) => {
2809
+ event.preventDefault();
2810
+ onSubmit(event);
2811
+ },
2812
+ children: body
2813
+ }
2814
+ ) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "ow-dialog__body", children: body })
2815
+ }
2816
+ );
2817
+ }
2818
+ function ConfirmDialog({
2819
+ open,
2820
+ onClose,
2821
+ title,
2822
+ description,
2823
+ confirmLabel,
2824
+ destructive = false,
2825
+ confirmDisabled = false,
2826
+ onConfirm,
2827
+ children
2828
+ }) {
2829
+ const [isWorking, setIsWorking] = (0, import_react30.useState)(false);
2830
+ const [error, setError] = (0, import_react30.useState)("");
2831
+ async function confirm() {
2832
+ setIsWorking(true);
2833
+ setError("");
2834
+ try {
2835
+ await onConfirm();
2836
+ onClose();
2837
+ } catch (confirmError) {
2838
+ setError(
2839
+ confirmError instanceof Error && confirmError.message ? confirmError.message : "That didn't work. Try again."
2840
+ );
2841
+ } finally {
2842
+ setIsWorking(false);
2843
+ }
2844
+ }
2845
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2846
+ Dialog,
2847
+ {
2848
+ open,
2849
+ onClose,
2850
+ dismissible: !isWorking,
2851
+ width: 380,
2852
+ className: "ow-dialog--confirm",
2853
+ title: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
2854
+ destructive ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "ow-dialog__danger-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TrashIcon, { size: 18 }) }) : null,
2855
+ title
2856
+ ] }),
2857
+ description,
2858
+ onSubmit: () => {
2859
+ if (!confirmDisabled && !isWorking) void confirm();
2860
+ },
2861
+ actions: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
2862
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Button, { type: "button", disabled: isWorking, autoFocus: true, onClick: onClose, children: "Cancel" }),
2863
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2864
+ Button,
2865
+ {
2866
+ type: "submit",
2867
+ variant: destructive ? "danger" : "primary",
2868
+ disabled: isWorking || confirmDisabled,
2869
+ children: isWorking ? "Working\u2026" : confirmLabel
2870
+ }
2871
+ )
2872
+ ] }),
2873
+ children: [
2874
+ children,
2875
+ error ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { role: "alert", className: "ow-dialog__error", children: error }) : null
2876
+ ]
2877
+ }
2878
+ );
2879
+ }
2880
+
2881
+ // src/components/Drawer/Drawer.tsx
2882
+ var import_react31 = require("react");
2883
+ var import_jsx_runtime30 = require("react/jsx-runtime");
2884
+ function Drawer({
2885
+ open,
2886
+ onClose,
2887
+ title,
2888
+ description,
2889
+ children,
2890
+ footer,
2891
+ side = "right",
2892
+ size = 420,
2893
+ dismissible = true,
2894
+ className
2895
+ }) {
2896
+ const titleId = (0, import_react31.useId)();
2897
+ const descriptionId = (0, import_react31.useId)();
2898
+ const { dialogRef, mounted } = useModalDialog(open, () => {
2899
+ if (dismissible) onClose();
2900
+ });
2901
+ if (!mounted) return null;
2902
+ const sizeStyle = side === "bottom" ? { height: `min(${size}px, 90dvh)` } : { width: `min(${size}px, 100vw - 24px)` };
2903
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
2904
+ "dialog",
2905
+ {
2906
+ ref: dialogRef,
2907
+ className: cx("ow-drawer", `ow-drawer--${side}`, className),
2908
+ style: sizeStyle,
2909
+ "aria-labelledby": titleId,
2910
+ "aria-describedby": description ? descriptionId : void 0,
2911
+ children: [
2912
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("header", { className: "ow-drawer__header", children: [
2913
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "ow-drawer__titles", children: [
2914
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("h2", { id: titleId, className: "ow-drawer__title", children: title }),
2915
+ description ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { id: descriptionId, className: "ow-drawer__description", children: description }) : null
2916
+ ] }),
2917
+ dismissible ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(CloseButton, { onClick: onClose }) : null
2918
+ ] }),
2919
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "ow-drawer__body", children }),
2920
+ footer ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("footer", { className: "ow-drawer__footer", children: footer }) : null
2921
+ ]
2922
+ }
2923
+ );
2924
+ }
2925
+
2926
+ // src/components/Popover/Popover.tsx
2927
+ var import_react32 = require("react");
2928
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2929
+ function Popover({
2930
+ trigger,
2931
+ children,
2932
+ open,
2933
+ defaultOpen = false,
2934
+ onOpenChange,
2935
+ placement = "bottom-start",
2936
+ title,
2937
+ "aria-label": ariaLabel,
2938
+ width = 280,
2939
+ autoFocus = true,
2940
+ className
2941
+ }) {
2942
+ const [isOpen, setOpen] = useControllableState(open, defaultOpen, onOpenChange);
2943
+ const triggerRef = (0, import_react32.useRef)(null);
2944
+ const panelRef = (0, import_react32.useRef)(null);
2945
+ const anchorRef = (0, import_react32.useRef)(null);
2946
+ const id = (0, import_react32.useId)();
2947
+ const { mounted, state } = usePresence(isOpen);
2948
+ const style = useFloating({ open: mounted, anchorRef, floatingRef: panelRef, placement, offset: 8, maxHeight: 640 });
2949
+ const close = (0, import_react32.useCallback)(
2950
+ (reason) => {
2951
+ setOpen(false);
2952
+ if (reason !== "outside") triggerRef.current?.focus();
2953
+ },
2954
+ [setOpen]
2955
+ );
2956
+ useDismiss(isOpen, [panelRef, anchorRef], close);
2957
+ (0, import_react32.useEffect)(() => {
2958
+ triggerRef.current = anchorRef.current?.firstElementChild;
2959
+ });
2960
+ (0, import_react32.useEffect)(() => {
2961
+ if (!isOpen || !autoFocus) return;
2962
+ const frame = requestAnimationFrame(() => {
2963
+ const panel = panelRef.current;
2964
+ const first = panel?.querySelector(
2965
+ 'input, select, textarea, button, [href], [tabindex]:not([tabindex="-1"])'
2966
+ );
2967
+ (first ?? panel)?.focus();
2968
+ });
2969
+ return () => cancelAnimationFrame(frame);
2970
+ }, [isOpen, autoFocus]);
2971
+ const triggerElement = (0, import_react32.isValidElement)(trigger) ? (0, import_react32.cloneElement)(trigger, {
2972
+ "aria-haspopup": "dialog",
2973
+ "aria-expanded": isOpen,
2974
+ "aria-controls": isOpen ? id : void 0,
2975
+ onClick: (event) => {
2976
+ trigger.props.onClick?.(event);
2977
+ if (!event.defaultPrevented) setOpen(!isOpen);
2978
+ }
2979
+ }) : trigger;
2980
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
2981
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { ref: anchorRef, className: "ow-popover-anchor", children: triggerElement }),
2982
+ mounted ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
2983
+ "div",
2984
+ {
2985
+ ref: panelRef,
2986
+ ...manualPopover,
2987
+ "data-state": state,
2988
+ id,
2989
+ role: "dialog",
2990
+ "aria-label": title ? void 0 : ariaLabel,
2991
+ "aria-labelledby": title ? `${id}-title` : void 0,
2992
+ tabIndex: -1,
2993
+ className: cx("ow-popover", "ow-floating", className),
2994
+ style: { ...style, width },
2995
+ onBlur: (event) => {
2996
+ const next = event.relatedTarget;
2997
+ if (next && !panelRef.current?.contains(next) && !anchorRef.current?.contains(next)) setOpen(false);
2998
+ },
2999
+ children: [
3000
+ title ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { id: `${id}-title`, className: "ow-popover__title", children: title }) : null,
3001
+ children
3002
+ ]
3003
+ }
3004
+ ) : null
3005
+ ] });
3006
+ }
3007
+
3008
+ // src/components/Menu/Menu.tsx
3009
+ var import_react34 = require("react");
3010
+
3011
+ // src/hooks/useMenuKeyboard.ts
3012
+ var import_react33 = require("react");
3013
+ var itemSelector = '[role="menuitem"]:not([disabled]):not([aria-disabled="true"]), [role="menuitemradio"]:not([disabled]), [role="menuitemcheckbox"]:not([disabled])';
3014
+ function items(menu) {
3015
+ return menu ? [...menu.querySelectorAll(itemSelector)] : [];
3016
+ }
3017
+ function useMenuKeyboard({
3018
+ open,
3019
+ menuRef,
3020
+ triggerRef,
3021
+ onClose
3022
+ }) {
3023
+ (0, import_react33.useEffect)(() => {
3024
+ if (!open) return;
3025
+ const frame = window.requestAnimationFrame(() => {
3026
+ const menu = menuRef.current;
3027
+ if (menu?.contains(document.activeElement)) return;
3028
+ items(menu)[0]?.focus();
3029
+ });
3030
+ return () => window.cancelAnimationFrame(frame);
3031
+ }, [open, menuRef]);
3032
+ return (event) => {
3033
+ const list = items(menuRef.current);
3034
+ const index = list.indexOf(document.activeElement);
3035
+ const move = (next) => {
3036
+ event.preventDefault();
3037
+ list[(next + list.length) % list.length]?.focus();
3038
+ };
3039
+ switch (event.key) {
3040
+ case "ArrowDown":
3041
+ move(index + 1);
3042
+ break;
3043
+ case "ArrowUp":
3044
+ move(index < 0 ? list.length - 1 : index - 1);
3045
+ break;
3046
+ case "Home":
3047
+ move(0);
3048
+ break;
3049
+ case "End":
3050
+ move(list.length - 1);
3051
+ break;
3052
+ case "Escape":
3053
+ event.preventDefault();
3054
+ event.stopPropagation();
3055
+ onClose();
3056
+ triggerRef?.current?.focus();
3057
+ break;
3058
+ case "Tab":
3059
+ onClose();
3060
+ break;
3061
+ }
3062
+ };
3063
+ }
3064
+
3065
+ // src/components/Menu/Menu.tsx
3066
+ var import_jsx_runtime32 = require("react/jsx-runtime");
3067
+ var MenuContext = (0, import_react34.createContext)(null);
3068
+ function Menu({ trigger, children, label, align = "start", above = false, width, defaultOpen = false, className }) {
3069
+ const [open, setOpen] = (0, import_react34.useState)(defaultOpen);
3070
+ const rootRef = (0, import_react34.useRef)(null);
3071
+ const menuRef = (0, import_react34.useRef)(null);
3072
+ const triggerRef = (0, import_react34.useRef)(null);
3073
+ const menuId = (0, import_react34.useId)();
3074
+ const close = () => setOpen(false);
3075
+ const onMenuKeyDown = useMenuKeyboard({ open, menuRef, triggerRef, onClose: close });
3076
+ const { mounted, state } = usePresence(open);
3077
+ const floatingStyle = useFloating({
3078
+ open: mounted,
3079
+ anchorRef: rootRef,
3080
+ floatingRef: menuRef,
3081
+ placement: `${above ? "top" : "bottom"}-${align}`,
3082
+ offset: 8
3083
+ });
3084
+ (0, import_react34.useEffect)(() => {
3085
+ triggerRef.current = rootRef.current?.firstElementChild;
3086
+ });
3087
+ (0, import_react34.useEffect)(() => {
3088
+ if (!open) return;
3089
+ const onPointerDown = (event) => {
3090
+ if (!rootRef.current?.contains(event.target)) setOpen(false);
3091
+ };
3092
+ document.addEventListener("pointerdown", onPointerDown, true);
3093
+ return () => document.removeEventListener("pointerdown", onPointerDown, true);
3094
+ }, [open]);
3095
+ const triggerElement = (0, import_react34.isValidElement)(trigger) ? (0, import_react34.cloneElement)(trigger, {
3096
+ "aria-haspopup": "menu",
3097
+ "aria-expanded": open,
3098
+ "aria-controls": open ? menuId : void 0,
3099
+ onClick: (event) => {
3100
+ trigger.props.onClick?.(event);
3101
+ if (!event.defaultPrevented) setOpen((current) => !current);
3102
+ }
3103
+ }) : trigger;
3104
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { ref: rootRef, className: "ow-menu", children: [
3105
+ triggerElement,
3106
+ mounted ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3107
+ MenuContext.Provider,
3108
+ {
3109
+ value: {
3110
+ close() {
3111
+ setOpen(false);
3112
+ triggerRef.current?.focus();
3113
+ }
3114
+ },
3115
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3116
+ "div",
3117
+ {
3118
+ ref: menuRef,
3119
+ ...manualPopover,
3120
+ "data-state": state,
3121
+ id: menuId,
3122
+ role: "menu",
3123
+ "aria-label": label,
3124
+ className: cx("ow-menu__panel", "ow-floating", className),
3125
+ style: width === void 0 ? floatingStyle : { ...floatingStyle, width },
3126
+ onKeyDown: onMenuKeyDown,
3127
+ children
3128
+ }
3129
+ )
3130
+ }
3131
+ ) : null
3132
+ ] });
3133
+ }
3134
+ var MenuItem = (0, import_react34.forwardRef)(function MenuItem2({ icon: icon2, onSelect, destructive = false, shortcut, className, children, onClick, ...buttonProps }, ref) {
3135
+ const menu = (0, import_react34.useContext)(MenuContext);
3136
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
3137
+ "button",
3138
+ {
3139
+ ref,
3140
+ type: "button",
3141
+ role: "menuitem",
3142
+ tabIndex: -1,
3143
+ className: cx("ow-menu__item", destructive && "ow-menu__item--destructive", className),
3144
+ onClick: (event) => {
3145
+ onClick?.(event);
3146
+ if (event.defaultPrevented) return;
3147
+ menu?.close();
3148
+ onSelect?.();
3149
+ },
3150
+ ...buttonProps,
3151
+ children: [
3152
+ icon2 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "ow-menu__icon", children: icon2 }) : null,
3153
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "ow-menu__label", children }),
3154
+ shortcut ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("kbd", { className: "ow-menu__shortcut", children: shortcut }) : null
3155
+ ]
3156
+ }
3157
+ );
3158
+ });
3159
+ function MenuLabel({ children }) {
3160
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "ow-menu__group-label", role: "presentation", children });
3161
+ }
3162
+ function MenuSeparator() {
3163
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "ow-menu__separator", role: "separator" });
3164
+ }
3165
+
3166
+ // src/components/CommandPalette/CommandPalette.tsx
3167
+ var import_react35 = require("react");
3168
+
3169
+ // src/components/CommandPalette/filterCommands.ts
3170
+ function score(query, text, loose = true) {
3171
+ const haystack = text.toLowerCase();
3172
+ if (haystack.startsWith(query)) return 100 - Math.min(haystack.length, 50) / 10;
3173
+ const wordStart = haystack.indexOf(` ${query}`);
3174
+ if (wordStart >= 0) return 80 - wordStart / 10;
3175
+ const anywhere = haystack.indexOf(query);
3176
+ if (anywhere >= 0) return 60 - anywhere / 10;
3177
+ if (!loose) return 0;
3178
+ let position = 0;
3179
+ let gaps = 0;
3180
+ for (const letter of query) {
3181
+ const found = haystack.indexOf(letter, position);
3182
+ if (found < 0) return 0;
3183
+ gaps += found - position;
3184
+ position = found + 1;
3185
+ }
3186
+ return Math.max(1, 40 - gaps);
3187
+ }
3188
+ function filterCommands(commands, query) {
3189
+ const words = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
3190
+ if (!words.length) return commands;
3191
+ return commands.map((command, index) => {
3192
+ const extra = `${command.group ?? ""} ${command.keywords ?? ""} ${command.hint ?? ""}`;
3193
+ let total = 0;
3194
+ for (const word of words) {
3195
+ const best = Math.max(score(word, command.title) * 1.5, score(word, extra, false));
3196
+ if (!best) return void 0;
3197
+ total += best;
3198
+ }
3199
+ return { command, rank: total - (command.disabled ? 50 : 0) - index / 1e3 };
3200
+ }).filter((entry) => Boolean(entry)).sort((a, b) => b.rank - a.rank).map((entry) => entry.command);
3201
+ }
3202
+
3203
+ // src/components/CommandPalette/CommandPalette.tsx
3204
+ var import_jsx_runtime33 = require("react/jsx-runtime");
3205
+ function CommandPalette({ open, onClose, commands, placeholder = "Search commands\u2026" }) {
3206
+ const { dialogRef, mounted } = useModalDialog(open, onClose);
3207
+ const [query, setQuery] = (0, import_react35.useState)("");
3208
+ const [activeIndex, setActiveIndex] = (0, import_react35.useState)(0);
3209
+ const listRef = (0, import_react35.useRef)(null);
3210
+ const listId = (0, import_react35.useId)();
3211
+ const results = (0, import_react35.useMemo)(() => filterCommands(commands, query), [commands, query]);
3212
+ const active = results[Math.min(activeIndex, results.length - 1)];
3213
+ (0, import_react35.useEffect)(() => setActiveIndex(0), [query]);
3214
+ (0, import_react35.useEffect)(() => {
3215
+ if (open) setQuery("");
3216
+ }, [open]);
3217
+ (0, import_react35.useEffect)(() => {
3218
+ listRef.current?.querySelector("[aria-selected=true]")?.scrollIntoView({ block: "nearest" });
3219
+ }, [activeIndex, results]);
3220
+ if (!mounted) return null;
3221
+ function run(command) {
3222
+ if (!command || command.disabled) return;
3223
+ onClose();
3224
+ window.setTimeout(() => command.run(), 0);
3225
+ }
3226
+ function move(step) {
3227
+ if (!results.length) return;
3228
+ setActiveIndex((index) => (Math.min(index, results.length - 1) + step + results.length) % results.length);
3229
+ }
3230
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("dialog", { ref: dialogRef, className: "ow-dialog ow-palette", "aria-label": "Command palette", children: [
3231
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "ow-palette__search", children: [
3232
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(SearchIcon, { size: 16, className: "ow-palette__search-icon" }),
3233
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3234
+ "input",
3235
+ {
3236
+ autoFocus: true,
3237
+ className: "ow-palette__input",
3238
+ placeholder,
3239
+ role: "combobox",
3240
+ "aria-expanded": "true",
3241
+ "aria-controls": listId,
3242
+ "aria-activedescendant": active ? `${listId}-${active.id}` : void 0,
3243
+ "aria-autocomplete": "list",
3244
+ value: query,
3245
+ onChange: (event) => setQuery(event.target.value),
3246
+ onKeyDown: (event) => {
3247
+ if (event.key === "ArrowDown" || event.ctrlKey && event.key === "n") {
3248
+ event.preventDefault();
3249
+ move(1);
3250
+ } else if (event.key === "ArrowUp" || event.ctrlKey && event.key === "p") {
3251
+ event.preventDefault();
3252
+ move(-1);
3253
+ } else if (event.key === "Enter") {
3254
+ event.preventDefault();
3255
+ run(active);
3256
+ }
3257
+ }
3258
+ }
3259
+ ),
3260
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: "ow-palette__esc", children: "esc" })
3261
+ ] }),
3262
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ul", { ref: listRef, id: listId, role: "listbox", "aria-label": "Commands", className: "ow-palette__list", children: results.length ? results.map((command, index) => {
3263
+ const showGroup = !query.trim() && command.group && command.group !== results[index - 1]?.group;
3264
+ const isActive = command === active;
3265
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("li", { role: "presentation", children: [
3266
+ showGroup ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "ow-palette__group", children: command.group }) : null,
3267
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
3268
+ "div",
3269
+ {
3270
+ id: `${listId}-${command.id}`,
3271
+ role: "option",
3272
+ "aria-selected": isActive,
3273
+ "aria-disabled": Boolean(command.disabled),
3274
+ title: command.disabled,
3275
+ className: cx("ow-palette__option", {
3276
+ "ow-palette__option--active": isActive,
3277
+ "ow-palette__option--disabled": Boolean(command.disabled)
3278
+ }),
3279
+ onMouseMove: () => setActiveIndex(index),
3280
+ onClick: () => run(command),
3281
+ children: [
3282
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "ow-palette__icon", "aria-hidden": "true", children: command.icon }),
3283
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "ow-palette__title", children: command.title }),
3284
+ command.disabled && isActive ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "ow-palette__hint", children: command.disabled }) : command.hint ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "ow-palette__hint", children: command.hint }) : null,
3285
+ command.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("kbd", { className: "ow-palette__shortcut", children: command.shortcut }) : null,
3286
+ isActive && !command.disabled ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CornerDownLeftIcon, { size: 13, className: "ow-palette__enter" }) : null
3287
+ ]
3288
+ }
3289
+ )
3290
+ ] }, command.id);
3291
+ }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("li", { className: "ow-palette__empty", children: [
3292
+ "No commands match \u201C",
3293
+ query,
3294
+ "\u201D."
3295
+ ] }) })
3296
+ ] });
3297
+ }
3298
+
3299
+ // src/components/Tabs/Tabs.tsx
3300
+ var import_react36 = require("react");
3301
+ var import_jsx_runtime34 = require("react/jsx-runtime");
3302
+ var TabsContext = (0, import_react36.createContext)(null);
3303
+ function useTabs(component) {
3304
+ const context = (0, import_react36.useContext)(TabsContext);
3305
+ if (!context) throw new Error(`${component} must be inside <Tabs>.`);
3306
+ return context;
3307
+ }
3308
+ var idPart = (value) => value.replace(/[^\w-]/g, "_");
3309
+ function Tabs({ value, defaultValue = "", onValueChange, variant = "segmented", className, children, ...props }) {
3310
+ const [current, select] = useControllableState(value, defaultValue, onValueChange);
3311
+ const baseId = (0, import_react36.useId)();
3312
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(TabsContext.Provider, { value: { value: current, select, baseId, variant }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: cx("ow-tabs", `ow-tabs--${variant}`, className), ...props, children }) });
3313
+ }
3314
+ function TabList({ className, onKeyDown, children, ...props }) {
3315
+ const { value, select } = useTabs("TabList");
3316
+ const listRef = (0, import_react36.useRef)(null);
3317
+ useIndicator(listRef, '[role="tab"][aria-selected="true"]', value);
3318
+ (0, import_react36.useLayoutEffect)(() => {
3319
+ const list = listRef.current;
3320
+ if (!list || list.querySelector('[role="tab"][aria-selected="true"]')) return;
3321
+ const first = list.querySelector('[role="tab"]:not(:disabled)');
3322
+ if (first?.dataset.value) select(first.dataset.value);
3323
+ }, [value, select]);
3324
+ function handleKeyDown(event) {
3325
+ onKeyDown?.(event);
3326
+ const tabs = [...event.currentTarget.querySelectorAll('[role="tab"]:not(:disabled)')];
3327
+ const index = tabs.indexOf(document.activeElement);
3328
+ if (index < 0) return;
3329
+ const moves = { ArrowRight: index + 1, ArrowLeft: index - 1, Home: 0, End: tabs.length - 1 };
3330
+ if (!(event.key in moves)) return;
3331
+ event.preventDefault();
3332
+ const next = tabs[(moves[event.key] + tabs.length) % tabs.length];
3333
+ next.focus();
3334
+ if (next.dataset.value) select(next.dataset.value);
3335
+ }
3336
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { ref: listRef, role: "tablist", className: cx("ow-tabs__list", className), onKeyDown: handleKeyDown, ...props, children: [
3337
+ children,
3338
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ow-indicator", "aria-hidden": "true" })
3339
+ ] });
3340
+ }
3341
+ function Tab({ value, icon: icon2, className, children, onClick, ...props }) {
3342
+ const { value: current, select, baseId } = useTabs("Tab");
3343
+ const selected = current === value;
3344
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
3345
+ "button",
3346
+ {
3347
+ type: "button",
3348
+ role: "tab",
3349
+ id: `${baseId}-tab-${idPart(value)}`,
3350
+ "aria-selected": selected,
3351
+ "aria-controls": `${baseId}-panel-${idPart(value)}`,
3352
+ tabIndex: selected ? 0 : -1,
3353
+ "data-value": value,
3354
+ className: cx("ow-tab", className),
3355
+ onClick: (event) => {
3356
+ onClick?.(event);
3357
+ if (!event.defaultPrevented) select(value);
3358
+ },
3359
+ ...props,
3360
+ children: [
3361
+ icon2 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ow-tab__icon", children: icon2 }) : null,
3362
+ children
3363
+ ]
3364
+ }
3365
+ );
3366
+ }
3367
+ function TabPanel({ value, keepMounted = false, className, children, ...props }) {
3368
+ const { value: current, baseId } = useTabs("TabPanel");
3369
+ const selected = current === value;
3370
+ if (!selected && !keepMounted) return null;
3371
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3372
+ "div",
3373
+ {
3374
+ role: "tabpanel",
3375
+ id: `${baseId}-panel-${idPart(value)}`,
3376
+ "aria-labelledby": `${baseId}-tab-${idPart(value)}`,
3377
+ tabIndex: 0,
3378
+ hidden: !selected,
3379
+ className: cx("ow-tabs__panel", className),
3380
+ ...props,
3381
+ children
3382
+ }
3383
+ );
3384
+ }
3385
+
3386
+ // src/components/Accordion/Accordion.tsx
3387
+ var import_react37 = require("react");
3388
+ var import_jsx_runtime35 = require("react/jsx-runtime");
3389
+ function DisclosureView({
3390
+ open,
3391
+ onToggle,
3392
+ title,
3393
+ subtitle,
3394
+ icon: icon2,
3395
+ actions,
3396
+ headingLevel,
3397
+ disabled,
3398
+ children,
3399
+ className,
3400
+ item
3401
+ }) {
3402
+ const id = (0, import_react37.useId)();
3403
+ const panelRef = (0, import_react37.useRef)(null);
3404
+ const Heading = `h${headingLevel}`;
3405
+ (0, import_react37.useEffect)(() => {
3406
+ if (panelRef.current) panelRef.current.inert = !open;
3407
+ }, [open]);
3408
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: cx(item ? "ow-accordion__item" : "ow-disclosure", className), "data-open": open, children: [
3409
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "ow-disclosure__header", children: [
3410
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Heading, { className: "ow-disclosure__heading", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
3411
+ "button",
3412
+ {
3413
+ type: "button",
3414
+ id: `${id}-trigger`,
3415
+ className: "ow-disclosure__trigger",
3416
+ "aria-expanded": open,
3417
+ "aria-controls": `${id}-panel`,
3418
+ disabled,
3419
+ "data-accordion-trigger": item ? "" : void 0,
3420
+ onClick: onToggle,
3421
+ children: [
3422
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChevronRightIcon, { size: 14, className: "ow-disclosure__chevron" }),
3423
+ icon2 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ow-disclosure__icon", children: icon2 }) : null,
3424
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ow-disclosure__titles", children: [
3425
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ow-disclosure__title", children: title }),
3426
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ow-disclosure__subtitle", children: subtitle }) : null
3427
+ ] })
3428
+ ]
3429
+ }
3430
+ ) }),
3431
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "ow-disclosure__actions", children: actions }) : null
3432
+ ] }),
3433
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3434
+ "div",
3435
+ {
3436
+ ref: panelRef,
3437
+ id: `${id}-panel`,
3438
+ role: "region",
3439
+ "aria-labelledby": `${id}-trigger`,
3440
+ className: "ow-disclosure__panel",
3441
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "ow-disclosure__clip", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "ow-disclosure__content", children }) })
3442
+ }
3443
+ )
3444
+ ] });
3445
+ }
3446
+ function Disclosure({
3447
+ open,
3448
+ defaultOpen = false,
3449
+ onOpenChange,
3450
+ variant = "card",
3451
+ headingLevel = 3,
3452
+ className,
3453
+ ...props
3454
+ }) {
3455
+ const [isOpen, setOpen] = useControllableState(open, defaultOpen, onOpenChange);
3456
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3457
+ DisclosureView,
3458
+ {
3459
+ ...props,
3460
+ open: isOpen,
3461
+ onToggle: () => setOpen(!isOpen),
3462
+ headingLevel,
3463
+ className: cx(variant === "plain" && "ow-disclosure--plain", className)
3464
+ }
3465
+ );
3466
+ }
3467
+ var AccordionContext = (0, import_react37.createContext)(null);
3468
+ function Accordion({
3469
+ type = "single",
3470
+ value,
3471
+ defaultValue = [],
3472
+ onValueChange,
3473
+ variant = "bordered",
3474
+ headingLevel = 3,
3475
+ className,
3476
+ children,
3477
+ onKeyDown,
3478
+ ...props
3479
+ }) {
3480
+ const [openValues, setOpenValues] = useControllableState(value, defaultValue, onValueChange);
3481
+ function toggle(item) {
3482
+ const isOpen = openValues.includes(item);
3483
+ if (type === "single") setOpenValues(isOpen ? [] : [item]);
3484
+ else setOpenValues(isOpen ? openValues.filter((open) => open !== item) : [...openValues, item]);
3485
+ }
3486
+ function handleKeyDown(event) {
3487
+ onKeyDown?.(event);
3488
+ const triggers = [
3489
+ ...event.currentTarget.querySelectorAll("[data-accordion-trigger]:not(:disabled)")
3490
+ ];
3491
+ const index = triggers.indexOf(document.activeElement);
3492
+ if (index < 0) return;
3493
+ const moves = { ArrowDown: index + 1, ArrowUp: index - 1, Home: 0, End: triggers.length - 1 };
3494
+ if (!(event.key in moves)) return;
3495
+ event.preventDefault();
3496
+ triggers[(moves[event.key] + triggers.length) % triggers.length]?.focus();
3497
+ }
3498
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(AccordionContext.Provider, { value: { isOpen: (item) => openValues.includes(item), toggle, headingLevel }, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: cx("ow-accordion", `ow-accordion--${variant}`, className), onKeyDown: handleKeyDown, ...props, children }) });
3499
+ }
3500
+ function AccordionItem({ value, ...props }) {
3501
+ const context = (0, import_react37.useContext)(AccordionContext);
3502
+ if (!context) throw new Error("AccordionItem must be inside <Accordion>.");
3503
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3504
+ DisclosureView,
3505
+ {
3506
+ ...props,
3507
+ item: true,
3508
+ open: context.isOpen(value),
3509
+ onToggle: () => context.toggle(value),
3510
+ headingLevel: context.headingLevel
3511
+ }
3512
+ );
3513
+ }
3514
+
3515
+ // src/components/Breadcrumbs/Breadcrumbs.tsx
3516
+ var import_react38 = require("react");
3517
+ var import_jsx_runtime36 = require("react/jsx-runtime");
3518
+ function Breadcrumbs({ items: items2, separator = "chevron", label = "Breadcrumb", className }) {
3519
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("nav", { "aria-label": label, className: cx("ow-breadcrumbs", className), children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ol", { className: "ow-breadcrumbs__list", children: items2.map((item, index) => {
3520
+ const isLast = index === items2.length - 1;
3521
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("li", { className: "ow-breadcrumbs__item", children: [
3522
+ isLast ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ow-breadcrumbs__current", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("a", { className: "ow-breadcrumbs__link", href: item.href, onClick: item.onClick, children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "button", className: "ow-breadcrumbs__link", onClick: item.onClick, children: item.label }),
3523
+ isLast ? null : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ow-breadcrumbs__separator", "aria-hidden": "true", children: separator === "slash" ? "/" : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ChevronRightIcon, { size: 14 }) })
3524
+ ] }, index);
3525
+ }) }) });
3526
+ }
3527
+ function linkClassName({ variant = "default" } = {}) {
3528
+ return cx("ow-link", `ow-link--${variant}`);
3529
+ }
3530
+ var Link = (0, import_react38.forwardRef)(function Link2({ variant = "default", external = false, className, children, target, rel, ...props }, ref) {
3531
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
3532
+ "a",
3533
+ {
3534
+ ref,
3535
+ className: cx(linkClassName({ variant }), className),
3536
+ target: external ? target ?? "_blank" : target,
3537
+ rel: external ? rel ?? "noopener noreferrer" : rel,
3538
+ ...props,
3539
+ children: [
3540
+ children,
3541
+ external ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
3542
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ArrowUpRightIcon, { size: 13, className: "ow-link__external" }),
3543
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ow-visually-hidden", children: " (opens in a new tab)" })
3544
+ ] }) : null
3545
+ ]
3546
+ }
3547
+ );
3548
+ });
3549
+
3550
+ // src/components/Pagination/Pagination.tsx
3551
+ var import_jsx_runtime37 = require("react/jsx-runtime");
3552
+ function paginationItems(page, pageCount, siblingCount = 1, boundaryCount = 1) {
3553
+ const range = (from, to) => Array.from({ length: Math.max(0, to - from + 1) }, (_, i) => from + i);
3554
+ const startPages = range(1, Math.min(boundaryCount, pageCount));
3555
+ const endPages = range(Math.max(pageCount - boundaryCount + 1, boundaryCount + 1), pageCount);
3556
+ const siblingsStart = Math.max(
3557
+ Math.min(page - siblingCount, pageCount - boundaryCount - siblingCount * 2 - 1),
3558
+ boundaryCount + 2
3559
+ );
3560
+ const siblingsEnd = Math.min(
3561
+ Math.max(page + siblingCount, boundaryCount + siblingCount * 2 + 2),
3562
+ endPages.length > 0 ? endPages[0] - 2 : pageCount - 1
3563
+ );
3564
+ return [
3565
+ ...startPages,
3566
+ ...siblingsStart > boundaryCount + 2 ? ["start-gap"] : boundaryCount + 1 < pageCount - boundaryCount ? [boundaryCount + 1] : [],
3567
+ ...range(siblingsStart, siblingsEnd),
3568
+ ...siblingsEnd < pageCount - boundaryCount - 1 ? ["end-gap"] : pageCount - boundaryCount > boundaryCount ? [pageCount - boundaryCount] : [],
3569
+ ...endPages
3570
+ ];
3571
+ }
3572
+ function Pagination({
3573
+ page,
3574
+ pageCount,
3575
+ onPageChange,
3576
+ siblingCount = 1,
3577
+ boundaryCount = 1,
3578
+ size = "md",
3579
+ label = "Pagination",
3580
+ className
3581
+ }) {
3582
+ const items2 = paginationItems(page, pageCount, siblingCount, boundaryCount);
3583
+ const go = (next) => onPageChange(Math.min(Math.max(1, next), pageCount));
3584
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("nav", { "aria-label": label, className: cx("ow-pagination", `ow-pagination--${size}`, className), children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("ul", { className: "ow-pagination__list", children: [
3585
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3586
+ "button",
3587
+ {
3588
+ type: "button",
3589
+ className: "ow-pagination__button ow-pagination__step",
3590
+ "aria-label": "Previous page",
3591
+ disabled: page <= 1,
3592
+ onClick: () => go(page - 1),
3593
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ChevronLeftIcon, { size: 16 })
3594
+ }
3595
+ ) }),
3596
+ items2.map(
3597
+ (item) => typeof item === "number" ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3598
+ "button",
3599
+ {
3600
+ type: "button",
3601
+ className: "ow-pagination__button",
3602
+ "aria-current": item === page ? "page" : void 0,
3603
+ "aria-label": `Page ${item}`,
3604
+ onClick: () => go(item),
3605
+ children: item
3606
+ }
3607
+ ) }, item) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("li", { className: "ow-pagination__gap", "aria-hidden": "true", children: "\u2026" }, item)
3608
+ ),
3609
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3610
+ "button",
3611
+ {
3612
+ type: "button",
3613
+ className: "ow-pagination__button ow-pagination__step",
3614
+ "aria-label": "Next page",
3615
+ disabled: page >= pageCount,
3616
+ onClick: () => go(page + 1),
3617
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ChevronRightIcon, { size: 16 })
3618
+ }
3619
+ ) })
3620
+ ] }) });
3621
+ }
3622
+
3623
+ // src/components/Steps/Steps.tsx
3624
+ var import_react39 = require("react");
3625
+ var import_jsx_runtime38 = require("react/jsx-runtime");
3626
+ function Steps({ items: items2, current = 0, orientation = "vertical", title, label = "Steps", className }) {
3627
+ const statuses = items2.map((item, index) => item.status ?? (index < current ? "done" : index === current ? "current" : "upcoming"));
3628
+ const doneCount = statuses.filter((status) => status === "done").length;
3629
+ const headingId = (0, import_react39.useId)();
3630
+ const list = /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ol", { className: "ow-steps__list", children: items2.map((item, index) => {
3631
+ const status = statuses[index];
3632
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
3633
+ "li",
3634
+ {
3635
+ className: cx("ow-steps__item", `ow-steps__item--${status}`),
3636
+ "aria-current": status === "current" ? "step" : void 0,
3637
+ children: [
3638
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "ow-steps__marker", children: status === "done" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckIcon, { size: 14, strokeWidth: 3 }) : index + 1 }),
3639
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "ow-steps__text", children: [
3640
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "ow-steps__title", children: [
3641
+ status === "done" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "ow-visually-hidden", children: "Done: " }) : null,
3642
+ item.title
3643
+ ] }),
3644
+ item.description && (orientation === "horizontal" || status !== "done") ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "ow-steps__description", children: item.description }) : null
3645
+ ] }),
3646
+ item.action && status !== "done" && orientation === "vertical" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "ow-steps__action", children: item.action }) : null
3647
+ ]
3648
+ },
3649
+ index
3650
+ );
3651
+ }) });
3652
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
3653
+ "section",
3654
+ {
3655
+ className: cx("ow-steps", `ow-steps--${orientation}`, className),
3656
+ "aria-labelledby": title && orientation === "vertical" ? headingId : void 0,
3657
+ "aria-label": title && orientation === "vertical" ? void 0 : label,
3658
+ children: [
3659
+ title && orientation === "vertical" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "ow-steps__header", children: [
3660
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("h3", { id: headingId, className: "ow-steps__heading", children: title }),
3661
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "ow-steps__count", children: [
3662
+ doneCount,
3663
+ " of ",
3664
+ items2.length,
3665
+ " done"
3666
+ ] })
3667
+ ] }) : null,
3668
+ list
3669
+ ]
3670
+ }
3671
+ );
3672
+ }
3673
+
3674
+ // src/components/NavList/NavList.tsx
3675
+ var import_react40 = require("react");
3676
+ var import_jsx_runtime39 = require("react/jsx-runtime");
3677
+ function NavList({ label, heading, orientation = "vertical", children, className }) {
3678
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("nav", { "aria-label": label, className: cx("ow-nav", `ow-nav--${orientation}`, className), children: [
3679
+ heading && orientation === "vertical" ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "ow-nav__heading", children: heading }) : null,
3680
+ children
3681
+ ] });
3682
+ }
3683
+ var NavItem = (0, import_react40.forwardRef)(function NavItem2({ icon: icon2, active = false, className, children, type = "button", href, end, ...buttonProps }, ref) {
3684
+ const content = /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
3685
+ icon2 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "ow-nav__icon", children: icon2 }) : null,
3686
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "ow-nav__label", children }),
3687
+ end !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "ow-nav__end", children: end }) : null
3688
+ ] });
3689
+ const shared = {
3690
+ "aria-current": active ? "page" : void 0,
3691
+ className: cx("ow-nav__item", active && "ow-nav__item--active", className)
3692
+ };
3693
+ if (href !== void 0) {
3694
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3695
+ "a",
3696
+ {
3697
+ ref,
3698
+ href,
3699
+ ...shared,
3700
+ ...buttonProps,
3701
+ children: content
3702
+ }
3703
+ );
3704
+ }
3705
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("button", { ref, type, ...shared, ...buttonProps, children: content });
3706
+ });
3707
+
3708
+ // src/components/Table/Table.tsx
3709
+ var import_react41 = require("react");
3710
+ var import_jsx_runtime40 = require("react/jsx-runtime");
3711
+ function compare(a, b) {
3712
+ if (typeof a === "number" && typeof b === "number") return a - b;
3713
+ return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
3714
+ }
3715
+ function Table({
3716
+ columns,
3717
+ rows,
3718
+ rowKey = "id",
3719
+ caption,
3720
+ hideCaption = false,
3721
+ sort,
3722
+ defaultSort,
3723
+ onSortChange,
3724
+ manualSort = false,
3725
+ selectionMode = "none",
3726
+ selectedKeys,
3727
+ defaultSelectedKeys = [],
3728
+ onSelectionChange,
3729
+ emptyContent = "Nothing here yet.",
3730
+ density = "comfortable",
3731
+ stickyHeader = false,
3732
+ maxHeight,
3733
+ className
3734
+ }) {
3735
+ const [currentSort, setSort] = useControllableState(sort, defaultSort, onSortChange);
3736
+ const [selected, setSelected] = useControllableState(selectedKeys, defaultSelectedKeys, onSelectionChange);
3737
+ const keyOf = (row) => typeof rowKey === "function" ? rowKey(row) : row[rowKey];
3738
+ const field = (row, key) => row[key];
3739
+ const sorted = (0, import_react41.useMemo)(() => {
3740
+ if (!currentSort || manualSort) return rows;
3741
+ const column = columns.find((c) => c.key === currentSort.key);
3742
+ if (!column) return rows;
3743
+ const value = (row) => column.sortValue ? column.sortValue(row) : field(row, column.key);
3744
+ const result = [...rows].sort((a, b) => compare(value(a), value(b)));
3745
+ return currentSort.direction === "descending" ? result.reverse() : result;
3746
+ }, [rows, columns, currentSort, manualSort]);
3747
+ const allKeys = sorted.map(keyOf);
3748
+ const selectedCount = allKeys.filter((key) => selected.includes(key)).length;
3749
+ function toggleSort(key) {
3750
+ setSort(
3751
+ currentSort?.key === key ? { key, direction: currentSort.direction === "ascending" ? "descending" : "ascending" } : { key, direction: "ascending" }
3752
+ );
3753
+ }
3754
+ const selectable = selectionMode === "multiple";
3755
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3756
+ "div",
3757
+ {
3758
+ className: cx("ow-table-wrap", stickyHeader && "ow-table-wrap--sticky", className),
3759
+ style: maxHeight ? { maxHeight } : void 0,
3760
+ tabIndex: maxHeight ? 0 : void 0,
3761
+ children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("table", { className: cx("ow-table", `ow-table--${density}`), children: [
3762
+ caption ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("caption", { className: cx("ow-table__caption", hideCaption && "ow-visually-hidden"), children: caption }) : null,
3763
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("tr", { children: [
3764
+ selectable ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("th", { className: "ow-table__select", scope: "col", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3765
+ Checkbox,
3766
+ {
3767
+ size: "sm",
3768
+ "aria-label": "Select all rows",
3769
+ checked: sorted.length > 0 && selectedCount === sorted.length,
3770
+ indeterminate: selectedCount > 0 && selectedCount < sorted.length,
3771
+ onChange: (event) => setSelected(
3772
+ event.target.checked ? [.../* @__PURE__ */ new Set([...selected, ...allKeys])] : selected.filter((key) => !allKeys.includes(key))
3773
+ )
3774
+ }
3775
+ ) }) : null,
3776
+ columns.map((column) => {
3777
+ const direction = currentSort?.key === column.key ? currentSort.direction : void 0;
3778
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3779
+ "th",
3780
+ {
3781
+ scope: "col",
3782
+ "aria-sort": direction ?? (column.sortable ? "none" : void 0),
3783
+ className: cx(`ow-table__cell--${column.align ?? "start"}`),
3784
+ style: column.width !== void 0 ? { width: column.width } : void 0,
3785
+ children: column.sortable ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("button", { type: "button", className: "ow-table__sort", onClick: () => toggleSort(column.key), children: [
3786
+ column.header,
3787
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: cx("ow-table__sort-icon", direction && "ow-table__sort-icon--active"), children: direction === "ascending" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ArrowUpIcon, { size: 12 }) : direction === "descending" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ArrowDownIcon, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ChevronsUpDownIcon, { size: 12 }) })
3788
+ ] }) : column.header
3789
+ },
3790
+ column.key
3791
+ );
3792
+ })
3793
+ ] }) }),
3794
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("tbody", { children: sorted.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("td", { className: "ow-table__empty", colSpan: columns.length + (selectable ? 1 : 0), children: emptyContent }) }) : sorted.map((row) => {
3795
+ const key = keyOf(row);
3796
+ const isSelected = selected.includes(key);
3797
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("tr", { className: cx(isSelected && "ow-table__row--selected"), children: [
3798
+ selectable ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("td", { className: "ow-table__select", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3799
+ Checkbox,
3800
+ {
3801
+ size: "sm",
3802
+ "aria-label": "Select row",
3803
+ checked: isSelected,
3804
+ onChange: (event) => setSelected(
3805
+ event.target.checked ? [...selected, key] : selected.filter((k) => k !== key)
3806
+ )
3807
+ }
3808
+ ) }) : null,
3809
+ columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("td", { className: cx(`ow-table__cell--${column.align ?? "start"}`), children: column.render ? column.render(row) : field(row, column.key) }, column.key))
3810
+ ] }, key);
3811
+ }) })
3812
+ ] })
3813
+ }
3814
+ );
3815
+ }
3816
+
3817
+ // src/components/Stat/Stat.tsx
3818
+ var import_jsx_runtime41 = require("react/jsx-runtime");
3819
+ function Sparkline({ values }) {
3820
+ const max = Math.max(...values);
3821
+ const min = Math.min(...values);
3822
+ const span = max - min || 1;
3823
+ const points = values.map((value, index) => {
3824
+ const x = index / (values.length - 1) * 100;
3825
+ const y = 36 - (value - min) / span * 32;
3826
+ return [x, y];
3827
+ });
3828
+ const line = points.map(([x, y], index) => `${index ? "L" : "M"}${x.toFixed(2)} ${y.toFixed(2)}`).join(" ");
3829
+ const [lastX, lastY] = points[points.length - 1];
3830
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "ow-stat__trend", "aria-hidden": "true", children: [
3831
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("svg", { viewBox: "0 0 100 40", preserveAspectRatio: "none", children: [
3832
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("path", { d: `${line} L100 40 L0 40 Z`, className: "ow-stat__trend-area" }),
3833
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("path", { d: line, className: "ow-stat__trend-line", vectorEffect: "non-scaling-stroke" })
3834
+ ] }),
3835
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "ow-stat__trend-end", style: { left: `${lastX}%`, top: `${lastY / 40 * 100}%` } })
3836
+ ] });
3837
+ }
3838
+ function Stat({ label, value, icon: icon2, change, changeTone, description, trend, className }) {
3839
+ const tone = changeTone ?? (change?.startsWith("+") ? "positive" : /^[-−]/.test(change ?? "") ? "negative" : "neutral");
3840
+ const rising = change ? !/^[-−]/.test(change) : false;
3841
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: cx("ow-stat", className), children: [
3842
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "ow-stat__label", children: [
3843
+ icon2 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "ow-stat__icon", children: icon2 }) : null,
3844
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: label })
3845
+ ] }),
3846
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "ow-stat__row", children: [
3847
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "ow-stat__value", children: value }),
3848
+ change ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: cx("ow-stat__change", `ow-stat__change--${tone}`), children: [
3849
+ tone === "neutral" ? null : rising ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArrowUpIcon, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArrowDownIcon, { size: 12 }),
3850
+ change
3851
+ ] }) : null
3852
+ ] }),
3853
+ description ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "ow-stat__description", children: description }) : null,
3854
+ trend && trend.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Sparkline, { values: trend }) : null
3855
+ ] });
3856
+ }
3857
+
3858
+ // src/components/FileTree/FileTree.tsx
3859
+ var import_react42 = require("react");
3860
+ var import_jsx_runtime42 = require("react/jsx-runtime");
3861
+ function flatten(nodes, expanded, parent, level = 1) {
3862
+ return nodes.flatMap((node) => {
3863
+ const path = parent ? `${parent}/${node.name}` : node.name;
3864
+ const isFolder = node.children !== void 0;
3865
+ const row = { node, path, level, parent, isFolder };
3866
+ return isFolder && expanded.has(path) ? [row, ...flatten(node.children, expanded, path, level + 1)] : [row];
3867
+ });
3868
+ }
3869
+ function allFolders(nodes, parent) {
3870
+ return nodes.flatMap((node) => {
3871
+ const path = parent ? `${parent}/${node.name}` : node.name;
3872
+ return node.children ? [path, ...allFolders(node.children, path)] : [];
3873
+ });
3874
+ }
3875
+ function FileTree({
3876
+ items: items2,
3877
+ selected,
3878
+ defaultSelected = "",
3879
+ onSelect,
3880
+ defaultExpanded = "all",
3881
+ label = "Files",
3882
+ className
3883
+ }) {
3884
+ const [current, setCurrent] = useControllableState(selected, defaultSelected, onSelect);
3885
+ const [expanded, setExpanded] = (0, import_react42.useState)(() => new Set(defaultExpanded === "all" ? allFolders(items2) : defaultExpanded));
3886
+ const rows = (0, import_react42.useMemo)(() => flatten(items2, expanded), [items2, expanded]);
3887
+ const [focusPath, setFocusPath] = (0, import_react42.useState)();
3888
+ const refs = (0, import_react42.useRef)(/* @__PURE__ */ new Map());
3889
+ const tabStop = rows.some((row) => row.path === focusPath) ? focusPath : (rows.find((row) => row.path === current) ?? rows[0])?.path;
3890
+ function focus(path) {
3891
+ if (!path) return;
3892
+ setFocusPath(path);
3893
+ refs.current.get(path)?.focus();
3894
+ }
3895
+ function toggle(path, open) {
3896
+ setExpanded((previous) => {
3897
+ const next = new Set(previous);
3898
+ if (open ?? !next.has(path)) next.add(path);
3899
+ else next.delete(path);
3900
+ return next;
3901
+ });
3902
+ }
3903
+ function activate(row) {
3904
+ if (row.isFolder) toggle(row.path);
3905
+ else setCurrent(row.path);
3906
+ }
3907
+ function onKeyDown(event, row) {
3908
+ const index = rows.indexOf(row);
3909
+ const handlers = {
3910
+ ArrowDown: () => focus(rows[index + 1]?.path),
3911
+ ArrowUp: () => focus(rows[index - 1]?.path),
3912
+ Home: () => focus(rows[0]?.path),
3913
+ End: () => focus(rows[rows.length - 1]?.path),
3914
+ ArrowRight: () => {
3915
+ if (!row.isFolder) return;
3916
+ if (!expanded.has(row.path)) toggle(row.path, true);
3917
+ else focus(rows[index + 1]?.level === row.level + 1 ? rows[index + 1].path : void 0);
3918
+ },
3919
+ ArrowLeft: () => {
3920
+ if (row.isFolder && expanded.has(row.path)) toggle(row.path, false);
3921
+ else focus(row.parent);
3922
+ },
3923
+ Enter: () => activate(row),
3924
+ " ": () => activate(row)
3925
+ };
3926
+ const handler = handlers[event.key];
3927
+ if (!handler) return;
3928
+ event.preventDefault();
3929
+ event.stopPropagation();
3930
+ handler();
3931
+ }
3932
+ function render(nodes, parent, level = 1) {
3933
+ return nodes.map((node) => {
3934
+ const path = parent ? `${parent}/${node.name}` : node.name;
3935
+ const row = rows.find((entry) => entry.path === path);
3936
+ if (!row) return null;
3937
+ const isOpen = row.isFolder && expanded.has(path);
3938
+ const icon2 = node.icon ?? (row.isFolder ? isOpen ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FolderOpenIcon, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FolderIcon, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FileIcon, { size: 16 }));
3939
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
3940
+ "li",
3941
+ {
3942
+ ref: (element) => {
3943
+ if (element) refs.current.set(path, element);
3944
+ else refs.current.delete(path);
3945
+ },
3946
+ role: "treeitem",
3947
+ "aria-level": level,
3948
+ "aria-expanded": row.isFolder ? isOpen : void 0,
3949
+ "aria-selected": row.isFolder ? void 0 : current === path,
3950
+ tabIndex: tabStop === path ? 0 : -1,
3951
+ className: "ow-tree__item",
3952
+ onKeyDown: (event) => onKeyDown(event, row),
3953
+ onFocus: (event) => {
3954
+ if (event.target === event.currentTarget) setFocusPath(path);
3955
+ },
3956
+ children: [
3957
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
3958
+ "div",
3959
+ {
3960
+ className: cx("ow-tree__row", !row.isFolder && current === path && "ow-tree__row--selected"),
3961
+ title: path,
3962
+ onClick: () => {
3963
+ focus(path);
3964
+ activate(row);
3965
+ },
3966
+ children: [
3967
+ row.isFolder ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChevronRightIcon, { size: 14, className: cx("ow-tree__chevron", isOpen && "ow-tree__chevron--open") }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "ow-tree__spacer" }),
3968
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: cx("ow-tree__icon", row.isFolder && "ow-tree__icon--folder"), children: icon2 }),
3969
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "ow-tree__name", children: node.name }),
3970
+ node.meta ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "ow-tree__meta", children: node.meta }) : null
3971
+ ]
3972
+ }
3973
+ ),
3974
+ isOpen && node.children.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { role: "group", className: "ow-tree__group", children: render(node.children, path, level + 1) }) : null
3975
+ ]
3976
+ },
3977
+ path
3978
+ );
3979
+ });
3980
+ }
3981
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { role: "tree", "aria-label": label, className: cx("ow-tree", className), children: render(items2) });
3982
+ }
3983
+
3984
+ // src/components/EmptyState/EmptyState.tsx
3985
+ var import_jsx_runtime43 = require("react/jsx-runtime");
3986
+ function EmptyState({ title, description, icon: icon2, actions, bordered = false, className }) {
3987
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cx("ow-empty", bordered && "ow-empty--bordered", className), children: [
3988
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "ow-empty__icon", "aria-hidden": "true", children: icon2 ?? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(InboxIcon, { size: 20 }) }),
3989
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "ow-empty__text", children: [
3990
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "ow-empty__title", children: title }),
3991
+ description ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "ow-empty__description", children: description }) : null
3992
+ ] }),
3993
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "ow-empty__actions", children: actions }) : null
3994
+ ] });
3995
+ }
3996
+
3997
+ // src/components/Tag/Tag.tsx
3998
+ var import_jsx_runtime44 = require("react/jsx-runtime");
3999
+ function Tag({ onRemove, variant = "neutral", size = "md", icon: icon2, removeLabel, className, children, ...props }) {
4000
+ const name = removeLabel ?? (typeof children === "string" ? children : "tag");
4001
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: cx("ow-tag", `ow-tag--${variant}`, `ow-tag--${size}`, onRemove && "ow-tag--removable", className), ...props, children: [
4002
+ icon2 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "ow-tag__icon", children: icon2 }) : null,
4003
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "ow-tag__label", children }),
4004
+ onRemove ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { type: "button", className: "ow-tag__remove", "aria-label": `Remove ${name}`, onClick: onRemove, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(XIcon, { size: 12 }) }) : null
4005
+ ] });
4006
+ }
4007
+ function TagGroup({ label, className, children, ...props }) {
4008
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { role: "group", "aria-label": label, className: cx("ow-tag-group", className), ...props, children });
4009
+ }
4010
+ function ColorSwatch({ color, name, value, size = "md", shape = "square", className }) {
4011
+ const swatch = /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
4012
+ "span",
4013
+ {
4014
+ className: cx("ow-swatch", `ow-swatch--${size}`, shape === "circle" && "ow-swatch--circle"),
4015
+ style: { background: color },
4016
+ ...name && !value ? { role: "img", "aria-label": name } : { "aria-hidden": true }
4017
+ }
4018
+ );
4019
+ if (!name && !value) return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className, children: swatch });
4020
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: cx("ow-swatch-label", className), children: [
4021
+ swatch,
4022
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "ow-swatch-label__text", children: [
4023
+ name ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "ow-swatch-label__name", children: name }) : null,
4024
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "ow-swatch-label__value", children: value })
4025
+ ] })
4026
+ ] });
4027
+ }
4028
+
4029
+ // src/components/Avatar/Avatar.tsx
4030
+ var import_react43 = require("react");
4031
+ var import_jsx_runtime45 = require("react/jsx-runtime");
4032
+ function Avatar({ name, src, size = "md", label, className }) {
4033
+ const initials = getInitials(name);
4034
+ const [failedImage, setFailedImage] = (0, import_react43.useState)();
4035
+ const showImage = src && src !== failedImage;
4036
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4037
+ "span",
4038
+ {
4039
+ className: cx("ow-avatar", `ow-avatar--${size}`, !initials && !showImage && "ow-avatar--empty", className),
4040
+ ...label ? { role: "img", "aria-label": label } : { "aria-hidden": true },
4041
+ children: showImage ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("img", { src, alt: "", className: "ow-avatar__image", onError: () => setFailedImage(src) }) : initials || /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(UserIcon, { size: size === "sm" ? 13 : size === "lg" ? 18 : 15 })
4042
+ }
4043
+ );
4044
+ }
4045
+
4046
+ // src/components/Avatar/AvatarGroup.tsx
4047
+ var import_react44 = require("react");
4048
+ var import_jsx_runtime46 = require("react/jsx-runtime");
4049
+ function AvatarGroup({ children, max = 4, size = "md", label, className }) {
4050
+ const avatars = import_react44.Children.toArray(children).filter(import_react44.isValidElement);
4051
+ const shown = avatars.slice(0, max);
4052
+ const hidden = avatars.length - shown.length;
4053
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { role: "group", "aria-label": label, className: cx("ow-avatar-group", className), children: [
4054
+ shown.map((avatar) => (0, import_react44.cloneElement)(avatar, { size })),
4055
+ hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: cx("ow-avatar", `ow-avatar--${size}`, "ow-avatar--count"), children: [
4056
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { "aria-hidden": "true", children: [
4057
+ "+",
4058
+ hidden
4059
+ ] }),
4060
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ow-visually-hidden", children: [
4061
+ "and ",
4062
+ hidden,
4063
+ " more"
4064
+ ] })
4065
+ ] }) : null
4066
+ ] });
4067
+ }
4068
+ function User({ name, description, src, size = "md", className }) {
4069
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: cx("ow-user", `ow-user--${size}`, className), children: [
4070
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Avatar, { name, src, size }),
4071
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ow-user__text", children: [
4072
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ow-user__name", children: name }),
4073
+ description ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ow-user__description", children: description }) : null
4074
+ ] })
4075
+ ] });
4076
+ }
4077
+
4078
+ // src/components/Kbd/Kbd.tsx
4079
+ var import_jsx_runtime47 = require("react/jsx-runtime");
4080
+ function Kbd({ className, ...props }) {
4081
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("kbd", { className: cx("ow-kbd", className), ...props });
4082
+ }
4083
+ function Code({ className, ...props }) {
4084
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("code", { className: cx("ow-code", className), ...props });
4085
+ }
4086
+
4087
+ // src/components/Card/Card.tsx
4088
+ var import_jsx_runtime48 = require("react/jsx-runtime");
4089
+ function Card({ className, padding = "md", ...props }) {
4090
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: cx("ow-card", `ow-card--pad-${padding}`, className), ...props });
4091
+ }
4092
+ function SettingsRow({ children, description, label, className }) {
4093
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: cx("ow-settings-row", className), children: [
4094
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "ow-settings-row__text", children: [
4095
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ow-settings-row__label", children: label }),
4096
+ description ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ow-settings-row__description", children: description }) : null
4097
+ ] }),
4098
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ow-settings-row__control", children })
4099
+ ] });
4100
+ }
4101
+
4102
+ // src/components/Layout/Layout.tsx
4103
+ var import_react45 = require("react");
4104
+ var import_jsx_runtime49 = require("react/jsx-runtime");
4105
+ var space = (token) => token === "none" ? "0" : `var(--ow-space-${token})`;
4106
+ var alignments = { start: "flex-start", center: "center", end: "flex-end", stretch: "stretch", baseline: "baseline", between: "space-between" };
4107
+ function Stack({
4108
+ direction = "column",
4109
+ gap = "md",
4110
+ align,
4111
+ justify,
4112
+ wrap = false,
4113
+ as = "div",
4114
+ className,
4115
+ style,
4116
+ children,
4117
+ ...props
4118
+ }) {
4119
+ const Element = as;
4120
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
4121
+ Element,
4122
+ {
4123
+ className: cx("ow-stack", className),
4124
+ style: {
4125
+ flexDirection: direction,
4126
+ gap: space(gap),
4127
+ alignItems: align ? alignments[align] : void 0,
4128
+ justifyContent: justify ? alignments[justify] : void 0,
4129
+ flexWrap: wrap ? "wrap" : void 0,
4130
+ ...style
4131
+ },
4132
+ ...props,
4133
+ children
4134
+ }
4135
+ );
4136
+ }
4137
+ function Separator({ orientation = "horizontal", label, spacing = "none", className }) {
4138
+ const margin2 = orientation === "horizontal" ? `${space(spacing)} 0` : `0 ${space(spacing)}`;
4139
+ if (label && orientation === "horizontal") {
4140
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { role: "separator", className: cx("ow-separator-label", className), style: { margin: margin2 }, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "ow-separator-label__text", children: label }) });
4141
+ }
4142
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
4143
+ "div",
4144
+ {
4145
+ role: "separator",
4146
+ "aria-orientation": orientation,
4147
+ className: cx("ow-separator", `ow-separator--${orientation}`, className),
4148
+ style: { margin: margin2 }
4149
+ }
4150
+ );
4151
+ }
4152
+ function ScrollShadow({
4153
+ orientation = "vertical",
4154
+ size = 32,
4155
+ maxSize,
4156
+ className,
4157
+ style,
4158
+ children,
4159
+ "aria-label": ariaLabel,
4160
+ ...props
4161
+ }) {
4162
+ const ref = (0, import_react45.useRef)(null);
4163
+ const [edges, setEdges] = (0, import_react45.useState)({ start: false, end: false });
4164
+ (0, import_react45.useEffect)(() => {
4165
+ const element = ref.current;
4166
+ if (!element) return;
4167
+ const update = () => {
4168
+ const position = orientation === "vertical" ? element.scrollTop : element.scrollLeft;
4169
+ const extent = orientation === "vertical" ? element.scrollHeight - element.clientHeight : element.scrollWidth - element.clientWidth;
4170
+ setEdges({ start: position > 1, end: position < extent - 1 });
4171
+ };
4172
+ update();
4173
+ element.addEventListener("scroll", update, { passive: true });
4174
+ const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(update);
4175
+ observer?.observe(element);
4176
+ if (element.firstElementChild) observer?.observe(element.firstElementChild);
4177
+ return () => {
4178
+ element.removeEventListener("scroll", update);
4179
+ observer?.disconnect();
4180
+ };
4181
+ }, [orientation]);
4182
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
4183
+ "div",
4184
+ {
4185
+ ref,
4186
+ className: cx("ow-scroll-shadow", `ow-scroll-shadow--${orientation}`, className),
4187
+ "data-start": edges.start || void 0,
4188
+ "data-end": edges.end || void 0,
4189
+ tabIndex: ariaLabel ? 0 : void 0,
4190
+ role: ariaLabel ? "region" : void 0,
4191
+ "aria-label": ariaLabel,
4192
+ style: {
4193
+ "--ow-scroll-shadow": `${size}px`,
4194
+ [orientation === "vertical" ? "maxHeight" : "maxWidth"]: maxSize,
4195
+ ...style
4196
+ },
4197
+ ...props,
4198
+ children
4199
+ }
4200
+ );
4201
+ }
4202
+ function VisuallyHidden({ className, ...props }) {
4203
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: cx("ow-visually-hidden", className), ...props });
4204
+ }
4205
+
4206
+ // src/components/Marketing/Marketing.tsx
4207
+ var import_react46 = require("react");
4208
+ var import_jsx_runtime50 = require("react/jsx-runtime");
4209
+ function Chip({ className, ...props }) {
4210
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: cx("ow-chip", className), ...props });
4211
+ }
4212
+ function SectionHeading({
4213
+ eyebrow,
4214
+ title,
4215
+ intro,
4216
+ align = "start",
4217
+ as: Heading = "h2",
4218
+ className
4219
+ }) {
4220
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: cx("ow-section-heading", align === "center" && "ow-section-heading--center", className), children: [
4221
+ eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Chip, { children: eyebrow }) : null,
4222
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Heading, { className: "ow-section-heading__title", children: title }),
4223
+ intro ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "ow-section-heading__intro", children: intro }) : null
4224
+ ] });
4225
+ }
4226
+ function SiteHeader({ brand, nav, actions, className }) {
4227
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("header", { className: cx("ow-site-header", className), children: [
4228
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "ow-site-header__brand", children: brand }),
4229
+ nav ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("nav", { className: "ow-site-header__nav", children: nav }) : null,
4230
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "ow-site-header__actions", children: actions }) : null
4231
+ ] });
4232
+ }
4233
+ function DotGrid({ fade = false, interactive = false, className, children, onPointerMove, ...props }) {
4234
+ const ref = (0, import_react46.useRef)(null);
4235
+ function track(event) {
4236
+ onPointerMove?.(event);
4237
+ const element = ref.current;
4238
+ if (!interactive || !element) return;
4239
+ const rect = element.getBoundingClientRect();
4240
+ element.style.setProperty("--ow-pointer-x", `${event.clientX - rect.left}px`);
4241
+ element.style.setProperty("--ow-pointer-y", `${event.clientY - rect.top}px`);
4242
+ }
4243
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
4244
+ "div",
4245
+ {
4246
+ ref,
4247
+ className: cx("ow-dot-grid", fade && "ow-dot-grid--fade", interactive && "ow-dot-grid--interactive", className),
4248
+ onPointerMove: track,
4249
+ ...props,
4250
+ children: [
4251
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "ow-dot-grid__dots", "aria-hidden": "true" }),
4252
+ interactive ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "ow-dot-grid__brass", "aria-hidden": "true" }) : null,
4253
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "ow-dot-grid__content", children })
4254
+ ]
4255
+ }
4256
+ );
4257
+ }
4258
+
4259
+ // src/components/ColorPicker/ColorPicker.tsx
4260
+ var import_react47 = require("react");
4261
+ var import_react_colorful = require("react-colorful");
4262
+ var import_jsx_runtime51 = require("react/jsx-runtime");
4263
+ var swatchColor = (swatch) => typeof swatch === "string" ? swatch : swatch.color;
4264
+ var swatchName = (swatch) => typeof swatch === "string" ? swatch : swatch.name;
4265
+ var same = (a, b) => a.toLowerCase().replace(/^#/, "") === b.toLowerCase().replace(/^#/, "");
4266
+ function ColorPicker({
4267
+ value,
4268
+ defaultValue = "#312c7e",
4269
+ onChange,
4270
+ alpha = false,
4271
+ swatches,
4272
+ showInput = true,
4273
+ eyeDropper = true,
4274
+ "aria-label": ariaLabel = "Colour",
4275
+ className
4276
+ }) {
4277
+ const [color, setColor] = useControllableState(value, defaultValue, onChange);
4278
+ const [canPick, setCanPick] = (0, import_react47.useState)(false);
4279
+ const rootRef = (0, import_react47.useRef)(null);
4280
+ (0, import_react47.useEffect)(() => setCanPick(typeof window !== "undefined" && "EyeDropper" in window), []);
4281
+ (0, import_react47.useEffect)(() => {
4282
+ const names = { saturation: "Colour", hue: "Hue", alpha: "Opacity" };
4283
+ for (const [part, label] of Object.entries(names)) {
4284
+ rootRef.current?.querySelector(`.react-colorful__${part} .react-colorful__interactive`)?.setAttribute("aria-label", label);
4285
+ }
4286
+ }, [alpha]);
4287
+ const Picker = alpha ? import_react_colorful.HexAlphaColorPicker : import_react_colorful.HexColorPicker;
4288
+ const change = (next) => setColor(next.toLowerCase());
4289
+ async function pickFromScreen() {
4290
+ if (!window.EyeDropper) return;
4291
+ try {
4292
+ const result = await new window.EyeDropper().open();
4293
+ change(result.sRGBHex);
4294
+ } catch {
4295
+ }
4296
+ }
4297
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { ref: rootRef, role: "group", "aria-label": ariaLabel, className: cx("ow-color-picker", className), children: [
4298
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Picker, { color, onChange: change }),
4299
+ showInput || eyeDropper && canPick ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "ow-color-picker__row", children: [
4300
+ eyeDropper && canPick ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", className: "ow-color-picker__dropper", "aria-label": "Pick a colour from the screen", onClick: pickFromScreen, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(PipetteIcon, { size: 15 }) }) : null,
4301
+ showInput ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { className: "ow-input-group ow-input-group--sm ow-color-picker__input", children: [
4302
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "ow-input-group__addon", "aria-hidden": "true", children: "#" }),
4303
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4304
+ import_react_colorful.HexColorInput,
4305
+ {
4306
+ className: "ow-input-group__input",
4307
+ color,
4308
+ onChange: change,
4309
+ alpha,
4310
+ "aria-label": "Hex colour",
4311
+ spellCheck: false
4312
+ }
4313
+ )
4314
+ ] }) : null,
4315
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "ow-color-picker__preview", style: { "--ow-color-picker-value": color }, "aria-hidden": "true" })
4316
+ ] }) : null,
4317
+ swatches?.length ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "ow-color-picker__swatches", role: "group", "aria-label": "Swatches", children: swatches.map((swatch) => {
4318
+ const swatchValue = swatchColor(swatch);
4319
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4320
+ "button",
4321
+ {
4322
+ type: "button",
4323
+ className: "ow-color-picker__swatch",
4324
+ style: { "--ow-color-picker-value": swatchValue },
4325
+ "aria-label": swatchName(swatch),
4326
+ "aria-pressed": same(swatchValue, color),
4327
+ title: swatchName(swatch),
4328
+ onClick: () => change(swatchValue)
4329
+ },
4330
+ swatchValue
4331
+ );
4332
+ }) }) : null
4333
+ ] });
4334
+ }
4335
+ function assignRef6(ref, value) {
4336
+ if (typeof ref === "function") ref(value);
4337
+ else if (ref) ref.current = value;
4338
+ }
4339
+ var ColorField = (0, import_react47.forwardRef)(function ColorField2({
4340
+ value,
4341
+ defaultValue = "#312c7e",
4342
+ onChange,
4343
+ size = "md",
4344
+ isInvalid = false,
4345
+ disabled = false,
4346
+ placement = "bottom-start",
4347
+ id,
4348
+ className,
4349
+ "aria-label": ariaLabel,
4350
+ "aria-labelledby": ariaLabelledBy,
4351
+ "aria-describedby": ariaDescribedBy,
4352
+ ...pickerProps
4353
+ }, ref) {
4354
+ const [color, setColor] = useControllableState(value, defaultValue, onChange);
4355
+ const [isOpen, setOpen] = (0, import_react47.useState)(false);
4356
+ const triggerRef = (0, import_react47.useRef)(null);
4357
+ const panelRef = (0, import_react47.useRef)(null);
4358
+ const panelId = (0, import_react47.useId)();
4359
+ const { mounted, state } = usePresence(isOpen);
4360
+ const style = useFloating({ open: mounted, anchorRef: triggerRef, floatingRef: panelRef, placement, offset: 6, maxHeight: 640 });
4361
+ const close = (0, import_react47.useCallback)((reason) => {
4362
+ setOpen(false);
4363
+ if (reason !== "outside") triggerRef.current?.focus();
4364
+ }, []);
4365
+ useDismiss(isOpen, [panelRef, triggerRef], close);
4366
+ (0, import_react47.useEffect)(() => {
4367
+ if (!isOpen) return void 0;
4368
+ const frame = requestAnimationFrame(() => panelRef.current?.querySelector(".react-colorful__interactive")?.focus());
4369
+ return () => cancelAnimationFrame(frame);
4370
+ }, [isOpen]);
4371
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
4372
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
4373
+ "button",
4374
+ {
4375
+ ref: (element) => {
4376
+ triggerRef.current = element;
4377
+ assignRef6(ref, element);
4378
+ },
4379
+ id,
4380
+ type: "button",
4381
+ "aria-haspopup": "dialog",
4382
+ "aria-expanded": isOpen,
4383
+ "aria-controls": isOpen ? panelId : void 0,
4384
+ "aria-label": ariaLabel,
4385
+ "aria-labelledby": ariaLabelledBy,
4386
+ "aria-describedby": [`${panelId}-value`, ariaDescribedBy].filter(Boolean).join(" "),
4387
+ "aria-invalid": isInvalid || void 0,
4388
+ disabled,
4389
+ className: cx(
4390
+ "ow-select",
4391
+ "ow-color-field",
4392
+ `ow-select--${size}`,
4393
+ { "ow-select--open": isOpen, "ow-select--invalid": isInvalid && !isOpen },
4394
+ className
4395
+ ),
4396
+ onClick: () => setOpen(!isOpen),
4397
+ onKeyDown: (event) => {
4398
+ if (event.key === "ArrowDown" && !isOpen) {
4399
+ event.preventDefault();
4400
+ setOpen(true);
4401
+ }
4402
+ },
4403
+ children: [
4404
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "ow-color-field__swatch", style: { "--ow-color-picker-value": color }, "aria-hidden": "true" }),
4405
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { id: `${panelId}-value`, className: "ow-select__value ow-color-field__value", children: color.toUpperCase() }),
4406
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ChevronDownIcon, { size: size === "sm" ? 14 : 16, className: "ow-select__chevron" })
4407
+ ]
4408
+ }
4409
+ ),
4410
+ mounted ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4411
+ "div",
4412
+ {
4413
+ ref: panelRef,
4414
+ ...manualPopover,
4415
+ "data-state": state,
4416
+ id: panelId,
4417
+ role: "dialog",
4418
+ "aria-label": "Choose a colour",
4419
+ className: "ow-popover ow-floating ow-color-field__panel",
4420
+ style,
4421
+ onKeyDown: (event) => {
4422
+ if (event.key === "Enter" && event.target.closest(".react-colorful")) close();
4423
+ },
4424
+ children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ColorPicker, { ...pickerProps, value: color, onChange: setColor })
4425
+ }
4426
+ ) : null
4427
+ ] });
4428
+ });
4429
+
4430
+ // src/utils/brand.ts
4431
+ var brandSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
4432
+ var lightness = [0.968, 0.94, 0.89, 0.81, 0.68, 0.53, 0.42, 0.33, 0.27, 0.22, 0.17];
4433
+ var chroma = [0.012, 0.022, 0.04, 0.066, 0.1, 0.135, 0.134, 0.086, 0.072, 0.058, 0.045];
4434
+ var peakChroma = 0.135;
4435
+ function parseHex(color) {
4436
+ let hex = color.trim().replace(/^#/, "");
4437
+ if (hex.length === 3 || hex.length === 4) hex = [...hex.slice(0, 3)].map((d) => d + d).join("");
4438
+ if (!/^[0-9a-f]{6}([0-9a-f]{2})?$/i.test(hex)) throw new Error(`brandScale: "${color}" isn't a hex colour like #2563eb.`);
4439
+ return [0, 2, 4].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
4440
+ }
4441
+ var toLinear = (v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
4442
+ var fromLinear = (v) => v <= 31308e-7 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055;
4443
+ function hexToOklch(color) {
4444
+ const [r, g, b] = parseHex(color).map(toLinear);
4445
+ const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
4446
+ const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
4447
+ const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
4448
+ const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
4449
+ const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
4450
+ const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
4451
+ return { l: L, c: Math.hypot(A, B), h: (Math.atan2(B, A) * 180 / Math.PI + 360) % 360 };
4452
+ }
4453
+ function oklchToLinear({ l: L, c, h }) {
4454
+ const A = c * Math.cos(h * Math.PI / 180);
4455
+ const B = c * Math.sin(h * Math.PI / 180);
4456
+ const l = (L + 0.3963377774 * A + 0.2158037573 * B) ** 3;
4457
+ const m = (L - 0.1055613458 * A - 0.0638541728 * B) ** 3;
4458
+ const s = (L - 0.0894841775 * A - 1.291485548 * B) ** 3;
4459
+ return [
4460
+ 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
4461
+ -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
4462
+ -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
4463
+ ];
4464
+ }
4465
+ var inGamut = (rgb) => rgb.every((v) => v >= -1e-4 && v <= 1 + 1e-4);
4466
+ function toHex(color) {
4467
+ let { c } = color;
4468
+ if (!inGamut(oklchToLinear(color))) {
4469
+ let low = 0;
4470
+ let high = c;
4471
+ for (let i = 0; i < 24; i += 1) {
4472
+ const mid = (low + high) / 2;
4473
+ if (inGamut(oklchToLinear({ ...color, c: mid }))) low = mid;
4474
+ else high = mid;
4475
+ }
4476
+ c = low;
4477
+ }
4478
+ return `#${oklchToLinear({ ...color, c }).map((v) => Math.round(Math.min(1, Math.max(0, fromLinear(Math.min(1, Math.max(0, v))))) * 255)).map((v) => v.toString(16).padStart(2, "0")).join("")}`;
4479
+ }
4480
+ function brandScale(color) {
4481
+ const { c, h } = hexToOklch(color);
4482
+ const strength = Math.min(1.6, c / peakChroma);
4483
+ return Object.fromEntries(brandSteps.map((step, i) => [step, toHex({ l: lightness[i], c: chroma[i] * strength, h })]));
4484
+ }
4485
+ function brandVariables(brand) {
4486
+ const scale = typeof brand === "string" ? brandScale(brand) : brand;
4487
+ return Object.fromEntries(brandSteps.map((step) => [`--ow-brand-${step}`, scale[step]]));
4488
+ }
4489
+ function brandCss(brand, selector = ":root") {
4490
+ const scale = typeof brand === "string" ? brandScale(brand) : brand;
4491
+ return `${selector} {
4492
+ ${brandSteps.map((step) => ` --ow-brand-${step}: ${scale[step]};`).join("\n")}
4493
+ }`;
4494
+ }
4495
+ function applyBrand(brand, element = document.documentElement) {
4496
+ for (const step of brandSteps) element.style.removeProperty(`--ow-brand-${step}`);
4497
+ if (brand === null) return;
4498
+ const variables = brandVariables(brand);
4499
+ for (const [name, value] of Object.entries(variables)) element.style.setProperty(name, value);
4500
+ }
4501
+ var brandPresets = [
4502
+ {
4503
+ id: "midnight",
4504
+ name: "Midnight",
4505
+ scale: {
4506
+ 50: "#f2f3fc",
4507
+ 100: "#e7e9f9",
4508
+ 200: "#d4d7f4",
4509
+ 300: "#b7bbea",
4510
+ 400: "#898cd0",
4511
+ 500: "#5856ad",
4512
+ 600: "#312c7e",
4513
+ 700: "#1e1b4b",
4514
+ 800: "#18163d",
4515
+ 900: "#13112f",
4516
+ 950: "#0b0a20"
4517
+ }
4518
+ },
4519
+ {
4520
+ id: "ocean",
4521
+ name: "Ocean",
4522
+ scale: {
4523
+ 50: "#edf5fe",
4524
+ 100: "#dfedfd",
4525
+ 200: "#c3defa",
4526
+ 300: "#9ac5f3",
4527
+ 400: "#5a9de0",
4528
+ 500: "#006ebe",
4529
+ 600: "#004f8a",
4530
+ 700: "#003763",
4531
+ 800: "#00274a",
4532
+ 900: "#001b36",
4533
+ 950: "#001023"
4534
+ }
4535
+ },
4536
+ {
4537
+ id: "teal",
4538
+ name: "Teal",
4539
+ scale: {
4540
+ 50: "#ebf7f7",
4541
+ 100: "#daf1f0",
4542
+ 200: "#bae4e4",
4543
+ 300: "#87d0cf",
4544
+ 400: "#1fadad",
4545
+ 500: "#007c7c",
4546
+ 600: "#005959",
4547
+ 700: "#003e3e",
4548
+ 800: "#002d2d",
4549
+ 900: "#002020",
4550
+ 950: "#001313"
4551
+ }
4552
+ },
4553
+ {
4554
+ id: "forest",
4555
+ name: "Forest",
4556
+ scale: {
4557
+ 50: "#eef7f0",
4558
+ 100: "#e0f0e3",
4559
+ 200: "#c6e4cd",
4560
+ 300: "#9ecfaa",
4561
+ 400: "#5fac76",
4562
+ 500: "#008240",
4563
+ 600: "#005d2d",
4564
+ 700: "#00411d",
4565
+ 800: "#003014",
4566
+ 900: "#00220c",
4567
+ 950: "#001506"
4568
+ }
4569
+ },
4570
+ {
4571
+ id: "plum",
4572
+ name: "Plum",
4573
+ scale: {
4574
+ 50: "#f9f2f9",
4575
+ 100: "#f4e6f4",
4576
+ 200: "#ead1eb",
4577
+ 300: "#dab1db",
4578
+ 400: "#bb80be",
4579
+ 500: "#95489a",
4580
+ 600: "#732778",
4581
+ 700: "#4d2150",
4582
+ 800: "#39163b",
4583
+ 900: "#290e2b",
4584
+ 950: "#1a071b"
4585
+ }
4586
+ },
4587
+ {
4588
+ id: "rose",
4589
+ name: "Rose",
4590
+ scale: {
4591
+ 50: "#fef1f1",
4592
+ 100: "#fce5e6",
4593
+ 200: "#f8cfd1",
4594
+ 300: "#eeadb1",
4595
+ 400: "#d67981",
4596
+ 500: "#b43b4e",
4597
+ 600: "#8e1331",
4598
+ 700: "#5e1924",
4599
+ 800: "#470f19",
4600
+ 900: "#330910",
4601
+ 950: "#210408"
4602
+ }
4603
+ },
4604
+ {
4605
+ id: "ember",
4606
+ name: "Ember",
4607
+ scale: {
4608
+ 50: "#fdf2ec",
4609
+ 100: "#fae7dd",
4610
+ 200: "#f5d3c0",
4611
+ 300: "#eab395",
4612
+ 400: "#d18254",
4613
+ 500: "#a94e00",
4614
+ 600: "#7b3700",
4615
+ 700: "#572500",
4616
+ 800: "#411900",
4617
+ 900: "#2f1100",
4618
+ 950: "#1e0800"
4619
+ }
4620
+ }
4621
+ ];
4622
+ //# sourceMappingURL=index.cjs.map