@thangnqdev/ui 0.1.1 → 0.2.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 (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -65
  3. package/dist/bento/index.cjs.map +1 -1
  4. package/dist/bento/index.js +2 -2
  5. package/dist/bento/styles.css +2 -46
  6. package/dist/buttons/index.cjs +111 -18
  7. package/dist/buttons/index.cjs.map +1 -1
  8. package/dist/buttons/index.d.cts +1 -1
  9. package/dist/buttons/index.d.ts +1 -1
  10. package/dist/buttons/index.js +3 -3
  11. package/dist/buttons/styles.css +2 -6
  12. package/dist/{chunk-4S6L5V7X.js → chunk-2YJBW4E2.js} +2 -2
  13. package/dist/chunk-2YJBW4E2.js.map +1 -0
  14. package/dist/{chunk-F5Q7BTMH.js → chunk-4CRFNALF.js} +1011 -556
  15. package/dist/chunk-4CRFNALF.js.map +1 -0
  16. package/dist/{chunk-LWFRUJRU.js → chunk-4MS6ZHFQ.js} +225 -41
  17. package/dist/chunk-4MS6ZHFQ.js.map +1 -0
  18. package/dist/{chunk-2OXZK6IP.js → chunk-77KTYOMQ.js} +3 -3
  19. package/dist/chunk-77KTYOMQ.js.map +1 -0
  20. package/dist/{chunk-IABPUCAQ.js → chunk-ADO3SVUA.js} +2 -2
  21. package/dist/chunk-ADO3SVUA.js.map +1 -0
  22. package/dist/{chunk-GXI2H5XA.js → chunk-D7FB3TCA.js} +3 -3
  23. package/dist/chunk-D7FB3TCA.js.map +1 -0
  24. package/dist/chunk-DSEL7ELZ.js +314 -0
  25. package/dist/chunk-DSEL7ELZ.js.map +1 -0
  26. package/dist/{chunk-KJRBRTQE.js → chunk-EXFR2BFJ.js} +37 -28
  27. package/dist/chunk-EXFR2BFJ.js.map +1 -0
  28. package/dist/{chunk-PF4ZHGVW.js → chunk-GXWB6BSY.js} +116 -23
  29. package/dist/chunk-GXWB6BSY.js.map +1 -0
  30. package/dist/{chunk-66VWUJEI.js → chunk-I2FQBMVW.js} +3 -3
  31. package/dist/chunk-I2FQBMVW.js.map +1 -0
  32. package/dist/{chunk-EU2LPUYP.js → chunk-I5O2WCGF.js} +3 -3
  33. package/dist/chunk-I5O2WCGF.js.map +1 -0
  34. package/dist/{chunk-ATYGDTMK.js → chunk-ME4XILG5.js} +5 -5
  35. package/dist/chunk-ME4XILG5.js.map +1 -0
  36. package/dist/{chunk-5FZ6ZFII.js → chunk-PC5SZFZC.js} +373 -150
  37. package/dist/chunk-PC5SZFZC.js.map +1 -0
  38. package/dist/{chunk-C4SUXMI3.js → chunk-S6XJMYME.js} +3 -3
  39. package/dist/chunk-S6XJMYME.js.map +1 -0
  40. package/dist/{chunk-A7P3O5Z5.js → chunk-V52JOSDF.js} +3 -3
  41. package/dist/chunk-V52JOSDF.js.map +1 -0
  42. package/dist/{chunk-NFVONJUK.js → chunk-W5WNWTQC.js} +455 -211
  43. package/dist/chunk-W5WNWTQC.js.map +1 -0
  44. package/dist/{chunk-WAFHC4DQ.js → chunk-YJ64RI7J.js} +3 -3
  45. package/dist/chunk-YJ64RI7J.js.map +1 -0
  46. package/dist/chunk-YOCGBORV.js +155 -0
  47. package/dist/chunk-YOCGBORV.js.map +1 -0
  48. package/dist/chunk-ZEDXARXW.js +96 -0
  49. package/dist/chunk-ZEDXARXW.js.map +1 -0
  50. package/dist/components.css +2 -0
  51. package/dist/core/index.cjs +33 -24
  52. package/dist/core/index.cjs.map +1 -1
  53. package/dist/core/index.js +2 -2
  54. package/dist/core/styles.css +2 -130
  55. package/dist/data-display/index.cjs +770 -247
  56. package/dist/data-display/index.cjs.map +1 -1
  57. package/dist/data-display/index.d.cts +1 -1
  58. package/dist/data-display/index.d.ts +1 -1
  59. package/dist/data-display/index.js +5 -4
  60. package/dist/data-display/styles.css +2 -4
  61. package/dist/feedback/index.cjs.map +1 -1
  62. package/dist/feedback/index.js +2 -2
  63. package/dist/feedback/styles.css +2 -4
  64. package/dist/forms/index.cjs +1211 -459
  65. package/dist/forms/index.cjs.map +1 -1
  66. package/dist/forms/index.d.cts +1 -1
  67. package/dist/forms/index.d.ts +1 -1
  68. package/dist/forms/index.js +8 -8
  69. package/dist/forms/styles.css +2 -6
  70. package/dist/glass/index.cjs.map +1 -1
  71. package/dist/glass/index.js +2 -2
  72. package/dist/glass/styles.css +2 -81
  73. package/dist/{index-D6fE7w-b.d.cts → index-BGt_hecO.d.cts} +1 -0
  74. package/dist/{index-D6fE7w-b.d.ts → index-BGt_hecO.d.ts} +1 -0
  75. package/dist/{index-DzcWh1Hs.d.cts → index-BtDvpZCf.d.cts} +7 -0
  76. package/dist/{index-DzcWh1Hs.d.ts → index-BtDvpZCf.d.ts} +7 -0
  77. package/dist/{index-Cle6QzQl.d.ts → index-COX1sBUN.d.ts} +27 -3
  78. package/dist/{index-BkRqGNG1.d.ts → index-Cg8MuP7u.d.cts} +40 -13
  79. package/dist/{index-BkRqGNG1.d.cts → index-Cg8MuP7u.d.ts} +40 -13
  80. package/dist/{index-CenuF_P2.d.ts → index-DHkPRTvE.d.cts} +39 -8
  81. package/dist/{index-CenuF_P2.d.cts → index-DHkPRTvE.d.ts} +39 -8
  82. package/dist/{index-TyK-Ldpy.d.cts → index-Du_oht9k.d.cts} +27 -3
  83. package/dist/index.cjs +2481 -917
  84. package/dist/index.cjs.map +1 -1
  85. package/dist/index.d.cts +5 -5
  86. package/dist/index.d.ts +5 -5
  87. package/dist/index.js +19 -19
  88. package/dist/layout/index.cjs.map +1 -1
  89. package/dist/layout/index.js +2 -2
  90. package/dist/layout/styles.css +2 -8
  91. package/dist/navigation/index.cjs +288 -48
  92. package/dist/navigation/index.cjs.map +1 -1
  93. package/dist/navigation/index.d.cts +1 -1
  94. package/dist/navigation/index.d.ts +1 -1
  95. package/dist/navigation/index.js +6 -6
  96. package/dist/navigation/styles.css +2 -4
  97. package/dist/overlays/index.cjs +566 -229
  98. package/dist/overlays/index.cjs.map +1 -1
  99. package/dist/overlays/index.d.cts +1 -1
  100. package/dist/overlays/index.d.ts +1 -1
  101. package/dist/overlays/index.js +7 -7
  102. package/dist/overlays/styles.css +2 -8
  103. package/dist/reset.css +45 -0
  104. package/dist/styles.css +1 -1
  105. package/dist/tokens.css +11 -0
  106. package/dist/typography/index.cjs.map +1 -1
  107. package/dist/typography/index.js +4 -4
  108. package/dist/typography/styles.css +2 -5
  109. package/llms.txt +211 -113
  110. package/package.json +160 -116
  111. package/src/bento/BentoCard.tsx +140 -140
  112. package/src/bento/BentoGrid.tsx +50 -50
  113. package/src/bento/index.ts +2 -2
  114. package/src/bento/tokens.css +46 -46
  115. package/src/buttons/Button.tsx +104 -104
  116. package/src/buttons/ButtonGroup.tsx +43 -43
  117. package/src/buttons/IconButton.tsx +79 -79
  118. package/src/buttons/SplitButton.tsx +186 -86
  119. package/src/buttons/ToggleButton.tsx +157 -157
  120. package/src/buttons/index.ts +5 -5
  121. package/src/buttons/tokens.css +6 -6
  122. package/src/core/ThemeProvider.tsx +135 -123
  123. package/src/core/index.ts +2 -2
  124. package/src/core/tokens.css +134 -130
  125. package/src/data-display/Accordion.tsx +147 -147
  126. package/src/data-display/Avatar.tsx +134 -134
  127. package/src/data-display/Card.tsx +112 -112
  128. package/src/data-display/Chip.tsx +74 -74
  129. package/src/data-display/DataTablePro.tsx +299 -121
  130. package/src/data-display/StatCard.tsx +60 -60
  131. package/src/data-display/Table.tsx +74 -74
  132. package/src/data-display/Timeline.tsx +62 -62
  133. package/src/data-display/TreeView.tsx +243 -104
  134. package/src/data-display/tokens.css +4 -4
  135. package/src/feedback/Alert.tsx +80 -80
  136. package/src/feedback/EmptyState.tsx +45 -45
  137. package/src/feedback/Skeleton.tsx +66 -66
  138. package/src/feedback/Spinner.tsx +65 -65
  139. package/src/feedback/index.ts +5 -5
  140. package/src/feedback/tokens.css +4 -4
  141. package/src/forms/Checkbox.tsx +149 -69
  142. package/src/forms/CheckboxGroup.tsx +76 -29
  143. package/src/forms/Combobox.tsx +172 -28
  144. package/src/forms/DatePicker.tsx +385 -81
  145. package/src/forms/FileUpload.tsx +51 -7
  146. package/src/forms/FormField.tsx +115 -115
  147. package/src/forms/Input.tsx +151 -151
  148. package/src/forms/NumberInput.tsx +34 -20
  149. package/src/forms/PasswordInput.tsx +35 -35
  150. package/src/forms/PinInput.tsx +139 -125
  151. package/src/forms/Radio.tsx +142 -142
  152. package/src/forms/RangeSlider.tsx +237 -111
  153. package/src/forms/SearchInput.tsx +34 -34
  154. package/src/forms/Select.tsx +103 -103
  155. package/src/forms/Slider.tsx +85 -85
  156. package/src/forms/Textarea.tsx +114 -114
  157. package/src/forms/tokens.css +6 -6
  158. package/src/glass/GlassButton.tsx +59 -59
  159. package/src/glass/GlassCard.tsx +71 -71
  160. package/src/glass/index.ts +3 -3
  161. package/src/glass/tokens.css +81 -81
  162. package/src/index.ts +26 -26
  163. package/src/layout/AspectRatio.tsx +39 -39
  164. package/src/layout/Container.tsx +53 -53
  165. package/src/layout/Divider.tsx +61 -61
  166. package/src/layout/Flex.tsx +79 -79
  167. package/src/layout/Grid.tsx +124 -124
  168. package/src/layout/PageLayout.tsx +59 -59
  169. package/src/layout/Section.tsx +47 -47
  170. package/src/layout/Spacer.tsx +30 -30
  171. package/src/layout/Stack.tsx +88 -88
  172. package/src/layout/tokens.css +8 -8
  173. package/src/navigation/Breadcrumb.tsx +73 -73
  174. package/src/navigation/CommandPalette.tsx +142 -142
  175. package/src/navigation/DropdownMenu.tsx +244 -160
  176. package/src/navigation/Pagination.tsx +114 -114
  177. package/src/navigation/Stepper.tsx +93 -93
  178. package/src/navigation/Tabs.tsx +265 -133
  179. package/src/navigation/index.ts +6 -6
  180. package/src/navigation/tokens.css +4 -4
  181. package/src/overlays/AlertDialog.tsx +63 -54
  182. package/src/overlays/BottomSheet.tsx +30 -10
  183. package/src/overlays/ContextMenu.tsx +51 -9
  184. package/src/overlays/Drawer.tsx +160 -145
  185. package/src/overlays/FocusTrap.tsx +122 -49
  186. package/src/overlays/Modal.tsx +296 -219
  187. package/src/overlays/Popover.tsx +55 -25
  188. package/src/overlays/Portal.tsx +23 -23
  189. package/src/overlays/Toast.tsx +175 -137
  190. package/src/overlays/Tooltip.tsx +125 -100
  191. package/src/overlays/tokens.css +8 -8
  192. package/src/registry/components.ts +1368 -0
  193. package/src/styles/components.css +39 -0
  194. package/src/styles/index.css +2 -93
  195. package/src/styles/reset.css +45 -0
  196. package/src/styles/tokens.css +11 -2
  197. package/src/typography/Blockquote.tsx +32 -32
  198. package/src/typography/Code.tsx +89 -89
  199. package/src/typography/Heading.tsx +56 -56
  200. package/src/typography/Kbd.tsx +25 -25
  201. package/src/typography/Label.tsx +47 -47
  202. package/src/typography/Link.tsx +56 -56
  203. package/src/typography/Text.tsx +62 -62
  204. package/src/typography/index.ts +7 -7
  205. package/src/typography/tokens.css +5 -5
  206. package/src/utils/cn.ts +6 -6
  207. package/src/utils/scroll-lock.ts +19 -0
  208. package/src/utils/useControllableState.ts +54 -0
  209. package/ui-contract.json +192 -35
  210. package/dist/chunk-2OXZK6IP.js.map +0 -1
  211. package/dist/chunk-4S6L5V7X.js.map +0 -1
  212. package/dist/chunk-5FZ6ZFII.js.map +0 -1
  213. package/dist/chunk-66VWUJEI.js.map +0 -1
  214. package/dist/chunk-A7P3O5Z5.js.map +0 -1
  215. package/dist/chunk-ATYGDTMK.js.map +0 -1
  216. package/dist/chunk-C4SUXMI3.js.map +0 -1
  217. package/dist/chunk-EU2LPUYP.js.map +0 -1
  218. package/dist/chunk-F5Q7BTMH.js.map +0 -1
  219. package/dist/chunk-GXI2H5XA.js.map +0 -1
  220. package/dist/chunk-H3LCNPMC.js +0 -101
  221. package/dist/chunk-H3LCNPMC.js.map +0 -1
  222. package/dist/chunk-IABPUCAQ.js.map +0 -1
  223. package/dist/chunk-KJRBRTQE.js.map +0 -1
  224. package/dist/chunk-LBUBXUYQ.js +0 -40
  225. package/dist/chunk-LBUBXUYQ.js.map +0 -1
  226. package/dist/chunk-LWFRUJRU.js.map +0 -1
  227. package/dist/chunk-NFVONJUK.js.map +0 -1
  228. package/dist/chunk-PF4ZHGVW.js.map +0 -1
  229. package/dist/chunk-WAFHC4DQ.js.map +0 -1
  230. package/dist/chunk-X76KBH4Y.js +0 -71
  231. package/dist/chunk-X76KBH4Y.js.map +0 -1
@@ -1,19 +1,19 @@
1
- import { Chip } from './chunk-X76KBH4Y.js';
2
- import { Label } from './chunk-GXI2H5XA.js';
3
- import { Popover } from './chunk-H3LCNPMC.js';
4
- import { Kbd } from './chunk-EU2LPUYP.js';
5
- import { Button } from './chunk-66VWUJEI.js';
6
- import { __export, cn } from './chunk-4S6L5V7X.js';
7
- import React2, { createContext, useContext, forwardRef, useId, useState, useRef, useEffect } from 'react';
8
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
1
+ import { useFormField, useCheckboxGroup, checkboxVariants, FormLabel, FormHelperText, FormField, FormErrorMessage, CheckboxGroupContext, CheckboxGroup, Checkbox, Chip } from './chunk-DSEL7ELZ.js';
2
+ import { useControllableState, Popover } from './chunk-YOCGBORV.js';
3
+ import { Kbd } from './chunk-I5O2WCGF.js';
4
+ import { Button } from './chunk-I2FQBMVW.js';
5
+ import { __export, cn } from './chunk-2YJBW4E2.js';
6
+ import React, { forwardRef, useState, useRef, useEffect, createContext, useContext, useCallback, useId } from 'react';
9
7
  import { cva } from 'class-variance-authority';
10
- import { X, Search, EyeOff, Eye, ChevronDown, Minus, Check, ChevronLeft, ChevronRight, Calendar, Clock, ChevronsUpDown, UploadCloud, FileText, File, CheckCircle2, AlertCircle, Plus } from 'lucide-react';
8
+ import { X, Search, EyeOff, Eye, ChevronDown, ChevronLeft, ChevronRight, Calendar, Clock, Check, ChevronsUpDown, UploadCloud, FileText, File, CheckCircle2, AlertCircle, Minus, Plus } from 'lucide-react';
9
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
11
10
 
12
11
  // src/forms/index.ts
13
12
  var forms_exports = {};
14
13
  __export(forms_exports, {
15
14
  Checkbox: () => Checkbox,
16
15
  CheckboxGroup: () => CheckboxGroup,
16
+ CheckboxGroupContext: () => CheckboxGroupContext,
17
17
  Combobox: () => Combobox,
18
18
  CurrencyInput: () => CurrencyInput,
19
19
  DatePicker: () => DatePicker,
@@ -50,93 +50,9 @@ __export(forms_exports, {
50
50
  switchThumbVariants: () => switchThumbVariants,
51
51
  switchVariants: () => switchVariants,
52
52
  textareaVariants: () => textareaVariants,
53
+ useCheckboxGroup: () => useCheckboxGroup,
53
54
  useFormField: () => useFormField
54
55
  });
55
- var FormFieldContext = createContext(null);
56
- function useFormField() {
57
- const context = useContext(FormFieldContext);
58
- return context;
59
- }
60
- var FormField = forwardRef(
61
- ({ className, isRequired, isInvalid, isDisabled, children, ...props }, ref) => {
62
- const generatedId = useId();
63
- const id = props.id || generatedId;
64
- const labelId = `${id}-label`;
65
- const descriptionId = `${id}-description`;
66
- const errorId = `${id}-error`;
67
- return /* @__PURE__ */ jsx(
68
- FormFieldContext.Provider,
69
- {
70
- value: {
71
- id,
72
- labelId,
73
- descriptionId,
74
- errorId,
75
- isRequired,
76
- isInvalid,
77
- isDisabled
78
- },
79
- children: /* @__PURE__ */ jsx("div", { ref, className: cn("space-y-1.5 w-full", className), ...props, children })
80
- }
81
- );
82
- }
83
- );
84
- FormField.displayName = "FormField";
85
- var FormLabel = forwardRef(
86
- ({ className, required, children, ...props }, ref) => {
87
- const context = useFormField();
88
- const isRequired = required ?? context?.isRequired;
89
- const isError = context?.isInvalid;
90
- return /* @__PURE__ */ jsx(
91
- Label,
92
- {
93
- ref,
94
- id: context?.labelId,
95
- htmlFor: context?.id,
96
- required: isRequired,
97
- error: isError,
98
- className,
99
- ...props,
100
- children
101
- }
102
- );
103
- }
104
- );
105
- FormLabel.displayName = "FormLabel";
106
- var FormHelperText = forwardRef(
107
- ({ className, children, ...props }, ref) => {
108
- const context = useFormField();
109
- return /* @__PURE__ */ jsx(
110
- "p",
111
- {
112
- ref,
113
- id: context?.descriptionId,
114
- className: cn("text-xs text-[var(--ui-text-muted)]", className),
115
- ...props,
116
- children
117
- }
118
- );
119
- }
120
- );
121
- FormHelperText.displayName = "FormHelperText";
122
- var FormErrorMessage = forwardRef(
123
- ({ className, children, ...props }, ref) => {
124
- const context = useFormField();
125
- if (!context?.isInvalid && !children) return null;
126
- return /* @__PURE__ */ jsx(
127
- "p",
128
- {
129
- ref,
130
- id: context?.errorId,
131
- role: "alert",
132
- className: cn("text-xs font-medium text-[var(--ui-error)]", className),
133
- ...props,
134
- children
135
- }
136
- );
137
- }
138
- );
139
- FormErrorMessage.displayName = "FormErrorMessage";
140
56
  var inputVariants = cva(
141
57
  "w-full rounded-[var(--ui-radius-md)] border bg-[var(--ui-bg-surface)]/70 backdrop-blur-md text-[var(--ui-text-primary)] placeholder:text-[var(--ui-text-muted)] transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]/70 focus-visible:border-[var(--ui-primary)] focus-visible:shadow-[0_0_16px_rgba(99,102,241,0.2)] disabled:cursor-not-allowed disabled:opacity-50 shadow-inner",
142
58
  {
@@ -187,7 +103,7 @@ var Input = forwardRef(
187
103
  const [uncontrolledVal, setUncontrolledVal] = useState(
188
104
  props.defaultValue !== void 0 ? String(props.defaultValue) : ""
189
105
  );
190
- const innerRef = React2.useRef(null);
106
+ const innerRef = React.useRef(null);
191
107
  const handleRef = (node) => {
192
108
  innerRef.current = node;
193
109
  if (typeof ref === "function") {
@@ -448,77 +364,6 @@ var Select = forwardRef(
448
364
  }
449
365
  );
450
366
  Select.displayName = "Select";
451
- var checkboxVariants = cva(
452
- "peer shrink-0 rounded-[var(--ui-radius-sm)] border border-[var(--ui-border-default)] bg-[var(--ui-bg-surface)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)] disabled:cursor-not-allowed disabled:opacity-50 transition-all cursor-pointer flex items-center justify-center text-[var(--ui-primary-fg)]",
453
- {
454
- variants: {
455
- size: {
456
- sm: "w-4 h-4 text-xs",
457
- md: "w-5 h-5 text-sm",
458
- lg: "w-6 h-6 text-base"
459
- }
460
- },
461
- defaultVariants: {
462
- size: "md"
463
- }
464
- }
465
- );
466
- var Checkbox = forwardRef(
467
- ({ className, size, indeterminate = false, label, checked, disabled, id, onChange, ...props }, ref) => {
468
- const formField = useFormField();
469
- const isDisabled = disabled ?? formField?.isDisabled ?? false;
470
- const checkboxId = id || formField?.id;
471
- return /* @__PURE__ */ jsxs("label", { className: cn("inline-flex items-center gap-2 select-none cursor-pointer", isDisabled && "cursor-not-allowed opacity-50"), children: [
472
- /* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
473
- /* @__PURE__ */ jsx(
474
- "input",
475
- {
476
- ref,
477
- type: "checkbox",
478
- id: checkboxId,
479
- disabled: isDisabled,
480
- checked,
481
- onChange,
482
- className: "sr-only peer",
483
- ...props
484
- }
485
- ),
486
- /* @__PURE__ */ jsx(
487
- "div",
488
- {
489
- className: cn(
490
- checkboxVariants({ size }),
491
- (checked || indeterminate) && "bg-[var(--ui-primary)] border-[var(--ui-primary)]",
492
- className
493
- ),
494
- children: indeterminate ? /* @__PURE__ */ jsx(Minus, { className: "w-3.5 h-3.5 stroke-[3]" }) : checked && /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5 stroke-[3]" })
495
- }
496
- )
497
- ] }),
498
- label && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--ui-text-primary)]", children: label })
499
- ] });
500
- }
501
- );
502
- Checkbox.displayName = "Checkbox";
503
- var CheckboxGroup = forwardRef(
504
- ({ className, orientation = "vertical", children, value, onChange, ...props }, ref) => {
505
- return /* @__PURE__ */ jsx(
506
- "div",
507
- {
508
- ref,
509
- role: "group",
510
- className: cn(
511
- "flex gap-2",
512
- orientation === "vertical" ? "flex-col" : "flex-row flex-wrap items-center",
513
- className
514
- ),
515
- ...props,
516
- children
517
- }
518
- );
519
- }
520
- );
521
- CheckboxGroup.displayName = "CheckboxGroup";
522
367
  var RadioGroupContext = createContext(null);
523
368
  var radioVariants = cva(
524
369
  "peer shrink-0 rounded-full border border-[var(--ui-border-default)] bg-[var(--ui-bg-surface)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)] disabled:cursor-not-allowed disabled:opacity-50 transition-all cursor-pointer flex items-center justify-center",
@@ -593,7 +438,7 @@ var RadioGroup = forwardRef(
593
438
  children,
594
439
  ...props
595
440
  }, ref) => {
596
- const [val, setVal] = React2.useState(defaultValue || "");
441
+ const [val, setVal] = React.useState(defaultValue || "");
597
442
  const currentValue = controlledValue !== void 0 ? controlledValue : val;
598
443
  const handleChange = (newValue) => {
599
444
  setVal(newValue);
@@ -722,7 +567,7 @@ var Slider = forwardRef(
722
567
  disabled,
723
568
  ...props
724
569
  }, ref) => {
725
- const [val, setVal] = React2.useState(defaultValue);
570
+ const [val, setVal] = React.useState(defaultValue);
726
571
  const currentValue = controlledValue !== void 0 ? controlledValue : val;
727
572
  const percentage = Math.min(100, Math.max(0, (currentValue - min) / (max - min) * 100));
728
573
  const handleChange = (e) => {
@@ -778,81 +623,192 @@ var RangeSlider = forwardRef(
778
623
  showValue = false,
779
624
  formatValue = (v) => `${v}`,
780
625
  className,
781
- disabled = false
626
+ disabled = false,
627
+ name,
628
+ "aria-label": ariaLabel = "Range slider"
782
629
  }, ref) => {
783
- const [stateValue, setStateValue] = useState(defaultValue);
784
- const [minVal, maxVal] = controlledValue || stateValue;
785
- const minPercentage = Math.min(100, Math.max(0, (minVal - min) / (max - min) * 100));
786
- const maxPercentage = Math.min(100, Math.max(0, (maxVal - min) / (max - min) * 100));
787
- const handleMinChange = (e) => {
788
- const val = Math.min(Number(e.target.value), maxVal - step);
789
- setStateValue([val, maxVal]);
790
- onChange?.([val, maxVal]);
630
+ const isControlled = controlledValue !== void 0;
631
+ const [internalValue, setInternalValue] = useState(defaultValue);
632
+ const currentValue = isControlled ? controlledValue : internalValue;
633
+ const [minVal, maxVal] = [
634
+ Math.max(min, Math.min(currentValue[0], currentValue[1])),
635
+ Math.min(max, Math.max(currentValue[0], currentValue[1]))
636
+ ];
637
+ const trackRef = useRef(null);
638
+ const draggingThumbRef = useRef(null);
639
+ const updateValues = useCallback(
640
+ (newMin, newMax) => {
641
+ const clampedMin = Math.max(min, Math.min(newMin, newMax));
642
+ const clampedMax = Math.min(max, Math.max(clampedMin, newMax));
643
+ const next = [clampedMin, clampedMax];
644
+ if (!isControlled) {
645
+ setInternalValue(next);
646
+ }
647
+ onChange?.(next);
648
+ },
649
+ [min, max, isControlled, onChange]
650
+ );
651
+ const getValueFromPointer = useCallback(
652
+ (clientX) => {
653
+ if (!trackRef.current) return min;
654
+ const rect = trackRef.current.getBoundingClientRect();
655
+ const percent = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
656
+ const rawValue = min + percent * (max - min);
657
+ const steppedValue = Math.round((rawValue - min) / step) * step + min;
658
+ return Math.min(max, Math.max(min, Number(steppedValue.toFixed(4))));
659
+ },
660
+ [min, max, step]
661
+ );
662
+ const handlePointerDown = (e) => {
663
+ if (disabled) return;
664
+ const clickedVal = getValueFromPointer(e.clientX);
665
+ const distToMin = Math.abs(clickedVal - minVal);
666
+ const distToMax = Math.abs(clickedVal - maxVal);
667
+ const targetThumb = distToMin <= distToMax ? "min" : "max";
668
+ draggingThumbRef.current = targetThumb;
669
+ if (targetThumb === "min") {
670
+ updateValues(Math.min(clickedVal, maxVal), maxVal);
671
+ } else {
672
+ updateValues(minVal, Math.max(clickedVal, minVal));
673
+ }
674
+ e.currentTarget.setPointerCapture(e.pointerId);
791
675
  };
792
- const handleMaxChange = (e) => {
793
- const val = Math.max(Number(e.target.value), minVal + step);
794
- setStateValue([minVal, val]);
795
- onChange?.([minVal, val]);
676
+ const handlePointerMove = (e) => {
677
+ if (disabled || !draggingThumbRef.current) return;
678
+ const moveVal = getValueFromPointer(e.clientX);
679
+ if (draggingThumbRef.current === "min") {
680
+ updateValues(Math.min(moveVal, maxVal), maxVal);
681
+ } else {
682
+ updateValues(minVal, Math.max(moveVal, minVal));
683
+ }
796
684
  };
797
- return /* @__PURE__ */ jsxs("div", { ref, className: cn("w-full flex items-center gap-4", className), children: [
798
- /* @__PURE__ */ jsxs("div", { className: "relative w-full flex items-center h-6 select-none touch-none", children: [
799
- /* @__PURE__ */ jsx("div", { className: "w-full h-2 rounded-full bg-[var(--ui-border-default)] overflow-hidden relative", children: /* @__PURE__ */ jsx(
800
- "div",
801
- {
802
- className: "absolute h-full bg-[var(--ui-primary)]",
803
- style: {
804
- left: `${minPercentage}%`,
805
- width: `${maxPercentage - minPercentage}%`
685
+ const handlePointerUp = (e) => {
686
+ if (draggingThumbRef.current) {
687
+ draggingThumbRef.current = null;
688
+ try {
689
+ e.currentTarget.releasePointerCapture(e.pointerId);
690
+ } catch {
691
+ }
692
+ }
693
+ };
694
+ const handleKeyDownMin = (e) => {
695
+ if (disabled) return;
696
+ let nextMin = minVal;
697
+ if (e.key === "ArrowRight" || e.key === "ArrowUp") {
698
+ e.preventDefault();
699
+ nextMin = Math.min(minVal + step, maxVal);
700
+ } else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
701
+ e.preventDefault();
702
+ nextMin = Math.max(minVal - step, min);
703
+ } else if (e.key === "Home") {
704
+ e.preventDefault();
705
+ nextMin = min;
706
+ } else if (e.key === "End") {
707
+ e.preventDefault();
708
+ nextMin = maxVal;
709
+ }
710
+ if (nextMin !== minVal) {
711
+ updateValues(nextMin, maxVal);
712
+ }
713
+ };
714
+ const handleKeyDownMax = (e) => {
715
+ if (disabled) return;
716
+ let nextMax = maxVal;
717
+ if (e.key === "ArrowRight" || e.key === "ArrowUp") {
718
+ e.preventDefault();
719
+ nextMax = Math.min(maxVal + step, max);
720
+ } else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
721
+ e.preventDefault();
722
+ nextMax = Math.max(maxVal - step, minVal);
723
+ } else if (e.key === "Home") {
724
+ e.preventDefault();
725
+ nextMax = minVal;
726
+ } else if (e.key === "End") {
727
+ e.preventDefault();
728
+ nextMax = max;
729
+ }
730
+ if (nextMax !== maxVal) {
731
+ updateValues(minVal, nextMax);
732
+ }
733
+ };
734
+ const minPercentage = Math.min(100, Math.max(0, (minVal - min) / (max - min || 1) * 100));
735
+ const maxPercentage = Math.min(100, Math.max(0, (maxVal - min) / (max - min || 1) * 100));
736
+ return /* @__PURE__ */ jsxs(
737
+ "div",
738
+ {
739
+ ref,
740
+ className: cn("w-full flex items-center gap-4", disabled && "opacity-50 cursor-not-allowed", className),
741
+ children: [
742
+ /* @__PURE__ */ jsxs(
743
+ "div",
744
+ {
745
+ ref: trackRef,
746
+ onPointerDown: handlePointerDown,
747
+ onPointerMove: handlePointerMove,
748
+ onPointerUp: handlePointerUp,
749
+ className: "relative w-full flex items-center h-7 select-none touch-none cursor-pointer",
750
+ children: [
751
+ /* @__PURE__ */ jsx("div", { className: "w-full h-2 rounded-full bg-[var(--ui-border-default)] overflow-hidden relative", children: /* @__PURE__ */ jsx(
752
+ "div",
753
+ {
754
+ className: "absolute h-full bg-[var(--ui-primary)]",
755
+ style: {
756
+ left: `${minPercentage}%`,
757
+ width: `${Math.max(0, maxPercentage - minPercentage)}%`
758
+ }
759
+ }
760
+ ) }),
761
+ name && /* @__PURE__ */ jsxs(Fragment, { children: [
762
+ /* @__PURE__ */ jsx("input", { type: "hidden", name: `${name}_min`, value: minVal }),
763
+ /* @__PURE__ */ jsx("input", { type: "hidden", name: `${name}_max`, value: maxVal })
764
+ ] }),
765
+ /* @__PURE__ */ jsx(
766
+ "div",
767
+ {
768
+ role: "slider",
769
+ tabIndex: disabled ? -1 : 0,
770
+ "aria-label": `${ariaLabel} minimum`,
771
+ "aria-valuemin": min,
772
+ "aria-valuemax": maxVal,
773
+ "aria-valuenow": minVal,
774
+ "aria-disabled": disabled,
775
+ onKeyDown: handleKeyDownMin,
776
+ className: cn(
777
+ "absolute w-5 h-5 rounded-full bg-white border-2 border-[var(--ui-primary)] shadow-md -translate-x-1/2 z-20 cursor-grab active:cursor-grabbing transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)] focus-visible:ring-offset-2",
778
+ disabled && "pointer-events-none"
779
+ ),
780
+ style: { left: `${minPercentage}%` }
781
+ }
782
+ ),
783
+ /* @__PURE__ */ jsx(
784
+ "div",
785
+ {
786
+ role: "slider",
787
+ tabIndex: disabled ? -1 : 0,
788
+ "aria-label": `${ariaLabel} maximum`,
789
+ "aria-valuemin": minVal,
790
+ "aria-valuemax": max,
791
+ "aria-valuenow": maxVal,
792
+ "aria-disabled": disabled,
793
+ onKeyDown: handleKeyDownMax,
794
+ className: cn(
795
+ "absolute w-5 h-5 rounded-full bg-white border-2 border-[var(--ui-primary)] shadow-md -translate-x-1/2 z-20 cursor-grab active:cursor-grabbing transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)] focus-visible:ring-offset-2",
796
+ disabled && "pointer-events-none"
797
+ ),
798
+ style: { left: `${maxPercentage}%` }
799
+ }
800
+ )
801
+ ]
806
802
  }
807
- }
808
- ) }),
809
- /* @__PURE__ */ jsx(
810
- "input",
811
- {
812
- type: "range",
813
- min,
814
- max,
815
- step,
816
- value: minVal,
817
- disabled,
818
- onChange: handleMinChange,
819
- className: "absolute inset-0 w-full h-full opacity-0 pointer-events-auto cursor-pointer z-20"
820
- }
821
- ),
822
- /* @__PURE__ */ jsx(
823
- "input",
824
- {
825
- type: "range",
826
- min,
827
- max,
828
- step,
829
- value: maxVal,
830
- disabled,
831
- onChange: handleMaxChange,
832
- className: "absolute inset-0 w-full h-full opacity-0 pointer-events-auto cursor-pointer z-30"
833
- }
834
- ),
835
- /* @__PURE__ */ jsx(
836
- "div",
837
- {
838
- className: "absolute w-5 h-5 rounded-full bg-white border-2 border-[var(--ui-primary)] shadow-md pointer-events-none -translate-x-1/2 z-10",
839
- style: { left: `${minPercentage}%` }
840
- }
841
- ),
842
- /* @__PURE__ */ jsx(
843
- "div",
844
- {
845
- className: "absolute w-5 h-5 rounded-full bg-white border-2 border-[var(--ui-primary)] shadow-md pointer-events-none -translate-x-1/2 z-10",
846
- style: { left: `${maxPercentage}%` }
847
- }
848
- )
849
- ] }),
850
- showValue && /* @__PURE__ */ jsxs("span", { className: "text-xs font-semibold font-mono text-[var(--ui-text-secondary)] min-w-[5rem] text-right", children: [
851
- formatValue(minVal),
852
- " - ",
853
- formatValue(maxVal)
854
- ] })
855
- ] });
803
+ ),
804
+ showValue && /* @__PURE__ */ jsxs("span", { className: "text-xs font-semibold font-mono text-[var(--ui-text-secondary)] min-w-[5rem] text-right", children: [
805
+ formatValue(minVal),
806
+ " - ",
807
+ formatValue(maxVal)
808
+ ] })
809
+ ]
810
+ }
811
+ );
856
812
  }
857
813
  );
858
814
  RangeSlider.displayName = "RangeSlider";
@@ -870,16 +826,13 @@ var PinInput = forwardRef(
870
826
  autoFocus = false,
871
827
  ...props
872
828
  }, ref) => {
873
- const [pins, setPins] = useState(() => {
829
+ const isControlled = controlledValue !== void 0;
830
+ const [internalPins, setInternalPins] = useState(() => {
874
831
  const initial = (controlledValue !== void 0 ? controlledValue : defaultValue).slice(0, length);
875
832
  return Array.from({ length }, (_, i) => initial[i] || "");
876
833
  });
834
+ const pins = isControlled ? Array.from({ length }, (_, i) => controlledValue[i] || "") : internalPins;
877
835
  const inputsRef = useRef([]);
878
- useEffect(() => {
879
- if (controlledValue !== void 0) {
880
- setPins(Array.from({ length }, (_, i) => controlledValue[i] || ""));
881
- }
882
- }, [controlledValue, length]);
883
836
  useEffect(() => {
884
837
  if (autoFocus && inputsRef.current[0]) {
885
838
  inputsRef.current[0].focus();
@@ -889,7 +842,9 @@ var PinInput = forwardRef(
889
842
  const sanitized = val.replace(/[^0-9a-zA-Z]/g, "").slice(-1);
890
843
  const newPins = [...pins];
891
844
  newPins[index] = sanitized;
892
- setPins(newPins);
845
+ if (!isControlled) {
846
+ setInternalPins(newPins);
847
+ }
893
848
  const combined = newPins.join("");
894
849
  onChange?.(combined);
895
850
  if (sanitized && index < length - 1) {
@@ -900,16 +855,28 @@ var PinInput = forwardRef(
900
855
  }
901
856
  };
902
857
  const handleKeyDown = (index, e) => {
903
- if (e.key === "Backspace" && !pins[index] && index > 0) {
858
+ if (e.key === "Backspace") {
859
+ if (!pins[index] && index > 0) {
860
+ const newPins = [...pins];
861
+ newPins[index - 1] = "";
862
+ if (!isControlled) setInternalPins(newPins);
863
+ onChange?.(newPins.join(""));
864
+ inputsRef.current[index - 1]?.focus();
865
+ }
866
+ } else if (e.key === "ArrowLeft" && index > 0) {
867
+ e.preventDefault();
904
868
  inputsRef.current[index - 1]?.focus();
869
+ } else if (e.key === "ArrowRight" && index < length - 1) {
870
+ e.preventDefault();
871
+ inputsRef.current[index + 1]?.focus();
905
872
  }
906
873
  };
907
874
  const handlePaste = (e) => {
908
875
  e.preventDefault();
909
- const pasted = e.clipboardData.getData("text").slice(0, length);
876
+ const pasted = e.clipboardData.getData("text").replace(/[^0-9a-zA-Z]/g, "").slice(0, length);
910
877
  if (!pasted) return;
911
878
  const newPins = Array.from({ length }, (_, i) => pasted[i] || "");
912
- setPins(newPins);
879
+ if (!isControlled) setInternalPins(newPins);
913
880
  const combined = newPins.join("");
914
881
  onChange?.(combined);
915
882
  const nextEmptyIndex = newPins.findIndex((p) => !p);
@@ -929,6 +896,7 @@ var PinInput = forwardRef(
929
896
  inputMode: "numeric",
930
897
  maxLength: 1,
931
898
  disabled,
899
+ "aria-label": `Digit ${index + 1} of ${length}`,
932
900
  value: pins[index],
933
901
  onChange: (e) => handleDigitChange(index, e.target.value),
934
902
  onKeyDown: (e) => handleKeyDown(index, e),
@@ -957,7 +925,7 @@ function formatDisplayDate(d) {
957
925
  var DatePicker = forwardRef(
958
926
  ({
959
927
  value: controlledValue,
960
- defaultValue,
928
+ defaultValue = null,
961
929
  onChange,
962
930
  placeholder = "Select date...",
963
931
  minDate,
@@ -967,26 +935,28 @@ var DatePicker = forwardRef(
967
935
  className,
968
936
  presets
969
937
  }, ref) => {
970
- const [internalDate, setInternalDate] = useState(
971
- defaultValue !== void 0 ? defaultValue : null
972
- );
973
- const selectedDate = controlledValue !== void 0 ? controlledValue : internalDate;
938
+ const [selectedDate, setSelectedDate] = useControllableState({
939
+ value: controlledValue,
940
+ defaultValue,
941
+ onChange,
942
+ name: "DatePicker"
943
+ });
974
944
  const [viewDate, setViewDate] = useState(selectedDate || /* @__PURE__ */ new Date());
975
945
  const [isOpen, setIsOpen] = useState(false);
946
+ const [focusedDate, setFocusedDate] = useState(selectedDate || /* @__PURE__ */ new Date());
976
947
  useEffect(() => {
977
948
  if (selectedDate) {
978
949
  setViewDate(selectedDate);
950
+ setFocusedDate(selectedDate);
979
951
  }
980
952
  }, [selectedDate]);
981
953
  const handleSelectDate = (d) => {
982
- setInternalDate(d);
983
- onChange?.(d);
954
+ setSelectedDate(d);
984
955
  setIsOpen(false);
985
956
  };
986
957
  const handleClear = (e) => {
987
958
  e.stopPropagation();
988
- setInternalDate(null);
989
- onChange?.(null);
959
+ setSelectedDate(null);
990
960
  };
991
961
  const prevMonth = () => {
992
962
  setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1));
@@ -1019,20 +989,68 @@ var DatePicker = forwardRef(
1019
989
  }
1020
990
  const todayStr = formatDate(/* @__PURE__ */ new Date());
1021
991
  const selectedStr = selectedDate ? formatDate(selectedDate) : "";
992
+ const focusedStr = formatDate(focusedDate);
993
+ const handleGridKeyDown = (e) => {
994
+ let nextDate = new Date(focusedDate);
995
+ let handled = false;
996
+ if (e.key === "ArrowLeft") {
997
+ nextDate.setDate(nextDate.getDate() - 1);
998
+ handled = true;
999
+ } else if (e.key === "ArrowRight") {
1000
+ nextDate.setDate(nextDate.getDate() + 1);
1001
+ handled = true;
1002
+ } else if (e.key === "ArrowUp") {
1003
+ nextDate.setDate(nextDate.getDate() - 7);
1004
+ handled = true;
1005
+ } else if (e.key === "ArrowDown") {
1006
+ nextDate.setDate(nextDate.getDate() + 7);
1007
+ handled = true;
1008
+ } else if (e.key === "PageUp") {
1009
+ nextDate.setMonth(nextDate.getMonth() - 1);
1010
+ handled = true;
1011
+ } else if (e.key === "PageDown") {
1012
+ nextDate.setMonth(nextDate.getMonth() + 1);
1013
+ handled = true;
1014
+ } else if (e.key === "Home") {
1015
+ nextDate.setDate(1);
1016
+ handled = true;
1017
+ } else if (e.key === "End") {
1018
+ const lastDay = new Date(nextDate.getFullYear(), nextDate.getMonth() + 1, 0).getDate();
1019
+ nextDate.setDate(lastDay);
1020
+ handled = true;
1021
+ } else if (e.key === "Enter" || e.key === " ") {
1022
+ e.preventDefault();
1023
+ handleSelectDate(focusedDate);
1024
+ return;
1025
+ } else if (e.key === "Escape") {
1026
+ e.preventDefault();
1027
+ setIsOpen(false);
1028
+ return;
1029
+ }
1030
+ if (handled) {
1031
+ e.preventDefault();
1032
+ setFocusedDate(nextDate);
1033
+ if (nextDate.getMonth() !== viewDate.getMonth() || nextDate.getFullYear() !== viewDate.getFullYear()) {
1034
+ setViewDate(new Date(nextDate.getFullYear(), nextDate.getMonth(), 1));
1035
+ }
1036
+ }
1037
+ };
1022
1038
  return /* @__PURE__ */ jsx("div", { ref, className: cn("relative inline-block w-full", className), children: /* @__PURE__ */ jsx(
1023
1039
  Popover,
1024
1040
  {
1025
- isOpen,
1026
- onClose: () => setIsOpen(false),
1041
+ open: isOpen,
1042
+ onOpenChange: setIsOpen,
1027
1043
  trigger: /* @__PURE__ */ jsxs(
1028
1044
  "button",
1029
1045
  {
1030
1046
  type: "button",
1031
1047
  disabled,
1032
- onClick: () => !disabled && setIsOpen(!isOpen),
1048
+ "aria-haspopup": "dialog",
1049
+ "aria-expanded": isOpen,
1050
+ "aria-label": selectedDate ? `Selected date: ${formatDisplayDate(selectedDate)}` : placeholder,
1033
1051
  className: cn(
1034
- "w-full h-10 px-3.5 rounded-[var(--ui-radius-md)] border bg-[var(--ui-bg-surface)] text-left flex items-center justify-between text-sm transition-all shadow-inner cursor-pointer",
1035
- disabled ? "opacity-50 cursor-not-allowed border-[var(--ui-border-subtle)]" : "border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)] focus:ring-2 focus:ring-[var(--ui-primary)]/50"
1052
+ "w-full h-10 px-3.5 rounded-[var(--ui-radius-md)] border bg-[var(--ui-bg-surface)] text-left flex items-center justify-between text-sm transition-all shadow-inner cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
1053
+ disabled ? "opacity-50 cursor-not-allowed border-[var(--ui-border-subtle)]" : "border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)]"
1036
1054
  ),
1037
1055
  children: [
1038
1056
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 truncate", children: [
@@ -1042,7 +1060,11 @@ var DatePicker = forwardRef(
1042
1060
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 text-[var(--ui-text-muted)]", children: clearable && selectedDate && !disabled && /* @__PURE__ */ jsx(
1043
1061
  "span",
1044
1062
  {
1063
+ role: "button",
1064
+ tabIndex: 0,
1065
+ "aria-label": "Clear date",
1045
1066
  onClick: handleClear,
1067
+ onKeyDown: (e) => e.key === "Enter" && handleClear(e),
1046
1068
  className: "p-1 rounded-full hover:bg-[var(--ui-bg-tertiary)] hover:text-[var(--ui-text-primary)] transition-colors",
1047
1069
  children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5" })
1048
1070
  }
@@ -1050,74 +1072,131 @@ var DatePicker = forwardRef(
1050
1072
  ]
1051
1073
  }
1052
1074
  ),
1053
- children: /* @__PURE__ */ jsxs("div", { className: "p-4 w-72 rounded-2xl bg-[var(--ui-bg-surface)] backdrop-blur-2xl border border-[var(--ui-border-default)] shadow-2xl space-y-3", children: [
1054
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1055
- /* @__PURE__ */ jsx("span", { className: "text-xs font-bold text-[var(--ui-text-primary)] font-mono uppercase tracking-wider", children: viewDate.toLocaleString("default", { month: "long", year: "numeric" }) }),
1056
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1057
- /* @__PURE__ */ jsx(
1075
+ children: /* @__PURE__ */ jsxs(
1076
+ "div",
1077
+ {
1078
+ role: "dialog",
1079
+ "aria-label": "Choose date",
1080
+ className: "p-4 w-72 rounded-2xl bg-[var(--ui-bg-surface)] backdrop-blur-2xl border border-[var(--ui-border-default)] shadow-2xl space-y-3",
1081
+ onKeyDown: handleGridKeyDown,
1082
+ children: [
1083
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1084
+ /* @__PURE__ */ jsx(
1085
+ "span",
1086
+ {
1087
+ id: "calendar-month-heading",
1088
+ className: "text-xs font-bold text-[var(--ui-text-primary)] font-mono uppercase tracking-wider",
1089
+ "aria-live": "polite",
1090
+ children: viewDate.toLocaleString("default", { month: "long", year: "numeric" })
1091
+ }
1092
+ ),
1093
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1094
+ /* @__PURE__ */ jsx(
1095
+ "button",
1096
+ {
1097
+ type: "button",
1098
+ onClick: prevMonth,
1099
+ "aria-label": "Previous month",
1100
+ className: "p-1 rounded-lg hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors cursor-pointer",
1101
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" })
1102
+ }
1103
+ ),
1104
+ /* @__PURE__ */ jsx(
1105
+ "button",
1106
+ {
1107
+ type: "button",
1108
+ onClick: nextMonth,
1109
+ "aria-label": "Next month",
1110
+ className: "p-1 rounded-lg hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors cursor-pointer",
1111
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" })
1112
+ }
1113
+ )
1114
+ ] })
1115
+ ] }),
1116
+ presets && presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 pb-2 border-b border-[var(--ui-border-subtle)]", children: presets.map((preset, idx) => /* @__PURE__ */ jsx(
1058
1117
  "button",
1059
1118
  {
1060
1119
  type: "button",
1061
- onClick: prevMonth,
1062
- className: "p-1 rounded-lg hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors",
1063
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" })
1120
+ onClick: () => handleSelectDate(preset.date),
1121
+ className: "px-2 py-0.5 rounded-md text-[10px] font-semibold bg-[var(--ui-bg-secondary)] hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-secondary)] transition-colors cursor-pointer",
1122
+ children: preset.label
1123
+ },
1124
+ idx
1125
+ )) }),
1126
+ /* @__PURE__ */ jsx(
1127
+ "div",
1128
+ {
1129
+ role: "row",
1130
+ className: "grid grid-cols-7 text-center text-[10px] font-bold text-[var(--ui-text-muted)] font-mono",
1131
+ children: [
1132
+ { short: "Su", full: "Sunday" },
1133
+ { short: "Mo", full: "Monday" },
1134
+ { short: "Tu", full: "Tuesday" },
1135
+ { short: "We", full: "Wednesday" },
1136
+ { short: "Th", full: "Thursday" },
1137
+ { short: "Fr", full: "Friday" },
1138
+ { short: "Sa", full: "Saturday" }
1139
+ ].map((d) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": d.full, className: "py-1", children: d.short }, d.short))
1064
1140
  }
1065
1141
  ),
1066
1142
  /* @__PURE__ */ jsx(
1067
- "button",
1143
+ "div",
1068
1144
  {
1069
- type: "button",
1070
- onClick: nextMonth,
1071
- className: "p-1 rounded-lg hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors",
1072
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" })
1145
+ role: "grid",
1146
+ "aria-labelledby": "calendar-month-heading",
1147
+ className: "grid grid-cols-7 gap-1",
1148
+ children: days.map((item, idx) => {
1149
+ const itemStr = formatDate(item.date);
1150
+ const isSelected = itemStr === selectedStr;
1151
+ const isToday = itemStr === todayStr;
1152
+ const isFocused = itemStr === focusedStr;
1153
+ const fullDateLabel = item.date.toLocaleDateString("en-US", {
1154
+ weekday: "long",
1155
+ year: "numeric",
1156
+ month: "long",
1157
+ day: "numeric"
1158
+ });
1159
+ return /* @__PURE__ */ jsx(
1160
+ "button",
1161
+ {
1162
+ type: "button",
1163
+ role: "gridcell",
1164
+ disabled: item.disabled,
1165
+ "aria-selected": isSelected,
1166
+ "aria-current": isToday ? "date" : void 0,
1167
+ "aria-label": fullDateLabel,
1168
+ tabIndex: isFocused ? 0 : -1,
1169
+ onClick: () => handleSelectDate(item.date),
1170
+ className: cn(
1171
+ "h-8 w-8 rounded-full text-xs font-semibold flex items-center justify-center transition-all cursor-pointer outline-none",
1172
+ item.disabled && "opacity-25 cursor-not-allowed pointer-events-none",
1173
+ !item.currentMonth && "text-[var(--ui-text-muted)] opacity-50",
1174
+ isFocused && "ring-2 ring-[var(--ui-primary)]",
1175
+ isSelected ? "bg-[var(--ui-primary)] text-white font-bold shadow-md shadow-blue-500/30" : isToday ? "border border-[var(--ui-primary)] text-[var(--ui-primary)]" : "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1176
+ ),
1177
+ children: item.date.getDate()
1178
+ },
1179
+ idx
1180
+ );
1181
+ })
1073
1182
  }
1074
1183
  )
1075
- ] })
1076
- ] }),
1077
- presets && presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 pb-2 border-b border-[var(--ui-border-subtle)]", children: presets.map((preset, idx) => /* @__PURE__ */ jsx(
1078
- "button",
1079
- {
1080
- type: "button",
1081
- onClick: () => handleSelectDate(preset.date),
1082
- className: "px-2 py-0.5 rounded-md text-[10px] font-semibold bg-[var(--ui-bg-secondary)] hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-secondary)] transition-colors",
1083
- children: preset.label
1084
- },
1085
- idx
1086
- )) }),
1087
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 text-center text-[10px] font-bold text-[var(--ui-text-muted)] font-mono", children: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((d) => /* @__PURE__ */ jsx("div", { className: "py-1", children: d }, d)) }),
1088
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((item, idx) => {
1089
- const itemStr = formatDate(item.date);
1090
- const isSelected = itemStr === selectedStr;
1091
- const isToday = itemStr === todayStr;
1092
- return /* @__PURE__ */ jsx(
1093
- "button",
1094
- {
1095
- type: "button",
1096
- disabled: item.disabled,
1097
- onClick: () => handleSelectDate(item.date),
1098
- className: cn(
1099
- "h-8 w-8 rounded-full text-xs font-semibold flex items-center justify-center transition-all cursor-pointer",
1100
- item.disabled && "opacity-25 cursor-not-allowed pointer-events-none",
1101
- !item.currentMonth && "text-[var(--ui-text-muted)] opacity-50",
1102
- isSelected ? "bg-[var(--ui-primary)] text-white font-bold shadow-md shadow-blue-500/30" : isToday ? "border border-[var(--ui-primary)] text-[var(--ui-primary)]" : "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1103
- ),
1104
- children: item.date.getDate()
1105
- },
1106
- idx
1107
- );
1108
- }) })
1109
- ] })
1184
+ ]
1185
+ }
1186
+ )
1110
1187
  }
1111
1188
  ) });
