@spear-ai/spectral 1.16.0 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/dist/Accordion.d.ts.map +1 -1
  2. package/dist/Accordion.js +1 -1
  3. package/dist/Accordion.js.map +1 -1
  4. package/dist/Alert/AlertBase.d.ts.map +1 -1
  5. package/dist/Alert/AlertBase.js.map +1 -1
  6. package/dist/Alert.js.map +1 -1
  7. package/dist/Avatar.js.map +1 -1
  8. package/dist/Badge.d.ts.map +1 -1
  9. package/dist/Badge.js.map +1 -1
  10. package/dist/Button.d.ts.map +1 -1
  11. package/dist/Button.js +6 -6
  12. package/dist/Button.js.map +1 -1
  13. package/dist/ButtonGroup/ButtonGroupButton.js.map +1 -1
  14. package/dist/ButtonGroup.d.ts.map +1 -1
  15. package/dist/ButtonGroup.js +1 -1
  16. package/dist/ButtonGroup.js.map +1 -1
  17. package/dist/ButtonIcon.js +1 -1
  18. package/dist/ButtonIcon.js.map +1 -1
  19. package/dist/Checkbox/CheckboxBase.js.map +1 -1
  20. package/dist/Checkbox.js.map +1 -1
  21. package/dist/Combobox.js.map +1 -1
  22. package/dist/ControlGroup/ControlGroupSelect.js.map +1 -1
  23. package/dist/ControlGroup.d.ts.map +1 -1
  24. package/dist/ControlGroup.js +1 -1
  25. package/dist/ControlGroup.js.map +1 -1
  26. package/dist/DataCard/Card.d.ts.map +1 -1
  27. package/dist/DataCard/Card.js.map +1 -1
  28. package/dist/DataCard.js.map +1 -1
  29. package/dist/DateTimePicker/Calendar.js.map +1 -1
  30. package/dist/DateTimePicker/DateTimeDisplayInput.js.map +1 -1
  31. package/dist/DateTimePicker/TimePeriodSelect.js.map +1 -1
  32. package/dist/DateTimePicker/TimePicker.js.map +1 -1
  33. package/dist/DateTimePicker.js.map +1 -1
  34. package/dist/Dialog.d.ts.map +1 -1
  35. package/dist/Dialog.js +2 -2
  36. package/dist/Dialog.js.map +1 -1
  37. package/dist/Drawer.d.ts +2 -0
  38. package/dist/Drawer.d.ts.map +1 -1
  39. package/dist/Drawer.js +5 -5
  40. package/dist/Drawer.js.map +1 -1
  41. package/dist/DropdownMenu.js.map +1 -1
  42. package/dist/FormFieldMessage.d.ts.map +1 -1
  43. package/dist/FormFieldMessage.js.map +1 -1
  44. package/dist/HoverCard.d.ts.map +1 -1
  45. package/dist/HoverCard.js.map +1 -1
  46. package/dist/Icons/AdjustmentsIcon.d.ts.map +1 -1
  47. package/dist/Icons/AdjustmentsIcon.js.map +1 -1
  48. package/dist/Icons/AnalyzeIcon.d.ts.map +1 -1
  49. package/dist/Icons/AnalyzeIcon.js.map +1 -1
  50. package/dist/Icons/AnnotationsIcon.d.ts.map +1 -1
  51. package/dist/Icons/AnnotationsIcon.js.map +1 -1
  52. package/dist/Icons/ApprovedIcon.d.ts.map +1 -1
  53. package/dist/Icons/ApprovedIcon.js.map +1 -1
  54. package/dist/Icons/ArrowDownIcon.d.ts.map +1 -1
  55. package/dist/Icons/ArrowDownIcon.js.map +1 -1
  56. package/dist/Icons/ArrowUpIcon.d.ts.map +1 -1
  57. package/dist/Icons/ArrowUpIcon.js.map +1 -1
  58. package/dist/Icons/BoxToolIcon.d.ts.map +1 -1
  59. package/dist/Icons/BoxToolIcon.js.map +1 -1
  60. package/dist/Icons/CalendarIcon.d.ts.map +1 -1
  61. package/dist/Icons/CalendarIcon.js.map +1 -1
  62. package/dist/Icons/CheckCircleIcon.d.ts.map +1 -1
  63. package/dist/Icons/CheckCircleIcon.js.map +1 -1
  64. package/dist/Icons/CheckSquareIcon.d.ts.map +1 -1
  65. package/dist/Icons/CheckSquareIcon.js.map +1 -1
  66. package/dist/Icons/CheckmarkIcon.d.ts.map +1 -1
  67. package/dist/Icons/CheckmarkIcon.js.map +1 -1
  68. package/dist/Icons/ChevronDownIcon.d.ts.map +1 -1
  69. package/dist/Icons/ChevronDownIcon.js.map +1 -1
  70. package/dist/Icons/ChevronUpIcon.d.ts.map +1 -1
  71. package/dist/Icons/ChevronUpIcon.js.map +1 -1
  72. package/dist/Icons/ClockIcon.d.ts.map +1 -1
  73. package/dist/Icons/ClockIcon.js.map +1 -1
  74. package/dist/Icons/CloseCircleIcon.d.ts.map +1 -1
  75. package/dist/Icons/CloseCircleIcon.js.map +1 -1
  76. package/dist/Icons/CloseIcon.d.ts.map +1 -1
  77. package/dist/Icons/CloseIcon.js.map +1 -1
  78. package/dist/Icons/Crosshairs2Icon.d.ts.map +1 -1
  79. package/dist/Icons/Crosshairs2Icon.js.map +1 -1
  80. package/dist/Icons/CrosshairsIcon.d.ts.map +1 -1
  81. package/dist/Icons/CrosshairsIcon.js.map +1 -1
  82. package/dist/Icons/DashboardIcon.d.ts.map +1 -1
  83. package/dist/Icons/DashboardIcon.js.map +1 -1
  84. package/dist/Icons/DatabaseIcon.d.ts.map +1 -1
  85. package/dist/Icons/DatabaseIcon.js.map +1 -1
  86. package/dist/Icons/DeleteIcon.d.ts.map +1 -1
  87. package/dist/Icons/DeleteIcon.js.map +1 -1
  88. package/dist/Icons/DurationIcon.d.ts.map +1 -1
  89. package/dist/Icons/DurationIcon.js.map +1 -1
  90. package/dist/Icons/EditIcon.d.ts.map +1 -1
  91. package/dist/Icons/EditIcon.js.map +1 -1
  92. package/dist/Icons/EmailIcon.d.ts.map +1 -1
  93. package/dist/Icons/EmailIcon.js.map +1 -1
  94. package/dist/Icons/EraserIcon.d.ts.map +1 -1
  95. package/dist/Icons/EraserIcon.js.map +1 -1
  96. package/dist/Icons/ErrorIcon.d.ts.map +1 -1
  97. package/dist/Icons/ErrorIcon.js.map +1 -1
  98. package/dist/Icons/EyeClosedIcon.d.ts.map +1 -1
  99. package/dist/Icons/EyeClosedIcon.js.map +1 -1
  100. package/dist/Icons/EyeClosedIcon2.d.ts.map +1 -1
  101. package/dist/Icons/EyeClosedIcon2.js.map +1 -1
  102. package/dist/Icons/EyeOpenIcon.d.ts.map +1 -1
  103. package/dist/Icons/EyeOpenIcon.js.map +1 -1
  104. package/dist/Icons/FileDownloadIcon.d.ts.map +1 -1
  105. package/dist/Icons/FileDownloadIcon.js.map +1 -1
  106. package/dist/Icons/GoToFirstIcon.d.ts.map +1 -1
  107. package/dist/Icons/GoToFirstIcon.js.map +1 -1
  108. package/dist/Icons/GoToLastIcon.d.ts.map +1 -1
  109. package/dist/Icons/GoToLastIcon.js.map +1 -1
  110. package/dist/Icons/HarmonicCursorsIcon.d.ts.map +1 -1
  111. package/dist/Icons/HarmonicCursorsIcon.js.map +1 -1
  112. package/dist/Icons/InfoIcon.d.ts.map +1 -1
  113. package/dist/Icons/InfoIcon.js.map +1 -1
  114. package/dist/Icons/KeyboardIcon.d.ts.map +1 -1
  115. package/dist/Icons/KeyboardIcon.js.map +1 -1
  116. package/dist/Icons/LabelIcon.d.ts.map +1 -1
  117. package/dist/Icons/LabelIcon.js.map +1 -1
  118. package/dist/Icons/LassoIcon.d.ts.map +1 -1
  119. package/dist/Icons/LassoIcon.js.map +1 -1
  120. package/dist/Icons/LineToolIcon.d.ts.map +1 -1
  121. package/dist/Icons/LineToolIcon.js.map +1 -1
  122. package/dist/Icons/LiveViewIcon.d.ts.map +1 -1
  123. package/dist/Icons/LiveViewIcon.js.map +1 -1
  124. package/dist/Icons/LoaderIcon.d.ts.map +1 -1
  125. package/dist/Icons/LoaderIcon.js.map +1 -1
  126. package/dist/Icons/LocationIcon.d.ts.map +1 -1
  127. package/dist/Icons/LocationIcon.js.map +1 -1
  128. package/dist/Icons/LogoutIcon.d.ts.map +1 -1
  129. package/dist/Icons/LogoutIcon.js.map +1 -1
  130. package/dist/Icons/MaximizeIcon.d.ts.map +1 -1
  131. package/dist/Icons/MaximizeIcon.js.map +1 -1
  132. package/dist/Icons/MeasureIcon.d.ts.map +1 -1
  133. package/dist/Icons/MeasureIcon.js.map +1 -1
  134. package/dist/Icons/MenuDotsIcon.d.ts.map +1 -1
  135. package/dist/Icons/MenuDotsIcon.js.map +1 -1
  136. package/dist/Icons/MenuIcon.d.ts.map +1 -1
  137. package/dist/Icons/MenuIcon.js.map +1 -1
  138. package/dist/Icons/MessagesIcon.d.ts.map +1 -1
  139. package/dist/Icons/MessagesIcon.js.map +1 -1
  140. package/dist/Icons/MetadataIcon.d.ts.map +1 -1
  141. package/dist/Icons/MetadataIcon.js.map +1 -1
  142. package/dist/Icons/MinimizeIcon.d.ts.map +1 -1
  143. package/dist/Icons/MinimizeIcon.js.map +1 -1
  144. package/dist/Icons/MinusIcon.d.ts.map +1 -1
  145. package/dist/Icons/MinusIcon.js.map +1 -1
  146. package/dist/Icons/OntologyIcon.d.ts.map +1 -1
  147. package/dist/Icons/OntologyIcon.js.map +1 -1
  148. package/dist/Icons/PanelIconClose.d.ts.map +1 -1
  149. package/dist/Icons/PanelIconClose.js.map +1 -1
  150. package/dist/Icons/PanelIconOpen.d.ts.map +1 -1
  151. package/dist/Icons/PanelIconOpen.js.map +1 -1
  152. package/dist/Icons/PauseIcon.d.ts.map +1 -1
  153. package/dist/Icons/PauseIcon.js.map +1 -1
  154. package/dist/Icons/PlayIcon.d.ts.map +1 -1
  155. package/dist/Icons/PlayIcon.js.map +1 -1
  156. package/dist/Icons/PlusIcon.d.ts.map +1 -1
  157. package/dist/Icons/PlusIcon.js.map +1 -1
  158. package/dist/Icons/PolygonIcon.d.ts.map +1 -1
  159. package/dist/Icons/PolygonIcon.js.map +1 -1
  160. package/dist/Icons/PrinterIcon.d.ts.map +1 -1
  161. package/dist/Icons/PrinterIcon.js.map +1 -1
  162. package/dist/Icons/ProgressCheckIcon.d.ts.map +1 -1
  163. package/dist/Icons/ProgressCheckIcon.js.map +1 -1
  164. package/dist/Icons/ResetIcon.d.ts.map +1 -1
  165. package/dist/Icons/ResetIcon.js.map +1 -1
  166. package/dist/Icons/ReviewedIcon.d.ts.map +1 -1
  167. package/dist/Icons/ReviewedIcon.js.map +1 -1
  168. package/dist/Icons/ScissorsIcon.d.ts.map +1 -1
  169. package/dist/Icons/ScissorsIcon.js.map +1 -1
  170. package/dist/Icons/SearchIcon.d.ts.map +1 -1
  171. package/dist/Icons/SearchIcon.js.map +1 -1
  172. package/dist/Icons/SettingsIcon.d.ts.map +1 -1
  173. package/dist/Icons/SettingsIcon.js.map +1 -1
  174. package/dist/Icons/SortAscendingIcon.d.ts.map +1 -1
  175. package/dist/Icons/SortAscendingIcon.js.map +1 -1
  176. package/dist/Icons/SortAtoZIcon.d.ts.map +1 -1
  177. package/dist/Icons/SortAtoZIcon.js.map +1 -1
  178. package/dist/Icons/SortDescendingIcon.d.ts.map +1 -1
  179. package/dist/Icons/SortDescendingIcon.js.map +1 -1
  180. package/dist/Icons/SortZtoAIcon.d.ts.map +1 -1
  181. package/dist/Icons/SortZtoAIcon.js.map +1 -1
  182. package/dist/Icons/SparklesIcon.d.ts.map +1 -1
  183. package/dist/Icons/SparklesIcon.js.map +1 -1
  184. package/dist/Icons/StackIcon.d.ts.map +1 -1
  185. package/dist/Icons/StackIcon.js.map +1 -1
  186. package/dist/Icons/StarIcon.d.ts.map +1 -1
  187. package/dist/Icons/StarIcon.js.map +1 -1
  188. package/dist/Icons/SyncIcon.d.ts.map +1 -1
  189. package/dist/Icons/SyncIcon.js.map +1 -1
  190. package/dist/Icons/SyncOffIcon.d.ts.map +1 -1
  191. package/dist/Icons/SyncOffIcon.js.map +1 -1
  192. package/dist/Icons/TrashIcon.d.ts.map +1 -1
  193. package/dist/Icons/TrashIcon.js.map +1 -1
  194. package/dist/Icons/UndoIcon.d.ts.map +1 -1
  195. package/dist/Icons/UndoIcon.js.map +1 -1
  196. package/dist/Icons/UploadIcon.d.ts.map +1 -1
  197. package/dist/Icons/UploadIcon.js.map +1 -1
  198. package/dist/Icons/User2Icon.d.ts.map +1 -1
  199. package/dist/Icons/User2Icon.js.map +1 -1
  200. package/dist/Icons/UserIcon.d.ts.map +1 -1
  201. package/dist/Icons/UserIcon.js.map +1 -1
  202. package/dist/Icons/WarningIcon.d.ts.map +1 -1
  203. package/dist/Icons/WarningIcon.js.map +1 -1
  204. package/dist/Icons/ZoomAllIcon.d.ts.map +1 -1
  205. package/dist/Icons/ZoomAllIcon.js.map +1 -1
  206. package/dist/Icons/ZoomXIcon.d.ts.map +1 -1
  207. package/dist/Icons/ZoomXIcon.js.map +1 -1
  208. package/dist/Icons/ZoomYIcon.d.ts.map +1 -1
  209. package/dist/Icons/ZoomYIcon.js.map +1 -1
  210. package/dist/IconsAnimated/PanelLeftCloseIcon.js.map +1 -1
  211. package/dist/IconsAnimated/PanelLeftOpenIcon.js.map +1 -1
  212. package/dist/Input.js +1 -1
  213. package/dist/Input.js.map +1 -1
  214. package/dist/InputNumeric.d.ts.map +1 -1
  215. package/dist/InputNumeric.js.map +1 -1
  216. package/dist/InputOTP.d.ts.map +1 -1
  217. package/dist/InputOTP.js.map +1 -1
  218. package/dist/Kbd.d.ts.map +1 -1
  219. package/dist/Kbd.js.map +1 -1
  220. package/dist/Label.js.map +1 -1
  221. package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
  222. package/dist/MultiSelect.js.map +1 -1
  223. package/dist/Popover.d.ts.map +1 -1
  224. package/dist/Popover.js.map +1 -1
  225. package/dist/RadioButton.js +4 -1
  226. package/dist/RadioButton.js.map +1 -1
  227. package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts.map +1 -1
  228. package/dist/RadioButtonGroup/RadioButtonGroupBase.js +7 -2
  229. package/dist/RadioButtonGroup/RadioButtonGroupBase.js.map +1 -1
  230. package/dist/RadioButtonGroup.d.ts.map +1 -1
  231. package/dist/RadioButtonGroup.js.map +1 -1
  232. package/dist/RadioGroup.d.ts.map +1 -1
  233. package/dist/RadioGroup.js +1 -1
  234. package/dist/RadioGroup.js.map +1 -1
  235. package/dist/Select.js.map +1 -1
  236. package/dist/Skeleton.js.map +1 -1
  237. package/dist/Slider.js.map +1 -1
  238. package/dist/Switch/SwitchBase.d.ts.map +1 -1
  239. package/dist/Switch/SwitchBase.js.map +1 -1
  240. package/dist/Switch.js.map +1 -1
  241. package/dist/Tabs/TabsBase.d.ts.map +1 -1
  242. package/dist/Tabs/TabsBase.js.map +1 -1
  243. package/dist/Tabs.d.ts.map +1 -1
  244. package/dist/Tabs.js.map +1 -1
  245. package/dist/Textarea.js.map +1 -1
  246. package/dist/Toast.d.ts.map +1 -1
  247. package/dist/Toast.js.map +1 -1
  248. package/dist/Toggle/ToggleBase.js.map +1 -1
  249. package/dist/Toggle.d.ts.map +1 -1
  250. package/dist/Toggle.js +6 -2
  251. package/dist/Toggle.js.map +1 -1
  252. package/dist/ToggleGroup/ToggleGroupBase.d.ts.map +1 -1
  253. package/dist/ToggleGroup/ToggleGroupBase.js.map +1 -1
  254. package/dist/ToggleGroup/ToggleGroupItem.js +1 -1
  255. package/dist/ToggleGroup/ToggleGroupItem.js.map +1 -1
  256. package/dist/ToggleGroup/ToggleGroupSplitMenuItem.js +1 -1
  257. package/dist/ToggleGroup/ToggleGroupSplitMenuItem.js.map +1 -1
  258. package/dist/ToggleGroup.js +9 -1
  259. package/dist/ToggleGroup.js.map +1 -1
  260. package/dist/Tooltip.d.ts.map +1 -1
  261. package/dist/Tooltip.js.map +1 -1
  262. package/dist/Tray.d.ts.map +1 -1
  263. package/dist/Tray.js +1 -1
  264. package/dist/Tray.js.map +1 -1
  265. package/dist/styles/spectral.css +1 -1
  266. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ControlGroupSelect.js","names":[],"sources":["../../src/components/ControlGroup/ControlGroupSelect.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { Input } from '@primitives/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@primitives/select'\nimport { getStateClasses, type DropdownWidth, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useId, type ComponentProps } from 'react'\nimport { ControlGroup, ControlGroupItem, useControlGroup, type ControlGroupProps } from './ControlGroup'\n\nconst numberInputNoSpinner = '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none'\nconst defaultInputLabel = 'Amount'\nconst defaultSelectLabel = 'Select an option'\n\nexport interface SelectOptionType {\n disabled?: boolean\n label: string\n value: string\n}\n\n/** `inline`: `inputPlaceholder` / `selectPlaceholder` show inside the fields. `above`: same strings render as labels above each control (no inner placeholders). */\nexport type ControlGroupSelectCaptionLayout = 'above' | 'inline'\n\ntype ControlGroupSelectInputControlProps =\n | {\n inputValue: ComponentProps<typeof Input>['value']\n onInputChange: ComponentProps<typeof Input>['onChange']\n }\n | {\n inputValue?: undefined\n onInputChange?: undefined\n }\n\ntype ControlGroupSelectBaseProps = ComponentProps<typeof Select> &\n Pick<ControlGroupProps, 'orientation'> & {\n amountStep?: number\n /** Accessible name for the group wrapper (use when there is no visible group heading). */\n ariaLabel?: string\n captionLayout?: ControlGroupSelectCaptionLayout\n className?: string\n dataTestId?: string\n disabled?: boolean\n dropdownWidth?: DropdownWidth\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n /** Class applied to the input `ControlGroupItem` segment for width/split composition. */\n inputItemClassName?: string\n /** When `captionLayout` is `inline`, overrides the input's accessible name (defaults to `inputPlaceholder` when set). */\n inputAriaLabel?: string\n inputPlaceholder?: string\n maxAmount?: number\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: false). */\n messageReserveSpace?: boolean\n minAmount?: number\n selectPlaceholder?: string\n /** When `captionLayout` is `inline` and `selectPlaceholder` is empty, sets the select trigger's accessible name. */\n selectAriaLabel?: string\n /** Class applied to the select `ControlGroupItem` segment for width/split composition. */\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n state?: Exclude<FormFieldState, 'disabled'>\n type?: 'number' | 'text'\n warningMessage?: string | string[] | Record<string, unknown> | null\n }\n\nexport type ControlGroupSelectProps = ControlGroupSelectBaseProps & ControlGroupSelectInputControlProps\n\nconst fieldStackClass = 'flex w-full min-w-0 flex-col gap-1.5'\nconst groupedFieldBaseClasses =\n 'h-12! min-h-12! border-2! border-input-border bg-input-bg text-base text-input-text transition duration-200 placeholder:text-input-text-placeholder hover:border-input-border--hover focus-visible:border-input-border--focus focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus disabled:pointer-events-none disabled:border-input-border--disabled disabled:bg-input-bg--disabled disabled:text-input-text--disabled'\n\nconst getFieldMinWidth = (caption?: string, extraCharacters: number = 0): string | undefined => {\n const normalizedCaption = caption?.trim()\n if (!normalizedCaption) return undefined\n return `${Math.max(normalizedCaption.length + extraCharacters, 8)}ch`\n}\n\nconst getReadableLabel = (label: string | undefined, fallback: string): string => {\n const normalizedLabel = label?.trim()\n return normalizedLabel && normalizedLabel.length > 0 ? normalizedLabel : fallback\n}\n\nexport const ControlGroupSelect = ({\n amountStep,\n ariaLabel,\n captionLayout = 'inline',\n className,\n dataTestId = 'spectral-control-group-select',\n disabled,\n errorMessage,\n id,\n dropdownWidth = 'trigger',\n inputAriaLabel,\n inputPlaceholder,\n inputItemClassName,\n inputValue,\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxAmount = 1000000,\n minAmount = 0,\n onInputChange,\n orientation = 'horizontal',\n selectAriaLabel,\n selectItemClassName,\n selectOptions,\n selectPlaceholder,\n state = 'default',\n type = 'number',\n warningMessage,\n ...selectProps\n}: ControlGroupSelectProps) => {\n const baseId = useId()\n const idPrefix = id ?? baseId\n const inputId = `${idPrefix}-amount`\n const selectTriggerId = `${idPrefix}-select`\n const inputLabelId = `${inputId}-label`\n const selectLabelId = `${selectTriggerId}-label`\n\n const useAboveLabels = captionLayout === 'above'\n const inputCaption = useAboveLabels ? undefined : inputPlaceholder\n const selectCaption = useAboveLabels ? undefined : selectPlaceholder\n const inputLabelText = getReadableLabel(inputPlaceholder, defaultInputLabel)\n const selectLabelText = getReadableLabel(selectPlaceholder, defaultSelectLabel)\n\n const inputAccessibleName = inputAriaLabel ?? (useAboveLabels ? undefined : inputLabelText)\n const selectTriggerAriaLabel = selectAriaLabel ?? (useAboveLabels ? undefined : selectLabelText)\n const inputMinWidth = getFieldMinWidth(inputPlaceholder, 3)\n const selectTriggerMinWidth = getFieldMinWidth(selectPlaceholder, 5)\n const groupAriaLabel = ariaLabel ?? `${inputLabelText} and ${selectLabelText}`\n\n const isDisabled = !!disabled\n const isInputControlled = inputValue !== undefined && onInputChange !== undefined\n\n return (\n <ControlGroup\n aria-label={groupAriaLabel}\n className={className}\n data-testid={dataTestId}\n disabled={disabled}\n errorMessage={errorMessage}\n id={idPrefix}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n orientation={orientation}\n state={state}\n warningMessage={warningMessage}\n >\n <ControlGroupSelectInner\n amountStep={amountStep}\n dataTestId={dataTestId}\n inputAccessibleName={inputAccessibleName}\n inputCaption={inputCaption}\n inputId={inputId}\n inputLabelId={inputLabelId}\n inputLabelText={inputLabelText}\n inputItemClassName={inputItemClassName}\n inputMinWidth={inputMinWidth}\n inputValue={isInputControlled ? inputValue : undefined}\n isDisabled={isDisabled}\n maxAmount={maxAmount}\n minAmount={minAmount}\n onInputChange={isInputControlled ? onInputChange : undefined}\n dropdownWidth={dropdownWidth}\n selectCaption={selectCaption}\n selectOptions={selectOptions}\n selectLabelId={selectLabelId}\n selectLabelText={selectLabelText}\n selectItemClassName={selectItemClassName}\n selectProps={selectProps}\n selectTriggerAriaLabel={selectTriggerAriaLabel}\n selectTriggerId={selectTriggerId}\n selectTriggerMinWidth={selectTriggerMinWidth}\n type={type}\n useAboveLabels={useAboveLabels}\n />\n </ControlGroup>\n )\n}\n\ninterface ControlGroupSelectInnerProps {\n amountStep?: number\n dataTestId: string\n dropdownWidth: DropdownWidth\n inputAccessibleName?: string\n inputCaption?: string\n inputId: string\n inputLabelId: string\n inputLabelText: string\n inputItemClassName?: string\n inputMinWidth?: string\n inputValue?: ComponentProps<typeof Input>['value']\n isDisabled: boolean\n maxAmount: number\n minAmount: number\n onInputChange?: ComponentProps<typeof Input>['onChange']\n selectCaption?: string\n selectLabelId: string\n selectLabelText: string\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n selectProps: Omit<ComponentProps<typeof Select>, 'children'>\n selectTriggerAriaLabel?: string\n selectTriggerId: string\n selectTriggerMinWidth?: string\n type: 'number' | 'text'\n useAboveLabels: boolean\n}\n\nconst ControlGroupSelectInner = ({\n amountStep,\n dataTestId,\n dropdownWidth,\n inputAccessibleName,\n inputCaption,\n inputId,\n inputLabelId,\n inputLabelText,\n inputItemClassName,\n inputMinWidth,\n inputValue,\n isDisabled,\n maxAmount,\n minAmount,\n onInputChange,\n selectCaption,\n selectLabelId,\n selectLabelText,\n selectItemClassName,\n selectOptions,\n selectProps,\n selectTriggerAriaLabel,\n selectTriggerId,\n selectTriggerMinWidth,\n type,\n useAboveLabels,\n}: ControlGroupSelectInnerProps) => {\n const { messageId, orientation, state } = useControlGroup()\n const isSelectOpenControlled = selectProps.open !== undefined\n const handleSelectOpenChange: NonNullable<ComponentProps<typeof Select>['onOpenChange']> = (nextOpen) => {\n selectProps.onOpenChange?.(nextOpen)\n }\n\n const inputRadiusClasses = orientation === 'horizontal' ? 'rounded-s-md rounded-e-none' : 'rounded-ss-md rounded-se-md rounded-es-none rounded-ee-none'\n const selectRadiusClasses = orientation === 'horizontal' ? 'rounded-s-none rounded-e-md' : 'rounded-ss-none rounded-se-none rounded-es-md rounded-ee-md'\n const firstItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0' : 'mbe-0'\n const secondItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0 [&>*:last-child]:-ms-0.5' : 'mbe-0 [&>*:last-child]:-mt-0.5'\n\n const inputElement = (\n <Input\n aria-describedby={messageId}\n aria-label={inputAccessibleName}\n aria-labelledby={useAboveLabels ? inputLabelId : undefined}\n className={cn(groupedFieldBaseClasses, inputRadiusClasses, getStateClasses(state), type === 'number' && numberInputNoSpinner, type === 'number' && 'tabular-nums')}\n data-testid={`${dataTestId}-input`}\n disabled={isDisabled}\n id={useAboveLabels ? inputId : undefined}\n type={type === 'number' ? 'number' : 'text'}\n placeholder={inputCaption}\n style={inputMinWidth ? { minWidth: inputMinWidth } : undefined}\n min={minAmount ?? 0}\n max={maxAmount ?? 1000000}\n {...(inputValue !== undefined && onInputChange !== undefined ? { value: inputValue, onChange: onInputChange } : {})}\n step={amountStep ?? 1}\n />\n )\n\n const selectTriggerElement = (\n <SelectTrigger\n aria-describedby={messageId}\n aria-label={selectTriggerAriaLabel}\n aria-labelledby={useAboveLabels ? selectLabelId : undefined}\n className={cn(\n 'text-input-text data-placeholder:text-input-text-placeholder!',\n selectRadiusClasses,\n 'px-4 w-full justify-between focus-visible:border-input-border--focus focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus',\n getStateClasses(state),\n )}\n data-testid={`${dataTestId}-select-trigger`}\n disabled={isDisabled}\n id={useAboveLabels ? selectTriggerId : undefined}\n style={selectTriggerMinWidth ? { minWidth: selectTriggerMinWidth } : undefined}\n >\n <SelectValue\n className='min-w-0 block max-w-full truncate text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder!'\n placeholder={selectCaption}\n />\n </SelectTrigger>\n )\n\n return (\n <>\n <ControlGroupItem className={cn(useAboveLabels ? firstItemAboveLabelClasses : undefined, inputItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label\n className='text-text-primary'\n htmlFor={inputId}\n id={inputLabelId}\n >\n {inputLabelText}\n </Label>\n {inputElement}\n </div>\n ) : (\n inputElement\n )}\n </ControlGroupItem>\n <Select\n {...selectProps}\n data-testid={`${dataTestId}-select-root`}\n disabled={isDisabled}\n {...(isSelectOpenControlled ? { open: selectProps.open } : {})}\n onOpenChange={handleSelectOpenChange}\n >\n <ControlGroupItem className={cn(useAboveLabels ? secondItemAboveLabelClasses : undefined, selectItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label\n className='text-text-primary'\n htmlFor={selectTriggerId}\n id={selectLabelId}\n >\n {selectLabelText}\n </Label>\n {selectTriggerElement}\n </div>\n ) : (\n selectTriggerElement\n )}\n </ControlGroupItem>\n <SelectContent\n data-testid={`${dataTestId}-select-content`}\n dropdownWidth={dropdownWidth}\n >\n {selectOptions.map((option) => (\n <SelectItem\n disabled={option.disabled}\n key={option.value}\n value={option.value}\n >\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;AAQA,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAC1B,MAAM,qBAAqB;AAyD3B,MAAM,kBAAkB;AACxB,MAAM,0BACJ;AAEF,MAAM,oBAAoB,SAAkB,kBAA0B,MAA0B;CAC9F,MAAM,oBAAoB,SAAS,MAAM;AACzC,KAAI,CAAC,kBAAmB,QAAO;AAC/B,QAAO,GAAG,KAAK,IAAI,kBAAkB,SAAS,iBAAiB,EAAE,CAAC;;AAGpE,MAAM,oBAAoB,OAA2B,aAA6B;CAChF,MAAM,kBAAkB,OAAO,MAAM;AACrC,QAAO,mBAAmB,gBAAgB,SAAS,IAAI,kBAAkB;;AAG3E,MAAa,sBAAsB,EACjC,YACA,WACA,gBAAgB,UAChB,WACA,aAAa,iCACb,UACA,cACA,IACA,gBAAgB,WAChB,gBACA,kBACA,oBACA,YACA,sBAAsB,GACtB,sBAAsB,OACtB,YAAY,KACZ,YAAY,GACZ,eACA,cAAc,cACd,iBACA,qBACA,eACA,mBACA,QAAQ,WACR,OAAO,UACP,gBACA,GAAG,kBAC0B;CAC7B,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,MAAM;CACvB,MAAM,UAAU,GAAG,SAAS;CAC5B,MAAM,kBAAkB,GAAG,SAAS;CACpC,MAAM,eAAe,GAAG,QAAQ;CAChC,MAAM,gBAAgB,GAAG,gBAAgB;CAEzC,MAAM,iBAAiB,kBAAkB;CACzC,MAAM,eAAe,iBAAiB,SAAY;CAClD,MAAM,gBAAgB,iBAAiB,SAAY;CACnD,MAAM,iBAAiB,iBAAiB,kBAAkB,kBAAkB;CAC5E,MAAM,kBAAkB,iBAAiB,mBAAmB,mBAAmB;CAE/E,MAAM,sBAAsB,mBAAmB,iBAAiB,SAAY;CAC5E,MAAM,yBAAyB,oBAAoB,iBAAiB,SAAY;CAChF,MAAM,gBAAgB,iBAAiB,kBAAkB,EAAE;CAC3D,MAAM,wBAAwB,iBAAiB,mBAAmB,EAAE;CACpE,MAAM,iBAAiB,aAAa,GAAG,eAAe,OAAO;CAE7D,MAAM,aAAa,CAAC,CAAC;CACrB,MAAM,oBAAoB,eAAe,UAAa,kBAAkB;AAExE,QACE,oBAAC,cAAD;EACE,cAAY;EACD;EACX,eAAa;EACH;EACI;EACd,IAAI;EACiB;EACA;EACR;EACN;EACS;YAEhB,oBAAC,yBAAD;GACc;GACA;GACS;GACP;GACL;GACK;GACE;GACI;GACL;GACf,YAAY,oBAAoB,aAAa;GACjC;GACD;GACA;GACX,eAAe,oBAAoB,gBAAgB;GACpC;GACA;GACA;GACA;GACE;GACI;GACR;GACW;GACP;GACM;GACjB;GACU;GAChB;EACW;;AAiCnB,MAAM,2BAA2B,EAC/B,YACA,YACA,eACA,qBACA,cACA,SACA,cACA,gBACA,oBACA,eACA,YACA,YACA,WACA,WACA,eACA,eACA,eACA,iBACA,qBACA,eACA,aACA,wBACA,iBACA,uBACA,MACA,qBACkC;CAClC,MAAM,EAAE,WAAW,aAAa,UAAU,iBAAiB;CAC3D,MAAM,yBAAyB,YAAY,SAAS;CACpD,MAAM,0BAAsF,aAAa;AACvG,cAAY,eAAe,SAAS;;CAGtC,MAAM,qBAAqB,gBAAgB,eAAe,gCAAgC;CAC1F,MAAM,sBAAsB,gBAAgB,eAAe,gCAAgC;CAC3F,MAAM,6BAA6B,gBAAgB,eAAe,SAAS;CAC3E,MAAM,8BAA8B,gBAAgB,eAAe,kCAAkC;CAErG,MAAM,eACJ,oBAAC,OAAD;EACE,oBAAkB;EAClB,cAAY;EACZ,mBAAiB,iBAAiB,eAAe;EACjD,WAAW,GAAG,yBAAyB,oBAAoB,gBAAgB,MAAM,EAAE,SAAS,YAAY,sBAAsB,SAAS,YAAY,eAAe;EAClK,eAAa,GAAG,WAAW;EAC3B,UAAU;EACV,IAAI,iBAAiB,UAAU;EAC/B,MAAM,SAAS,WAAW,WAAW;EACrC,aAAa;EACb,OAAO,gBAAgB,EAAE,UAAU,eAAe,GAAG;EACrD,KAAK,aAAa;EAClB,KAAK,aAAa;EAClB,GAAK,eAAe,UAAa,kBAAkB,SAAY;GAAE,OAAO;GAAY,UAAU;GAAe,GAAG,EAAE;EAClH,MAAM,cAAc;EACpB;CAGJ,MAAM,uBACJ,oBAAC,eAAD;EACE,oBAAkB;EAClB,cAAY;EACZ,mBAAiB,iBAAiB,gBAAgB;EAClD,WAAW,GACT,iEACA,qBACA,8LACA,gBAAgB,MAAM,CACvB;EACD,eAAa,GAAG,WAAW;EAC3B,UAAU;EACV,IAAI,iBAAiB,kBAAkB;EACvC,OAAO,wBAAwB,EAAE,UAAU,uBAAuB,GAAG;YAErE,oBAAC,aAAD;GACE,WAAU;GACV,aAAa;GACb;EACY;AAGlB,QACE,4CACE,oBAAC,kBAAD;EAAkB,WAAW,GAAG,iBAAiB,6BAA6B,QAAW,mBAAmB;YACzG,iBACC,qBAAC,OAAD;GAAK,WAAW;aAAhB,CACE,oBAAC,OAAD;IACE,WAAU;IACV,SAAS;IACT,IAAI;cAEH;IACK,GACP,aACG;OAEN;EAEe,GACnB,qBAAC,QAAD;EACE,GAAI;EACJ,eAAa,GAAG,WAAW;EAC3B,UAAU;EACV,GAAK,yBAAyB,EAAE,MAAM,YAAY,MAAM,GAAG,EAAE;EAC7D,cAAc;YALhB,CAOE,oBAAC,kBAAD;GAAkB,WAAW,GAAG,iBAAiB,8BAA8B,QAAW,oBAAoB;aAC3G,iBACC,qBAAC,OAAD;IAAK,WAAW;cAAhB,CACE,oBAAC,OAAD;KACE,WAAU;KACV,SAAS;KACT,IAAI;eAEH;KACK,GACP,qBACG;QAEN;GAEe,GACnB,oBAAC,eAAD;GACE,eAAa,GAAG,WAAW;GACZ;aAEd,cAAc,KAAK,WAClB,oBAAC,YAAD;IACE,UAAU,OAAO;IAEjB,OAAO,OAAO;cAEb,OAAO;IACG,EAJN,OAAO,MAID,CACb;GACY,EACT;IACR"}
1
+ {"version":3,"file":"ControlGroupSelect.js","names":[],"sources":["../../src/components/ControlGroup/ControlGroupSelect.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { Input } from '@primitives/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@primitives/select'\nimport { getStateClasses, type DropdownWidth, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useId, type ComponentProps } from 'react'\nimport { ControlGroup, ControlGroupItem, useControlGroup, type ControlGroupProps } from './ControlGroup'\n\nconst numberInputNoSpinner = '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none'\nconst defaultInputLabel = 'Amount'\nconst defaultSelectLabel = 'Select an option'\n\nexport interface SelectOptionType {\n disabled?: boolean\n label: string\n value: string\n}\n\n/** `inline`: `inputPlaceholder` / `selectPlaceholder` show inside the fields. `above`: same strings render as labels above each control (no inner placeholders). */\nexport type ControlGroupSelectCaptionLayout = 'above' | 'inline'\n\ntype ControlGroupSelectInputControlProps =\n | {\n inputValue: ComponentProps<typeof Input>['value']\n onInputChange: ComponentProps<typeof Input>['onChange']\n }\n | {\n inputValue?: undefined\n onInputChange?: undefined\n }\n\ntype ControlGroupSelectBaseProps = ComponentProps<typeof Select> &\n Pick<ControlGroupProps, 'orientation'> & {\n amountStep?: number\n /** Accessible name for the group wrapper (use when there is no visible group heading). */\n ariaLabel?: string\n captionLayout?: ControlGroupSelectCaptionLayout\n className?: string\n dataTestId?: string\n disabled?: boolean\n dropdownWidth?: DropdownWidth\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n /** Class applied to the input `ControlGroupItem` segment for width/split composition. */\n inputItemClassName?: string\n /** When `captionLayout` is `inline`, overrides the input's accessible name (defaults to `inputPlaceholder` when set). */\n inputAriaLabel?: string\n inputPlaceholder?: string\n maxAmount?: number\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: false). */\n messageReserveSpace?: boolean\n minAmount?: number\n selectPlaceholder?: string\n /** When `captionLayout` is `inline` and `selectPlaceholder` is empty, sets the select trigger's accessible name. */\n selectAriaLabel?: string\n /** Class applied to the select `ControlGroupItem` segment for width/split composition. */\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n state?: Exclude<FormFieldState, 'disabled'>\n type?: 'number' | 'text'\n warningMessage?: string | string[] | Record<string, unknown> | null\n }\n\nexport type ControlGroupSelectProps = ControlGroupSelectBaseProps & ControlGroupSelectInputControlProps\n\nconst fieldStackClass = 'flex w-full min-w-0 flex-col gap-1.5'\nconst groupedFieldBaseClasses =\n 'h-12! min-h-12! border-2! border-input-border bg-input-bg text-base text-input-text transition duration-200 placeholder:text-input-text-placeholder hover:border-input-border--hover focus-visible:border-input-border--focus focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus disabled:pointer-events-none disabled:border-input-border--disabled disabled:bg-input-bg--disabled disabled:text-input-text--disabled'\n\nconst getFieldMinWidth = (caption?: string, extraCharacters: number = 0): string | undefined => {\n const normalizedCaption = caption?.trim()\n if (!normalizedCaption) return undefined\n return `${Math.max(normalizedCaption.length + extraCharacters, 8)}ch`\n}\n\nconst getReadableLabel = (label: string | undefined, fallback: string): string => {\n const normalizedLabel = label?.trim()\n return normalizedLabel && normalizedLabel.length > 0 ? normalizedLabel : fallback\n}\n\nexport const ControlGroupSelect = ({\n amountStep,\n ariaLabel,\n captionLayout = 'inline',\n className,\n dataTestId = 'spectral-control-group-select',\n disabled,\n errorMessage,\n id,\n dropdownWidth = 'trigger',\n inputAriaLabel,\n inputPlaceholder,\n inputItemClassName,\n inputValue,\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxAmount = 1000000,\n minAmount = 0,\n onInputChange,\n orientation = 'horizontal',\n selectAriaLabel,\n selectItemClassName,\n selectOptions,\n selectPlaceholder,\n state = 'default',\n type = 'number',\n warningMessage,\n ...selectProps\n}: ControlGroupSelectProps) => {\n const baseId = useId()\n const idPrefix = id ?? baseId\n const inputId = `${idPrefix}-amount`\n const selectTriggerId = `${idPrefix}-select`\n const inputLabelId = `${inputId}-label`\n const selectLabelId = `${selectTriggerId}-label`\n\n const useAboveLabels = captionLayout === 'above'\n const inputCaption = useAboveLabels ? undefined : inputPlaceholder\n const selectCaption = useAboveLabels ? undefined : selectPlaceholder\n const inputLabelText = getReadableLabel(inputPlaceholder, defaultInputLabel)\n const selectLabelText = getReadableLabel(selectPlaceholder, defaultSelectLabel)\n\n const inputAccessibleName = inputAriaLabel ?? (useAboveLabels ? undefined : inputLabelText)\n const selectTriggerAriaLabel = selectAriaLabel ?? (useAboveLabels ? undefined : selectLabelText)\n const inputMinWidth = getFieldMinWidth(inputPlaceholder, 3)\n const selectTriggerMinWidth = getFieldMinWidth(selectPlaceholder, 5)\n const groupAriaLabel = ariaLabel ?? `${inputLabelText} and ${selectLabelText}`\n\n const isDisabled = !!disabled\n const isInputControlled = inputValue !== undefined && onInputChange !== undefined\n\n return (\n <ControlGroup\n aria-label={groupAriaLabel}\n className={className}\n data-testid={dataTestId}\n disabled={disabled}\n errorMessage={errorMessage}\n id={idPrefix}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n orientation={orientation}\n state={state}\n warningMessage={warningMessage}\n >\n <ControlGroupSelectInner\n amountStep={amountStep}\n dataTestId={dataTestId}\n inputAccessibleName={inputAccessibleName}\n inputCaption={inputCaption}\n inputId={inputId}\n inputLabelId={inputLabelId}\n inputLabelText={inputLabelText}\n inputItemClassName={inputItemClassName}\n inputMinWidth={inputMinWidth}\n inputValue={isInputControlled ? inputValue : undefined}\n isDisabled={isDisabled}\n maxAmount={maxAmount}\n minAmount={minAmount}\n onInputChange={isInputControlled ? onInputChange : undefined}\n dropdownWidth={dropdownWidth}\n selectCaption={selectCaption}\n selectOptions={selectOptions}\n selectLabelId={selectLabelId}\n selectLabelText={selectLabelText}\n selectItemClassName={selectItemClassName}\n selectProps={selectProps}\n selectTriggerAriaLabel={selectTriggerAriaLabel}\n selectTriggerId={selectTriggerId}\n selectTriggerMinWidth={selectTriggerMinWidth}\n type={type}\n useAboveLabels={useAboveLabels}\n />\n </ControlGroup>\n )\n}\n\ninterface ControlGroupSelectInnerProps {\n amountStep?: number\n dataTestId: string\n dropdownWidth: DropdownWidth\n inputAccessibleName?: string\n inputCaption?: string\n inputId: string\n inputLabelId: string\n inputLabelText: string\n inputItemClassName?: string\n inputMinWidth?: string\n inputValue?: ComponentProps<typeof Input>['value']\n isDisabled: boolean\n maxAmount: number\n minAmount: number\n onInputChange?: ComponentProps<typeof Input>['onChange']\n selectCaption?: string\n selectLabelId: string\n selectLabelText: string\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n selectProps: Omit<ComponentProps<typeof Select>, 'children'>\n selectTriggerAriaLabel?: string\n selectTriggerId: string\n selectTriggerMinWidth?: string\n type: 'number' | 'text'\n useAboveLabels: boolean\n}\n\nconst ControlGroupSelectInner = ({\n amountStep,\n dataTestId,\n dropdownWidth,\n inputAccessibleName,\n inputCaption,\n inputId,\n inputLabelId,\n inputLabelText,\n inputItemClassName,\n inputMinWidth,\n inputValue,\n isDisabled,\n maxAmount,\n minAmount,\n onInputChange,\n selectCaption,\n selectLabelId,\n selectLabelText,\n selectItemClassName,\n selectOptions,\n selectProps,\n selectTriggerAriaLabel,\n selectTriggerId,\n selectTriggerMinWidth,\n type,\n useAboveLabels,\n}: ControlGroupSelectInnerProps) => {\n const { messageId, orientation, state } = useControlGroup()\n const isSelectOpenControlled = selectProps.open !== undefined\n const handleSelectOpenChange: NonNullable<ComponentProps<typeof Select>['onOpenChange']> = (nextOpen) => {\n selectProps.onOpenChange?.(nextOpen)\n }\n\n const inputRadiusClasses = orientation === 'horizontal' ? 'rounded-s-md rounded-e-none' : 'rounded-ss-md rounded-se-md rounded-es-none rounded-ee-none'\n const selectRadiusClasses = orientation === 'horizontal' ? 'rounded-s-none rounded-e-md' : 'rounded-ss-none rounded-se-none rounded-es-md rounded-ee-md'\n const firstItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0' : 'mbe-0'\n const secondItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0 [&>*:last-child]:-ms-0.5' : 'mbe-0 [&>*:last-child]:-mt-0.5'\n\n const inputElement = (\n <Input\n aria-describedby={messageId}\n aria-label={inputAccessibleName}\n aria-labelledby={useAboveLabels ? inputLabelId : undefined}\n className={cn(groupedFieldBaseClasses, inputRadiusClasses, getStateClasses(state), type === 'number' && numberInputNoSpinner, type === 'number' && 'tabular-nums')}\n data-testid={`${dataTestId}-input`}\n disabled={isDisabled}\n id={useAboveLabels ? inputId : undefined}\n type={type === 'number' ? 'number' : 'text'}\n placeholder={inputCaption}\n style={inputMinWidth ? { minWidth: inputMinWidth } : undefined}\n min={minAmount ?? 0}\n max={maxAmount ?? 1000000}\n {...(inputValue !== undefined && onInputChange !== undefined ? { value: inputValue, onChange: onInputChange } : {})}\n step={amountStep ?? 1}\n />\n )\n\n const selectTriggerElement = (\n <SelectTrigger\n aria-describedby={messageId}\n aria-label={selectTriggerAriaLabel}\n aria-labelledby={useAboveLabels ? selectLabelId : undefined}\n className={cn(\n 'text-input-text data-placeholder:text-input-text-placeholder!',\n selectRadiusClasses,\n 'px-4 w-full justify-between focus-visible:border-input-border--focus focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus',\n getStateClasses(state),\n )}\n data-testid={`${dataTestId}-select-trigger`}\n disabled={isDisabled}\n id={useAboveLabels ? selectTriggerId : undefined}\n style={selectTriggerMinWidth ? { minWidth: selectTriggerMinWidth } : undefined}\n >\n <SelectValue className='min-w-0 block max-w-full truncate text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder!' placeholder={selectCaption} />\n </SelectTrigger>\n )\n\n return (\n <>\n <ControlGroupItem className={cn(useAboveLabels ? firstItemAboveLabelClasses : undefined, inputItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={inputId} id={inputLabelId}>\n {inputLabelText}\n </Label>\n {inputElement}\n </div>\n ) : (\n inputElement\n )}\n </ControlGroupItem>\n <Select {...selectProps} data-testid={`${dataTestId}-select-root`} disabled={isDisabled} {...(isSelectOpenControlled ? { open: selectProps.open } : {})} onOpenChange={handleSelectOpenChange}>\n <ControlGroupItem className={cn(useAboveLabels ? secondItemAboveLabelClasses : undefined, selectItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={selectTriggerId} id={selectLabelId}>\n {selectLabelText}\n </Label>\n {selectTriggerElement}\n </div>\n ) : (\n selectTriggerElement\n )}\n </ControlGroupItem>\n <SelectContent data-testid={`${dataTestId}-select-content`} dropdownWidth={dropdownWidth}>\n {selectOptions.map((option) => (\n <SelectItem disabled={option.disabled} key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;AAQA,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAC1B,MAAM,qBAAqB;AAyD3B,MAAM,kBAAkB;AACxB,MAAM,0BACJ;AAEF,MAAM,oBAAoB,SAAkB,kBAA0B,MAA0B;CAC9F,MAAM,oBAAoB,SAAS,MAAM;AACzC,KAAI,CAAC,kBAAmB,QAAO;AAC/B,QAAO,GAAG,KAAK,IAAI,kBAAkB,SAAS,iBAAiB,EAAE,CAAC;;AAGpE,MAAM,oBAAoB,OAA2B,aAA6B;CAChF,MAAM,kBAAkB,OAAO,MAAM;AACrC,QAAO,mBAAmB,gBAAgB,SAAS,IAAI,kBAAkB;;AAG3E,MAAa,sBAAsB,EACjC,YACA,WACA,gBAAgB,UAChB,WACA,aAAa,iCACb,UACA,cACA,IACA,gBAAgB,WAChB,gBACA,kBACA,oBACA,YACA,sBAAsB,GACtB,sBAAsB,OACtB,YAAY,KACZ,YAAY,GACZ,eACA,cAAc,cACd,iBACA,qBACA,eACA,mBACA,QAAQ,WACR,OAAO,UACP,gBACA,GAAG,kBAC0B;CAC7B,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,MAAM;CACvB,MAAM,UAAU,GAAG,SAAS;CAC5B,MAAM,kBAAkB,GAAG,SAAS;CACpC,MAAM,eAAe,GAAG,QAAQ;CAChC,MAAM,gBAAgB,GAAG,gBAAgB;CAEzC,MAAM,iBAAiB,kBAAkB;CACzC,MAAM,eAAe,iBAAiB,SAAY;CAClD,MAAM,gBAAgB,iBAAiB,SAAY;CACnD,MAAM,iBAAiB,iBAAiB,kBAAkB,kBAAkB;CAC5E,MAAM,kBAAkB,iBAAiB,mBAAmB,mBAAmB;CAE/E,MAAM,sBAAsB,mBAAmB,iBAAiB,SAAY;CAC5E,MAAM,yBAAyB,oBAAoB,iBAAiB,SAAY;CAChF,MAAM,gBAAgB,iBAAiB,kBAAkB,EAAE;CAC3D,MAAM,wBAAwB,iBAAiB,mBAAmB,EAAE;CACpE,MAAM,iBAAiB,aAAa,GAAG,eAAe,OAAO;CAE7D,MAAM,aAAa,CAAC,CAAC;CACrB,MAAM,oBAAoB,eAAe,UAAa,kBAAkB;AAExE,QACE,oBAAC,cAAD;EACE,cAAY;EACD;EACX,eAAa;EACH;EACI;EACd,IAAI;EACiB;EACA;EACR;EACN;EACS;YAEhB,oBAAC,yBAAD;GACc;GACA;GACS;GACP;GACL;GACK;GACE;GACI;GACL;GACf,YAAY,oBAAoB,aAAa;GACjC;GACD;GACA;GACX,eAAe,oBAAoB,gBAAgB;GACpC;GACA;GACA;GACA;GACE;GACI;GACR;GACW;GACP;GACM;GACjB;GACU;GAChB;EACW;;AAiCnB,MAAM,2BAA2B,EAC/B,YACA,YACA,eACA,qBACA,cACA,SACA,cACA,gBACA,oBACA,eACA,YACA,YACA,WACA,WACA,eACA,eACA,eACA,iBACA,qBACA,eACA,aACA,wBACA,iBACA,uBACA,MACA,qBACkC;CAClC,MAAM,EAAE,WAAW,aAAa,UAAU,iBAAiB;CAC3D,MAAM,yBAAyB,YAAY,SAAS;CACpD,MAAM,0BAAsF,aAAa;AACvG,cAAY,eAAe,SAAS;;CAGtC,MAAM,qBAAqB,gBAAgB,eAAe,gCAAgC;CAC1F,MAAM,sBAAsB,gBAAgB,eAAe,gCAAgC;CAC3F,MAAM,6BAA6B,gBAAgB,eAAe,SAAS;CAC3E,MAAM,8BAA8B,gBAAgB,eAAe,kCAAkC;CAErG,MAAM,eACJ,oBAAC,OAAD;EACE,oBAAkB;EAClB,cAAY;EACZ,mBAAiB,iBAAiB,eAAe;EACjD,WAAW,GAAG,yBAAyB,oBAAoB,gBAAgB,MAAM,EAAE,SAAS,YAAY,sBAAsB,SAAS,YAAY,eAAe;EAClK,eAAa,GAAG,WAAW;EAC3B,UAAU;EACV,IAAI,iBAAiB,UAAU;EAC/B,MAAM,SAAS,WAAW,WAAW;EACrC,aAAa;EACb,OAAO,gBAAgB,EAAE,UAAU,eAAe,GAAG;EACrD,KAAK,aAAa;EAClB,KAAK,aAAa;EAClB,GAAK,eAAe,UAAa,kBAAkB,SAAY;GAAE,OAAO;GAAY,UAAU;GAAe,GAAG,EAAE;EAClH,MAAM,cAAc;EACpB;CAGJ,MAAM,uBACJ,oBAAC,eAAD;EACE,oBAAkB;EAClB,cAAY;EACZ,mBAAiB,iBAAiB,gBAAgB;EAClD,WAAW,GACT,iEACA,qBACA,8LACA,gBAAgB,MAAM,CACvB;EACD,eAAa,GAAG,WAAW;EAC3B,UAAU;EACV,IAAI,iBAAiB,kBAAkB;EACvC,OAAO,wBAAwB,EAAE,UAAU,uBAAuB,GAAG;YAErE,oBAAC,aAAD;GAAa,WAAU;GAA+H,aAAa;GAAiB;EACtK;AAGlB,QACE,4CACE,oBAAC,kBAAD;EAAkB,WAAW,GAAG,iBAAiB,6BAA6B,QAAW,mBAAmB;YACzG,iBACC,qBAAC,OAAD;GAAK,WAAW;aAAhB,CACE,oBAAC,OAAD;IAAO,WAAU;IAAoB,SAAS;IAAS,IAAI;cACxD;IACK,GACP,aACG;OAEN;EAEe,GACnB,qBAAC,QAAD;EAAQ,GAAI;EAAa,eAAa,GAAG,WAAW;EAAe,UAAU;EAAY,GAAK,yBAAyB,EAAE,MAAM,YAAY,MAAM,GAAG,EAAE;EAAG,cAAc;YAAvK,CACE,oBAAC,kBAAD;GAAkB,WAAW,GAAG,iBAAiB,8BAA8B,QAAW,oBAAoB;aAC3G,iBACC,qBAAC,OAAD;IAAK,WAAW;cAAhB,CACE,oBAAC,OAAD;KAAO,WAAU;KAAoB,SAAS;KAAiB,IAAI;eAChE;KACK,GACP,qBACG;QAEN;GAEe,GACnB,oBAAC,eAAD;GAAe,eAAa,GAAG,WAAW;GAAiC;aACxE,cAAc,KAAK,WAClB,oBAAC,YAAD;IAAY,UAAU,OAAO;IAA6B,OAAO,OAAO;cACrE,OAAO;IACG,EAF+B,OAAO,MAEtC,CACb;GACY,EACT;IACR"}
@@ -1 +1 @@
1
- {"version":3,"file":"ControlGroup.d.ts","names":[],"sources":["../src/components/ControlGroup/ControlGroup.tsx"],"mappings":";;;;;;;UAKU,wBAAA;EACR,SAAA;EACA,UAAA;EACA,SAAA;EACA,SAAA;EACA,WAAA;EACA,KAAA,EAAO,cAAA;AAAA;AAAA,cAKI,eAAA,QAAe,wBAAA;AAAA,UAQX,iBAAA,SAA0B,cAAA;EACzC,QAAA;EACA,YAAA,uBAAmC,MAAA;EACnC,EAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,WAAA;EACA,KAAA,GAAQ,cAAA;EACR,cAAA,uBAAqC,MAAA;AAAA;AAAA,cAG1B,YAAA;EAAY,SAAA;EAAA,QAAA;EAAA,YAAA;EAAA,EAAA;EAAA,mBAAA;EAAA,mBAAA;EAAA,IAAA;EAAA,WAAA;EAAA,KAAA;EAAA,cAAA;EAAA,GAAA;AAAA,GAAoL,iBAAA,KAAiB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cA0CjN,gBAAA;EAAgB,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,IAAA,MAAK,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"ControlGroup.d.ts","names":[],"sources":["../src/components/ControlGroup/ControlGroup.tsx"],"mappings":";;;;;;;UAKU,wBAAA;EACR,SAAA;EACA,UAAA;EACA,SAAA;EACA,SAAA;EACA,WAAA;EACA,KAAA,EAAO,cAAA;AAAA;AAAA,cAKI,eAAA,QAAe,wBAAA;AAAA,UAQX,iBAAA,SAA0B,cAAA;EACzC,QAAA;EACA,YAAA,uBAAmC,MAAA;EACnC,EAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,WAAA;EACA,KAAA,GAAQ,cAAA;EACR,cAAA,uBAAqC,MAAA;AAAA;AAAA,cAG1B,YAAA;EAAY,SAAA;EAAA,QAAA;EAAA,YAAA;EAAA,EAAA;EAAA,mBAAA;EAAA,mBAAA;EAAA,IAAA;EAAA,WAAA;EAAA,KAAA;EAAA,cAAA;EAAA,GAAA;AAAA,GAAoL,iBAAA,KAAiB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAuCjN,gBAAA;EAAgB,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,IAAA,MAAK,oBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -30,7 +30,7 @@ const ControlGroup = ({ className, disabled, errorMessage, id, messageReserveLin
30
30
  },
31
31
  children: /* @__PURE__ */ jsxs("div", {
32
32
  "data-slot": "control-group-field",
33
- className: "gap-1.5 flex w-full flex-col",
33
+ className: "flex w-full flex-col gap-1.5",
34
34
  children: [
35
35
  /* @__PURE__ */ jsx("div", {
36
36
  "data-slot": "control-group",
@@ -1 +1 @@
1
- {"version":3,"file":"ControlGroup.js","names":[],"sources":["../src/components/ControlGroup/ControlGroup.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId, useFormFieldState, WarningMessage, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { createContext, useContext, type ComponentProps } from 'react'\n\ninterface ControlGroupContextValue {\n messageId?: string\n isDisabled: boolean\n isInvalid: boolean\n isLoading: boolean\n orientation: 'horizontal' | 'vertical'\n state: FormFieldState\n}\n\nconst ControlGroupContext = createContext<ControlGroupContextValue | null>(null)\n\nexport const useControlGroup = () => {\n const context = useContext(ControlGroupContext)\n if (context === null) {\n throw new Error('useControlGroup must be used within a ControlGroup')\n }\n return context\n}\n\nexport interface ControlGroupProps extends ComponentProps<'div'> {\n disabled?: boolean\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name?: string\n orientation?: 'horizontal' | 'vertical'\n state?: FormFieldState\n warningMessage?: string | string[] | Record<string, unknown> | null\n}\n\nexport const ControlGroup = ({ className, disabled, errorMessage, id, messageReserveLines = 1, messageReserveSpace = false, name, orientation = 'horizontal', state = 'default', warningMessage, ...props }: ControlGroupProps) => {\n const groupId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(groupId)\n const warningMessageId = `${groupId}-warning`\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n\n return (\n <ControlGroupContext.Provider value={{ messageId, isDisabled, isInvalid, isLoading, orientation, state }}>\n <div\n data-slot='control-group-field'\n className='gap-1.5 flex w-full flex-col'\n >\n <div\n data-slot='control-group'\n data-orientation={orientation}\n data-state={state}\n id={groupId}\n role='group'\n aria-describedby={messageId}\n className={cn('group flex w-full', orientation === 'vertical' && 'flex-col', isDisabled && 'pointer-events-none opacity-50', className)}\n {...props}\n />\n <ErrorMessage\n dataTestId='spectral-control-group-error-message'\n id={errorMessageId}\n message={isInvalid ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-control-group-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </ControlGroupContext.Provider>\n )\n}\n\nexport const ControlGroupItem = ({ className, ...props }: ComponentProps<typeof Slot>) => {\n const { orientation } = useControlGroup()\n\n return (\n <Slot\n data-slot='control-group-item'\n className={cn(\n 'rounded-none focus-within:z-10 hover:z-10',\n orientation === 'horizontal' && 'first:rounded-s-md last:me-0 last:rounded-e-md -me-0.5 h-auto',\n orientation === 'vertical' && 'first:rounded-ss-md first:rounded-se-md last:rounded-ee-md last:rounded-es-md last:mbe-0 -mbe-0.5 w-auto',\n className,\n )}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;;;;AAcA,MAAM,sBAAsB,cAA+C,KAAK;AAEhF,MAAa,wBAAwB;CACnC,MAAM,UAAU,WAAW,oBAAoB;AAC/C,KAAI,YAAY,KACd,OAAM,IAAI,MAAM,qDAAqD;AAEvE,QAAO;;AAeT,MAAa,gBAAgB,EAAE,WAAW,UAAU,cAAc,IAAI,sBAAsB,GAAG,sBAAsB,OAAO,MAAM,cAAc,cAAc,QAAQ,WAAW,gBAAgB,GAAG,YAA+B;CACjO,MAAM,UAAU,eAAe,IAAI,KAAK;CACxC,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,mBAAmB,GAAG,QAAQ;CACpC,MAAM,EAAE,YAAY,WAAW,cAAc,kBAAkB,UAAU,MAAM;CAC/E,MAAM,YAAY,UAAU,WAAW,eAAe,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;AAElI,QACE,oBAAC,oBAAoB,UAArB;EAA8B,OAAO;GAAE;GAAW;GAAY;GAAW;GAAW;GAAa;GAAO;YACtG,qBAAC,OAAD;GACE,aAAU;GACV,WAAU;aAFZ;IAIE,oBAAC,OAAD;KACE,aAAU;KACV,oBAAkB;KAClB,cAAY;KACZ,IAAI;KACJ,MAAK;KACL,oBAAkB;KAClB,WAAW,GAAG,qBAAqB,gBAAgB,cAAc,YAAY,cAAc,kCAAkC,UAAU;KACvI,GAAI;KACJ;IACF,oBAAC,cAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,YAAY,eAAe;KACf;KACrB,qBAAqB,uBAAuB,UAAU;KACtD;IACF,oBAAC,gBAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,UAAU,YAAY,iBAAiB;KAC3B;KACrB,qBAAqB,uBAAuB,UAAU;KACtD;IACE;;EACuB;;AAInC,MAAa,oBAAoB,EAAE,WAAW,GAAG,YAAyC;CACxF,MAAM,EAAE,gBAAgB,iBAAiB;AAEzC,QACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GACT,6CACA,gBAAgB,gBAAgB,iEAChC,gBAAgB,cAAc,4GAC9B,UACD;EACD,GAAI;EACJ"}
1
+ {"version":3,"file":"ControlGroup.js","names":[],"sources":["../src/components/ControlGroup/ControlGroup.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId, useFormFieldState, WarningMessage, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { createContext, useContext, type ComponentProps } from 'react'\n\ninterface ControlGroupContextValue {\n messageId?: string\n isDisabled: boolean\n isInvalid: boolean\n isLoading: boolean\n orientation: 'horizontal' | 'vertical'\n state: FormFieldState\n}\n\nconst ControlGroupContext = createContext<ControlGroupContextValue | null>(null)\n\nexport const useControlGroup = () => {\n const context = useContext(ControlGroupContext)\n if (context === null) {\n throw new Error('useControlGroup must be used within a ControlGroup')\n }\n return context\n}\n\nexport interface ControlGroupProps extends ComponentProps<'div'> {\n disabled?: boolean\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name?: string\n orientation?: 'horizontal' | 'vertical'\n state?: FormFieldState\n warningMessage?: string | string[] | Record<string, unknown> | null\n}\n\nexport const ControlGroup = ({ className, disabled, errorMessage, id, messageReserveLines = 1, messageReserveSpace = false, name, orientation = 'horizontal', state = 'default', warningMessage, ...props }: ControlGroupProps) => {\n const groupId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(groupId)\n const warningMessageId = `${groupId}-warning`\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n\n return (\n <ControlGroupContext.Provider value={{ messageId, isDisabled, isInvalid, isLoading, orientation, state }}>\n <div data-slot='control-group-field' className='flex w-full flex-col gap-1.5'>\n <div\n data-slot='control-group'\n data-orientation={orientation}\n data-state={state}\n id={groupId}\n role='group'\n aria-describedby={messageId}\n className={cn('group flex w-full', orientation === 'vertical' && 'flex-col', isDisabled && 'pointer-events-none opacity-50', className)}\n {...props}\n />\n <ErrorMessage\n dataTestId='spectral-control-group-error-message'\n id={errorMessageId}\n message={isInvalid ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-control-group-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </ControlGroupContext.Provider>\n )\n}\n\nexport const ControlGroupItem = ({ className, ...props }: ComponentProps<typeof Slot>) => {\n const { orientation } = useControlGroup()\n\n return (\n <Slot\n data-slot='control-group-item'\n className={cn(\n 'rounded-none focus-within:z-10 hover:z-10',\n orientation === 'horizontal' && 'first:rounded-s-md last:me-0 last:rounded-e-md -me-0.5 h-auto',\n orientation === 'vertical' && 'first:rounded-ss-md first:rounded-se-md last:rounded-ee-md last:rounded-es-md last:mbe-0 -mbe-0.5 w-auto',\n className,\n )}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;;;;AAcA,MAAM,sBAAsB,cAA+C,KAAK;AAEhF,MAAa,wBAAwB;CACnC,MAAM,UAAU,WAAW,oBAAoB;AAC/C,KAAI,YAAY,KACd,OAAM,IAAI,MAAM,qDAAqD;AAEvE,QAAO;;AAeT,MAAa,gBAAgB,EAAE,WAAW,UAAU,cAAc,IAAI,sBAAsB,GAAG,sBAAsB,OAAO,MAAM,cAAc,cAAc,QAAQ,WAAW,gBAAgB,GAAG,YAA+B;CACjO,MAAM,UAAU,eAAe,IAAI,KAAK;CACxC,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,mBAAmB,GAAG,QAAQ;CACpC,MAAM,EAAE,YAAY,WAAW,cAAc,kBAAkB,UAAU,MAAM;CAC/E,MAAM,YAAY,UAAU,WAAW,eAAe,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;AAElI,QACE,oBAAC,oBAAoB,UAArB;EAA8B,OAAO;GAAE;GAAW;GAAY;GAAW;GAAW;GAAa;GAAO;YACtG,qBAAC,OAAD;GAAK,aAAU;GAAsB,WAAU;aAA/C;IACE,oBAAC,OAAD;KACE,aAAU;KACV,oBAAkB;KAClB,cAAY;KACZ,IAAI;KACJ,MAAK;KACL,oBAAkB;KAClB,WAAW,GAAG,qBAAqB,gBAAgB,cAAc,YAAY,cAAc,kCAAkC,UAAU;KACvI,GAAI;KACJ;IACF,oBAAC,cAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,YAAY,eAAe;KACf;KACrB,qBAAqB,uBAAuB,UAAU;KACtD;IACF,oBAAC,gBAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,UAAU,YAAY,iBAAiB;KAC3B;KACrB,qBAAqB,uBAAuB,UAAU;KACtD;IACE;;EACuB;;AAInC,MAAa,oBAAoB,EAAE,WAAW,GAAG,YAAyC;CACxF,MAAM,EAAE,gBAAgB,iBAAiB;AAEzC,QACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GACT,6CACA,gBAAgB,gBAAgB,iEAChC,gBAAgB,cAAc,4GAC9B,UACD;EACD,GAAI;EACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"Card.d.ts","names":[],"sources":["../../src/components/DataCard/Card.tsx"],"mappings":";;;;;KAIY,SAAA,GAAY,cAAA;EAA0B,OAAA;AAAA;AAAA,cAIrC,QAAA;EAAA,GAAQ;AAAA,GAAkB,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAUnC,UAAA;EAAU,SAAA;EAAA,GAAA;AAAA,GAA6B,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWhD,SAAA;EAAS,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAA8C,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAahE,iBAAA;EAAiB,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAA8C,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAaxE,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWjD,IAAA;EAAI,OAAA;EAAA,QAAA;EAAA,SAAA;EAAA,GAAA;AAAA,GAAwD,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Card.d.ts","names":[],"sources":["../../src/components/DataCard/Card.tsx"],"mappings":";;;;;KAIY,SAAA,GAAY,cAAA;EAA0B,OAAA;AAAA;AAAA,cAIrC,QAAA;EAAA,GAAQ;AAAA,GAAkB,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAInC,UAAA;EAAU,SAAA;EAAA,GAAA;AAAA,GAA6B,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIhD,SAAA;EAAS,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAA8C,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAMhE,iBAAA;EAAiB,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAA8C,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAMxE,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIjD,IAAA;EAAI,OAAA;EAAA,QAAA;EAAA,SAAA;EAAA,GAAA;AAAA,GAAwD,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Card.js","names":[],"sources":["../../src/components/DataCard/Card.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport type CardProps = ComponentProps<'div'> & { asChild?: boolean }\n\nconst cardClasses = 'text-text-primary flex flex-col w-full card-effects p-3 gap-6 rounded-xl'\n\nexport const CardBase = ({ ...props }: CardProps) => {\n return (\n <div\n data-slot='card'\n data-testid='spectral-card'\n {...props}\n />\n )\n}\n\nexport const CardHeader = ({ className, ...props }: CardProps) => {\n return (\n <div\n className={cn('pb-4 @container/card-header flex items-center justify-between', className)}\n data-slot='card-header'\n data-testid='spectral-card-header'\n {...props}\n />\n )\n}\n\nexport const CardTitle = ({ className, asChild = false, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return (\n <Comp\n className={cn('font-semibold text-xl', className)}\n data-slot='card-title'\n data-testid='spectral-card-title'\n {...props}\n />\n )\n}\n\nexport const CardHeaderEndSlot = ({ className, asChild = false, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return (\n <Comp\n className={cn('justify-self-end', className)}\n data-slot='card-action'\n data-testid='spectral-card-action'\n {...props}\n />\n )\n}\n\nexport const CardContent = ({ className, ...props }: CardProps) => {\n return (\n <div\n className={className}\n data-slot='card-content'\n data-testid='spectral-card-content'\n {...props}\n />\n )\n}\n\nexport const Card = ({ asChild = false, children, className, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return (\n <Comp\n className={cn(cardClasses, className)}\n data-slot='card'\n data-testid='spectral-card'\n {...props}\n >\n {children}\n </Comp>\n )\n}\n"],"mappings":";;;;;;;AAMA,MAAM,cAAc;AAEpB,MAAa,YAAY,EAAE,GAAG,YAAuB;AACnD,QACE,oBAAC,OAAD;EACE,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAa,cAAc,EAAE,WAAW,GAAG,YAAuB;AAChE,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,iEAAiE,UAAU;EACzF,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAa,aAAa,EAAE,WAAW,UAAU,OAAO,GAAG,YAAuB;AAGhF,QACE,oBAHW,UAAU,OAAO,OAG5B;EACE,WAAW,GAAG,yBAAyB,UAAU;EACjD,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAa,qBAAqB,EAAE,WAAW,UAAU,OAAO,GAAG,YAAuB;AAGxF,QACE,oBAHW,UAAU,OAAO,OAG5B;EACE,WAAW,GAAG,oBAAoB,UAAU;EAC5C,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAa,eAAe,EAAE,WAAW,GAAG,YAAuB;AACjE,QACE,oBAAC,OAAD;EACa;EACX,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAa,QAAQ,EAAE,UAAU,OAAO,UAAU,WAAW,GAAG,YAAuB;AAGrF,QACE,oBAHW,UAAU,OAAO,OAG5B;EACE,WAAW,GAAG,aAAa,UAAU;EACrC,aAAU;EACV,eAAY;EACZ,GAAI;EAEH;EACI"}
1
+ {"version":3,"file":"Card.js","names":[],"sources":["../../src/components/DataCard/Card.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport type CardProps = ComponentProps<'div'> & { asChild?: boolean }\n\nconst cardClasses = 'text-text-primary flex flex-col w-full card-effects p-3 gap-6 rounded-xl'\n\nexport const CardBase = ({ ...props }: CardProps) => {\n return <div data-slot='card' data-testid='spectral-card' {...props} />\n}\n\nexport const CardHeader = ({ className, ...props }: CardProps) => {\n return <div className={cn('pb-4 @container/card-header flex items-center justify-between', className)} data-slot='card-header' data-testid='spectral-card-header' {...props} />\n}\n\nexport const CardTitle = ({ className, asChild = false, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return <Comp className={cn('font-semibold text-xl', className)} data-slot='card-title' data-testid='spectral-card-title' {...props} />\n}\n\nexport const CardHeaderEndSlot = ({ className, asChild = false, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return <Comp className={cn('justify-self-end', className)} data-slot='card-action' data-testid='spectral-card-action' {...props} />\n}\n\nexport const CardContent = ({ className, ...props }: CardProps) => {\n return <div className={className} data-slot='card-content' data-testid='spectral-card-content' {...props} />\n}\n\nexport const Card = ({ asChild = false, children, className, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return (\n <Comp className={cn(cardClasses, className)} data-slot='card' data-testid='spectral-card' {...props}>\n {children}\n </Comp>\n )\n}\n"],"mappings":";;;;;;;AAMA,MAAM,cAAc;AAEpB,MAAa,YAAY,EAAE,GAAG,YAAuB;AACnD,QAAO,oBAAC,OAAD;EAAK,aAAU;EAAO,eAAY;EAAgB,GAAI;EAAS;;AAGxE,MAAa,cAAc,EAAE,WAAW,GAAG,YAAuB;AAChE,QAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,iEAAiE,UAAU;EAAE,aAAU;EAAc,eAAY;EAAuB,GAAI;EAAS;;AAGjL,MAAa,aAAa,EAAE,WAAW,UAAU,OAAO,GAAG,YAAuB;AAGhF,QAAO,oBAFM,UAAU,OAAO,OAEvB;EAAM,WAAW,GAAG,yBAAyB,UAAU;EAAE,aAAU;EAAa,eAAY;EAAsB,GAAI;EAAS;;AAGxI,MAAa,qBAAqB,EAAE,WAAW,UAAU,OAAO,GAAG,YAAuB;AAGxF,QAAO,oBAFM,UAAU,OAAO,OAEvB;EAAM,WAAW,GAAG,oBAAoB,UAAU;EAAE,aAAU;EAAc,eAAY;EAAuB,GAAI;EAAS;;AAGrI,MAAa,eAAe,EAAE,WAAW,GAAG,YAAuB;AACjE,QAAO,oBAAC,OAAD;EAAgB;EAAW,aAAU;EAAe,eAAY;EAAwB,GAAI;EAAS;;AAG9G,MAAa,QAAQ,EAAE,UAAU,OAAO,UAAU,WAAW,GAAG,YAAuB;AAGrF,QACE,oBAHW,UAAU,OAAO,OAG5B;EAAM,WAAW,GAAG,aAAa,UAAU;EAAE,aAAU;EAAO,eAAY;EAAgB,GAAI;EAC3F;EACI"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataCard.js","names":[],"sources":["../src/components/DataCard/DataCard.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\nimport { Card, CardContent, CardHeader, CardTitle, type CardProps } from './Card'\n\nexport type DataCardProps = CardProps & {\n accentColor: string\n cardHeaderEndSlot: ReactNode\n dataDescription: string\n dataValue: string | number\n title: string\n}\n\nexport const DataCard = ({ accentColor, cardHeaderEndSlot, className, dataDescription, dataValue, title, ...props }: DataCardProps) => {\n return (\n <Card\n className={cn('gap-4 card-effects', className)}\n {...props}\n data-testid='spectral-datacard'\n >\n <CardHeader\n className='pb-0'\n data-testid='spectral-datacard-header'\n >\n <CardTitle\n className='text-sm font-bold uppercase'\n data-testid='spectral-datacard-title'\n >\n {title}\n </CardTitle>\n <div\n style={{ color: accentColor }}\n data-testid='spectral-datacard-end-slot'\n >\n {cardHeaderEndSlot}\n </div>\n </CardHeader>\n <CardContent>\n <div className='gap-4 flex flex-col'>\n <div\n className='text-4xl font-bold tabular-nums'\n data-testid='spectral-datacard-data-value'\n style={{ color: accentColor }}\n >\n {dataValue}\n </div>\n <div\n className='text-xs text-data-card-description'\n data-testid='spectral-datacard-data-description'\n >\n {dataDescription}\n </div>\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":";;;;;;;AAYA,MAAa,YAAY,EAAE,aAAa,mBAAmB,WAAW,iBAAiB,WAAW,OAAO,GAAG,YAA2B;AACrI,QACE,qBAAC,MAAD;EACE,WAAW,GAAG,sBAAsB,UAAU;EAC9C,GAAI;EACJ,eAAY;YAHd,CAKE,qBAAC,YAAD;GACE,WAAU;GACV,eAAY;aAFd,CAIE,oBAAC,WAAD;IACE,WAAU;IACV,eAAY;cAEX;IACS,GACZ,oBAAC,OAAD;IACE,OAAO,EAAE,OAAO,aAAa;IAC7B,eAAY;cAEX;IACG,EACK;MACb,oBAAC,aAAD,YACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IACE,WAAU;IACV,eAAY;IACZ,OAAO,EAAE,OAAO,aAAa;cAE5B;IACG,GACN,oBAAC,OAAD;IACE,WAAU;IACV,eAAY;cAEX;IACG,EACF;MACM,EACT"}
1
+ {"version":3,"file":"DataCard.js","names":[],"sources":["../src/components/DataCard/DataCard.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\nimport { Card, CardContent, CardHeader, CardTitle, type CardProps } from './Card'\n\nexport type DataCardProps = CardProps & {\n accentColor: string\n cardHeaderEndSlot: ReactNode\n dataDescription: string\n dataValue: string | number\n title: string\n}\n\nexport const DataCard = ({ accentColor, cardHeaderEndSlot, className, dataDescription, dataValue, title, ...props }: DataCardProps) => {\n return (\n <Card className={cn('gap-4 card-effects', className)} {...props} data-testid='spectral-datacard'>\n <CardHeader className='pb-0' data-testid='spectral-datacard-header'>\n <CardTitle className='text-sm font-bold uppercase' data-testid='spectral-datacard-title'>\n {title}\n </CardTitle>\n <div style={{ color: accentColor }} data-testid='spectral-datacard-end-slot'>\n {cardHeaderEndSlot}\n </div>\n </CardHeader>\n <CardContent>\n <div className='gap-4 flex flex-col'>\n <div className='text-4xl font-bold tabular-nums' data-testid='spectral-datacard-data-value' style={{ color: accentColor }}>\n {dataValue}\n </div>\n <div className='text-xs text-data-card-description' data-testid='spectral-datacard-data-description'>\n {dataDescription}\n </div>\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":";;;;;;;AAYA,MAAa,YAAY,EAAE,aAAa,mBAAmB,WAAW,iBAAiB,WAAW,OAAO,GAAG,YAA2B;AACrI,QACE,qBAAC,MAAD;EAAM,WAAW,GAAG,sBAAsB,UAAU;EAAE,GAAI;EAAO,eAAY;YAA7E,CACE,qBAAC,YAAD;GAAY,WAAU;GAAO,eAAY;aAAzC,CACE,oBAAC,WAAD;IAAW,WAAU;IAA8B,eAAY;cAC5D;IACS,GACZ,oBAAC,OAAD;IAAK,OAAO,EAAE,OAAO,aAAa;IAAE,eAAY;cAC7C;IACG,EACK;MACb,oBAAC,aAAD,YACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IAAK,WAAU;IAAkC,eAAY;IAA+B,OAAO,EAAE,OAAO,aAAa;cACtH;IACG,GACN,oBAAC,OAAD;IAAK,WAAU;IAAqC,eAAY;cAC7D;IACG,EACF;MACM,EACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"Calendar.js","names":[],"sources":["../../src/components/DateTimePicker/Calendar.tsx"],"sourcesContent":["import { ChevronDownIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { useMemo } from 'react'\nimport { DayPicker, type DayPickerProps, type Matcher, type Locale } from 'react-day-picker'\n\nexport type CalendarProps = DayPickerProps & {\n disabled?: Matcher | Matcher[]\n disablePastDates?: boolean\n fixedWeeks?: boolean\n /** The locale object used to localize dates. Import from 'react-day-picker/locale'. */\n locale?: Partial<Locale>\n}\n\nexport const Calendar = ({ classNames, disabled, disablePastDates = true, fixedWeeks, locale, showOutsideDays = true, ...props }: CalendarProps) => {\n // Memoize today's date to avoid creating new Date objects on every render\n const today = useMemo(() => new Date(), [])\n\n // Combine user-provided disabled dates with past dates if enabled\n const combinedDisabled: Matcher[] = [...(disablePastDates ? [{ before: today }] : []), ...(Array.isArray(disabled) ? disabled : disabled ? [disabled] : [])]\n\n return (\n <DayPicker\n {...props}\n classNames={{\n months: cn('months relative flex'),\n month: cn('month'),\n caption: cn('calendar-header'),\n caption_label: cn('month-title'),\n nav: cn('rdp-nav flex w-full items-center'),\n nav_button: cn('nav-button h-7 w-7 p-0 bg-transparent opacity-50 hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent'),\n button_previous: cn('nav-prev left-1 top-0 absolute'),\n button_next: cn('nav-next right-1 top-0 absolute'),\n table: cn('table w-full border-collapse'),\n head_row: cn('day-head-row flex'),\n head_cell: cn('days-of-week'),\n row: cn('day-row mt-2 flex w-full'),\n cell: cn('day-cell'),\n day: cn('day'),\n day_range_start: cn('day-range-start'),\n day_range_middle: cn('day-range-middle'),\n day_range_end: cn('day-range-end'),\n day_selected: cn('day-selected'),\n day_outside: cn('day-outside'),\n day_disabled: cn('day-disabled'),\n hidden: cn('hidden'),\n ...classNames,\n }}\n components={{\n Chevron: ({ orientation }) => (\n <ChevronDownIcon\n aria-hidden='true'\n className={cn('size-4', orientation === 'left' && 'rotate-90', orientation === 'right' && '-rotate-90')}\n />\n ),\n }}\n data-slot='calendar'\n data-testid='spectral-calendar'\n disabled={combinedDisabled.length > 0 ? combinedDisabled : undefined}\n fixedWeeks={fixedWeeks}\n locale={locale}\n showOutsideDays={showOutsideDays}\n />\n )\n}\n\nCalendar.displayName = 'Calendar'\n"],"mappings":";;;;;;;;AAaA,MAAa,YAAY,EAAE,YAAY,UAAU,mBAAmB,MAAM,YAAY,QAAQ,kBAAkB,MAAM,GAAG,YAA2B;CAElJ,MAAM,QAAQ,8BAAc,IAAI,MAAM,EAAE,EAAE,CAAC;CAG3C,MAAM,mBAA8B,CAAC,GAAI,mBAAmB,CAAC,EAAE,QAAQ,OAAO,CAAC,GAAG,EAAE,EAAG,GAAI,MAAM,QAAQ,SAAS,GAAG,WAAW,WAAW,CAAC,SAAS,GAAG,EAAE,CAAE;AAE5J,QACE,oBAAC,WAAD;EACE,GAAI;EACJ,YAAY;GACV,QAAQ,GAAG,uBAAuB;GAClC,OAAO,GAAG,QAAQ;GAClB,SAAS,GAAG,kBAAkB;GAC9B,eAAe,GAAG,cAAc;GAChC,KAAK,GAAG,mCAAmC;GAC3C,YAAY,GAAG,mLAAmL;GAClM,iBAAiB,GAAG,iCAAiC;GACrD,aAAa,GAAG,kCAAkC;GAClD,OAAO,GAAG,+BAA+B;GACzC,UAAU,GAAG,oBAAoB;GACjC,WAAW,GAAG,eAAe;GAC7B,KAAK,GAAG,2BAA2B;GACnC,MAAM,GAAG,WAAW;GACpB,KAAK,GAAG,MAAM;GACd,iBAAiB,GAAG,kBAAkB;GACtC,kBAAkB,GAAG,mBAAmB;GACxC,eAAe,GAAG,gBAAgB;GAClC,cAAc,GAAG,eAAe;GAChC,aAAa,GAAG,cAAc;GAC9B,cAAc,GAAG,eAAe;GAChC,QAAQ,GAAG,SAAS;GACpB,GAAG;GACJ;EACD,YAAY,EACV,UAAU,EAAE,kBACV,oBAAC,iBAAD;GACE,eAAY;GACZ,WAAW,GAAG,UAAU,gBAAgB,UAAU,aAAa,gBAAgB,WAAW,aAAa;GACvG,GAEL;EACD,aAAU;EACV,eAAY;EACZ,UAAU,iBAAiB,SAAS,IAAI,mBAAmB;EAC/C;EACJ;EACS;EACjB;;AAIN,SAAS,cAAc"}
1
+ {"version":3,"file":"Calendar.js","names":[],"sources":["../../src/components/DateTimePicker/Calendar.tsx"],"sourcesContent":["import { ChevronDownIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { useMemo } from 'react'\nimport { DayPicker, type DayPickerProps, type Matcher, type Locale } from 'react-day-picker'\n\nexport type CalendarProps = DayPickerProps & {\n disabled?: Matcher | Matcher[]\n disablePastDates?: boolean\n fixedWeeks?: boolean\n /** The locale object used to localize dates. Import from 'react-day-picker/locale'. */\n locale?: Partial<Locale>\n}\n\nexport const Calendar = ({ classNames, disabled, disablePastDates = true, fixedWeeks, locale, showOutsideDays = true, ...props }: CalendarProps) => {\n // Memoize today's date to avoid creating new Date objects on every render\n const today = useMemo(() => new Date(), [])\n\n // Combine user-provided disabled dates with past dates if enabled\n const combinedDisabled: Matcher[] = [...(disablePastDates ? [{ before: today }] : []), ...(Array.isArray(disabled) ? disabled : disabled ? [disabled] : [])]\n\n return (\n <DayPicker\n {...props}\n classNames={{\n months: cn('months relative flex'),\n month: cn('month'),\n caption: cn('calendar-header'),\n caption_label: cn('month-title'),\n nav: cn('rdp-nav flex w-full items-center'),\n nav_button: cn('nav-button h-7 w-7 p-0 bg-transparent opacity-50 hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent'),\n button_previous: cn('nav-prev left-1 top-0 absolute'),\n button_next: cn('nav-next right-1 top-0 absolute'),\n table: cn('table w-full border-collapse'),\n head_row: cn('day-head-row flex'),\n head_cell: cn('days-of-week'),\n row: cn('day-row mt-2 flex w-full'),\n cell: cn('day-cell'),\n day: cn('day'),\n day_range_start: cn('day-range-start'),\n day_range_middle: cn('day-range-middle'),\n day_range_end: cn('day-range-end'),\n day_selected: cn('day-selected'),\n day_outside: cn('day-outside'),\n day_disabled: cn('day-disabled'),\n hidden: cn('hidden'),\n ...classNames,\n }}\n components={{\n Chevron: ({ orientation }) => <ChevronDownIcon aria-hidden='true' className={cn('size-4', orientation === 'left' && 'rotate-90', orientation === 'right' && '-rotate-90')} />,\n }}\n data-slot='calendar'\n data-testid='spectral-calendar'\n disabled={combinedDisabled.length > 0 ? combinedDisabled : undefined}\n fixedWeeks={fixedWeeks}\n locale={locale}\n showOutsideDays={showOutsideDays}\n />\n )\n}\n\nCalendar.displayName = 'Calendar'\n"],"mappings":";;;;;;;;AAaA,MAAa,YAAY,EAAE,YAAY,UAAU,mBAAmB,MAAM,YAAY,QAAQ,kBAAkB,MAAM,GAAG,YAA2B;CAElJ,MAAM,QAAQ,8BAAc,IAAI,MAAM,EAAE,EAAE,CAAC;CAG3C,MAAM,mBAA8B,CAAC,GAAI,mBAAmB,CAAC,EAAE,QAAQ,OAAO,CAAC,GAAG,EAAE,EAAG,GAAI,MAAM,QAAQ,SAAS,GAAG,WAAW,WAAW,CAAC,SAAS,GAAG,EAAE,CAAE;AAE5J,QACE,oBAAC,WAAD;EACE,GAAI;EACJ,YAAY;GACV,QAAQ,GAAG,uBAAuB;GAClC,OAAO,GAAG,QAAQ;GAClB,SAAS,GAAG,kBAAkB;GAC9B,eAAe,GAAG,cAAc;GAChC,KAAK,GAAG,mCAAmC;GAC3C,YAAY,GAAG,mLAAmL;GAClM,iBAAiB,GAAG,iCAAiC;GACrD,aAAa,GAAG,kCAAkC;GAClD,OAAO,GAAG,+BAA+B;GACzC,UAAU,GAAG,oBAAoB;GACjC,WAAW,GAAG,eAAe;GAC7B,KAAK,GAAG,2BAA2B;GACnC,MAAM,GAAG,WAAW;GACpB,KAAK,GAAG,MAAM;GACd,iBAAiB,GAAG,kBAAkB;GACtC,kBAAkB,GAAG,mBAAmB;GACxC,eAAe,GAAG,gBAAgB;GAClC,cAAc,GAAG,eAAe;GAChC,aAAa,GAAG,cAAc;GAC9B,cAAc,GAAG,eAAe;GAChC,QAAQ,GAAG,SAAS;GACpB,GAAG;GACJ;EACD,YAAY,EACV,UAAU,EAAE,kBAAkB,oBAAC,iBAAD;GAAiB,eAAY;GAAO,WAAW,GAAG,UAAU,gBAAgB,UAAU,aAAa,gBAAgB,WAAW,aAAa;GAAI,GAC9K;EACD,aAAU;EACV,eAAY;EACZ,UAAU,iBAAiB,SAAS,IAAI,mBAAmB;EAC/C;EACJ;EACS;EACjB;;AAIN,SAAS,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimeDisplayInput.js","names":[],"sources":["../../src/components/DateTimePicker/DateTimeDisplayInput.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { getInputClasses } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { forwardRef, useCallback, useEffect, useId, useMemo, useRef, type ComponentProps, type KeyboardEvent, type ReactNode } from 'react'\nimport { formatSelectPeriodLabel, getLocalizedPeriodLabels, getResolvedLocale, type HourFormat, type PeriodLabels } from './DateTimeUtils'\n\nexport interface DateTimeDisplayInputProps extends Omit<ComponentProps<'div'>, 'onChange' | 'defaultValue'> {\n defaultValue?: Date\n disabled?: boolean\n endIcon?: ReactNode\n hourFormat?: HourFormat\n label?: string\n locale?: string\n onChange?: (date: Date | undefined) => void\n showTime?: boolean\n state?: 'default' | 'disabled' | 'error'\n value?: Date\n // Legacy prop names for backward compatibility\n /** @deprecated Use `value` instead */\n date?: Date\n /** @deprecated Use `onChange` instead */\n onDateChange?: (date: Date | undefined) => void\n}\n\ninterface SegmentConfig {\n length: number\n max: number\n min: number\n type: 'month' | 'day' | 'year' | 'hour' | 'minute' | 'period'\n}\n\nconst SEGMENT_CONFIGS: Record<string, SegmentConfig> = {\n month: { type: 'month', min: 1, max: 12, length: 2 },\n day: { type: 'day', min: 1, max: 31, length: 2 },\n year: { type: 'year', min: 1900, max: 2100, length: 4 },\n hour12: { type: 'hour', min: 1, max: 12, length: 2 },\n hour24: { type: 'hour', min: 0, max: 23, length: 2 },\n minute: { type: 'minute', min: 0, max: 59, length: 2 },\n period: { type: 'period', min: 0, max: 1, length: 2 },\n}\n\n/**\n * Get max days for a given month/year\n */\nconst getMaxDaysInMonth = (month: number, year: number): number => {\n if (month === 2) {\n const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0\n return isLeapYear ? 29 : 28\n }\n if ([4, 6, 9, 11].includes(month)) return 30\n return 31\n}\n\n/**\n * A single segment input (month, day, year, hour, minute)\n */\ninterface SegmentInputProps {\n ariaLabel: string\n config: SegmentConfig\n disabled?: boolean\n onLeftFocus?: () => void\n onRightFocus?: () => void\n onValueChange: (value: number) => void\n periodLabels?: PeriodLabels\n value: number | undefined\n}\n\n/**\n * SegmentInput - A single editable segment (month, day, year, hour, minute, period)\n *\n * Uses an uncontrolled input pattern to avoid React re-render issues during typing:\n * - Edit buffer stored in ref (not state) to prevent re-renders\n * - DOM value manipulated directly during typing\n * - Only syncs with React when value is committed (blur, tab, arrow keys)\n */\nconst SegmentInput = ({ ariaLabel, config, disabled, onLeftFocus, onRightFocus, onValueChange, periodLabels, value }: SegmentInputProps) => {\n const inputRef = useRef<HTMLInputElement>(null)\n // Use refs to avoid re-renders during typing - this is the key to making it work\n const editBufferRef = useRef('')\n const isEditingRef = useRef(false)\n\n // Placeholder text for empty segments\n const placeholderText = useMemo(() => {\n switch (config.type) {\n case 'month':\n return 'MM'\n case 'day':\n return 'dd'\n case 'year':\n return 'yyyy'\n case 'hour':\n return config.max === 23 ? 'HH' : 'hh'\n case 'minute':\n return 'mm'\n case 'period':\n return (periodLabels?.am ?? 'am').toLowerCase()\n default:\n return '––'\n }\n }, [config.type, config.max, periodLabels])\n\n // Format display value from the committed value prop\n const displayValue = useMemo(() => {\n if (value === undefined) {\n return placeholderText\n }\n if (config.type === 'period') {\n const label = value === 0 ? (periodLabels?.am ?? 'am') : (periodLabels?.pm ?? 'pm')\n return label.toLowerCase()\n }\n return value.toString().padStart(config.length, '0')\n }, [value, config, periodLabels, placeholderText])\n\n // Sync input value when external value changes (and we're not editing)\n useEffect(() => {\n if (inputRef.current && !isEditingRef.current) {\n inputRef.current.value = displayValue\n }\n }, [displayValue])\n\n // Commit the edit buffer - called on blur, tab, arrow navigation\n const commitEdit = useCallback(() => {\n const buffer = editBufferRef.current\n if (buffer) {\n let numValue = parseInt(buffer, 10)\n if (!isNaN(numValue)) {\n numValue = Math.max(config.min, Math.min(config.max, numValue))\n onValueChange(numValue)\n }\n }\n // Reset edit state\n editBufferRef.current = ''\n isEditingRef.current = false\n // Sync display value after commit\n if (inputRef.current) {\n inputRef.current.value = displayValue\n }\n }, [config.min, config.max, displayValue, onValueChange])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return\n\n // Tab navigation (let it bubble naturally)\n if (e.key === 'Tab') {\n commitEdit()\n return\n }\n\n // Arrow navigation between segments\n if (e.key === 'ArrowRight') {\n e.preventDefault()\n commitEdit()\n onRightFocus?.()\n return\n }\n if (e.key === 'ArrowLeft') {\n e.preventDefault()\n commitEdit()\n onLeftFocus?.()\n return\n }\n\n // Period toggle (AM/PM)\n if (config.type === 'period') {\n e.preventDefault()\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n onValueChange(value === 0 ? 1 : 0)\n } else if (e.key.toLowerCase() === 'a') {\n onValueChange(0)\n } else if (e.key.toLowerCase() === 'p') {\n onValueChange(1)\n }\n return\n }\n\n // Arrow up/down to increment/decrement\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n editBufferRef.current = ''\n isEditingRef.current = false\n const newValue = value === undefined ? config.min : value >= config.max ? config.min : value + 1\n onValueChange(newValue)\n return\n }\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n editBufferRef.current = ''\n isEditingRef.current = false\n const newValue = value === undefined ? config.max : value <= config.min ? config.max : value - 1\n onValueChange(newValue)\n return\n }\n\n // Home/End for min/max\n if (e.key === 'Home') {\n e.preventDefault()\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(config.min)\n return\n }\n if (e.key === 'End') {\n e.preventDefault()\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(config.max)\n return\n }\n\n // Numeric input - directly manipulate DOM, no React state\n if (e.key >= '0' && e.key <= '9') {\n e.preventDefault()\n const newBuffer = editBufferRef.current + e.key\n const numValue = parseInt(newBuffer, 10)\n\n // For 2-digit fields\n if (config.length === 2) {\n if (newBuffer.length >= 2) {\n // Two digits entered - commit and advance\n const clamped = Math.max(config.min, Math.min(config.max, numValue))\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(clamped)\n onRightFocus?.()\n } else if (numValue * 10 > config.max) {\n // First digit is too large to form a valid two-digit number\n const clamped = Math.max(config.min, Math.min(config.max, numValue))\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(clamped)\n onRightFocus?.()\n } else {\n // First digit could lead to valid values, wait for second digit\n // Update refs and DOM directly - NO state update\n editBufferRef.current = newBuffer\n isEditingRef.current = true\n if (inputRef.current) {\n inputRef.current.value = newBuffer\n }\n }\n } else if (config.length === 4) {\n // Year field - advance after 4 digits\n if (newBuffer.length >= 4) {\n const clamped = Math.max(config.min, Math.min(config.max, numValue))\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(clamped)\n onRightFocus?.()\n } else {\n // Update refs and DOM directly - NO state update\n editBufferRef.current = newBuffer\n isEditingRef.current = true\n if (inputRef.current) {\n inputRef.current.value = newBuffer\n }\n }\n }\n return\n }\n\n if (e.key === 'Backspace') {\n e.preventDefault()\n if (editBufferRef.current) {\n const newBuffer = editBufferRef.current.slice(0, -1)\n editBufferRef.current = newBuffer\n isEditingRef.current = newBuffer.length > 0\n if (inputRef.current) {\n inputRef.current.value = newBuffer || displayValue\n }\n } else if (value !== undefined) {\n editBufferRef.current = ''\n isEditingRef.current = true\n onValueChange(config.min)\n if (inputRef.current) {\n inputRef.current.value = placeholderText\n }\n }\n }\n },\n [disabled, config, value, displayValue, placeholderText, onValueChange, onLeftFocus, onRightFocus, commitEdit],\n )\n\n const handleBlur = useCallback(() => {\n // Only commit if we have a partial edit\n if (editBufferRef.current) {\n commitEdit()\n }\n }, [commitEdit])\n\n const handleFocus = useCallback(() => {\n // Only clear buffer if we're not in the middle of an edit\n if (!isEditingRef.current) {\n editBufferRef.current = ''\n }\n // Move cursor to end\n const input = inputRef.current\n if (input) {\n const len = input.value.length\n input.setSelectionRange(len, len)\n }\n }, [])\n\n // Prevent browser from changing the input value directly\n const handleChange = useCallback(() => {\n // Reset to our controlled value if browser tries to change it\n if (inputRef.current) {\n inputRef.current.value = editBufferRef.current || displayValue\n }\n }, [displayValue])\n\n // Width and padding based on segment type\n const getSegmentStyle = useCallback(() => {\n switch (config.type) {\n case 'year':\n return { width: 46, paddingLeft: 0 }\n case 'period':\n return { width: 28, paddingLeft: 0, marginLeft: 4 }\n case 'month':\n return { width: 28, paddingLeft: 0 }\n case 'day':\n return { width: 28, paddingLeft: 0 }\n case 'hour':\n return { width: 28, paddingLeft: 0 }\n case 'minute':\n return { width: 30, paddingLeft: 0 }\n default:\n return { width: 24, paddingLeft: 0 }\n }\n }, [config.type])\n\n const segmentStyle = useMemo(() => getSegmentStyle(), [getSegmentStyle])\n const isPlaceholder = useMemo(() => value === undefined, [value])\n\n return (\n <input\n aria-label={ariaLabel}\n aria-valuemax={config.max}\n aria-valuemin={config.min}\n aria-valuenow={value}\n className={cn(\n 'rounded inline-flex items-center justify-center text-center tabular-nums',\n 'border-none bg-transparent outline-none',\n 'focus:bg-bg-tertiary focus:text-text-primary focus:ring-1 focus:ring-accent',\n 'hover:bg-bg-secondary',\n disabled && 'cursor-not-allowed opacity-50',\n isPlaceholder && 'text-text-placeholder text-sm',\n )}\n data-segment={config.type}\n defaultValue={displayValue}\n disabled={disabled}\n inputMode='numeric'\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n ref={inputRef}\n role='spinbutton'\n style={segmentStyle}\n tabIndex={disabled ? -1 : 0}\n />\n )\n}\n\n/**\n * A segmented date/time input that mimics native date input behavior.\n * Each segment (month, day, year, hour, minute, period) is separately focusable.\n *\n * Supports both controlled and uncontrolled usage:\n * - Controlled: `<DateTimeDisplayInput value={date} onChange={setDate} />`\n * - Uncontrolled: `<DateTimeDisplayInput defaultValue={new Date()} />`\n *\n * @example\n * ```tsx\n * // Controlled usage\n * const [date, setDate] = useState<Date | undefined>(new Date())\n * <DateTimeDisplayInput value={date} onChange={setDate} />\n *\n * // Uncontrolled usage\n * <DateTimeDisplayInput defaultValue={new Date()} />\n *\n * // Legacy props (deprecated, use value/onChange instead)\n * <DateTimeDisplayInput date={date} onDateChange={setDate} />\n * ```\n */\nexport const DateTimeDisplayInput = forwardRef<HTMLDivElement, DateTimeDisplayInputProps>(\n (\n {\n className,\n defaultValue,\n disabled,\n endIcon,\n hourFormat = '12',\n id,\n label,\n locale,\n onChange,\n showTime = true,\n state = 'default',\n value,\n 'aria-labelledby': ariaLabelledBy,\n // Legacy props (deprecated)\n date: legacyDate,\n onDateChange: legacyOnDateChange,\n ...props\n },\n ref,\n ) => {\n const generatedId = useId()\n const displayInputId = id ?? `datetime-display-input-${generatedId}`\n const displayLabelId = `${displayInputId}-label`\n const containerRef = useRef<HTMLDivElement>(null)\n const resolvedAriaLabelledBy = [label ? displayLabelId : undefined, ariaLabelledBy].filter(Boolean).join(' ') || undefined\n\n // Support both new (value/onChange) and legacy (date/onDateChange) prop names\n const effectiveValue = value ?? legacyDate\n const effectiveOnChange = onChange ?? legacyOnDateChange\n\n // Use controllable state to support both controlled and uncontrolled usage\n const [date, setDate] = useUncontrolledState<Date | undefined>({\n defaultValue: defaultValue,\n onChange: effectiveOnChange,\n value: effectiveValue,\n })\n\n // Resolve locale and get period labels\n const resolvedLocale = useMemo(() => getResolvedLocale(locale), [locale])\n const periodLabels = useMemo(() => getLocalizedPeriodLabels(resolvedLocale), [resolvedLocale])\n\n // Extract values from date\n const values = useMemo(() => {\n if (!date) return { month: undefined, day: undefined, year: undefined, hour: undefined, minute: undefined, period: undefined as 0 | 1 | undefined }\n\n const hours = date.getHours()\n let displayHour: number\n let period: 0 | 1\n\n if (hourFormat === '24') {\n displayHour = hours\n period = 0\n } else {\n period = hours >= 12 ? 1 : 0\n displayHour = hours % 12\n if (displayHour === 0) displayHour = 12\n }\n\n return {\n month: date.getMonth() + 1,\n day: date.getDate(),\n year: date.getFullYear(),\n hour: displayHour,\n minute: date.getMinutes(),\n period,\n }\n }, [date, hourFormat])\n\n // Check if date is complete (all date parts filled in)\n // Time inputs should be disabled until a valid date is entered\n const isDateComplete = values.month !== undefined && values.day !== undefined && values.year !== undefined\n\n // Build the date from segment values\n const updateDate = useCallback(\n (updates: Partial<typeof values>) => {\n const newValues = { ...values, ...updates }\n\n // If all date parts are undefined, clear the date\n if (newValues.month === undefined && newValues.day === undefined && newValues.year === undefined) {\n setDate(undefined)\n return\n }\n\n // Use current date as base for any undefined values\n const now = new Date()\n const month = (newValues.month ?? now.getMonth() + 1) - 1\n const day = newValues.day ?? now.getDate()\n const year = newValues.year ?? now.getFullYear()\n\n // Clamp day to max days in month\n const maxDays = getMaxDaysInMonth(month + 1, year)\n const clampedDay = Math.min(day, maxDays)\n\n // Check if date just became complete (was incomplete before, complete now)\n const wasDateComplete = values.month !== undefined && values.day !== undefined && values.year !== undefined\n const isNowDateComplete = newValues.month !== undefined && newValues.day !== undefined && newValues.year !== undefined\n const dateJustCompleted = !wasDateComplete && isNowDateComplete\n\n let hours: number\n if (hourFormat === '24') {\n // Default to 0:00 (midnight) when date first completed in 24-hour format\n hours = dateJustCompleted ? 0 : (newValues.hour ?? 0)\n } else {\n // Default to 12:00 PM when date first completed in 12-hour format\n const defaultHour = dateJustCompleted ? 12 : (newValues.hour ?? 12)\n const defaultPeriod = dateJustCompleted ? 1 : (newValues.period ?? 0) // PM by default\n const hour12 = defaultHour\n const period = defaultPeriod\n if (hour12 === 12) {\n hours = period === 0 ? 0 : 12\n } else {\n hours = period === 0 ? hour12 : hour12 + 12\n }\n }\n\n const minutes = dateJustCompleted ? 0 : (newValues.minute ?? 0)\n\n const newDate = new Date(year, month, clampedDay, hours, minutes, 0, 0)\n setDate(newDate)\n },\n [values, hourFormat, setDate],\n )\n\n // Define segments based on format\n const segments = useMemo(() => {\n const dateSegments = [\n { key: 'month', config: SEGMENT_CONFIGS.month, ariaLabel: 'Month' },\n { key: 'day', config: SEGMENT_CONFIGS.day, ariaLabel: 'Day' },\n { key: 'year', config: SEGMENT_CONFIGS.year, ariaLabel: 'Year' },\n ]\n\n if (!showTime) return dateSegments\n\n const timeSegments =\n hourFormat === '24'\n ? [\n { key: 'hour', config: SEGMENT_CONFIGS.hour24, ariaLabel: 'Hours' },\n { key: 'minute', config: SEGMENT_CONFIGS.minute, ariaLabel: 'Minutes' },\n ]\n : [\n { key: 'hour', config: SEGMENT_CONFIGS.hour12, ariaLabel: 'Hours' },\n { key: 'minute', config: SEGMENT_CONFIGS.minute, ariaLabel: 'Minutes' },\n { key: 'period', config: SEGMENT_CONFIGS.period, ariaLabel: formatSelectPeriodLabel(periodLabels, 'Select {am} or {pm}') },\n ]\n\n return [...dateSegments, ...timeSegments]\n }, [showTime, hourFormat, periodLabels])\n\n // Focus helpers\n const focusSegment = useCallback((index: number) => {\n const segment = containerRef.current?.querySelectorAll(`[role='spinbutton']`)[index] as HTMLElement\n segment?.focus()\n }, [])\n\n const inputClasses = getInputClasses(state)\n\n return (\n <div className='gap-1.5 flex flex-col'>\n {label && (\n <Label\n className='text-sm font-medium text-text-primary'\n id={displayLabelId}\n >\n {label}\n </Label>\n )}\n <div\n className={cn(inputClasses, 'relative', (disabled ?? state === 'disabled') && 'cursor-not-allowed', className)}\n data-slot='datetime-display-input'\n id={displayInputId}\n ref={ref ?? containerRef}\n aria-labelledby={resolvedAriaLabelledBy}\n {...props}\n >\n <div\n className='flex items-center'\n ref={containerRef}\n >\n {segments.map((segment, index) => {\n const isDateSegment = ['month', 'day', 'year'].includes(segment.key)\n const isTimeSegment = ['hour', 'minute', 'period'].includes(segment.key)\n const isLastDateSegment = segment.key === 'year'\n const isFirstTimeSegment = segment.key === 'hour'\n\n // Disable time segments until date is complete\n const isSegmentDisabled = disabled ?? (isTimeSegment && !isDateComplete)\n\n return (\n <span\n key={segment.key}\n className='flex items-center'\n >\n {/* Add comma and space before time section */}\n {isFirstTimeSegment && (\n <span\n aria-hidden='true'\n className='text-text-secondary select-none'\n >\n ,&nbsp;\n </span>\n )}\n\n <SegmentInput\n ariaLabel={segment.ariaLabel}\n config={segment.config}\n disabled={isSegmentDisabled}\n onLeftFocus={() => index > 0 && focusSegment(index - 1)}\n onRightFocus={() => index < segments.length - 1 && focusSegment(index + 1)}\n onValueChange={(val) => updateDate({ [segment.key]: val })}\n periodLabels={periodLabels}\n value={values[segment.key as keyof typeof values]}\n />\n\n {/* Date separators */}\n {isDateSegment && !isLastDateSegment && (\n <span\n aria-hidden='true'\n className='text-text-secondary select-none'\n >\n /\n </span>\n )}\n\n {/* Time separator - colon between hour and minute */}\n {isFirstTimeSegment && (\n <span\n aria-hidden='true'\n className='text-inherit select-none'\n >\n :\n </span>\n )}\n </span>\n )\n })}\n </div>\n {endIcon}\n </div>\n </div>\n )\n },\n)\nDateTimeDisplayInput.displayName = 'DateTimeDisplayInput'\n"],"mappings":"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"}
1
+ {"version":3,"file":"DateTimeDisplayInput.js","names":[],"sources":["../../src/components/DateTimePicker/DateTimeDisplayInput.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { getInputClasses } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { forwardRef, useCallback, useEffect, useId, useMemo, useRef, type ComponentProps, type KeyboardEvent, type ReactNode } from 'react'\nimport { formatSelectPeriodLabel, getLocalizedPeriodLabels, getResolvedLocale, type HourFormat, type PeriodLabels } from './DateTimeUtils'\n\nexport interface DateTimeDisplayInputProps extends Omit<ComponentProps<'div'>, 'onChange' | 'defaultValue'> {\n defaultValue?: Date\n disabled?: boolean\n endIcon?: ReactNode\n hourFormat?: HourFormat\n label?: string\n locale?: string\n onChange?: (date: Date | undefined) => void\n showTime?: boolean\n state?: 'default' | 'disabled' | 'error'\n value?: Date\n // Legacy prop names for backward compatibility\n /** @deprecated Use `value` instead */\n date?: Date\n /** @deprecated Use `onChange` instead */\n onDateChange?: (date: Date | undefined) => void\n}\n\ninterface SegmentConfig {\n length: number\n max: number\n min: number\n type: 'month' | 'day' | 'year' | 'hour' | 'minute' | 'period'\n}\n\nconst SEGMENT_CONFIGS: Record<string, SegmentConfig> = {\n month: { type: 'month', min: 1, max: 12, length: 2 },\n day: { type: 'day', min: 1, max: 31, length: 2 },\n year: { type: 'year', min: 1900, max: 2100, length: 4 },\n hour12: { type: 'hour', min: 1, max: 12, length: 2 },\n hour24: { type: 'hour', min: 0, max: 23, length: 2 },\n minute: { type: 'minute', min: 0, max: 59, length: 2 },\n period: { type: 'period', min: 0, max: 1, length: 2 },\n}\n\n/**\n * Get max days for a given month/year\n */\nconst getMaxDaysInMonth = (month: number, year: number): number => {\n if (month === 2) {\n const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0\n return isLeapYear ? 29 : 28\n }\n if ([4, 6, 9, 11].includes(month)) return 30\n return 31\n}\n\n/**\n * A single segment input (month, day, year, hour, minute)\n */\ninterface SegmentInputProps {\n ariaLabel: string\n config: SegmentConfig\n disabled?: boolean\n onLeftFocus?: () => void\n onRightFocus?: () => void\n onValueChange: (value: number) => void\n periodLabels?: PeriodLabels\n value: number | undefined\n}\n\n/**\n * SegmentInput - A single editable segment (month, day, year, hour, minute, period)\n *\n * Uses an uncontrolled input pattern to avoid React re-render issues during typing:\n * - Edit buffer stored in ref (not state) to prevent re-renders\n * - DOM value manipulated directly during typing\n * - Only syncs with React when value is committed (blur, tab, arrow keys)\n */\nconst SegmentInput = ({ ariaLabel, config, disabled, onLeftFocus, onRightFocus, onValueChange, periodLabels, value }: SegmentInputProps) => {\n const inputRef = useRef<HTMLInputElement>(null)\n // Use refs to avoid re-renders during typing - this is the key to making it work\n const editBufferRef = useRef('')\n const isEditingRef = useRef(false)\n\n // Placeholder text for empty segments\n const placeholderText = useMemo(() => {\n switch (config.type) {\n case 'month':\n return 'MM'\n case 'day':\n return 'dd'\n case 'year':\n return 'yyyy'\n case 'hour':\n return config.max === 23 ? 'HH' : 'hh'\n case 'minute':\n return 'mm'\n case 'period':\n return (periodLabels?.am ?? 'am').toLowerCase()\n default:\n return '––'\n }\n }, [config.type, config.max, periodLabels])\n\n // Format display value from the committed value prop\n const displayValue = useMemo(() => {\n if (value === undefined) {\n return placeholderText\n }\n if (config.type === 'period') {\n const label = value === 0 ? (periodLabels?.am ?? 'am') : (periodLabels?.pm ?? 'pm')\n return label.toLowerCase()\n }\n return value.toString().padStart(config.length, '0')\n }, [value, config, periodLabels, placeholderText])\n\n // Sync input value when external value changes (and we're not editing)\n useEffect(() => {\n if (inputRef.current && !isEditingRef.current) {\n inputRef.current.value = displayValue\n }\n }, [displayValue])\n\n // Commit the edit buffer - called on blur, tab, arrow navigation\n const commitEdit = useCallback(() => {\n const buffer = editBufferRef.current\n if (buffer) {\n let numValue = parseInt(buffer, 10)\n if (!isNaN(numValue)) {\n numValue = Math.max(config.min, Math.min(config.max, numValue))\n onValueChange(numValue)\n }\n }\n // Reset edit state\n editBufferRef.current = ''\n isEditingRef.current = false\n // Sync display value after commit\n if (inputRef.current) {\n inputRef.current.value = displayValue\n }\n }, [config.min, config.max, displayValue, onValueChange])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return\n\n // Tab navigation (let it bubble naturally)\n if (e.key === 'Tab') {\n commitEdit()\n return\n }\n\n // Arrow navigation between segments\n if (e.key === 'ArrowRight') {\n e.preventDefault()\n commitEdit()\n onRightFocus?.()\n return\n }\n if (e.key === 'ArrowLeft') {\n e.preventDefault()\n commitEdit()\n onLeftFocus?.()\n return\n }\n\n // Period toggle (AM/PM)\n if (config.type === 'period') {\n e.preventDefault()\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n onValueChange(value === 0 ? 1 : 0)\n } else if (e.key.toLowerCase() === 'a') {\n onValueChange(0)\n } else if (e.key.toLowerCase() === 'p') {\n onValueChange(1)\n }\n return\n }\n\n // Arrow up/down to increment/decrement\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n editBufferRef.current = ''\n isEditingRef.current = false\n const newValue = value === undefined ? config.min : value >= config.max ? config.min : value + 1\n onValueChange(newValue)\n return\n }\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n editBufferRef.current = ''\n isEditingRef.current = false\n const newValue = value === undefined ? config.max : value <= config.min ? config.max : value - 1\n onValueChange(newValue)\n return\n }\n\n // Home/End for min/max\n if (e.key === 'Home') {\n e.preventDefault()\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(config.min)\n return\n }\n if (e.key === 'End') {\n e.preventDefault()\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(config.max)\n return\n }\n\n // Numeric input - directly manipulate DOM, no React state\n if (e.key >= '0' && e.key <= '9') {\n e.preventDefault()\n const newBuffer = editBufferRef.current + e.key\n const numValue = parseInt(newBuffer, 10)\n\n // For 2-digit fields\n if (config.length === 2) {\n if (newBuffer.length >= 2) {\n // Two digits entered - commit and advance\n const clamped = Math.max(config.min, Math.min(config.max, numValue))\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(clamped)\n onRightFocus?.()\n } else if (numValue * 10 > config.max) {\n // First digit is too large to form a valid two-digit number\n const clamped = Math.max(config.min, Math.min(config.max, numValue))\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(clamped)\n onRightFocus?.()\n } else {\n // First digit could lead to valid values, wait for second digit\n // Update refs and DOM directly - NO state update\n editBufferRef.current = newBuffer\n isEditingRef.current = true\n if (inputRef.current) {\n inputRef.current.value = newBuffer\n }\n }\n } else if (config.length === 4) {\n // Year field - advance after 4 digits\n if (newBuffer.length >= 4) {\n const clamped = Math.max(config.min, Math.min(config.max, numValue))\n editBufferRef.current = ''\n isEditingRef.current = false\n onValueChange(clamped)\n onRightFocus?.()\n } else {\n // Update refs and DOM directly - NO state update\n editBufferRef.current = newBuffer\n isEditingRef.current = true\n if (inputRef.current) {\n inputRef.current.value = newBuffer\n }\n }\n }\n return\n }\n\n if (e.key === 'Backspace') {\n e.preventDefault()\n if (editBufferRef.current) {\n const newBuffer = editBufferRef.current.slice(0, -1)\n editBufferRef.current = newBuffer\n isEditingRef.current = newBuffer.length > 0\n if (inputRef.current) {\n inputRef.current.value = newBuffer || displayValue\n }\n } else if (value !== undefined) {\n editBufferRef.current = ''\n isEditingRef.current = true\n onValueChange(config.min)\n if (inputRef.current) {\n inputRef.current.value = placeholderText\n }\n }\n }\n },\n [disabled, config, value, displayValue, placeholderText, onValueChange, onLeftFocus, onRightFocus, commitEdit],\n )\n\n const handleBlur = useCallback(() => {\n // Only commit if we have a partial edit\n if (editBufferRef.current) {\n commitEdit()\n }\n }, [commitEdit])\n\n const handleFocus = useCallback(() => {\n // Only clear buffer if we're not in the middle of an edit\n if (!isEditingRef.current) {\n editBufferRef.current = ''\n }\n // Move cursor to end\n const input = inputRef.current\n if (input) {\n const len = input.value.length\n input.setSelectionRange(len, len)\n }\n }, [])\n\n // Prevent browser from changing the input value directly\n const handleChange = useCallback(() => {\n // Reset to our controlled value if browser tries to change it\n if (inputRef.current) {\n inputRef.current.value = editBufferRef.current || displayValue\n }\n }, [displayValue])\n\n // Width and padding based on segment type\n const getSegmentStyle = useCallback(() => {\n switch (config.type) {\n case 'year':\n return { width: 46, paddingLeft: 0 }\n case 'period':\n return { width: 28, paddingLeft: 0, marginLeft: 4 }\n case 'month':\n return { width: 28, paddingLeft: 0 }\n case 'day':\n return { width: 28, paddingLeft: 0 }\n case 'hour':\n return { width: 28, paddingLeft: 0 }\n case 'minute':\n return { width: 30, paddingLeft: 0 }\n default:\n return { width: 24, paddingLeft: 0 }\n }\n }, [config.type])\n\n const segmentStyle = useMemo(() => getSegmentStyle(), [getSegmentStyle])\n const isPlaceholder = useMemo(() => value === undefined, [value])\n\n return (\n <input\n aria-label={ariaLabel}\n aria-valuemax={config.max}\n aria-valuemin={config.min}\n aria-valuenow={value}\n className={cn(\n 'rounded inline-flex items-center justify-center text-center tabular-nums',\n 'border-none bg-transparent outline-none',\n 'focus:bg-bg-tertiary focus:text-text-primary focus:ring-1 focus:ring-accent',\n 'hover:bg-bg-secondary',\n disabled && 'cursor-not-allowed opacity-50',\n isPlaceholder && 'text-text-placeholder text-sm',\n )}\n data-segment={config.type}\n defaultValue={displayValue}\n disabled={disabled}\n inputMode='numeric'\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n ref={inputRef}\n role='spinbutton'\n style={segmentStyle}\n tabIndex={disabled ? -1 : 0}\n />\n )\n}\n\n/**\n * A segmented date/time input that mimics native date input behavior.\n * Each segment (month, day, year, hour, minute, period) is separately focusable.\n *\n * Supports both controlled and uncontrolled usage:\n * - Controlled: `<DateTimeDisplayInput value={date} onChange={setDate} />`\n * - Uncontrolled: `<DateTimeDisplayInput defaultValue={new Date()} />`\n *\n * @example\n * ```tsx\n * // Controlled usage\n * const [date, setDate] = useState<Date | undefined>(new Date())\n * <DateTimeDisplayInput value={date} onChange={setDate} />\n *\n * // Uncontrolled usage\n * <DateTimeDisplayInput defaultValue={new Date()} />\n *\n * // Legacy props (deprecated, use value/onChange instead)\n * <DateTimeDisplayInput date={date} onDateChange={setDate} />\n * ```\n */\nexport const DateTimeDisplayInput = forwardRef<HTMLDivElement, DateTimeDisplayInputProps>(\n (\n {\n className,\n defaultValue,\n disabled,\n endIcon,\n hourFormat = '12',\n id,\n label,\n locale,\n onChange,\n showTime = true,\n state = 'default',\n value,\n 'aria-labelledby': ariaLabelledBy,\n // Legacy props (deprecated)\n date: legacyDate,\n onDateChange: legacyOnDateChange,\n ...props\n },\n ref,\n ) => {\n const generatedId = useId()\n const displayInputId = id ?? `datetime-display-input-${generatedId}`\n const displayLabelId = `${displayInputId}-label`\n const containerRef = useRef<HTMLDivElement>(null)\n const resolvedAriaLabelledBy = [label ? displayLabelId : undefined, ariaLabelledBy].filter(Boolean).join(' ') || undefined\n\n // Support both new (value/onChange) and legacy (date/onDateChange) prop names\n const effectiveValue = value ?? legacyDate\n const effectiveOnChange = onChange ?? legacyOnDateChange\n\n // Use controllable state to support both controlled and uncontrolled usage\n const [date, setDate] = useUncontrolledState<Date | undefined>({\n defaultValue: defaultValue,\n onChange: effectiveOnChange,\n value: effectiveValue,\n })\n\n // Resolve locale and get period labels\n const resolvedLocale = useMemo(() => getResolvedLocale(locale), [locale])\n const periodLabels = useMemo(() => getLocalizedPeriodLabels(resolvedLocale), [resolvedLocale])\n\n // Extract values from date\n const values = useMemo(() => {\n if (!date) return { month: undefined, day: undefined, year: undefined, hour: undefined, minute: undefined, period: undefined as 0 | 1 | undefined }\n\n const hours = date.getHours()\n let displayHour: number\n let period: 0 | 1\n\n if (hourFormat === '24') {\n displayHour = hours\n period = 0\n } else {\n period = hours >= 12 ? 1 : 0\n displayHour = hours % 12\n if (displayHour === 0) displayHour = 12\n }\n\n return {\n month: date.getMonth() + 1,\n day: date.getDate(),\n year: date.getFullYear(),\n hour: displayHour,\n minute: date.getMinutes(),\n period,\n }\n }, [date, hourFormat])\n\n // Check if date is complete (all date parts filled in)\n // Time inputs should be disabled until a valid date is entered\n const isDateComplete = values.month !== undefined && values.day !== undefined && values.year !== undefined\n\n // Build the date from segment values\n const updateDate = useCallback(\n (updates: Partial<typeof values>) => {\n const newValues = { ...values, ...updates }\n\n // If all date parts are undefined, clear the date\n if (newValues.month === undefined && newValues.day === undefined && newValues.year === undefined) {\n setDate(undefined)\n return\n }\n\n // Use current date as base for any undefined values\n const now = new Date()\n const month = (newValues.month ?? now.getMonth() + 1) - 1\n const day = newValues.day ?? now.getDate()\n const year = newValues.year ?? now.getFullYear()\n\n // Clamp day to max days in month\n const maxDays = getMaxDaysInMonth(month + 1, year)\n const clampedDay = Math.min(day, maxDays)\n\n // Check if date just became complete (was incomplete before, complete now)\n const wasDateComplete = values.month !== undefined && values.day !== undefined && values.year !== undefined\n const isNowDateComplete = newValues.month !== undefined && newValues.day !== undefined && newValues.year !== undefined\n const dateJustCompleted = !wasDateComplete && isNowDateComplete\n\n let hours: number\n if (hourFormat === '24') {\n // Default to 0:00 (midnight) when date first completed in 24-hour format\n hours = dateJustCompleted ? 0 : (newValues.hour ?? 0)\n } else {\n // Default to 12:00 PM when date first completed in 12-hour format\n const defaultHour = dateJustCompleted ? 12 : (newValues.hour ?? 12)\n const defaultPeriod = dateJustCompleted ? 1 : (newValues.period ?? 0) // PM by default\n const hour12 = defaultHour\n const period = defaultPeriod\n if (hour12 === 12) {\n hours = period === 0 ? 0 : 12\n } else {\n hours = period === 0 ? hour12 : hour12 + 12\n }\n }\n\n const minutes = dateJustCompleted ? 0 : (newValues.minute ?? 0)\n\n const newDate = new Date(year, month, clampedDay, hours, minutes, 0, 0)\n setDate(newDate)\n },\n [values, hourFormat, setDate],\n )\n\n // Define segments based on format\n const segments = useMemo(() => {\n const dateSegments = [\n { key: 'month', config: SEGMENT_CONFIGS.month, ariaLabel: 'Month' },\n { key: 'day', config: SEGMENT_CONFIGS.day, ariaLabel: 'Day' },\n { key: 'year', config: SEGMENT_CONFIGS.year, ariaLabel: 'Year' },\n ]\n\n if (!showTime) return dateSegments\n\n const timeSegments =\n hourFormat === '24'\n ? [\n { key: 'hour', config: SEGMENT_CONFIGS.hour24, ariaLabel: 'Hours' },\n { key: 'minute', config: SEGMENT_CONFIGS.minute, ariaLabel: 'Minutes' },\n ]\n : [\n { key: 'hour', config: SEGMENT_CONFIGS.hour12, ariaLabel: 'Hours' },\n { key: 'minute', config: SEGMENT_CONFIGS.minute, ariaLabel: 'Minutes' },\n { key: 'period', config: SEGMENT_CONFIGS.period, ariaLabel: formatSelectPeriodLabel(periodLabels, 'Select {am} or {pm}') },\n ]\n\n return [...dateSegments, ...timeSegments]\n }, [showTime, hourFormat, periodLabels])\n\n // Focus helpers\n const focusSegment = useCallback((index: number) => {\n const segment = containerRef.current?.querySelectorAll(`[role='spinbutton']`)[index] as HTMLElement\n segment?.focus()\n }, [])\n\n const inputClasses = getInputClasses(state)\n\n return (\n <div className='gap-1.5 flex flex-col'>\n {label && (\n <Label className='text-sm font-medium text-text-primary' id={displayLabelId}>\n {label}\n </Label>\n )}\n <div className={cn(inputClasses, 'relative', (disabled ?? state === 'disabled') && 'cursor-not-allowed', className)} data-slot='datetime-display-input' id={displayInputId} ref={ref ?? containerRef} aria-labelledby={resolvedAriaLabelledBy} {...props}>\n <div className='flex items-center' ref={containerRef}>\n {segments.map((segment, index) => {\n const isDateSegment = ['month', 'day', 'year'].includes(segment.key)\n const isTimeSegment = ['hour', 'minute', 'period'].includes(segment.key)\n const isLastDateSegment = segment.key === 'year'\n const isFirstTimeSegment = segment.key === 'hour'\n\n // Disable time segments until date is complete\n const isSegmentDisabled = disabled ?? (isTimeSegment && !isDateComplete)\n\n return (\n <span key={segment.key} className='flex items-center'>\n {/* Add comma and space before time section */}\n {isFirstTimeSegment && (\n <span aria-hidden='true' className='text-text-secondary select-none'>\n ,&nbsp;\n </span>\n )}\n\n <SegmentInput\n ariaLabel={segment.ariaLabel}\n config={segment.config}\n disabled={isSegmentDisabled}\n onLeftFocus={() => index > 0 && focusSegment(index - 1)}\n onRightFocus={() => index < segments.length - 1 && focusSegment(index + 1)}\n onValueChange={(val) => updateDate({ [segment.key]: val })}\n periodLabels={periodLabels}\n value={values[segment.key as keyof typeof values]}\n />\n\n {/* Date separators */}\n {isDateSegment && !isLastDateSegment && (\n <span aria-hidden='true' className='text-text-secondary select-none'>\n /\n </span>\n )}\n\n {/* Time separator - colon between hour and minute */}\n {isFirstTimeSegment && (\n <span aria-hidden='true' className='text-inherit select-none'>\n :\n </span>\n )}\n </span>\n )\n })}\n </div>\n {endIcon}\n </div>\n </div>\n )\n },\n)\nDateTimeDisplayInput.displayName = 'DateTimeDisplayInput'\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TimePeriodSelect.js","names":[],"sources":["../../src/components/DateTimePicker/TimePeriodSelect.tsx"],"sourcesContent":["import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@primitives/select'\nimport { cn } from '@utils/twUtils'\nimport { forwardRef, type ComponentProps, type KeyboardEvent } from 'react'\nimport { type Period, type PeriodLabels } from './DateTimeUtils'\n\nexport interface TimePeriodSelectProps extends Omit<ComponentProps<'button'>, 'onChange' | 'ref'> {\n ariaLabel?: string\n labels?: PeriodLabels\n onLeftFocus?: () => void\n onPeriodChange: (period: Period) => void\n onRightFocus?: () => void\n period: Period\n}\n\nconst DEFAULT_LABELS: PeriodLabels = { am: 'AM', pm: 'PM' }\n\nexport const TimePeriodSelect = forwardRef<HTMLButtonElement, TimePeriodSelectProps>(({ ariaLabel, className, disabled, labels = DEFAULT_LABELS, onLeftFocus, onPeriodChange, onRightFocus, period, ...props }, ref) => {\n // Generate default ARIA label from the provided labels if not explicitly provided\n const effectiveAriaLabel = ariaLabel ?? `Select ${labels.am} or ${labels.pm}`\n const handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === 'ArrowRight') {\n e.preventDefault()\n onRightFocus?.()\n }\n if (e.key === 'ArrowLeft') {\n e.preventDefault()\n onLeftFocus?.()\n }\n }\n\n return (\n <Select\n defaultValue={period}\n disabled={disabled}\n onValueChange={(value) => onPeriodChange(value as Period)}\n value={period}\n >\n <SelectTrigger\n aria-label={effectiveAriaLabel}\n className={cn('w-fit', className)}\n data-slot='time-period-select'\n data-testid='spectral-time-period-select'\n onKeyDown={handleKeyDown}\n ref={ref}\n size='sm'\n {...props}\n >\n <SelectValue>{period === 'AM' ? labels.am : labels.pm}</SelectValue>\n </SelectTrigger>\n <SelectContent\n data-testid='spectral-time-period-select-content'\n position='popper'\n sideOffset={4}\n >\n <SelectItem\n data-testid='spectral-time-period-select-am'\n value='AM'\n >\n {labels.am}\n </SelectItem>\n <SelectItem\n data-testid='spectral-time-period-select-pm'\n value='PM'\n >\n {labels.pm}\n </SelectItem>\n </SelectContent>\n </Select>\n )\n})\n\nTimePeriodSelect.displayName = 'TimePeriodSelect'\n"],"mappings":";;;;;;;AAcA,MAAM,iBAA+B;CAAE,IAAI;CAAM,IAAI;CAAM;AAE3D,MAAa,mBAAmB,YAAsD,EAAE,WAAW,WAAW,UAAU,SAAS,gBAAgB,aAAa,gBAAgB,cAAc,QAAQ,GAAG,SAAS,QAAQ;CAEtN,MAAM,qBAAqB,aAAa,UAAU,OAAO,GAAG,MAAM,OAAO;CACzE,MAAM,iBAAiB,MAAwC;AAC7D,MAAI,EAAE,QAAQ,cAAc;AAC1B,KAAE,gBAAgB;AAClB,mBAAgB;;AAElB,MAAI,EAAE,QAAQ,aAAa;AACzB,KAAE,gBAAgB;AAClB,kBAAe;;;AAInB,QACE,qBAAC,QAAD;EACE,cAAc;EACJ;EACV,gBAAgB,UAAU,eAAe,MAAgB;EACzD,OAAO;YAJT,CAME,oBAAC,eAAD;GACE,cAAY;GACZ,WAAW,GAAG,SAAS,UAAU;GACjC,aAAU;GACV,eAAY;GACZ,WAAW;GACN;GACL,MAAK;GACL,GAAI;aAEJ,oBAAC,aAAD,YAAc,WAAW,OAAO,OAAO,KAAK,OAAO,IAAiB;GACtD,GAChB,qBAAC,eAAD;GACE,eAAY;GACZ,UAAS;GACT,YAAY;aAHd,CAKE,oBAAC,YAAD;IACE,eAAY;IACZ,OAAM;cAEL,OAAO;IACG,GACb,oBAAC,YAAD;IACE,eAAY;IACZ,OAAM;cAEL,OAAO;IACG,EACC;KACT;;EAEX;AAEF,iBAAiB,cAAc"}
1
+ {"version":3,"file":"TimePeriodSelect.js","names":[],"sources":["../../src/components/DateTimePicker/TimePeriodSelect.tsx"],"sourcesContent":["import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@primitives/select'\nimport { cn } from '@utils/twUtils'\nimport { forwardRef, type ComponentProps, type KeyboardEvent } from 'react'\nimport { type Period, type PeriodLabels } from './DateTimeUtils'\n\nexport interface TimePeriodSelectProps extends Omit<ComponentProps<'button'>, 'onChange' | 'ref'> {\n ariaLabel?: string\n labels?: PeriodLabels\n onLeftFocus?: () => void\n onPeriodChange: (period: Period) => void\n onRightFocus?: () => void\n period: Period\n}\n\nconst DEFAULT_LABELS: PeriodLabels = { am: 'AM', pm: 'PM' }\n\nexport const TimePeriodSelect = forwardRef<HTMLButtonElement, TimePeriodSelectProps>(({ ariaLabel, className, disabled, labels = DEFAULT_LABELS, onLeftFocus, onPeriodChange, onRightFocus, period, ...props }, ref) => {\n // Generate default ARIA label from the provided labels if not explicitly provided\n const effectiveAriaLabel = ariaLabel ?? `Select ${labels.am} or ${labels.pm}`\n const handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === 'ArrowRight') {\n e.preventDefault()\n onRightFocus?.()\n }\n if (e.key === 'ArrowLeft') {\n e.preventDefault()\n onLeftFocus?.()\n }\n }\n\n return (\n <Select defaultValue={period} disabled={disabled} onValueChange={(value) => onPeriodChange(value as Period)} value={period}>\n <SelectTrigger aria-label={effectiveAriaLabel} className={cn('w-fit', className)} data-slot='time-period-select' data-testid='spectral-time-period-select' onKeyDown={handleKeyDown} ref={ref} size='sm' {...props}>\n <SelectValue>{period === 'AM' ? labels.am : labels.pm}</SelectValue>\n </SelectTrigger>\n <SelectContent data-testid='spectral-time-period-select-content' position='popper' sideOffset={4}>\n <SelectItem data-testid='spectral-time-period-select-am' value='AM'>\n {labels.am}\n </SelectItem>\n <SelectItem data-testid='spectral-time-period-select-pm' value='PM'>\n {labels.pm}\n </SelectItem>\n </SelectContent>\n </Select>\n )\n})\n\nTimePeriodSelect.displayName = 'TimePeriodSelect'\n"],"mappings":";;;;;;;AAcA,MAAM,iBAA+B;CAAE,IAAI;CAAM,IAAI;CAAM;AAE3D,MAAa,mBAAmB,YAAsD,EAAE,WAAW,WAAW,UAAU,SAAS,gBAAgB,aAAa,gBAAgB,cAAc,QAAQ,GAAG,SAAS,QAAQ;CAEtN,MAAM,qBAAqB,aAAa,UAAU,OAAO,GAAG,MAAM,OAAO;CACzE,MAAM,iBAAiB,MAAwC;AAC7D,MAAI,EAAE,QAAQ,cAAc;AAC1B,KAAE,gBAAgB;AAClB,mBAAgB;;AAElB,MAAI,EAAE,QAAQ,aAAa;AACzB,KAAE,gBAAgB;AAClB,kBAAe;;;AAInB,QACE,qBAAC,QAAD;EAAQ,cAAc;EAAkB;EAAU,gBAAgB,UAAU,eAAe,MAAgB;EAAE,OAAO;YAApH,CACE,oBAAC,eAAD;GAAe,cAAY;GAAoB,WAAW,GAAG,SAAS,UAAU;GAAE,aAAU;GAAqB,eAAY;GAA8B,WAAW;GAAoB;GAAK,MAAK;GAAK,GAAI;aAC3M,oBAAC,aAAD,YAAc,WAAW,OAAO,OAAO,KAAK,OAAO,IAAiB;GACtD,GAChB,qBAAC,eAAD;GAAe,eAAY;GAAsC,UAAS;GAAS,YAAY;aAA/F,CACE,oBAAC,YAAD;IAAY,eAAY;IAAiC,OAAM;cAC5D,OAAO;IACG,GACb,oBAAC,YAAD;IAAY,eAAY;IAAiC,OAAM;cAC5D,OAAO;IACG,EACC;KACT;;EAEX;AAEF,iBAAiB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"TimePicker.js","names":[],"sources":["../../src/components/DateTimePicker/TimePicker.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { useMemo, useRef, type ComponentProps } from 'react'\nimport { DateTimeInput } from './DateTimeInput'\nimport { DEFAULT_TRANSLATIONS, detectHourFormat, formatSelectPeriodLabel, getLocalizedPeriodLabels, getPeriodFromHours, getResolvedLocale, type HourFormat, type Period, type TimePickerTranslations } from './DateTimeUtils'\nimport { TimePeriodSelect } from './TimePeriodSelect'\n\nexport interface TimePickerProps extends Omit<ComponentProps<'div'>, 'onChange'> {\n date: Date | undefined\n hourFormat?: HourFormat\n locale?: string\n onChange: (date: Date | undefined) => void\n onPeriodChange?: (newPeriod: Period) => void\n /** Override translation strings for ARIA labels */\n translations?: Partial<TimePickerTranslations>\n}\n\nexport const TimePicker = ({ className, date, hourFormat, locale, onChange, onPeriodChange, translations, ...props }: TimePickerProps) => {\n const minuteRef = useRef<HTMLInputElement>(null)\n const hourRef = useRef<HTMLInputElement>(null)\n const periodRef = useRef<HTMLButtonElement>(null)\n\n // Resolve locale with fallback chain\n const resolvedLocale = useMemo(() => getResolvedLocale(locale), [locale])\n\n // Merge translations with defaults\n const mergedTranslations = useMemo(() => ({ ...DEFAULT_TRANSLATIONS, ...translations }), [translations])\n\n // Auto-detect hour format from locale if not explicitly provided\n const effectiveHourFormat = useMemo(() => hourFormat ?? detectHourFormat(resolvedLocale), [hourFormat, resolvedLocale])\n\n // Get localized AM/PM labels\n const periodLabels = useMemo(() => getLocalizedPeriodLabels(resolvedLocale), [resolvedLocale])\n\n // Generate localized ARIA label for period select\n const selectPeriodAriaLabel = useMemo(() => formatSelectPeriodLabel(periodLabels, mergedTranslations.selectPeriodTemplate), [mergedTranslations.selectPeriodTemplate, periodLabels])\n\n const is24Hour = effectiveHourFormat === '24'\n const period = date ? getPeriodFromHours(date.getHours()) : 'AM'\n\n const handlePeriodChange = (newPeriod: Period) => {\n if (!date) {\n onPeriodChange?.(newPeriod)\n return\n }\n\n // Update the date to reflect the new period\n const newDate = new Date(date)\n const currentHours = newDate.getHours()\n const currentPeriod = getPeriodFromHours(currentHours)\n\n if (currentPeriod !== newPeriod) {\n // Toggle between AM and PM (add or subtract 12 hours)\n const adjustment = newPeriod === 'PM' ? 12 : -12\n newDate.setHours(currentHours + adjustment)\n onChange(newDate)\n }\n\n onPeriodChange?.(newPeriod)\n }\n\n return (\n <div\n aria-label={is24Hour ? mergedTranslations.timePicker24Hour : mergedTranslations.timePicker12Hour}\n className={cn('gap-1 inline-flex items-center', className)}\n data-slot='time-picker'\n data-testid='spectral-time-picker'\n role='group'\n {...props}\n >\n <DateTimeInput\n aria-label={is24Hour ? mergedTranslations.hours24 : mergedTranslations.hours12}\n className='w-12'\n data-testid='spectral-time-picker-hours'\n date={date}\n locale={resolvedLocale}\n onRightFocus={() => minuteRef.current?.focus()}\n period={is24Hour ? undefined : period}\n picker={is24Hour ? 'hours' : '12hours'}\n ref={hourRef}\n setDate={onChange}\n translations={mergedTranslations}\n />\n\n <span\n aria-hidden='true'\n className='select-none'\n >\n :\n </span>\n\n <DateTimeInput\n aria-label={mergedTranslations.minutes}\n className='w-12'\n data-testid='spectral-time-picker-minutes'\n date={date}\n locale={resolvedLocale}\n onLeftFocus={() => hourRef.current?.focus()}\n onRightFocus={!is24Hour ? () => periodRef.current?.focus() : undefined}\n period={is24Hour ? undefined : period}\n picker='minutes'\n ref={minuteRef}\n setDate={onChange}\n translations={mergedTranslations}\n />\n\n {!is24Hour && (\n <TimePeriodSelect\n ariaLabel={selectPeriodAriaLabel}\n labels={periodLabels}\n onLeftFocus={() => minuteRef.current?.focus()}\n onPeriodChange={handlePeriodChange}\n period={period}\n ref={periodRef}\n />\n )}\n </div>\n )\n}\nTimePicker.displayName = 'TimePicker'\n"],"mappings":";;;;;;;;;AAgBA,MAAa,cAAc,EAAE,WAAW,MAAM,YAAY,QAAQ,UAAU,gBAAgB,cAAc,GAAG,YAA6B;CACxI,MAAM,YAAY,OAAyB,KAAK;CAChD,MAAM,UAAU,OAAyB,KAAK;CAC9C,MAAM,YAAY,OAA0B,KAAK;CAGjD,MAAM,iBAAiB,cAAc,kBAAkB,OAAO,EAAE,CAAC,OAAO,CAAC;CAGzE,MAAM,qBAAqB,eAAe;EAAE,GAAG;EAAsB,GAAG;EAAc,GAAG,CAAC,aAAa,CAAC;CAGxG,MAAM,sBAAsB,cAAc,cAAc,iBAAiB,eAAe,EAAE,CAAC,YAAY,eAAe,CAAC;CAGvH,MAAM,eAAe,cAAc,yBAAyB,eAAe,EAAE,CAAC,eAAe,CAAC;CAG9F,MAAM,wBAAwB,cAAc,wBAAwB,cAAc,mBAAmB,qBAAqB,EAAE,CAAC,mBAAmB,sBAAsB,aAAa,CAAC;CAEpL,MAAM,WAAW,wBAAwB;CACzC,MAAM,SAAS,OAAO,mBAAmB,KAAK,UAAU,CAAC,GAAG;CAE5D,MAAM,sBAAsB,cAAsB;AAChD,MAAI,CAAC,MAAM;AACT,oBAAiB,UAAU;AAC3B;;EAIF,MAAM,UAAU,IAAI,KAAK,KAAK;EAC9B,MAAM,eAAe,QAAQ,UAAU;AAGvC,MAFsB,mBAAmB,aAExB,KAAK,WAAW;GAE/B,MAAM,aAAa,cAAc,OAAO,KAAK;AAC7C,WAAQ,SAAS,eAAe,WAAW;AAC3C,YAAS,QAAQ;;AAGnB,mBAAiB,UAAU;;AAG7B,QACE,qBAAC,OAAD;EACE,cAAY,WAAW,mBAAmB,mBAAmB,mBAAmB;EAChF,WAAW,GAAG,kCAAkC,UAAU;EAC1D,aAAU;EACV,eAAY;EACZ,MAAK;EACL,GAAI;YANN;GAQE,oBAAC,eAAD;IACE,cAAY,WAAW,mBAAmB,UAAU,mBAAmB;IACvE,WAAU;IACV,eAAY;IACN;IACN,QAAQ;IACR,oBAAoB,UAAU,SAAS,OAAO;IAC9C,QAAQ,WAAW,SAAY;IAC/B,QAAQ,WAAW,UAAU;IAC7B,KAAK;IACL,SAAS;IACT,cAAc;IACd;GAEF,oBAAC,QAAD;IACE,eAAY;IACZ,WAAU;cACX;IAEM;GAEP,oBAAC,eAAD;IACE,cAAY,mBAAmB;IAC/B,WAAU;IACV,eAAY;IACN;IACN,QAAQ;IACR,mBAAmB,QAAQ,SAAS,OAAO;IAC3C,cAAc,CAAC,iBAAiB,UAAU,SAAS,OAAO,GAAG;IAC7D,QAAQ,WAAW,SAAY;IAC/B,QAAO;IACP,KAAK;IACL,SAAS;IACT,cAAc;IACd;GAED,CAAC,YACA,oBAAC,kBAAD;IACE,WAAW;IACX,QAAQ;IACR,mBAAmB,UAAU,SAAS,OAAO;IAC7C,gBAAgB;IACR;IACR,KAAK;IACL;GAEA;;;AAGV,WAAW,cAAc"}
1
+ {"version":3,"file":"TimePicker.js","names":[],"sources":["../../src/components/DateTimePicker/TimePicker.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { useMemo, useRef, type ComponentProps } from 'react'\nimport { DateTimeInput } from './DateTimeInput'\nimport { DEFAULT_TRANSLATIONS, detectHourFormat, formatSelectPeriodLabel, getLocalizedPeriodLabels, getPeriodFromHours, getResolvedLocale, type HourFormat, type Period, type TimePickerTranslations } from './DateTimeUtils'\nimport { TimePeriodSelect } from './TimePeriodSelect'\n\nexport interface TimePickerProps extends Omit<ComponentProps<'div'>, 'onChange'> {\n date: Date | undefined\n hourFormat?: HourFormat\n locale?: string\n onChange: (date: Date | undefined) => void\n onPeriodChange?: (newPeriod: Period) => void\n /** Override translation strings for ARIA labels */\n translations?: Partial<TimePickerTranslations>\n}\n\nexport const TimePicker = ({ className, date, hourFormat, locale, onChange, onPeriodChange, translations, ...props }: TimePickerProps) => {\n const minuteRef = useRef<HTMLInputElement>(null)\n const hourRef = useRef<HTMLInputElement>(null)\n const periodRef = useRef<HTMLButtonElement>(null)\n\n // Resolve locale with fallback chain\n const resolvedLocale = useMemo(() => getResolvedLocale(locale), [locale])\n\n // Merge translations with defaults\n const mergedTranslations = useMemo(() => ({ ...DEFAULT_TRANSLATIONS, ...translations }), [translations])\n\n // Auto-detect hour format from locale if not explicitly provided\n const effectiveHourFormat = useMemo(() => hourFormat ?? detectHourFormat(resolvedLocale), [hourFormat, resolvedLocale])\n\n // Get localized AM/PM labels\n const periodLabels = useMemo(() => getLocalizedPeriodLabels(resolvedLocale), [resolvedLocale])\n\n // Generate localized ARIA label for period select\n const selectPeriodAriaLabel = useMemo(() => formatSelectPeriodLabel(periodLabels, mergedTranslations.selectPeriodTemplate), [mergedTranslations.selectPeriodTemplate, periodLabels])\n\n const is24Hour = effectiveHourFormat === '24'\n const period = date ? getPeriodFromHours(date.getHours()) : 'AM'\n\n const handlePeriodChange = (newPeriod: Period) => {\n if (!date) {\n onPeriodChange?.(newPeriod)\n return\n }\n\n // Update the date to reflect the new period\n const newDate = new Date(date)\n const currentHours = newDate.getHours()\n const currentPeriod = getPeriodFromHours(currentHours)\n\n if (currentPeriod !== newPeriod) {\n // Toggle between AM and PM (add or subtract 12 hours)\n const adjustment = newPeriod === 'PM' ? 12 : -12\n newDate.setHours(currentHours + adjustment)\n onChange(newDate)\n }\n\n onPeriodChange?.(newPeriod)\n }\n\n return (\n <div aria-label={is24Hour ? mergedTranslations.timePicker24Hour : mergedTranslations.timePicker12Hour} className={cn('gap-1 inline-flex items-center', className)} data-slot='time-picker' data-testid='spectral-time-picker' role='group' {...props}>\n <DateTimeInput\n aria-label={is24Hour ? mergedTranslations.hours24 : mergedTranslations.hours12}\n className='w-12'\n data-testid='spectral-time-picker-hours'\n date={date}\n locale={resolvedLocale}\n onRightFocus={() => minuteRef.current?.focus()}\n period={is24Hour ? undefined : period}\n picker={is24Hour ? 'hours' : '12hours'}\n ref={hourRef}\n setDate={onChange}\n translations={mergedTranslations}\n />\n\n <span aria-hidden='true' className='select-none'>\n :\n </span>\n\n <DateTimeInput\n aria-label={mergedTranslations.minutes}\n className='w-12'\n data-testid='spectral-time-picker-minutes'\n date={date}\n locale={resolvedLocale}\n onLeftFocus={() => hourRef.current?.focus()}\n onRightFocus={!is24Hour ? () => periodRef.current?.focus() : undefined}\n period={is24Hour ? undefined : period}\n picker='minutes'\n ref={minuteRef}\n setDate={onChange}\n translations={mergedTranslations}\n />\n\n {!is24Hour && <TimePeriodSelect ariaLabel={selectPeriodAriaLabel} labels={periodLabels} onLeftFocus={() => minuteRef.current?.focus()} onPeriodChange={handlePeriodChange} period={period} ref={periodRef} />}\n </div>\n )\n}\nTimePicker.displayName = 'TimePicker'\n"],"mappings":";;;;;;;;;AAgBA,MAAa,cAAc,EAAE,WAAW,MAAM,YAAY,QAAQ,UAAU,gBAAgB,cAAc,GAAG,YAA6B;CACxI,MAAM,YAAY,OAAyB,KAAK;CAChD,MAAM,UAAU,OAAyB,KAAK;CAC9C,MAAM,YAAY,OAA0B,KAAK;CAGjD,MAAM,iBAAiB,cAAc,kBAAkB,OAAO,EAAE,CAAC,OAAO,CAAC;CAGzE,MAAM,qBAAqB,eAAe;EAAE,GAAG;EAAsB,GAAG;EAAc,GAAG,CAAC,aAAa,CAAC;CAGxG,MAAM,sBAAsB,cAAc,cAAc,iBAAiB,eAAe,EAAE,CAAC,YAAY,eAAe,CAAC;CAGvH,MAAM,eAAe,cAAc,yBAAyB,eAAe,EAAE,CAAC,eAAe,CAAC;CAG9F,MAAM,wBAAwB,cAAc,wBAAwB,cAAc,mBAAmB,qBAAqB,EAAE,CAAC,mBAAmB,sBAAsB,aAAa,CAAC;CAEpL,MAAM,WAAW,wBAAwB;CACzC,MAAM,SAAS,OAAO,mBAAmB,KAAK,UAAU,CAAC,GAAG;CAE5D,MAAM,sBAAsB,cAAsB;AAChD,MAAI,CAAC,MAAM;AACT,oBAAiB,UAAU;AAC3B;;EAIF,MAAM,UAAU,IAAI,KAAK,KAAK;EAC9B,MAAM,eAAe,QAAQ,UAAU;AAGvC,MAFsB,mBAAmB,aAExB,KAAK,WAAW;GAE/B,MAAM,aAAa,cAAc,OAAO,KAAK;AAC7C,WAAQ,SAAS,eAAe,WAAW;AAC3C,YAAS,QAAQ;;AAGnB,mBAAiB,UAAU;;AAG7B,QACE,qBAAC,OAAD;EAAK,cAAY,WAAW,mBAAmB,mBAAmB,mBAAmB;EAAkB,WAAW,GAAG,kCAAkC,UAAU;EAAE,aAAU;EAAc,eAAY;EAAuB,MAAK;EAAQ,GAAI;YAA/O;GACE,oBAAC,eAAD;IACE,cAAY,WAAW,mBAAmB,UAAU,mBAAmB;IACvE,WAAU;IACV,eAAY;IACN;IACN,QAAQ;IACR,oBAAoB,UAAU,SAAS,OAAO;IAC9C,QAAQ,WAAW,SAAY;IAC/B,QAAQ,WAAW,UAAU;IAC7B,KAAK;IACL,SAAS;IACT,cAAc;IACd;GAEF,oBAAC,QAAD;IAAM,eAAY;IAAO,WAAU;cAAc;IAE1C;GAEP,oBAAC,eAAD;IACE,cAAY,mBAAmB;IAC/B,WAAU;IACV,eAAY;IACN;IACN,QAAQ;IACR,mBAAmB,QAAQ,SAAS,OAAO;IAC3C,cAAc,CAAC,iBAAiB,UAAU,SAAS,OAAO,GAAG;IAC7D,QAAQ,WAAW,SAAY;IAC/B,QAAO;IACP,KAAK;IACL,SAAS;IACT,cAAc;IACd;GAED,CAAC,YAAY,oBAAC,kBAAD;IAAkB,WAAW;IAAuB,QAAQ;IAAc,mBAAmB,UAAU,SAAS,OAAO;IAAE,gBAAgB;IAA4B;IAAQ,KAAK;IAAa;GACzM;;;AAGV,WAAW,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimePicker.js","names":[],"sources":["../src/components/DateTimePicker/DateTimePicker.tsx"],"sourcesContent":["import { CalendarIcon } from '@components/Icons'\nimport { Popover, PopoverContent, PopoverTrigger } from '@components/Popover/Popover'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useMemo, type ComponentProps } from 'react'\nimport { type Locale } from 'react-day-picker'\nimport { Calendar, type CalendarProps } from './Calendar'\nimport { DateTimeDisplayInput } from './DateTimeDisplayInput'\nimport { detectHourFormat, getResolvedLocale, type HourFormat, type Period, type TimePickerTranslations } from './DateTimeUtils'\nimport { TimePicker } from './TimePicker'\n\nexport interface DateTimePickerProps extends Omit<ComponentProps<'div'>, 'onChange' | 'defaultValue'> {\n calendarProps?: Omit<CalendarProps, 'mode' | 'selected' | 'onSelect' | 'disablePastDates' | 'locale'>\n defaultValue?: Date\n disabled?: boolean\n disablePastDates?: boolean\n errorMessage?: string | string[] | Record<string, unknown> | null\n hourFormat?: HourFormat\n label?: string\n locale?: Partial<Locale>\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (date: Date | undefined) => void\n showTimePicker?: boolean\n state?: 'default' | 'disabled' | 'error'\n timeLocale?: string\n /** Override translation strings for time picker ARIA labels */\n timeTranslations?: Partial<TimePickerTranslations>\n value?: Date\n}\n\nexport const DateTimePicker = ({\n calendarProps,\n className,\n defaultValue,\n disabled = false,\n disablePastDates = true,\n errorMessage,\n hourFormat,\n label,\n locale,\n messageReserveLines = 1,\n messageReserveSpace = false,\n onChange,\n showTimePicker = true,\n state = 'default',\n timeLocale,\n timeTranslations,\n value,\n id,\n ...props\n}: DateTimePickerProps) => {\n const fieldId = useFormFieldId(id)\n const errorMessageId = getErrorMessageId(fieldId)\n const describedBy = state === 'error' && errorMessage ? errorMessageId : undefined\n const [date, setDate] = useUncontrolledState<Date | undefined>({\n defaultValue,\n onChange,\n value,\n })\n\n // Resolve time locale with fallback chain\n const resolvedTimeLocale = useMemo(() => getResolvedLocale(timeLocale), [timeLocale])\n\n // Auto-detect hour format from locale if not explicitly provided\n const effectiveHourFormat = useMemo(() => hourFormat ?? detectHourFormat(resolvedTimeLocale), [hourFormat, resolvedTimeLocale])\n\n const handleDateSelect = (selectedDate: Date | undefined) => {\n if (!selectedDate) {\n setDate(undefined)\n return\n }\n\n // Preserve the time from the existing date\n if (date) {\n selectedDate.setHours(date.getHours(), date.getMinutes(), 0, 0)\n }\n\n setDate(selectedDate)\n }\n\n const handleTimeChange = useCallback(\n (newDate: Date | undefined) => {\n setDate(newDate)\n },\n [setDate],\n )\n\n const handlePeriodChange = (period: Period) => {\n // Period change is already handled in TimePicker\n // This callback is for external consumers who want to react to period changes\n void period\n }\n\n const handleInputDateChange = (newDate: Date | undefined) => {\n setDate(newDate)\n }\n\n return (\n <Popover>\n <div\n className={cn('w-full', className)}\n data-slot='datetime-picker'\n data-testid='spectral-datetime-picker'\n {...props}\n >\n <DateTimeDisplayInput\n aria-describedby={describedBy}\n aria-invalid={state === 'error'}\n className={cn('gap-4 pr-12 flex w-full justify-start', !date && 'text-text-secondary')}\n data-testid='spectral-datetime-picker-input'\n disabled={disabled}\n endIcon={\n <PopoverTrigger\n asChild\n disabled={disabled}\n >\n <CalendarIcon\n aria-label='Open date picker'\n className={cn('right-4 text-input-icon hover:text-input-icon--hover absolute top-1/2 -translate-y-1/2 cursor-pointer focus:outline-none', disabled ? 'pointer-events-none cursor-not-allowed opacity-50' : 'hover:text-input-icon--hover cursor-pointer')}\n data-testid='spectral-datetime-picker-trigger'\n disabled={disabled}\n />\n </PopoverTrigger>\n }\n hourFormat={effectiveHourFormat}\n id={fieldId}\n label={label}\n onChange={handleInputDateChange}\n showTime={showTimePicker}\n state={state}\n value={date}\n />\n <ErrorMessage\n dataTestId='spectral-datetime-picker-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n />\n </div>\n\n <PopoverContent\n align='start'\n className={cn('rounded-lg py-4 px-6 flex', !showTimePicker && 'w-[330px]', showTimePicker && effectiveHourFormat === '24' && 'w-[486px]', showTimePicker && effectiveHourFormat === '12' && 'w-[560px]')}\n data-testid='spectral-datetime-picker-popover'\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <Calendar\n {...calendarProps}\n disablePastDates={disablePastDates}\n locale={locale}\n mode='single'\n onSelect={handleDateSelect}\n selected={date}\n />\n {showTimePicker && (\n <div className='pl-6 border-l border-border-secondary'>\n <TimePicker\n date={date}\n hourFormat={effectiveHourFormat}\n locale={resolvedTimeLocale}\n onChange={handleTimeChange}\n onPeriodChange={handlePeriodChange}\n translations={timeTranslations}\n />\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n\nDateTimePicker.displayName = 'DateTimePicker'\n\n// Re-export sub-components for granular usage\nexport { Calendar } from './Calendar'\nexport { DateTimeDisplayInput } from './DateTimeDisplayInput'\nexport { DateTimeInput } from './DateTimeInput'\nexport { TimePeriodSelect } from './TimePeriodSelect'\nexport { TimePicker } from './TimePicker'\nexport * from './DateTimeUtils'\nexport { type Locale } from 'react-day-picker'\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgCA,MAAa,kBAAkB,EAC7B,eACA,WACA,cACA,WAAW,OACX,mBAAmB,MACnB,cACA,YACA,OACA,QACA,sBAAsB,GACtB,sBAAsB,OACtB,UACA,iBAAiB,MACjB,QAAQ,WACR,YACA,kBACA,OACA,IACA,GAAG,YACsB;CACzB,MAAM,UAAU,eAAe,GAAG;CAClC,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,cAAc,UAAU,WAAW,eAAe,iBAAiB;CACzE,MAAM,CAAC,MAAM,WAAW,qBAAuC;EAC7D;EACA;EACA;EACD,CAAC;CAGF,MAAM,qBAAqB,cAAc,kBAAkB,WAAW,EAAE,CAAC,WAAW,CAAC;CAGrF,MAAM,sBAAsB,cAAc,cAAc,iBAAiB,mBAAmB,EAAE,CAAC,YAAY,mBAAmB,CAAC;CAE/H,MAAM,oBAAoB,iBAAmC;AAC3D,MAAI,CAAC,cAAc;AACjB,WAAQ,OAAU;AAClB;;AAIF,MAAI,KACF,cAAa,SAAS,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE;AAGjE,UAAQ,aAAa;;CAGvB,MAAM,mBAAmB,aACtB,YAA8B;AAC7B,UAAQ,QAAQ;IAElB,CAAC,QAAQ,CACV;CAED,MAAM,sBAAsB,WAAmB;CAM/C,MAAM,yBAAyB,YAA8B;AAC3D,UAAQ,QAAQ;;AAGlB,QACE,qBAAC,SAAD,aACE,qBAAC,OAAD;EACE,WAAW,GAAG,UAAU,UAAU;EAClC,aAAU;EACV,eAAY;EACZ,GAAI;YAJN,CAME,oBAAC,sBAAD;GACE,oBAAkB;GAClB,gBAAc,UAAU;GACxB,WAAW,GAAG,yCAAyC,CAAC,QAAQ,sBAAsB;GACtF,eAAY;GACF;GACV,SACE,oBAAC,gBAAD;IACE;IACU;cAEV,oBAAC,cAAD;KACE,cAAW;KACX,WAAW,GAAG,4HAA4H,WAAW,sDAAsD,8CAA8C;KACzP,eAAY;KACF;KACV;IACa;GAEnB,YAAY;GACZ,IAAI;GACG;GACP,UAAU;GACV,UAAU;GACH;GACP,OAAO;GACP,GACF,oBAAC,cAAD;GACE,YAAW;GACX,IAAI;GACJ,SAAS,UAAU,UAAU,eAAe;GACvB;GACA;GACrB,EACE;KAEN,qBAAC,gBAAD;EACE,OAAM;EACN,WAAW,GAAG,6BAA6B,CAAC,kBAAkB,aAAa,kBAAkB,wBAAwB,QAAQ,aAAa,kBAAkB,wBAAwB,QAAQ,YAAY;EACxM,eAAY;EACZ,kBAAkB,MAAM,EAAE,gBAAgB;YAJ5C,CAME,oBAAC,UAAD;GACE,GAAI;GACc;GACV;GACR,MAAK;GACL,UAAU;GACV,UAAU;GACV,GACD,kBACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,YAAD;IACQ;IACN,YAAY;IACZ,QAAQ;IACR,UAAU;IACV,gBAAgB;IAChB,cAAc;IACd;GACE,EAEO;IACT;;AAId,eAAe,cAAc"}
1
+ {"version":3,"file":"DateTimePicker.js","names":[],"sources":["../src/components/DateTimePicker/DateTimePicker.tsx"],"sourcesContent":["import { CalendarIcon } from '@components/Icons'\nimport { Popover, PopoverContent, PopoverTrigger } from '@components/Popover/Popover'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useMemo, type ComponentProps } from 'react'\nimport { type Locale } from 'react-day-picker'\nimport { Calendar, type CalendarProps } from './Calendar'\nimport { DateTimeDisplayInput } from './DateTimeDisplayInput'\nimport { detectHourFormat, getResolvedLocale, type HourFormat, type Period, type TimePickerTranslations } from './DateTimeUtils'\nimport { TimePicker } from './TimePicker'\n\nexport interface DateTimePickerProps extends Omit<ComponentProps<'div'>, 'onChange' | 'defaultValue'> {\n calendarProps?: Omit<CalendarProps, 'mode' | 'selected' | 'onSelect' | 'disablePastDates' | 'locale'>\n defaultValue?: Date\n disabled?: boolean\n disablePastDates?: boolean\n errorMessage?: string | string[] | Record<string, unknown> | null\n hourFormat?: HourFormat\n label?: string\n locale?: Partial<Locale>\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (date: Date | undefined) => void\n showTimePicker?: boolean\n state?: 'default' | 'disabled' | 'error'\n timeLocale?: string\n /** Override translation strings for time picker ARIA labels */\n timeTranslations?: Partial<TimePickerTranslations>\n value?: Date\n}\n\nexport const DateTimePicker = ({\n calendarProps,\n className,\n defaultValue,\n disabled = false,\n disablePastDates = true,\n errorMessage,\n hourFormat,\n label,\n locale,\n messageReserveLines = 1,\n messageReserveSpace = false,\n onChange,\n showTimePicker = true,\n state = 'default',\n timeLocale,\n timeTranslations,\n value,\n id,\n ...props\n}: DateTimePickerProps) => {\n const fieldId = useFormFieldId(id)\n const errorMessageId = getErrorMessageId(fieldId)\n const describedBy = state === 'error' && errorMessage ? errorMessageId : undefined\n const [date, setDate] = useUncontrolledState<Date | undefined>({\n defaultValue,\n onChange,\n value,\n })\n\n // Resolve time locale with fallback chain\n const resolvedTimeLocale = useMemo(() => getResolvedLocale(timeLocale), [timeLocale])\n\n // Auto-detect hour format from locale if not explicitly provided\n const effectiveHourFormat = useMemo(() => hourFormat ?? detectHourFormat(resolvedTimeLocale), [hourFormat, resolvedTimeLocale])\n\n const handleDateSelect = (selectedDate: Date | undefined) => {\n if (!selectedDate) {\n setDate(undefined)\n return\n }\n\n // Preserve the time from the existing date\n if (date) {\n selectedDate.setHours(date.getHours(), date.getMinutes(), 0, 0)\n }\n\n setDate(selectedDate)\n }\n\n const handleTimeChange = useCallback(\n (newDate: Date | undefined) => {\n setDate(newDate)\n },\n [setDate],\n )\n\n const handlePeriodChange = (period: Period) => {\n // Period change is already handled in TimePicker\n // This callback is for external consumers who want to react to period changes\n void period\n }\n\n const handleInputDateChange = (newDate: Date | undefined) => {\n setDate(newDate)\n }\n\n return (\n <Popover>\n <div className={cn('w-full', className)} data-slot='datetime-picker' data-testid='spectral-datetime-picker' {...props}>\n <DateTimeDisplayInput\n aria-describedby={describedBy}\n aria-invalid={state === 'error'}\n className={cn('gap-4 pr-12 flex w-full justify-start', !date && 'text-text-secondary')}\n data-testid='spectral-datetime-picker-input'\n disabled={disabled}\n endIcon={\n <PopoverTrigger asChild disabled={disabled}>\n <CalendarIcon\n aria-label='Open date picker'\n className={cn('right-4 text-input-icon hover:text-input-icon--hover absolute top-1/2 -translate-y-1/2 cursor-pointer focus:outline-none', disabled ? 'pointer-events-none cursor-not-allowed opacity-50' : 'hover:text-input-icon--hover cursor-pointer')}\n data-testid='spectral-datetime-picker-trigger'\n disabled={disabled}\n />\n </PopoverTrigger>\n }\n hourFormat={effectiveHourFormat}\n id={fieldId}\n label={label}\n onChange={handleInputDateChange}\n showTime={showTimePicker}\n state={state}\n value={date}\n />\n <ErrorMessage\n dataTestId='spectral-datetime-picker-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n />\n </div>\n\n <PopoverContent\n align='start'\n className={cn('rounded-lg py-4 px-6 flex', !showTimePicker && 'w-[330px]', showTimePicker && effectiveHourFormat === '24' && 'w-[486px]', showTimePicker && effectiveHourFormat === '12' && 'w-[560px]')}\n data-testid='spectral-datetime-picker-popover'\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <Calendar {...calendarProps} disablePastDates={disablePastDates} locale={locale} mode='single' onSelect={handleDateSelect} selected={date} />\n {showTimePicker && (\n <div className='pl-6 border-l border-border-secondary'>\n <TimePicker date={date} hourFormat={effectiveHourFormat} locale={resolvedTimeLocale} onChange={handleTimeChange} onPeriodChange={handlePeriodChange} translations={timeTranslations} />\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n\nDateTimePicker.displayName = 'DateTimePicker'\n\n// Re-export sub-components for granular usage\nexport { Calendar } from './Calendar'\nexport { DateTimeDisplayInput } from './DateTimeDisplayInput'\nexport { DateTimeInput } from './DateTimeInput'\nexport { TimePeriodSelect } from './TimePeriodSelect'\nexport { TimePicker } from './TimePicker'\nexport * from './DateTimeUtils'\nexport { type Locale } from 'react-day-picker'\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgCA,MAAa,kBAAkB,EAC7B,eACA,WACA,cACA,WAAW,OACX,mBAAmB,MACnB,cACA,YACA,OACA,QACA,sBAAsB,GACtB,sBAAsB,OACtB,UACA,iBAAiB,MACjB,QAAQ,WACR,YACA,kBACA,OACA,IACA,GAAG,YACsB;CACzB,MAAM,UAAU,eAAe,GAAG;CAClC,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,cAAc,UAAU,WAAW,eAAe,iBAAiB;CACzE,MAAM,CAAC,MAAM,WAAW,qBAAuC;EAC7D;EACA;EACA;EACD,CAAC;CAGF,MAAM,qBAAqB,cAAc,kBAAkB,WAAW,EAAE,CAAC,WAAW,CAAC;CAGrF,MAAM,sBAAsB,cAAc,cAAc,iBAAiB,mBAAmB,EAAE,CAAC,YAAY,mBAAmB,CAAC;CAE/H,MAAM,oBAAoB,iBAAmC;AAC3D,MAAI,CAAC,cAAc;AACjB,WAAQ,OAAU;AAClB;;AAIF,MAAI,KACF,cAAa,SAAS,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE;AAGjE,UAAQ,aAAa;;CAGvB,MAAM,mBAAmB,aACtB,YAA8B;AAC7B,UAAQ,QAAQ;IAElB,CAAC,QAAQ,CACV;CAED,MAAM,sBAAsB,WAAmB;CAM/C,MAAM,yBAAyB,YAA8B;AAC3D,UAAQ,QAAQ;;AAGlB,QACE,qBAAC,SAAD,aACE,qBAAC,OAAD;EAAK,WAAW,GAAG,UAAU,UAAU;EAAE,aAAU;EAAkB,eAAY;EAA2B,GAAI;YAAhH,CACE,oBAAC,sBAAD;GACE,oBAAkB;GAClB,gBAAc,UAAU;GACxB,WAAW,GAAG,yCAAyC,CAAC,QAAQ,sBAAsB;GACtF,eAAY;GACF;GACV,SACE,oBAAC,gBAAD;IAAgB;IAAkB;cAChC,oBAAC,cAAD;KACE,cAAW;KACX,WAAW,GAAG,4HAA4H,WAAW,sDAAsD,8CAA8C;KACzP,eAAY;KACF;KACV;IACa;GAEnB,YAAY;GACZ,IAAI;GACG;GACP,UAAU;GACV,UAAU;GACH;GACP,OAAO;GACP,GACF,oBAAC,cAAD;GACE,YAAW;GACX,IAAI;GACJ,SAAS,UAAU,UAAU,eAAe;GACvB;GACA;GACrB,EACE;KAEN,qBAAC,gBAAD;EACE,OAAM;EACN,WAAW,GAAG,6BAA6B,CAAC,kBAAkB,aAAa,kBAAkB,wBAAwB,QAAQ,aAAa,kBAAkB,wBAAwB,QAAQ,YAAY;EACxM,eAAY;EACZ,kBAAkB,MAAM,EAAE,gBAAgB;YAJ5C,CAME,oBAAC,UAAD;GAAU,GAAI;GAAiC;GAA0B;GAAQ,MAAK;GAAS,UAAU;GAAkB,UAAU;GAAQ,GAC5I,kBACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,YAAD;IAAkB;IAAM,YAAY;IAAqB,QAAQ;IAAoB,UAAU;IAAkB,gBAAgB;IAAoB,cAAc;IAAoB;GACnL,EAEO;IACT;;AAId,eAAe,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"mappings":";;;;;;cAMM,MAAA;EAAM,MAAA;EAAA,KAAA;EAAA,GAAA;AAAA,GAIT,IAAA,CAAK,cAAA,QAAsB,eAAA,CAAgB,IAAA;EAC5C,MAAA;EACA,aAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAYK,aAAA;EAAA,GAAa;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAU7E,YAAA;EAAA,GAAY;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,MAAA,MAAO,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAU3E,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAYpF,aAAA;EAAa,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWxF,aAAA;EAAa,QAAA;EAAA,SAAA;EAAA,aAAA;EAAA,eAAA;EAAA,iBAAA;EAAA,oBAAA;EAAA,eAAA;EAAA,GAAA;AAAA,GAShB,cAAA,QAAsB,eAAA,CAAgB,OAAA;EACvC,aAAA;EACA,eAAA,IAAmB,KAAA,EAAO,aAAA;EAC1B,iBAAA,IAAqB,KAAA,EAAO,YAAA,GAAe,UAAA;EAC3C,oBAAA,IAAwB,KAAA,EAAO,YAAA;EAC/B,eAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAsCK,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAW9D,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAW9D,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWpF,iBAAA;EAAiB,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,WAAA,MAAY,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Dialog.d.ts","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"mappings":";;;;;;cAMM,MAAA;EAAM,MAAA;EAAA,KAAA;EAAA,GAAA;AAAA,GAIT,IAAA,CAAK,cAAA,QAAsB,eAAA,CAAgB,IAAA;EAC5C,MAAA;EACA,aAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIK,aAAA;EAAA,GAAa;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI7E,YAAA;EAAA,GAAY;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,MAAA,MAAO,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI3E,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIpF,aAAA;EAAa,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAYxF,aAAA;EAAa,QAAA;EAAA,SAAA;EAAA,aAAA;EAAA,eAAA;EAAA,iBAAA;EAAA,oBAAA;EAAA,eAAA;EAAA,GAAA;AAAA,GAShB,cAAA,QAAsB,eAAA,CAAgB,OAAA;EACvC,aAAA;EACA,eAAA,IAAmB,KAAA,EAAO,aAAA;EAC1B,iBAAA,IAAqB,KAAA,EAAO,YAAA,GAAe,UAAA;EAC3C,oBAAA,IAAwB,KAAA,EAAO,YAAA;EAC/B,eAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAmCK,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI9D,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI9D,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIpF,iBAAA;EAAiB,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,WAAA,MAAY,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/Dialog.js CHANGED
@@ -41,7 +41,7 @@ const DialogClose = ({ className, ...props }) => {
41
41
  };
42
42
  const DialogOverlay = ({ className, ...props }) => {
43
43
  return /* @__PURE__ */ jsx(DialogPrimitive.Overlay, {
44
- className: cn("inset-0 bg-black/50 backdrop-blur-sm fixed z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0", "motion-safe:data-[state=closed]:fade-out-0", className),
44
+ className: cn("inset-0 bg-black/50 backdrop-blur-sm fixed z-50 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:animate-out", "motion-safe:data-[state=closed]:fade-out-0", className),
45
45
  "data-slot": "dialog-overlay",
46
46
  "data-testid": "spectral-dialog-overlay",
47
47
  ...props
@@ -60,7 +60,7 @@ const DialogContent = ({ children, className, dialogOverlay = true, onEscapeKeyD
60
60
  onPointerDownOutside,
61
61
  ...props,
62
62
  children: [children, showCloseButton && /* @__PURE__ */ jsxs(DialogPrimitive.Close, {
63
- className: `top-4 right-4 rounded-xs absolute opacity-70 transition-opacity hover:cursor-pointer hover:opacity-100 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-accent disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-text-primary [&_svg]:pointer-events-none [&_svg]:shrink-0`,
63
+ className: `focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-accent data-[state=open]:text-text-primary top-4 right-4 rounded-xs absolute opacity-70 transition-opacity hover:opacity-100 hover:cursor-pointer disabled:pointer-events-none data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:shrink-0`,
64
64
  "data-slot": "dialog-close",
65
65
  "data-testid": "spectral-dialog-close",
66
66
  children: [/* @__PURE__ */ jsx(CloseIcon, { size: 18 }), /* @__PURE__ */ jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.js","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import { CloseIcon } from '@components/Icons/CloseIcon'\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\nimport { RemoveScroll } from 'react-remove-scroll'\n\nconst Dialog = ({\n isOpen,\n modal = false,\n ...props\n}: Omit<ComponentProps<typeof DialogPrimitive.Root>, 'open'> & {\n isOpen?: boolean\n dialogOverlay?: boolean\n}) => {\n return (\n <DialogPrimitive.Root\n open={isOpen}\n modal={modal}\n data-slot='dialog'\n data-testid='spectral-dialog'\n {...props}\n />\n )\n}\n\nconst DialogTrigger = ({ ...props }: ComponentProps<typeof DialogPrimitive.Trigger>) => {\n return (\n <DialogPrimitive.Trigger\n asChild\n data-testid='spectral-dialog-trigger'\n {...props}\n />\n )\n}\n\nconst DialogPortal = ({ ...props }: ComponentProps<typeof DialogPrimitive.Portal>) => {\n return (\n <DialogPrimitive.Portal\n data-slot='dialog-portal'\n data-testid='dialog-portal'\n {...props}\n />\n )\n}\n\nconst DialogClose = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Close>) => {\n return (\n <DialogPrimitive.Close\n asChild\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n {...props}\n className={cn('hover:cursor-pointer', className)}\n />\n )\n}\n\nconst DialogOverlay = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Overlay>) => {\n return (\n <DialogPrimitive.Overlay\n className={cn('inset-0 bg-black/50 backdrop-blur-sm fixed z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0', 'motion-safe:data-[state=closed]:fade-out-0', className)}\n data-slot='dialog-overlay'\n data-testid='spectral-dialog-overlay'\n {...props}\n />\n )\n}\n\nconst DialogContent = ({\n children,\n className,\n dialogOverlay = true,\n onEscapeKeyDown,\n onInteractOutside,\n onPointerDownOutside,\n showCloseButton = true,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Content> & {\n dialogOverlay?: boolean\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n onInteractOutside?: (event: PointerEvent | FocusEvent) => void\n onPointerDownOutside?: (event: PointerEvent) => void\n showCloseButton?: boolean\n}) => {\n return (\n <DialogPortal\n data-slot='dialog-portal'\n data-testid='spectral-dialog-portal'\n >\n {dialogOverlay && <DialogOverlay />}\n <DialogPrimitive.Content\n className={cn(\n 'max-w-xl gap-4 rounded-lg p-6 shadow-lg has-[[data-slot=dialog-footer]]:pb-0 fixed top-[50%] left-[50%] z-50 flex max-h-[90vh] w-full -translate-x-1/2 -translate-y-1/2 flex-col overflow-y-auto overscroll-contain bg-dialog-bg',\n 'motion-safe:data-[state=open]:duration-200 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:slide-in-from-bottom-20 motion-safe:data-[state=open]:zoom-in-100!',\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95',\n RemoveScroll.classNames.fullWidth,\n className,\n )}\n data-slot='dialog-content'\n data-testid='spectral-dialog-content'\n onEscapeKeyDown={onEscapeKeyDown}\n onInteractOutside={onInteractOutside}\n onPointerDownOutside={onPointerDownOutside}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n className={`top-4 right-4 rounded-xs absolute opacity-70 transition-opacity hover:cursor-pointer hover:opacity-100 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-accent disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-text-primary [&_svg]:pointer-events-none [&_svg]:shrink-0`}\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n >\n <CloseIcon size={18} />\n <span className='sr-only'>Close dialog</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n )\n}\n\nconst DialogHeader = ({ className, ...props }: ComponentProps<'div'>) => {\n return (\n <div\n className={cn('gap-2 sm:text-left flex flex-col text-center', className)}\n data-slot='dialog-header'\n data-testid='spectral-dialog-header'\n {...props}\n />\n )\n}\n\nconst DialogFooter = ({ className, ...props }: ComponentProps<'div'>) => {\n return (\n <div\n className={cn('gap-2 sm:flex-row sm:justify-end bottom-0 py-4 px-6 -mx-6 sticky z-10 flex flex-col-reverse bg-dialog-bg/85', className)}\n data-slot='dialog-footer'\n data-testid='spectral-dialog-footer'\n {...props}\n />\n )\n}\n\nconst DialogTitle = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Title>) => {\n return (\n <DialogPrimitive.Title\n className={cn('text-2xl font-semibold leading-none', className)}\n data-slot='dialog-title'\n data-testid='spectral-dialog-title'\n {...props}\n />\n )\n}\n\nconst DialogDescription = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Description>) => {\n return (\n <DialogPrimitive.Description\n className={cn('text-muted-foreground text-sm', className)}\n data-slot='dialog-description'\n data-testid='spectral-dialog-description'\n {...props}\n />\n )\n}\n\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger }\n"],"mappings":";;;;;;;;;AAMA,MAAM,UAAU,EACd,QACA,QAAQ,OACR,GAAG,YAIC;AACJ,QACE,oBAAC,gBAAgB,MAAjB;EACE,MAAM;EACC;EACP,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EAAE,GAAG,YAA4D;AACtF,QACE,oBAAC,gBAAgB,SAAjB;EACE;EACA,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,gBAAgB,EAAE,GAAG,YAA2D;AACpF,QACE,oBAAC,gBAAgB,QAAjB;EACE,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QACE,oBAAC,gBAAgB,OAAjB;EACE;EACA,aAAU;EACV,eAAY;EACZ,GAAI;EACJ,WAAW,GAAG,wBAAwB,UAAU;EAChD;;AAIN,MAAM,iBAAiB,EAAE,WAAW,GAAG,YAA4D;AACjG,QACE,oBAAC,gBAAgB,SAAjB;EACE,WAAW,GAAG,gLAAgL,8CAA8C,UAAU;EACtP,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EACrB,UACA,WACA,gBAAgB,MAChB,iBACA,mBACA,sBACA,kBAAkB,MAClB,GAAG,YAOC;AACJ,QACE,qBAAC,cAAD;EACE,aAAU;EACV,eAAY;YAFd,CAIG,iBAAiB,oBAAC,eAAD,EAAiB,GACnC,qBAAC,gBAAgB,SAAjB;GACE,WAAW,GACT,oOACA,wLACA,sIACA,aAAa,WAAW,WACxB,UACD;GACD,aAAU;GACV,eAAY;GACK;GACE;GACG;GACtB,GAAI;aAbN,CAeG,UACA,mBACC,qBAAC,gBAAgB,OAAjB;IACE,WAAW;IACX,aAAU;IACV,eAAY;cAHd,CAKE,oBAAC,WAAD,EAAW,MAAM,IAAM,GACvB,oBAAC,QAAD;KAAM,WAAU;eAAU;KAAmB,EACvB;MAEF;KACb;;;AAInB,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,gDAAgD,UAAU;EACxE,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,+GAA+G,UAAU;EACvI,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QACE,oBAAC,gBAAgB,OAAjB;EACE,WAAW,GAAG,uCAAuC,UAAU;EAC/D,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,qBAAqB,EAAE,WAAW,GAAG,YAAgE;AACzG,QACE,oBAAC,gBAAgB,aAAjB;EACE,WAAW,GAAG,iCAAiC,UAAU;EACzD,aAAU;EACV,eAAY;EACZ,GAAI;EACJ"}
1
+ {"version":3,"file":"Dialog.js","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import { CloseIcon } from '@components/Icons/CloseIcon'\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\nimport { RemoveScroll } from 'react-remove-scroll'\n\nconst Dialog = ({\n isOpen,\n modal = false,\n ...props\n}: Omit<ComponentProps<typeof DialogPrimitive.Root>, 'open'> & {\n isOpen?: boolean\n dialogOverlay?: boolean\n}) => {\n return <DialogPrimitive.Root open={isOpen} modal={modal} data-slot='dialog' data-testid='spectral-dialog' {...props} />\n}\n\nconst DialogTrigger = ({ ...props }: ComponentProps<typeof DialogPrimitive.Trigger>) => {\n return <DialogPrimitive.Trigger asChild data-testid='spectral-dialog-trigger' {...props} />\n}\n\nconst DialogPortal = ({ ...props }: ComponentProps<typeof DialogPrimitive.Portal>) => {\n return <DialogPrimitive.Portal data-slot='dialog-portal' data-testid='dialog-portal' {...props} />\n}\n\nconst DialogClose = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Close>) => {\n return <DialogPrimitive.Close asChild data-slot='dialog-close' data-testid='spectral-dialog-close' {...props} className={cn('hover:cursor-pointer', className)} />\n}\n\nconst DialogOverlay = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Overlay>) => {\n return (\n <DialogPrimitive.Overlay\n className={cn('inset-0 bg-black/50 backdrop-blur-sm fixed z-50 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:animate-out',\n 'motion-safe:data-[state=closed]:fade-out-0', className)}\n data-slot='dialog-overlay'\n data-testid='spectral-dialog-overlay'\n {...props}\n />\n )\n}\n\nconst DialogContent = ({\n children,\n className,\n dialogOverlay = true,\n onEscapeKeyDown,\n onInteractOutside,\n onPointerDownOutside,\n showCloseButton = true,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Content> & {\n dialogOverlay?: boolean\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n onInteractOutside?: (event: PointerEvent | FocusEvent) => void\n onPointerDownOutside?: (event: PointerEvent) => void\n showCloseButton?: boolean\n}) => {\n return (\n <DialogPortal data-slot='dialog-portal' data-testid='spectral-dialog-portal'>\n {dialogOverlay && <DialogOverlay />}\n <DialogPrimitive.Content\n className={cn(\n 'max-w-xl gap-4 rounded-lg p-6 shadow-lg has-[[data-slot=dialog-footer]]:pb-0 fixed top-[50%] left-[50%] z-50 flex max-h-[90vh] w-full -translate-x-1/2 -translate-y-1/2 flex-col overflow-y-auto overscroll-contain bg-dialog-bg',\n 'motion-safe:data-[state=open]:duration-200 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:slide-in-from-bottom-20 motion-safe:data-[state=open]:zoom-in-100!',\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95',\n RemoveScroll.classNames.fullWidth,\n className,\n )}\n data-slot='dialog-content'\n data-testid='spectral-dialog-content'\n onEscapeKeyDown={onEscapeKeyDown}\n onInteractOutside={onInteractOutside}\n onPointerDownOutside={onPointerDownOutside}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n className={`focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-accent data-[state=open]:text-text-primary top-4 right-4 rounded-xs absolute opacity-70 transition-opacity hover:opacity-100 hover:cursor-pointer disabled:pointer-events-none data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:shrink-0`}\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n >\n <CloseIcon size={18} />\n <span className='sr-only'>Close dialog</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n )\n}\n\nconst DialogHeader = ({ className, ...props }: ComponentProps<'div'>) => {\n return <div className={cn('gap-2 sm:text-left flex flex-col text-center', className)} data-slot='dialog-header' data-testid='spectral-dialog-header' {...props} />\n}\n\nconst DialogFooter = ({ className, ...props }: ComponentProps<'div'>) => {\n return <div className={cn('gap-2 sm:flex-row sm:justify-end bottom-0 py-4 px-6 -mx-6 sticky z-10 flex flex-col-reverse bg-dialog-bg/85', className)} data-slot='dialog-footer' data-testid='spectral-dialog-footer' {...props} />\n}\n\nconst DialogTitle = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Title>) => {\n return <DialogPrimitive.Title className={cn('text-2xl font-semibold leading-none', className)} data-slot='dialog-title' data-testid='spectral-dialog-title' {...props} />\n}\n\nconst DialogDescription = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Description>) => {\n return <DialogPrimitive.Description className={cn('text-muted-foreground text-sm', className)} data-slot='dialog-description' data-testid='spectral-dialog-description' {...props} />\n}\n\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger }\n"],"mappings":";;;;;;;;;AAMA,MAAM,UAAU,EACd,QACA,QAAQ,OACR,GAAG,YAIC;AACJ,QAAO,oBAAC,gBAAgB,MAAjB;EAAsB,MAAM;EAAe;EAAO,aAAU;EAAS,eAAY;EAAkB,GAAI;EAAS;;AAGzH,MAAM,iBAAiB,EAAE,GAAG,YAA4D;AACtF,QAAO,oBAAC,gBAAgB,SAAjB;EAAyB;EAAQ,eAAY;EAA0B,GAAI;EAAS;;AAG7F,MAAM,gBAAgB,EAAE,GAAG,YAA2D;AACpF,QAAO,oBAAC,gBAAgB,QAAjB;EAAwB,aAAU;EAAgB,eAAY;EAAgB,GAAI;EAAS;;AAGpG,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QAAO,oBAAC,gBAAgB,OAAjB;EAAuB;EAAQ,aAAU;EAAe,eAAY;EAAwB,GAAI;EAAO,WAAW,GAAG,wBAAwB,UAAU;EAAI;;AAGpK,MAAM,iBAAiB,EAAE,WAAW,GAAG,YAA4D;AACjG,QACE,oBAAC,gBAAgB,SAAjB;EACE,WAAW,GAAG,gLACd,8CAA8C,UAAU;EACxD,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EACrB,UACA,WACA,gBAAgB,MAChB,iBACA,mBACA,sBACA,kBAAkB,MAClB,GAAG,YAOC;AACJ,QACE,qBAAC,cAAD;EAAc,aAAU;EAAgB,eAAY;YAApD,CACG,iBAAiB,oBAAC,eAAD,EAAiB,GACnC,qBAAC,gBAAgB,SAAjB;GACE,WAAW,GACT,oOACA,wLACA,sIACA,aAAa,WAAW,WACxB,UACD;GACD,aAAU;GACV,eAAY;GACK;GACE;GACG;GACtB,GAAI;aAbN,CAeG,UACA,mBACC,qBAAC,gBAAgB,OAAjB;IACE,WAAW;IACX,aAAU;IACV,eAAY;cAHd,CAKE,oBAAC,WAAD,EAAW,MAAM,IAAM,GACvB,oBAAC,QAAD;KAAM,WAAU;eAAU;KAAmB,EACvB;MAEF;KACb;;;AAInB,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,gDAAgD,UAAU;EAAE,aAAU;EAAgB,eAAY;EAAyB,GAAI;EAAS;;AAGpK,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,+GAA+G,UAAU;EAAE,aAAU;EAAgB,eAAY;EAAyB,GAAI;EAAS;;AAGnO,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QAAO,oBAAC,gBAAgB,OAAjB;EAAuB,WAAW,GAAG,uCAAuC,UAAU;EAAE,aAAU;EAAe,eAAY;EAAwB,GAAI;EAAS;;AAG3K,MAAM,qBAAqB,EAAE,WAAW,GAAG,YAAgE;AACzG,QAAO,oBAAC,gBAAgB,aAAjB;EAA6B,WAAW,GAAG,iCAAiC,UAAU;EAAE,aAAU;EAAqB,eAAY;EAA8B,GAAI;EAAS"}
package/dist/Drawer.d.ts CHANGED
@@ -4,6 +4,7 @@ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
4
 
5
5
  //#region src/components/Drawer/Drawer.d.ts
6
6
  interface DrawerProps {
7
+ className?: string;
7
8
  children?: ReactNode;
8
9
  defaultOpen?: boolean;
9
10
  description?: string;
@@ -18,6 +19,7 @@ interface DrawerProps {
18
19
  }
19
20
  declare const Drawer: ({
20
21
  children,
22
+ className,
21
23
  defaultOpen,
22
24
  description,
23
25
  direction,
@@ -1 +1 @@
1
- {"version":3,"file":"Drawer.d.ts","names":[],"sources":["../src/components/Drawer/Drawer.tsx"],"mappings":";;;;;UAKiB,WAAA;EACf,QAAA,GAAW,SAAA;EACX,WAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,KAAA;EACA,YAAA,IAAgB,IAAA;EAChB,IAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA,EAAS,SAAA;AAAA;AAAA,cAGE,MAAA;EAAM,QAAA;EAAA,WAAA;EAAA,WAAA;EAAA,SAAA;EAAA,WAAA;EAAA,KAAA;EAAA,YAAA;EAAA,IAAA;EAAA,IAAA;EAAA,KAAA;EAAA;AAAA,GAA+J,WAAA,KAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Drawer.d.ts","names":[],"sources":["../src/components/Drawer/Drawer.tsx"],"mappings":";;;;;UAKiB,WAAA;EACf,SAAA;EACA,QAAA,GAAW,SAAA;EACX,WAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,KAAA;EACA,YAAA,IAAgB,IAAA;EAChB,IAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA,EAAS,SAAA;AAAA;AAAA,cAGE,MAAA;EAAM,QAAA;EAAA,SAAA;EAAA,WAAA;EAAA,WAAA;EAAA,SAAA;EAAA,WAAA;EAAA,KAAA;EAAA,YAAA;EAAA,IAAA;EAAA,IAAA;EAAA,KAAA;EAAA;AAAA,GAA0K,WAAA,KAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}