@spear-ai/spectral 1.15.3 → 1.15.5
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.
- package/dist/Accordion.d.ts.map +1 -1
- package/dist/Accordion.js +1 -1
- package/dist/Accordion.js.map +1 -1
- package/dist/Alert/AlertBase.d.ts.map +1 -1
- package/dist/Alert/AlertBase.js.map +1 -1
- package/dist/Alert.js.map +1 -1
- package/dist/Avatar.js.map +1 -1
- package/dist/Badge.d.ts.map +1 -1
- package/dist/Badge.js.map +1 -1
- package/dist/Button.js +6 -6
- package/dist/Button.js.map +1 -1
- package/dist/ButtonGroup/ButtonGroupButton.d.ts +1 -1
- package/dist/ButtonGroup/ButtonGroupButton.d.ts.map +1 -1
- package/dist/ButtonGroup/ButtonGroupButton.js +2 -1
- package/dist/ButtonGroup/ButtonGroupButton.js.map +1 -1
- package/dist/ButtonGroup.d.ts +2 -2
- package/dist/ButtonGroup.d.ts.map +1 -1
- package/dist/ButtonGroup.js +2 -1
- package/dist/ButtonGroup.js.map +1 -1
- package/dist/ButtonIcon.d.ts.map +1 -1
- package/dist/ButtonIcon.js +6 -5
- package/dist/ButtonIcon.js.map +1 -1
- package/dist/ButtonIconSlideout.d.ts +49 -0
- package/dist/ButtonIconSlideout.d.ts.map +1 -0
- package/dist/ButtonIconSlideout.js +108 -0
- package/dist/ButtonIconSlideout.js.map +1 -0
- package/dist/Checkbox/CheckboxBase.js.map +1 -1
- package/dist/Checkbox.js.map +1 -1
- package/dist/Combobox.js.map +1 -1
- package/dist/ControlGroup/ControlGroupSelect.js.map +1 -1
- package/dist/ControlGroup.d.ts.map +1 -1
- package/dist/ControlGroup.js +1 -1
- package/dist/ControlGroup.js.map +1 -1
- package/dist/DataCard/Card.d.ts.map +1 -1
- package/dist/DataCard/Card.js.map +1 -1
- package/dist/DataCard.js.map +1 -1
- package/dist/DateTimePicker/Calendar.js.map +1 -1
- package/dist/DateTimePicker/DateTimeDisplayInput.js.map +1 -1
- package/dist/DateTimePicker/TimePeriodSelect.js.map +1 -1
- package/dist/DateTimePicker/TimePicker.js.map +1 -1
- package/dist/DateTimePicker.js.map +1 -1
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Dialog.js +2 -2
- package/dist/Dialog.js.map +1 -1
- package/dist/Drawer.js +3 -3
- package/dist/Drawer.js.map +1 -1
- package/dist/DropdownMenu.js.map +1 -1
- package/dist/FormFieldMessage.d.ts.map +1 -1
- package/dist/FormFieldMessage.js.map +1 -1
- package/dist/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard.js.map +1 -1
- package/dist/Icons/AdjustmentsIcon.d.ts.map +1 -1
- package/dist/Icons/AdjustmentsIcon.js.map +1 -1
- package/dist/Icons/AnalyzeIcon.d.ts.map +1 -1
- package/dist/Icons/AnalyzeIcon.js.map +1 -1
- package/dist/Icons/AnnotationsIcon.d.ts.map +1 -1
- package/dist/Icons/AnnotationsIcon.js.map +1 -1
- package/dist/Icons/ApprovedIcon.d.ts.map +1 -1
- package/dist/Icons/ApprovedIcon.js.map +1 -1
- package/dist/Icons/ArrowDownIcon.d.ts.map +1 -1
- package/dist/Icons/ArrowDownIcon.js.map +1 -1
- package/dist/Icons/ArrowUpIcon.d.ts.map +1 -1
- package/dist/Icons/ArrowUpIcon.js.map +1 -1
- package/dist/Icons/BoxToolIcon.d.ts.map +1 -1
- package/dist/Icons/BoxToolIcon.js.map +1 -1
- package/dist/Icons/CalendarIcon.d.ts.map +1 -1
- package/dist/Icons/CalendarIcon.js.map +1 -1
- package/dist/Icons/CheckCircleIcon.d.ts.map +1 -1
- package/dist/Icons/CheckCircleIcon.js.map +1 -1
- package/dist/Icons/CheckSquareIcon.d.ts.map +1 -1
- package/dist/Icons/CheckSquareIcon.js.map +1 -1
- package/dist/Icons/CheckmarkIcon.d.ts.map +1 -1
- package/dist/Icons/CheckmarkIcon.js.map +1 -1
- package/dist/Icons/ChevronDownIcon.d.ts.map +1 -1
- package/dist/Icons/ChevronDownIcon.js.map +1 -1
- package/dist/Icons/ChevronUpIcon.d.ts.map +1 -1
- package/dist/Icons/ChevronUpIcon.js.map +1 -1
- package/dist/Icons/ClockIcon.d.ts.map +1 -1
- package/dist/Icons/ClockIcon.js.map +1 -1
- package/dist/Icons/CloseCircleIcon.d.ts.map +1 -1
- package/dist/Icons/CloseCircleIcon.js.map +1 -1
- package/dist/Icons/CloseIcon.d.ts.map +1 -1
- package/dist/Icons/CloseIcon.js.map +1 -1
- package/dist/Icons/Crosshairs2Icon.d.ts.map +1 -1
- package/dist/Icons/Crosshairs2Icon.js.map +1 -1
- package/dist/Icons/CrosshairsIcon.d.ts.map +1 -1
- package/dist/Icons/CrosshairsIcon.js.map +1 -1
- package/dist/Icons/DashboardIcon.d.ts.map +1 -1
- package/dist/Icons/DashboardIcon.js.map +1 -1
- package/dist/Icons/DatabaseIcon.d.ts.map +1 -1
- package/dist/Icons/DatabaseIcon.js.map +1 -1
- package/dist/Icons/DeleteIcon.d.ts.map +1 -1
- package/dist/Icons/DeleteIcon.js.map +1 -1
- package/dist/Icons/DurationIcon.d.ts.map +1 -1
- package/dist/Icons/DurationIcon.js.map +1 -1
- package/dist/Icons/EditIcon.d.ts.map +1 -1
- package/dist/Icons/EditIcon.js.map +1 -1
- package/dist/Icons/EmailIcon.d.ts.map +1 -1
- package/dist/Icons/EmailIcon.js.map +1 -1
- package/dist/Icons/EraserIcon.d.ts.map +1 -1
- package/dist/Icons/EraserIcon.js.map +1 -1
- package/dist/Icons/ErrorIcon.d.ts.map +1 -1
- package/dist/Icons/ErrorIcon.js.map +1 -1
- package/dist/Icons/EyeClosedIcon.d.ts.map +1 -1
- package/dist/Icons/EyeClosedIcon.js.map +1 -1
- package/dist/Icons/EyeClosedIcon2.d.ts.map +1 -1
- package/dist/Icons/EyeClosedIcon2.js.map +1 -1
- package/dist/Icons/EyeOpenIcon.d.ts.map +1 -1
- package/dist/Icons/EyeOpenIcon.js.map +1 -1
- package/dist/Icons/FileDownloadIcon.d.ts.map +1 -1
- package/dist/Icons/FileDownloadIcon.js.map +1 -1
- package/dist/Icons/GoToFirstIcon.d.ts.map +1 -1
- package/dist/Icons/GoToFirstIcon.js.map +1 -1
- package/dist/Icons/GoToLastIcon.d.ts.map +1 -1
- package/dist/Icons/GoToLastIcon.js.map +1 -1
- package/dist/Icons/HarmonicCursorsIcon.d.ts.map +1 -1
- package/dist/Icons/HarmonicCursorsIcon.js.map +1 -1
- package/dist/Icons/InfoIcon.d.ts.map +1 -1
- package/dist/Icons/InfoIcon.js.map +1 -1
- package/dist/Icons/KeyboardIcon.d.ts.map +1 -1
- package/dist/Icons/KeyboardIcon.js.map +1 -1
- package/dist/Icons/LabelIcon.d.ts.map +1 -1
- package/dist/Icons/LabelIcon.js.map +1 -1
- package/dist/Icons/LassoIcon.d.ts.map +1 -1
- package/dist/Icons/LassoIcon.js.map +1 -1
- package/dist/Icons/LineToolIcon.d.ts.map +1 -1
- package/dist/Icons/LineToolIcon.js.map +1 -1
- package/dist/Icons/LiveViewIcon.d.ts.map +1 -1
- package/dist/Icons/LiveViewIcon.js.map +1 -1
- package/dist/Icons/LoaderIcon.d.ts.map +1 -1
- package/dist/Icons/LoaderIcon.js.map +1 -1
- package/dist/Icons/LocationIcon.d.ts.map +1 -1
- package/dist/Icons/LocationIcon.js.map +1 -1
- package/dist/Icons/LogoutIcon.d.ts.map +1 -1
- package/dist/Icons/LogoutIcon.js.map +1 -1
- package/dist/Icons/MaximizeIcon.d.ts.map +1 -1
- package/dist/Icons/MaximizeIcon.js.map +1 -1
- package/dist/Icons/MeasureIcon.d.ts.map +1 -1
- package/dist/Icons/MeasureIcon.js.map +1 -1
- package/dist/Icons/MenuDotsIcon.d.ts.map +1 -1
- package/dist/Icons/MenuDotsIcon.js.map +1 -1
- package/dist/Icons/MenuIcon.d.ts.map +1 -1
- package/dist/Icons/MenuIcon.js.map +1 -1
- package/dist/Icons/MessagesIcon.d.ts.map +1 -1
- package/dist/Icons/MessagesIcon.js.map +1 -1
- package/dist/Icons/MetadataIcon.d.ts.map +1 -1
- package/dist/Icons/MetadataIcon.js.map +1 -1
- package/dist/Icons/MinimizeIcon.d.ts.map +1 -1
- package/dist/Icons/MinimizeIcon.js.map +1 -1
- package/dist/Icons/MinusIcon.d.ts.map +1 -1
- package/dist/Icons/MinusIcon.js.map +1 -1
- package/dist/Icons/OntologyIcon.d.ts.map +1 -1
- package/dist/Icons/OntologyIcon.js.map +1 -1
- package/dist/Icons/PanelIconClose.d.ts.map +1 -1
- package/dist/Icons/PanelIconClose.js.map +1 -1
- package/dist/Icons/PanelIconOpen.d.ts.map +1 -1
- package/dist/Icons/PanelIconOpen.js.map +1 -1
- package/dist/Icons/PauseIcon.d.ts.map +1 -1
- package/dist/Icons/PauseIcon.js.map +1 -1
- package/dist/Icons/PlayIcon.d.ts.map +1 -1
- package/dist/Icons/PlayIcon.js.map +1 -1
- package/dist/Icons/PlusIcon.d.ts.map +1 -1
- package/dist/Icons/PlusIcon.js.map +1 -1
- package/dist/Icons/PolygonIcon.d.ts.map +1 -1
- package/dist/Icons/PolygonIcon.js.map +1 -1
- package/dist/Icons/PrinterIcon.d.ts.map +1 -1
- package/dist/Icons/PrinterIcon.js.map +1 -1
- package/dist/Icons/ProgressCheckIcon.d.ts.map +1 -1
- package/dist/Icons/ProgressCheckIcon.js.map +1 -1
- package/dist/Icons/ResetIcon.d.ts.map +1 -1
- package/dist/Icons/ResetIcon.js.map +1 -1
- package/dist/Icons/ReviewedIcon.d.ts.map +1 -1
- package/dist/Icons/ReviewedIcon.js.map +1 -1
- package/dist/Icons/ScissorsIcon.d.ts.map +1 -1
- package/dist/Icons/ScissorsIcon.js.map +1 -1
- package/dist/Icons/SearchIcon.d.ts.map +1 -1
- package/dist/Icons/SearchIcon.js.map +1 -1
- package/dist/Icons/SettingsIcon.d.ts.map +1 -1
- package/dist/Icons/SettingsIcon.js.map +1 -1
- package/dist/Icons/SortAscendingIcon.d.ts.map +1 -1
- package/dist/Icons/SortAscendingIcon.js.map +1 -1
- package/dist/Icons/SortAtoZIcon.d.ts.map +1 -1
- package/dist/Icons/SortAtoZIcon.js.map +1 -1
- package/dist/Icons/SortDescendingIcon.d.ts.map +1 -1
- package/dist/Icons/SortDescendingIcon.js.map +1 -1
- package/dist/Icons/SortZtoAIcon.d.ts.map +1 -1
- package/dist/Icons/SortZtoAIcon.js.map +1 -1
- package/dist/Icons/SparklesIcon.d.ts.map +1 -1
- package/dist/Icons/SparklesIcon.js.map +1 -1
- package/dist/Icons/StackIcon.d.ts.map +1 -1
- package/dist/Icons/StackIcon.js.map +1 -1
- package/dist/Icons/StarIcon.d.ts.map +1 -1
- package/dist/Icons/StarIcon.js.map +1 -1
- package/dist/Icons/SyncIcon.d.ts.map +1 -1
- package/dist/Icons/SyncIcon.js.map +1 -1
- package/dist/Icons/SyncOffIcon.d.ts.map +1 -1
- package/dist/Icons/SyncOffIcon.js.map +1 -1
- package/dist/Icons/TrashIcon.d.ts.map +1 -1
- package/dist/Icons/TrashIcon.js.map +1 -1
- package/dist/Icons/UndoIcon.d.ts.map +1 -1
- package/dist/Icons/UndoIcon.js.map +1 -1
- package/dist/Icons/UploadIcon.d.ts.map +1 -1
- package/dist/Icons/UploadIcon.js.map +1 -1
- package/dist/Icons/User2Icon.d.ts.map +1 -1
- package/dist/Icons/User2Icon.js.map +1 -1
- package/dist/Icons/UserIcon.d.ts.map +1 -1
- package/dist/Icons/UserIcon.js.map +1 -1
- package/dist/Icons/WarningIcon.d.ts.map +1 -1
- package/dist/Icons/WarningIcon.js.map +1 -1
- package/dist/Icons/ZoomAllIcon.d.ts.map +1 -1
- package/dist/Icons/ZoomAllIcon.js.map +1 -1
- package/dist/Icons/ZoomXIcon.d.ts.map +1 -1
- package/dist/Icons/ZoomXIcon.js.map +1 -1
- package/dist/Icons/ZoomYIcon.d.ts.map +1 -1
- package/dist/Icons/ZoomYIcon.js.map +1 -1
- package/dist/IconsAnimated/PanelLeftCloseIcon.js.map +1 -1
- package/dist/IconsAnimated/PanelLeftOpenIcon.js.map +1 -1
- package/dist/Input.js +1 -1
- package/dist/Input.js.map +1 -1
- package/dist/InputNumeric.d.ts.map +1 -1
- package/dist/InputNumeric.js.map +1 -1
- package/dist/InputOTP.d.ts.map +1 -1
- package/dist/InputOTP.js.map +1 -1
- package/dist/Kbd.d.ts.map +1 -1
- package/dist/Kbd.js.map +1 -1
- package/dist/Label.js.map +1 -1
- package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
- package/dist/MultiSelect.js.map +1 -1
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Popover.js.map +1 -1
- package/dist/RadioButton.js +4 -1
- package/dist/RadioButton.js.map +1 -1
- package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts +1 -1
- package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts.map +1 -1
- package/dist/RadioButtonGroup/RadioButtonGroupBase.js +7 -2
- package/dist/RadioButtonGroup/RadioButtonGroupBase.js.map +1 -1
- package/dist/RadioButtonGroup.d.ts.map +1 -1
- package/dist/RadioButtonGroup.js.map +1 -1
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RadioGroup.js +1 -1
- package/dist/RadioGroup.js.map +1 -1
- package/dist/Select.js.map +1 -1
- package/dist/Skeleton.js.map +1 -1
- package/dist/Slider.js.map +1 -1
- package/dist/Switch/SwitchBase.d.ts.map +1 -1
- package/dist/Switch/SwitchBase.js.map +1 -1
- package/dist/Switch.js.map +1 -1
- package/dist/Tabs/TabsBase.d.ts.map +1 -1
- package/dist/Tabs/TabsBase.js.map +1 -1
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/Tabs.js.map +1 -1
- package/dist/Textarea.js.map +1 -1
- package/dist/Toast.d.ts.map +1 -1
- package/dist/Toast.js.map +1 -1
- package/dist/Toggle/ToggleBase.js.map +1 -1
- package/dist/Toggle.d.ts +1 -1
- package/dist/Toggle.d.ts.map +1 -1
- package/dist/Toggle.js +7 -2
- package/dist/Toggle.js.map +1 -1
- package/dist/ToggleGroup/ToggleGroupBase.d.ts.map +1 -1
- package/dist/ToggleGroup/ToggleGroupBase.js.map +1 -1
- package/dist/ToggleGroup/ToggleGroupItem.js +1 -1
- package/dist/ToggleGroup/ToggleGroupItem.js.map +1 -1
- package/dist/ToggleGroup/ToggleGroupSplitMenuItem.js +1 -1
- package/dist/ToggleGroup/ToggleGroupSplitMenuItem.js.map +1 -1
- package/dist/ToggleGroup.js +9 -1
- package/dist/ToggleGroup.js.map +1 -1
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip.js.map +1 -1
- package/dist/Tray.d.ts.map +1 -1
- package/dist/Tray.js +1 -1
- package/dist/Tray.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -2
- package/dist/styles/horizon/utilities.css +13 -8
- package/dist/styles/spectral.css +1 -1
- package/package.json +1 -1
|
@@ -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 , \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 , \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
|
|
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
|
|
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
|
|
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"}
|
package/dist/Dialog.d.ts.map
CHANGED
|
@@ -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,
|
|
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=
|
|
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:
|
|
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", {
|
package/dist/Dialog.js.map
CHANGED
|
@@ -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
|
|
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.js
CHANGED
|
@@ -46,11 +46,11 @@ const Drawer = ({ children, defaultOpen = false, description, direction = "right
|
|
|
46
46
|
}), /* @__PURE__ */ jsx(Drawer$1.Content, {
|
|
47
47
|
asChild: true,
|
|
48
48
|
"aria-label": !hasTitle && !hasDescription ? "Drawer" : void 0,
|
|
49
|
-
className: `z-10 flex flex-col overscroll-contain bg-drawer-bg
|
|
49
|
+
className: `z-10 flex flex-col overscroll-contain bg-drawer-bg focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent **:box-border ${className}`,
|
|
50
50
|
style,
|
|
51
51
|
"data-testid": "spectral-drawer-content",
|
|
52
52
|
children: /* @__PURE__ */ jsxs("div", {
|
|
53
|
-
className: "min-h-0 flex
|
|
53
|
+
className: "flex h-full min-h-0 flex-col",
|
|
54
54
|
children: [
|
|
55
55
|
/* @__PURE__ */ jsx(Drawer$1.Close, {}),
|
|
56
56
|
hasTitle && /* @__PURE__ */ jsx(Drawer$1.Title, {
|
|
@@ -64,7 +64,7 @@ const Drawer = ({ children, defaultOpen = false, description, direction = "right
|
|
|
64
64
|
children: description
|
|
65
65
|
}),
|
|
66
66
|
/* @__PURE__ */ jsx("div", {
|
|
67
|
-
className: "py-2 px-3 min-w-0 [&>*]:min-w-0 [&_*]:min-w-0 min-h-0
|
|
67
|
+
className: "py-2 px-3 min-w-0 [&>*]:min-w-0 [&_*]:min-w-0 flex-1 min-h-0 overflow-y-auto overflow-x-hidden overscroll-contain *:box-border",
|
|
68
68
|
"data-testid": "spectral-drawer-body",
|
|
69
69
|
children
|
|
70
70
|
})
|
package/dist/Drawer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer.js","names":["DrawerBase"],"sources":["../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import { SpectralProvider } from '@components/SpectralProvider/SpectralProvider'\nimport { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\nimport { Drawer as DrawerBase } from 'vaul'\n\nexport interface DrawerProps {\n children?: ReactNode\n defaultOpen?: boolean\n description?: string\n direction?: 'left' | 'right' | 'top' | 'bottom'\n dismissible?: boolean\n modal?: boolean\n onOpenChange?: (open: boolean) => void\n open?: boolean\n size?: string\n title?: string\n trigger: ReactNode\n}\n\nexport const Drawer = ({ children, defaultOpen = false, description, direction = 'right', dismissible = true, modal = true, onOpenChange, open, size = '380px', title, trigger }: DrawerProps) => {\n const baseStyles = 'font-sans! fixed'\n const hasTitle = typeof title === 'string' && title.trim().length > 0\n const hasDescription = typeof description === 'string' && description.trim().length > 0\n\n const directionStyles = {\n left: {\n className: cn(baseStyles, 'top-0 bottom-0 left-0 shadow-[20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n right: {\n className: cn(baseStyles, 'top-0 bottom-0 right-0 shadow-[-20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n top: {\n className: cn(baseStyles, 'top-0 left-0 right-0 shadow-[0_20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n bottom: {\n className: cn(baseStyles, 'bottom-0 left-0 right-0 shadow-[0_-20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n }\n\n const { className, style } = directionStyles[direction]\n\n return (\n <SpectralProvider>\n <DrawerBase.Root
|
|
1
|
+
{"version":3,"file":"Drawer.js","names":["DrawerBase"],"sources":["../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import { SpectralProvider } from '@components/SpectralProvider/SpectralProvider'\nimport { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\nimport { Drawer as DrawerBase } from 'vaul'\n\nexport interface DrawerProps {\n children?: ReactNode\n defaultOpen?: boolean\n description?: string\n direction?: 'left' | 'right' | 'top' | 'bottom'\n dismissible?: boolean\n modal?: boolean\n onOpenChange?: (open: boolean) => void\n open?: boolean\n size?: string\n title?: string\n trigger: ReactNode\n}\n\nexport const Drawer = ({ children, defaultOpen = false, description, direction = 'right', dismissible = true, modal = true, onOpenChange, open, size = '380px', title, trigger }: DrawerProps) => {\n const baseStyles = 'font-sans! fixed'\n const hasTitle = typeof title === 'string' && title.trim().length > 0\n const hasDescription = typeof description === 'string' && description.trim().length > 0\n\n const directionStyles = {\n left: {\n className: cn(baseStyles, 'top-0 bottom-0 left-0 shadow-[20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n right: {\n className: cn(baseStyles, 'top-0 bottom-0 right-0 shadow-[-20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n top: {\n className: cn(baseStyles, 'top-0 left-0 right-0 shadow-[0_20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n bottom: {\n className: cn(baseStyles, 'bottom-0 left-0 right-0 shadow-[0_-20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n }\n\n const { className, style } = directionStyles[direction]\n\n return (\n <SpectralProvider>\n <DrawerBase.Root data-testid='spectral-drawer' defaultOpen={defaultOpen} direction={direction} dismissible={dismissible} modal={modal} onOpenChange={onOpenChange} open={open}>\n <DrawerBase.Trigger asChild data-testid='spectral-drawer-trigger'>\n {trigger}\n </DrawerBase.Trigger>\n <DrawerBase.Portal>\n <DrawerBase.Overlay className='inset-0 fixed bg-transparent' data-testid='spectral-drawer-overlay' />\n <DrawerBase.Content asChild aria-label={!hasTitle && !hasDescription ? 'Drawer' : undefined} className={`z-10 flex flex-col overscroll-contain bg-drawer-bg focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent **:box-border ${className}`} style={style} data-testid='spectral-drawer-content'>\n <div className='flex h-full min-h-0 flex-col'>\n <DrawerBase.Close />\n {hasTitle && (\n <DrawerBase.Title className='px-3 pt-4 text-lg font-medium text-text-primary' data-testid='spectral-drawer-title'>\n {title}\n </DrawerBase.Title>\n )}\n {hasDescription && (\n <DrawerBase.Description className='mb-2 px-3 text-xs! text-text-secondary! uppercase' data-testid='spectral-drawer-description'>\n {description}\n </DrawerBase.Description>\n )}\n <div className='py-2 px-3 min-w-0 [&>*]:min-w-0 [&_*]:min-w-0 flex-1 min-h-0 overflow-y-auto overflow-x-hidden overscroll-contain *:box-border' data-testid='spectral-drawer-body'>\n {children}\n </div>\n </div>\n </DrawerBase.Content>\n </DrawerBase.Portal>\n </DrawerBase.Root>\n </SpectralProvider>\n )\n}\n"],"mappings":";;;;;;;;AAmBA,MAAa,UAAU,EAAE,UAAU,cAAc,OAAO,aAAa,YAAY,SAAS,cAAc,MAAM,QAAQ,MAAM,cAAc,MAAM,OAAO,SAAS,OAAO,cAA2B;CAChM,MAAM,aAAa;CACnB,MAAM,WAAW,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS;CACpE,MAAM,iBAAiB,OAAO,gBAAgB,YAAY,YAAY,MAAM,CAAC,SAAS;CAqBtF,MAAM,EAAE,WAAW,UAAU;EAlB3B,MAAM;GACJ,WAAW,GAAG,YAAY,mEAAmE;GAC7F,OAAO,EAAE,OAAO,MAAM;GACvB;EACD,OAAO;GACL,WAAW,GAAG,YAAY,qEAAqE;GAC/F,OAAO,EAAE,OAAO,MAAM;GACvB;EACD,KAAK;GACH,WAAW,GAAG,YAAY,kEAAkE;GAC5F,OAAO,EAAE,QAAQ,MAAM;GACxB;EACD,QAAQ;GACN,WAAW,GAAG,YAAY,sEAAsE;GAChG,OAAO,EAAE,QAAQ,MAAM;GACxB;EAGyC,CAAC;AAE7C,QACE,oBAAC,kBAAD,YACE,qBAACA,SAAW,MAAZ;EAAiB,eAAY;EAA+B;EAAwB;EAAwB;EAAoB;EAAqB;EAAoB;YAAzK,CACE,oBAACA,SAAW,SAAZ;GAAoB;GAAQ,eAAY;aACrC;GACkB,GACrB,qBAACA,SAAW,QAAZ,aACE,oBAACA,SAAW,SAAZ;GAAoB,WAAU;GAA+B,eAAY;GAA4B,GACrG,oBAACA,SAAW,SAAZ;GAAoB;GAAQ,cAAY,CAAC,YAAY,CAAC,iBAAiB,WAAW;GAAW,WAAW,8KAA8K;GAAoB;GAAO,eAAY;aAC3T,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAACA,SAAW,OAAZ,EAAoB;KACnB,YACC,oBAACA,SAAW,OAAZ;MAAkB,WAAU;MAAkD,eAAY;gBACvF;MACgB;KAEpB,kBACC,oBAACA,SAAW,aAAZ;MAAwB,WAAU;MAAoD,eAAY;gBAC/F;MACsB;KAE3B,oBAAC,OAAD;MAAK,WAAU;MAAiI,eAAY;MACzJ;MACG;KACF;;GACa,EACH,IACJ;KACD"}
|
package/dist/DropdownMenu.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenu.js","names":[],"sources":["../src/components/DropdownMenu/DropdownMenu.tsx"],"sourcesContent":["import { CheckmarkIcon } from '@components/Icons'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport { EmptyState, getDropdownWidthStyles, getDropdownSurfaceClasses, getOptionClasses, LoadingState, type DropdownWidth } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentPropsWithoutRef, type RefObject, type ReactNode } from 'react'\n\ntype Align = 'start' | 'center' | 'end'\ntype Side = 'top' | 'bottom' | 'left' | 'right'\ntype DropdownValue = string | string[]\n\ninterface BaseDropdownOption {\n disabled?: boolean\n label: string\n shortcut?: ReactNode\n value: string\n}\n\nexport interface DropdownMenuItemOption extends BaseDropdownOption {\n type?: 'item'\n}\n\nexport interface DropdownMenuCheckboxOption extends BaseDropdownOption {\n type: 'checkbox'\n}\n\nexport interface DropdownMenuLabelOption {\n id?: string\n label: string\n type: 'label'\n}\n\nexport interface DropdownMenuSeparatorOption {\n id?: string\n type: 'separator'\n}\n\nexport type DropdownMenuOption = DropdownMenuItemOption | DropdownMenuCheckboxOption | DropdownMenuLabelOption | DropdownMenuSeparatorOption\n\nexport interface DropdownMenuProps extends Omit<ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>, 'defaultOpen' | 'onOpenChange' | 'open'> {\n align?: Align\n asChild?: boolean\n alignOffset?: number\n avoidCollisions?: boolean\n collisionBoundary?: Element | Element[] | null\n collisionPadding?: number | Partial<Record<Side, number>>\n className?: string\n contentClassName?: string\n dataTestId?: string\n defaultOpen?: boolean\n defaultValue?: DropdownValue\n disabled?: boolean\n dropdownContentRef?: RefObject<HTMLDivElement | null>\n dropdownWidth?: DropdownWidth\n emptyMessage?: ReactNode\n loadingMessage?: string\n onOpenChange?: (open: boolean) => void\n onValueChange?: (value: DropdownValue) => void\n open?: boolean\n options: DropdownMenuOption[]\n selectionMode?: 'single' | 'multiple'\n side?: Side\n sideOffset?: number\n state?: 'default' | 'loading'\n trigger: ReactNode\n value?: DropdownValue\n}\n\nconst normalizeValue = (value: DropdownValue | undefined, selectionMode: 'single' | 'multiple') => {\n if (selectionMode === 'multiple') {\n if (Array.isArray(value)) return value\n return value ? [value] : []\n }\n\n if (Array.isArray(value)) {\n return value[0] ?? ''\n }\n\n return value ?? ''\n}\n\nconst isSelectableOption = (option: DropdownMenuOption): option is DropdownMenuItemOption | DropdownMenuCheckboxOption => {\n return option.type !== 'separator' && option.type !== 'label'\n}\n\nexport const DropdownMenu = ({\n align = 'start',\n asChild = true,\n alignOffset = 0,\n avoidCollisions = true,\n className,\n collisionBoundary,\n collisionPadding = 10,\n contentClassName,\n dataTestId,\n defaultOpen,\n defaultValue,\n disabled = false,\n dropdownContentRef,\n dropdownWidth = 'content',\n emptyMessage = 'No options found',\n loadingMessage = 'Loading…',\n modal = true,\n onOpenChange,\n onValueChange,\n open: openProp,\n options,\n selectionMode = 'single',\n side = 'bottom',\n sideOffset = 4,\n state = 'default',\n trigger,\n value: valueProp,\n}: DropdownMenuProps) => {\n const [open, setOpen] = useUncontrolledState<boolean>({\n value: openProp,\n defaultValue: defaultOpen ?? false,\n onChange: onOpenChange,\n })\n\n const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(open)\n\n const resolvedDefaultValue = normalizeValue(defaultValue, selectionMode)\n const resolvedControlledValue = valueProp === undefined ? undefined : normalizeValue(valueProp, selectionMode)\n const [value, setValue] = useUncontrolledState<DropdownValue>({\n value: resolvedControlledValue,\n defaultValue: resolvedDefaultValue,\n onChange: onValueChange,\n })\n\n const { dropdownWidthMode, dropdownWidthStyle } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--radix-dropdown-menu-trigger-width)',\n })\n\n const isDisabled = disabled || state === 'loading'\n const selectableOptions = options.filter(isSelectableOption)\n\n const isOptionSelected = (optionValue: string) => {\n if (selectionMode === 'multiple') {\n const values = Array.isArray(value) ? value : []\n return values.includes(optionValue)\n }\n\n return value === optionValue\n }\n\n const handleValueChange = (nextValue: string) => {\n if (selectionMode === 'multiple') {\n const values = Array.isArray(value) ? value : []\n const nextValues = values.includes(nextValue) ? values.filter((entry) => entry !== nextValue) : [...values, nextValue]\n setValue(nextValues)\n return\n }\n\n setValue(nextValue)\n setOpen(false)\n }\n\n const renderOption = (option: DropdownMenuOption, index: number) => {\n if (option.type === 'separator') {\n return (\n <DropdownMenuPrimitive.Separator\n className='-mx-1 my-1 h-px bg-border-secondary'\n data-testid='spectral-dropdown-menu-separator'\n key={option.id ?? `separator-${index}`}\n />\n )\n }\n\n if (option.type === 'label') {\n return (\n <DropdownMenuPrimitive.Label\n className='px-2 py-1.5 text-base font-semibold text-text-primary'\n data-testid='spectral-dropdown-menu-label'\n key={option.id ?? `label-${index}`}\n >\n {option.label}\n </DropdownMenuPrimitive.Label>\n )\n }\n\n const isSelected = isOptionSelected(option.value)\n const itemClassName = cn(getOptionClasses(Boolean(option.disabled), false, isSelected), 'group/spectral-dropdown-menu-item pr-2 gap-4 relative flex w-full justify-between')\n\n if (selectionMode === 'multiple' || option.type === 'checkbox') {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n checked={isSelected}\n className={itemClassName}\n data-testid='spectral-dropdown-menu-checkbox-item'\n disabled={option.disabled}\n key={option.value}\n onCheckedChange={() => handleValueChange(option.value)}\n onSelect={(event) => event.preventDefault()}\n >\n <span className='min-w-0 flex-1 truncate whitespace-nowrap'>{option.label}</span>\n {option.shortcut && <span className='text-xs tracking-widest ml-auto text-input-text-placeholder'>{option.shortcut}</span>}\n <span\n aria-hidden='true'\n className='ml-2 size-4 flex shrink-0 items-center justify-center'\n >\n <DropdownMenuPrimitive.ItemIndicator asChild>\n <span className='size-4 flex items-center justify-center'>\n <CheckmarkIcon size={16} />\n </span>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n </DropdownMenuPrimitive.CheckboxItem>\n )\n }\n\n return (\n <DropdownMenuPrimitive.Item\n className={itemClassName}\n data-testid='spectral-dropdown-menu-item'\n disabled={option.disabled}\n key={option.value}\n onSelect={() => handleValueChange(option.value)}\n >\n <span className='min-w-0 flex-1 truncate whitespace-nowrap'>{option.label}</span>\n {option.shortcut && <span className='text-xs tracking-widest ml-auto text-input-text-placeholder'>{option.shortcut}</span>}\n <span\n aria-hidden='true'\n className='ml-2 size-4 flex shrink-0 items-center justify-center'\n >\n {isSelected && <CheckmarkIcon size={16} />}\n </span>\n </DropdownMenuPrimitive.Item>\n )\n }\n\n return (\n <DropdownMenuPrimitive.Root\n modal={modal}\n onOpenChange={setOpen}\n open={open}\n >\n <DropdownMenuPrimitive.Trigger\n asChild={asChild}\n className={cn(className, 'transition-opacity duration-200 hover:cursor-pointer hover:opacity-80')}\n data-testid={dataTestId ?? 'spectral-dropdown-menu-trigger'}\n disabled={isDisabled}\n >\n {trigger}\n </DropdownMenuPrimitive.Trigger>\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n align={align}\n alignOffset={alignOffset}\n avoidCollisions={avoidCollisions}\n className={cn(\n 'p-1 relative z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=open]:zoom-in-95',\n 'max-h-[min(var(--radix-dropdown-menu-content-available-height),300px)] motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2',\n 'min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto',\n contentClassName,\n )}\n collisionBoundary={collisionBoundary}\n collisionPadding={collisionPadding}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-dropdown-menu-content'\n ref={(node) => {\n setDropdownElement(node)\n if (dropdownContentRef) {\n dropdownContentRef.current = node\n }\n }}\n side={side}\n sideOffset={sideOffset}\n style={{\n ...dropdownWidthStyle,\n ...dropdownShiftStyle,\n }}\n >\n {state === 'loading' ? <LoadingState message={loadingMessage} /> : selectableOptions.length === 0 ? <EmptyState message={emptyMessage} /> : options.map(renderOption)}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n )\n}\n\nDropdownMenu.displayName = 'DropdownMenu'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DropdownMenu.js","names":[],"sources":["../src/components/DropdownMenu/DropdownMenu.tsx"],"sourcesContent":["import { CheckmarkIcon } from '@components/Icons'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport { EmptyState, getDropdownWidthStyles, getDropdownSurfaceClasses, getOptionClasses, LoadingState, type DropdownWidth } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentPropsWithoutRef, type RefObject, type ReactNode } from 'react'\n\ntype Align = 'start' | 'center' | 'end'\ntype Side = 'top' | 'bottom' | 'left' | 'right'\ntype DropdownValue = string | string[]\n\ninterface BaseDropdownOption {\n disabled?: boolean\n label: string\n shortcut?: ReactNode\n value: string\n}\n\nexport interface DropdownMenuItemOption extends BaseDropdownOption {\n type?: 'item'\n}\n\nexport interface DropdownMenuCheckboxOption extends BaseDropdownOption {\n type: 'checkbox'\n}\n\nexport interface DropdownMenuLabelOption {\n id?: string\n label: string\n type: 'label'\n}\n\nexport interface DropdownMenuSeparatorOption {\n id?: string\n type: 'separator'\n}\n\nexport type DropdownMenuOption = DropdownMenuItemOption | DropdownMenuCheckboxOption | DropdownMenuLabelOption | DropdownMenuSeparatorOption\n\nexport interface DropdownMenuProps extends Omit<ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>, 'defaultOpen' | 'onOpenChange' | 'open'> {\n align?: Align\n asChild?: boolean\n alignOffset?: number\n avoidCollisions?: boolean\n collisionBoundary?: Element | Element[] | null\n collisionPadding?: number | Partial<Record<Side, number>>\n className?: string\n contentClassName?: string\n dataTestId?: string\n defaultOpen?: boolean\n defaultValue?: DropdownValue\n disabled?: boolean\n dropdownContentRef?: RefObject<HTMLDivElement | null>\n dropdownWidth?: DropdownWidth\n emptyMessage?: ReactNode\n loadingMessage?: string\n onOpenChange?: (open: boolean) => void\n onValueChange?: (value: DropdownValue) => void\n open?: boolean\n options: DropdownMenuOption[]\n selectionMode?: 'single' | 'multiple'\n side?: Side\n sideOffset?: number\n state?: 'default' | 'loading'\n trigger: ReactNode\n value?: DropdownValue\n}\n\nconst normalizeValue = (value: DropdownValue | undefined, selectionMode: 'single' | 'multiple') => {\n if (selectionMode === 'multiple') {\n if (Array.isArray(value)) return value\n return value ? [value] : []\n }\n\n if (Array.isArray(value)) {\n return value[0] ?? ''\n }\n\n return value ?? ''\n}\n\nconst isSelectableOption = (option: DropdownMenuOption): option is DropdownMenuItemOption | DropdownMenuCheckboxOption => {\n return option.type !== 'separator' && option.type !== 'label'\n}\n\nexport const DropdownMenu = ({\n align = 'start',\n asChild = true,\n alignOffset = 0,\n avoidCollisions = true,\n className,\n collisionBoundary,\n collisionPadding = 10,\n contentClassName,\n dataTestId,\n defaultOpen,\n defaultValue,\n disabled = false,\n dropdownContentRef,\n dropdownWidth = 'content',\n emptyMessage = 'No options found',\n loadingMessage = 'Loading…',\n modal = true,\n onOpenChange,\n onValueChange,\n open: openProp,\n options,\n selectionMode = 'single',\n side = 'bottom',\n sideOffset = 4,\n state = 'default',\n trigger,\n value: valueProp,\n}: DropdownMenuProps) => {\n const [open, setOpen] = useUncontrolledState<boolean>({\n value: openProp,\n defaultValue: defaultOpen ?? false,\n onChange: onOpenChange,\n })\n\n const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(open)\n\n const resolvedDefaultValue = normalizeValue(defaultValue, selectionMode)\n const resolvedControlledValue = valueProp === undefined ? undefined : normalizeValue(valueProp, selectionMode)\n const [value, setValue] = useUncontrolledState<DropdownValue>({\n value: resolvedControlledValue,\n defaultValue: resolvedDefaultValue,\n onChange: onValueChange,\n })\n\n const { dropdownWidthMode, dropdownWidthStyle } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--radix-dropdown-menu-trigger-width)',\n })\n\n const isDisabled = disabled || state === 'loading'\n const selectableOptions = options.filter(isSelectableOption)\n\n const isOptionSelected = (optionValue: string) => {\n if (selectionMode === 'multiple') {\n const values = Array.isArray(value) ? value : []\n return values.includes(optionValue)\n }\n\n return value === optionValue\n }\n\n const handleValueChange = (nextValue: string) => {\n if (selectionMode === 'multiple') {\n const values = Array.isArray(value) ? value : []\n const nextValues = values.includes(nextValue) ? values.filter((entry) => entry !== nextValue) : [...values, nextValue]\n setValue(nextValues)\n return\n }\n\n setValue(nextValue)\n setOpen(false)\n }\n\n const renderOption = (option: DropdownMenuOption, index: number) => {\n if (option.type === 'separator') {\n return <DropdownMenuPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-dropdown-menu-separator' key={option.id ?? `separator-${index}`} />\n }\n\n if (option.type === 'label') {\n return (\n <DropdownMenuPrimitive.Label className='px-2 py-1.5 text-base font-semibold text-text-primary' data-testid='spectral-dropdown-menu-label' key={option.id ?? `label-${index}`}>\n {option.label}\n </DropdownMenuPrimitive.Label>\n )\n }\n\n const isSelected = isOptionSelected(option.value)\n const itemClassName = cn(getOptionClasses(Boolean(option.disabled), false, isSelected), 'group/spectral-dropdown-menu-item pr-2 gap-4 relative flex w-full justify-between')\n\n if (selectionMode === 'multiple' || option.type === 'checkbox') {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n checked={isSelected}\n className={itemClassName}\n data-testid='spectral-dropdown-menu-checkbox-item'\n disabled={option.disabled}\n key={option.value}\n onCheckedChange={() => handleValueChange(option.value)}\n onSelect={(event) => event.preventDefault()}\n >\n <span className='min-w-0 flex-1 truncate whitespace-nowrap'>{option.label}</span>\n {option.shortcut && <span className='text-xs tracking-widest ml-auto text-input-text-placeholder'>{option.shortcut}</span>}\n <span aria-hidden='true' className='ml-2 size-4 flex shrink-0 items-center justify-center'>\n <DropdownMenuPrimitive.ItemIndicator asChild>\n <span className='size-4 flex items-center justify-center'>\n <CheckmarkIcon size={16} />\n </span>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n </DropdownMenuPrimitive.CheckboxItem>\n )\n }\n\n return (\n <DropdownMenuPrimitive.Item className={itemClassName} data-testid='spectral-dropdown-menu-item' disabled={option.disabled} key={option.value} onSelect={() => handleValueChange(option.value)}>\n <span className='min-w-0 flex-1 truncate whitespace-nowrap'>{option.label}</span>\n {option.shortcut && <span className='text-xs tracking-widest ml-auto text-input-text-placeholder'>{option.shortcut}</span>}\n <span aria-hidden='true' className='ml-2 size-4 flex shrink-0 items-center justify-center'>\n {isSelected && <CheckmarkIcon size={16} />}\n </span>\n </DropdownMenuPrimitive.Item>\n )\n }\n\n return (\n <DropdownMenuPrimitive.Root modal={modal} onOpenChange={setOpen} open={open}>\n <DropdownMenuPrimitive.Trigger asChild={asChild} className={cn(className, 'transition-opacity duration-200 hover:cursor-pointer hover:opacity-80')} data-testid={dataTestId ?? 'spectral-dropdown-menu-trigger'} disabled={isDisabled}>\n {trigger}\n </DropdownMenuPrimitive.Trigger>\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n align={align}\n alignOffset={alignOffset}\n avoidCollisions={avoidCollisions}\n className={cn(\n 'p-1 relative z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=open]:zoom-in-95',\n 'max-h-[min(var(--radix-dropdown-menu-content-available-height),300px)] motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2',\n 'min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto',\n contentClassName,\n )}\n collisionBoundary={collisionBoundary}\n collisionPadding={collisionPadding}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-dropdown-menu-content'\n ref={(node) => {\n setDropdownElement(node)\n if (dropdownContentRef) {\n dropdownContentRef.current = node\n }\n }}\n side={side}\n sideOffset={sideOffset}\n style={{\n ...dropdownWidthStyle,\n ...dropdownShiftStyle,\n }}\n >\n {state === 'loading' ? <LoadingState message={loadingMessage} /> : selectableOptions.length === 0 ? <EmptyState message={emptyMessage} /> : options.map(renderOption)}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n )\n}\n\nDropdownMenu.displayName = 'DropdownMenu'\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormFieldMessage.d.ts","names":[],"sources":["../src/components/FormFieldMessage/FormFieldMessage.tsx"],"mappings":";;;;KAGY,qBAAA,uBAA4C,MAAA;AAAA,UAE9C,qBAAA;EACR,SAAA;EACA,kBAAA;EACA,UAAA;EACA,EAAA;EACA,OAAA,EAAS,qBAAA;EACT,mBAAA;EACA,mBAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"FormFieldMessage.d.ts","names":[],"sources":["../src/components/FormFieldMessage/FormFieldMessage.tsx"],"mappings":";;;;KAGY,qBAAA,uBAA4C,MAAA;AAAA,UAE9C,qBAAA;EACR,SAAA;EACA,kBAAA;EACA,UAAA;EACA,EAAA;EACA,OAAA,EAAS,qBAAA;EACT,mBAAA;EACA,mBAAA;AAAA;AAAA,cA6EW,YAAA;EAAY,SAAA;EAAA,kBAAA;EAAA,UAAA;EAAA,EAAA;EAAA,OAAA;EAAA,mBAAA;EAAA;AAAA,GAAgJ,qBAAA,KAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAiBjL,cAAA;EAAc,SAAA;EAAA,kBAAA;EAAA,UAAA;EAAA,EAAA;EAAA,OAAA;EAAA,mBAAA;EAAA;AAAA,GAAkJ,qBAAA,KAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormFieldMessage.js","names":[],"sources":["../src/components/FormFieldMessage/FormFieldMessage.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\n\nexport type FormFieldMessageValue = string | string[] | Record<string, unknown> | null | undefined\n\ninterface BaseFieldMessageProps {\n className?: string\n containerClassName?: string\n dataTestId?: string\n id: string\n message: FormFieldMessageValue\n messageReserveLines?: number\n messageReserveSpace?: boolean\n}\n\nconst renderFieldMessageContent = (message: FormFieldMessageValue): ReactNode => {\n if (!message) return null\n\n if (typeof message === 'string') {\n return message\n }\n\n if (Array.isArray(message)) {\n return message.join(', ')\n }\n\n if (typeof message === 'object') {\n if ('message' in message && typeof message.message === 'string') return message.message\n if ('error' in message && typeof message.error === 'string') return message.error\n if ('details' in message && typeof message.details === 'string') return message.details\n try {\n return JSON.stringify(message)\n } catch {\n return '[Circular]'\n }\n }\n\n return String(message)\n}\n\nconst FormFieldMessage = ({\n ariaLive,\n className,\n containerClassName,\n dataTestId,\n id,\n message,\n messageReserveLines = 1,\n messageReserveSpace = false,\n role,\n tone,\n}: BaseFieldMessageProps & {\n ariaLive: 'assertive' | 'polite'\n role: 'alert' | 'status'\n tone: 'danger' | 'warning'\n}) => {\n const content = renderFieldMessageContent(message)\n const isVisible = Boolean(content)\n const reservedHeight
|
|
1
|
+
{"version":3,"file":"FormFieldMessage.js","names":[],"sources":["../src/components/FormFieldMessage/FormFieldMessage.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\n\nexport type FormFieldMessageValue = string | string[] | Record<string, unknown> | null | undefined\n\ninterface BaseFieldMessageProps {\n className?: string\n containerClassName?: string\n dataTestId?: string\n id: string\n message: FormFieldMessageValue\n messageReserveLines?: number\n messageReserveSpace?: boolean\n}\n\nconst renderFieldMessageContent = (message: FormFieldMessageValue): ReactNode => {\n if (!message) return null\n\n if (typeof message === 'string') {\n return message\n }\n\n if (Array.isArray(message)) {\n return message.join(', ')\n }\n\n if (typeof message === 'object') {\n if ('message' in message && typeof message.message === 'string') return message.message\n if ('error' in message && typeof message.error === 'string') return message.error\n if ('details' in message && typeof message.details === 'string') return message.details\n try {\n return JSON.stringify(message)\n } catch {\n return '[Circular]'\n }\n }\n\n return String(message)\n}\n\nconst FormFieldMessage = ({\n ariaLive,\n className,\n containerClassName,\n dataTestId,\n id,\n message,\n messageReserveLines = 1,\n messageReserveSpace = false,\n role,\n tone,\n}: BaseFieldMessageProps & {\n ariaLive: 'assertive' | 'polite'\n role: 'alert' | 'status'\n tone: 'danger' | 'warning'\n}) => {\n const content = renderFieldMessageContent(message)\n const isVisible = Boolean(content)\n const reservedHeight =\n messageReserveSpace && messageReserveLines > 0\n ? `${Math.max(messageReserveLines, 1) * 1.25 + 0.25}rem`\n : undefined\n const toneClasses = tone === 'danger' ? 'text-danger-400!' : 'text-warning-400!'\n\n return (\n <div\n aria-hidden={!isVisible}\n className={cn(\n 'transition-[opacity,transform] duration-150 ease-out motion-reduce:transition-none',\n messageReserveSpace ? 'pt-1' : 'pt-0',\n isVisible ? 'translate-y-0 opacity-100' : '-translate-y-0.5 opacity-0',\n containerClassName,\n )}\n style={reservedHeight ? { minHeight: reservedHeight } : undefined}\n >\n <p\n aria-atomic={isVisible ? 'true' : undefined}\n aria-live={isVisible ? ariaLive : undefined}\n className={cn('m-0! text-sm leading-5 overflow-hidden', toneClasses, className)}\n data-testid={isVisible ? dataTestId : undefined}\n id={id}\n role={isVisible ? role : undefined}\n >\n {content}\n </p>\n </div>\n )\n}\n\nexport const ErrorMessage = ({ className, containerClassName, dataTestId = 'spectral-form-field-error-message', id, message, messageReserveLines, messageReserveSpace }: BaseFieldMessageProps) => {\n return (\n <FormFieldMessage\n ariaLive='polite'\n className={className}\n containerClassName={containerClassName}\n dataTestId={dataTestId}\n id={id}\n message={message}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n role='status'\n tone='danger'\n />\n )\n}\n\nexport const WarningMessage = ({ className, containerClassName, dataTestId = 'spectral-form-field-warning-message', id, message, messageReserveLines, messageReserveSpace }: BaseFieldMessageProps) => {\n return (\n <FormFieldMessage\n ariaLive='polite'\n className={className}\n containerClassName={containerClassName}\n dataTestId={dataTestId}\n id={id}\n message={message}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n role='status'\n tone='warning'\n />\n )\n}\n"],"mappings":";;;;;;AAeA,MAAM,6BAA6B,YAA8C;AAC/E,KAAI,CAAC,QAAS,QAAO;AAErB,KAAI,OAAO,YAAY,SACrB,QAAO;AAGT,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO,QAAQ,KAAK,KAAK;AAG3B,KAAI,OAAO,YAAY,UAAU;AAC/B,MAAI,aAAa,WAAW,OAAO,QAAQ,YAAY,SAAU,QAAO,QAAQ;AAChF,MAAI,WAAW,WAAW,OAAO,QAAQ,UAAU,SAAU,QAAO,QAAQ;AAC5E,MAAI,aAAa,WAAW,OAAO,QAAQ,YAAY,SAAU,QAAO,QAAQ;AAChF,MAAI;AACF,UAAO,KAAK,UAAU,QAAQ;UACxB;AACN,UAAO;;;AAIX,QAAO,OAAO,QAAQ;;AAGxB,MAAM,oBAAoB,EACxB,UACA,WACA,oBACA,YACA,IACA,SACA,sBAAsB,GACtB,sBAAsB,OACtB,MACA,WAKI;CACJ,MAAM,UAAU,0BAA0B,QAAQ;CAClD,MAAM,YAAY,QAAQ,QAAQ;CAClC,MAAM,iBACJ,uBAAuB,sBAAsB,IACzC,GAAG,KAAK,IAAI,qBAAqB,EAAE,GAAG,OAAO,IAAK,OAClD;CACN,MAAM,cAAc,SAAS,WAAW,qBAAqB;AAE7D,QACE,oBAAC,OAAD;EACE,eAAa,CAAC;EACd,WAAW,GACT,sFACA,sBAAsB,SAAS,QAC/B,YAAY,8BAA8B,8BAC1C,mBACD;EACD,OAAO,iBAAiB,EAAE,WAAW,gBAAgB,GAAG;YAExD,oBAAC,KAAD;GACE,eAAa,YAAY,SAAS;GAClC,aAAW,YAAY,WAAW;GAClC,WAAW,GAAG,0CAA0C,aAAa,UAAU;GAC/E,eAAa,YAAY,aAAa;GAClC;GACJ,MAAM,YAAY,OAAO;aAExB;GACC;EACA;;AAIV,MAAa,gBAAgB,EAAE,WAAW,oBAAoB,aAAa,qCAAqC,IAAI,SAAS,qBAAqB,0BAAiD;AACjM,QACE,oBAAC,kBAAD;EACE,UAAS;EACE;EACS;EACR;EACR;EACK;EACY;EACA;EACrB,MAAK;EACL,MAAK;EACL;;AAIN,MAAa,kBAAkB,EAAE,WAAW,oBAAoB,aAAa,uCAAuC,IAAI,SAAS,qBAAqB,0BAAiD;AACrM,QACE,oBAAC,kBAAD;EACE,UAAS;EACE;EACS;EACR;EACR;EACK;EACY;EACA;EACrB,MAAK;EACL,MAAK;EACL"}
|
package/dist/HoverCard.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverCard.d.ts","names":[],"sources":["../src/components/HoverCard/HoverCard.tsx"],"mappings":";;;;;;KAIK,KAAA;AAAA,KACA,IAAA;AAAA,UAEK,qBAAA;EACR,KAAA,GAAQ,KAAA;EACR,WAAA;EACA,iBAAA,GAAoB,OAAA,WAAkB,OAAA;EACtC,gBAAA,YAA4B,OAAA,CAAQ,MAAA,CAAO,IAAA;EAC3C,IAAA,GAAO,IAAA;EACP,UAAA;EACA,KAAA;AAAA;AAAA,UAKe,cAAA,SAAuB,cAAA,QAAsB,kBAAA,CAAmB,IAAA,GAAO,qBAAA;AAAA;EAE5D,KAAA;EAAO,WAAA;EAAa,iBAAA;EAAmB,gBAAA;EAAkB,IAAA;EAAM,UAAA;EAAY,KAAA;EAAA,GAAU;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;
|
|
1
|
+
{"version":3,"file":"HoverCard.d.ts","names":[],"sources":["../src/components/HoverCard/HoverCard.tsx"],"mappings":";;;;;;KAIK,KAAA;AAAA,KACA,IAAA;AAAA,UAEK,qBAAA;EACR,KAAA,GAAQ,KAAA;EACR,WAAA;EACA,iBAAA,GAAoB,OAAA,WAAkB,OAAA;EACtC,gBAAA,YAA4B,OAAA,CAAQ,MAAA,CAAO,IAAA;EAC3C,IAAA,GAAO,IAAA;EACP,UAAA;EACA,KAAA;AAAA;AAAA,UAKe,cAAA,SAAuB,cAAA,QAAsB,kBAAA,CAAmB,IAAA,GAAO,qBAAA;AAAA;EAE5D,KAAA;EAAO,WAAA;EAAa,iBAAA;EAAmB,gBAAA;EAAkB,IAAA;EAAM,UAAA;EAAY,KAAA;EAAA,GAAU;AAAA,GAAS,cAAA,GAAc,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;EASrG,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,QAAsB,kBAAA,CAAmB,OAAA,IAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;EAMzG,KAAA,EAAO,SAAA;EACP,WAAA,EAAa,eAAA;EACb,SAAA;EACA,iBAAA,EAAmB,qBAAA;EACnB,gBAAA,EAAkB,oBAAA;EAClB,IAAA,EAAM,QAAA;EACN,UAAA,EAAY,cAAA;EACZ,KAAA,EAAO,SAAA;EAAA,GACJ;AAAA,GACF,cAAA,QAAsB,kBAAA,CAAmB,OAAA;EAC1C,KAAA;AAAA,IACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
|
package/dist/HoverCard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverCard.js","names":[],"sources":["../src/components/HoverCard/HoverCard.tsx"],"sourcesContent":["import * as HoverCardPrimitive from '@radix-ui/react-hover-card'\nimport { cn } from '@utils/twUtils'\nimport { createContext, useContext, type ComponentProps, type CSSProperties } from 'react'\n\ntype Align = 'start' | 'center' | 'end'\ntype Side = 'top' | 'right' | 'bottom' | 'left'\n\ninterface HoverCardContentProps {\n align?: Align\n alignOffset?: number\n collisionBoundary?: Element | null | (Element | null)[]\n collisionPadding?: number | Partial<Record<Side, number>>\n side?: Side\n sideOffset?: number\n width?: number | 'w-fit' | 'trigger-width'\n}\n\nconst HoverCardContext = createContext<HoverCardContentProps>({})\n\nexport interface HoverCardProps extends ComponentProps<typeof HoverCardPrimitive.Root>, HoverCardContentProps {}\n\nexport const HoverCard = ({ align, alignOffset, collisionBoundary, collisionPadding, side, sideOffset, width, ...props }: HoverCardProps) => {\n return (\n <HoverCardContext.Provider value={{ side, sideOffset, align, alignOffset, collisionBoundary, collisionPadding, width }}>\n <HoverCardPrimitive.Root
|
|
1
|
+
{"version":3,"file":"HoverCard.js","names":[],"sources":["../src/components/HoverCard/HoverCard.tsx"],"sourcesContent":["import * as HoverCardPrimitive from '@radix-ui/react-hover-card'\nimport { cn } from '@utils/twUtils'\nimport { createContext, useContext, type ComponentProps, type CSSProperties } from 'react'\n\ntype Align = 'start' | 'center' | 'end'\ntype Side = 'top' | 'right' | 'bottom' | 'left'\n\ninterface HoverCardContentProps {\n align?: Align\n alignOffset?: number\n collisionBoundary?: Element | null | (Element | null)[]\n collisionPadding?: number | Partial<Record<Side, number>>\n side?: Side\n sideOffset?: number\n width?: number | 'w-fit' | 'trigger-width'\n}\n\nconst HoverCardContext = createContext<HoverCardContentProps>({})\n\nexport interface HoverCardProps extends ComponentProps<typeof HoverCardPrimitive.Root>, HoverCardContentProps {}\n\nexport const HoverCard = ({ align, alignOffset, collisionBoundary, collisionPadding, side, sideOffset, width, ...props }: HoverCardProps) => {\n return (\n <HoverCardContext.Provider value={{ side, sideOffset, align, alignOffset, collisionBoundary, collisionPadding, width }}>\n <HoverCardPrimitive.Root data-slot='hover-card' data-testid='spectral-hover-card' {...props} />\n </HoverCardContext.Provider>\n )\n}\nHoverCard.displayName = 'HoverCard'\n\nexport const HoverCardTrigger = ({ className, ...props }: ComponentProps<typeof HoverCardPrimitive.Trigger>) => {\n return <HoverCardPrimitive.Trigger className={cn('font-base', className)} data-slot='hover-card-trigger' data-testid='spectral-hover-card-trigger' {...props} />\n}\nHoverCardTrigger.displayName = 'HoverCardTrigger'\n\nexport const HoverCardContent = ({\n align: alignProp,\n alignOffset: alignOffsetProp,\n className,\n collisionBoundary: collisionBoundaryProp,\n collisionPadding: collisionPaddingProp,\n side: sideProp,\n sideOffset: sideOffsetProp,\n width: widthProp,\n ...props\n}: ComponentProps<typeof HoverCardPrimitive.Content> & {\n width?: number | 'w-fit' | 'trigger-width'\n}) => {\n const context = useContext(HoverCardContext)\n\n const align = alignProp ?? context.align ?? 'center'\n const sideOffset = sideOffsetProp ?? context.sideOffset ?? 4\n const side = sideProp ?? context.side ?? 'bottom'\n const width = widthProp ?? context.width ?? 380\n const alignOffset = alignOffsetProp ?? context.alignOffset\n const collisionBoundary = collisionBoundaryProp ?? context.collisionBoundary\n const collisionPadding = collisionPaddingProp ?? context.collisionPadding\n\n return (\n <HoverCardPrimitive.Portal data-slot='hover-card-portal'>\n <HoverCardPrimitive.Content\n align={align}\n alignOffset={alignOffset}\n className={cn(\n 'rounded-lg shadow-lg p-5 z-50 origin-[--radix-hover-card-content-transform-origin] bg-popover-bg text-text-primary outline-none motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=left]:slide-in-from-right-2 motion-safe:data-[side=right]:slide-in-from-left-2 motion-safe:data-[side=top]:slide-in-from-bottom-2 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=open]:zoom-in-95',\n className,\n )}\n collisionBoundary={collisionBoundary}\n collisionPadding={collisionPadding}\n data-slot='hover-card-content'\n data-testid='spectral-hover-card-content'\n side={side}\n sideOffset={sideOffset}\n style={\n {\n width: typeof width === 'number' ? `${width}px` : width === 'trigger-width' ? 'var(--radix-hover-card-trigger-width)' : 'fit-content',\n } as CSSProperties\n }\n {...props}\n />\n </HoverCardPrimitive.Portal>\n )\n}\nHoverCardContent.displayName = 'HoverCardContent'\n"],"mappings":";;;;;;;AAiBA,MAAM,mBAAmB,cAAqC,EAAE,CAAC;AAIjE,MAAa,aAAa,EAAE,OAAO,aAAa,mBAAmB,kBAAkB,MAAM,YAAY,OAAO,GAAG,YAA4B;AAC3I,QACE,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO;GAAE;GAAM;GAAY;GAAO;GAAa;GAAmB;GAAkB;GAAO;YACpH,oBAAC,mBAAmB,MAApB;GAAyB,aAAU;GAAa,eAAY;GAAsB,GAAI;GAAS;EACrE;;AAGhC,UAAU,cAAc;AAExB,MAAa,oBAAoB,EAAE,WAAW,GAAG,YAA+D;AAC9G,QAAO,oBAAC,mBAAmB,SAApB;EAA4B,WAAW,GAAG,aAAa,UAAU;EAAE,aAAU;EAAqB,eAAY;EAA8B,GAAI;EAAS;;AAElK,iBAAiB,cAAc;AAE/B,MAAa,oBAAoB,EAC/B,OAAO,WACP,aAAa,iBACb,WACA,mBAAmB,uBACnB,kBAAkB,sBAClB,MAAM,UACN,YAAY,gBACZ,OAAO,WACP,GAAG,YAGC;CACJ,MAAM,UAAU,WAAW,iBAAiB;CAE5C,MAAM,QAAQ,aAAa,QAAQ,SAAS;CAC5C,MAAM,aAAa,kBAAkB,QAAQ,cAAc;CAC3D,MAAM,OAAO,YAAY,QAAQ,QAAQ;CACzC,MAAM,QAAQ,aAAa,QAAQ,SAAS;CAC5C,MAAM,cAAc,mBAAmB,QAAQ;CAC/C,MAAM,oBAAoB,yBAAyB,QAAQ;CAC3D,MAAM,mBAAmB,wBAAwB,QAAQ;AAEzD,QACE,oBAAC,mBAAmB,QAApB;EAA2B,aAAU;YACnC,oBAAC,mBAAmB,SAApB;GACS;GACM;GACb,WAAW,GACT,4kBACA,UACD;GACkB;GACD;GAClB,aAAU;GACV,eAAY;GACN;GACM;GACZ,OACE,EACE,OAAO,OAAO,UAAU,WAAW,GAAG,MAAM,MAAM,UAAU,kBAAkB,0CAA0C,eACzH;GAEH,GAAI;GACJ;EACwB;;AAGhC,iBAAiB,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdjustmentsIcon.d.ts","names":[],"sources":["../../src/components/Icons/AdjustmentsIcon.tsx"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"AdjustmentsIcon.d.ts","names":[],"sources":["../../src/components/Icons/AdjustmentsIcon.tsx"],"mappings":";;;;;cAqCa,eAAA;EAAe,GAAA;EAAA,SAAA;EAAA,KAAA;EAAA,WAAA;EAAA,IAAA;EAAA,GAAA;AAAA,GAlCyD,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdjustmentsIcon.js","names":[],"sources":["../../src/components/Icons/AdjustmentsIcon.tsx"],"sourcesContent":["import { IconBase } from './IconBase'\nimport { type IconProps } from './iconTypes'\n\nconst IconAdjustments = ({ ref, className, title, description, size = 24, ...rest }: IconProps) => {\n return (\n <IconBase
|
|
1
|
+
{"version":3,"file":"AdjustmentsIcon.js","names":[],"sources":["../../src/components/Icons/AdjustmentsIcon.tsx"],"sourcesContent":["import { IconBase } from './IconBase'\nimport { type IconProps } from './iconTypes'\n\nconst IconAdjustments = ({ ref, className, title, description, size = 24, ...rest }: IconProps) => {\n return (\n <IconBase size={size} className={className} title={title} description={description} ref={ref} {...rest}>\n <path\n d='M12 4.875C12 5.50489 12.2502 6.10898 12.6956 6.55438C13.141 6.99978 13.7451 7.25 14.375 7.25C15.0049 7.25 15.609 6.99978 16.0544 6.55438C16.4998 6.10898 16.75 5.50489 16.75 4.875C16.75 4.24511 16.4998 3.64102 16.0544 3.19562C15.609 2.75022 15.0049 2.5 14.375 2.5C13.7451 2.5 13.141 2.75022 12.6956 3.19562C12.2502 3.64102 12 4.24511 12 4.875Z'\n stroke='currentColor'\n strokeWidth='2'\n strokeLinecap='round'\n strokeLinejoin='round'\n />\n <path d='M2.5 4.875H12' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round' />\n <path d='M16.75 4.875H21.5' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round' />\n <path\n d='M4.875 12C4.875 12.6299 5.12522 13.234 5.57062 13.6794C6.01602 14.1248 6.62011 14.375 7.25 14.375C7.87989 14.375 8.48398 14.1248 8.92938 13.6794C9.37478 13.234 9.625 12.6299 9.625 12C9.625 11.3701 9.37478 10.766 8.92938 10.3206C8.48398 9.87522 7.87989 9.625 7.25 9.625C6.62011 9.625 6.01602 9.87522 5.57062 10.3206C5.12522 10.766 4.875 11.3701 4.875 12Z'\n stroke='currentColor'\n strokeWidth='2'\n strokeLinecap='round'\n strokeLinejoin='round'\n />\n <path d='M2.5 12H4.875' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round' />\n <path d='M9.625 12H21.5' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round' />\n <path\n d='M15.5625 19.125C15.5625 19.7549 15.8127 20.359 16.2581 20.8044C16.7035 21.2498 17.3076 21.5 17.9375 21.5C18.5674 21.5 19.1715 21.2498 19.6169 20.8044C20.0623 20.359 20.3125 19.7549 20.3125 19.125C20.3125 18.4951 20.0623 17.891 19.6169 17.4456C19.1715 17.0002 18.5674 16.75 17.9375 16.75C17.3076 16.75 16.7035 17.0002 16.2581 17.4456C15.8127 17.891 15.5625 18.4951 15.5625 19.125Z'\n stroke='currentColor'\n strokeWidth='2'\n strokeLinecap='round'\n strokeLinejoin='round'\n />\n <path d='M2.5 19.125H15.5625' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round' />\n <path d='M20.3125 19.125H21.5' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round' />\n </IconBase>\n )\n}\n\nexport const AdjustmentsIcon = Object.assign(IconAdjustments, { displayName: 'AdjustmentsIcon' })\n"],"mappings":";;;;;AAGA,MAAM,mBAAmB,EAAE,KAAK,WAAW,OAAO,aAAa,OAAO,IAAI,GAAG,WAAsB;AACjG,QACE,qBAAC,UAAD;EAAgB;EAAiB;EAAkB;EAAoB;EAAkB;EAAK,GAAI;YAAlG;GACE,oBAAC,QAAD;IACE,GAAE;IACF,QAAO;IACP,aAAY;IACZ,eAAc;IACd,gBAAe;IACf;GACF,oBAAC,QAAD;IAAM,GAAE;IAAgB,QAAO;IAAe,aAAY;IAAI,eAAc;IAAQ,gBAAe;IAAU;GAC7G,oBAAC,QAAD;IAAM,GAAE;IAAoB,QAAO;IAAe,aAAY;IAAI,eAAc;IAAQ,gBAAe;IAAU;GACjH,oBAAC,QAAD;IACE,GAAE;IACF,QAAO;IACP,aAAY;IACZ,eAAc;IACd,gBAAe;IACf;GACF,oBAAC,QAAD;IAAM,GAAE;IAAgB,QAAO;IAAe,aAAY;IAAI,eAAc;IAAQ,gBAAe;IAAU;GAC7G,oBAAC,QAAD;IAAM,GAAE;IAAiB,QAAO;IAAe,aAAY;IAAI,eAAc;IAAQ,gBAAe;IAAU;GAC9G,oBAAC,QAAD;IACE,GAAE;IACF,QAAO;IACP,aAAY;IACZ,eAAc;IACd,gBAAe;IACf;GACF,oBAAC,QAAD;IAAM,GAAE;IAAsB,QAAO;IAAe,aAAY;IAAI,eAAc;IAAQ,gBAAe;IAAU;GACnH,oBAAC,QAAD;IAAM,GAAE;IAAuB,QAAO;IAAe,aAAY;IAAI,eAAc;IAAQ,gBAAe;IAAU;GAC3G;;;AAIf,MAAa,kBAAkB,OAAO,OAAO,iBAAiB,EAAE,aAAa,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyzeIcon.d.ts","names":[],"sources":["../../src/components/Icons/AnalyzeIcon.tsx"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"AnalyzeIcon.d.ts","names":[],"sources":["../../src/components/Icons/AnalyzeIcon.tsx"],"mappings":";;;;;cA6Ca,WAAA;EAAW,GAAA;EAAA,SAAA;EAAA,KAAA;EAAA,WAAA;EAAA,IAAA;EAAA,GAAA;AAAA,GA1CyD,SAAA,KAAS,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|