1112
1189
  }
1113
1190
  );
1114
1191
  DatePicker.displayName = "DatePicker";
1115
1192
  var DateRangePicker = forwardRef(
1116
- ({ value: controlledVal, defaultValue, onChange, placeholder = "Select date range...", className, disabled = false }, ref) => {
1117
- const [internalRange, setInternalRange] = useState(
1118
- defaultValue || { from: null, to: null }
1119
- );
1120
- const range = controlledVal || internalRange;
1193
+ ({ value: controlledVal, defaultValue = { from: null, to: null }, onChange, placeholder = "Select date range...", className, disabled = false }, ref) => {
1194
+ const [range, setRange] = useControllableState({
1195
+ value: controlledVal,
1196
+ defaultValue,
1197
+ onChange,
1198
+ name: "DateRangePicker"
1199
+ });
1121
1200
  const [viewDate, setViewDate] = useState(range.from || /* @__PURE__ */ new Date());
1122
1201
  const [isOpen, setIsOpen] = useState(false);
1123
1202
  const handleDayClick = (d) => {
@@ -1132,8 +1211,7 @@ var DateRangePicker = forwardRef(
1132
1211
  setIsOpen(false);
1133
1212
  }
1134
1213
  }
1135
- setInternalRange(next);
1136
- onChange?.(next);
1214
+ setRange(next);
1137
1215
  };
1138
1216
  const displayText = range.from && range.to ? `${formatDisplayDate(range.from)} \u2013 ${formatDisplayDate(range.to)}` : range.from ? `${formatDisplayDate(range.from)} \u2013 ...` : placeholder;
1139
1217
  const year = viewDate.getFullYear();
@@ -1147,146 +1225,345 @@ var DateRangePicker = forwardRef(
1147
1225
  return /* @__PURE__ */ jsx("div", { ref, className: cn("relative inline-block w-full", className), children: /* @__PURE__ */ jsx(
1148
1226
  Popover,
1149
1227
  {
1150
- isOpen,
1151
- onClose: () => setIsOpen(false),
1228
+ open: isOpen,
1229
+ onOpenChange: setIsOpen,
1152
1230
  trigger: /* @__PURE__ */ jsx(
1153
1231
  "button",
1154
1232
  {
1155
1233
  type: "button",
1156
1234
  disabled,
1157
- onClick: () => !disabled && setIsOpen(!isOpen),
1158
- className: "w-full h-10 px-3.5 rounded-[var(--ui-radius-md)] border border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)] bg-[var(--ui-bg-surface)] text-left flex items-center justify-between text-sm shadow-inner cursor-pointer",
1235
+ "aria-haspopup": "dialog",
1236
+ "aria-expanded": isOpen,
1237
+ "aria-label": displayText,
1238
+ className: "w-full h-10 px-3.5 rounded-[var(--ui-radius-md)] border border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)] bg-[var(--ui-bg-surface)] text-left flex items-center justify-between text-sm shadow-inner cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
1159
1239
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 truncate", children: [
1160
1240
  /* @__PURE__ */ jsx(Calendar, { className: "w-4 h-4 text-[var(--ui-text-muted)] shrink-0" }),
1161
1241
  /* @__PURE__ */ jsx("span", { className: range.from ? "text-[var(--ui-text-primary)] font-medium" : "text-[var(--ui-text-muted)]", children: displayText })
1162
1242
  ] })
1163
1243
  }
1164
1244
  ),
1165
- children: /* @__PURE__ */ jsxs("div", { className: "p-4 w-76 rounded-2xl bg-[var(--ui-bg-surface)] backdrop-blur-2xl border border-[var(--ui-border-default)] shadow-2xl space-y-3", children: [
1166
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1167
- /* @__PURE__ */ jsx("span", { className: "text-xs font-bold text-[var(--ui-text-primary)] font-mono uppercase tracking-wider", children: viewDate.toLocaleString("default", { month: "long", year: "numeric" }) }),
1168
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1169
- /* @__PURE__ */ jsx(
1170
- "button",
1171
- {
1172
- type: "button",
1173
- onClick: () => setViewDate(new Date(year, month - 1, 1)),
1174
- className: "p-1 rounded-lg hover:bg-[var(--ui-bg-tertiary)]",
1175
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" })
1176
- }
1177
- ),
1178
- /* @__PURE__ */ jsx(
1179
- "button",
1245
+ children: /* @__PURE__ */ jsxs(
1246
+ "div",
1247
+ {
1248
+ role: "dialog",
1249
+ "aria-label": "Choose date range",
1250
+ className: "p-4 w-76 rounded-2xl bg-[var(--ui-bg-surface)] backdrop-blur-2xl border border-[var(--ui-border-default)] shadow-2xl space-y-3",
1251
+ children: [
1252
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1253
+ /* @__PURE__ */ jsx("span", { id: "range-month-heading", className: "text-xs font-bold text-[var(--ui-text-primary)] font-mono uppercase tracking-wider", children: viewDate.toLocaleString("default", { month: "long", year: "numeric" }) }),
1254
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1255
+ /* @__PURE__ */ jsx(
1256
+ "button",
1257
+ {
1258
+ type: "button",
1259
+ onClick: () => setViewDate(new Date(year, month - 1, 1)),
1260
+ "aria-label": "Previous month",
1261
+ className: "p-1 rounded-lg hover:bg-[var(--ui-bg-tertiary)] cursor-pointer",
1262
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" })
1263
+ }
1264
+ ),
1265
+ /* @__PURE__ */ jsx(
1266
+ "button",
1267
+ {
1268
+ type: "button",
1269
+ onClick: () => setViewDate(new Date(year, month + 1, 1)),
1270
+ "aria-label": "Next month",
1271
+ className: "p-1 rounded-lg hover:bg-[var(--ui-bg-tertiary)] cursor-pointer",
1272
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" })
1273
+ }
1274
+ )
1275
+ ] })
1276
+ ] }),
1277
+ /* @__PURE__ */ jsxs(
1278
+ "div",
1180
1279
  {
1181
- type: "button",
1182
- onClick: () => setViewDate(new Date(year, month + 1, 1)),
1183
- className: "p-1 rounded-lg hover:bg-[var(--ui-bg-tertiary)]",
1184
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" })
1280
+ role: "grid",
1281
+ "aria-labelledby": "range-month-heading",
1282
+ className: "grid grid-cols-7 gap-1 text-center",
1283
+ children: [
1284
+ Array.from({ length: firstDayIndex }).map((_, i) => /* @__PURE__ */ jsx("div", {}, `empty-${i}`)),
1285
+ days.map((d, idx) => {
1286
+ const dStr = formatDate(d);
1287
+ const fromStr = range.from ? formatDate(range.from) : "";
1288
+ const toStr = range.to ? formatDate(range.to) : "";
1289
+ const isFrom = dStr === fromStr;
1290
+ const isTo = dStr === toStr;
1291
+ const isInRange = range.from && range.to && d > range.from && d < range.to;
1292
+ return /* @__PURE__ */ jsx(
1293
+ "button",
1294
+ {
1295
+ type: "button",
1296
+ role: "gridcell",
1297
+ "aria-selected": Boolean(isFrom || isTo || isInRange),
1298
+ "aria-label": d.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" }),
1299
+ onClick: () => handleDayClick(d),
1300
+ className: cn(
1301
+ "h-8 w-8 rounded-full text-xs font-semibold flex items-center justify-center transition-all cursor-pointer",
1302
+ (isFrom || isTo) && "bg-[var(--ui-primary)] text-white shadow-md",
1303
+ isInRange && "bg-[var(--ui-primary)]/20 text-[var(--ui-primary)] rounded-none",
1304
+ !isFrom && !isTo && !isInRange && "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1305
+ ),
1306
+ children: d.getDate()
1307
+ },
1308
+ idx
1309
+ );
1310
+ })
1311
+ ]
1185
1312
  }
1186
1313
  )
1187
- ] })
1188
- ] }),
1189
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-7 gap-1 text-center", children: [
1190
- Array.from({ length: firstDayIndex }).map((_, i) => /* @__PURE__ */ jsx("div", {}, `empty-${i}`)),
1191
- days.map((d, idx) => {
1192
- const dStr = formatDate(d);
1193
- const fromStr = range.from ? formatDate(range.from) : "";
1194
- const toStr = range.to ? formatDate(range.to) : "";
1195
- const isFrom = dStr === fromStr;
1196
- const isTo = dStr === toStr;
1197
- const isInRange = range.from && range.to && d > range.from && d < range.to;
1198
- return /* @__PURE__ */ jsx(
1199
- "button",
1200
- {
1201
- type: "button",
1202
- onClick: () => handleDayClick(d),
1203
- className: cn(
1204
- "h-8 w-8 rounded-full text-xs font-semibold flex items-center justify-center transition-all cursor-pointer",
1205
- (isFrom || isTo) && "bg-[var(--ui-primary)] text-white shadow-md",
1206
- isInRange && "bg-[var(--ui-primary)]/20 text-[var(--ui-primary)] rounded-none",
1207
- !isFrom && !isTo && !isInRange && "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1208
- ),
1209
- children: d.getDate()
1210
- },
1211
- idx
1212
- );
1213
- })
1214
- ] })
1215
- ] })
1314
+ ]
1315
+ }
1316
+ )
1216
1317
  }
