@openwarelabs/ui 0.0.0-stage → 0.1.0

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