@reopt-ai/opt-ui 1.5.0 → 1.7.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 (99) hide show
  1. package/COMPONENT_CATALOG.md +178 -50
  2. package/README.md +28 -7
  3. package/dist/app.css +170 -0
  4. package/dist/core/index.cjs +164 -324
  5. package/dist/core/index.d.cts +3 -6
  6. package/dist/core/index.d.ts +3 -6
  7. package/dist/core/index.js +3 -323
  8. package/dist/docs/01-getting-started.md +25 -5
  9. package/dist/docs/02-components/01-core.md +36 -28
  10. package/dist/docs/02-components/02-visuals.md +1 -1
  11. package/dist/docs/02-components/03-shells.md +144 -23
  12. package/dist/docs/02-components/04-surfaces.md +1 -1
  13. package/dist/docs/02-components/index.md +4 -4
  14. package/dist/docs/03-recipes/03-layouts.md +16 -12
  15. package/dist/docs/05-migration/01-breaking-changes.md +46 -1
  16. package/dist/field-sidebar-BTZCBviA.d.cts +1031 -0
  17. package/dist/field-sidebar-BTZCBviA.d.cts.map +1 -0
  18. package/dist/field-sidebar-CB8vjvUM.d.ts +1031 -0
  19. package/dist/field-sidebar-CB8vjvUM.d.ts.map +1 -0
  20. package/dist/field-sidebar-Cs-J-5VE.js +4233 -0
  21. package/dist/field-sidebar-Cs-J-5VE.js.map +1 -0
  22. package/dist/field-sidebar-CzIQX70-.cjs +4561 -0
  23. package/dist/id-registry.cjs +1939 -1872
  24. package/dist/id-registry.d.cts +14 -11
  25. package/dist/id-registry.d.cts.map +1 -0
  26. package/dist/id-registry.d.ts +14 -11
  27. package/dist/id-registry.d.ts.map +1 -0
  28. package/dist/id-registry.js +1937 -1871
  29. package/dist/id-registry.js.map +1 -0
  30. package/dist/id-registry.json +113 -28
  31. package/dist/index.cjs +8380 -9790
  32. package/dist/index.d.cts +1555 -1442
  33. package/dist/index.d.cts.map +1 -0
  34. package/dist/index.d.ts +1555 -1442
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +7996 -9778
  37. package/dist/index.js.map +1 -0
  38. package/dist/meta.cjs +7753 -6875
  39. package/dist/meta.d.cts.map +1 -0
  40. package/dist/meta.d.ts.map +1 -0
  41. package/dist/meta.js +7752 -6846
  42. package/dist/meta.js.map +1 -0
  43. package/dist/pagination-DWbvACuN.js +3850 -0
  44. package/dist/pagination-DWbvACuN.js.map +1 -0
  45. package/dist/pagination-DjfxBcjX.cjs +4739 -0
  46. package/dist/query.cjs +386 -0
  47. package/dist/query.d.cts +141 -0
  48. package/dist/query.d.cts.map +1 -0
  49. package/dist/query.d.ts +141 -0
  50. package/dist/query.d.ts.map +1 -0
  51. package/dist/query.js +371 -0
  52. package/dist/query.js.map +1 -0
  53. package/dist/shader-surface-BUPZ0P-n.js +3654 -0
  54. package/dist/shader-surface-BUPZ0P-n.js.map +1 -0
  55. package/dist/shader-surface-BfTP9c1Q.d.ts +1788 -0
  56. package/dist/shader-surface-BfTP9c1Q.d.ts.map +1 -0
  57. package/dist/shader-surface-DRrcLrWf.d.cts +1788 -0
  58. package/dist/shader-surface-DRrcLrWf.d.cts.map +1 -0
  59. package/dist/shader-surface-Fav5K9UC.cjs +4041 -0
  60. package/dist/shells/index.cjs +58 -65
  61. package/dist/shells/index.d.cts +4 -5
  62. package/dist/shells/index.d.ts +4 -5
  63. package/dist/shells/index.js +4 -64
  64. package/dist/tailwind.css +49 -0
  65. package/dist/theme/presets/default.css +2 -2
  66. package/dist/theme/presets/minimal.css +2 -2
  67. package/dist/theme/presets/mono-dark.css +2 -2
  68. package/dist/theme/presets/natural.css +1 -1
  69. package/dist/theme/presets/pro.css +2 -2
  70. package/dist/theme/server.cjs +257 -228
  71. package/dist/theme/server.d.cts +48 -60
  72. package/dist/theme/server.d.cts.map +1 -0
  73. package/dist/theme/server.d.ts +48 -60
  74. package/dist/theme/server.d.ts.map +1 -0
  75. package/dist/theme/server.js +234 -189
  76. package/dist/theme/server.js.map +1 -0
  77. package/dist/types-D0FlcYnM.d.cts +301 -0
  78. package/dist/types-D0FlcYnM.d.cts.map +1 -0
  79. package/dist/types-D0FlcYnM.d.ts +301 -0
  80. package/dist/types-D0FlcYnM.d.ts.map +1 -0
  81. package/dist/visuals/index.cjs +10 -4
  82. package/dist/visuals/index.d.cts +2 -1
  83. package/dist/visuals/index.d.ts +2 -1
  84. package/dist/visuals/index.js +1 -2
  85. package/package.json +27 -11
  86. package/dist/chunk-3GWWZKX7.js +0 -38
  87. package/dist/chunk-3QFYBBL6.cjs +0 -4759
  88. package/dist/chunk-3XD4HIFL.js +0 -3241
  89. package/dist/chunk-AFF2HPE5.cjs +0 -5008
  90. package/dist/chunk-NXZJIHEZ.cjs +0 -3241
  91. package/dist/chunk-ONE3C5RV.cjs +0 -38
  92. package/dist/chunk-RBM2RNC2.js +0 -5008
  93. package/dist/chunk-VBGPEW45.js +0 -4759
  94. package/dist/index-BZ_lBlO1.d.ts +0 -474
  95. package/dist/index-BuvxoWHf.d.cts +0 -474
  96. package/dist/index-DWyqDIkH.d.cts +0 -1689
  97. package/dist/index-Uyijm14M.d.ts +0 -1689
  98. package/dist/types-D4-0lwaE.d.cts +0 -298
  99. package/dist/types-D4-0lwaE.d.ts +0 -298