1217
1318
  ) });
1218
1319
  }
1219
1320
  );
1220
1321
  DateRangePicker.displayName = "DateRangePicker";
1221
1322
  var TimePicker = forwardRef(
1222
- ({ value: controlledVal, defaultValue = "12:00", onChange, format = "24h", className, disabled = false }, ref) => {
1223
- const [internalTime, setInternalTime] = useState(defaultValue);
1224
- const time = controlledVal !== void 0 ? controlledVal : internalTime;
1225
- const [hours, setHours] = useState(time.split(":")[0] || "12");
1226
- const [minutes, setMinutes] = useState(time.split(":")[1] || "00");
1323
+ ({
1324
+ value: controlledVal,
1325
+ defaultValue,
1326
+ onChange,
1327
+ format = "24h",
1328
+ className,
1329
+ disabled = false,
1330
+ placeholder = "Select time..."
1331
+ }, ref) => {
1332
+ const is12h = format === "12h";
1333
+ const fallbackDefault = defaultValue ?? (is12h ? "12:00 PM" : "12:00");
1334
+ const [time, setTime] = useControllableState({
1335
+ value: controlledVal,
1336
+ defaultValue: fallbackDefault,
1337
+ onChange,
1338
+ name: "TimePicker"
1339
+ });
1227
1340
  const [isOpen, setIsOpen] = useState(false);
1228
- const updateTime = (newH, newM) => {
1229
- const full = `${newH.padStart(2, "0")}:${newM.padStart(2, "0")}`;
1230
- setHours(newH);
1231
- setMinutes(newM);
1232
- setInternalTime(full);
1233
- onChange?.(full);
1341
+ const parseTime = (str, is12) => {
1342
+ if (!str) return { hours: is12 ? "12" : "12", minutes: "00", period: "AM" };
1343
+ const trimmed = str.trim();
1344
+ let period2 = "AM";
1345
+ let cleanTime = trimmed;
1346
+ if (trimmed.toLowerCase().includes("pm")) {
1347
+ period2 = "PM";
1348
+ cleanTime = trimmed.replace(/pm/i, "").trim();
1349
+ } else if (trimmed.toLowerCase().includes("am")) {
1350
+ period2 = "AM";
1351
+ cleanTime = trimmed.replace(/am/i, "").trim();
1352
+ }
1353
+ const parts = cleanTime.split(":");
1354
+ let h = parts[0] ? parts[0].padStart(2, "0") : is12 ? "12" : "00";
1355
+ const m = parts[1] ? parts[1].padStart(2, "0") : "00";
1356
+ return { hours: h, minutes: m, period: period2 };
1357
+ };
1358
+ const { hours, minutes, period } = parseTime(time, is12h);
1359
+ const updateTime = (newH, newM, newPeriod) => {
1360
+ let formatted;
1361
+ if (is12h) {
1362
+ const p = newPeriod ?? period;
1363
+ formatted = `${newH.padStart(2, "0")}:${newM.padStart(2, "0")} ${p}`;
1364
+ } else {
1365
+ formatted = `${newH.padStart(2, "0")}:${newM.padStart(2, "0")}`;
1366
+ }
1367
+ setTime(formatted);
1368
+ };
1369
+ const hourOptions = is12h ? Array.from({ length: 12 }, (_, i) => String(i + 1).padStart(2, "0")) : Array.from({ length: 24 }, (_, i) => String(i).padStart(2, "0"));
1370
+ const minuteOptions = ["00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55"];
1371
+ const hourListRef = useRef(null);
1372
+ const minuteListRef = useRef(null);
1373
+ const periodListRef = useRef(null);
1374
+ useEffect(() => {
1375
+ if (isOpen) {
1376
+ const timer = setTimeout(() => {
1377
+ const activeHourEl = hourListRef.current?.querySelector('[aria-selected="true"]');
1378
+ activeHourEl?.focus();
1379
+ }, 10);
1380
+ return () => clearTimeout(timer);
1381
+ }
1382
+ }, [isOpen]);
1383
+ const handleHourKeyDown = (e) => {
1384
+ const idx = hourOptions.indexOf(hours);
1385
+ if (e.key === "ArrowDown") {
1386
+ e.preventDefault();
1387
+ const next = hourOptions[(idx + 1) % hourOptions.length];
1388
+ updateTime(next, minutes, period);
1389
+ } else if (e.key === "ArrowUp") {
1390
+ e.preventDefault();
1391
+ const prev = hourOptions[(idx - 1 + hourOptions.length) % hourOptions.length];
1392
+ updateTime(prev, minutes, period);
1393
+ } else if (e.key === "ArrowRight") {
1394
+ e.preventDefault();
1395
+ const activeMinEl = minuteListRef.current?.querySelector('[aria-selected="true"]') || minuteListRef.current?.querySelector('[role="option"]');
1396
+ activeMinEl?.focus();
1397
+ } else if (e.key === "Escape") {
1398
+ e.preventDefault();
1399
+ setIsOpen(false);
1400
+ }
1401
+ };
1402
+ const handleMinuteKeyDown = (e) => {
1403
+ const idx = minuteOptions.indexOf(minutes);
1404
+ if (e.key === "ArrowDown") {
1405
+ e.preventDefault();
1406
+ const next = minuteOptions[(idx + 1) % minuteOptions.length];
1407
+ updateTime(hours, next, period);
1408
+ } else if (e.key === "ArrowUp") {
1409
+ e.preventDefault();
1410
+ const prev = minuteOptions[(idx - 1 + minuteOptions.length) % minuteOptions.length];
1411
+ updateTime(hours, prev, period);
1412
+ } else if (e.key === "ArrowLeft") {
1413
+ e.preventDefault();
1414
+ const activeHourEl = hourListRef.current?.querySelector('[aria-selected="true"]');
1415
+ activeHourEl?.focus();
1416
+ } else if (e.key === "ArrowRight" && is12h) {
1417
+ e.preventDefault();
1418
+ const activePeriodEl = periodListRef.current?.querySelector('[aria-selected="true"]');
1419
+ activePeriodEl?.focus();
1420
+ } else if (e.key === "Escape") {
1421
+ e.preventDefault();
1422
+ setIsOpen(false);
1423
+ }
1424
+ };
1425
+ const handlePeriodKeyDown = (e) => {
1426
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
1427
+ e.preventDefault();
1428
+ const next = period === "AM" ? "PM" : "AM";
1429
+ updateTime(hours, minutes, next);
1430
+ } else if (e.key === "ArrowLeft") {
1431
+ e.preventDefault();
1432
+ const activeMinEl = minuteListRef.current?.querySelector('[aria-selected="true"]');
1433
+ activeMinEl?.focus();
1434
+ } else if (e.key === "Escape") {
1435
+ e.preventDefault();
1436
+ setIsOpen(false);
1437
+ }
1234
1438
  };
1235
1439
  return /* @__PURE__ */ jsx("div", { ref, className: cn("relative inline-block w-full", className), children: /* @__PURE__ */ jsx(
1236
1440
  Popover,
1237
1441
  {
1238
- isOpen,
1239
- onClose: () => setIsOpen(false),
1442
+ open: isOpen,
1443
+ onOpenChange: setIsOpen,
1240
1444
  trigger: /* @__PURE__ */ jsx(
1241
1445
  "button",
1242
1446
  {
1243
1447
  type: "button",
1244
1448
  disabled,
1245
- onClick: () => !disabled && setIsOpen(!isOpen),
1246
- className: "w-full h-10 px-3.5 rounded-[var(--ui-radius-md)] border border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)] bg-[var(--ui-bg-surface)] text-left flex items-center justify-between text-sm shadow-inner cursor-pointer",
1449
+ "aria-haspopup": "dialog",
1450
+ "aria-expanded": isOpen,
1451
+ "aria-label": `Selected time: ${time}`,
1452
+ className: cn(
1453
+ "w-full h-10 px-3.5 rounded-[var(--ui-radius-md)] border border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)] bg-[var(--ui-bg-surface)] text-left flex items-center justify-between text-sm shadow-inner transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
1454
+ disabled && "opacity-50 cursor-not-allowed"
1455
+ ),
1247
1456
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
1248
- /* @__PURE__ */ jsx(Clock, { className: "w-4 h-4 text-[var(--ui-text-muted)]" }),
1249
- /* @__PURE__ */ jsx("span", { className: "font-mono text-sm font-semibold text-[var(--ui-text-primary)]", children: time })
1457
+ /* @__PURE__ */ jsx(Clock, { className: "w-4 h-4 text-[var(--ui-text-muted)] shrink-0" }),
1458
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-sm font-semibold text-[var(--ui-text-primary)]", children: time || placeholder })
1250
1459
  ] })
1251
1460
  }
1252
1461
  ),
1253
- children: /* @__PURE__ */ jsxs("div", { className: "p-4 w-52 rounded-2xl bg-[var(--ui-bg-surface)] backdrop-blur-2xl border border-[var(--ui-border-default)] shadow-2xl space-y-3", children: [
1254
- /* @__PURE__ */ jsxs("span", { className: "text-xs font-bold text-[var(--ui-text-muted)] uppercase tracking-wider font-mono", children: [
1255
- "Select Time (",
1256
- format,
1257
- ")"
1258
- ] }),
1259
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2", children: [
1260
- /* @__PURE__ */ jsx("div", { className: "h-36 overflow-y-auto border border-[var(--ui-border-subtle)] rounded-xl p-1 w-16 text-center space-y-1", children: Array.from({ length: 24 }).map((_, i) => {
1261
- const h = String(i).padStart(2, "0");
1262
- return /* @__PURE__ */ jsx(
1263
- "div",
1264
- {
1265
- onClick: () => updateTime(h, minutes),
1266
- className: cn(
1267
- "text-xs py-1 rounded-lg font-mono font-semibold cursor-pointer transition-colors",
1268
- hours === h ? "bg-[var(--ui-primary)] text-white" : "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1269
- ),
1270
- children: h
1271
- },
1272
- h
1273
- );
1274
- }) }),
1275
- /* @__PURE__ */ jsx("span", { className: "text-sm font-bold", children: ":" }),
1276
- /* @__PURE__ */ jsx("div", { className: "h-36 overflow-y-auto border border-[var(--ui-border-subtle)] rounded-xl p-1 w-16 text-center space-y-1", children: ["00", "05", "10", "15", "20", "25", "30", "35", "40", "41", "45", "50", "55"].map((m) => /* @__PURE__ */ jsx(
1277
- "div",
1278
- {
1279
- onClick: () => updateTime(hours, m),
1280
- className: cn(
1281
- "text-xs py-1 rounded-lg font-mono font-semibold cursor-pointer transition-colors",
1282
- minutes === m ? "bg-[var(--ui-primary)] text-white" : "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1462
+ children: /* @__PURE__ */ jsxs(
1463
+ "div",
1464
+ {
1465
+ role: "dialog",
1466
+ "aria-label": "Choose time",
1467
+ className: "p-4 rounded-2xl bg-[var(--ui-bg-surface)] backdrop-blur-2xl border border-[var(--ui-border-default)] shadow-2xl space-y-3",
1468
+ children: [
1469
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-bold text-[var(--ui-text-muted)] uppercase tracking-wider font-mono", children: [
1470
+ "Select Time (",
1471
+ format,
1472
+ ")"
1473
+ ] }),
1474
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2", children: [
1475
+ /* @__PURE__ */ jsx(
1476
+ "div",
1477
+ {
1478
+ ref: hourListRef,
1479
+ tabIndex: 0,
1480
+ onKeyDown: handleHourKeyDown,
1481
+ className: "h-40 overflow-y-auto border border-[var(--ui-border-subtle)] rounded-xl p-1 w-16 text-center space-y-1 focus:outline-none focus:ring-1 focus:ring-[var(--ui-primary)]",
1482
+ role: "listbox",
1483
+ "aria-label": "Hour",
1484
+ children: hourOptions.map((h) => {
1485
+ const isSelected = hours === h;
1486
+ return /* @__PURE__ */ jsx(
1487
+ "div",
1488
+ {
1489
+ tabIndex: isSelected ? 0 : -1,
1490
+ role: "option",
1491
+ "aria-selected": isSelected,
1492
+ onClick: () => updateTime(h, minutes, period),
1493
+ className: cn(
1494
+ "text-xs py-1 rounded-lg font-mono font-semibold cursor-pointer transition-colors select-none outline-none focus-visible:ring-1 focus-visible:ring-[var(--ui-primary)]",
1495
+ isSelected ? "bg-[var(--ui-primary)] text-white" : "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1496
+ ),
1497
+ children: h
1498
+ },
1499
+ h
1500
+ );
1501
+ })
1502
+ }
1283
1503
  ),
1284
- children: m
1285
- },
1286
- m
1287
- )) })
1288
- ] })
1289
- ] })
1504
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold", children: ":" }),
1505
+ /* @__PURE__ */ jsx(
1506
+ "div",
1507
+ {
1508
+ ref: minuteListRef,
1509
+ tabIndex: 0,
1510
+ onKeyDown: handleMinuteKeyDown,
1511
+ className: "h-40 overflow-y-auto border border-[var(--ui-border-subtle)] rounded-xl p-1 w-16 text-center space-y-1 focus:outline-none focus:ring-1 focus:ring-[var(--ui-primary)]",
1512
+ role: "listbox",
1513
+ "aria-label": "Minute",
1514
+ children: minuteOptions.map((m) => {
1515
+ const isSelected = minutes === m;
1516
+ return /* @__PURE__ */ jsx(
1517
+ "div",
1518
+ {
1519
+ tabIndex: isSelected ? 0 : -1,
1520
+ role: "option",
1521
+ "aria-selected": isSelected,
1522
+ onClick: () => updateTime(hours, m, period),
1523
+ className: cn(
1524
+ "text-xs py-1 rounded-lg font-mono font-semibold cursor-pointer transition-colors select-none outline-none focus-visible:ring-1 focus-visible:ring-[var(--ui-primary)]",
1525
+ isSelected ? "bg-[var(--ui-primary)] text-white" : "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1526
+ ),
1527
+ children: m
1528
+ },
1529
+ m
1530
+ );
1531
+ })
1532
+ }
1533
+ ),
1534
+ is12h && /* @__PURE__ */ jsx(
1535
+ "div",
1536
+ {
1537
+ ref: periodListRef,
1538
+ tabIndex: 0,
1539
+ onKeyDown: handlePeriodKeyDown,
1540
+ className: "h-40 border border-[var(--ui-border-subtle)] rounded-xl p-1 w-14 text-center space-y-1 flex flex-col justify-center focus:outline-none focus:ring-1 focus:ring-[var(--ui-primary)]",
1541
+ role: "listbox",
1542
+ "aria-label": "Period",
1543
+ children: ["AM", "PM"].map((p) => {
1544
+ const isSelected = period === p;
1545
+ return /* @__PURE__ */ jsx(
1546
+ "div",
1547
+ {
1548
+ tabIndex: isSelected ? 0 : -1,
1549
+ role: "option",
1550
+ "aria-selected": isSelected,
1551
+ onClick: () => updateTime(hours, minutes, p),
1552
+ className: cn(
1553
+ "text-xs py-2 rounded-lg font-mono font-semibold cursor-pointer transition-colors select-none outline-none focus-visible:ring-1 focus-visible:ring-[var(--ui-primary)]",
1554
+ isSelected ? "bg-[var(--ui-primary)] text-white" : "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1555
+ ),
1556
+ children: p
1557
+ },
1558
+ p
1559
+ );
1560
+ })
1561
+ }
1562
+ )
1563
+ ] })
1564
+ ]
1565
+ }
1566
+ )
1290
1567
  }
1291
1568
  ) });
1292
1569
  }
@@ -1303,135 +1580,205 @@ var Combobox = forwardRef(
1303
1580
  emptyText = "No items found.",
1304
1581
  disabled = false,
1305
1582
  clearable = true,
1306
- className
1583
+ className,
1584
+ name,
1585
+ id: customId,
1586
+ "aria-label": ariaLabel = "Select option"
1307
1587
  }, ref) => {
1588
+ const baseId = useId();
1589
+ const comboId = customId || `combobox-${baseId}`;
1590
+ const listboxId = `listbox-${baseId}`;
1308
1591
  const [internalVal, setInternalVal] = useState(defaultValue);
1309
- const selectedValue = controlledVal !== void 0 ? controlledVal : internalVal;
1592
+ const isControlled = controlledVal !== void 0;
1593
+ const selectedValue = isControlled ? controlledVal : internalVal;
1310
1594
  const [search, setSearch] = useState("");
1311
1595
  const [isOpen, setIsOpen] = useState(false);
1312
1596
  const [highlightIndex, setHighlightIndex] = useState(0);
1597
+ const searchInputRef = useRef(null);
1598
+ const triggerRef = useRef(null);
1313
1599
  const filteredOptions = options.filter(
1314
1600
  (opt) => opt.label.toLowerCase().includes(search.toLowerCase()) || opt.value.toLowerCase().includes(search.toLowerCase()) || opt.description && opt.description.toLowerCase().includes(search.toLowerCase())
1315
1601
  );
1316
1602
  const selectedOption = options.find((opt) => opt.value === selectedValue);
1603
+ useEffect(() => {
1604
+ if (filteredOptions.length > 0) {
1605
+ setHighlightIndex((prev) => Math.min(prev, filteredOptions.length - 1));
1606
+ }
1607
+ }, [filteredOptions.length]);
1317
1608
  const handleSelect = (val) => {
1318
- setInternalVal(val);
1609
+ if (!isControlled) {
1610
+ setInternalVal(val);
1611
+ }
1319
1612
  onChange?.(val);
1320
1613
  setIsOpen(false);
1321
1614
  setSearch("");
1615
+ triggerRef.current?.focus();
1322
1616
  };
1323
1617
  const handleClear = (e) => {
1324
1618
  e.stopPropagation();
1325
- setInternalVal("");
1619
+ if (!isControlled) {
1620
+ setInternalVal("");
1621
+ }
1326
1622
  onChange?.("");
1327
1623
  };
1328
1624
  const handleKeyDown = (e) => {
1329
1625
  if (!isOpen) {
1330
- if (e.key === "ArrowDown" || e.key === "Enter") {
1626
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
1627
+ e.preventDefault();
1331
1628
  setIsOpen(true);
1332
1629
  }
1333
1630
  return;
1334
1631
  }
1335
1632
  if (e.key === "ArrowDown") {
1336
1633
  e.preventDefault();
1337
- setHighlightIndex((prev) => (prev + 1) % Math.max(1, filteredOptions.length));
1634
+ let next = highlightIndex + 1;
1635
+ while (next < filteredOptions.length && filteredOptions[next]?.disabled) {
1636
+ next++;
1637
+ }
1638
+ if (next < filteredOptions.length) {
1639
+ setHighlightIndex(next);
1640
+ }
1338
1641
  } else if (e.key === "ArrowUp") {
1339
1642
  e.preventDefault();
1340
- setHighlightIndex((prev) => (prev - 1 + filteredOptions.length) % Math.max(1, filteredOptions.length));
1643
+ let prev = highlightIndex - 1;
1644
+ while (prev >= 0 && filteredOptions[prev]?.disabled) {
1645
+ prev--;
1646
+ }
1647
+ if (prev >= 0) {
1648
+ setHighlightIndex(prev);
1649
+ }
1650
+ } else if (e.key === "Home") {
1651
+ e.preventDefault();
1652
+ let first = 0;
1653
+ while (first < filteredOptions.length && filteredOptions[first]?.disabled) {
1654
+ first++;
1655
+ }
1656
+ setHighlightIndex(first);
1657
+ } else if (e.key === "End") {
1658
+ e.preventDefault();
1659
+ let last = filteredOptions.length - 1;
1660
+ while (last >= 0 && filteredOptions[last]?.disabled) {
1661
+ last--;
1662
+ }
1663
+ setHighlightIndex(last);
1341
1664
  } else if (e.key === "Enter") {
1342
1665
  e.preventDefault();
1343
- if (filteredOptions[highlightIndex] && !filteredOptions[highlightIndex].disabled) {
1344
- handleSelect(filteredOptions[highlightIndex].value);
1666
+ const highlighted = filteredOptions[highlightIndex];
1667
+ if (highlighted && !highlighted.disabled) {
1668
+ handleSelect(highlighted.value);
1345
1669
  }
1346
1670
  } else if (e.key === "Escape") {
1671
+ e.preventDefault();
1347
1672
  setIsOpen(false);
1673
+ triggerRef.current?.focus();
1348
1674
  }
1349
1675
  };
1350
- return /* @__PURE__ */ jsx("div", { ref, className: cn("relative w-full", className), children: /* @__PURE__ */ jsx(
1351
- Popover,
1352
- {
1353
- isOpen,
1354
- onClose: () => setIsOpen(false),
1355
- trigger: /* @__PURE__ */ jsxs(
1356
- "button",
1357
- {
1358
- type: "button",
1359
- disabled,
1360
- onClick: () => !disabled && setIsOpen(!isOpen),
1361
- onKeyDown: handleKeyDown,
1362
- className: cn(
1363
- "w-full h-10 px-3.5 rounded-[var(--ui-radius-md)] border bg-[var(--ui-bg-surface)] text-left flex items-center justify-between text-sm transition-all shadow-inner cursor-pointer",
1364
- disabled ? "opacity-50 cursor-not-allowed border-[var(--ui-border-subtle)]" : "border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)] focus:ring-2 focus:ring-[var(--ui-primary)]/50"
1365
- ),
1366
- children: [
1367
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 truncate", children: [
1368
- selectedOption?.icon,
1369
- /* @__PURE__ */ jsx("span", { className: selectedOption ? "text-[var(--ui-text-primary)] font-medium" : "text-[var(--ui-text-muted)]", children: selectedOption ? selectedOption.label : placeholder })
1370
- ] }),
1371
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-[var(--ui-text-muted)]", children: [
1372
- clearable && selectedValue && !disabled && /* @__PURE__ */ jsx(
1373
- "span",
1374
- {
1375
- onClick: handleClear,
1376
- className: "p-1 rounded-full hover:bg-[var(--ui-bg-tertiary)] hover:text-[var(--ui-text-primary)] transition-colors",
1377
- children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5" })
1378
- }
1379
- ),
1380
- /* @__PURE__ */ jsx(ChevronsUpDown, { className: "w-4 h-4 opacity-50 shrink-0" })
1381
- ] })
1382
- ]
1383
- }
1384
- ),
1385
- children: /* @__PURE__ */ jsxs("div", { className: "p-2 w-72 rounded-2xl bg-[var(--ui-bg-surface)] backdrop-blur-2xl border border-[var(--ui-border-default)] shadow-2xl space-y-2", children: [
1386
- /* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
1387
- /* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 w-3.5 h-3.5 text-[var(--ui-text-muted)] pointer-events-none" }),
1388
- /* @__PURE__ */ jsx(
1389
- "input",
1390
- {
1391
- type: "text",
1392
- autoFocus: true,
1393
- placeholder: searchPlaceholder,
1394
- value: search,
1395
- onChange: (e) => {
1396
- setSearch(e.target.value);
1397
- setHighlightIndex(0);
1676
+ const activeDescendantId = filteredOptions[highlightIndex] ? `combobox-opt-${baseId}-${filteredOptions[highlightIndex].value}` : void 0;
1677
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative w-full", className), children: [
1678
+ name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: selectedValue }),
1679
+ /* @__PURE__ */ jsx(
1680
+ Popover,
1681
+ {
1682
+ isOpen,
1683
+ onClose: () => setIsOpen(false),
1684
+ trigger: /* @__PURE__ */ jsxs(
1685
+ "button",
1686
+ {
1687
+ ref: triggerRef,
1688
+ id: comboId,
1689
+ type: "button",
1690
+ disabled,
1691
+ role: "combobox",
1692
+ "aria-expanded": isOpen,
1693
+ "aria-haspopup": "listbox",
1694
+ "aria-controls": isOpen ? listboxId : void 0,
1695
+ "aria-label": ariaLabel,
1696
+ onClick: () => !disabled && setIsOpen(!isOpen),
1697
+ onKeyDown: handleKeyDown,
1698
+ className: cn(
1699
+ "w-full h-10 px-3.5 rounded-[var(--ui-radius-md)] border bg-[var(--ui-bg-surface)] text-left flex items-center justify-between text-sm transition-all shadow-inner cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
1700
+ disabled ? "opacity-50 cursor-not-allowed border-[var(--ui-border-subtle)]" : "border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)]"
1701
+ ),
1702
+ children: [
1703
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 truncate", children: [
1704
+ selectedOption?.icon,
1705
+ /* @__PURE__ */ jsx("span", { className: selectedOption ? "text-[var(--ui-text-primary)] font-medium" : "text-[var(--ui-text-muted)]", children: selectedOption ? selectedOption.label : placeholder })
1706
+ ] }),
1707
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-[var(--ui-text-muted)]", children: [
1708
+ clearable && selectedValue && !disabled && /* @__PURE__ */ jsx(
1709
+ "span",
1710
+ {
1711
+ onClick: handleClear,
1712
+ className: "p-1 rounded-full hover:bg-[var(--ui-bg-tertiary)] hover:text-[var(--ui-text-primary)] transition-colors cursor-pointer",
1713
+ children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5" })
1714
+ }
1715
+ ),
1716
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "w-4 h-4 opacity-50 shrink-0" })
1717
+ ] })
1718
+ ]
1719
+ }
1720
+ ),
1721
+ children: /* @__PURE__ */ jsxs("div", { className: "p-2 w-72 rounded-2xl bg-[var(--ui-bg-surface)] backdrop-blur-2xl border border-[var(--ui-border-default)] shadow-2xl space-y-2", children: [
1722
+ /* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
1723
+ /* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 w-3.5 h-3.5 text-[var(--ui-text-muted)] pointer-events-none" }),
1724
+ /* @__PURE__ */ jsx(
1725
+ "input",
1726
+ {
1727
+ ref: searchInputRef,
1728
+ type: "text",
1729
+ autoFocus: true,
1730
+ placeholder: searchPlaceholder,
1731
+ value: search,
1732
+ onChange: (e) => {
1733
+ setSearch(e.target.value);
1734
+ setHighlightIndex(0);
1735
+ },
1736
+ onKeyDown: handleKeyDown,
1737
+ role: "combobox",
1738
+ "aria-autocomplete": "list",
1739
+ "aria-expanded": "true",
1740
+ "aria-controls": listboxId,
1741
+ "aria-activedescendant": activeDescendantId,
1742
+ className: "w-full h-8 pl-8 pr-3 text-xs rounded-xl bg-[var(--ui-bg-secondary)] border border-[var(--ui-border-subtle)] focus:outline-none focus:border-[var(--ui-primary)] text-[var(--ui-text-primary)] placeholder:text-[var(--ui-text-muted)]"
1743
+ }
1744
+ )
1745
+ ] }),
1746
+ /* @__PURE__ */ jsx("div", { id: listboxId, className: "max-h-56 overflow-y-auto space-y-0.5", role: "listbox", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-4 text-center text-xs text-[var(--ui-text-muted)]", children: emptyText }) : filteredOptions.map((opt, idx) => {
1747
+ const isSelected = opt.value === selectedValue;
1748
+ const isHighlighted = idx === highlightIndex;
1749
+ const optId = `combobox-opt-${baseId}-${opt.value}`;
1750
+ return /* @__PURE__ */ jsxs(
1751
+ "div",
1752
+ {
1753
+ id: optId,
1754
+ role: "option",
1755
+ "aria-selected": isSelected,
1756
+ "aria-disabled": opt.disabled,
1757
+ onClick: () => !opt.disabled && handleSelect(opt.value),
1758
+ onMouseEnter: () => !opt.disabled && setHighlightIndex(idx),
1759
+ className: cn(
1760
+ "flex items-center justify-between px-3 py-2 rounded-xl text-xs font-medium cursor-pointer transition-colors select-none",
1761
+ opt.disabled && "opacity-40 cursor-not-allowed pointer-events-none",
1762
+ isSelected ? "bg-[var(--ui-primary)] text-white font-semibold shadow-xs" : isHighlighted ? "bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]" : "text-[var(--ui-text-primary)]"
1763
+ ),
1764
+ children: [
1765
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
1766
+ opt.icon,
1767
+ /* @__PURE__ */ jsxs("div", { children: [
1768
+ /* @__PURE__ */ jsx("span", { className: "block truncate", children: opt.label }),
1769
+ opt.description && /* @__PURE__ */ jsx("span", { className: cn("text-[10px] block truncate", isSelected ? "text-white/80" : "text-[var(--ui-text-muted)]"), children: opt.description })
1770
+ ] })
1771
+ ] }),
1772
+ isSelected && /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5 shrink-0" })
1773
+ ]
1398
1774
  },