@@ -0,0 +1,3850 @@
1
+ "use client";
2
+ import { clsx } from "clsx";
3
+ import { twMerge } from "tailwind-merge";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import * as React from "react";
6
+ import { createContext, forwardRef, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
7
+ import { AlertDialogPanel, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxPopover, ComboboxRoot, Composite, CompositeItem, CompositeProvider, CompositeRow, DialogDescription, DialogDisclosure, DialogDismiss, DialogHeading, DialogPanel, DialogRoot, DisclosureContent, DisclosureRoot, DisclosureTrigger, FormCheckbox, FormControl, FormDescription, FormError, FormField, FormGroup, FormGroupLabel, FormInput, FormLabel, FormProvider, FormPush, FormRadio, FormRadioGroup, FormRemove, FormReset, FormRoot, FormSubmit, FormSwitch, MenuButtonArrow, MenuItem, MenuItemCheckbox, MenuItemRadio, MenuPopover, MenuRoot, MenuSeparator, MenuTrigger, MenubarContainer, MenubarRoot, PopoverClose, PopoverContent, PopoverRoot, PopoverTrigger, SelectItem, SelectLabel, SelectPopover, SelectRoot, SelectTrigger, Tab, TabList, TabPanel, TabsRoot, ToolbarButton, ToolbarContainer, ToolbarRoot, ToolbarSeparator, Tooltip, TooltipAnchor, TooltipProvider, useFieldValue, useFormContext, useFormStore } from "@reopt-ai/opt-ui-primitives";
8
+ import { Bell, CalendarDays, ChartColumn, Check, ChevronLeft, ChevronRight, CircleAlert, CircleCheck, CreditCard, Download, Eye, FileText, Flag, Folder, Globe, Heart, Info, Link2, LogIn, Mail, MessageCircle, MousePointerClick, Search, Settings, Share2, ShoppingCart, Star, TrendingUp, TriangleAlert, Upload, User, UserPlus, XCircle, Zap } from "lucide-react";
9
+ //#region src/lib/cn.ts
10
+ /** Handles cn. */
11
+ function cn(...inputs) {
12
+ return twMerge(clsx(inputs));
13
+ }
14
+ //#endregion
15
+ //#region src/core/kbd.tsx
16
+ /** Renders the kbd component. */
17
+ function Kbd({ children, hint = false, className }) {
18
+ return /* @__PURE__ */ jsx("kbd", {
19
+ className: cn("border-border bg-bg-subtle text-text-tertiary inline-flex h-5 items-center gap-0.5 rounded border px-1.5 text-[11px] font-medium", hint && "opt-shortcut-hint", className),
20
+ "data-opt-id": "NPHB8",
21
+ "data-opt-slug": "kbd.Kbd",
22
+ children
23
+ });
24
+ }
25
+ //#endregion
26
+ //#region \0@oxc-project+runtime@0.146.0/helpers/esm/objectWithoutPropertiesLoose.js
27
+ function _objectWithoutPropertiesLoose(r, e) {
28
+ if (null == r) return {};
29
+ var t = {};
30
+ for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
31
+ if (e.includes(n)) continue;
32
+ t[n] = r[n];
33
+ }
34
+ return t;
35
+ }
36
+ //#endregion
37
+ //#region \0@oxc-project+runtime@0.146.0/helpers/esm/objectWithoutProperties.js
38
+ function _objectWithoutProperties(e, t) {
39
+ if (null == e) return {};
40
+ var o, r, i = _objectWithoutPropertiesLoose(e, t);
41
+ if (Object.getOwnPropertySymbols) {
42
+ var s = Object.getOwnPropertySymbols(e);
43
+ for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
44
+ }
45
+ return i;
46
+ }
47
+ //#endregion
48
+ //#region \0@oxc-project+runtime@0.146.0/helpers/esm/typeof.js
49
+ function _typeof(o) {
50
+ "@babel/helpers - typeof";
51
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
52
+ return typeof o;
53
+ } : function(o) {
54
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
55
+ }, _typeof(o);
56
+ }
57
+ //#endregion
58
+ //#region \0@oxc-project+runtime@0.146.0/helpers/esm/toPrimitive.js
59
+ function toPrimitive(t, r) {
60
+ if ("object" != _typeof(t) || !t) return t;
61
+ var e = t[Symbol.toPrimitive];
62
+ if (void 0 !== e) {
63
+ var i = e.call(t, r || "default");
64
+ if ("object" != _typeof(i)) return i;
65
+ throw new TypeError("@@toPrimitive must return a primitive value.");
66
+ }
67
+ return ("string" === r ? String : Number)(t);
68
+ }
69
+ //#endregion
70
+ //#region \0@oxc-project+runtime@0.146.0/helpers/esm/toPropertyKey.js
71
+ function toPropertyKey(t) {
72
+ var i = toPrimitive(t, "string");
73
+ return "symbol" == _typeof(i) ? i : i + "";
74
+ }
75
+ //#endregion
76
+ //#region \0@oxc-project+runtime@0.146.0/helpers/esm/defineProperty.js
77
+ function _defineProperty(e, r, t) {
78
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
79
+ value: t,
80
+ enumerable: !0,
81
+ configurable: !0,
82
+ writable: !0
83
+ }) : e[r] = t, e;
84
+ }
85
+ //#endregion
86
+ //#region \0@oxc-project+runtime@0.146.0/helpers/esm/objectSpread2.js
87
+ function ownKeys(e, r) {
88
+ var t = Object.keys(e);
89
+ if (Object.getOwnPropertySymbols) {
90
+ var o = Object.getOwnPropertySymbols(e);
91
+ r && (o = o.filter(function(r) {
92
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
93
+ })), t.push.apply(t, o);
94
+ }
95
+ return t;
96
+ }
97
+ function _objectSpread2(e) {
98
+ for (var r = 1; r < arguments.length; r++) {
99
+ var t = null != arguments[r] ? arguments[r] : {};
100
+ r % 2 ? ownKeys(Object(t), !0).forEach(function(r) {
101
+ _defineProperty(e, r, t[r]);
102
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r) {
103
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
104
+ });
105
+ }
106
+ return e;
107
+ }
108
+ //#endregion
109
+ //#region src/lib/styles.ts
110
+ /**
111
+ * 공유 스타일 토큰 — Primitive 전체에서 중복되는 Tailwind 패턴을 상수화합니다.
112
+ * 각 primitive는 이 토큰을 조합하고, 컴포넌트별 특수 스타일만 로컬에 정의합니다.
113
+ *
114
+ * CSS 변수 기반 — dark: prefix 불필요. 테마 프리셋이 모드별 값을 자동 해석합니다.
115
+ */
116
+ const OPT_FOCUS = "outline-none data-[focus-visible]:outline-2 data-[focus-visible]:outline-ring data-[focus-visible]:-outline-offset-1";
117
+ const OPT_FOCUS_VISIBLE = "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset";
118
+ const OPT_ACTIVE_ITEM = "data-[active-item]:bg-accent data-[active-item]:text-accent-fg";
119
+ const OPT_HOVER_ITEM = "[@media(any-hover:hover)]:hover:bg-accent-subtle active:bg-accent-subtle";
120
+ const OPT_BORDER = "border border-border";
121
+ const OPT_DIVIDER = "divide-border-subtle";
122
+ const OPT_SURFACE = "rounded-lg bg-surface shadow-sm";
123
+ const OPT_SURFACE_POPOVER = "z-50 rounded-lg border border-border bg-surface-overlay p-2 shadow-lg";
124
+ const OPT_TEXT_PRIMARY = "text-text-primary";
125
+ const OPT_TEXT_SECONDARY = "text-text-secondary";
126
+ const OPT_TEXT_TERTIARY = "text-text-tertiary";
127
+ const OPT_TEXT_LABEL = "text-sm font-medium text-text-primary";
128
+ const OPT_ITEM_BASE = "cursor-default rounded px-2 py-2 text-sm outline-none text-text-primary";
129
+ const OPT_INPUT = "flex h-10 w-full rounded-lg border border-border bg-surface px-4 text-sm text-text-primary outline-none placeholder:text-text-tertiary focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset";
130
+ const OPT_INPUT_SIZE = {
131
+ sm: "h-8 px-3 text-xs",
132
+ md: "",
133
+ lg: "h-12 px-5 text-base"
134
+ };
135
+ const OPT_TEXTAREA_SIZE = {
136
+ sm: "px-3 py-2 text-xs",
137
+ md: "",
138
+ lg: "px-5 py-4 text-base"
139
+ };
140
+ const OPT_INPUT_ERROR = "border-danger focus-visible:outline-danger";
141
+ const OPT_BADGE = "inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium";
142
+ const OPT_BADGE_BLUE = `${OPT_BADGE} bg-info-subtle text-info-fg`;
143
+ const OPT_BADGE_GREEN = `${OPT_BADGE} bg-success-subtle text-success-fg`;
144
+ const OPT_BADGE_YELLOW = `${OPT_BADGE} bg-warning-subtle text-warning-fg`;
145
+ const OPT_BADGE_RED = `${OPT_BADGE} bg-danger-subtle text-danger-fg`;
146
+ const OPT_BADGE_NEUTRAL = `${OPT_BADGE} bg-bg-subtle text-text-secondary`;
147
+ const OPT_BUTTON_PRIMARY = "inline-flex h-10 items-center justify-center rounded-lg bg-accent px-4 text-sm font-medium text-accent-fg outline-none hover:bg-accent-hover active:bg-accent-active focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2";
148
+ const OPT_BUTTON_SECONDARY = "inline-flex h-10 items-center justify-center rounded-lg border border-border bg-surface px-4 text-sm font-medium text-text-primary outline-none hover:bg-bg-subtle active:bg-bg-muted focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1";
149
+ const OPT_TH = "px-3 py-2.5 text-left text-xs font-semibold uppercase tracking-wider text-text-tertiary";
150
+ const OPT_TD = "px-3 py-2.5 text-sm text-text-primary whitespace-nowrap";
151
+ const OPT_TD_MUTED = "px-3 py-2.5 text-sm text-text-tertiary whitespace-nowrap";
152
+ const OPT_TABLE_ROW_ACTIVE = "outline-none data-[active-item]:bg-accent-subtle data-[focus-visible]:outline-2 data-[focus-visible]:outline-ring data-[focus-visible]:-outline-offset-1";
153
+ const OPT_DISCLOSURE_TRIGGER = "flex w-full items-center justify-between px-4 py-3.5 text-left text-sm font-medium text-text-primary outline-none hover:underline decoration-border underline-offset-2 data-[focus-visible]:outline-2 data-[focus-visible]:outline-ring data-[focus-visible]:-outline-offset-2";
154
+ const OPT_DISCLOSURE_CONTENT = "overflow-hidden data-[enter]:animate-in data-[enter]:fade-in data-[leave]:animate-out data-[leave]:fade-out";
155
+ const OPT_ANIMATE_ENTER_EXIT = "data-[enter]:animate-in data-[enter]:fade-in data-[enter]:slide-in-from-top-1 data-[leave]:animate-out data-[leave]:fade-out";
156
+ const OPT_ANIMATE_DIALOG = "data-[enter]:animate-in data-[enter]:fade-in data-[enter]:slide-in-from-top-2 data-[leave]:animate-out data-[leave]:fade-out data-[leave]:slide-out-to-top-2";
157
+ /**
158
+ * Drawer slide-in/out animations per side. ariakit `data-[enter]/data-[leave]`
159
+ * 패턴으로 `animate-in/animate-out` + `slide-in-from-{side}` 조합을 노출한다.
160
+ *
161
+ * Drawer 컴포넌트가 직접 인라인으로 정의하지 않고 이 토큰을 참조하도록 일관화.
162
+ */
163
+ const OPT_ANIMATE_DRAWER = {
164
+ right: "data-[enter]:animate-in data-[enter]:slide-in-from-right data-[leave]:animate-out data-[leave]:slide-out-to-right",
165
+ left: "data-[enter]:animate-in data-[enter]:slide-in-from-left data-[leave]:animate-out data-[leave]:slide-out-to-left",
166
+ bottom: "data-[enter]:animate-in data-[enter]:slide-in-from-bottom data-[leave]:animate-out data-[leave]:slide-out-to-bottom"
167
+ };
168
+ const OPT_DOT_GREEN = "h-2 w-2 rounded-full bg-success";
169
+ const OPT_DOT_YELLOW = "h-2 w-2 rounded-full bg-warning";
170
+ const OPT_DOT_RED = "h-2 w-2 rounded-full bg-danger";
171
+ const OPT_DOT_GRAY = "h-2 w-2 rounded-full bg-bg-muted";
172
+ //#endregion
173
+ //#region src/lib/field-messages.tsx
174
+ /**
175
+ * Internal utilities for field label/error/hint rendering.
176
+ * Not exported from the package — used only by Core components.
177
+ */
178
+ /** Renders a red asterisk for required fields. */
179
+ function RequiredMark() {
180
+ return /* @__PURE__ */ jsx("span", {
181
+ className: "text-danger-fg ml-0.5",
182
+ "aria-hidden": "true",
183
+ children: "*"
184
+ });
185
+ }
186
+ /** Computes the aria-describedby value from error/hint state. */
187
+ function getDescribedBy(id, error, hint) {
188
+ if (!id) return void 0;
189
+ if (error) return `${id}-error`;
190
+ if (hint) return `${id}-hint`;
191
+ }
192
+ /** Renders error or hint message below a field. Error takes priority. */
193
+ function FieldMessages({ id, error, hint }) {
194
+ if (!error && !hint) return null;
195
+ return /* @__PURE__ */ jsxs(Fragment, { children: [error && /* @__PURE__ */ jsx("p", {
196
+ id: id ? `${id}-error` : void 0,
197
+ className: "text-danger-fg text-sm",
198
+ role: "alert",
199
+ children: error
200
+ }), hint && !error && /* @__PURE__ */ jsx("p", {
201
+ id: id ? `${id}-hint` : void 0,
202
+ className: "text-text-tertiary text-sm",
203
+ children: hint
204
+ })] });
205
+ }
206
+ //#endregion
207
+ //#region src/lib/use-controlled-state.ts
208
+ /**
209
+ * Manages controlled/uncontrolled state for input components.
210
+ * When `controlledValue` is provided, acts as controlled; otherwise uses internal state.
211
+ */
212
+ function useControlledState(defaultValue, controlledValue, onChange) {
213
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
214
+ const isControlled = controlledValue !== void 0;
215
+ return [isControlled ? controlledValue : uncontrolledValue, useCallback((newValue) => {
216
+ if (!isControlled) setUncontrolledValue(newValue);
217
+ onChange === null || onChange === void 0 || onChange(newValue);
218
+ }, [isControlled, onChange])];
219
+ }
220
+ //#endregion
221
+ //#region src/core/stat-card.tsx
222
+ /** Renders the stat card component. */
223
+ function StatCard({ title, value, change, trend, sparklineData, className }) {
224
+ const trendColor = trend === "up" ? "text-success-fg" : trend === "down" ? "text-danger-fg" : "text-text-tertiary";
225
+ const trendIcon = trend === "up" ? "↑" : trend === "down" ? "↓" : "→";
226
+ const sparkColor = trend === "up" ? "var(--opt-chart-diverging-positive)" : trend === "down" ? "var(--opt-chart-diverging-negative)" : "var(--opt-chart-1)";
227
+ return /* @__PURE__ */ jsx("div", {
228
+ className: cn(OPT_SURFACE, OPT_BORDER, "flex flex-col gap-1 p-5", className),
229
+ "data-opt-id": "GAX47",
230
+ "data-opt-slug": "stat-card.StatCard",
231
+ children: /* @__PURE__ */ jsxs("div", {
232
+ className: "flex items-start justify-between gap-4",
233
+ children: [/* @__PURE__ */ jsxs("div", {
234
+ className: "flex min-w-0 flex-col gap-1",
235
+ children: [
236
+ /* @__PURE__ */ jsx("span", {
237
+ className: cn(OPT_TEXT_SECONDARY, "truncate text-sm"),
238
+ children: title
239
+ }),
240
+ /* @__PURE__ */ jsx("span", {
241
+ className: cn(OPT_TEXT_PRIMARY, "text-2xl font-bold"),
242
+ children: value
243
+ }),
244
+ /* @__PURE__ */ jsxs("span", {
245
+ className: cn("text-sm font-medium", trendColor),
246
+ children: [
247
+ trendIcon,
248
+ " ",
249
+ change
250
+ ]
251
+ })
252
+ ]
253
+ }), sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(MiniSparkline, {
254
+ data: sparklineData,
255
+ color: sparkColor
256
+ })]
257
+ })
258
+ });
259
+ }
260
+ function MiniSparkline({ data, color }) {
261
+ const width = 80;
262
+ const height = 32;
263
+ const padding = 2;
264
+ const min = Math.min(...data);
265
+ const range = Math.max(...data) - min || 1;
266
+ const points = data.map((v, i) => {
267
+ return `${padding + i / (data.length - 1) * 76},${padding + (1 - (v - min) / range) * 28}`;
268
+ }).join(" ");
269
+ return /* @__PURE__ */ jsx("svg", {
270
+ width,
271
+ height,
272
+ viewBox: `0 0 ${width} ${height}`,
273
+ className: "flex-shrink-0 self-center",
274
+ "aria-hidden": "true",
275
+ children: /* @__PURE__ */ jsx("polyline", {
276
+ points,
277
+ fill: "none",
278
+ stroke: color,
279
+ strokeWidth: 1.5,
280
+ strokeLinecap: "round",
281
+ strokeLinejoin: "round"
282
+ })
283
+ });
284
+ }
285
+ StatCard.displayName = "StatCard";
286
+ //#endregion
287
+ //#region src/i18n/ko.ts
288
+ /**
289
+ * opt-ui Korean default labels.
290
+ *
291
+ * Components consume these as defaults so consumers don't have to pass labels
292
+ * for the most common case. Korean is the package default — other locales
293
+ * should be imported explicitly (e.g. `enLabels`) and passed via component
294
+ * props or wrapped with a labels provider.
295
+ */
296
+ const koComboboxLabels = { empty: "결과가 없습니다." };
297
+ const koStarRatingLabels = {
298
+ /** {value}/{max}점 — readonly fallback aria-label */
299
+ readonlyAriaLabel: "{value}/{max}점",
300
+ /** rating group aria-label */
301
+ groupAriaLabel: "별점",
302
+ /** {star}점 — individual star aria-label */
303
+ starAriaLabel: "{star}점"
304
+ };
305
+ const koBreadcrumbLabels = {
306
+ /** {label}(으)로 이동 */
307
+ navAriaLabel: "{label}(으)로 이동" };
308
+ //#endregion
309
+ //#region src/core/button.tsx
310
+ const _excluded$15 = [
311
+ "variant",
312
+ "size",
313
+ "loading",
314
+ "leftIcon",
315
+ "rightIcon",
316
+ "className",
317
+ "disabled",
318
+ "children",
319
+ "aria-busy"
320
+ ];
321
+ const variantStyles$2 = {
322
+ primary: "bg-accent text-accent-fg hover:bg-accent-hover active:bg-accent-active focus-visible:ring-offset-2",
323
+ secondary: "border border-border bg-surface text-text-primary hover:bg-bg-subtle active:bg-bg-muted focus-visible:ring-offset-1",
324
+ ghost: "text-text-secondary hover:bg-bg-subtle active:bg-bg-muted focus-visible:ring-offset-1",
325
+ danger: "bg-danger text-danger-fg hover:bg-danger active:bg-danger focus-visible:ring-offset-2"
326
+ };
327
+ const sizeStyles$3 = {
328
+ sm: "h-[var(--opt-control-sm)] px-[var(--opt-control-padding-sm)] text-xs gap-[var(--opt-space-1-5)]",
329
+ md: "h-[var(--opt-control-md)] px-[var(--opt-control-padding-md)] text-sm gap-[var(--opt-space-2)]",
330
+ lg: "h-[var(--opt-control-lg)] px-[var(--opt-control-padding-lg)] text-base gap-[var(--opt-space-2)]"
331
+ };
332
+ /** Renders the button component. */
333
+ function Button(_ref) {
334
+ let { variant = "primary", size = "md", loading = false, leftIcon, rightIcon, className, disabled, children, "aria-busy": ariaBusy } = _ref, props = _objectWithoutProperties(_ref, _excluded$15);
335
+ const isDisabled = disabled || loading;
336
+ return /* @__PURE__ */ jsxs("button", _objectSpread2(_objectSpread2({
337
+ type: "button",
338
+ className: cn("inline-flex cursor-pointer items-center justify-center rounded-lg font-medium transition-colors", OPT_FOCUS_VISIBLE, variantStyles$2[variant], sizeStyles$3[size], isDisabled && "pointer-events-none cursor-not-allowed opacity-50", className),
339
+ disabled: isDisabled
340
+ }, props), {}, {
341
+ "aria-busy": loading ? true : ariaBusy,
342
+ "data-opt-id": "RGX84",
343
+ "data-opt-slug": "button.Button",
344
+ "data-opt-component": "button",
345
+ "data-opt-part": "root",
346
+ "data-variant": variant,
347
+ "data-size": size,
348
+ "data-state": loading ? "loading" : isDisabled ? "disabled" : "idle",
349
+ children: [
350
+ loading ? /* @__PURE__ */ jsxs("svg", {
351
+ className: "h-4 w-4 animate-spin",
352
+ viewBox: "0 0 24 24",
353
+ fill: "none",
354
+ "aria-hidden": "true",
355
+ children: [/* @__PURE__ */ jsx("circle", {
356
+ className: "opacity-25",
357
+ cx: "12",
358
+ cy: "12",
359
+ r: "10",
360
+ stroke: "currentColor",
361
+ strokeWidth: "4"
362
+ }), /* @__PURE__ */ jsx("path", {
363
+ className: "opacity-75",
364
+ fill: "currentColor",
365
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
366
+ })]
367
+ }) : leftIcon,
368
+ children,
369
+ !loading && rightIcon
370
+ ]
371
+ }));
372
+ }
373
+ //#endregion
374
+ //#region src/core/empty-state.tsx
375
+ const iconSizeClasses = {
376
+ sm: "text-3xl",
377
+ md: "text-4xl",
378
+ lg: "text-5xl"
379
+ };
380
+ /** Renders the empty state component. */
381
+ function EmptyState({ icon, title, description, actions, className, iconSize = "md", headingLevel = "h3" }) {
382
+ const HeadingTag = headingLevel;
383
+ return /* @__PURE__ */ jsxs("div", {
384
+ role: "status",
385
+ "aria-label": title,
386
+ className: cn("flex flex-col items-center justify-center px-4 py-12 text-center", className),
387
+ "data-opt-id": "5ZK92",
388
+ "data-opt-slug": "empty-state.EmptyState",
389
+ children: [
390
+ icon && /* @__PURE__ */ jsx("div", {
391
+ className: cn(`mb-4 text-text-tertiary`, iconSizeClasses[iconSize]),
392
+ "aria-hidden": "true",
393
+ children: icon
394
+ }),
395
+ /* @__PURE__ */ jsx(HeadingTag, {
396
+ className: `text-lg font-semibold ${OPT_TEXT_PRIMARY}`,
397
+ children: title
398
+ }),
399
+ description && /* @__PURE__ */ jsx("p", {
400
+ className: `mt-2 max-w-sm text-sm text-text-secondary`,
401
+ children: description
402
+ }),
403
+ actions && actions.length > 0 && /* @__PURE__ */ jsx("div", {
404
+ className: "mt-6 flex items-center gap-3",
405
+ children: actions.map((action) => /* @__PURE__ */ jsx(Button, {
406
+ onClick: action.onClick,
407
+ disabled: action.disabled,
408
+ variant: action.variant === "secondary" ? "secondary" : "primary",
409
+ children: action.label
410
+ }, action.id))
411
+ })
412
+ ]
413
+ });
414
+ }
415
+ //#endregion
416
+ //#region src/core/badge.tsx
417
+ const _excluded$14 = [
418
+ "variant",
419
+ "size",
420
+ "dot",
421
+ "progress",
422
+ "progressSize",
423
+ "className",
424
+ "children"
425
+ ];
426
+ const variantStyles$1 = {
427
+ default: "bg-bg-subtle text-text-secondary",
428
+ success: "bg-success-subtle text-success-fg",
429
+ warning: "bg-warning-subtle text-warning-fg",
430
+ error: "bg-danger-subtle text-danger-fg",
431
+ info: "bg-info-subtle text-info-fg"
432
+ };
433
+ const dotStyles = {
434
+ default: "bg-text-tertiary",
435
+ success: "bg-success",
436
+ warning: "bg-warning",
437
+ error: "bg-danger",
438
+ info: "bg-info"
439
+ };
440
+ const progressStroke = {
441
+ default: "stroke-text-tertiary",
442
+ success: "stroke-success",
443
+ warning: "stroke-warning",
444
+ error: "stroke-danger",
445
+ info: "stroke-info"
446
+ };
447
+ const sizeStyles$2 = {
448
+ sm: "px-1.5 py-0.5 text-[10px]",
449
+ md: "px-2 py-0.5 text-[11px]"
450
+ };
451
+ /** Renders the badge component. */
452
+ function Badge(_ref) {
453
+ let { variant = "default", size = "md", dot = false, progress, progressSize = 16, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$14);
454
+ const hasProgress = progress != null;
455
+ const clampedProgress = hasProgress ? Math.min(100, Math.max(0, progress)) : 0;
456
+ const radius = (progressSize - 3) / 2;
457
+ const circumference = 2 * Math.PI * radius;
458
+ const offset = circumference - clampedProgress / 100 * circumference;
459
+ return /* @__PURE__ */ jsxs("span", _objectSpread2(_objectSpread2({ className: cn(OPT_BADGE, variantStyles$1[variant], sizeStyles$2[size], className) }, props), {}, {
460
+ "data-opt-id": "9GBGZ",
461
+ "data-opt-slug": "badge.Badge",
462
+ children: [
463
+ hasProgress && /* @__PURE__ */ jsxs("svg", {
464
+ width: progressSize,
465
+ height: progressSize,
466
+ viewBox: `0 0 ${progressSize} ${progressSize}`,
467
+ className: "mr-1 -ml-0.5 shrink-0",
468
+ "aria-hidden": "true",
469
+ children: [/* @__PURE__ */ jsx("circle", {
470
+ cx: progressSize / 2,
471
+ cy: progressSize / 2,
472
+ r: radius,
473
+ fill: "none",
474
+ strokeWidth: 2,
475
+ className: "stroke-current opacity-20"
476
+ }), /* @__PURE__ */ jsx("circle", {
477
+ cx: progressSize / 2,
478
+ cy: progressSize / 2,
479
+ r: radius,
480
+ fill: "none",
481
+ strokeWidth: 2,
482
+ strokeLinecap: "round",
483
+ strokeDasharray: circumference,
484
+ strokeDashoffset: offset,
485
+ className: cn(progressStroke[variant], "transition-all"),
486
+ transform: `rotate(-90 ${progressSize / 2} ${progressSize / 2})`
487
+ })]
488
+ }),
489
+ dot && !hasProgress && /* @__PURE__ */ jsx("span", {
490
+ className: cn("mr-1.5 h-1.5 w-1.5 rounded-full", dotStyles[variant]),
491
+ "aria-hidden": "true"
492
+ }),
493
+ children
494
+ ]
495
+ }));
496
+ }
497
+ //#endregion
498
+ //#region src/core/spinner.tsx
499
+ const _excluded$13 = [
500
+ "size",
501
+ "className",
502
+ "role",
503
+ "aria-hidden",
504
+ "aria-label"
505
+ ];
506
+ const sizeStyles$1 = {
507
+ sm: "h-4 w-4",
508
+ md: "h-6 w-6",
509
+ lg: "h-8 w-8"
510
+ };
511
+ /** Renders the spinner component. */
512
+ function Spinner(_ref) {
513
+ let { size = "md", className, role, "aria-hidden": ariaHidden, "aria-label": ariaLabel } = _ref, props = _objectWithoutProperties(_ref, _excluded$13);
514
+ const isDecorative = ariaHidden === true || ariaHidden === "true";
515
+ return /* @__PURE__ */ jsxs("svg", _objectSpread2(_objectSpread2({
516
+ className: cn("animate-spin text-current", sizeStyles$1[size], className),
517
+ viewBox: "0 0 24 24",
518
+ fill: "none",
519
+ role: isDecorative ? void 0 : role !== null && role !== void 0 ? role : "status",
520
+ "aria-hidden": ariaHidden,
521
+ "aria-label": isDecorative ? void 0 : ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "Loading"
522
+ }, props), {}, {
523
+ "data-opt-id": "DJS29",
524
+ "data-opt-slug": "spinner.Spinner",
525
+ children: [/* @__PURE__ */ jsx("circle", {
526
+ className: "opacity-25",
527
+ cx: "12",
528
+ cy: "12",
529
+ r: "10",
530
+ stroke: "currentColor",
531
+ strokeWidth: "4"
532
+ }), /* @__PURE__ */ jsx("path", {
533
+ className: "opacity-75",
534
+ fill: "currentColor",
535
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
536
+ })]
537
+ }));
538
+ }
539
+ //#endregion
540
+ //#region src/core/alert.tsx
541
+ const _excluded$12 = [
542
+ "variant",
543
+ "title",
544
+ "icon",
545
+ "dismissible",
546
+ "onDismiss",
547
+ "className",
548
+ "children"
549
+ ];
550
+ const variantStyles = {
551
+ info: "border-info bg-info-subtle text-info-fg",
552
+ success: "border-success bg-success-subtle text-success-fg",
553
+ warning: "border-warning bg-warning-subtle text-warning-fg",
554
+ error: "border-danger bg-danger-subtle text-danger-fg"
555
+ };
556
+ const iconColors = {
557
+ info: "text-info-fg",
558
+ success: "text-success-fg",
559
+ warning: "text-warning-fg",
560
+ error: "text-danger-fg"
561
+ };
562
+ const defaultIcons = {
563
+ info: /* @__PURE__ */ jsx("svg", {
564
+ className: "h-5 w-5",
565
+ viewBox: "0 0 20 20",
566
+ fill: "currentColor",
567
+ "aria-hidden": "true",
568
+ children: /* @__PURE__ */ jsx("path", {
569
+ fillRule: "evenodd",
570
+ d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z",
571
+ clipRule: "evenodd"
572
+ })
573
+ }),
574
+ success: /* @__PURE__ */ jsx("svg", {
575
+ className: "h-5 w-5",
576
+ viewBox: "0 0 20 20",
577
+ fill: "currentColor",
578
+ "aria-hidden": "true",
579
+ children: /* @__PURE__ */ jsx("path", {
580
+ fillRule: "evenodd",
581
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",
582
+ clipRule: "evenodd"
583
+ })
584
+ }),
585
+ warning: /* @__PURE__ */ jsx("svg", {
586
+ className: "h-5 w-5",
587
+ viewBox: "0 0 20 20",
588
+ fill: "currentColor",
589
+ "aria-hidden": "true",
590
+ children: /* @__PURE__ */ jsx("path", {
591
+ fillRule: "evenodd",
592
+ d: "M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z",
593
+ clipRule: "evenodd"
594
+ })
595
+ }),
596
+ error: /* @__PURE__ */ jsx("svg", {
597
+ className: "h-5 w-5",
598
+ viewBox: "0 0 20 20",
599
+ fill: "currentColor",
600
+ "aria-hidden": "true",
601
+ children: /* @__PURE__ */ jsx("path", {
602
+ fillRule: "evenodd",
603
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z",
604
+ clipRule: "evenodd"
605
+ })
606
+ })
607
+ };
608
+ /** Renders the alert component. */
609
+ function Alert(_ref) {
610
+ let { variant = "info", title, icon, dismissible = false, onDismiss, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$12);
611
+ const displayIcon = icon !== null && icon !== void 0 ? icon : defaultIcons[variant];
612
+ return /* @__PURE__ */ jsx("div", _objectSpread2(_objectSpread2({
613
+ role: "alert",
614
+ className: cn("relative rounded-lg border p-4", variantStyles[variant], className)
615
+ }, props), {}, {
616
+ "data-opt-id": "4SPK6",
617
+ "data-opt-slug": "alert.Alert",
618
+ children: /* @__PURE__ */ jsxs("div", {
619
+ className: "flex",
620
+ children: [
621
+ displayIcon && /* @__PURE__ */ jsx("div", {
622
+ className: cn("flex-shrink-0", iconColors[variant]),
623
+ children: displayIcon
624
+ }),
625
+ /* @__PURE__ */ jsxs("div", {
626
+ className: cn("flex-1", displayIcon && "ml-3"),
627
+ children: [title && /* @__PURE__ */ jsx("h3", {
628
+ className: "text-sm font-medium",
629
+ children: title
630
+ }), children && /* @__PURE__ */ jsx("div", {
631
+ className: cn("text-sm", title && "mt-1", "opacity-90"),
632
+ children
633
+ })]
634
+ }),
635
+ dismissible && /* @__PURE__ */ jsx("div", {
636
+ className: "ml-auto pl-3",
637
+ children: /* @__PURE__ */ jsx("button", {
638
+ type: "button",
639
+ onClick: onDismiss,
640
+ className: cn("hover:bg-bg-subtle inline-flex rounded-md p-1.5 transition-colors", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset"),
641
+ "aria-label": "Dismiss",
642
+ children: /* @__PURE__ */ jsx("svg", {
643
+ className: "h-4 w-4",
644
+ viewBox: "0 0 20 20",
645
+ fill: "currentColor",
646
+ "aria-hidden": "true",
647
+ children: /* @__PURE__ */ jsx("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" })
648
+ })
649
+ })
650
+ })
651
+ ]
652
+ })
653
+ }));
654
+ }
655
+ //#endregion
656
+ //#region src/lib/use-input-id.ts
657
+ /**
658
+ * Generates a stable component ID from label text.
659
+ * Eliminates the duplicated `id ?? label?.replace(...)` pattern across input components.
660
+ */
661
+ function useInputId(id, label, prefix) {
662
+ return id !== null && id !== void 0 ? id : label ? `${prefix}-${label.replace(/\s+/g, "-").toLowerCase()}` : void 0;
663
+ }
664
+ //#endregion
665
+ //#region src/core/input.tsx
666
+ const _excluded$11 = [
667
+ "label",
668
+ "error",
669
+ "hint",
670
+ "leftIcon",
671
+ "rightIcon",
672
+ "fullWidth",
673
+ "size",
674
+ "required",
675
+ "className",
676
+ "id"
677
+ ];
678
+ const inputSizeStyles = OPT_INPUT_SIZE;
679
+ const Input = forwardRef((_ref, ref) => {
680
+ var _useInputId;
681
+ let { label, error, hint, leftIcon, rightIcon, fullWidth = false, size = "md", required, className, id } = _ref, props = _objectWithoutProperties(_ref, _excluded$11);
682
+ const fallbackId = useId().replace(/:/g, "");
683
+ const inputId = (_useInputId = useInputId(id, label, "input")) !== null && _useInputId !== void 0 ? _useInputId : `input-${fallbackId}`;
684
+ const hasError = Boolean(error);
685
+ return /* @__PURE__ */ jsxs("div", {
686
+ className: cn("flex flex-col gap-1.5", fullWidth && "w-full"),
687
+ "data-opt-id": "7BY1Q",
688
+ "data-opt-slug": "input.Input",
689
+ children: [
690
+ label && /* @__PURE__ */ jsxs("label", {
691
+ htmlFor: inputId,
692
+ className: "text-text-primary text-sm font-medium",
693
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
694
+ }),
695
+ /* @__PURE__ */ jsxs("div", {
696
+ className: "relative",
697
+ children: [
698
+ leftIcon && /* @__PURE__ */ jsx("div", {
699
+ className: "text-text-tertiary pointer-events-none absolute top-1/2 left-3 -translate-y-1/2",
700
+ children: leftIcon
701
+ }),
702
+ /* @__PURE__ */ jsx("input", _objectSpread2({
703
+ ref,
704
+ id: inputId,
705
+ className: cn(OPT_INPUT, inputSizeStyles[size], leftIcon && (size === "sm" ? "pl-8" : "pl-10"), rightIcon && (size === "sm" ? "pr-8" : "pr-10"), hasError && "border-danger focus-visible:outline-danger", !fullWidth && "w-auto", className),
706
+ "aria-invalid": hasError,
707
+ "aria-required": required,
708
+ "aria-describedby": getDescribedBy(inputId, error, hint),
709
+ required
710
+ }, props)),
711
+ rightIcon && /* @__PURE__ */ jsx("div", {
712
+ className: "text-text-tertiary pointer-events-none absolute top-1/2 right-3 -translate-y-1/2",
713
+ children: rightIcon
714
+ })
715
+ ]
716
+ }),
717
+ /* @__PURE__ */ jsx(FieldMessages, {
718
+ id: inputId,
719
+ error,
720
+ hint
721
+ })
722
+ ]
723
+ });
724
+ });
725
+ Input.displayName = "Input";
726
+ //#endregion
727
+ //#region src/core/star-rating.tsx
728
+ function interpolate(template, values) {
729
+ return template.replace(/\{(\w+)\}/g, (_, key) => key in values ? String(values[key]) : `{${key}}`);
730
+ }
731
+ const sizeMap = {
732
+ sm: "h-4 w-4",
733
+ md: "h-5 w-5",
734
+ lg: "h-6 w-6"
735
+ };
736
+ const gapMap = {
737
+ sm: "gap-0.5",
738
+ md: "gap-1",
739
+ lg: "gap-1"
740
+ };
741
+ function StarIcon({ filled, className }) {
742
+ return /* @__PURE__ */ jsx("svg", {
743
+ viewBox: "0 0 24 24",
744
+ className: cn(filled ? "fill-amber-400 text-amber-400" : "text-text-tertiary fill-none", className),
745
+ stroke: "currentColor",
746
+ strokeWidth: 1.5,
747
+ strokeLinecap: "round",
748
+ strokeLinejoin: "round",
749
+ "aria-hidden": "true",
750
+ children: /* @__PURE__ */ jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" })
751
+ });
752
+ }
753
+ /** Renders the star rating component. */
754
+ function StarRating({ value = 0, onChange, max = 5, readOnly = false, size = "md", className, ariaLabel }) {
755
+ const id = useId();
756
+ const [hovered, setHovered] = useState(null);
757
+ const displayValue = hovered !== null && hovered !== void 0 ? hovered : value;
758
+ const iconSize = sizeMap[size];
759
+ const gap = gapMap[size];
760
+ const handleClick = useCallback((star) => {
761
+ if (!readOnly && onChange) onChange(star);
762
+ }, [readOnly, onChange]);
763
+ const handleKeyDown = useCallback((e) => {
764
+ if (readOnly || !onChange) return;
765
+ if (e.key === "ArrowRight" || e.key === "ArrowUp") {
766
+ e.preventDefault();
767
+ onChange(Math.min(value + 1, max));
768
+ } else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
769
+ e.preventDefault();
770
+ onChange(Math.max(value - 1, 1));
771
+ } else if (e.key === "Home") {
772
+ e.preventDefault();
773
+ onChange(1);
774
+ } else if (e.key === "End") {
775
+ e.preventDefault();
776
+ onChange(max);
777
+ }
778
+ }, [
779
+ readOnly,
780
+ onChange,
781
+ value,
782
+ max
783
+ ]);
784
+ if (readOnly) return /* @__PURE__ */ jsx("div", {
785
+ className: cn("inline-flex items-center", gap, className),
786
+ role: "img",
787
+ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : interpolate(koStarRatingLabels.readonlyAriaLabel, {
788
+ value,
789
+ max
790
+ }),
791
+ "data-opt-id": "B6ZY4",
792
+ "data-opt-slug": "star-rating.StarRating",
793
+ children: Array.from({ length: max }, (_, i) => /* @__PURE__ */ jsx(StarIcon, {
794
+ filled: i < value,
795
+ className: iconSize
796
+ }, i))
797
+ });
798
+ return /* @__PURE__ */ jsxs("div", {
799
+ className: cn("inline-flex items-center", gap, className),
800
+ role: "radiogroup",
801
+ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : koStarRatingLabels.groupAriaLabel,
802
+ onKeyDown: handleKeyDown,
803
+ onMouseLeave: () => setHovered(null),
804
+ "data-opt-id": "B6ZY4",
805
+ "data-opt-slug": "star-rating.StarRating",
806
+ children: [Array.from({ length: max }, (_, i) => {
807
+ const star = i + 1;
808
+ const checked = star === value;
809
+ return /* @__PURE__ */ jsx("button", {
810
+ type: "button",
811
+ role: "radio",
812
+ "aria-checked": checked,
813
+ "aria-label": interpolate(koStarRatingLabels.starAriaLabel, { star }),
814
+ tabIndex: checked || value === 0 && i === 0 ? 0 : -1,
815
+ className: cn("cursor-pointer rounded-sm transition-transform", "focus-visible:outline-accent hover:scale-110 focus-visible:outline-2 focus-visible:outline-offset-2"),
816
+ onClick: () => handleClick(star),
817
+ onMouseEnter: () => setHovered(star),
818
+ children: /* @__PURE__ */ jsx(StarIcon, {
819
+ filled: i < displayValue,
820
+ className: iconSize
821
+ })
822
+ }, i);
823
+ }), /* @__PURE__ */ jsx("input", {
824
+ type: "hidden",
825
+ name: `${id}-rating`,
826
+ value
827
+ })]
828
+ });
829
+ }
830
+ //#endregion
831
+ //#region src/core/composite-zone.tsx
832
+ /** Renders the composite zone component. */
833
+ function CompositeZone({ children, label, focusLoop = true, focusWrap = true, className }) {
834
+ return /* @__PURE__ */ jsx(CompositeProvider, {
835
+ focusLoop,
836
+ focusWrap,
837
+ "data-opt-id": "1JZXE",
838
+ "data-opt-slug": "composite-zone.CompositeZone",
839
+ children: /* @__PURE__ */ jsx(Composite, {
840
+ role: "grid",
841
+ "aria-label": label,
842
+ className,
843
+ children
844
+ })
845
+ });
846
+ }
847
+ //#endregion
848
+ //#region src/core/disclosure.tsx
849
+ const _excluded$10 = ["className"];
850
+ const _excluded2$8 = ["className"];
851
+ const triggerClass$1 = `flex w-full cursor-pointer items-center justify-between px-4 py-4 text-left text-sm font-medium text-text-primary transition-colors hover:bg-bg-subtle ${OPT_FOCUS} data-[active-item]:bg-bg-subtle data-[disabled]:cursor-not-allowed`;
852
+ const contentClass = `overflow-hidden ${OPT_ANIMATE_ENTER_EXIT}`;
853
+ /** Renders the disclosure root component. */
854
+ function DisclosureRoot$1(props) {
855
+ return /* @__PURE__ */ jsx(DisclosureRoot, _objectSpread2(_objectSpread2({ animated: true }, props), {}, {
856
+ "data-opt-id": "AS61F",
857
+ "data-opt-slug": "disclosure.DisclosureRoot"
858
+ }));
859
+ }
860
+ /** Renders the disclosure trigger component. */
861
+ function DisclosureTrigger$1(_ref) {
862
+ let { className } = _ref, props = _objectWithoutProperties(_ref, _excluded$10);
863
+ return /* @__PURE__ */ jsx(DisclosureTrigger, _objectSpread2(_objectSpread2({ className: cn(triggerClass$1, className) }, props), {}, {
864
+ "data-opt-id": "14EZW",
865
+ "data-opt-slug": "disclosure.DisclosureTrigger"
866
+ }));
867
+ }
868
+ /** Renders the disclosure content component. */
869
+ function DisclosureContent$1(_ref2) {
870
+ let { className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$8);
871
+ return /* @__PURE__ */ jsx(DisclosureContent, _objectSpread2(_objectSpread2({ className: cn(contentClass, className) }, props), {}, {
872
+ "data-opt-id": "78HYF",
873
+ "data-opt-slug": "disclosure.DisclosureContent"
874
+ }));
875
+ }
876
+ //#endregion
877
+ //#region src/core/tabs.tsx
878
+ const _excluded$9 = ["variant"];
879
+ const _excluded2$7 = ["className", "actions"];
880
+ const _excluded3$7 = [
881
+ "className",
882
+ "icon",
883
+ "status",
884
+ "statusLabel",
885
+ "children"
886
+ ];
887
+ const _excluded4$5 = ["className"];
888
+ const TabsVariantContext = React.createContext("underline");
889
+ const tabClass = `cursor-pointer border-b-2 border-transparent px-4 py-2.5 text-sm text-text-tertiary transition-colors hover:text-text-primary data-[active-item]:text-text-primary data-[active-item]:border-text-primary data-[disabled]:cursor-not-allowed ${OPT_FOCUS}`;
890
+ const tabListClass = "flex border-b border-border-subtle";
891
+ const workspaceTabClass = `group relative inline-flex min-h-9 min-w-33 max-w-54 flex-none cursor-pointer items-center gap-element rounded-t-md border border-b-0 border-transparent px-group py-element font-mono text-xs text-text-tertiary transition-colors data-[disabled]:cursor-not-allowed [&:not([data-active-item]):hover]:bg-raised [&:not([data-active-item]):hover]:text-secondary data-[active-item]:z-10 data-[active-item]:-mb-px data-[active-item]:border-border data-[active-item]:bg-surface data-[active-item]:text-primary before:absolute before:inset-x-group before:top-0 before:h-0.5 before:rounded-b-sm before:bg-accent before:opacity-0 before:transition-opacity before:content-[''] data-[active-item]:before:opacity-100 ${OPT_FOCUS}`;
892
+ const workspaceTabListClass = "flex min-w-0 flex-1 items-end gap-element overflow-x-auto px-element [scrollbar-width:thin]";
893
+ const workspaceBarClass = "flex min-h-11 items-end border-b border-border bg-subtle pt-element";
894
+ const workspaceActionsClass = "flex flex-none items-center gap-element self-stretch border-l border-border-subtle bg-subtle px-element";
895
+ const barClass = "flex items-center justify-between gap-group";
896
+ const actionsClass = "flex flex-none items-center gap-element";
897
+ const tabPanelClass = `pt-4 ${OPT_FOCUS} data-[focus-visible]:rounded-lg`;
898
+ /** Renders the tabs root component. */
899
+ function TabsRoot$1(_ref) {
900
+ let { variant = "underline" } = _ref, props = _objectWithoutProperties(_ref, _excluded$9);
901
+ return /* @__PURE__ */ jsx(TabsVariantContext.Provider, {
902
+ value: variant,
903
+ children: /* @__PURE__ */ jsx(TabsRoot, _objectSpread2(_objectSpread2({}, props), {}, {
904
+ "data-opt-id": "DJ8K8",
905
+ "data-opt-slug": "tabs.TabsRoot"
906
+ }))
907
+ });
908
+ }
909
+ /** Renders the tab list component. */
910
+ function TabList$1(_ref2) {
911
+ let { className, actions } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$7);
912
+ const variant = React.useContext(TabsVariantContext);
913
+ const list = /* @__PURE__ */ jsx(TabList, _objectSpread2(_objectSpread2({ className: cn(variant === "workspace" ? workspaceTabListClass : tabListClass, className) }, props), {}, {
914
+ "data-opt-id": "68K7E",
915
+ "data-opt-slug": "tabs.TabList"
916
+ }));
917
+ if (!actions) return list;
918
+ return /* @__PURE__ */ jsxs("div", {
919
+ className: variant === "workspace" ? workspaceBarClass : barClass,
920
+ children: [list, /* @__PURE__ */ jsx("div", {
921
+ className: variant === "workspace" ? workspaceActionsClass : actionsClass,
922
+ children: actions
923
+ })]
924
+ });
925
+ }
926
+ /** Renders the tab component. */
927
+ function Tab$1(_ref3) {
928
+ let { className, icon, status, statusLabel, children } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3$7);
929
+ const variant = React.useContext(TabsVariantContext);
930
+ const decorated = icon != null || status != null;
931
+ return /* @__PURE__ */ jsx(Tab, _objectSpread2(_objectSpread2({ className: cn(variant === "workspace" ? workspaceTabClass : tabClass, className) }, props), {}, {
932
+ "data-opt-id": "HZTNP",
933
+ "data-opt-slug": "tabs.Tab",
934
+ children: decorated ? /* @__PURE__ */ jsxs(Fragment, { children: [
935
+ icon != null && /* @__PURE__ */ jsx("span", {
936
+ "aria-hidden": "true",
937
+ className: "text-text-tertiary group-data-[active-item]:text-accent flex flex-none items-center transition-colors",
938
+ children: icon
939
+ }),
940
+ /* @__PURE__ */ jsx("span", {
941
+ className: "min-w-0 flex-1 truncate text-left",
942
+ children
943
+ }),
944
+ status != null && /* @__PURE__ */ jsx("span", {
945
+ role: "status",
946
+ "aria-label": statusLabel,
947
+ className: cn("size-element flex-none rounded-full", status === "running" ? "bg-accent ring-accent-subtle ring-2" : "bg-text-tertiary")
948
+ })
949
+ ] }) : children
950
+ }));
951
+ }
952
+ /** Renders the tab panel component. */
953
+ function TabPanel$1(_ref4) {
954
+ let { className } = _ref4, props = _objectWithoutProperties(_ref4, _excluded4$5);
955
+ return /* @__PURE__ */ jsx(TabPanel, _objectSpread2(_objectSpread2({ className: cn(tabPanelClass, className) }, props), {}, {
956
+ "data-opt-id": "C0MBP",
957
+ "data-opt-slug": "tabs.TabPanel"
958
+ }));
959
+ }
960
+ //#endregion
961
+ //#region src/core/select.tsx
962
+ const _excluded$8 = [
963
+ "className",
964
+ "minWidth",
965
+ "style"
966
+ ];
967
+ const _excluded2$6 = ["className"];
968
+ const _excluded3$6 = ["className"];
969
+ const triggerClass = `${OPT_INPUT} cursor-pointer items-center justify-between data-[disabled]:cursor-not-allowed ${OPT_FOCUS}`;
970
+ const popoverClass$1 = `${OPT_SURFACE_POPOVER} ${OPT_ANIMATE_ENTER_EXIT} z-[120]`;
971
+ const itemClass$1 = `flex cursor-pointer items-center gap-2 data-[disabled]:cursor-not-allowed ${OPT_ITEM_BASE} ${OPT_ACTIVE_ITEM}`;
972
+ /** Renders the select root component. */
973
+ function SelectRoot$1(props) {
974
+ return /* @__PURE__ */ jsx(SelectRoot, _objectSpread2(_objectSpread2({}, props), {}, {
975
+ "data-opt-id": "A5TYW",
976
+ "data-opt-slug": "select.SelectRoot"
977
+ }));
978
+ }
979
+ /** Renders the select label component. */
980
+ function SelectLabel$1(props) {
981
+ return /* @__PURE__ */ jsx(SelectLabel, _objectSpread2(_objectSpread2({}, props), {}, {
982
+ "data-opt-id": "SKM59",
983
+ "data-opt-slug": "select.SelectLabel"
984
+ }));
985
+ }
986
+ /** Renders the select trigger component. */
987
+ function SelectTrigger$1(_ref) {
988
+ let { className, minWidth = 140, style } = _ref, props = _objectWithoutProperties(_ref, _excluded$8);
989
+ return /* @__PURE__ */ jsx(SelectTrigger, _objectSpread2(_objectSpread2({
990
+ className: cn(triggerClass, className),
991
+ style: _objectSpread2({ minWidth: typeof minWidth === "number" ? `${minWidth}px` : minWidth }, style)
992
+ }, props), {}, {
993
+ "data-opt-id": "V6F86",
994
+ "data-opt-slug": "select.SelectTrigger"
995
+ }));
996
+ }
997
+ /** Renders the select popover component. */
998
+ function SelectPopover$1(_ref2) {
999
+ let { className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$6);
1000
+ return /* @__PURE__ */ jsx(SelectPopover, _objectSpread2(_objectSpread2({ className: cn(popoverClass$1, className) }, props), {}, {
1001
+ "data-opt-id": "P152F",
1002
+ "data-opt-slug": "select.SelectPopover"
1003
+ }));
1004
+ }
1005
+ /** Renders the select item component. */
1006
+ function SelectItem$1(_ref3) {
1007
+ let { className } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3$6);
1008
+ return /* @__PURE__ */ jsx(SelectItem, _objectSpread2(_objectSpread2({ className: cn(itemClass$1, className) }, props), {}, {
1009
+ "data-opt-id": "KKBAF",
1010
+ "data-opt-slug": "select.SelectItem"
1011
+ }));
1012
+ }
1013
+ //#endregion
1014
+ //#region src/core/dialog.tsx
1015
+ const _excluded$7 = ["className"];
1016
+ const _excluded2$5 = ["className", "size"];
1017
+ const _excluded3$5 = ["className", "size"];
1018
+ const _excluded4$4 = ["className"];
1019
+ const _excluded5$3 = ["className"];
1020
+ const _excluded6$2 = ["className"];
1021
+ const sizeClasses = {
1022
+ xs: "max-w-xs",
1023
+ sm: "max-w-sm",
1024
+ md: "max-w-lg",
1025
+ lg: "max-w-2xl",
1026
+ xl: "max-w-4xl",
1027
+ full: "max-w-[calc(100vw-2rem)]"
1028
+ };
1029
+ const panelBase = `fixed inset-auto left-1/2 top-[20%] z-50 m-0 w-full -translate-x-1/2 rounded-xl border border-border bg-surface p-0 shadow-2xl ${OPT_ANIMATE_DIALOG}`;
1030
+ /** Renders the dialog root component. */
1031
+ function DialogRoot$1(props) {
1032
+ return /* @__PURE__ */ jsx(DialogRoot, _objectSpread2(_objectSpread2({ animated: true }, props), {}, {
1033
+ "data-opt-id": "MDC91",
1034
+ "data-opt-slug": "dialog.DialogRoot"
1035
+ }));
1036
+ }
1037
+ /** Renders the dialog disclosure component. */
1038
+ function DialogDisclosure$1(_ref) {
1039
+ let { className } = _ref, props = _objectWithoutProperties(_ref, _excluded$7);
1040
+ return /* @__PURE__ */ jsx(DialogDisclosure, _objectSpread2(_objectSpread2({ className: cn("inline-flex cursor-pointer items-center justify-center rounded-lg font-medium transition-colors", OPT_BUTTON_PRIMARY, OPT_FOCUS_VISIBLE, className) }, props), {}, {
1041
+ "data-opt-id": "32QJK",
1042
+ "data-opt-slug": "dialog.DialogDisclosure"
1043
+ }));
1044
+ }
1045
+ /** Renders the dialog panel component. */
1046
+ function DialogPanel$1(_ref2) {
1047
+ let { className, size = "md" } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$5);
1048
+ return /* @__PURE__ */ jsx(DialogPanel, _objectSpread2(_objectSpread2({ className: cn(panelBase, sizeClasses[size], className) }, props), {}, {
1049
+ "data-opt-id": "BTMTG",
1050
+ "data-opt-slug": "dialog.DialogPanel"
1051
+ }));
1052
+ }
1053
+ /**
1054
+ * A dialog that demands an explicit choice: `role="alertdialog"` with no
1055
+ * backdrop/Escape dismissal. Use for destructive confirmations. Compose with
1056
+ * the other Dialog parts (DialogRoot/Heading/Description/Dismiss/…).
1057
+ */
1058
+ function AlertDialogPanel$1(_ref3) {
1059
+ let { className, size = "sm" } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3$5);
1060
+ return /* @__PURE__ */ jsx(AlertDialogPanel, _objectSpread2(_objectSpread2({ className: cn(panelBase, sizeClasses[size], className) }, props), {}, {
1061
+ "data-opt-id": "80HGS",
1062
+ "data-opt-slug": "dialog.AlertDialogPanel"
1063
+ }));
1064
+ }
1065
+ /** Renders the dialog heading component. */
1066
+ function DialogHeading$1(_ref4) {
1067
+ let { className } = _ref4, props = _objectWithoutProperties(_ref4, _excluded4$4);
1068
+ return /* @__PURE__ */ jsx(DialogHeading, _objectSpread2(_objectSpread2({ className: cn(`text-lg font-semibold ${OPT_TEXT_PRIMARY}`, className) }, props), {}, {
1069
+ "data-opt-id": "4NW4H",
1070
+ "data-opt-slug": "dialog.DialogHeading"
1071
+ }));
1072
+ }
1073
+ /** Renders the dialog description component. */
1074
+ function DialogDescription$1(_ref5) {
1075
+ let { className } = _ref5, props = _objectWithoutProperties(_ref5, _excluded5$3);
1076
+ return /* @__PURE__ */ jsx(DialogDescription, _objectSpread2(_objectSpread2({ className: cn(`text-sm ${OPT_TEXT_SECONDARY}`, className) }, props), {}, {
1077
+ "data-opt-id": "2BN3X",
1078
+ "data-opt-slug": "dialog.DialogDescription"
1079
+ }));
1080
+ }
1081
+ /** Renders the dialog dismiss component. */
1082
+ function DialogDismiss$1(_ref6) {
1083
+ let { className } = _ref6, props = _objectWithoutProperties(_ref6, _excluded6$2);
1084
+ return /* @__PURE__ */ jsx(DialogDismiss, _objectSpread2(_objectSpread2({ className: cn("hover:bg-bg-subtle rounded-md p-1.5 transition-colors", "cursor-pointer data-[disabled]:cursor-not-allowed", OPT_FOCUS, className) }, props), {}, {
1085
+ "data-opt-id": "JXT0Y",
1086
+ "data-opt-slug": "dialog.DialogDismiss"
1087
+ }));
1088
+ }
1089
+ /** Renders the dialog header component. */
1090
+ function DialogHeader({ children, className }) {
1091
+ return /* @__PURE__ */ jsx("div", {
1092
+ className: cn("border-border flex items-start justify-between gap-4 border-b px-6 py-4", className),
1093
+ "data-opt-id": "K8NYY",
1094
+ "data-opt-slug": "dialog.DialogHeader",
1095
+ children: /* @__PURE__ */ jsx("div", {
1096
+ className: "gap-element flex min-w-0 flex-1 flex-col",
1097
+ children
1098
+ })
1099
+ });
1100
+ }
1101
+ /** Renders the dialog body component. */
1102
+ function DialogBody({ children, className }) {
1103
+ return /* @__PURE__ */ jsx("div", {
1104
+ className: cn("flex-1 overflow-y-auto px-6 py-4", className),
1105
+ "data-opt-id": "EE32H",
1106
+ "data-opt-slug": "dialog.DialogBody",
1107
+ children
1108
+ });
1109
+ }
1110
+ /** Renders the dialog footer component. */
1111
+ function DialogFooter({ children, className }) {
1112
+ return /* @__PURE__ */ jsx("div", {
1113
+ className: cn("border-border gap-element flex items-center justify-end border-t px-6 py-4", className),
1114
+ "data-opt-id": "AYQSR",
1115
+ "data-opt-slug": "dialog.DialogFooter",
1116
+ children
1117
+ });
1118
+ }
1119
+ //#endregion
1120
+ //#region src/core/combobox.tsx
1121
+ const _excluded$6 = ["className"];
1122
+ const _excluded2$4 = ["className"];
1123
+ const _excluded3$4 = ["className"];
1124
+ const _excluded4$3 = ["className"];
1125
+ const inputClass$1 = `${OPT_INPUT} ${OPT_FOCUS}`;
1126
+ const popoverClass = `${OPT_SURFACE_POPOVER} max-h-60 overflow-y-auto ${OPT_ANIMATE_ENTER_EXIT}`;
1127
+ const itemClass = `${OPT_ITEM_BASE} ${OPT_ACTIVE_ITEM}`;
1128
+ const groupLabelClass = "px-2 py-1.5 text-xs font-medium text-text-tertiary";
1129
+ const emptyClass = "py-4 text-center text-sm text-text-tertiary";
1130
+ /** Renders the combobox root component. */
1131
+ function ComboboxRoot$1(props) {
1132
+ return /* @__PURE__ */ jsx(ComboboxRoot, _objectSpread2(_objectSpread2({}, props), {}, {
1133
+ "data-opt-id": "VACXX",
1134
+ "data-opt-slug": "combobox.ComboboxRoot"
1135
+ }));
1136
+ }
1137
+ /** Renders the combobox input component. */
1138
+ function ComboboxInput$1(_ref) {
1139
+ let { className } = _ref, props = _objectWithoutProperties(_ref, _excluded$6);
1140
+ return /* @__PURE__ */ jsx(ComboboxInput, _objectSpread2(_objectSpread2({ className: cn(inputClass$1, className) }, props), {}, {
1141
+ "data-opt-id": "92FZS",
1142
+ "data-opt-slug": "combobox.ComboboxInput"
1143
+ }));
1144
+ }
1145
+ /** Renders the combobox popover component. */
1146
+ function ComboboxPopover$1(_ref2) {
1147
+ let { className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$4);
1148
+ return /* @__PURE__ */ jsx(ComboboxPopover, _objectSpread2(_objectSpread2({ className: cn(popoverClass, className) }, props), {}, {
1149
+ "data-opt-id": "WS4PD",
1150
+ "data-opt-slug": "combobox.ComboboxPopover"
1151
+ }));
1152
+ }
1153
+ /** Renders the combobox item component. */
1154
+ function ComboboxItem$1(_ref3) {
1155
+ let { className } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3$4);
1156
+ return /* @__PURE__ */ jsx(ComboboxItem, _objectSpread2(_objectSpread2({ className: cn(itemClass, className) }, props), {}, {
1157
+ "data-opt-id": "MAZJN",
1158
+ "data-opt-slug": "combobox.ComboboxItem"
1159
+ }));
1160
+ }
1161
+ /** Renders the combobox group component. */
1162
+ function ComboboxGroup$1(props) {
1163
+ return /* @__PURE__ */ jsx(ComboboxGroup, _objectSpread2(_objectSpread2({}, props), {}, {
1164
+ "data-opt-id": "SPJQC",
1165
+ "data-opt-slug": "combobox.ComboboxGroup"
1166
+ }));
1167
+ }
1168
+ /** Renders the combobox group label component. */
1169
+ function ComboboxGroupLabel$1(_ref4) {
1170
+ let { className } = _ref4, props = _objectWithoutProperties(_ref4, _excluded4$3);
1171
+ return /* @__PURE__ */ jsx(ComboboxGroupLabel, _objectSpread2(_objectSpread2({ className: cn(groupLabelClass, className) }, props), {}, {
1172
+ "data-opt-id": "512YF",
1173
+ "data-opt-slug": "combobox.ComboboxGroupLabel"
1174
+ }));
1175
+ }
1176
+ /** Renders the combobox empty component. */
1177
+ function ComboboxEmpty({ className, children = koComboboxLabels.empty }) {
1178
+ return /* @__PURE__ */ jsx("p", {
1179
+ className: cn(emptyClass, className),
1180
+ "data-opt-id": "RZ06M",
1181
+ "data-opt-slug": "combobox.ComboboxEmpty",
1182
+ children
1183
+ });
1184
+ }
1185
+ //#endregion
1186
+ //#region src/core/menu.tsx
1187
+ const _excluded$5 = ["className"];
1188
+ const _excluded2$3 = ["className"];
1189
+ const _excluded3$3 = ["className"];
1190
+ const _excluded4$2 = ["className"];
1191
+ const _excluded5$2 = ["className"];
1192
+ const _excluded6$1 = ["className"];
1193
+ const _excluded7$1 = ["className"];
1194
+ const menuButtonClass = `inline-flex cursor-pointer items-center gap-1 rounded px-3 py-1.5 text-sm text-text-primary hover:bg-bg-subtle data-[active]:bg-bg-subtle data-[disabled]:cursor-not-allowed ${OPT_FOCUS}`;
1195
+ const menuPopoverClass = `${OPT_SURFACE_POPOVER} min-w-[180px] ${OPT_ANIMATE_ENTER_EXIT}`;
1196
+ const menuItemClass = `flex cursor-pointer items-center justify-between rounded-md px-2 py-1.5 text-sm text-text-primary outline-none data-[disabled]:cursor-not-allowed ${OPT_ACTIVE_ITEM}`;
1197
+ const menuSeparatorClass = "my-1 border-t border-border-subtle";
1198
+ const menubarClass = `${OPT_SURFACE} ${OPT_BORDER} flex items-center gap-1 px-1 py-1`;
1199
+ /** Renders the menubar root component. */
1200
+ function MenubarRoot$1(props) {
1201
+ return /* @__PURE__ */ jsx(MenubarRoot, _objectSpread2(_objectSpread2({}, props), {}, {
1202
+ "data-opt-id": "2ERC6",
1203
+ "data-opt-slug": "menu.MenubarRoot"
1204
+ }));
1205
+ }
1206
+ /** Renders the menubar container component. */
1207
+ function MenubarContainer$1(_ref) {
1208
+ let { className } = _ref, props = _objectWithoutProperties(_ref, _excluded$5);
1209
+ return /* @__PURE__ */ jsx(MenubarContainer, _objectSpread2(_objectSpread2({ className: cn(menubarClass, className) }, props), {}, {
1210
+ "data-opt-id": "4MVQT",
1211
+ "data-opt-slug": "menu.MenubarContainer"
1212
+ }));
1213
+ }
1214
+ /** Renders the menu root component. */
1215
+ function MenuRoot$1(props) {
1216
+ return /* @__PURE__ */ jsx(MenuRoot, _objectSpread2(_objectSpread2({}, props), {}, {
1217
+ "data-opt-id": "H2WRF",
1218
+ "data-opt-slug": "menu.MenuRoot"
1219
+ }));
1220
+ }
1221
+ /** Renders the menu trigger component. */
1222
+ function MenuTrigger$1(_ref2) {
1223
+ let { className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$3);
1224
+ return /* @__PURE__ */ jsx(MenuTrigger, _objectSpread2(_objectSpread2({ className: cn(menuButtonClass, className) }, props), {}, {
1225
+ "data-opt-id": "46BJG",
1226
+ "data-opt-slug": "menu.MenuTrigger"
1227
+ }));
1228
+ }
1229
+ /** Renders the menu button arrow component. */
1230
+ function MenuButtonArrow$1(props) {
1231
+ return /* @__PURE__ */ jsx(MenuButtonArrow, _objectSpread2(_objectSpread2({}, props), {}, {
1232
+ "data-opt-id": "J1AQH",
1233
+ "data-opt-slug": "menu.MenuButtonArrow"
1234
+ }));
1235
+ }
1236
+ /** Renders the menu popover component. */
1237
+ function MenuPopover$1(_ref3) {
1238
+ let { className } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3$3);
1239
+ return /* @__PURE__ */ jsx(MenuPopover, _objectSpread2(_objectSpread2({ className: cn(menuPopoverClass, className) }, props), {}, {
1240
+ "data-opt-id": "Q1MFY",
1241
+ "data-opt-slug": "menu.MenuPopover"
1242
+ }));
1243
+ }
1244
+ /** Renders the menu item component. */
1245
+ function MenuItem$1(_ref4) {
1246
+ let { className } = _ref4, props = _objectWithoutProperties(_ref4, _excluded4$2);
1247
+ return /* @__PURE__ */ jsx(MenuItem, _objectSpread2(_objectSpread2({ className: cn(menuItemClass, className) }, props), {}, {
1248
+ "data-opt-id": "71JVB",
1249
+ "data-opt-slug": "menu.MenuItem"
1250
+ }));
1251
+ }
1252
+ /** Renders the menu item checkbox component. */
1253
+ function MenuItemCheckbox$1(_ref5) {
1254
+ let { className } = _ref5, props = _objectWithoutProperties(_ref5, _excluded5$2);
1255
+ return /* @__PURE__ */ jsx(MenuItemCheckbox, _objectSpread2(_objectSpread2({ className: cn(menuItemClass, className) }, props), {}, {
1256
+ "data-opt-id": "DG8B3",
1257
+ "data-opt-slug": "menu.MenuItemCheckbox"
1258
+ }));
1259
+ }
1260
+ /** Renders the menu item radio component. */
1261
+ function MenuItemRadio$1(_ref6) {
1262
+ let { className } = _ref6, props = _objectWithoutProperties(_ref6, _excluded6$1);
1263
+ return /* @__PURE__ */ jsx(MenuItemRadio, _objectSpread2(_objectSpread2({ className: cn(menuItemClass, className) }, props), {}, {
1264
+ "data-opt-id": "ZT759",
1265
+ "data-opt-slug": "menu.MenuItemRadio"
1266
+ }));
1267
+ }
1268
+ /** Renders the menu separator component. */
1269
+ function MenuSeparator$1(_ref7) {
1270
+ let { className } = _ref7, props = _objectWithoutProperties(_ref7, _excluded7$1);
1271
+ return /* @__PURE__ */ jsx(MenuSeparator, _objectSpread2(_objectSpread2({ className: cn(menuSeparatorClass, className) }, props), {}, {
1272
+ "data-opt-id": "AJV8K",
1273
+ "data-opt-slug": "menu.MenuSeparator"
1274
+ }));
1275
+ }
1276
+ //#endregion
1277
+ //#region src/core/toolbar.tsx
1278
+ const _excluded$4 = ["className"];
1279
+ const _excluded2$2 = ["className"];
1280
+ const _excluded3$2 = ["className"];
1281
+ const _excluded4$1 = ["className"];
1282
+ const _excluded5$1 = ["className"];
1283
+ const toolbarClass = `${OPT_SURFACE} ${OPT_BORDER} inline-flex w-fit items-center gap-0.5 px-1.5 py-1`;
1284
+ const buttonClass = `cursor-pointer rounded-md px-2.5 py-1.5 text-text-primary transition-colors data-[disabled]:cursor-not-allowed ${OPT_ACTIVE_ITEM} ${OPT_FOCUS}`;
1285
+ const separatorClass = "mx-1 h-6 w-px bg-border-subtle";
1286
+ const tooltipClass = "z-50 rounded-md bg-foreground px-2 py-1 text-xs text-background shadow-lg";
1287
+ /** Renders the toolbar root component. */
1288
+ function ToolbarRoot$1(props) {
1289
+ return /* @__PURE__ */ jsx(ToolbarRoot, _objectSpread2(_objectSpread2({}, props), {}, {
1290
+ "data-opt-id": "V33Y0",
1291
+ "data-opt-slug": "toolbar.ToolbarRoot"
1292
+ }));
1293
+ }
1294
+ /** Renders the toolbar container component. */
1295
+ function ToolbarContainer$1(_ref) {
1296
+ let { className } = _ref, props = _objectWithoutProperties(_ref, _excluded$4);
1297
+ return /* @__PURE__ */ jsx(ToolbarContainer, _objectSpread2(_objectSpread2({ className: cn(toolbarClass, className) }, props), {}, {
1298
+ "data-opt-id": "2AVXB",
1299
+ "data-opt-slug": "toolbar.ToolbarContainer"
1300
+ }));
1301
+ }
1302
+ /** Renders the toolbar button component. */
1303
+ function ToolbarButton$1(_ref2) {
1304
+ let { className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$2);
1305
+ return /* @__PURE__ */ jsx(ToolbarButton, _objectSpread2(_objectSpread2({ className: cn(buttonClass, className) }, props), {}, {
1306
+ "data-opt-id": "C212C",
1307
+ "data-opt-slug": "toolbar.ToolbarButton"
1308
+ }));
1309
+ }
1310
+ /** Renders the toolbar separator component. */
1311
+ function ToolbarSeparator$1(_ref3) {
1312
+ let { className } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3$2);
1313
+ return /* @__PURE__ */ jsx(ToolbarSeparator, _objectSpread2(_objectSpread2({ className: cn(separatorClass, className) }, props), {}, {
1314
+ "data-opt-id": "9J72S",
1315
+ "data-opt-slug": "toolbar.ToolbarSeparator"
1316
+ }));
1317
+ }
1318
+ /** Renders the tooltip provider component. */
1319
+ function TooltipProvider$1(props) {
1320
+ return /* @__PURE__ */ jsx(TooltipProvider, _objectSpread2(_objectSpread2({}, props), {}, {
1321
+ "data-opt-id": "6NKHT",
1322
+ "data-opt-slug": "toolbar.TooltipProvider"
1323
+ }));
1324
+ }
1325
+ /** Renders the tooltip anchor component. */
1326
+ function TooltipAnchor$1(_ref4) {
1327
+ let { className } = _ref4, props = _objectWithoutProperties(_ref4, _excluded4$1);
1328
+ return /* @__PURE__ */ jsx(TooltipAnchor, _objectSpread2(_objectSpread2({ className }, props), {}, {
1329
+ "data-opt-id": "SAW1B",
1330
+ "data-opt-slug": "toolbar.TooltipAnchor"
1331
+ }));
1332
+ }
1333
+ /** Renders the tooltip component. */
1334
+ function Tooltip$1(_ref5) {
1335
+ let { className } = _ref5, props = _objectWithoutProperties(_ref5, _excluded5$1);
1336
+ return /* @__PURE__ */ jsx(Tooltip, _objectSpread2(_objectSpread2({ className: cn(tooltipClass, className) }, props), {}, {
1337
+ "data-opt-id": "XSAT4",
1338
+ "data-opt-slug": "toolbar.Tooltip"
1339
+ }));
1340
+ }
1341
+ //#endregion
1342
+ //#region src/core/number-input.tsx
1343
+ /** Number of decimal places a finite number is written with (handles exponents). */
1344
+ function decimalPlaces(n) {
1345
+ if (!Number.isFinite(n)) return 0;
1346
+ const s = String(n);
1347
+ const exp = s.indexOf("e");
1348
+ if (exp >= 0) {
1349
+ const mantissa = s.slice(0, exp);
1350
+ const dot = mantissa.indexOf(".");
1351
+ const mantissaDecimals = dot >= 0 ? mantissa.length - dot - 1 : 0;
1352
+ return Math.max(0, mantissaDecimals - Number(s.slice(exp + 1)));
1353
+ }
1354
+ const dot = s.indexOf(".");
1355
+ return dot >= 0 ? s.length - dot - 1 : 0;
1356
+ }
1357
+ /**
1358
+ * Adds `delta` to `value` without binary floating-point drift (e.g. 0.1 + 0.2).
1359
+ * Rounds to the largest precision present among the operands and `step`.
1360
+ */
1361
+ function addPrecise(value, delta, step) {
1362
+ const decimals = Math.max(decimalPlaces(value), decimalPlaces(delta), decimalPlaces(step));
1363
+ if (decimals === 0) return value + delta;
1364
+ const factor = 10 ** Math.min(decimals, 15);
1365
+ return Math.round((value + delta) * factor) / factor;
1366
+ }
1367
+ const NUMBER_PATTERN = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
1368
+ const PARTIAL_NUMBER_PATTERN = /^[+-]?$|^[+-]?\.$|^[+-]?(?:\d+\.?\d*|\.\d+)[eE][+-]?$/;
1369
+ function parseDraftValue(raw) {
1370
+ const value = raw.trim();
1371
+ if (value === "") return { kind: "empty" };
1372
+ if (PARTIAL_NUMBER_PATTERN.test(value)) return { kind: "partial" };
1373
+ if (!NUMBER_PATTERN.test(value)) return { kind: "invalid" };
1374
+ const parsed = Number(value);
1375
+ if (!Number.isFinite(parsed)) return { kind: "invalid" };
1376
+ return {
1377
+ kind: "valid",
1378
+ value: parsed
1379
+ };
1380
+ }
1381
+ const DEFAULT_LABELS$1 = {
1382
+ input: "Number",
1383
+ decrease: "Decrease",
1384
+ increase: "Increase",
1385
+ clear: "Clear value",
1386
+ invalid: "Enter a valid number"
1387
+ };
1388
+ /** Renders the number input component. */
1389
+ function NumberInput({ value: controlledValue, defaultValue, onChange, nullable, clearable = false, min, max, step = 1, largeStep, scrub = false, label, unit, required, error, hint, disabled = false, disabledReason, labels, className, id, "aria-label": ariaLabel }) {
1390
+ var _useInputId, _ref, _ref2;
1391
+ const generatedId = React.useId();
1392
+ const inputId = (_useInputId = useInputId(id, label, "number-input")) !== null && _useInputId !== void 0 ? _useInputId : `${generatedId}-number-input`;
1393
+ const resolvedLabels = _objectSpread2(_objectSpread2({}, DEFAULT_LABELS$1), labels);
1394
+ const isNullable = nullable === true;
1395
+ const nativeDisabled = disabled && !disabledReason;
1396
+ const interactionDisabled = disabled;
1397
+ const [invalidDraft, setInvalidDraft] = React.useState(false);
1398
+ const effectiveError = error !== null && error !== void 0 ? error : invalidDraft ? resolvedLabels.invalid : "";
1399
+ const hasError = Boolean(effectiveError);
1400
+ const clamp = React.useCallback((v) => {
1401
+ let clamped = v;
1402
+ if (min !== void 0) clamped = Math.max(min, clamped);
1403
+ if (max !== void 0) clamped = Math.min(max, clamped);
1404
+ return clamped;
1405
+ }, [min, max]);
1406
+ const [rawValue, setRawValue] = useControlledState((_ref = defaultValue) !== null && _ref !== void 0 ? _ref : isNullable ? null : 0, controlledValue, React.useCallback((next) => {
1407
+ if (isNullable) {
1408
+ onChange === null || onChange === void 0 || onChange(next);
1409
+ return;
1410
+ }
1411
+ if (next !== null) onChange === null || onChange === void 0 || onChange(next);
1412
+ }, [isNullable, onChange]));
1413
+ const value = rawValue;
1414
+ const numericValue = value !== null && value !== void 0 ? value : 0;
1415
+ const setValue = React.useCallback((next) => {
1416
+ setRawValue(next === null ? null : clamp(next));
1417
+ }, [clamp, setRawValue]);
1418
+ const format = React.useCallback((v) => {
1419
+ const decimals = Math.max(decimalPlaces(step), decimalPlaces(v));
1420
+ return v.toFixed(Math.min(decimals, 20));
1421
+ }, [step]);
1422
+ const [inputText, setInputText] = React.useState(null);
1423
+ const focusedRef = React.useRef(false);
1424
+ const displayValue = inputText !== null && inputText !== void 0 ? inputText : value === null ? "" : format(value);
1425
+ const stateRef = React.useRef({
1426
+ step,
1427
+ clamp,
1428
+ format
1429
+ });
1430
+ stateRef.current = {
1431
+ step,
1432
+ clamp,
1433
+ format
1434
+ };
1435
+ const valueRef = React.useRef(value);
1436
+ valueRef.current = value;
1437
+ const getSpinBase = React.useCallback(() => {
1438
+ if (valueRef.current !== null) return valueRef.current;
1439
+ return clamp(min !== null && min !== void 0 ? min : 0);
1440
+ }, [clamp, min]);
1441
+ const spin = React.useCallback((delta) => {
1442
+ if (interactionDisabled) return;
1443
+ const s = stateRef.current;
1444
+ const next = s.clamp(addPrecise(getSpinBase(), delta, s.step));
1445
+ valueRef.current = next;
1446
+ setInvalidDraft(false);
1447
+ setValue(next);
1448
+ if (focusedRef.current) setInputText(s.format(next));
1449
+ }, [
1450
+ getSpinBase,
1451
+ interactionDisabled,
1452
+ setValue
1453
+ ]);
1454
+ const setTo = React.useCallback((next) => {
1455
+ if (interactionDisabled) return;
1456
+ const s = stateRef.current;
1457
+ const clamped = s.clamp(next);
1458
+ valueRef.current = clamped;
1459
+ setInvalidDraft(false);
1460
+ setValue(clamped);
1461
+ if (focusedRef.current) setInputText(s.format(clamped));
1462
+ }, [interactionDisabled, setValue]);
1463
+ const handleChange = React.useCallback((e) => {
1464
+ const raw = e.target.value;
1465
+ setInputText(raw);
1466
+ const parsed = parseDraftValue(raw);
1467
+ if (parsed.kind === "empty") {
1468
+ setInvalidDraft(false);
1469
+ if (isNullable) {
1470
+ valueRef.current = null;
1471
+ setValue(null);
1472
+ }
1473
+ return;
1474
+ }
1475
+ if (parsed.kind === "partial") {
1476
+ setInvalidDraft(false);
1477
+ return;
1478
+ }
1479
+ if (parsed.kind === "invalid") {
1480
+ setInvalidDraft(true);
1481
+ return;
1482
+ }
1483
+ setInvalidDraft(false);
1484
+ setValue(parsed.value);
1485
+ }, [isNullable, setValue]);
1486
+ const handleFocus = React.useCallback(() => {
1487
+ focusedRef.current = true;
1488
+ }, []);
1489
+ const handleBlur = React.useCallback(() => {
1490
+ focusedRef.current = false;
1491
+ setInputText(null);
1492
+ setInvalidDraft(false);
1493
+ setValue(valueRef.current);
1494
+ }, [setValue]);
1495
+ const handleClear = React.useCallback(() => {
1496
+ if (!isNullable || interactionDisabled) return;
1497
+ valueRef.current = null;
1498
+ setInvalidDraft(false);
1499
+ setInputText(focusedRef.current ? "" : null);
1500
+ setValue(null);
1501
+ }, [
1502
+ interactionDisabled,
1503
+ isNullable,
1504
+ setValue
1505
+ ]);
1506
+ const repeatedRef = React.useRef(false);
1507
+ const timersRef = React.useRef({});
1508
+ const stopRepeat = React.useCallback(() => {
1509
+ const t = timersRef.current;
1510
+ if (t.timeout !== void 0) window.clearTimeout(t.timeout);
1511
+ if (t.interval !== void 0) window.clearInterval(t.interval);
1512
+ timersRef.current = {};
1513
+ }, []);
1514
+ React.useEffect(() => stopRepeat, [stopRepeat]);
1515
+ const handleStepPointerDown = React.useCallback((dir) => (e) => {
1516
+ if (e.button !== 0 || interactionDisabled) return;
1517
+ repeatedRef.current = false;
1518
+ stopRepeat();
1519
+ const delta = () => dir * stateRef.current.step;
1520
+ timersRef.current.timeout = window.setTimeout(() => {
1521
+ timersRef.current.interval = window.setInterval(() => {
1522
+ repeatedRef.current = true;
1523
+ spin(delta());
1524
+ }, 60);
1525
+ }, 300);
1526
+ }, [
1527
+ interactionDisabled,
1528
+ spin,
1529
+ stopRepeat
1530
+ ]);
1531
+ const handleStepClick = React.useCallback((dir) => () => {
1532
+ if (interactionDisabled) return;
1533
+ if (repeatedRef.current) {
1534
+ repeatedRef.current = false;
1535
+ return;
1536
+ }
1537
+ spin(dir * stateRef.current.step);
1538
+ }, [interactionDisabled, spin]);
1539
+ const handleKeyDown = React.useCallback((e) => {
1540
+ if (interactionDisabled) return;
1541
+ const s = stateRef.current;
1542
+ const big = largeStep !== null && largeStep !== void 0 ? largeStep : s.step * 10;
1543
+ switch (e.key) {
1544
+ case "ArrowUp":
1545
+ e.preventDefault();
1546
+ spin(s.step);
1547
+ break;
1548
+ case "ArrowDown":
1549
+ e.preventDefault();
1550
+ spin(-s.step);
1551
+ break;
1552
+ case "PageUp":
1553
+ e.preventDefault();
1554
+ spin(big);
1555
+ break;
1556
+ case "PageDown":
1557
+ e.preventDefault();
1558
+ spin(-big);
1559
+ break;
1560
+ case "Home":
1561
+ if (min !== void 0) {
1562
+ e.preventDefault();
1563
+ setTo(min);
1564
+ }
1565
+ break;
1566
+ case "End": if (max !== void 0) {
1567
+ e.preventDefault();
1568
+ setTo(max);
1569
+ }
1570
+ }
1571
+ }, [
1572
+ interactionDisabled,
1573
+ spin,
1574
+ setTo,
1575
+ largeStep,
1576
+ min,
1577
+ max
1578
+ ]);
1579
+ const scrubStartRef = React.useRef(null);
1580
+ const handleScrubPointerDown = React.useCallback((e) => {
1581
+ if (e.button !== 0 || interactionDisabled) return;
1582
+ e.preventDefault();
1583
+ scrubStartRef.current = {
1584
+ x: e.clientX,
1585
+ value: getSpinBase()
1586
+ };
1587
+ try {
1588
+ e.currentTarget.setPointerCapture(e.pointerId);
1589
+ } catch (_unused) {}
1590
+ }, [getSpinBase, interactionDisabled]);
1591
+ const handleScrubPointerMove = React.useCallback((e) => {
1592
+ const start = scrubStartRef.current;
1593
+ if (!start) return;
1594
+ const s = stateRef.current;
1595
+ const steps = Math.round((e.clientX - start.x) / 6);
1596
+ setInvalidDraft(false);
1597
+ setValue(s.clamp(addPrecise(start.value, steps * s.step, s.step)));
1598
+ }, [setValue]);
1599
+ const handleScrubPointerUp = React.useCallback((e) => {
1600
+ scrubStartRef.current = null;
1601
+ try {
1602
+ e.currentTarget.releasePointerCapture(e.pointerId);
1603
+ } catch (_unused2) {}
1604
+ }, []);
1605
+ const canDecrement = value === null || min === void 0 || numericValue > min;
1606
+ const canIncrement = value === null || max === void 0 || numericValue < max;
1607
+ const decrementUnavailable = interactionDisabled || !canDecrement;
1608
+ const incrementUnavailable = interactionDisabled || !canIncrement;
1609
+ const showClear = isNullable && clearable && value !== null;
1610
+ return /* @__PURE__ */ jsxs("div", {
1611
+ className: cn("flex flex-col gap-1.5", className),
1612
+ "data-opt-id": "GKPSV",
1613
+ "data-opt-slug": "number-input.NumberInput",
1614
+ children: [
1615
+ label && /* @__PURE__ */ jsxs("span", {
1616
+ className: cn("text-sm font-medium text-text-primary", scrub && !interactionDisabled && "w-fit cursor-ew-resize touch-none select-none"),
1617
+ onPointerDown: scrub ? handleScrubPointerDown : void 0,
1618
+ onPointerMove: scrub ? handleScrubPointerMove : void 0,
1619
+ onPointerUp: scrub ? handleScrubPointerUp : void 0,
1620
+ onPointerCancel: scrub ? handleScrubPointerUp : void 0,
1621
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
1622
+ }),
1623
+ /* @__PURE__ */ jsxs("div", {
1624
+ className: "flex items-center",
1625
+ children: [
1626
+ /* @__PURE__ */ jsx("button", {
1627
+ type: "button",
1628
+ onClick: handleStepClick(-1),
1629
+ onPointerDown: handleStepPointerDown(-1),
1630
+ onPointerUp: stopRepeat,
1631
+ onPointerLeave: stopRepeat,
1632
+ onPointerCancel: stopRepeat,
1633
+ disabled: nativeDisabled || !canDecrement,
1634
+ "aria-disabled": decrementUnavailable || void 0,
1635
+ "aria-label": resolvedLabels.decrease,
1636
+ title: disabledReason,
1637
+ className: cn("border-border bg-surface text-text-secondary flex h-10 w-10 items-center justify-center rounded-l-lg border border-r-0 text-sm font-medium", decrementUnavailable ? "cursor-not-allowed opacity-40" : "hover:bg-bg-subtle cursor-pointer", nativeDisabled && "pointer-events-none", OPT_FOCUS_VISIBLE),
1638
+ children: "−"
1639
+ }),
1640
+ /* @__PURE__ */ jsxs("div", {
1641
+ className: "relative min-w-0 flex-1",
1642
+ children: [
1643
+ /* @__PURE__ */ jsx("input", {
1644
+ type: "text",
1645
+ inputMode: "decimal",
1646
+ id: inputId,
1647
+ value: displayValue,
1648
+ onChange: handleChange,
1649
+ onFocus: handleFocus,
1650
+ onBlur: handleBlur,
1651
+ onKeyDown: handleKeyDown,
1652
+ disabled: nativeDisabled,
1653
+ readOnly: interactionDisabled,
1654
+ "aria-disabled": interactionDisabled || void 0,
1655
+ "aria-label": (_ref2 = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label) !== null && _ref2 !== void 0 ? _ref2 : resolvedLabels.input,
1656
+ "aria-invalid": hasError,
1657
+ "aria-required": required,
1658
+ "aria-describedby": getDescribedBy(inputId, effectiveError, hint),
1659
+ min,
1660
+ max,
1661
+ step,
1662
+ title: disabledReason,
1663
+ className: cn(OPT_INPUT, "[appearance:textfield] rounded-none border-x-0 text-center [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none", (unit || showClear) && "pr-10", unit && showClear && "pr-16", interactionDisabled && "cursor-not-allowed opacity-60", hasError && "border-danger focus-visible:outline-danger")
1664
+ }),
1665
+ unit && /* @__PURE__ */ jsx("span", {
1666
+ className: cn("text-text-tertiary pointer-events-none absolute top-1/2 -translate-y-1/2 text-sm", showClear ? "right-10" : "right-3"),
1667
+ "aria-hidden": "true",
1668
+ children: unit
1669
+ }),
1670
+ showClear && /* @__PURE__ */ jsx("button", {
1671
+ type: "button",
1672
+ onClick: handleClear,
1673
+ disabled: nativeDisabled,
1674
+ "aria-disabled": interactionDisabled || void 0,
1675
+ "aria-label": resolvedLabels.clear,
1676
+ title: disabledReason,
1677
+ className: cn("text-text-tertiary absolute top-1/2 right-2 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded text-sm", interactionDisabled ? "cursor-not-allowed opacity-40" : "hover:bg-bg-subtle hover:text-text-primary cursor-pointer", nativeDisabled && "pointer-events-none", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset"),
1678
+ children: "×"
1679
+ })
1680
+ ]
1681
+ }),
1682
+ /* @__PURE__ */ jsx("button", {
1683
+ type: "button",
1684
+ onClick: handleStepClick(1),
1685
+ onPointerDown: handleStepPointerDown(1),
1686
+ onPointerUp: stopRepeat,
1687
+ onPointerLeave: stopRepeat,
1688
+ onPointerCancel: stopRepeat,
1689
+ disabled: nativeDisabled || !canIncrement,
1690
+ "aria-disabled": incrementUnavailable || void 0,
1691
+ "aria-label": resolvedLabels.increase,
1692
+ title: disabledReason,
1693
+ className: cn("border-border bg-surface text-text-secondary flex h-10 w-10 items-center justify-center rounded-r-lg border border-l-0 text-sm font-medium", incrementUnavailable ? "cursor-not-allowed opacity-40" : "hover:bg-bg-subtle cursor-pointer", nativeDisabled && "pointer-events-none", OPT_FOCUS_VISIBLE),
1694
+ children: "+"
1695
+ })
1696
+ ]
1697
+ }),
1698
+ /* @__PURE__ */ jsx(FieldMessages, {
1699
+ id: inputId,
1700
+ error: effectiveError,
1701
+ hint
1702
+ })
1703
+ ]
1704
+ });
1705
+ }
1706
+ NumberInput.displayName = "NumberInput";
1707
+ //#endregion
1708
+ //#region src/core/slider.tsx
1709
+ function getSliderState(value, min, max, step) {
1710
+ const safeMin = Number.isFinite(min) ? min : 0;
1711
+ const rawMax = Number.isFinite(max) ? max : 100;
1712
+ const safeMax = rawMax >= safeMin ? rawMax : safeMin;
1713
+ const safeStep = Number.isFinite(step) && step > 0 ? step : 1;
1714
+ const clampedValue = Math.min(Math.max(Number.isFinite(value) ? value : safeMin, safeMin), safeMax);
1715
+ return {
1716
+ value: clampedValue,
1717
+ min: safeMin,
1718
+ max: safeMax,
1719
+ step: safeStep,
1720
+ percentage: safeMax === safeMin ? 0 : (clampedValue - safeMin) / (safeMax - safeMin) * 100
1721
+ };
1722
+ }
1723
+ /** Renders the slider component. */
1724
+ function Slider({ value: controlledValue, defaultValue = 0, onChange, min = 0, max = 100, step = 1, label, showValue = false, formatValue, disabled = false, className, "aria-label": ariaLabel }) {
1725
+ var _ref;
1726
+ const [localValue, setLocalValue] = useState(defaultValue);
1727
+ const sliderState = getSliderState(controlledValue !== null && controlledValue !== void 0 ? controlledValue : localValue, min, max, step);
1728
+ const handleChange = useCallback((e) => {
1729
+ const next = getSliderState(parseFloat(e.target.value), min, max, step).value;
1730
+ if (controlledValue === void 0) setLocalValue(next);
1731
+ onChange === null || onChange === void 0 || onChange(next);
1732
+ }, [
1733
+ controlledValue,
1734
+ min,
1735
+ max,
1736
+ step,
1737
+ onChange
1738
+ ]);
1739
+ const displayValue = formatValue ? formatValue(sliderState.value) : String(sliderState.value);
1740
+ return /* @__PURE__ */ jsxs("div", {
1741
+ className: cn("flex flex-col gap-1.5", className),
1742
+ "data-opt-id": "VJCDH",
1743
+ "data-opt-slug": "slider.Slider",
1744
+ children: [(label || showValue) && /* @__PURE__ */ jsxs("div", {
1745
+ className: "flex items-center justify-between",
1746
+ children: [label && /* @__PURE__ */ jsx("span", {
1747
+ className: "text-sm font-medium text-text-primary",
1748
+ children: label
1749
+ }), showValue && /* @__PURE__ */ jsx("span", {
1750
+ className: "text-text-tertiary text-sm",
1751
+ children: displayValue
1752
+ })]
1753
+ }), /* @__PURE__ */ jsx("input", {
1754
+ type: "range",
1755
+ min: sliderState.min,
1756
+ max: sliderState.max,
1757
+ step: sliderState.step,
1758
+ value: sliderState.value,
1759
+ onChange: handleChange,
1760
+ disabled,
1761
+ "aria-label": (_ref = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label) !== null && _ref !== void 0 ? _ref : "Slider",
1762
+ "aria-valuemin": sliderState.min,
1763
+ "aria-valuemax": sliderState.max,
1764
+ "aria-valuenow": sliderState.value,
1765
+ "aria-valuetext": displayValue,
1766
+ className: cn("h-2 w-full cursor-pointer appearance-none rounded-full", "bg-bg-subtle", "[&::-webkit-slider-thumb]:bg-accent [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:shadow-sm", "[&::-moz-range-thumb]:bg-accent [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:shadow-sm", "disabled:cursor-not-allowed disabled:opacity-40", OPT_FOCUS_VISIBLE),
1767
+ style: { background: disabled ? void 0 : `linear-gradient(to right, var(--color-accent) ${sliderState.percentage}%, var(--color-bg-subtle) ${sliderState.percentage}%)` }
1768
+ })]
1769
+ });
1770
+ }
1771
+ Slider.displayName = "Slider";
1772
+ //#endregion
1773
+ //#region src/core/popover.tsx
1774
+ const _excluded$3 = ["className"];
1775
+ const _excluded2$1 = ["className"];
1776
+ const _excluded3$1 = ["className"];
1777
+ /** Renders the popover root component. */
1778
+ function PopoverRoot$1(props) {
1779
+ return /* @__PURE__ */ jsx(PopoverRoot, _objectSpread2(_objectSpread2({}, props), {}, {
1780
+ "data-opt-id": "DWJD5",
1781
+ "data-opt-slug": "popover.PopoverRoot"
1782
+ }));
1783
+ }
1784
+ const PopoverTrigger$1 = forwardRef((_ref, ref) => {
1785
+ let { className } = _ref, props = _objectWithoutProperties(_ref, _excluded$3);
1786
+ return /* @__PURE__ */ jsx(PopoverTrigger, _objectSpread2(_objectSpread2({
1787
+ ref,
1788
+ className: cn("inline-flex items-center gap-1.5 rounded-lg px-3 py-2 text-sm", "cursor-pointer data-[disabled]:cursor-not-allowed", OPT_FOCUS_VISIBLE, className)
1789
+ }, props), {}, {
1790
+ "data-opt-id": "2W9BZ",
1791
+ "data-opt-slug": "popover.PopoverTrigger"
1792
+ }));
1793
+ });
1794
+ PopoverTrigger$1.displayName = "PopoverTrigger";
1795
+ /** Renders the popover content component. */
1796
+ function PopoverContent$1(_ref2) {
1797
+ let { className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$1);
1798
+ return /* @__PURE__ */ jsx(PopoverContent, _objectSpread2(_objectSpread2({ className: cn("bg-surface-overlay z-50 rounded-lg p-4 shadow-lg", OPT_BORDER, OPT_ANIMATE_ENTER_EXIT, className) }, props), {}, {
1799
+ "data-opt-id": "E03EY",
1800
+ "data-opt-slug": "popover.PopoverContent"
1801
+ }));
1802
+ }
1803
+ /** Renders the popover close component. */
1804
+ function PopoverClose$1(_ref3) {
1805
+ let { className } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3$1);
1806
+ return /* @__PURE__ */ jsx(PopoverClose, _objectSpread2(_objectSpread2({ className: cn("text-text-tertiary hover:bg-bg-subtle inline-flex items-center justify-center rounded-md p-1 text-sm", "cursor-pointer data-[disabled]:cursor-not-allowed", OPT_FOCUS_VISIBLE, className) }, props), {}, {
1807
+ "data-opt-id": "FP4KF",
1808
+ "data-opt-slug": "popover.PopoverClose"
1809
+ }));
1810
+ }
1811
+ //#endregion
1812
+ //#region src/core/color-picker.tsx
1813
+ const DEFAULT_PRESETS$1 = [
1814
+ "#3b82f6",
1815
+ "#10b981",
1816
+ "#f59e0b",
1817
+ "#8b5cf6",
1818
+ "#ef4444",
1819
+ "#06b6d4",
1820
+ "#f97316",
1821
+ "#ec4899",
1822
+ "#84cc16",
1823
+ "#6366f1",
1824
+ "#14b8a6",
1825
+ "#a855f7",
1826
+ "#78716c",
1827
+ "#000000",
1828
+ "#6b7280",
1829
+ "#ffffff"
1830
+ ];
1831
+ const ColorPicker = forwardRef(({ value, onChange, presets = DEFAULT_PRESETS$1, label, required, error, hint, placeholder = "#000000", disabled = false, className, id, "aria-label": ariaLabel }, ref) => {
1832
+ var _useInputId, _ref;
1833
+ const [color, setColor] = useControlledState("#3b82f6", value, onChange);
1834
+ const fallbackId = useId().replace(/:/g, "");
1835
+ const pickerId = (_useInputId = useInputId(id, label, "color-picker")) !== null && _useInputId !== void 0 ? _useInputId : `color-picker-${fallbackId}`;
1836
+ const hasError = Boolean(error);
1837
+ const [inputValue, setInputValue] = useState(color);
1838
+ const inputRef = useRef(null);
1839
+ const handlePresetClick = useCallback((preset) => {
1840
+ setColor(preset);
1841
+ setInputValue(preset);
1842
+ }, [setColor]);
1843
+ const handleInputChange = useCallback((e) => {
1844
+ const val = e.target.value;
1845
+ setInputValue(val);
1846
+ if (/^#[0-9a-fA-F]{6}$/.test(val)) setColor(val);
1847
+ }, [setColor]);
1848
+ const handleInputBlur = useCallback(() => {
1849
+ if (!/^#[0-9a-fA-F]{6}$/.test(inputValue)) setInputValue(color);
1850
+ }, [inputValue, color]);
1851
+ const lastValueRef = useRef(value);
1852
+ if (value !== void 0 && value !== lastValueRef.current) {
1853
+ lastValueRef.current = value;
1854
+ if (value !== inputValue) setInputValue(value);
1855
+ }
1856
+ return /* @__PURE__ */ jsxs("div", {
1857
+ className: cn("flex flex-col gap-1.5", className),
1858
+ "data-opt-id": "V2CSG",
1859
+ "data-opt-slug": "color-picker.ColorPicker",
1860
+ children: [
1861
+ label && /* @__PURE__ */ jsxs("span", {
1862
+ className: "text-sm font-medium text-text-primary",
1863
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
1864
+ }),
1865
+ /* @__PURE__ */ jsxs(PopoverRoot$1, { children: [/* @__PURE__ */ jsxs(PopoverTrigger$1, {
1866
+ id: pickerId,
1867
+ className: cn(OPT_INPUT, "cursor-pointer items-center gap-2", hasError && "border-danger focus-visible:outline-danger", disabled && "pointer-events-none opacity-50"),
1868
+ disabled,
1869
+ "aria-label": (_ref = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label) !== null && _ref !== void 0 ? _ref : "Color picker",
1870
+ "aria-required": required,
1871
+ "aria-invalid": hasError,
1872
+ "aria-describedby": getDescribedBy(pickerId, error, hint),
1873
+ children: [/* @__PURE__ */ jsx("span", {
1874
+ className: "border-border inline-block h-5 w-5 rounded border",
1875
+ style: { backgroundColor: color },
1876
+ "aria-hidden": "true"
1877
+ }), /* @__PURE__ */ jsx("span", {
1878
+ className: OPT_TEXT_PRIMARY,
1879
+ children: color
1880
+ })]
1881
+ }), /* @__PURE__ */ jsxs(PopoverContent$1, {
1882
+ className: cn("bg-surface-overlay z-50 rounded-lg p-3 shadow-lg", OPT_BORDER),
1883
+ children: [/* @__PURE__ */ jsx("div", {
1884
+ className: "mb-3 grid grid-cols-8 gap-1.5",
1885
+ role: "listbox",
1886
+ "aria-label": "Color presets",
1887
+ children: presets.map((preset) => /* @__PURE__ */ jsx("button", {
1888
+ type: "button",
1889
+ onClick: () => handlePresetClick(preset),
1890
+ className: cn("h-7 w-7 rounded-md border transition-transform hover:scale-110", OPT_FOCUS_VISIBLE, preset === color ? "border-accent ring-ring ring-offset-ring-offset ring-2 ring-offset-1" : "border-border", preset === "#ffffff" && "border-black/20"),
1891
+ style: { backgroundColor: preset },
1892
+ role: "option",
1893
+ "aria-selected": preset === color,
1894
+ "aria-label": preset
1895
+ }, preset))
1896
+ }), /* @__PURE__ */ jsxs("div", {
1897
+ className: "flex items-center gap-2",
1898
+ children: [/* @__PURE__ */ jsx("span", {
1899
+ className: "border-border h-8 w-8 rounded-md border",
1900
+ style: { backgroundColor: color },
1901
+ "aria-hidden": "true"
1902
+ }), /* @__PURE__ */ jsx("input", {
1903
+ ref: ref !== null && ref !== void 0 ? ref : inputRef,
1904
+ type: "text",
1905
+ value: inputValue,
1906
+ onChange: handleInputChange,
1907
+ onBlur: handleInputBlur,
1908
+ placeholder,
1909
+ maxLength: 7,
1910
+ className: cn("border-border bg-surface flex-1 rounded-md border px-2 py-1.5 font-mono text-sm", OPT_TEXT_PRIMARY, OPT_FOCUS_VISIBLE),
1911
+ "aria-label": "Hex color value"
1912
+ })]
1913
+ })]
1914
+ })] }),
1915
+ /* @__PURE__ */ jsx(FieldMessages, {
1916
+ id: pickerId,
1917
+ error,
1918
+ hint
1919
+ })
1920
+ ]
1921
+ });
1922
+ });
1923
+ ColorPicker.displayName = "ColorPicker";
1924
+ //#endregion
1925
+ //#region src/lib/icon-registry.tsx
1926
+ const defaultIconEntries = [
1927
+ {
1928
+ id: "click",
1929
+ label: "Click",
1930
+ Icon: MousePointerClick,
1931
+ group: "Actions"
1932
+ },
1933
+ {
1934
+ id: "view",
1935
+ label: "View",
1936
+ Icon: Eye,
1937
+ group: "Actions"
1938
+ },
1939
+ {
1940
+ id: "cart",
1941
+ label: "Cart",
1942
+ Icon: ShoppingCart,
1943
+ group: "Actions"
1944
+ },
1945
+ {
1946
+ id: "purchase",
1947
+ label: "Purchase",
1948
+ Icon: CreditCard,
1949
+ group: "Actions"
1950
+ },
1951
+ {
1952
+ id: "signup",
1953
+ label: "Sign Up",
1954
+ Icon: UserPlus,
1955
+ group: "Actions"
1956
+ },
1957
+ {
1958
+ id: "login",
1959
+ label: "Login",
1960
+ Icon: LogIn,
1961
+ group: "Actions"
1962
+ },
1963
+ {
1964
+ id: "search",
1965
+ label: "Search",
1966
+ Icon: Search,
1967
+ group: "Actions"
1968
+ },
1969
+ {
1970
+ id: "download",
1971
+ label: "Download",
1972
+ Icon: Download,
1973
+ group: "Actions"
1974
+ },
1975
+ {
1976
+ id: "share",
1977
+ label: "Share",
1978
+ Icon: Share2,
1979
+ group: "Social"
1980
+ },
1981
+ {
1982
+ id: "like",
1983
+ label: "Like",
1984
+ Icon: Heart,
1985
+ group: "Social"
1986
+ },
1987
+ {
1988
+ id: "comment",
1989
+ label: "Comment",
1990
+ Icon: MessageCircle,
1991
+ group: "Social"
1992
+ },
1993
+ {
1994
+ id: "follow",
1995
+ label: "Follow",
1996
+ Icon: UserPlus,
1997
+ group: "Social"
1998
+ },
1999
+ {
2000
+ id: "star",
2001
+ label: "Star",
2002
+ Icon: Star,
2003
+ group: "Status"
2004
+ },
2005
+ {
2006
+ id: "flag",
2007
+ label: "Flag",
2008
+ Icon: Flag,
2009
+ group: "Status"
2010
+ },
2011
+ {
2012
+ id: "check",
2013
+ label: "Check",
2014
+ Icon: Check,
2015
+ group: "Status"
2016
+ },
2017
+ {
2018
+ id: "error",
2019
+ label: "Error",
2020
+ Icon: CircleAlert,
2021
+ group: "Status"
2022
+ },
2023
+ {
2024
+ id: "warning",
2025
+ label: "Warning",
2026
+ Icon: TriangleAlert,
2027
+ group: "Status"
2028
+ },
2029
+ {
2030
+ id: "info",
2031
+ label: "Info",
2032
+ Icon: Info,
2033
+ group: "Status"
2034
+ },
2035
+ {
2036
+ id: "bell",
2037
+ label: "Bell",
2038
+ Icon: Bell,
2039
+ group: "Objects"
2040
+ },
2041
+ {
2042
+ id: "mail",
2043
+ label: "Mail",
2044
+ Icon: Mail,
2045
+ group: "Objects"
2046
+ },
2047
+ {
2048
+ id: "file",
2049
+ label: "File",
2050
+ Icon: FileText,
2051
+ group: "Objects"
2052
+ },
2053
+ {
2054
+ id: "folder",
2055
+ label: "Folder",
2056
+ Icon: Folder,
2057
+ group: "Objects"
2058
+ },
2059
+ {
2060
+ id: "settings",
2061
+ label: "Settings",
2062
+ Icon: Settings,
2063
+ group: "Objects"
2064
+ },
2065
+ {
2066
+ id: "link",
2067
+ label: "Link",
2068
+ Icon: Link2,
2069
+ group: "Objects"
2070
+ }
2071
+ ];
2072
+ const extraIconEntries = [
2073
+ {
2074
+ id: "eye",
2075
+ label: "Eye",
2076
+ Icon: Eye
2077
+ },
2078
+ {
2079
+ id: "user",
2080
+ label: "User",
2081
+ Icon: User
2082
+ },
2083
+ {
2084
+ id: "shopping-cart",
2085
+ label: "Shopping Cart",
2086
+ Icon: ShoppingCart
2087
+ },
2088
+ {
2089
+ id: "credit-card",
2090
+ label: "Credit Card",
2091
+ Icon: CreditCard
2092
+ },
2093
+ {
2094
+ id: "heart",
2095
+ label: "Heart",
2096
+ Icon: Heart
2097
+ },
2098
+ {
2099
+ id: "upload",
2100
+ label: "Upload",
2101
+ Icon: Upload
2102
+ },
2103
+ {
2104
+ id: "globe",
2105
+ label: "Globe",
2106
+ Icon: Globe
2107
+ },
2108
+ {
2109
+ id: "zap",
2110
+ label: "Zap",
2111
+ Icon: Zap
2112
+ },
2113
+ {
2114
+ id: "trending-up",
2115
+ label: "Trending Up",
2116
+ Icon: TrendingUp
2117
+ },
2118
+ {
2119
+ id: "bar-chart",
2120
+ label: "Bar Chart",
2121
+ Icon: ChartColumn
2122
+ },
2123
+ {
2124
+ id: "check-circle",
2125
+ label: "Check Circle",
2126
+ Icon: CircleCheck
2127
+ },
2128
+ {
2129
+ id: "x-circle",
2130
+ label: "X Circle",
2131
+ Icon: XCircle
2132
+ }
2133
+ ];
2134
+ const iconRegistry = new Map([...defaultIconEntries, ...extraIconEntries].map((entry) => [entry.id, entry]));
2135
+ const defaultIconRegistry = defaultIconEntries;
2136
+ /** Returns icon registry entry. */
2137
+ function getIconRegistryEntry(id) {
2138
+ return iconRegistry.get(id);
2139
+ }
2140
+ //#endregion
2141
+ //#region src/core/icon-picker.tsx
2142
+ const DEFAULT_ICONS = [...defaultIconRegistry.map(({ id, label, Icon, group }) => ({
2143
+ id,
2144
+ label,
2145
+ group,
2146
+ icon: /* @__PURE__ */ jsx(Icon, {})
2147
+ }))];
2148
+ function renderIconPreview(icon, options) {
2149
+ if (typeof icon === "string" || typeof icon === "number") return /* @__PURE__ */ jsx("span", {
2150
+ className: cn(options.textClassName, "leading-none"),
2151
+ "aria-hidden": true,
2152
+ children: icon
2153
+ });
2154
+ if (React.isValidElement(icon)) return React.cloneElement(icon, {
2155
+ "aria-hidden": true,
2156
+ className: cn(options.elementClassName, icon.props.className)
2157
+ });
2158
+ return /* @__PURE__ */ jsx("span", {
2159
+ className: cn("flex items-center justify-center", options.elementClassName),
2160
+ "aria-hidden": true,
2161
+ children: icon
2162
+ });
2163
+ }
2164
+ /** Renders the icon picker component. */
2165
+ function IconPicker({ value, onChange, icons = DEFAULT_ICONS, label, required, error, hint, placeholder = "Select icon", disabled = false, className, id, "aria-label": ariaLabel }) {
2166
+ var _useInputId, _ref;
2167
+ const [selected, setSelected] = useControlledState("", value, onChange);
2168
+ const fallbackId = React.useId().replace(/:/g, "");
2169
+ const pickerId = (_useInputId = useInputId(id, label, "icon-picker")) !== null && _useInputId !== void 0 ? _useInputId : `icon-picker-${fallbackId}`;
2170
+ const hasError = Boolean(error);
2171
+ const [search, setSearch] = React.useState("");
2172
+ const selectedIcon = React.useMemo(() => icons.find((i) => i.id === selected), [icons, selected]);
2173
+ const filteredIcons = React.useMemo(() => {
2174
+ if (!search) return icons;
2175
+ const q = search.toLowerCase();
2176
+ return icons.filter((i) => {
2177
+ var _i$group;
2178
+ return i.label.toLowerCase().includes(q) || i.id.toLowerCase().includes(q) || ((_i$group = i.group) === null || _i$group === void 0 ? void 0 : _i$group.toLowerCase().includes(q));
2179
+ });
2180
+ }, [icons, search]);
2181
+ const groups = React.useMemo(() => {
2182
+ const map = /* @__PURE__ */ new Map();
2183
+ for (const icon of filteredIcons) {
2184
+ var _icon$group;
2185
+ const group = (_icon$group = icon.group) !== null && _icon$group !== void 0 ? _icon$group : "Other";
2186
+ if (!map.has(group)) map.set(group, []);
2187
+ map.get(group).push(icon);
2188
+ }
2189
+ return map;
2190
+ }, [filteredIcons]);
2191
+ const handleSelect = React.useCallback((iconId) => {
2192
+ setSelected(iconId);
2193
+ }, [setSelected]);
2194
+ return /* @__PURE__ */ jsxs("div", {
2195
+ className: cn("flex flex-col gap-1.5", className),
2196
+ "data-opt-id": "0DRGP",
2197
+ "data-opt-slug": "icon-picker.IconPicker",
2198
+ children: [
2199
+ label && /* @__PURE__ */ jsxs("span", {
2200
+ className: "text-sm font-medium text-text-primary",
2201
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
2202
+ }),
2203
+ /* @__PURE__ */ jsxs(PopoverRoot$1, { children: [/* @__PURE__ */ jsx(PopoverTrigger$1, {
2204
+ id: pickerId,
2205
+ className: cn(OPT_INPUT, "cursor-pointer items-center gap-2", !selectedIcon && "text-text-tertiary", hasError && "border-danger focus-visible:outline-danger", disabled && "pointer-events-none opacity-50"),
2206
+ disabled,
2207
+ "aria-label": (_ref = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label) !== null && _ref !== void 0 ? _ref : "Icon picker",
2208
+ "aria-required": required,
2209
+ "aria-invalid": hasError,
2210
+ "aria-describedby": getDescribedBy(pickerId, error, hint),
2211
+ children: selectedIcon ? /* @__PURE__ */ jsxs(Fragment, { children: [renderIconPreview(selectedIcon.icon, {
2212
+ elementClassName: "size-5 shrink-0",
2213
+ textClassName: "text-lg"
2214
+ }), /* @__PURE__ */ jsx("span", {
2215
+ className: OPT_TEXT_PRIMARY,
2216
+ children: selectedIcon.label
2217
+ })] }) : /* @__PURE__ */ jsx("span", { children: placeholder })
2218
+ }), /* @__PURE__ */ jsxs(PopoverContent$1, {
2219
+ className: cn("bg-surface-overlay z-50 w-72 rounded-lg p-3 shadow-lg", OPT_BORDER),
2220
+ children: [/* @__PURE__ */ jsx("input", {
2221
+ type: "text",
2222
+ value: search,
2223
+ onChange: (e) => setSearch(e.target.value),
2224
+ placeholder: "Search icons...",
2225
+ className: cn("border-border bg-surface mb-2 w-full rounded-md border px-3 py-1.5 text-sm outline-transparent", OPT_TEXT_PRIMARY, "placeholder:text-text-tertiary", OPT_FOCUS_VISIBLE),
2226
+ "aria-label": "Search icons"
2227
+ }), /* @__PURE__ */ jsx("div", {
2228
+ className: "max-h-56 overflow-y-auto",
2229
+ children: filteredIcons.length === 0 ? /* @__PURE__ */ jsx("div", {
2230
+ className: cn(OPT_TEXT_SECONDARY, "py-4 text-center text-sm"),
2231
+ children: "No icons found"
2232
+ }) : Array.from(groups.entries()).map(([groupName, groupIcons]) => /* @__PURE__ */ jsxs("div", {
2233
+ className: "mb-2",
2234
+ children: [/* @__PURE__ */ jsx("span", {
2235
+ className: cn(OPT_TEXT_TERTIARY, "mb-1 block text-[10px] font-semibold tracking-wider uppercase"),
2236
+ children: groupName
2237
+ }), /* @__PURE__ */ jsx("div", {
2238
+ className: "grid grid-cols-6 gap-1",
2239
+ children: groupIcons.map((icon) => /* @__PURE__ */ jsx("button", {
2240
+ type: "button",
2241
+ onClick: () => handleSelect(icon.id),
2242
+ className: cn("flex h-9 w-9 items-center justify-center rounded-md text-lg transition-colors", OPT_FOCUS_VISIBLE, icon.id === selected ? "bg-accent-subtle ring-ring ring-2" : "hover:bg-bg-subtle"),
2243
+ title: icon.label,
2244
+ "aria-label": icon.label,
2245
+ "aria-selected": icon.id === selected || void 0,
2246
+ children: renderIconPreview(icon.icon, {
2247
+ elementClassName: "size-4",
2248
+ textClassName: "text-lg"
2249
+ })
2250
+ }, icon.id))
2251
+ })]
2252
+ }, groupName))
2253
+ })]
2254
+ })] }),
2255
+ /* @__PURE__ */ jsx(FieldMessages, {
2256
+ id: pickerId,
2257
+ error,
2258
+ hint
2259
+ })
2260
+ ]
2261
+ });
2262
+ }
2263
+ IconPicker.displayName = "IconPicker";
2264
+ //#endregion
2265
+ //#region src/core/tag-input.tsx
2266
+ const DEFAULT_DELIMITERS = [
2267
+ ",",
2268
+ ";",
2269
+ "\n"
2270
+ ];
2271
+ function splitByDelimiters(text, delimiters) {
2272
+ const pattern = delimiters.map((d) => d instanceof RegExp ? d.source : d.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
2273
+ return text.split(new RegExp(pattern)).map((s) => s.trim()).filter(Boolean);
2274
+ }
2275
+ const TagInput = forwardRef(({ value, onChange, placeholder = "Add tag...", label, required, error, hint, maxTags, disabled = false, className, id, "aria-label": ariaLabel, suggestions, delimiters = DEFAULT_DELIMITERS, allowDuplicates = false }, ref) => {
2276
+ var _useInputId, _ref, _ref2, _ref3, _ref4;
2277
+ const [tags, setTags] = useControlledState([], value, onChange);
2278
+ const fallbackId = useId().replace(/:/g, "");
2279
+ const tagInputId = (_useInputId = useInputId(id, label, "tag-input")) !== null && _useInputId !== void 0 ? _useInputId : `tag-input-${fallbackId}`;
2280
+ const hasError = Boolean(error);
2281
+ const describedBy = getDescribedBy(tagInputId, error, hint);
2282
+ const [inputValue, setInputValue] = useState("");
2283
+ const [highlightIndex, setHighlightIndex] = useState(-1);
2284
+ const [showSuggestions, setShowSuggestions] = useState(false);
2285
+ const innerRef = useRef(null);
2286
+ const inputRef = (_ref = ref) !== null && _ref !== void 0 ? _ref : innerRef;
2287
+ const listboxRef = useRef(null);
2288
+ const listboxId = useId();
2289
+ const undoStack = useRef([]);
2290
+ const redoStack = useRef([]);
2291
+ const tagRefs = useRef(/* @__PURE__ */ new Map());
2292
+ function pushUndo(prev) {
2293
+ undoStack.current.push(prev);
2294
+ redoStack.current = [];
2295
+ }
2296
+ const undo = useCallback(() => {
2297
+ if (undoStack.current.length === 0) return;
2298
+ const prev = undoStack.current.pop();
2299
+ redoStack.current.push([...tags]);
2300
+ setTags(prev);
2301
+ }, [tags, setTags]);
2302
+ const redo = useCallback(() => {
2303
+ if (redoStack.current.length === 0) return;
2304
+ const next = redoStack.current.pop();
2305
+ undoStack.current.push([...tags]);
2306
+ setTags(next);
2307
+ }, [tags, setTags]);
2308
+ const filtered = suggestions && inputValue.trim() ? suggestions.filter((s) => s.toLowerCase().includes(inputValue.trim().toLowerCase()) && (allowDuplicates || !tags.includes(s))) : [];
2309
+ const isOpen = showSuggestions && filtered.length > 0;
2310
+ useEffect(() => {
2311
+ setHighlightIndex(-1);
2312
+ }, [inputValue]);
2313
+ const addTag = useCallback((tag) => {
2314
+ const trimmed = tag.trim();
2315
+ if (!trimmed) return;
2316
+ if (!allowDuplicates && tags.includes(trimmed)) return;
2317
+ if (maxTags && tags.length >= maxTags) return;
2318
+ pushUndo([...tags]);
2319
+ setTags([...tags, trimmed]);
2320
+ setInputValue("");
2321
+ setShowSuggestions(false);
2322
+ }, [
2323
+ tags,
2324
+ setTags,
2325
+ maxTags,
2326
+ allowDuplicates
2327
+ ]);
2328
+ const removeTag = useCallback((index) => {
2329
+ pushUndo([...tags]);
2330
+ setTags(tags.filter((_, i) => i !== index));
2331
+ }, [tags, setTags]);
2332
+ const handleTagKeyDown = useCallback((e, index) => {
2333
+ if (e.key === "Backspace" || e.key === "Delete") {
2334
+ e.preventDefault();
2335
+ const nextTags = tags.filter((_, i) => i !== index);
2336
+ pushUndo([...tags]);
2337
+ setTags(nextTags);
2338
+ requestAnimationFrame(() => {
2339
+ if (nextTags.length === 0) {
2340
+ var _inputRef$current;
2341
+ (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.focus();
2342
+ } else if (index < nextTags.length) {
2343
+ var _tagRefs$current$get;
2344
+ (_tagRefs$current$get = tagRefs.current.get(index)) === null || _tagRefs$current$get === void 0 || _tagRefs$current$get.focus();
2345
+ } else {
2346
+ var _tagRefs$current$get2;
2347
+ (_tagRefs$current$get2 = tagRefs.current.get(nextTags.length - 1)) === null || _tagRefs$current$get2 === void 0 || _tagRefs$current$get2.focus();
2348
+ }
2349
+ });
2350
+ return;
2351
+ }
2352
+ if ((e.ctrlKey || e.metaKey) && e.key === "z" && !e.shiftKey) {
2353
+ e.preventDefault();
2354
+ undo();
2355
+ requestAnimationFrame(() => {
2356
+ var _inputRef$current2;
2357
+ return (_inputRef$current2 = inputRef.current) === null || _inputRef$current2 === void 0 ? void 0 : _inputRef$current2.focus();
2358
+ });
2359
+ return;
2360
+ }
2361
+ if ((e.ctrlKey || e.metaKey) && (e.key === "Z" || e.key === "z" && e.shiftKey || e.key === "y")) {
2362
+ e.preventDefault();
2363
+ redo();
2364
+ requestAnimationFrame(() => {
2365
+ var _inputRef$current3;
2366
+ return (_inputRef$current3 = inputRef.current) === null || _inputRef$current3 === void 0 ? void 0 : _inputRef$current3.focus();
2367
+ });
2368
+ return;
2369
+ }
2370
+ if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
2371
+ var _inputRef$current4;
2372
+ (_inputRef$current4 = inputRef.current) === null || _inputRef$current4 === void 0 || _inputRef$current4.focus();
2373
+ }
2374
+ }, [
2375
+ tags,
2376
+ setTags,
2377
+ undo,
2378
+ redo,
2379
+ inputRef
2380
+ ]);
2381
+ const handleInputKeyDown = useCallback((e) => {
2382
+ var _inputRef$current5;
2383
+ if ((e.ctrlKey || e.metaKey) && e.key === "z" && !e.shiftKey) {
2384
+ e.preventDefault();
2385
+ undo();
2386
+ return;
2387
+ }
2388
+ if ((e.ctrlKey || e.metaKey) && (e.key === "Z" || e.key === "z" && e.shiftKey || e.key === "y")) {
2389
+ e.preventDefault();
2390
+ redo();
2391
+ return;
2392
+ }
2393
+ if (isOpen) {
2394
+ if (e.key === "ArrowDown") {
2395
+ e.preventDefault();
2396
+ setHighlightIndex((prev) => prev < filtered.length - 1 ? prev + 1 : 0);
2397
+ return;
2398
+ }
2399
+ if (e.key === "ArrowUp") {
2400
+ e.preventDefault();
2401
+ setHighlightIndex((prev) => prev > 0 ? prev - 1 : filtered.length - 1);
2402
+ return;
2403
+ }
2404
+ if (e.key === "Enter" && highlightIndex >= 0) {
2405
+ e.preventDefault();
2406
+ addTag(filtered[highlightIndex]);
2407
+ return;
2408
+ }
2409
+ if (e.key === "Escape") {
2410
+ e.preventDefault();
2411
+ setShowSuggestions(false);
2412
+ return;
2413
+ }
2414
+ }
2415
+ if (e.key === "Enter") {
2416
+ e.preventDefault();
2417
+ addTag(inputValue);
2418
+ } else if (e.key === "Backspace" && inputValue === "" && tags.length > 0) removeTag(tags.length - 1);
2419
+ else if (e.key === "ArrowLeft" && ((_inputRef$current5 = inputRef.current) === null || _inputRef$current5 === void 0 ? void 0 : _inputRef$current5.selectionStart) === 0 && tags.length > 0) {
2420
+ var _tagRefs$current$get3;
2421
+ e.preventDefault();
2422
+ (_tagRefs$current$get3 = tagRefs.current.get(tags.length - 1)) === null || _tagRefs$current$get3 === void 0 || _tagRefs$current$get3.focus();
2423
+ }
2424
+ }, [
2425
+ inputValue,
2426
+ tags,
2427
+ addTag,
2428
+ removeTag,
2429
+ isOpen,
2430
+ highlightIndex,
2431
+ filtered,
2432
+ undo,
2433
+ redo,
2434
+ inputRef
2435
+ ]);
2436
+ const handlePaste = useCallback((e) => {
2437
+ const parts = splitByDelimiters(e.clipboardData.getData("text/plain"), delimiters);
2438
+ if (parts.length < 2) return;
2439
+ e.preventDefault();
2440
+ const prev = [...tags];
2441
+ let next = [...tags];
2442
+ const remaining = maxTags ? maxTags - next.length : Infinity;
2443
+ for (const part of parts.slice(0, remaining)) {
2444
+ if (!allowDuplicates && next.includes(part)) continue;
2445
+ next = [...next, part];
2446
+ }
2447
+ if (next.length !== prev.length) {
2448
+ pushUndo(prev);
2449
+ setTags(next);
2450
+ setInputValue("");
2451
+ }
2452
+ }, [
2453
+ tags,
2454
+ setTags,
2455
+ maxTags,
2456
+ delimiters,
2457
+ allowDuplicates
2458
+ ]);
2459
+ useEffect(() => {
2460
+ if (highlightIndex >= 0 && listboxRef.current) {
2461
+ var _el$scrollIntoView;
2462
+ const el = listboxRef.current.children[highlightIndex];
2463
+ el === null || el === void 0 || (_el$scrollIntoView = el.scrollIntoView) === null || _el$scrollIntoView === void 0 || _el$scrollIntoView.call(el, { block: "nearest" });
2464
+ }
2465
+ }, [highlightIndex]);
2466
+ const atLimit = Boolean(maxTags && tags.length >= maxTags);
2467
+ return /* @__PURE__ */ jsxs("div", {
2468
+ className: cn("relative flex flex-col gap-1.5", className),
2469
+ "data-opt-id": "3TDWF",
2470
+ "data-opt-slug": "tag-input.TagInput",
2471
+ children: [
2472
+ label && /* @__PURE__ */ jsxs("span", {
2473
+ className: "text-sm font-medium text-text-primary",
2474
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
2475
+ }),
2476
+ /* @__PURE__ */ jsxs("div", {
2477
+ className: cn("border-border bg-surface flex min-h-10 flex-wrap items-center gap-1.5 rounded-lg border px-3 py-1.5", "focus-within:ring-ring focus-within:ring-offset-ring-offset focus-within:ring-2 focus-within:ring-offset-1", hasError && "border-danger", disabled && "pointer-events-none opacity-50"),
2478
+ onMouseDown: () => {
2479
+ var _inputRef$current6;
2480
+ return (_inputRef$current6 = inputRef.current) === null || _inputRef$current6 === void 0 ? void 0 : _inputRef$current6.focus();
2481
+ },
2482
+ role: "group",
2483
+ "aria-label": (_ref2 = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label) !== null && _ref2 !== void 0 ? _ref2 : "Tag input",
2484
+ "aria-required": required,
2485
+ "aria-invalid": hasError,
2486
+ "aria-describedby": describedBy,
2487
+ children: [tags.length > 0 && /* @__PURE__ */ jsx(CompositeProvider, {
2488
+ focusLoop: true,
2489
+ children: /* @__PURE__ */ jsx(Composite, {
2490
+ "aria-label": "Selected tags",
2491
+ className: "contents",
2492
+ children: tags.map((tag, i) => /* @__PURE__ */ jsxs(CompositeItem, {
2493
+ render: /* @__PURE__ */ jsx("span", { ref: (el) => {
2494
+ if (el) tagRefs.current.set(i, el);
2495
+ else tagRefs.current.delete(i);
2496
+ } }),
2497
+ className: cn(OPT_BADGE_BLUE, "flex items-center gap-1 py-1", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset", "rounded-md"),
2498
+ onKeyDown: (e) => handleTagKeyDown(e, i),
2499
+ children: [tag, !disabled && /* @__PURE__ */ jsx("button", {
2500
+ type: "button",
2501
+ tabIndex: -1,
2502
+ onClick: (e) => {
2503
+ var _inputRef$current7;
2504
+ e.stopPropagation();
2505
+ removeTag(i);
2506
+ (_inputRef$current7 = inputRef.current) === null || _inputRef$current7 === void 0 || _inputRef$current7.focus();
2507
+ },
2508
+ className: "hover:bg-accent-subtle ml-0.5 rounded-full p-0.5",
2509
+ "aria-label": `Remove ${tag}`,
2510
+ children: /* @__PURE__ */ jsx("svg", {
2511
+ width: "10",
2512
+ height: "10",
2513
+ viewBox: "0 0 10 10",
2514
+ fill: "none",
2515
+ stroke: "currentColor",
2516
+ strokeWidth: "1.5",
2517
+ strokeLinecap: "round",
2518
+ children: /* @__PURE__ */ jsx("path", { d: "M2.5 2.5L7.5 7.5M7.5 2.5L2.5 7.5" })
2519
+ })
2520
+ })]
2521
+ }, `${tag}-${i}`))
2522
+ })
2523
+ }), /* @__PURE__ */ jsx("input", {
2524
+ ref: inputRef,
2525
+ type: "text",
2526
+ value: inputValue,
2527
+ onChange: (e) => {
2528
+ setInputValue(e.target.value);
2529
+ setShowSuggestions(true);
2530
+ },
2531
+ onKeyDown: handleInputKeyDown,
2532
+ onPaste: handlePaste,
2533
+ onFocus: () => setShowSuggestions(true),
2534
+ onBlur: () => {
2535
+ setTimeout(() => setShowSuggestions(false), 150);
2536
+ },
2537
+ placeholder: tags.length === 0 ? placeholder : atLimit ? "" : "",
2538
+ disabled: disabled || atLimit,
2539
+ className: cn("min-w-[60px] flex-1 border-none bg-transparent text-sm outline-transparent", OPT_TEXT_PRIMARY, OPT_FOCUS_VISIBLE, "placeholder:text-text-tertiary"),
2540
+ "aria-label": (_ref3 = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label) !== null && _ref3 !== void 0 ? _ref3 : "Tag input",
2541
+ role: suggestions ? "combobox" : void 0,
2542
+ "aria-describedby": describedBy,
2543
+ "aria-expanded": suggestions ? isOpen : void 0,
2544
+ "aria-controls": suggestions ? listboxId : void 0,
2545
+ "aria-activedescendant": isOpen && highlightIndex >= 0 ? `${listboxId}-${highlightIndex}` : void 0,
2546
+ "aria-autocomplete": suggestions ? "list" : void 0
2547
+ })]
2548
+ }),
2549
+ isOpen && /* @__PURE__ */ jsx("ul", {
2550
+ ref: listboxRef,
2551
+ id: listboxId,
2552
+ role: "listbox",
2553
+ "aria-label": (_ref4 = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label) !== null && _ref4 !== void 0 ? _ref4 : "Tag suggestions",
2554
+ className: "border-border bg-surface absolute top-full z-50 mt-1 max-h-48 w-full overflow-auto rounded-lg border shadow-md",
2555
+ children: filtered.map((suggestion, i) => /* @__PURE__ */ jsx("li", {
2556
+ id: `${listboxId}-${i}`,
2557
+ role: "option",
2558
+ "aria-selected": i === highlightIndex,
2559
+ className: cn("cursor-pointer px-3 py-1.5 text-sm", "text-text-primary", i === highlightIndex && "bg-accent-subtle"),
2560
+ onMouseDown: (e) => {
2561
+ e.preventDefault();
2562
+ addTag(suggestion);
2563
+ },
2564
+ onMouseEnter: () => setHighlightIndex(i),
2565
+ children: suggestion
2566
+ }, suggestion))
2567
+ }),
2568
+ maxTags && /* @__PURE__ */ jsxs("span", {
2569
+ className: "text-text-tertiary text-xs",
2570
+ children: [
2571
+ tags.length,
2572
+ "/",
2573
+ maxTags
2574
+ ]
2575
+ }),
2576
+ /* @__PURE__ */ jsx(FieldMessages, {
2577
+ id: tagInputId,
2578
+ error,
2579
+ hint
2580
+ })
2581
+ ]
2582
+ });
2583
+ });
2584
+ TagInput.displayName = "TagInput";
2585
+ //#endregion
2586
+ //#region src/core/date-range-picker.tsx
2587
+ const DAYS = [
2588
+ "Su",
2589
+ "Mo",
2590
+ "Tu",
2591
+ "We",
2592
+ "Th",
2593
+ "Fr",
2594
+ "Sa"
2595
+ ];
2596
+ function defaultFormat(date) {
2597
+ return date.toLocaleDateString("en-US", {
2598
+ year: "numeric",
2599
+ month: "short",
2600
+ day: "numeric"
2601
+ });
2602
+ }
2603
+ function isSameDay(a, b) {
2604
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
2605
+ }
2606
+ function isInRange(date, start, end) {
2607
+ if (!start || !end) return false;
2608
+ const t = date.getTime();
2609
+ return t >= start.getTime() && t <= end.getTime();
2610
+ }
2611
+ function getDaysInMonth(year, month) {
2612
+ return new Date(year, month + 1, 0).getDate();
2613
+ }
2614
+ function getFirstDayOfMonth(year, month) {
2615
+ return new Date(year, month, 1).getDay();
2616
+ }
2617
+ function startOfDay(date) {
2618
+ const normalized = new Date(date);
2619
+ normalized.setHours(0, 0, 0, 0);
2620
+ return normalized;
2621
+ }
2622
+ function getDateKey(date) {
2623
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
2624
+ }
2625
+ function createDateInMonth(year, month, day) {
2626
+ return startOfDay(new Date(year, month, Math.min(day, getDaysInMonth(year, month))));
2627
+ }
2628
+ const DEFAULT_PRESETS = [
2629
+ {
2630
+ label: "Today",
2631
+ range: () => {
2632
+ const now = /* @__PURE__ */ new Date();
2633
+ now.setHours(0, 0, 0, 0);
2634
+ return {
2635
+ start: now,
2636
+ end: new Date(now)
2637
+ };
2638
+ }
2639
+ },
2640
+ {
2641
+ label: "Last 7 days",
2642
+ range: () => {
2643
+ const end = /* @__PURE__ */ new Date();
2644
+ end.setHours(0, 0, 0, 0);
2645
+ const start = new Date(end);
2646
+ start.setDate(start.getDate() - 6);
2647
+ return {
2648
+ start,
2649
+ end
2650
+ };
2651
+ }
2652
+ },
2653
+ {
2654
+ label: "Last 30 days",
2655
+ range: () => {
2656
+ const end = /* @__PURE__ */ new Date();
2657
+ end.setHours(0, 0, 0, 0);
2658
+ const start = new Date(end);
2659
+ start.setDate(start.getDate() - 29);
2660
+ return {
2661
+ start,
2662
+ end
2663
+ };
2664
+ }
2665
+ },
2666
+ {
2667
+ label: "Last 90 days",
2668
+ range: () => {
2669
+ const end = /* @__PURE__ */ new Date();
2670
+ end.setHours(0, 0, 0, 0);
2671
+ const start = new Date(end);
2672
+ start.setDate(start.getDate() - 89);
2673
+ return {
2674
+ start,
2675
+ end
2676
+ };
2677
+ }
2678
+ },
2679
+ {
2680
+ label: "This month",
2681
+ range: () => {
2682
+ const now = /* @__PURE__ */ new Date();
2683
+ now.setHours(0, 0, 0, 0);
2684
+ return {
2685
+ start: new Date(now.getFullYear(), now.getMonth(), 1),
2686
+ end: now
2687
+ };
2688
+ }
2689
+ },
2690
+ {
2691
+ label: "Last month",
2692
+ range: () => {
2693
+ const now = /* @__PURE__ */ new Date();
2694
+ return {
2695
+ start: new Date(now.getFullYear(), now.getMonth() - 1, 1),
2696
+ end: new Date(now.getFullYear(), now.getMonth(), 0)
2697
+ };
2698
+ }
2699
+ }
2700
+ ];
2701
+ const GRANULARITY_OPTIONS = [
2702
+ {
2703
+ value: "hour",
2704
+ label: "Hour"
2705
+ },
2706
+ {
2707
+ value: "day",
2708
+ label: "Day"
2709
+ },
2710
+ {
2711
+ value: "week",
2712
+ label: "Week"
2713
+ },
2714
+ {
2715
+ value: "month",
2716
+ label: "Month"
2717
+ }
2718
+ ];
2719
+ const COMPARISON_OPTIONS = [{
2720
+ value: "previous",
2721
+ label: "vs Previous period"
2722
+ }, {
2723
+ value: "year-over-year",
2724
+ label: "vs Same period last year"
2725
+ }];
2726
+ /** Renders the date range picker component. */
2727
+ function DateRangePicker({ value, onChange, presets = DEFAULT_PRESETS, placeholder = "Select date range", label, required, error, hint, className, id, triggerClassName, "aria-label": ariaLabel, disabled = false, format = defaultFormat, comparison = false, comparisonMode, onComparisonChange, showGranularity = false, granularity, onGranularityChange }) {
2728
+ var _useInputId, _ref3;
2729
+ const fallbackId = useId().replace(/:/g, "");
2730
+ const pickerId = (_useInputId = useInputId(id, label, "date-range-picker")) !== null && _useInputId !== void 0 ? _useInputId : `date-range-picker-${fallbackId}`;
2731
+ const hasError = Boolean(error);
2732
+ const [range, setRange] = useControlledState({
2733
+ start: null,
2734
+ end: null
2735
+ }, value, onChange);
2736
+ const [selecting, setSelecting] = useState("start");
2737
+ const [viewDate, setViewDate] = useState(() => {
2738
+ var _range$start;
2739
+ const d = (_range$start = range.start) !== null && _range$start !== void 0 ? _range$start : /* @__PURE__ */ new Date();
2740
+ return {
2741
+ year: d.getFullYear(),
2742
+ month: d.getMonth()
2743
+ };
2744
+ });
2745
+ const [focusedDate, setFocusedDate] = useState(() => {
2746
+ var _ref, _range$start2;
2747
+ return startOfDay((_ref = (_range$start2 = range.start) !== null && _range$start2 !== void 0 ? _range$start2 : range.end) !== null && _ref !== void 0 ? _ref : /* @__PURE__ */ new Date());
2748
+ });
2749
+ const dayButtonRefs = useRef({});
2750
+ const granularityButtonRefs = useRef({
2751
+ hour: null,
2752
+ day: null,
2753
+ week: null,
2754
+ month: null
2755
+ });
2756
+ const pendingFocusDateRef = useRef(null);
2757
+ const displayText = useMemo(() => {
2758
+ if (range.start && range.end) return `${format(range.start)} — ${format(range.end)}`;
2759
+ if (range.start) return `${format(range.start)} — ...`;
2760
+ return placeholder;
2761
+ }, [
2762
+ range,
2763
+ format,
2764
+ placeholder
2765
+ ]);
2766
+ const handleDayClick = useCallback((day) => {
2767
+ setFocusedDate(day);
2768
+ if (selecting === "start") {
2769
+ setRange({
2770
+ start: day,
2771
+ end: null
2772
+ });
2773
+ setSelecting("end");
2774
+ } else {
2775
+ if (range.start && day.getTime() < range.start.getTime()) setRange({
2776
+ start: day,
2777
+ end: range.start
2778
+ });
2779
+ else setRange({
2780
+ start: range.start,
2781
+ end: day
2782
+ });
2783
+ setSelecting("start");
2784
+ }
2785
+ }, [
2786
+ selecting,
2787
+ range.start,
2788
+ setRange
2789
+ ]);
2790
+ const handlePresetClick = useCallback((preset) => {
2791
+ var _ref2, _newRange$start;
2792
+ const newRange = preset.range();
2793
+ const nextFocusDate = startOfDay((_ref2 = (_newRange$start = newRange.start) !== null && _newRange$start !== void 0 ? _newRange$start : newRange.end) !== null && _ref2 !== void 0 ? _ref2 : /* @__PURE__ */ new Date());
2794
+ setRange(newRange);
2795
+ setViewDate({
2796
+ year: nextFocusDate.getFullYear(),
2797
+ month: nextFocusDate.getMonth()
2798
+ });
2799
+ setFocusedDate(nextFocusDate);
2800
+ setSelecting("start");
2801
+ }, [setRange]);
2802
+ const moveFocusToDate = useCallback((date) => {
2803
+ const nextDate = startOfDay(date);
2804
+ pendingFocusDateRef.current = nextDate;
2805
+ setViewDate({
2806
+ year: nextDate.getFullYear(),
2807
+ month: nextDate.getMonth()
2808
+ });
2809
+ setFocusedDate(nextDate);
2810
+ }, []);
2811
+ const prevMonth = useCallback(() => {
2812
+ setViewDate((v) => {
2813
+ const m = v.month - 1;
2814
+ const nextViewDate = m < 0 ? {
2815
+ year: v.year - 1,
2816
+ month: 11
2817
+ } : {
2818
+ year: v.year,
2819
+ month: m
2820
+ };
2821
+ setFocusedDate((currentFocusedDate) => createDateInMonth(nextViewDate.year, nextViewDate.month, currentFocusedDate.getDate()));
2822
+ return nextViewDate;
2823
+ });
2824
+ }, []);
2825
+ const nextMonth = useCallback(() => {
2826
+ setViewDate((v) => {
2827
+ const m = v.month + 1;
2828
+ const nextViewDate = m > 11 ? {
2829
+ year: v.year + 1,
2830
+ month: 0
2831
+ } : {
2832
+ year: v.year,
2833
+ month: m
2834
+ };
2835
+ setFocusedDate((currentFocusedDate) => createDateInMonth(nextViewDate.year, nextViewDate.month, currentFocusedDate.getDate()));
2836
+ return nextViewDate;
2837
+ });
2838
+ }, []);
2839
+ const { daysInMonth, firstDay, monthLabel } = useMemo(() => {
2840
+ return {
2841
+ daysInMonth: getDaysInMonth(viewDate.year, viewDate.month),
2842
+ firstDay: getFirstDayOfMonth(viewDate.year, viewDate.month),
2843
+ monthLabel: new Date(viewDate.year, viewDate.month).toLocaleDateString("en-US", {
2844
+ month: "long",
2845
+ year: "numeric"
2846
+ })
2847
+ };
2848
+ }, [viewDate.year, viewDate.month]);
2849
+ const today = useMemo(() => {
2850
+ const d = /* @__PURE__ */ new Date();
2851
+ d.setHours(0, 0, 0, 0);
2852
+ return d;
2853
+ }, []);
2854
+ const calendarWeeks = useMemo(() => {
2855
+ const leadingDays = Array.from({ length: firstDay }, () => null);
2856
+ const monthDays = Array.from({ length: daysInMonth }, (_, index) => startOfDay(new Date(viewDate.year, viewDate.month, index + 1)));
2857
+ const trailingDays = Array.from({ length: (7 - ((leadingDays.length + monthDays.length) % 7 || 7)) % 7 }, () => null);
2858
+ const cells = [
2859
+ ...leadingDays,
2860
+ ...monthDays,
2861
+ ...trailingDays
2862
+ ];
2863
+ return Array.from({ length: cells.length / 7 }, (_, rowIndex) => cells.slice(rowIndex * 7, rowIndex * 7 + 7));
2864
+ }, [
2865
+ daysInMonth,
2866
+ firstDay,
2867
+ viewDate.month,
2868
+ viewDate.year
2869
+ ]);
2870
+ const handleDayKeyDown = useCallback((event, day) => {
2871
+ const nextDateFactory = {
2872
+ ArrowLeft: () => startOfDay(new Date(day.getFullYear(), day.getMonth(), day.getDate() - 1)),
2873
+ ArrowRight: () => startOfDay(new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1)),
2874
+ ArrowUp: () => startOfDay(new Date(day.getFullYear(), day.getMonth(), day.getDate() - 7)),
2875
+ ArrowDown: () => startOfDay(new Date(day.getFullYear(), day.getMonth(), day.getDate() + 7)),
2876
+ Home: () => startOfDay(new Date(day.getFullYear(), day.getMonth(), day.getDate() - day.getDay())),
2877
+ End: () => startOfDay(new Date(day.getFullYear(), day.getMonth(), day.getDate() + (6 - day.getDay()))),
2878
+ PageUp: () => createDateInMonth(day.getFullYear(), day.getMonth() - 1, day.getDate()),
2879
+ PageDown: () => createDateInMonth(day.getFullYear(), day.getMonth() + 1, day.getDate())
2880
+ }[event.key];
2881
+ if (!nextDateFactory) return;
2882
+ event.preventDefault();
2883
+ moveFocusToDate(nextDateFactory());
2884
+ }, [moveFocusToDate]);
2885
+ const handleGranularityKeyDown = useCallback((event, currentValue) => {
2886
+ const currentIndex = GRANULARITY_OPTIONS.findIndex((opt) => opt.value === currentValue);
2887
+ if (currentIndex < 0) return;
2888
+ let nextIndex = -1;
2889
+ switch (event.key) {
2890
+ case "ArrowRight":
2891
+ case "ArrowDown":
2892
+ nextIndex = (currentIndex + 1) % GRANULARITY_OPTIONS.length;
2893
+ break;
2894
+ case "ArrowLeft":
2895
+ case "ArrowUp":
2896
+ nextIndex = (currentIndex - 1 + GRANULARITY_OPTIONS.length) % GRANULARITY_OPTIONS.length;
2897
+ break;
2898
+ case "Home":
2899
+ nextIndex = 0;
2900
+ break;
2901
+ case "End":
2902
+ nextIndex = GRANULARITY_OPTIONS.length - 1;
2903
+ break;
2904
+ default: return;
2905
+ }
2906
+ event.preventDefault();
2907
+ const nextValue = GRANULARITY_OPTIONS[nextIndex].value;
2908
+ onGranularityChange === null || onGranularityChange === void 0 || onGranularityChange(nextValue);
2909
+ requestAnimationFrame(() => {
2910
+ var _granularityButtonRef;
2911
+ (_granularityButtonRef = granularityButtonRefs.current[nextValue]) === null || _granularityButtonRef === void 0 || _granularityButtonRef.focus();
2912
+ });
2913
+ }, [onGranularityChange]);
2914
+ useEffect(() => {
2915
+ var _dayButtonRefs$curren;
2916
+ if (!pendingFocusDateRef.current) return;
2917
+ const button = (_dayButtonRefs$curren = dayButtonRefs.current[getDateKey(pendingFocusDateRef.current)]) !== null && _dayButtonRefs$curren !== void 0 ? _dayButtonRefs$curren : null;
2918
+ if (!button) return;
2919
+ button.focus();
2920
+ pendingFocusDateRef.current = null;
2921
+ }, [
2922
+ calendarWeeks,
2923
+ focusedDate,
2924
+ monthLabel
2925
+ ]);
2926
+ return /* @__PURE__ */ jsxs("div", {
2927
+ className: cn("flex flex-col gap-1.5", className),
2928
+ "data-opt-id": "0KKZ0",
2929
+ "data-opt-slug": "date-range-picker.DateRangePicker",
2930
+ children: [
2931
+ label && /* @__PURE__ */ jsxs("span", {
2932
+ className: "text-text-primary text-sm font-medium",
2933
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
2934
+ }),
2935
+ /* @__PURE__ */ jsxs(PopoverRoot$1, { children: [/* @__PURE__ */ jsxs(PopoverTrigger$1, {
2936
+ id: pickerId,
2937
+ className: cn(triggerClassName !== null && triggerClassName !== void 0 ? triggerClassName : OPT_INPUT, "cursor-pointer justify-between gap-2 text-left", !range.start && "text-text-tertiary", hasError && "border-danger focus-visible:outline-danger", disabled && "pointer-events-none opacity-50"),
2938
+ disabled,
2939
+ "aria-label": (_ref3 = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : label) !== null && _ref3 !== void 0 ? _ref3 : "Date range picker",
2940
+ "aria-required": required,
2941
+ "aria-invalid": hasError,
2942
+ "aria-describedby": getDescribedBy(pickerId, error, hint),
2943
+ children: [/* @__PURE__ */ jsx("span", {
2944
+ className: "truncate",
2945
+ children: displayText
2946
+ }), /* @__PURE__ */ jsx(CalendarDays, {
2947
+ "aria-hidden": "true",
2948
+ className: "text-text-tertiary size-4 shrink-0"
2949
+ })]
2950
+ }), /* @__PURE__ */ jsxs(PopoverContent$1, {
2951
+ className: cn("bg-surface-overlay z-50 rounded-lg p-4 shadow-lg", OPT_BORDER),
2952
+ children: [/* @__PURE__ */ jsxs("div", {
2953
+ className: "flex gap-4",
2954
+ children: [presets.length > 0 && /* @__PURE__ */ jsxs("div", {
2955
+ className: "border-border-subtle flex flex-col gap-1 border-r pr-4",
2956
+ children: [/* @__PURE__ */ jsx("span", {
2957
+ className: cn("text-text-secondary", "mb-1 text-xs font-semibold tracking-wider uppercase"),
2958
+ children: "Presets"
2959
+ }), presets.map((preset) => /* @__PURE__ */ jsx("button", {
2960
+ type: "button",
2961
+ onClick: () => handlePresetClick(preset),
2962
+ className: cn("rounded-md px-3 py-1.5 text-left text-sm", "text-text-primary", "hover:bg-accent-subtle", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset"),
2963
+ children: preset.label
2964
+ }, preset.label))]
2965
+ }), /* @__PURE__ */ jsxs("div", {
2966
+ className: "flex flex-col gap-2",
2967
+ children: [/* @__PURE__ */ jsxs("div", {
2968
+ className: "flex items-center justify-between",
2969
+ children: [
2970
+ /* @__PURE__ */ jsx("button", {
2971
+ type: "button",
2972
+ onClick: prevMonth,
2973
+ className: cn("rounded-md p-1", OPT_TEXT_SECONDARY, "hover:bg-bg-subtle", OPT_FOCUS_VISIBLE),
2974
+ "aria-label": "Previous month",
2975
+ children: /* @__PURE__ */ jsx(ChevronLeft, {
2976
+ "aria-hidden": "true",
2977
+ className: "size-4 rtl:-scale-x-100"
2978
+ })
2979
+ }),
2980
+ /* @__PURE__ */ jsx("span", {
2981
+ className: cn(OPT_TEXT_PRIMARY, "text-sm font-medium"),
2982
+ children: monthLabel
2983
+ }),
2984
+ /* @__PURE__ */ jsx("button", {
2985
+ type: "button",
2986
+ onClick: nextMonth,
2987
+ className: cn("rounded-md p-1", OPT_TEXT_SECONDARY, "hover:bg-bg-subtle", OPT_FOCUS_VISIBLE),
2988
+ "aria-label": "Next month",
2989
+ children: /* @__PURE__ */ jsx(ChevronRight, {
2990
+ "aria-hidden": "true",
2991
+ className: "size-4 rtl:-scale-x-100"
2992
+ })
2993
+ })
2994
+ ]
2995
+ }), /* @__PURE__ */ jsxs("div", {
2996
+ className: "flex flex-col gap-0",
2997
+ role: "grid",
2998
+ "aria-label": monthLabel,
2999
+ children: [/* @__PURE__ */ jsx("div", {
3000
+ className: "grid grid-cols-7 gap-0",
3001
+ role: "row",
3002
+ children: DAYS.map((d) => /* @__PURE__ */ jsx("div", {
3003
+ className: cn(OPT_TEXT_TERTIARY, "flex h-8 w-8 items-center justify-center text-xs font-medium"),
3004
+ role: "columnheader",
3005
+ children: d
3006
+ }, d))
3007
+ }), calendarWeeks.map((week, weekIndex) => /* @__PURE__ */ jsx("div", {
3008
+ className: "grid grid-cols-7 gap-0",
3009
+ role: "row",
3010
+ children: week.map((day, dayIndex) => {
3011
+ if (!day) return /* @__PURE__ */ jsx("div", {
3012
+ className: "h-8 w-8",
3013
+ role: "gridcell",
3014
+ "aria-hidden": "true"
3015
+ }, `${monthLabel}-empty-${weekIndex + 1}-${dayIndex + 1}`);
3016
+ const isToday = isSameDay(day, today);
3017
+ const isSelected = range.start && isSameDay(day, range.start) || range.end && isSameDay(day, range.end);
3018
+ const inRange = isInRange(day, range.start, range.end);
3019
+ const isFocused = isSameDay(day, focusedDate);
3020
+ const dayLabel = day.toLocaleDateString("en-US", {
3021
+ weekday: "long",
3022
+ year: "numeric",
3023
+ month: "long",
3024
+ day: "numeric"
3025
+ });
3026
+ const dateKey = getDateKey(day);
3027
+ return /* @__PURE__ */ jsx("div", {
3028
+ role: "gridcell",
3029
+ "aria-selected": isSelected || void 0,
3030
+ className: "flex h-8 w-8 items-center justify-center",
3031
+ children: /* @__PURE__ */ jsx("button", {
3032
+ ref: (node) => {
3033
+ dayButtonRefs.current[dateKey] = node;
3034
+ },
3035
+ type: "button",
3036
+ onClick: () => handleDayClick(day),
3037
+ onFocus: () => setFocusedDate(day),
3038
+ onKeyDown: (event) => handleDayKeyDown(event, day),
3039
+ tabIndex: isFocused ? 0 : -1,
3040
+ className: cn("flex h-8 w-8 items-center justify-center rounded-md text-sm", OPT_FOCUS_VISIBLE, isSelected && "bg-accent text-accent-fg font-medium", !isSelected && inRange && "bg-accent-subtle text-accent-fg", !isSelected && !inRange && "text-text-primary hover:bg-bg-subtle", isToday && !isSelected && "decoration-accent font-semibold underline underline-offset-2"),
3041
+ "aria-label": dayLabel,
3042
+ "aria-current": isToday ? "date" : void 0,
3043
+ children: day.getDate()
3044
+ })
3045
+ }, dateKey);
3046
+ })
3047
+ }, `${monthLabel}-week-${weekIndex + 1}`))]
3048
+ })]
3049
+ })]
3050
+ }), (showGranularity || comparison) && /* @__PURE__ */ jsxs("div", {
3051
+ className: "border-border-subtle mt-3 flex flex-wrap items-center gap-3 border-t pt-3",
3052
+ children: [showGranularity && /* @__PURE__ */ jsxs("div", {
3053
+ className: "flex items-center gap-1.5",
3054
+ role: "radiogroup",
3055
+ "aria-label": "Time granularity",
3056
+ children: [/* @__PURE__ */ jsx("span", {
3057
+ className: cn("text-text-secondary", "text-xs font-medium"),
3058
+ children: "Granularity"
3059
+ }), GRANULARITY_OPTIONS.map((opt) => /* @__PURE__ */ jsx("button", {
3060
+ ref: (node) => {
3061
+ granularityButtonRefs.current[opt.value] = node;
3062
+ },
3063
+ type: "button",
3064
+ role: "radio",
3065
+ "aria-checked": granularity === opt.value,
3066
+ onKeyDown: (event) => handleGranularityKeyDown(event, opt.value),
3067
+ onClick: () => onGranularityChange === null || onGranularityChange === void 0 ? void 0 : onGranularityChange(opt.value),
3068
+ className: cn("rounded-md px-2 py-1 text-xs", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset", granularity === opt.value ? "bg-accent text-accent-fg font-medium" : cn("text-text-primary", "hover:bg-bg-subtle")),
3069
+ children: opt.label
3070
+ }, opt.value))]
3071
+ }), comparison && /* @__PURE__ */ jsxs("div", {
3072
+ className: "flex items-center gap-1.5",
3073
+ role: "group",
3074
+ "aria-label": "Comparison mode",
3075
+ children: [/* @__PURE__ */ jsx("span", {
3076
+ className: cn("text-text-secondary", "text-xs font-medium"),
3077
+ children: "Compare"
3078
+ }), COMPARISON_OPTIONS.map((opt) => /* @__PURE__ */ jsx("button", {
3079
+ type: "button",
3080
+ "aria-pressed": comparisonMode === opt.value,
3081
+ onClick: () => onComparisonChange === null || onComparisonChange === void 0 ? void 0 : onComparisonChange(comparisonMode === opt.value ? null : opt.value),
3082
+ className: cn("rounded-md px-2 py-1 text-xs", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset", comparisonMode === opt.value ? "bg-accent text-accent-fg font-medium" : cn("text-text-primary", "hover:bg-bg-subtle")),
3083
+ children: opt.label
3084
+ }, opt.value))]
3085
+ })]
3086
+ })]
3087
+ })] }),
3088
+ /* @__PURE__ */ jsx(FieldMessages, {
3089
+ id: pickerId,
3090
+ error,
3091
+ hint
3092
+ })
3093
+ ]
3094
+ });
3095
+ }
3096
+ DateRangePicker.displayName = "DateRangePicker";
3097
+ //#endregion
3098
+ //#region src/core/form.tsx
3099
+ const _excluded$2 = ["className", "store"];
3100
+ const _excluded2 = ["className"];
3101
+ const _excluded3 = [
3102
+ "className",
3103
+ "resize",
3104
+ "rows",
3105
+ "name"
3106
+ ];
3107
+ const _excluded4 = ["className"];
3108
+ const _excluded5 = ["className"];
3109
+ const _excluded6 = [
3110
+ "className",
3111
+ "size",
3112
+ "name"
3113
+ ];
3114
+ const _excluded7 = ["className"];
3115
+ const _excluded8 = ["className"];
3116
+ const _excluded9 = [
3117
+ "className",
3118
+ "disabled",
3119
+ "children"
3120
+ ];
3121
+ const _excluded10 = ["className"];
3122
+ const _excluded11 = ["className"];
3123
+ const _excluded12 = ["className"];
3124
+ const _excluded13 = ["className"];
3125
+ const _excluded14 = ["className"];
3126
+ const _excluded15 = ["className"];
3127
+ const _excluded16 = ["className"];
3128
+ const _excluded17 = ["className"];
3129
+ const _excluded18 = ["className"];
3130
+ const _excluded19 = ["className"];
3131
+ const _excluded20 = ["className"];
3132
+ const _excluded21 = ["name"];
3133
+ const _excluded22 = ["name"];
3134
+ const _excluded23 = ["name"];
3135
+ const _excluded24 = ["name"];
3136
+ const _excluded25 = ["name"];
3137
+ const _excluded26 = ["name"];
3138
+ const _excluded27 = ["name"];
3139
+ const inputClass = `${OPT_INPUT} aria-[invalid=true]:border-danger`;
3140
+ const labelClass = OPT_TEXT_LABEL;
3141
+ const descriptionClass = "text-xs text-text-tertiary";
3142
+ const errorClass = "text-xs text-danger-fg";
3143
+ const submitClass = OPT_BUTTON_PRIMARY;
3144
+ const checkboxClass = `h-4 w-4 rounded accent-accent ${OPT_FOCUS_VISIBLE}`;
3145
+ const radioClass = `h-4 w-4 accent-accent ${OPT_FOCUS_VISIBLE}`;
3146
+ function useRequiredFormContext(componentName) {
3147
+ const form = useFormContext();
3148
+ if (!form) throw new Error(`${componentName} must be used within FormRoot or FormProvider with a store.`);
3149
+ return form;
3150
+ }
3151
+ /** Renders the form root component. */
3152
+ function FormRoot$1(_ref) {
3153
+ let { className, store } = _ref, props = _objectWithoutProperties(_ref, _excluded$2);
3154
+ const form = /* @__PURE__ */ jsx(FormRoot, _objectSpread2({ className: cn("gap-section flex flex-col", className) }, props));
3155
+ if (store) return /* @__PURE__ */ jsx(FormProvider, {
3156
+ store,
3157
+ "data-opt-id": "YBT1H",
3158
+ "data-opt-slug": "form.FormRoot",
3159
+ children: form
3160
+ });
3161
+ return form;
3162
+ }
3163
+ /** Renders the form input component. */
3164
+ function FormInput$1(_ref2) {
3165
+ let { className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2);
3166
+ return /* @__PURE__ */ jsx(FormInput, _objectSpread2(_objectSpread2({ className: cn(inputClass, className) }, props), {}, {
3167
+ "data-opt-id": "D7Z8F",
3168
+ "data-opt-slug": "form.FormInput"
3169
+ }));
3170
+ }
3171
+ const resizeStyles = {
3172
+ none: "resize-none",
3173
+ vertical: "resize-y",
3174
+ horizontal: "resize-x",
3175
+ both: "resize"
3176
+ };
3177
+ /** Renders the form textarea component. */
3178
+ function FormTextarea(_ref3) {
3179
+ var _ref4;
3180
+ let { className, resize = "vertical", rows = 4, name } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3);
3181
+ const form = useRequiredFormContext("FormTextarea");
3182
+ const value = (_ref4 = useFieldValue(form, name)) !== null && _ref4 !== void 0 ? _ref4 : "";
3183
+ const error = form === null || form === void 0 ? void 0 : form.getError(name);
3184
+ const touched = form === null || form === void 0 ? void 0 : form.getFieldTouched(name);
3185
+ const hasError = Boolean(error && touched);
3186
+ return /* @__PURE__ */ jsx("textarea", _objectSpread2(_objectSpread2({
3187
+ name,
3188
+ value,
3189
+ onChange: (e) => form === null || form === void 0 ? void 0 : form.setValue(name, e.target.value),
3190
+ className: cn("border-border bg-surface flex w-full rounded-lg border px-4 py-3", "text-text-primary placeholder:text-text-tertiary focus-visible:ring-ring focus-visible:ring-offset-ring-offset text-sm outline-none focus-visible:ring-2 focus-visible:ring-offset-1", OPT_FOCUS_VISIBLE, resizeStyles[resize], hasError && "border-danger", className),
3191
+ rows,
3192
+ "aria-invalid": hasError || void 0
3193
+ }, props), {}, {
3194
+ "data-opt-id": "Q8G2A",
3195
+ "data-opt-slug": "form.FormTextarea"
3196
+ }));
3197
+ }
3198
+ /** Renders the form select component. */
3199
+ function FormSelect({ name, children, className, placeholder, minWidth = 140, "aria-label": ariaLabel }) {
3200
+ var _ref5;
3201
+ const form = useRequiredFormContext("FormSelect");
3202
+ const value = (_ref5 = useFieldValue(form, name)) !== null && _ref5 !== void 0 ? _ref5 : "";
3203
+ const error = form === null || form === void 0 ? void 0 : form.getError(name);
3204
+ const touched = form === null || form === void 0 ? void 0 : form.getFieldTouched(name);
3205
+ const hasError = Boolean(error && touched);
3206
+ const handleSetValue = useCallback((v) => {
3207
+ var _v$;
3208
+ return form.setValue(name, Array.isArray(v) ? (_v$ = v[0]) !== null && _v$ !== void 0 ? _v$ : "" : v);
3209
+ }, [form, name]);
3210
+ return /* @__PURE__ */ jsxs(SelectRoot$1, {
3211
+ value,
3212
+ onValueChange: handleSetValue,
3213
+ "data-opt-id": "A2XF7",
3214
+ "data-opt-slug": "form.FormSelect",
3215
+ children: [/* @__PURE__ */ jsx(SelectTrigger$1, {
3216
+ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : name,
3217
+ "aria-invalid": hasError || void 0,
3218
+ className: cn("inline-flex cursor-pointer items-center justify-between data-[disabled]:cursor-not-allowed", hasError && "border-danger", className),
3219
+ style: { minWidth: typeof minWidth === "number" ? `${minWidth}px` : minWidth },
3220
+ children: value || placeholder || "Select…"
3221
+ }), children]
3222
+ });
3223
+ }
3224
+ /** Renders the form select popover component. */
3225
+ function FormSelectPopover(_ref6) {
3226
+ let { className } = _ref6, props = _objectWithoutProperties(_ref6, _excluded4);
3227
+ return /* @__PURE__ */ jsx(SelectPopover$1, _objectSpread2(_objectSpread2({ className: cn(OPT_SURFACE_POPOVER, OPT_ANIMATE_ENTER_EXIT, "z-[120]", className) }, props), {}, {
3228
+ "data-opt-id": "CQSPJ",
3229
+ "data-opt-slug": "form.FormSelectPopover"
3230
+ }));
3231
+ }
3232
+ /** Renders the form select item component. */
3233
+ function FormSelectItem(_ref7) {
3234
+ let { className } = _ref7, props = _objectWithoutProperties(_ref7, _excluded5);
3235
+ return /* @__PURE__ */ jsx(SelectItem$1, _objectSpread2(_objectSpread2({ className: cn("flex cursor-pointer items-center gap-2 data-[disabled]:cursor-not-allowed", OPT_ITEM_BASE, OPT_ACTIVE_ITEM, className) }, props), {}, {
3236
+ "data-opt-id": "J3970",
3237
+ "data-opt-slug": "form.FormSelectItem"
3238
+ }));
3239
+ }
3240
+ const switchSizeStyles = {
3241
+ sm: {
3242
+ track: "h-5 w-9",
3243
+ thumb: "h-4 w-4"
3244
+ },
3245
+ md: {
3246
+ track: "h-6 w-11",
3247
+ thumb: "h-5 w-5"
3248
+ },
3249
+ lg: {
3250
+ track: "h-7 w-14",
3251
+ thumb: "h-6 w-6"
3252
+ }
3253
+ };
3254
+ /** Renders the form switch component. */
3255
+ function FormSwitch$1(_ref8) {
3256
+ let { className, size = "md", name } = _ref8, props = _objectWithoutProperties(_ref8, _excluded6);
3257
+ const styles = switchSizeStyles[size];
3258
+ const form = useRequiredFormContext("FormSwitch");
3259
+ const checked = Boolean(useFieldValue(form, name));
3260
+ return /* @__PURE__ */ jsx(FormSwitch, _objectSpread2(_objectSpread2({
3261
+ name,
3262
+ className: cn("group relative inline-flex shrink-0 cursor-pointer rounded-full p-0.5 transition-colors", styles.track, "bg-bg-muted", "aria-[checked=true]:bg-accent", "disabled:cursor-not-allowed disabled:opacity-50", OPT_FOCUS_VISIBLE, className),
3263
+ "aria-checked": checked
3264
+ }, props), {}, {
3265
+ "data-opt-id": "48T40",
3266
+ "data-opt-slug": "form.FormSwitch",
3267
+ children: /* @__PURE__ */ jsx("span", { className: cn("pointer-events-none inline-block transform rounded-full bg-white shadow-sm ring-0 transition-transform", styles.thumb, "translate-x-0", size === "sm" && "group-aria-[checked=true]:translate-x-4", size === "md" && "group-aria-[checked=true]:translate-x-5", size === "lg" && "group-aria-[checked=true]:translate-x-7") })
3268
+ }));
3269
+ }
3270
+ /** Renders the form label component. */
3271
+ function FormLabel$1(_ref9) {
3272
+ let { className } = _ref9, props = _objectWithoutProperties(_ref9, _excluded7);
3273
+ return /* @__PURE__ */ jsx(FormLabel, _objectSpread2(_objectSpread2({ className: cn(labelClass, className) }, props), {}, {
3274
+ "data-opt-id": "JHRKM",
3275
+ "data-opt-slug": "form.FormLabel"
3276
+ }));
3277
+ }
3278
+ /** Renders the form error component. */
3279
+ function FormError$1(_ref10) {
3280
+ let { className } = _ref10, props = _objectWithoutProperties(_ref10, _excluded8);
3281
+ return /* @__PURE__ */ jsx(FormError, _objectSpread2(_objectSpread2({ className: cn(errorClass, className) }, props), {}, {
3282
+ "data-opt-id": "E9NM4",
3283
+ "data-opt-slug": "form.FormError"
3284
+ }));
3285
+ }
3286
+ /** Renders the form submit component. */
3287
+ function FormSubmit$1(_ref11) {
3288
+ var _form$isSubmitting;
3289
+ let { className, disabled, children } = _ref11, props = _objectWithoutProperties(_ref11, _excluded9);
3290
+ const form = useFormContext();
3291
+ const isSubmitting = (_form$isSubmitting = form === null || form === void 0 ? void 0 : form.isSubmitting()) !== null && _form$isSubmitting !== void 0 ? _form$isSubmitting : false;
3292
+ return /* @__PURE__ */ jsx(FormSubmit, _objectSpread2(_objectSpread2({
3293
+ className: cn(submitClass, className),
3294
+ disabled: disabled !== null && disabled !== void 0 ? disabled : isSubmitting
3295
+ }, props), {}, {
3296
+ "data-opt-id": "K580M",
3297
+ "data-opt-slug": "form.FormSubmit",
3298
+ children
3299
+ }));
3300
+ }
3301
+ /** Renders the form provider component. */
3302
+ function FormProvider$1(props) {
3303
+ return /* @__PURE__ */ jsx(FormProvider, _objectSpread2(_objectSpread2({}, props), {}, {
3304
+ "data-opt-id": "G0DQ4",
3305
+ "data-opt-slug": "form.FormProvider"
3306
+ }));
3307
+ }
3308
+ /** Renders the form group component. */
3309
+ function FormGroup$1(_ref12) {
3310
+ let { className } = _ref12, props = _objectWithoutProperties(_ref12, _excluded10);
3311
+ return /* @__PURE__ */ jsx(FormGroup, _objectSpread2(_objectSpread2({ className: cn("gap-group flex flex-col", className) }, props), {}, {
3312
+ "data-opt-id": "89E8Q",
3313
+ "data-opt-slug": "form.FormGroup"
3314
+ }));
3315
+ }
3316
+ /** Renders the form group label component. */
3317
+ function FormGroupLabel$1(_ref13) {
3318
+ let { className } = _ref13, props = _objectWithoutProperties(_ref13, _excluded11);
3319
+ return /* @__PURE__ */ jsx(FormGroupLabel, _objectSpread2(_objectSpread2({ className: cn(labelClass, "font-semibold", className) }, props), {}, {
3320
+ "data-opt-id": "W95BH",
3321
+ "data-opt-slug": "form.FormGroupLabel"
3322
+ }));
3323
+ }
3324
+ /** Renders the form description component. */
3325
+ function FormDescription$1(_ref14) {
3326
+ let { className } = _ref14, props = _objectWithoutProperties(_ref14, _excluded12);
3327
+ return /* @__PURE__ */ jsx(FormDescription, _objectSpread2(_objectSpread2({ className: cn(descriptionClass, className) }, props), {}, {
3328
+ "data-opt-id": "RFB40",
3329
+ "data-opt-slug": "form.FormDescription"
3330
+ }));
3331
+ }
3332
+ /** Renders the form field component. */
3333
+ function FormField$1(_ref15) {
3334
+ let { className } = _ref15, props = _objectWithoutProperties(_ref15, _excluded13);
3335
+ return /* @__PURE__ */ jsx(FormField, _objectSpread2(_objectSpread2({ className: cn("gap-element flex flex-col", className) }, props), {}, {
3336
+ "data-opt-id": "C68GP",
3337
+ "data-opt-slug": "form.FormField"
3338
+ }));
3339
+ }
3340
+ /** Renders the form control component. */
3341
+ function FormControl$1(_ref16) {
3342
+ let { className } = _ref16, props = _objectWithoutProperties(_ref16, _excluded14);
3343
+ return /* @__PURE__ */ jsx(FormControl, _objectSpread2(_objectSpread2({ className: cn(inputClass, className) }, props), {}, {
3344
+ "data-opt-id": "XNF0F",
3345
+ "data-opt-slug": "form.FormControl"
3346
+ }));
3347
+ }
3348
+ /** Renders the form push component. */
3349
+ function FormPush$1(_ref17) {
3350
+ let { className } = _ref17, props = _objectWithoutProperties(_ref17, _excluded15);
3351
+ return /* @__PURE__ */ jsx(FormPush, _objectSpread2(_objectSpread2({ className: cn(OPT_BUTTON_SECONDARY, className) }, props), {}, {
3352
+ "data-opt-id": "5SV8S",
3353
+ "data-opt-slug": "form.FormPush"
3354
+ }));
3355
+ }
3356
+ /** Renders the form remove component. */
3357
+ function FormRemove$1(_ref18) {
3358
+ let { className } = _ref18, props = _objectWithoutProperties(_ref18, _excluded16);
3359
+ return /* @__PURE__ */ jsx(FormRemove, _objectSpread2(_objectSpread2({ className: cn("text-danger-fg hover:text-danger focus-visible:ring-ring focus-visible:ring-offset-ring-offset inline-flex items-center text-sm outline-none focus-visible:ring-2 focus-visible:ring-offset-1", OPT_FOCUS_VISIBLE, className) }, props), {}, {
3360
+ "data-opt-id": "FEW6V",
3361
+ "data-opt-slug": "form.FormRemove"
3362
+ }));
3363
+ }
3364
+ /** Renders the form reset component. */
3365
+ function FormReset$1(_ref19) {
3366
+ let { className } = _ref19, props = _objectWithoutProperties(_ref19, _excluded17);
3367
+ return /* @__PURE__ */ jsx(FormReset, _objectSpread2(_objectSpread2({ className: cn(OPT_BUTTON_SECONDARY, className) }, props), {}, {
3368
+ "data-opt-id": "M3FVB",
3369
+ "data-opt-slug": "form.FormReset"
3370
+ }));
3371
+ }
3372
+ /** Renders the form checkbox component. */
3373
+ function FormCheckbox$1(_ref20) {
3374
+ let { className } = _ref20, props = _objectWithoutProperties(_ref20, _excluded18);
3375
+ return /* @__PURE__ */ jsx(FormCheckbox, _objectSpread2(_objectSpread2({ className: cn(checkboxClass, className) }, props), {}, {
3376
+ "data-opt-id": "3BZS1",
3377
+ "data-opt-slug": "form.FormCheckbox"
3378
+ }));
3379
+ }
3380
+ /** Renders the form radio group component. */
3381
+ function FormRadioGroup$1(_ref21) {
3382
+ let { className } = _ref21, props = _objectWithoutProperties(_ref21, _excluded19);
3383
+ return /* @__PURE__ */ jsx(FormRadioGroup, _objectSpread2(_objectSpread2({ className: cn("gap-group flex flex-col", className) }, props), {}, {
3384
+ "data-opt-id": "J8XRP",
3385
+ "data-opt-slug": "form.FormRadioGroup"
3386
+ }));
3387
+ }
3388
+ /** Renders the form radio component. */
3389
+ function FormRadio$1(_ref22) {
3390
+ let { className } = _ref22, props = _objectWithoutProperties(_ref22, _excluded20);
3391
+ return /* @__PURE__ */ jsx(FormRadio, _objectSpread2(_objectSpread2({ className: cn(radioClass, className) }, props), {}, {
3392
+ "data-opt-id": "YTN4Q",
3393
+ "data-opt-slug": "form.FormRadio"
3394
+ }));
3395
+ }
3396
+ /** Renders the form number input component. */
3397
+ function FormNumberInput(_ref23) {
3398
+ var _ref24;
3399
+ let { name } = _ref23, props = _objectWithoutProperties(_ref23, _excluded21);
3400
+ const form = useRequiredFormContext("FormNumberInput");
3401
+ const value = (_ref24 = useFieldValue(form, name)) !== null && _ref24 !== void 0 ? _ref24 : 0;
3402
+ const error = form === null || form === void 0 ? void 0 : form.getError(name);
3403
+ const touched = form === null || form === void 0 ? void 0 : form.getFieldTouched(name);
3404
+ return /* @__PURE__ */ jsx(NumberInput, _objectSpread2(_objectSpread2({
3405
+ value,
3406
+ onChange: (v) => form.setValue(name, v),
3407
+ error: error && touched ? error : void 0
3408
+ }, props), {}, {
3409
+ "data-opt-id": "FJ2A2",
3410
+ "data-opt-slug": "form.FormNumberInput"
3411
+ }));
3412
+ }
3413
+ /** Renders the form slider component. */
3414
+ function FormSlider(_ref25) {
3415
+ var _ref26;
3416
+ let { name } = _ref25, props = _objectWithoutProperties(_ref25, _excluded22);
3417
+ const form = useRequiredFormContext("FormSlider");
3418
+ const value = (_ref26 = useFieldValue(form, name)) !== null && _ref26 !== void 0 ? _ref26 : 0;
3419
+ return /* @__PURE__ */ jsx(Slider, _objectSpread2(_objectSpread2({
3420
+ value,
3421
+ onChange: (v) => form.setValue(name, v)
3422
+ }, props), {}, {
3423
+ "data-opt-id": "3XQ3A",
3424
+ "data-opt-slug": "form.FormSlider"
3425
+ }));
3426
+ }
3427
+ /** Renders the form star rating component. */
3428
+ function FormStarRating(_ref27) {
3429
+ var _ref28;
3430
+ let { name } = _ref27, props = _objectWithoutProperties(_ref27, _excluded23);
3431
+ const form = useRequiredFormContext("FormStarRating");
3432
+ const value = (_ref28 = useFieldValue(form, name)) !== null && _ref28 !== void 0 ? _ref28 : 0;
3433
+ return /* @__PURE__ */ jsx(StarRating, _objectSpread2(_objectSpread2({
3434
+ value,
3435
+ onChange: (v) => form.setValue(name, v)
3436
+ }, props), {}, {
3437
+ "data-opt-id": "EKNJJ",
3438
+ "data-opt-slug": "form.FormStarRating"
3439
+ }));
3440
+ }
3441
+ /** Renders the form color picker component. */
3442
+ function FormColorPicker(_ref29) {
3443
+ var _ref30;
3444
+ let { name } = _ref29, props = _objectWithoutProperties(_ref29, _excluded24);
3445
+ const form = useRequiredFormContext("FormColorPicker");
3446
+ const value = (_ref30 = useFieldValue(form, name)) !== null && _ref30 !== void 0 ? _ref30 : "#000000";
3447
+ const error = form === null || form === void 0 ? void 0 : form.getError(name);
3448
+ const touched = form === null || form === void 0 ? void 0 : form.getFieldTouched(name);
3449
+ return /* @__PURE__ */ jsx(ColorPicker, _objectSpread2(_objectSpread2({
3450
+ value,
3451
+ onChange: (v) => form.setValue(name, v),
3452
+ error: error && touched ? error : void 0
3453
+ }, props), {}, {
3454
+ "data-opt-id": "4ATTC",
3455
+ "data-opt-slug": "form.FormColorPicker"
3456
+ }));
3457
+ }
3458
+ /** Renders the form icon picker component. */
3459
+ function FormIconPicker(_ref31) {
3460
+ var _ref32;
3461
+ let { name } = _ref31, props = _objectWithoutProperties(_ref31, _excluded25);
3462
+ const form = useRequiredFormContext("FormIconPicker");
3463
+ const value = (_ref32 = useFieldValue(form, name)) !== null && _ref32 !== void 0 ? _ref32 : "";
3464
+ const error = form === null || form === void 0 ? void 0 : form.getError(name);
3465
+ const touched = form === null || form === void 0 ? void 0 : form.getFieldTouched(name);
3466
+ return /* @__PURE__ */ jsx(IconPicker, _objectSpread2(_objectSpread2({
3467
+ value,
3468
+ onChange: (v) => form.setValue(name, v),
3469
+ error: error && touched ? error : void 0
3470
+ }, props), {}, {
3471
+ "data-opt-id": "7Q41M",
3472
+ "data-opt-slug": "form.FormIconPicker"
3473
+ }));
3474
+ }
3475
+ /** Renders the form tag input component. */
3476
+ function FormTagInput(_ref33) {
3477
+ var _ref34;
3478
+ let { name } = _ref33, props = _objectWithoutProperties(_ref33, _excluded26);
3479
+ const form = useRequiredFormContext("FormTagInput");
3480
+ const value = (_ref34 = useFieldValue(form, name)) !== null && _ref34 !== void 0 ? _ref34 : [];
3481
+ const error = form === null || form === void 0 ? void 0 : form.getError(name);
3482
+ const touched = form === null || form === void 0 ? void 0 : form.getFieldTouched(name);
3483
+ return /* @__PURE__ */ jsx(TagInput, _objectSpread2(_objectSpread2({
3484
+ value,
3485
+ onChange: (v) => form.setValue(name, v),
3486
+ error: error && touched ? error : void 0
3487
+ }, props), {}, {
3488
+ "data-opt-id": "W05M1",
3489
+ "data-opt-slug": "form.FormTagInput"
3490
+ }));
3491
+ }
3492
+ /** Renders the form date range picker component. */
3493
+ function FormDateRangePicker(_ref35) {
3494
+ var _ref36;
3495
+ let { name } = _ref35, props = _objectWithoutProperties(_ref35, _excluded27);
3496
+ const form = useRequiredFormContext("FormDateRangePicker");
3497
+ const value = (_ref36 = useFieldValue(form, name)) !== null && _ref36 !== void 0 ? _ref36 : {
3498
+ start: null,
3499
+ end: null
3500
+ };
3501
+ const error = form === null || form === void 0 ? void 0 : form.getError(name);
3502
+ const touched = form === null || form === void 0 ? void 0 : form.getFieldTouched(name);
3503
+ return /* @__PURE__ */ jsx(DateRangePicker, _objectSpread2(_objectSpread2({
3504
+ value,
3505
+ onChange: (v) => form.setValue(name, v),
3506
+ error: error && touched ? error : void 0
3507
+ }, props), {}, {
3508
+ "data-opt-id": "4NE9A",
3509
+ "data-opt-slug": "form.FormDateRangePicker"
3510
+ }));
3511
+ }
3512
+ //#endregion
3513
+ //#region src/core/checkbox.tsx
3514
+ const _excluded$1 = [
3515
+ "label",
3516
+ "required",
3517
+ "error",
3518
+ "hint",
3519
+ "description",
3520
+ "checked",
3521
+ "defaultChecked",
3522
+ "onChange",
3523
+ "size",
3524
+ "disabled",
3525
+ "className",
3526
+ "id",
3527
+ "value",
3528
+ "indeterminate"
3529
+ ];
3530
+ const CheckboxGroupContext = createContext(null);
3531
+ function setForwardedRef(ref, value) {
3532
+ if (typeof ref === "function") ref(value);
3533
+ else if (ref) ref.current = value;
3534
+ }
3535
+ const sizeStyles = {
3536
+ sm: {
3537
+ box: "h-4 w-4",
3538
+ icon: "h-3 w-3",
3539
+ text: "text-sm"
3540
+ },
3541
+ md: {
3542
+ box: "h-5 w-5",
3543
+ icon: "h-3.5 w-3.5",
3544
+ text: "text-sm"
3545
+ },
3546
+ lg: {
3547
+ box: "h-6 w-6",
3548
+ icon: "h-4 w-4",
3549
+ text: "text-base"
3550
+ }
3551
+ };
3552
+ function CheckIcon({ className }) {
3553
+ return /* @__PURE__ */ jsx("svg", {
3554
+ "aria-hidden": "true",
3555
+ className,
3556
+ viewBox: "0 0 16 16",
3557
+ fill: "none",
3558
+ stroke: "currentColor",
3559
+ strokeWidth: 2.5,
3560
+ strokeLinecap: "round",
3561
+ strokeLinejoin: "round",
3562
+ children: /* @__PURE__ */ jsx("path", { d: "M3.5 8.5L6.5 11.5L12.5 4.5" })
3563
+ });
3564
+ }
3565
+ function IndeterminateIcon({ className }) {
3566
+ return /* @__PURE__ */ jsx("svg", {
3567
+ "aria-hidden": "true",
3568
+ className,
3569
+ viewBox: "0 0 16 16",
3570
+ fill: "none",
3571
+ stroke: "currentColor",
3572
+ strokeWidth: 2.5,
3573
+ strokeLinecap: "round",
3574
+ children: /* @__PURE__ */ jsx("path", { d: "M4 8H12" })
3575
+ });
3576
+ }
3577
+ const Checkbox = forwardRef((_ref, ref) => {
3578
+ var _groupContext$size, _groupContext$disable, _useInputId;
3579
+ let { label, required, error, hint, description, checked: checkedProp, defaultChecked, onChange, size: sizeProp = "md", disabled: disabledProp, className, id, value, indeterminate } = _ref, props = _objectWithoutProperties(_ref, _excluded$1);
3580
+ const groupContext = useContext(CheckboxGroupContext);
3581
+ const size = (_groupContext$size = groupContext === null || groupContext === void 0 ? void 0 : groupContext.size) !== null && _groupContext$size !== void 0 ? _groupContext$size : sizeProp;
3582
+ const disabled = (_groupContext$disable = groupContext === null || groupContext === void 0 ? void 0 : groupContext.disabled) !== null && _groupContext$disable !== void 0 ? _groupContext$disable : disabledProp;
3583
+ const isInGroup = groupContext !== null && value !== void 0;
3584
+ const [internalChecked, setInternalChecked] = useState(defaultChecked !== null && defaultChecked !== void 0 ? defaultChecked : false);
3585
+ const checked = isInGroup ? groupContext.value.includes(value) : checkedProp !== null && checkedProp !== void 0 ? checkedProp : internalChecked;
3586
+ const handleChange = (event) => {
3587
+ const newChecked = event.target.checked;
3588
+ if (isInGroup && value) {
3589
+ const newValue = newChecked ? [...groupContext.value, value] : groupContext.value.filter((v) => v !== value);
3590
+ groupContext.onChange(newValue);
3591
+ } else if (checkedProp !== void 0) onChange === null || onChange === void 0 || onChange(newChecked);
3592
+ else {
3593
+ setInternalChecked(newChecked);
3594
+ onChange === null || onChange === void 0 || onChange(newChecked);
3595
+ }
3596
+ };
3597
+ const fallbackId = useId().replace(/:/g, "");
3598
+ const checkboxId = (_useInputId = useInputId(id, label, "checkbox")) !== null && _useInputId !== void 0 ? _useInputId : `checkbox-${fallbackId}`;
3599
+ const hintText = hint !== null && hint !== void 0 ? hint : description;
3600
+ const hasError = Boolean(error);
3601
+ const styles = sizeStyles[size];
3602
+ const isIndeterminate = Boolean(indeterminate);
3603
+ const inputRef = useCallback((node) => {
3604
+ if (node) node.indeterminate = isIndeterminate;
3605
+ setForwardedRef(ref, node);
3606
+ }, [isIndeterminate, ref]);
3607
+ return /* @__PURE__ */ jsxs("div", {
3608
+ className: cn("flex flex-col gap-1.5", className),
3609
+ "data-opt-id": "3P3MA",
3610
+ "data-opt-slug": "checkbox.Checkbox",
3611
+ children: [/* @__PURE__ */ jsxs("div", {
3612
+ className: "flex items-start gap-3",
3613
+ children: [/* @__PURE__ */ jsxs("label", {
3614
+ className: cn("relative inline-flex shrink-0 cursor-pointer items-center justify-center", disabled && "cursor-not-allowed"),
3615
+ children: [/* @__PURE__ */ jsx("input", _objectSpread2({
3616
+ ref: inputRef,
3617
+ type: "checkbox",
3618
+ id: checkboxId,
3619
+ checked,
3620
+ onChange: handleChange,
3621
+ disabled,
3622
+ "aria-invalid": hasError,
3623
+ "aria-required": required,
3624
+ "aria-describedby": getDescribedBy(checkboxId, error, hintText),
3625
+ className: "peer sr-only"
3626
+ }, props)), /* @__PURE__ */ jsx("span", {
3627
+ className: cn("inline-flex items-center justify-center rounded", styles.box, "border-border border-2", "bg-surface", "peer-checked:border-accent peer-checked:bg-accent", isIndeterminate && "border-accent bg-accent", "peer-disabled:cursor-not-allowed peer-disabled:opacity-50", "peer-focus-visible:ring-ring peer-focus-visible:ring-2 peer-focus-visible:ring-offset-1", "transition-colors"),
3628
+ children: isIndeterminate ? /* @__PURE__ */ jsx(IndeterminateIcon, { className: cn(styles.icon, "text-accent-fg opacity-0 transition-opacity", "opacity-100") }) : /* @__PURE__ */ jsx(CheckIcon, { className: cn(styles.icon, "text-accent-fg opacity-0 transition-opacity", checked && "opacity-100") })
3629
+ })]
3630
+ }), (label || hintText) && /* @__PURE__ */ jsxs("div", {
3631
+ className: "flex flex-col",
3632
+ children: [label && /* @__PURE__ */ jsxs("label", {
3633
+ htmlFor: checkboxId,
3634
+ className: cn("text-text-primary cursor-pointer font-medium", styles.text, disabled && "cursor-not-allowed opacity-50"),
3635
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
3636
+ }), hintText && /* @__PURE__ */ jsx("p", {
3637
+ id: `${checkboxId}-hint`,
3638
+ className: cn("text-text-tertiary text-sm", disabled && "opacity-50"),
3639
+ children: hintText
3640
+ })]
3641
+ })]
3642
+ }), /* @__PURE__ */ jsx(FieldMessages, {
3643
+ id: checkboxId,
3644
+ error
3645
+ })]
3646
+ });
3647
+ });
3648
+ Checkbox.displayName = "Checkbox";
3649
+ const EMPTY_STRING_ARRAY = [];
3650
+ /** Renders the checkbox group component. */
3651
+ function CheckboxGroup({ children, value: valueProp, defaultValue = EMPTY_STRING_ARRAY, onChange, disabled, size = "md", error, required, className, orientation = "vertical", label }) {
3652
+ const [value, setValue] = useControlledState(defaultValue, valueProp, onChange);
3653
+ const hasError = Boolean(error);
3654
+ const groupId = label ? `checkbox-group-${label.replace(/\s+/g, "-").toLowerCase()}` : void 0;
3655
+ const ctxValue = useMemo(() => ({
3656
+ value,
3657
+ onChange: setValue,
3658
+ disabled,
3659
+ size
3660
+ }), [
3661
+ value,
3662
+ setValue,
3663
+ disabled,
3664
+ size
3665
+ ]);
3666
+ return /* @__PURE__ */ jsx(CheckboxGroupContext.Provider, {
3667
+ value: ctxValue,
3668
+ children: /* @__PURE__ */ jsxs("div", {
3669
+ className: cn("flex flex-col gap-1.5", className),
3670
+ "data-opt-id": "V6NSW",
3671
+ "data-opt-slug": "checkbox.CheckboxGroup",
3672
+ children: [/* @__PURE__ */ jsxs("div", {
3673
+ role: "group",
3674
+ "aria-label": label,
3675
+ "aria-required": required,
3676
+ "aria-invalid": hasError,
3677
+ "aria-describedby": hasError && groupId ? `${groupId}-error` : void 0,
3678
+ className: cn("flex", orientation === "vertical" ? "flex-col gap-3" : "flex-row gap-6"),
3679
+ children: [label && /* @__PURE__ */ jsxs("div", {
3680
+ className: "text-text-secondary mb-1 text-sm font-medium",
3681
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
3682
+ }), children]
3683
+ }), /* @__PURE__ */ jsx(FieldMessages, {
3684
+ id: groupId,
3685
+ error
3686
+ })]
3687
+ })
3688
+ });
3689
+ }
3690
+ //#endregion
3691
+ //#region src/core/pagination.tsx
3692
+ const _excluded = [
3693
+ "totalItems",
3694
+ "totalPages",
3695
+ "hasMore",
3696
+ "pageSize",
3697
+ "currentPage",
3698
+ "onPageChange",
3699
+ "showPageNumbers",
3700
+ "siblingCount",
3701
+ "variant",
3702
+ "isDisabled",
3703
+ "label",
3704
+ "labels",
3705
+ "className"
3706
+ ];
3707
+ const DEFAULT_LABELS = {
3708
+ previous: "Previous page",
3709
+ next: "Next page",
3710
+ page: (page) => `Go to page ${page}`,
3711
+ currentPage: (page) => `Page ${page}, current page`,
3712
+ compact: (page, totalPages) => totalPages === void 0 ? `Page ${page}` : `Page ${page} of ${totalPages}`,
3713
+ count: (start, end, totalItems) => `${start}-${end} of ${totalItems}`
3714
+ };
3715
+ function buildPageRange(current, total, siblings) {
3716
+ if (total <= 1) return [1];
3717
+ const range = [];
3718
+ const left = Math.max(2, current - siblings);
3719
+ const right = Math.min(total - 1, current + siblings);
3720
+ range.push(1);
3721
+ if (left > 2) range.push("ellipsis");
3722
+ for (let i = left; i <= right; i++) range.push(i);
3723
+ if (right < total - 1) range.push("ellipsis");
3724
+ if (total > 1) range.push(total);
3725
+ return range;
3726
+ }
3727
+ function positiveInteger(value) {
3728
+ if (!Number.isFinite(value) || value === void 0 || value <= 0) return;
3729
+ return Math.max(1, Math.floor(value));
3730
+ }
3731
+ function resolveTotalPages({ totalItems, totalPages, pageSize, currentPage, hasMore }) {
3732
+ const explicitTotalPages = positiveInteger(totalPages);
3733
+ if (explicitTotalPages !== void 0) return explicitTotalPages;
3734
+ const safePageSize = positiveInteger(pageSize);
3735
+ if (safePageSize !== void 0 && Number.isFinite(totalItems) && totalItems !== void 0) return Math.max(1, Math.ceil(Math.max(0, totalItems) / safePageSize));
3736
+ if (hasMore) return Math.max(1, Math.floor(currentPage) + 1);
3737
+ return Math.max(1, Math.floor(currentPage));
3738
+ }
3739
+ function clampPage(page, totalPages) {
3740
+ if (!Number.isFinite(page)) return 1;
3741
+ return Math.min(Math.max(1, Math.floor(page)), totalPages);
3742
+ }
3743
+ const btnBase = `inline-flex h-8 min-w-8 items-center justify-center rounded-md px-2 text-sm transition-colors ${OPT_FOCUS_VISIBLE}`;
3744
+ const btnEnabled = "text-text-primary hover:bg-bg-subtle active:bg-bg-muted cursor-pointer";
3745
+ const btnDisabled = "text-text-tertiary cursor-not-allowed opacity-50";
3746
+ const btnActive = "bg-accent text-accent-fg hover:bg-accent-hover cursor-default";
3747
+ /** Renders the pagination component. */
3748
+ function Pagination(_ref) {
3749
+ let { totalItems, totalPages: totalPagesProp, hasMore, pageSize, currentPage, onPageChange, showPageNumbers = true, siblingCount = 1, variant, isDisabled = false, label = "Pagination", labels, className } = _ref, props = _objectWithoutProperties(_ref, _excluded);
3750
+ const resolvedLabels = _objectSpread2(_objectSpread2({}, DEFAULT_LABELS), labels);
3751
+ const totalPages = resolveTotalPages({
3752
+ totalItems,
3753
+ totalPages: totalPagesProp,
3754
+ pageSize,
3755
+ currentPage,
3756
+ hasMore
3757
+ });
3758
+ const safeCurrentPage = clampPage(currentPage, totalPages);
3759
+ const resolvedVariant = variant !== null && variant !== void 0 ? variant : showPageNumbers ? "pages" : "none";
3760
+ const itemRange = Number.isFinite(totalItems) && totalItems !== void 0 && positiveInteger(pageSize) !== void 0 ? {
3761
+ start: totalItems === 0 ? 0 : (safeCurrentPage - 1) * pageSize + 1,
3762
+ end: Math.min(safeCurrentPage * pageSize, totalItems)
3763
+ } : null;
3764
+ const pages = useMemo(() => buildPageRange(safeCurrentPage, totalPages, siblingCount), [
3765
+ safeCurrentPage,
3766
+ totalPages,
3767
+ siblingCount
3768
+ ]);
3769
+ const hasPrev = safeCurrentPage > 1;
3770
+ const hasNext = hasMore === true || safeCurrentPage < totalPages;
3771
+ const prevDisabled = isDisabled || !hasPrev;
3772
+ const nextDisabled = isDisabled || !hasNext;
3773
+ const handlePageChange = (page) => {
3774
+ if (isDisabled) return;
3775
+ const next = hasMore ? Math.max(1, Math.floor(page)) : clampPage(page, totalPages);
3776
+ if (next !== safeCurrentPage) onPageChange(next);
3777
+ };
3778
+ return /* @__PURE__ */ jsxs("nav", _objectSpread2(_objectSpread2({
3779
+ "aria-label": label,
3780
+ className: cn("gap-element flex items-center", className)
3781
+ }, props), {}, {
3782
+ "data-opt-id": "QBEE2",
3783
+ "data-opt-slug": "pagination.Pagination",
3784
+ children: [
3785
+ /* @__PURE__ */ jsx("button", {
3786
+ type: "button",
3787
+ className: cn(btnBase, prevDisabled ? btnDisabled : btnEnabled),
3788
+ disabled: prevDisabled,
3789
+ onClick: () => handlePageChange(safeCurrentPage - 1),
3790
+ "aria-label": resolvedLabels.previous,
3791
+ children: /* @__PURE__ */ jsx("svg", {
3792
+ width: "16",
3793
+ height: "16",
3794
+ viewBox: "0 0 16 16",
3795
+ fill: "none",
3796
+ stroke: "currentColor",
3797
+ strokeWidth: "2",
3798
+ strokeLinecap: "round",
3799
+ strokeLinejoin: "round",
3800
+ children: /* @__PURE__ */ jsx("path", { d: "M10 12 6 8l4-4" })
3801
+ })
3802
+ }),
3803
+ resolvedVariant === "pages" && pages.map((p, i) => p === "ellipsis" ? /* @__PURE__ */ jsx("span", {
3804
+ className: "text-text-tertiary px-1",
3805
+ "aria-hidden": "true",
3806
+ children: "…"
3807
+ }, `e${i}`) : /* @__PURE__ */ jsx("button", {
3808
+ type: "button",
3809
+ className: cn(btnBase, p === safeCurrentPage ? btnActive : btnEnabled),
3810
+ "aria-current": p === safeCurrentPage ? "page" : void 0,
3811
+ "aria-label": p === safeCurrentPage ? resolvedLabels.currentPage(p) : resolvedLabels.page(p),
3812
+ disabled: isDisabled,
3813
+ onClick: () => handlePageChange(p),
3814
+ children: p
3815
+ }, p)),
3816
+ resolvedVariant === "count" && itemRange && totalItems !== void 0 && /* @__PURE__ */ jsx("span", {
3817
+ className: "text-text-secondary px-2 text-sm",
3818
+ "aria-live": "polite",
3819
+ children: resolvedLabels.count(itemRange.start, itemRange.end, totalItems)
3820
+ }),
3821
+ resolvedVariant === "compact" && /* @__PURE__ */ jsx("span", {
3822
+ className: "text-text-secondary px-2 text-sm",
3823
+ "aria-live": "polite",
3824
+ children: resolvedLabels.compact(safeCurrentPage, hasMore && totalPages === safeCurrentPage + 1 ? void 0 : totalPages)
3825
+ }),
3826
+ /* @__PURE__ */ jsx("button", {
3827
+ type: "button",
3828
+ className: cn(btnBase, nextDisabled ? btnDisabled : btnEnabled),
3829
+ disabled: nextDisabled,
3830
+ onClick: () => handlePageChange(safeCurrentPage + 1),
3831
+ "aria-label": resolvedLabels.next,
3832
+ children: /* @__PURE__ */ jsx("svg", {
3833
+ width: "16",
3834
+ height: "16",
3835
+ viewBox: "0 0 16 16",
3836
+ fill: "none",
3837
+ stroke: "currentColor",
3838
+ strokeWidth: "2",
3839
+ strokeLinecap: "round",
3840
+ strokeLinejoin: "round",
3841
+ children: /* @__PURE__ */ jsx("path", { d: "M6 4l4 4-4 4" })
3842
+ })
3843
+ })
3844
+ ]
3845
+ }));
3846
+ }
3847
+ //#endregion
3848
+ export { TooltipAnchor$1 as $, koBreadcrumbLabels as $t, FormSwitch$1 as A, OPT_SURFACE_POPOVER as An, SelectPopover$1 as At, getIconRegistryEntry as B, _objectSpread2 as Bn, Composite as Bt, FormRoot$1 as C, OPT_FOCUS as Cn, DialogFooter as Ct, FormSlider as D, OPT_INPUT_ERROR as Dn, DialogRoot$1 as Dt, FormSelectPopover as E, OPT_INPUT as En, DialogPanel$1 as Et, useFormStore as F, OPT_TEXT_LABEL as Fn, TabPanel$1 as Ft, PopoverTrigger$1 as G, StarRating as Gt, PopoverClose$1 as H, Kbd as Hn, CompositeProvider as Ht, DEFAULT_PRESETS as I, OPT_TEXT_PRIMARY as In, TabsRoot$1 as It, ToolbarButton$1 as J, Alert as Jt, Slider as K, Input as Kt, DateRangePicker as L, OPT_TEXT_SECONDARY as Ln, DisclosureContent$1 as Lt, FormTextarea as M, OPT_TD as Mn, SelectTrigger$1 as Mt, useFieldValue as N, OPT_TD_MUTED as Nn, Tab$1 as Nt, FormStarRating as O, OPT_ITEM_BASE as On, SelectItem$1 as Ot, useFormContext as P, OPT_TEXTAREA_SIZE as Pn, TabList$1 as Pt, Tooltip$1 as Q, Button as Qt, TagInput as R, OPT_TEXT_TERTIARY as Rn, DisclosureRoot$1 as Rt, FormReset$1 as S, OPT_DOT_YELLOW as Sn, DialogDismiss$1 as St, FormSelectItem as T, OPT_HOVER_ITEM as Tn, DialogHeading$1 as Tt, PopoverContent$1 as U, cn as Un, CompositeRow as Ut, ColorPicker as V, _objectWithoutProperties as Vn, CompositeItem as Vt, PopoverRoot$1 as W, CompositeZone as Wt, ToolbarRoot$1 as X, Badge as Xt, ToolbarContainer$1 as Y, Spinner as Yt, ToolbarSeparator$1 as Z, EmptyState as Zt, FormProvider$1 as _, OPT_DISCLOSURE_TRIGGER as _n, ComboboxRoot$1 as _t, FormColorPicker as a, RequiredMark as an, MenuPopover$1 as at, FormRadioGroup$1 as b, OPT_DOT_GREEN as bn, DialogDescription$1 as bt, FormDescription$1 as c, OPT_ANIMATE_DRAWER as cn, MenuTrigger$1 as ct, FormGroup$1 as d, OPT_BADGE_GREEN as dn, ComboboxEmpty as dt, koComboboxLabels as en, TooltipProvider$1 as et, FormGroupLabel$1 as f, OPT_BADGE_NEUTRAL as fn, ComboboxGroup$1 as ft, FormNumberInput as g, OPT_DISCLOSURE_CONTENT as gn, ComboboxPopover$1 as gt, FormLabel$1 as h, OPT_BORDER as hn, ComboboxItem$1 as ht, FormCheckbox$1 as i, FieldMessages as in, MenuItemRadio$1 as it, FormTagInput as j, OPT_TABLE_ROW_ACTIVE as jn, SelectRoot$1 as jt, FormSubmit$1 as k, OPT_SURFACE as kn, SelectLabel$1 as kt, FormError$1 as l, OPT_ANIMATE_ENTER_EXIT as ln, MenubarContainer$1 as lt, FormInput$1 as m, OPT_BADGE_YELLOW as mn, ComboboxInput$1 as mt, Checkbox as n, StatCard as nn, MenuItem$1 as nt, FormControl$1 as o, getDescribedBy as on, MenuRoot$1 as ot, FormIconPicker as p, OPT_BADGE_RED as pn, ComboboxGroupLabel$1 as pt, NumberInput as q, useInputId as qt, CheckboxGroup as r, useControlledState as rn, MenuItemCheckbox$1 as rt, FormDateRangePicker as s, OPT_ACTIVE_ITEM as sn, MenuSeparator$1 as st, Pagination as t, koStarRatingLabels as tn, MenuButtonArrow$1 as tt, FormField$1 as u, OPT_BADGE_BLUE as un, MenubarRoot$1 as ut, FormPush$1 as v, OPT_DIVIDER as vn, AlertDialogPanel$1 as vt, FormSelect as w, OPT_FOCUS_VISIBLE as wn, DialogHeader as wt, FormRemove$1 as x, OPT_DOT_RED as xn, DialogDisclosure$1 as xt, FormRadio$1 as y, OPT_DOT_GRAY as yn, DialogBody as yt, IconPicker as z, OPT_TH as zn, DisclosureTrigger$1 as zt };
3849
+
3850
+ //# sourceMappingURL=pagination-DWbvACuN.js.map