1399
- className: "w-full h-8 pl-8 pr-3 text-xs rounded-xl bg-[var(--ui-bg-secondary)] border border-[var(--ui-border-subtle)] focus:outline-none focus:border-[var(--ui-primary)] text-[var(--ui-text-primary)] placeholder:text-[var(--ui-text-muted)]"
1400
- }
1401
- )
1402
- ] }),
1403
- /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto space-y-0.5", role: "listbox", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-4 text-center text-xs text-[var(--ui-text-muted)]", children: emptyText }) : filteredOptions.map((opt, idx) => {
1404
- const isSelected = opt.value === selectedValue;
1405
- const isHighlighted = idx === highlightIndex;
1406
- return /* @__PURE__ */ jsxs(
1407
- "div",
1408
- {
1409
- role: "option",
1410
- "aria-selected": isSelected,
1411
- onClick: () => !opt.disabled && handleSelect(opt.value),
1412
- onMouseEnter: () => setHighlightIndex(idx),
1413
- className: cn(
1414
- "flex items-center justify-between px-3 py-2 rounded-xl text-xs font-medium cursor-pointer transition-colors",
1415
- opt.disabled && "opacity-40 cursor-not-allowed pointer-events-none",
1416
- isSelected ? "bg-[var(--ui-primary)] text-white font-semibold shadow-xs" : isHighlighted ? "bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]" : "text-[var(--ui-text-primary)]"
1417
- ),
1418
- children: [
1419
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
1420
- opt.icon,
1421
- /* @__PURE__ */ jsxs("div", { children: [
1422
- /* @__PURE__ */ jsx("span", { className: "block truncate", children: opt.label }),
1423
- opt.description && /* @__PURE__ */ jsx("span", { className: cn("text-[10px] block truncate", isSelected ? "text-white/80" : "text-[var(--ui-text-muted)]"), children: opt.description })
1424
- ] })
1425
- ] }),
1426
- isSelected && /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5 shrink-0" })
1427
- ]
1428
- },
1429
- opt.value
1430
- );
1431
- }) })
1432
- ] })
1433
- }
1434
- ) });
1775
+ opt.value
1776
+ );
1777
+ }) })
1778
+ ] })
1779
+ }
1780
+ )
1781
+ ] });
1435
1782
  }
1436
1783
  );
1437
1784
  Combobox.displayName = "Combobox";
@@ -1448,28 +1795,69 @@ var MultiSelect = forwardRef(
1448
1795
  className
1449
1796
  }, ref) => {
1450
1797
  const [internalVal, setInternalVal] = useState(defaultValue);
1451
- const selectedValues = controlledVal !== void 0 ? controlledVal : internalVal;
1798
+ const isControlled = controlledVal !== void 0;
1799
+ const selectedValues = isControlled ? controlledVal : internalVal;
1452
1800
  const [search, setSearch] = useState("");
1453
1801
  const [isOpen, setIsOpen] = useState(false);
1802
+ const [highlightedIndex, setHighlightedIndex] = useState(0);
1454
1803
  const filteredOptions = options.filter(
1455
1804
  (opt) => opt.label.toLowerCase().includes(search.toLowerCase()) || opt.value.toLowerCase().includes(search.toLowerCase())
1456
1805
  );
1457
1806
  const toggleOption = (val) => {
1807
+ const opt = options.find((o) => o.value === val);
1808
+ if (opt?.disabled) return;
1458
1809
  const next = selectedValues.includes(val) ? selectedValues.filter((v) => v !== val) : [...selectedValues, val];
1459
- setInternalVal(next);
1810
+ if (!isControlled) {
1811
+ setInternalVal(next);
1812
+ }
1460
1813
  onChange?.(next);
1461
1814
  };
1462
1815
  const removeTag = (val, e) => {
1463
1816
  e?.stopPropagation?.();
1464
1817
  const next = selectedValues.filter((v) => v !== val);
1465
- setInternalVal(next);
1818
+ if (!isControlled) {
1819
+ setInternalVal(next);
1820
+ }
1466
1821
  onChange?.(next);
1467
1822
  };
1468
1823
  const clearAll = (e) => {
1469
1824
  e?.stopPropagation?.();
1470
- setInternalVal([]);
1825
+ if (!isControlled) {
1826
+ setInternalVal([]);
1827
+ }
1471
1828
  onChange?.([]);
1472
1829
  };
1830
+ const handleSearchKeyDown = (e) => {
1831
+ if (filteredOptions.length === 0) return;
1832
+ if (e.key === "ArrowDown") {
1833
+ e.preventDefault();
1834
+ setHighlightedIndex((prev) => {
1835
+ let next = (prev + 1) % filteredOptions.length;
1836
+ while (filteredOptions[next]?.disabled && next !== prev) {
1837
+ next = (next + 1) % filteredOptions.length;
1838
+ }
1839
+ return next;
1840
+ });
1841
+ } else if (e.key === "ArrowUp") {
1842
+ e.preventDefault();
1843
+ setHighlightedIndex((prev) => {
1844
+ let next = (prev - 1 + filteredOptions.length) % filteredOptions.length;
1845
+ while (filteredOptions[next]?.disabled && next !== prev) {
1846
+ next = (next - 1 + filteredOptions.length) % filteredOptions.length;
1847
+ }
1848
+ return next;
1849
+ });
1850
+ } else if (e.key === "Enter" || e.key === " ") {
1851
+ e.preventDefault();
1852
+ const current = filteredOptions[highlightedIndex];
1853
+ if (current && !current.disabled) {
1854
+ toggleOption(current.value);
1855
+ }
1856
+ } else if (e.key === "Escape") {
1857
+ e.preventDefault();
1858
+ setIsOpen(false);
1859
+ }
1860
+ };
1473
1861
  return /* @__PURE__ */ jsx("div", { ref, className: cn("relative w-full", className), children: /* @__PURE__ */ jsx(
1474
1862
  Popover,
1475
1863
  {
@@ -1478,9 +1866,19 @@ var MultiSelect = forwardRef(
1478
1866
  trigger: /* @__PURE__ */ jsxs(
1479
1867
  "div",
1480
1868
  {
1869
+ tabIndex: disabled ? -1 : 0,
1870
+ role: "combobox",
1871
+ "aria-expanded": isOpen,
1872
+ "aria-haspopup": "listbox",
1481
1873
  onClick: () => !disabled && setIsOpen(!isOpen),
1874
+ onKeyDown: (e) => {
1875
+ if ((e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && !disabled) {
1876
+ e.preventDefault();
1877
+ setIsOpen(true);
1878
+ }
1879
+ },
1482
1880
  className: cn(
1483
- "min-h-10 py-1.5 px-3 rounded-[var(--ui-radius-md)] border bg-[var(--ui-bg-surface)] flex flex-wrap items-center justify-between gap-1.5 text-sm transition-all shadow-inner cursor-pointer",
1881
+ "min-h-10 py-1.5 px-3 rounded-[var(--ui-radius-md)] border bg-[var(--ui-bg-surface)] flex flex-wrap items-center justify-between gap-1.5 text-sm transition-all shadow-inner cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
1484
1882
  disabled ? "opacity-50 cursor-not-allowed border-[var(--ui-border-subtle)]" : "border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)]"
1485
1883
  ),
1486
1884
  children: [
@@ -1509,7 +1907,7 @@ var MultiSelect = forwardRef(
1509
1907
  "span",
1510
1908
  {
1511
1909
  onClick: clearAll,
1512
- className: "p-1 rounded-full hover:bg-[var(--ui-bg-tertiary)] hover:text-[var(--ui-text-primary)] transition-colors",
1910
+ className: "p-1 rounded-full hover:bg-[var(--ui-bg-tertiary)] hover:text-[var(--ui-text-primary)] transition-colors cursor-pointer",
1513
1911
  children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5" })
1514
1912
  }
1515
1913
  ),
@@ -1528,20 +1926,30 @@ var MultiSelect = forwardRef(
1528
1926
  autoFocus: true,
1529
1927
  placeholder: searchPlaceholder,
1530
1928
  value: search,
1531
- onChange: (e) => setSearch(e.target.value),
1929
+ onChange: (e) => {
1930
+ setSearch(e.target.value);
1931
+ setHighlightedIndex(0);
1932
+ },
1933
+ onKeyDown: handleSearchKeyDown,
1532
1934
  className: "w-full h-8 pl-8 pr-3 text-xs rounded-xl bg-[var(--ui-bg-secondary)] border border-[var(--ui-border-subtle)] focus:outline-none focus:border-[var(--ui-primary)] text-[var(--ui-text-primary)]"
1533
1935
  }
1534
1936
  )
1535
1937
  ] }),
1536
- /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto space-y-0.5", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-4 text-center text-xs text-[var(--ui-text-muted)]", children: "No options found." }) : filteredOptions.map((opt) => {
1938
+ /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto space-y-0.5", role: "listbox", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-4 text-center text-xs text-[var(--ui-text-muted)]", children: "No options found." }) : filteredOptions.map((opt, index) => {
1537
1939
  const isChecked = selectedValues.includes(opt.value);
1940
+ const isHighlighted = highlightedIndex === index;
1538
1941
  return /* @__PURE__ */ jsxs(
1539
1942
  "div",
1540
1943
  {
1541
- onClick: () => toggleOption(opt.value),
1944
+ role: "option",
1945
+ "aria-selected": isChecked,
1946
+ "aria-disabled": opt.disabled,
1947
+ onClick: () => !opt.disabled && toggleOption(opt.value),
1542
1948
  className: cn(
1543
- "flex items-center justify-between px-3 py-2 rounded-xl text-xs font-medium cursor-pointer transition-colors",
1544
- isChecked ? "bg-[var(--ui-primary)]/15 text-[var(--ui-primary)] font-semibold" : "hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)]"
1949
+ "flex items-center justify-between px-3 py-2 rounded-xl text-xs font-medium transition-colors select-none",
1950
+ opt.disabled ? "opacity-40 cursor-not-allowed text-[var(--ui-text-muted)]" : "cursor-pointer",
1951
+ isChecked && "text-[var(--ui-primary)] font-semibold",
1952
+ isHighlighted && !opt.disabled && "bg-[var(--ui-primary)]/15"
1545
1953
  ),
1546
1954
  children: [
1547
1955
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
@@ -1583,26 +1991,58 @@ var FileUpload = forwardRef(
1583
1991
  const [isDragOver, setIsDragOver] = useState(false);
1584
1992
  const [fileList, setFileList] = useState([]);
1585
1993
  const inputRef = useRef(null);
1994
+ const fileListRef = useRef(fileList);
1995
+ fileListRef.current = fileList;
1996
+ useEffect(() => {
1997
+ return () => {
1998
+ fileListRef.current.forEach((item) => {
1999
+ if (item.previewUrl) {
2000
+ URL.revokeObjectURL(item.previewUrl);
2001
+ }
2002
+ });
2003
+ };
2004
+ }, []);
2005
+ const matchesAccept = (file, acceptStr) => {
2006
+ if (!acceptStr) return true;
2007
+ const patterns = acceptStr.split(",").map((p) => p.trim().toLowerCase());
2008
+ const fileName = file.name.toLowerCase();
2009
+ const fileType = file.type.toLowerCase();
2010
+ return patterns.some((p) => {
2011
+ if (p.startsWith(".")) {
2012
+ return fileName.endsWith(p);
2013
+ }
2014
+ if (p.endsWith("/*")) {
2015
+ const baseType = p.replace("/*", "");
2016
+ return fileType.startsWith(baseType);
2017
+ }
2018
+ return fileType === p;
2019
+ });
2020
+ };
1586
2021
  const processFiles = (incoming) => {
1587
2022
  if (!incoming) return;
1588
2023
  const validFiles = [];
1589
2024
  const newUploaded = [];
1590
2025
  Array.from(incoming).forEach((file) => {
1591
2026
  if (fileList.length + newUploaded.length >= maxFiles) return;
2027
+ const isAccepted = matchesAccept(file, accept);
1592
2028
  const isOversized = file.size > maxSizeMB * 1024 * 1024;
2029
+ const hasError = !isAccepted || isOversized;
2030
+ let errorMsg;
2031
+ if (!isAccepted) errorMsg = `File type not supported (${accept})`;
2032
+ else if (isOversized) errorMsg = `File exceeds ${maxSizeMB}MB limit`;
1593
2033
  const fileObj = {
1594
2034
  id: `${file.name}-${Date.now()}-${Math.random()}`,
1595
2035
  file,
1596
2036
  name: file.name,
1597
2037
  size: file.size,
1598
2038
  type: file.type,
1599
- progress: isOversized ? 0 : 100,
1600
- status: isOversized ? "error" : "completed",
1601
- errorMessage: isOversized ? `File exceeds ${maxSizeMB}MB limit` : void 0,
1602
- previewUrl: file.type.startsWith("image/") ? URL.createObjectURL(file) : void 0
2039
+ progress: hasError ? 0 : 100,
2040
+ status: hasError ? "error" : "completed",
2041
+ errorMessage: errorMsg,
2042
+ previewUrl: file.type.startsWith("image/") && !hasError ? URL.createObjectURL(file) : void 0
1603
2043
  };
1604
2044
  newUploaded.push(fileObj);
1605
- if (!isOversized) validFiles.push(file);
2045
+ if (!hasError) validFiles.push(file);
1606
2046
  });
1607
2047
  setFileList((prev) => [...prev, ...newUploaded]);
1608
2048
  if (validFiles.length > 0) {
@@ -1628,7 +2068,13 @@ var FileUpload = forwardRef(
1628
2068
  if (inputRef.current) inputRef.current.value = "";
1629
2069
  };
1630
2070
  const removeFile = (id) => {
1631
- setFileList((prev) => prev.filter((f) => f.id !== id));
2071
+ setFileList((prev) => {
2072
+ const item = prev.find((f) => f.id === id);
2073
+ if (item?.previewUrl) {
2074
+ URL.revokeObjectURL(item.previewUrl);
2075
+ }
2076
+ return prev.filter((f) => f.id !== id);
2077
+ });
1632
2078
  onFileRemove?.(id);
1633
2079
  };
1634
2080
  return /* @__PURE__ */ jsxs("div", { ref, className: cn("w-full space-y-4", className), children: [
@@ -1736,8 +2182,12 @@ var NumberInput = forwardRef(
1736
2182
  className,
1737
2183
  ...props
1738
2184
  }, ref) => {
1739
- const [internalVal, setInternalVal] = useState(defaultValue);
1740
- const value = controlledVal !== void 0 ? controlledVal : internalVal;
2185
+ const [value, setValue] = useControllableState({
2186
+ value: controlledVal,
2187
+ defaultValue,
2188
+ onChange,
2189
+ name: "NumberInput"
2190
+ });
1741
2191
  const clamp = (num) => {
1742
2192
  let clamped = Math.min(max, Math.max(min, num));
1743
2193
  if (precision > 0) {
@@ -1748,14 +2198,12 @@ var NumberInput = forwardRef(
1748
2198
  const handleIncrement = () => {
1749
2199
  if (disabled) return;
1750
2200
  const next = clamp(value + step);
1751
- setInternalVal(next);
1752
- onChange?.(next);
2201
+ setValue(next);
1753
2202
  };
1754
2203
  const handleDecrement = () => {
1755
2204
  if (disabled) return;
1756
2205
  const next = clamp(value - step);
1757
- setInternalVal(next);
1758
- onChange?.(next);
2206
+ setValue(next);
1759
2207
  };
1760
2208
  const handleInputChange = (e) => {
1761
2209
  const val = e.target.value;
@@ -1765,8 +2213,7 @@ var NumberInput = forwardRef(
1765
2213
  const parsed = parseFloat(val);
1766
2214
  if (!isNaN(parsed)) {
1767
2215
  const next = clamp(parsed);
1768
- setInternalVal(next);
1769
- onChange?.(next);
2216
+ setValue(next);
1770
2217
  }
1771
2218
  };
1772
2219
  const handleKeyDown = (e) => {
@@ -1787,7 +2234,7 @@ var NumberInput = forwardRef(
1787
2234
  type: "button",
1788
2235
  disabled: disabled || value <= min,
1789
2236
  onClick: handleDecrement,
1790
- className: "px-3 h-full flex items-center justify-center hover:bg-[var(--ui-bg-tertiary)] disabled:opacity-30 disabled:pointer-events-none text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors border-r border-[var(--ui-border-subtle)]",
2237
+ className: "px-3 h-full flex items-center justify-center hover:bg-[var(--ui-bg-tertiary)] disabled:opacity-30 disabled:pointer-events-none text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors border-r border-[var(--ui-border-subtle)] cursor-pointer",
1791
2238
  children: /* @__PURE__ */ jsx(Minus, { className: "w-3.5 h-3.5" })
1792
2239
  }
1793
2240
  ),
@@ -1810,7 +2257,7 @@ var NumberInput = forwardRef(
1810
2257
  type: "button",
1811
2258
  disabled: disabled || value >= max,
1812
2259
  onClick: handleIncrement,
1813
- className: "px-3 h-full flex items-center justify-center hover:bg-[var(--ui-bg-tertiary)] disabled:opacity-30 disabled:pointer-events-none text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors border-l border-[var(--ui-border-subtle)]",
2260
+ className: "px-3 h-full flex items-center justify-center hover:bg-[var(--ui-bg-tertiary)] disabled:opacity-30 disabled:pointer-events-none text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors border-l border-[var(--ui-border-subtle)] cursor-pointer",
1814
2261
  children: /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5" })
1815
2262
  }
1816
2263
  )
@@ -1841,7 +2288,7 @@ var NumberInput = forwardRef(
1841
2288
  type: "button",
1842
2289
  disabled: disabled || value >= max,
1843
2290
  onClick: handleIncrement,
1844
- className: "px-1.5 h-1/2 flex items-center justify-center hover:bg-[var(--ui-bg-tertiary)] rounded-t text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] disabled:opacity-30 transition-colors",
2291
+ className: "px-1.5 h-1/2 flex items-center justify-center hover:bg-[var(--ui-bg-tertiary)] rounded-t text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] disabled:opacity-30 transition-colors cursor-pointer",
1845
2292
  children: /* @__PURE__ */ jsx(Plus, { className: "w-3 h-3" })
1846
2293
  }
1847
2294
  ),
@@ -1851,7 +2298,7 @@ var NumberInput = forwardRef(
1851
2298
  type: "button",
1852
2299
  disabled: disabled || value <= min,
1853
2300
  onClick: handleDecrement,
1854
- className: "px-1.5 h-1/2 flex items-center justify-center hover:bg-[var(--ui-bg-tertiary)] rounded-b text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] disabled:opacity-30 transition-colors",
2301
+ className: "px-1.5 h-1/2 flex items-center justify-center hover:bg-[var(--ui-bg-tertiary)] rounded-b text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] disabled:opacity-30 transition-colors cursor-pointer",
1855
2302
  children: /* @__PURE__ */ jsx(Minus, { className: "w-3 h-3" })
1856
2303
  }
1857
2304
  )
@@ -1880,19 +2327,27 @@ var CurrencyInput = forwardRef(
1880
2327
  }, ref) => {
1881
2328
  const symbol = currencySymbol || (currency === "VND" ? "\u20AB" : currency === "EUR" ? "\u20AC" : "$");
1882
2329
  const isSuffix = position === "suffix" || currency === "VND";
1883
- const [internalVal, setInternalVal] = useState(defaultValue);
1884
- const value = controlledVal !== void 0 ? controlledVal : internalVal;
1885
- const [displayVal, setDisplayVal] = useState(formatCurrencyString(value));
2330
+ const [value, setValue, isControlled] = useControllableState({
2331
+ value: controlledVal,
2332
+ defaultValue,
2333
+ onChange,
2334
+ name: "CurrencyInput"
2335
+ });
2336
+ const [internalInputString, setInternalInputString] = useState(formatCurrencyString(value));
1886
2337
  useEffect(() => {
1887
- setDisplayVal(formatCurrencyString(value));
1888
- }, [value]);
2338
+ if (!isControlled) {
2339
+ setInternalInputString(formatCurrencyString(value));
2340
+ }
2341
+ }, [value, isControlled]);
2342
+ const displayVal = isControlled ? formatCurrencyString(value) : internalInputString;
1889
2343
  const handleInputChange = (e) => {
1890
2344
  const raw = e.target.value.replace(/[^0-9.]/g, "");
1891
2345
  const parsed = parseFloat(raw);
1892
2346
  const num = isNaN(parsed) ? 0 : parsed;
1893
- setDisplayVal(raw ? formatCurrencyString(num) : "");
1894
- setInternalVal(num);
1895
- onChange?.(num);
2347
+ if (!isControlled) {
2348
+ setInternalInputString(raw ? formatCurrencyString(num) : "");
2349
+ }
2350
+ setValue(num);
1896
2351
  };
1897
2352
  return /* @__PURE__ */ jsxs("div", { className: cn("relative w-full flex items-center", className), children: [
1898
2353
  !isSuffix && /* @__PURE__ */ jsx("span", { className: "absolute left-3.5 text-sm font-bold text-[var(--ui-text-muted)] pointer-events-none font-mono", children: symbol }),
@@ -1986,6 +2441,6 @@ var MaskedInput = forwardRef(
1986
2441
  );
1987
2442
  MaskedInput.displayName = "MaskedInput";
1988
2443
 
1989
- export { Checkbox, CheckboxGroup, Combobox, CurrencyInput, DatePicker, DateRangePicker, FileUpload, FormErrorMessage, FormField, FormHelperText, FormLabel, Input, MaskedInput, MultiSelect, NumberInput, PasswordInput, PinInput, Radio, RadioGroup, RangeSlider, SearchInput, Select, Slider, Switch, Textarea, TimePicker, applyMask, checkboxVariants, formatCurrencyString, formatDate, formatDisplayDate, formatFileSize, forms_exports, inputVariants, radioVariants, selectVariants, switchThumbVariants, switchVariants, textareaVariants, useFormField };
1990
- //# sourceMappingURL=chunk-F5Q7BTMH.js.map
1991
- //# sourceMappingURL=chunk-F5Q7BTMH.js.map
2444
+ export { Combobox, CurrencyInput, DatePicker, DateRangePicker, FileUpload, Input, MaskedInput, MultiSelect, NumberInput, PasswordInput, PinInput, Radio, RadioGroup, RangeSlider, SearchInput, Select, Slider, Switch, Textarea, TimePicker, applyMask, formatCurrencyString, formatDate, formatDisplayDate, formatFileSize, forms_exports, inputVariants, radioVariants, selectVariants, switchThumbVariants, switchVariants, textareaVariants };
2445
+ //# sourceMappingURL=chunk-4CRFNALF.js.map
2446
+ //# sourceMappingURL=chunk-4CRFNALF.js.map