@spear-ai/spectral 1.20.1 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Accordion.js +0 -4
- package/dist/Accordion.js.map +1 -1
- package/dist/Alert/AlertBase.d.ts +0 -1
- package/dist/Alert/AlertBase.d.ts.map +1 -1
- package/dist/Alert/AlertBase.js +14 -17
- package/dist/Alert/AlertBase.js.map +1 -1
- package/dist/Alert.js +16 -4
- package/dist/Alert.js.map +1 -1
- package/dist/AlertDialog.js +3 -3
- package/dist/AlertDialog.js.map +1 -1
- package/dist/Avatar.js +1 -9
- package/dist/Avatar.js.map +1 -1
- package/dist/Badge.js +0 -1
- package/dist/Badge.js.map +1 -1
- package/dist/Button.js +0 -3
- package/dist/Button.js.map +1 -1
- package/dist/ButtonGroup.js +0 -4
- package/dist/ButtonGroup.js.map +1 -1
- package/dist/ButtonIcon.js +0 -1
- package/dist/ButtonIcon.js.map +1 -1
- package/dist/ButtonIconSlideout.js +0 -3
- package/dist/ButtonIconSlideout.js.map +1 -1
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Checkbox.js +5 -8
- package/dist/Checkbox.js.map +1 -1
- package/dist/Combobox.d.ts +1 -0
- package/dist/Combobox.d.ts.map +1 -1
- package/dist/Combobox.js +0 -4
- package/dist/Combobox.js.map +1 -1
- package/dist/ControlGroup/ControlGroupSelect.js +0 -5
- package/dist/ControlGroup/ControlGroupSelect.js.map +1 -1
- package/dist/DataCard/Card.js +0 -6
- package/dist/DataCard/Card.js.map +1 -1
- package/dist/DataCard.js +1 -7
- package/dist/DataCard.js.map +1 -1
- package/dist/DateTimePicker/Calendar.js +0 -1
- package/dist/DateTimePicker/Calendar.js.map +1 -1
- package/dist/DateTimePicker/DateTimeInput.js +0 -1
- package/dist/DateTimePicker/DateTimeInput.js.map +1 -1
- package/dist/DateTimePicker/TimePeriodSelect.js +0 -4
- package/dist/DateTimePicker/TimePeriodSelect.js.map +1 -1
- package/dist/DateTimePicker/TimePicker.js +0 -3
- package/dist/DateTimePicker/TimePicker.js.map +1 -1
- package/dist/DateTimePicker.js +0 -4
- package/dist/DateTimePicker.js.map +1 -1
- package/dist/Dialog.js +0 -16
- package/dist/Dialog.js.map +1 -1
- package/dist/DirectionalColorWheel/DirectionalColorWheelDisclosure.js +0 -2
- package/dist/DirectionalColorWheel/DirectionalColorWheelDisclosure.js.map +1 -1
- package/dist/DirectionalColorWheel/DirectionalColorWheelGlyph.js +0 -1
- package/dist/DirectionalColorWheel/DirectionalColorWheelGlyph.js.map +1 -1
- package/dist/DirectionalColorWheel.js +9 -21
- package/dist/DirectionalColorWheel.js.map +1 -1
- package/dist/Drawer.js +6 -29
- package/dist/Drawer.js.map +1 -1
- package/dist/DropdownMenu.js +1 -9
- package/dist/DropdownMenu.js.map +1 -1
- package/dist/FormFieldMessage.js +0 -1
- package/dist/FormFieldMessage.js.map +1 -1
- package/dist/HoverCard.js +0 -3
- package/dist/HoverCard.js.map +1 -1
- package/dist/Input.js +0 -10
- package/dist/Input.js.map +1 -1
- package/dist/InputOTP.js +0 -4
- package/dist/InputOTP.js.map +1 -1
- package/dist/InputSearch.js +3 -15
- package/dist/InputSearch.js.map +1 -1
- package/dist/Kbd.js +0 -2
- package/dist/Kbd.js.map +1 -1
- package/dist/Meter.d.ts +23 -0
- package/dist/Meter.d.ts.map +1 -0
- package/dist/Meter.js +45 -0
- package/dist/Meter.js.map +1 -0
- package/dist/MultiSelect/MultiSelectBase.js +1 -16
- package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
- package/dist/Popover.js +0 -3
- package/dist/Popover.js.map +1 -1
- package/dist/RadialMenu.js +1 -7
- package/dist/RadialMenu.js.map +1 -1
- package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts.map +1 -1
- package/dist/RadioButtonGroup/RadioButtonGroupBase.js +1 -4
- package/dist/RadioButtonGroup/RadioButtonGroupBase.js.map +1 -1
- package/dist/RadioButtonGroup.js +1 -1
- package/dist/RadioButtonGroup.js.map +1 -1
- package/dist/RadioGroup.js +0 -6
- package/dist/RadioGroup.js.map +1 -1
- package/dist/Select.js +12 -41
- package/dist/Select.js.map +1 -1
- package/dist/Slider.js +2 -11
- package/dist/Slider.js.map +1 -1
- package/dist/Switch.js +0 -6
- package/dist/Switch.js.map +1 -1
- package/dist/Tabs/TabsBase.js +0 -5
- package/dist/Tabs/TabsBase.js.map +1 -1
- package/dist/Textarea.js +0 -4
- package/dist/Textarea.js.map +1 -1
- package/dist/Toast.d.ts +2 -0
- package/dist/Toast.d.ts.map +1 -1
- package/dist/Toast.js +9 -8
- package/dist/Toast.js.map +1 -1
- package/dist/Toggle.js +0 -1
- package/dist/Toggle.js.map +1 -1
- package/dist/ToggleGroup/ToggleGroupItem.js +0 -1
- package/dist/ToggleGroup/ToggleGroupItem.js.map +1 -1
- package/dist/ToggleGroup.js +0 -1
- package/dist/ToggleGroup.js.map +1 -1
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip.js +4 -5
- package/dist/Tooltip.js.map +1 -1
- package/dist/Tray.js +1 -9
- package/dist/Tray.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/styles/horizon/base.css +31 -16
- package/dist/styles/horizon/colors.css +37 -21
- package/dist/styles/horizon/theme.css +15 -7
- package/dist/styles/horizon/utilities.css +19 -45
- package/dist/styles/spectral.css +1 -1
- package/package.json +4 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioButtonGroupBase.js","names":[],"sources":["../../src/components/RadioButtonGroup/RadioButtonGroupBase.tsx"],"sourcesContent":["import { Slot, type AsChildProp } from '@primitives/slot'\nimport { getActiveColorStyle, type ActiveColor, type ActiveTextColor } from '@utils/activeColorStyle'\nimport { cn } from '@utils/twUtils'\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type ButtonHTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type Ref }\n from 'react'\n\ninterface RadioButtonGroupContextValue {\n activeColor?: ActiveColor\n activeTextColor?: ActiveTextColor\n focusItemByIndex: (index: number) => void\n getIndexByValue: (value: string) => number\n isDisabledAtIndex: (index: number) => boolean\n itemCount: () => number\n loop: boolean\n orientation: 'horizontal' | 'vertical'\n selectByIndex: (index: number) => void\n onValueChange?: (value: string) => void\n value?: string\n isKeptActive?: boolean\n expanded?: boolean\n variant?: 'default' | 'outline' | 'divided'\n register: (value: string, element: HTMLButtonElement | null, disabled: boolean) => () => void\n}\n\nconst RadioButtonGroupContext = createContext<RadioButtonGroupContextValue | null>(null)\n\nexport interface RadioButtonGroupProps {\n activeColor?: ActiveColor\n activeTextColor?: ActiveTextColor\n asChild?: boolean\n children: ReactNode\n className?: string\n expanded?: boolean\n isKeptActive?: boolean\n loop?: boolean\n onValueChange?: (value: string) => void\n orientation?: 'horizontal' | 'vertical'\n value?: string\n variant?: 'default' | 'outline' | 'divided'\n 'aria-label'?: string\n 'aria-labelledby'?: string\n}\n\nexport interface RadioButtonGroupItemProps extends AsChildProp, Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'onSelect' | 'type'> {\n activeColor?: ActiveColor\n activeTextColor?: ActiveTextColor\n children: ReactNode\n onSelect?: (value: string) => void\n value: string\n}\n\ninterface RadioButtonRegistryItem {\n value: string\n element: HTMLButtonElement | null\n disabled: boolean\n}\n\nexport const RadioButtonGroupBase = ({ 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, activeColor = 'default', activeTextColor, children, className, expanded = false, isKeptActive = false, loop = true, onValueChange, orientation = 'horizontal', value, variant = 'default' }: RadioButtonGroupProps) => {\n const [registry, setRegistry] = useState<RadioButtonRegistryItem[]>([])\n\n const register = useCallback((nextValue: string, element: HTMLButtonElement | null, disabled: boolean) => {\n setRegistry((previousRegistry) => {\n const existingIndex = previousRegistry.findIndex((item) => item.value === nextValue)\n\n if (existingIndex !== -1) {\n const existingItem = previousRegistry[existingIndex]\n if (existingItem?.element === element && existingItem.disabled === disabled) return previousRegistry\n\n return previousRegistry.map((item, index) =>\n index === existingIndex ? { value: nextValue, element, disabled } : item,\n )\n }\n\n return [...previousRegistry, { value: nextValue, element, disabled }]\n })\n\n return () => {\n setRegistry((previousRegistry) => previousRegistry.filter((item) => item.value !== nextValue))\n }\n }, [])\n\n const getIndexByValue = useCallback((itemValue: string) => registry.findIndex((item) => item.value === itemValue), [registry])\n const itemCount = useCallback(() => registry.length, [registry])\n const isDisabledAtIndex = useCallback((index: number) => registry[index]?.disabled ?? false, [registry])\n\n const getNextEnabledIndex = useCallback(\n (startIndex: number, direction: 1 | -1) => {\n const items = registry\n if (items.length === 0) return -1\n\n let currentIndex = startIndex\n for (let attempt = 0; attempt < items.length; attempt += 1) {\n if (!loop && (currentIndex < 0 || currentIndex >= items.length)) return -1\n const boundedIndex = loop ? (currentIndex + items.length) % items.length : currentIndex\n if (!items[boundedIndex]?.disabled) return boundedIndex\n currentIndex += direction\n }\n\n return -1\n },\n [loop, registry],\n )\n\n const focusItemByIndex = useCallback(\n (index: number) => {\n const targetIndex = getNextEnabledIndex(index, 1)\n if (targetIndex === -1) return\n registry[targetIndex]?.element?.focus()\n },\n [getNextEnabledIndex, registry],\n )\n\n const selectByIndex = useCallback(\n (index: number) => {\n const target = registry[index]\n if (!target || target.disabled) return\n onValueChange?.(target.value)\n },\n [onValueChange, registry],\n )\n\n const contextValue = useMemo(\n () => ({\n activeColor,\n activeTextColor,\n focusItemByIndex,\n getIndexByValue,\n isDisabledAtIndex,\n itemCount,\n loop,\n onValueChange,\n orientation,\n selectByIndex,\n value,\n isKeptActive,\n expanded,\n variant,\n register,\n }),\n [activeColor, activeTextColor, expanded, focusItemByIndex, getIndexByValue, isDisabledAtIndex, isKeptActive, itemCount, loop, onValueChange, orientation, register, selectByIndex, value, variant],\n )\n\n return (\n <RadioButtonGroupContext.Provider value={contextValue}>\n <div\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n className={cn(\n 'rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md flex h-fit w-fit items-center',\n 'data-[expanded=true]:w-full',\n `data-[variant=outline]:gap-0 data-[variant=outline]:[--color-toggle-border:var(--color-toggle-outline-border)] data-[variant=outline]:[&_button:not(:last-of-type)]:[border-right-color:var(--color-toggle-outline-divider)]\n data-[variant=divided]:gap-0 data-[variant=divided]:[--color-toggle-border:var(--color-toggle-outline-border)] data-[variant=divided]:[&_button:not(:last-of-type)]:[border-right-color:var(--color-toggle-outline-divider)]\n data-[variant=divided]:[&_button]:border-y-0 data-[variant=divided]:[&_button:first-of-type]:border-l-0 data-[variant=divided]:[&_button:last-of-type]:border-r-0`,\n className,\n )}\n data-expanded={expanded}\n data-orientation={orientation}\n data-testid='spectral-radio-button-group'\n data-variant={variant}\n aria-orientation={orientation}\n role='radiogroup'\n >\n {children}\n </div>\n </RadioButtonGroupContext.Provider>\n )\n}\n\nexport const RadioButtonGroupItem = ({\n asChild = false,\n activeColor,\n activeTextColor,\n children,\n className,\n disabled = false,\n onClick,\n onSelect,\n ref,\n style,\n value,\n ...rest\n}: RadioButtonGroupItemProps & {\n ref?: Ref<HTMLButtonElement | null>\n}) => {\n const context = useContext(RadioButtonGroupContext)\n\n if (!context) {\n throw new Error('RadioButtonGroupItem must be used within a RadioButtonGroup')\n }\n\n const { activeColor: contextActiveColor, activeTextColor: contextActiveTextColor, value: selectedValue, onValueChange, isKeptActive, expanded, variant, orientation, register, getIndexByValue, isDisabledAtIndex, focusItemByIndex, itemCount, loop, selectByIndex } = context\n const isSelected = selectedValue === value\n const resolvedActiveColor = activeColor ?? contextActiveColor\n const resolvedActiveTextColor = activeTextColor ?? contextActiveTextColor\n const itemRef = useRef<HTMLButtonElement | null>(null)\n\n useImperativeHandle<HTMLButtonElement | null, HTMLButtonElement | null>(ref, () => itemRef.current)\n\n useEffect(() => register(value, itemRef.current, disabled), [disabled, register, value])\n\n const setItemRef = (node: HTMLButtonElement | null) => {\n itemRef.current = node\n if (!ref) return\n if (typeof ref === 'function') {\n ref(node)\n return\n }\n ref.current = node\n }\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n if (onClick) onClick(event)\n if (event.defaultPrevented) return\n if (!disabled) {\n if (onValueChange) {\n onValueChange(value)\n }\n if (onSelect) {\n onSelect(value)\n }\n }\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (rest.onKeyDown) rest.onKeyDown(event)\n if (event.defaultPrevented) return\n\n const currentIndex = getIndexByValue(value)\n if (currentIndex === -1) return\n\n const key = event.key\n const isHorizontal = orientation === 'horizontal'\n const moveNext = (isHorizontal && key === 'ArrowRight') || (!isHorizontal && key === 'ArrowDown')\n const movePrev = (isHorizontal && key === 'ArrowLeft') || (!isHorizontal && key === 'ArrowUp')\n\n if (key === 'Home') {\n event.preventDefault()\n for (let index = 0; index < itemCount(); index += 1) {\n if (!isDisabledAtIndex(index)) {\n selectByIndex(index)\n focusItemByIndex(index)\n return\n }\n }\n return\n }\n\n if (key === 'End') {\n event.preventDefault()\n for (let index = itemCount() - 1; index >= 0; index -= 1) {\n if (!isDisabledAtIndex(index)) {\n selectByIndex(index)\n focusItemByIndex(index)\n return\n }\n }\n return\n }\n\n if (!moveNext && !movePrev) return\n event.preventDefault()\n\n const direction = moveNext ? 1 : -1\n let nextIndex = currentIndex + direction\n for (let attempt = 0; attempt < itemCount(); attempt += 1) {\n if (!loop && (nextIndex < 0 || nextIndex >= itemCount())) return\n const boundedIndex = loop ? (nextIndex + itemCount()) % itemCount() : nextIndex\n if (!isDisabledAtIndex(boundedIndex)) {\n selectByIndex(boundedIndex)\n focusItemByIndex(boundedIndex)\n return\n }\n nextIndex += direction\n }\n }\n\n const selectedIndex = selectedValue ? getIndexByValue(selectedValue) : -1\n const firstEnabledIndex = (() => {\n for (let index = 0; index < itemCount(); index += 1) {\n if (!isDisabledAtIndex(index)) return index\n }\n return -1\n })()\n const currentIndex = getIndexByValue(value)\n const tabIndex = isSelected || (selectedIndex === -1 && firstEnabledIndex !== -1 && currentIndex === firstEnabledIndex) ? 0 : -1\n\n const baseProps = {\n ...rest,\n className: cn(\n `gap-2 text-sm font-medium h-9 px-3 min-w-9 [&_svg:not([class*='size-']):not([width]):not([height])]:size-4 inline-flex items-center justify-center rounded-none border border-toggle-border\n bg-toggle-bg text-toggle-text shadow-none transition-colors hover:cursor-pointer hover:border-toggle-border--hover hover:bg-toggle-bg--hover hover:text-toggle-text--hover focus-visible:z-10\n focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent active:border-toggle-border--active active:bg-toggle-bg--active active:text-toggle-text--active\n disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&:not(:first-child)]:border-l-0`,\n expanded && 'w-full',\n isKeptActive && 'data-[state=on]:border-toggle-border--active data-[state=on]:bg-toggle-bg--active data-[state=on]:text-toggle-text--active',\n className,\n ),\n style: { ...getActiveColorStyle(resolvedActiveColor, resolvedActiveTextColor), ...style },\n disabled,\n onClick: handleClick,\n onKeyDown: handleKeyDown,\n role: 'radio',\n 'aria-checked': isSelected,\n 'data-state': isSelected ? 'on' : 'off',\n 'data-testid': 'spectral-radio-button-group-item',\n 'data-variant': variant,\n tabIndex: disabled ? -1 : tabIndex,\n }\n\n if (asChild) {\n return (\n <Slot ref={setItemRef as Ref<HTMLElement>} {...baseProps}>\n {children}\n </Slot>\n )\n }\n\n return (\n <button ref={setItemRef} {...baseProps} type='button'>\n {children}\n </button>\n )\n}\n\nRadioButtonGroupItem.displayName = 'RadioButtonGroupItem'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RadioButtonGroupBase.js","names":[],"sources":["../../src/components/RadioButtonGroup/RadioButtonGroupBase.tsx"],"sourcesContent":["import { Slot, type AsChildProp } from '@primitives/slot'\nimport { getActiveColorStyle, type ActiveColor, type ActiveTextColor } from '@utils/activeColorStyle'\nimport { cn } from '@utils/twUtils'\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type ButtonHTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type Ref }\n from 'react'\n\ninterface RadioButtonGroupContextValue {\n activeColor?: ActiveColor\n activeTextColor?: ActiveTextColor\n focusItemByIndex: (index: number) => void\n getIndexByValue: (value: string) => number\n isDisabledAtIndex: (index: number) => boolean\n itemCount: () => number\n loop: boolean\n orientation: 'horizontal' | 'vertical'\n selectByIndex: (index: number) => void\n onValueChange?: (value: string) => void\n value?: string\n isKeptActive?: boolean\n expanded?: boolean\n variant?: 'default' | 'outline' | 'divided'\n register: (value: string, element: HTMLButtonElement | null, disabled: boolean) => () => void\n}\n\nconst RadioButtonGroupContext = createContext<RadioButtonGroupContextValue | null>(null)\n\nexport interface RadioButtonGroupProps {\n activeColor?: ActiveColor\n activeTextColor?: ActiveTextColor\n asChild?: boolean\n children: ReactNode\n className?: string\n expanded?: boolean\n isKeptActive?: boolean\n loop?: boolean\n onValueChange?: (value: string) => void\n orientation?: 'horizontal' | 'vertical'\n value?: string\n variant?: 'default' | 'outline' | 'divided'\n 'aria-label'?: string\n 'aria-labelledby'?: string\n}\n\nexport interface RadioButtonGroupItemProps extends AsChildProp, Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'onSelect' | 'type'> {\n activeColor?: ActiveColor\n activeTextColor?: ActiveTextColor\n children: ReactNode\n onSelect?: (value: string) => void\n value: string\n}\n\ninterface RadioButtonRegistryItem {\n value: string\n element: HTMLButtonElement | null\n disabled: boolean\n}\n\nexport const RadioButtonGroupBase = ({ 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, activeColor = 'default', activeTextColor, children, className, expanded = false, isKeptActive = false, loop = true, onValueChange, orientation = 'horizontal', value, variant = 'default' }: RadioButtonGroupProps) => {\n const [registry, setRegistry] = useState<RadioButtonRegistryItem[]>([])\n\n const register = useCallback((nextValue: string, element: HTMLButtonElement | null, disabled: boolean) => {\n setRegistry((previousRegistry) => {\n const existingIndex = previousRegistry.findIndex((item) => item.value === nextValue)\n\n if (existingIndex !== -1) {\n const existingItem = previousRegistry[existingIndex]\n if (existingItem?.element === element && existingItem.disabled === disabled) return previousRegistry\n\n return previousRegistry.map((item, index) =>\n index === existingIndex ? { value: nextValue, element, disabled } : item,\n )\n }\n\n return [...previousRegistry, { value: nextValue, element, disabled }]\n })\n\n return () => {\n setRegistry((previousRegistry) => previousRegistry.filter((item) => item.value !== nextValue))\n }\n }, [])\n\n const getIndexByValue = useCallback((itemValue: string) => registry.findIndex((item) => item.value === itemValue), [registry])\n const itemCount = useCallback(() => registry.length, [registry])\n const isDisabledAtIndex = useCallback((index: number) => registry[index]?.disabled ?? false, [registry])\n\n const getNextEnabledIndex = useCallback(\n (startIndex: number, direction: 1 | -1) => {\n const items = registry\n if (items.length === 0) return -1\n\n let currentIndex = startIndex\n for (let attempt = 0; attempt < items.length; attempt += 1) {\n if (!loop && (currentIndex < 0 || currentIndex >= items.length)) return -1\n const boundedIndex = loop ? (currentIndex + items.length) % items.length : currentIndex\n if (!items[boundedIndex]?.disabled) return boundedIndex\n currentIndex += direction\n }\n\n return -1\n },\n [loop, registry],\n )\n\n const focusItemByIndex = useCallback(\n (index: number) => {\n const targetIndex = getNextEnabledIndex(index, 1)\n if (targetIndex === -1) return\n registry[targetIndex]?.element?.focus()\n },\n [getNextEnabledIndex, registry],\n )\n\n const selectByIndex = useCallback(\n (index: number) => {\n const target = registry[index]\n if (!target || target.disabled) return\n onValueChange?.(target.value)\n },\n [onValueChange, registry],\n )\n\n const contextValue = useMemo(\n () => ({\n activeColor,\n activeTextColor,\n focusItemByIndex,\n getIndexByValue,\n isDisabledAtIndex,\n itemCount,\n loop,\n onValueChange,\n orientation,\n selectByIndex,\n value,\n isKeptActive,\n expanded,\n variant,\n register,\n }),\n [activeColor, activeTextColor, expanded, focusItemByIndex, getIndexByValue, isDisabledAtIndex, isKeptActive, itemCount, loop, onValueChange, orientation, register, selectByIndex, value, variant],\n )\n\n return (\n <RadioButtonGroupContext.Provider value={contextValue}>\n <div\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n className={cn(\n 'rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md flex h-fit w-fit items-center data-[expanded=true]:w-full! data-[variant=outline]:gap-0',\n 'data-[variant=outline]:[--color-toggle-border:var(--color-toggle-outline-border)] data-[variant=outline]:[&_button:not(:last-of-type)]:[border-right-color:var(--color-toggle-outline-divider)]',\n 'data-[variant=divided]:gap-0 data-[variant=divided]:[--color-toggle-border:var(--color-toggle-outline-border)] data-[variant=divided]:[&_button]:border-y-0',\n 'data-[variant=divided]:[&_button:not(:last-of-type)]:[border-right-color:var(--color-toggle-outline-divider)] data-[variant=divided]:[&_button:first-of-type]:border-l-0 data-[variant=divided]:[&_button:last-of-type]:border-r-0',\n className,\n )}\n data-expanded={expanded}\n data-orientation={orientation}\n data-testid='spectral-radio-button-group'\n data-variant={variant}\n aria-orientation={orientation}\n role='radiogroup'\n >\n {children}\n </div>\n </RadioButtonGroupContext.Provider>\n )\n}\n\nexport const RadioButtonGroupItem = ({\n asChild = false,\n activeColor,\n activeTextColor,\n children,\n className,\n disabled = false,\n onClick,\n onSelect,\n ref,\n style,\n value,\n ...rest\n}: RadioButtonGroupItemProps & {\n ref?: Ref<HTMLButtonElement | null>\n}) => {\n const context = useContext(RadioButtonGroupContext)\n\n if (!context) {\n throw new Error('RadioButtonGroupItem must be used within a RadioButtonGroup')\n }\n\n const {\n activeColor: contextActiveColor,\n activeTextColor: contextActiveTextColor,\n value: selectedValue,\n onValueChange,\n isKeptActive,\n expanded,\n variant,\n orientation,\n register,\n getIndexByValue,\n isDisabledAtIndex,\n focusItemByIndex,\n itemCount,\n loop,\n selectByIndex\n } = context\n const isSelected = selectedValue === value\n const resolvedActiveColor = activeColor ?? contextActiveColor\n const resolvedActiveTextColor = activeTextColor ?? contextActiveTextColor\n const itemRef = useRef<HTMLButtonElement | null>(null)\n\n useImperativeHandle<HTMLButtonElement | null, HTMLButtonElement | null>(ref, () => itemRef.current)\n\n useEffect(() => register(value, itemRef.current, disabled), [disabled, register, value])\n\n const setItemRef = (node: HTMLButtonElement | null) => {\n itemRef.current = node\n if (!ref) return\n if (typeof ref === 'function') {\n ref(node)\n return\n }\n ref.current = node\n }\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n if (onClick) onClick(event)\n if (event.defaultPrevented) return\n if (!disabled) {\n if (onValueChange) {\n onValueChange(value)\n }\n if (onSelect) {\n onSelect(value)\n }\n }\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (rest.onKeyDown) rest.onKeyDown(event)\n if (event.defaultPrevented) return\n\n const currentIndex = getIndexByValue(value)\n if (currentIndex === -1) return\n\n const key = event.key\n const isHorizontal = orientation === 'horizontal'\n const moveNext = (isHorizontal && key === 'ArrowRight') || (!isHorizontal && key === 'ArrowDown')\n const movePrev = (isHorizontal && key === 'ArrowLeft') || (!isHorizontal && key === 'ArrowUp')\n\n if (key === 'Home') {\n event.preventDefault()\n for (let index = 0; index < itemCount(); index += 1) {\n if (!isDisabledAtIndex(index)) {\n selectByIndex(index)\n focusItemByIndex(index)\n return\n }\n }\n return\n }\n\n if (key === 'End') {\n event.preventDefault()\n for (let index = itemCount() - 1; index >= 0; index -= 1) {\n if (!isDisabledAtIndex(index)) {\n selectByIndex(index)\n focusItemByIndex(index)\n return\n }\n }\n return\n }\n\n if (!moveNext && !movePrev) return\n event.preventDefault()\n\n const direction = moveNext ? 1 : -1\n let nextIndex = currentIndex + direction\n for (let attempt = 0; attempt < itemCount(); attempt += 1) {\n if (!loop && (nextIndex < 0 || nextIndex >= itemCount())) return\n const boundedIndex = loop ? (nextIndex + itemCount()) % itemCount() : nextIndex\n if (!isDisabledAtIndex(boundedIndex)) {\n selectByIndex(boundedIndex)\n focusItemByIndex(boundedIndex)\n return\n }\n nextIndex += direction\n }\n }\n\n const selectedIndex = selectedValue ? getIndexByValue(selectedValue) : -1\n const firstEnabledIndex = (() => {\n for (let index = 0; index < itemCount(); index += 1) {\n if (!isDisabledAtIndex(index)) return index\n }\n return -1\n })()\n const currentIndex = getIndexByValue(value)\n const tabIndex = isSelected || (selectedIndex === -1 && firstEnabledIndex !== -1 && currentIndex === firstEnabledIndex) ? 0 : -1\n\n const baseProps = {\n ...rest,\n className: cn(\n `gap-2 text-sm font-medium h-9 px-3 min-w-9 [&_svg:not([class*='size-']):not([width]):not([height])]:size-4 inline-flex items-center justify-center rounded-none border border-toggle-border\n bg-toggle-bg text-toggle-text shadow-none transition-colors hover:cursor-pointer hover:border-toggle-border--hover hover:bg-toggle-bg--hover hover:text-toggle-text--hover focus-visible:z-10\n focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent active:border-toggle-border--active active:bg-toggle-bg--active active:text-toggle-text--active\n disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&:not(:first-child)]:border-l-0`,\n expanded && 'w-full',\n isKeptActive && 'data-[state=on]:border-toggle-border--active data-[state=on]:bg-toggle-bg--active data-[state=on]:text-toggle-text--active',\n className,\n ),\n style: { ...getActiveColorStyle(resolvedActiveColor, resolvedActiveTextColor), ...style },\n disabled,\n onClick: handleClick,\n onKeyDown: handleKeyDown,\n role: 'radio',\n 'aria-checked': isSelected,\n 'data-state': isSelected ? 'on' : 'off',\n 'data-testid': 'spectral-radio-button-group-item',\n 'data-variant': variant,\n tabIndex: disabled ? -1 : tabIndex,\n }\n\n if (asChild) {\n return (\n <Slot ref={setItemRef as Ref<HTMLElement>} {...baseProps}>\n {children}\n </Slot>\n )\n }\n\n return (\n <button ref={setItemRef} {...baseProps} type='button'>\n {children}\n </button>\n )\n}\n\nRadioButtonGroupItem.displayName = 'RadioButtonGroupItem'\n"],"mappings":"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"}
|
package/dist/RadioButtonGroup.js
CHANGED
|
@@ -7,7 +7,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
7
7
|
//#region src/components/RadioButtonGroup/RadioButtonGroup.tsx
|
|
8
8
|
const RadioButtonGroup = ({ className, children, ...props }) => {
|
|
9
9
|
return /* @__PURE__ */ jsx(RadioButtonGroupBase, {
|
|
10
|
-
className: cn("rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md flex
|
|
10
|
+
className: cn("rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md flex items-center whitespace-nowrap", className),
|
|
11
11
|
...props,
|
|
12
12
|
children
|
|
13
13
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioButtonGroup.js","names":["RadioButtonGroupItemBase"],"sources":["../src/components/RadioButtonGroup/RadioButtonGroup.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\nimport { RadioButtonGroupBase, RadioButtonGroupItem as RadioButtonGroupItemBase, type RadioButtonGroupItemProps as RadioButtonGroupItemPropsBase } from './RadioButtonGroupBase'\n\nexport type RadioButtonGroupProps = ComponentProps<typeof RadioButtonGroupBase>\nexport type RadioButtonGroupItemProps = RadioButtonGroupItemPropsBase\n\nexport const RadioButtonGroup = ({ className, children, ...props }: RadioButtonGroupProps) => {\n return (\n <RadioButtonGroupBase className={cn('rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md flex
|
|
1
|
+
{"version":3,"file":"RadioButtonGroup.js","names":["RadioButtonGroupItemBase"],"sources":["../src/components/RadioButtonGroup/RadioButtonGroup.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\nimport { RadioButtonGroupBase, RadioButtonGroupItem as RadioButtonGroupItemBase, type RadioButtonGroupItemProps as RadioButtonGroupItemPropsBase } from './RadioButtonGroupBase'\n\nexport type RadioButtonGroupProps = ComponentProps<typeof RadioButtonGroupBase>\nexport type RadioButtonGroupItemProps = RadioButtonGroupItemPropsBase\n\nexport const RadioButtonGroup = ({ className, children, ...props }: RadioButtonGroupProps) => {\n return (\n <RadioButtonGroupBase className={cn('rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md flex items-center whitespace-nowrap', className)} {...props}>\n {children}\n </RadioButtonGroupBase>\n )\n}\nexport const RadioButtonGroupItem = RadioButtonGroupItemBase\n"],"mappings":";;;;;;;AAOA,MAAa,oBAAoB,EAAE,WAAW,UAAU,GAAG,YAAmC;AAC5F,QACE,oBAAC,sBAAD;EAAsB,WAAW,GAAG,6HAA6H,UAAU;EAAE,GAAI;EAC9K;EACoB;;AAG3B,MAAa,uBAAuBA"}
|
package/dist/RadioGroup.js
CHANGED
|
@@ -51,7 +51,6 @@ const RadioGroup = (allProps) => {
|
|
|
51
51
|
/* @__PURE__ */ jsx(RadioGroupPrimitive.Root, {
|
|
52
52
|
className: cn("flex w-full text-text-primary", orientation === "vertical" ? "gap-4 flex-col" : "gap-5 flex-row", variant === "unstyled" && "gap-2.5 w-fit", className),
|
|
53
53
|
"data-state": state,
|
|
54
|
-
"data-testid": "spectral-radio-group",
|
|
55
54
|
id: groupId,
|
|
56
55
|
"aria-invalid": state === "error" ? true : void 0,
|
|
57
56
|
"aria-describedby": [messageId, ariaDescribedBy].filter(Boolean).join(" ") || void 0,
|
|
@@ -89,7 +88,6 @@ const DEFAULT_TRANSITION = {
|
|
|
89
88
|
const RadioButton = memo(({ className, id, isDisabled, ref, transition = DEFAULT_TRANSITION, value, ...props }) => {
|
|
90
89
|
if (useReducedMotion()) return /* @__PURE__ */ jsx(RadioGroupPrimitive.Item, {
|
|
91
90
|
className: cn("h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors", "hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent", "data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg", isDisabled && DISABLED_STYLES, className),
|
|
92
|
-
"data-testid": "spectral-radio-group-item",
|
|
93
91
|
disabled: isDisabled,
|
|
94
92
|
id,
|
|
95
93
|
ref,
|
|
@@ -105,7 +103,6 @@ const RadioButton = memo(({ className, id, isDisabled, ref, transition = DEFAULT
|
|
|
105
103
|
...props,
|
|
106
104
|
children: /* @__PURE__ */ jsx(motion.button, {
|
|
107
105
|
className: cn("h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors", "hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent", "data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg", isDisabled && DISABLED_STYLES, className),
|
|
108
|
-
"data-testid": "spectral-radio-group-item",
|
|
109
106
|
ref,
|
|
110
107
|
whileHover: { scale: 1.05 },
|
|
111
108
|
whileTap: { scale: .95 },
|
|
@@ -140,7 +137,6 @@ const RadioGroupItem = ({ children, className, disabled, ref, value, ...props })
|
|
|
140
137
|
const isDisabled = groupDisabled || disabledValues.includes(stringValue) || Boolean(disabled);
|
|
141
138
|
if (variant === "unstyled") return /* @__PURE__ */ jsx(RadioGroupPrimitive.Item, {
|
|
142
139
|
asChild: true,
|
|
143
|
-
"data-testid": "spectral-radio-group-item",
|
|
144
140
|
disabled: isDisabled,
|
|
145
141
|
id,
|
|
146
142
|
ref,
|
|
@@ -148,7 +144,6 @@ const RadioGroupItem = ({ children, className, disabled, ref, value, ...props })
|
|
|
148
144
|
...props,
|
|
149
145
|
children: /* @__PURE__ */ jsx(Label, {
|
|
150
146
|
className: cn("rounded flex h-fit w-fit border-2 border-transparent data-[state=checked]:border-radio-border--selected", isDisabled && DISABLED_STYLES, itemClassName, className),
|
|
151
|
-
"data-testid": "spectral-radio-group-item-label",
|
|
152
147
|
htmlFor: id,
|
|
153
148
|
children
|
|
154
149
|
})
|
|
@@ -172,7 +167,6 @@ RadioGroupItem.displayName = "RadioGroup.Item";
|
|
|
172
167
|
const RadioGroupLabel = ({ ref, className, ...props }) => {
|
|
173
168
|
return /* @__PURE__ */ jsx(Label, {
|
|
174
169
|
ref,
|
|
175
|
-
"data-testid": "spectral-radio-group-label",
|
|
176
170
|
className: cn("text-md font-medium block", className),
|
|
177
171
|
...props
|
|
178
172
|
});
|
package/dist/RadioGroup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.js","names":[],"sources":["../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { AnimatePresence, motion, useReducedMotion, type Transition } from 'motion/react'\nimport { createContext, memo, useContext, useId, useMemo, type ComponentProps, type ComponentRef, type ReactElement, type ReactNode, type Ref } from 'react'\n\ntype RadioGroupVariant = 'default' | 'unstyled'\n\nexport interface RadioGroupProps extends Omit<ComponentProps<typeof RadioGroupPrimitive.Root>, 'onChange' | 'disabled'> {\n 'aria-describedby'?: string\n 'aria-label'?: string\n className?: string\n disabled?: boolean | string[]\n errorMessage?: BaseFormFieldProps['errorMessage']\n itemClassName?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name: string\n onChange?: (selected: string) => void\n onValueChange: (selected: string) => void\n orientation?: 'horizontal' | 'vertical'\n required?: boolean\n selected?: string\n state?: FormFieldState\n variant?: RadioGroupVariant\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport interface RadioGroupItemProps extends ComponentProps<typeof RadioGroupPrimitive.Item> {\n className?: string\n children?: ReactNode\n description?: string | ReactNode\n id?: string\n value: string\n}\n\ninterface RadioGroupContextType {\n disabledValues: string[]\n groupDisabled: boolean\n itemClassName?: string\n orientation: 'horizontal' | 'vertical'\n selected?: string\n variant: RadioGroupVariant\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextType>({\n disabledValues: [],\n groupDisabled: false,\n orientation: 'vertical',\n variant: 'default',\n})\n\nconst DISABLED_STYLES = 'pointer-events-none opacity-60'\n\nconst RadioGroup = (\n allProps: RadioGroupProps & {\n ref?: Ref<ComponentRef<typeof RadioGroupPrimitive.Root>>\n },\n): ReactElement => {\n const isControlled = 'selected' in allProps\n const {\n className,\n disabled,\n errorMessage,\n itemClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n orientation = 'vertical',\n ref,\n selected: selectedProp,\n state = 'default',\n variant = 'default',\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const selected = isControlled ? (selectedProp ?? '') : selectedProp\n const groupId = useFormFieldId(props.id, name)\n const errorMessageId = `${groupId}-error`\n const warningMessageId = `${groupId}-warning`\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const handleValueChange = (nextValue: string) => {\n onValueChange(nextValue)\n onChange?.(nextValue)\n }\n\n const contextValue = useMemo(\n () => ({\n disabledValues: Array.isArray(disabled) ? disabled : [],\n groupDisabled: typeof disabled === 'boolean' ? disabled : false,\n itemClassName,\n orientation,\n selected,\n variant,\n }),\n [orientation, variant, disabled, itemClassName, selected],\n )\n\n return (\n <RadioGroupContext.Provider value={contextValue}>\n <div data-slot='radio-group-field' className='flex w-full flex-col gap-1.5'>\n <RadioGroupPrimitive.Root\n className={cn('flex w-full text-text-primary', orientation === 'vertical' ? 'gap-4 flex-col' : 'gap-5 flex-row', variant === 'unstyled' && 'gap-2.5 w-fit', className)}\n data-state={state}\n data-testid='spectral-radio-group'\n id={groupId}\n aria-invalid={state === 'error' ? true : undefined}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n disabled={contextValue.groupDisabled}\n name={name}\n onValueChange={handleValueChange}\n ref={ref}\n value={selected}\n {...props}\n />\n <ErrorMessage\n dataTestId='spectral-radio-group-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-radio-group-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </RadioGroupContext.Provider>\n )\n}\nRadioGroup.displayName = 'RadioGroup'\n\nconst DEFAULT_TRANSITION: Transition = { type: 'spring', stiffness: 200, damping: 16 }\n\nconst RadioButton = memo(\n ({\n className,\n id,\n isDisabled,\n ref,\n transition = DEFAULT_TRANSITION,\n value,\n ...props\n }: Omit<ComponentProps<typeof RadioGroupPrimitive.Item>, 'asChild'> & {\n isDisabled?: boolean\n ref?: Ref<HTMLButtonElement>\n transition?: Transition\n }) => {\n const prefersReducedMotion = useReducedMotion()\n\n // When reduced motion is preferred, fall back to original non-animated behavior\n if (prefersReducedMotion) {\n return (\n <RadioGroupPrimitive.Item\n className={cn(\n 'h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors',\n 'hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg',\n isDisabled && DISABLED_STYLES,\n className,\n )}\n data-testid='spectral-radio-group-item'\n disabled={isDisabled}\n id={id}\n ref={ref as Ref<ComponentRef<typeof RadioGroupPrimitive.Item>>}\n value={value}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className={cn(`after:inset-0 after:h-2.5 after:w-2.5 after:absolute after:m-auto after:rounded-full after:bg-radio-bg--selected after:content-['']`, isDisabled && DISABLED_STYLES)} />\n </RadioGroupPrimitive.Item>\n )\n }\n\n return (\n <RadioGroupPrimitive.Item value={value} id={id} disabled={isDisabled} asChild {...props}>\n <motion.button\n className={cn(\n 'h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors',\n 'hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg',\n isDisabled && DISABLED_STYLES,\n className,\n )}\n data-testid='spectral-radio-group-item'\n ref={ref}\n whileHover={{ scale: 1.05 }}\n whileTap={{ scale: 0.95 }}\n >\n <RadioGroupPrimitive.Indicator className='relative flex items-center justify-center'>\n <AnimatePresence>\n <motion.div animate={{ opacity: 1, scale: 1 }} className='h-2.5 w-2.5 absolute rounded-full bg-radio-bg--selected' exit={{ opacity: 0, scale: 0 }} initial={{ opacity: 0, scale: 0 }} key='radio-indicator' transition={transition} />\n </AnimatePresence>\n </RadioGroupPrimitive.Indicator>\n </motion.button>\n </RadioGroupPrimitive.Item>\n )\n },\n)\nRadioButton.displayName = 'RadioButton'\n\nconst RadioGroupItem = ({\n children,\n className,\n disabled,\n ref,\n value,\n ...props\n}: RadioGroupItemProps & {\n ref?: Ref<ComponentRef<typeof RadioGroupPrimitive.Item>>\n}): ReactElement => {\n const { disabledValues, groupDisabled, itemClassName, variant, orientation } = useContext(RadioGroupContext)\n const generatedId = useId()\n\n const stringValue = value.toString()\n const id = props.id?.toString() ?? `${stringValue}-${generatedId}`\n const isDisabled = groupDisabled || disabledValues.includes(stringValue) || Boolean(disabled)\n\n if (variant === 'unstyled') {\n return (\n <RadioGroupPrimitive.Item asChild data-testid='spectral-radio-group-item' disabled={isDisabled} id={id} ref={ref} value={stringValue} {...props}>\n <Label className={cn('rounded flex h-fit w-fit border-2 border-transparent data-[state=checked]:border-radio-border--selected', isDisabled && DISABLED_STYLES, itemClassName, className)} data-testid='spectral-radio-group-item-label' htmlFor={id}>\n {children}\n </Label>\n </RadioGroupPrimitive.Item>\n )\n }\n\n return (\n <div className={cn('flex items-center', isDisabled && DISABLED_STYLES, itemClassName, className, orientation)}>\n <RadioButton ref={ref} value={stringValue} id={id} isDisabled={isDisabled} {...props} />\n {children && (\n <Label className={cn('text-md font-normal cursor-pointer', orientation === 'vertical' ? 'ml-2' : 'ml-1')} htmlFor={id}>\n {children}\n </Label>\n )}\n </div>\n )\n}\nRadioGroupItem.displayName = 'RadioGroup.Item'\n\nconst RadioGroupLabel = ({\n ref,\n className,\n ...props\n}: ComponentProps<typeof Label> & {\n ref?: Ref<ComponentRef<typeof Label>>\n}): ReactElement => {\n return <Label ref={ref} data-testid='spectral-radio-group-label' className={cn('text-md font-medium block', className)} {...props} />\n}\nRadioGroupLabel.displayName = 'RadioGroup.Label'\n\nexport { RadioGroup, RadioGroupItem, RadioGroupLabel }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RadioGroup.js","names":[],"sources":["../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { AnimatePresence, motion, useReducedMotion, type Transition } from 'motion/react'\nimport { createContext, memo, useContext, useId, useMemo, type ComponentProps, type ComponentRef, type ReactElement, type ReactNode, type Ref } from 'react'\n\ntype RadioGroupVariant = 'default' | 'unstyled'\n\nexport interface RadioGroupProps extends Omit<ComponentProps<typeof RadioGroupPrimitive.Root>, 'onChange' | 'disabled'> {\n 'aria-describedby'?: string\n 'aria-label'?: string\n className?: string\n disabled?: boolean | string[]\n errorMessage?: BaseFormFieldProps['errorMessage']\n itemClassName?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name: string\n onChange?: (selected: string) => void\n onValueChange: (selected: string) => void\n orientation?: 'horizontal' | 'vertical'\n required?: boolean\n selected?: string\n state?: FormFieldState\n variant?: RadioGroupVariant\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport interface RadioGroupItemProps extends ComponentProps<typeof RadioGroupPrimitive.Item> {\n className?: string\n children?: ReactNode\n description?: string | ReactNode\n id?: string\n value: string\n}\n\ninterface RadioGroupContextType {\n disabledValues: string[]\n groupDisabled: boolean\n itemClassName?: string\n orientation: 'horizontal' | 'vertical'\n selected?: string\n variant: RadioGroupVariant\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextType>({\n disabledValues: [],\n groupDisabled: false,\n orientation: 'vertical',\n variant: 'default',\n})\n\nconst DISABLED_STYLES = 'pointer-events-none opacity-60'\n\nconst RadioGroup = (\n allProps: RadioGroupProps & {\n ref?: Ref<ComponentRef<typeof RadioGroupPrimitive.Root>>\n },\n): ReactElement => {\n const isControlled = 'selected' in allProps\n const {\n className,\n disabled,\n errorMessage,\n itemClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n orientation = 'vertical',\n ref,\n selected: selectedProp,\n state = 'default',\n variant = 'default',\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const selected = isControlled ? (selectedProp ?? '') : selectedProp\n const groupId = useFormFieldId(props.id, name)\n const errorMessageId = `${groupId}-error`\n const warningMessageId = `${groupId}-warning`\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const handleValueChange = (nextValue: string) => {\n onValueChange(nextValue)\n onChange?.(nextValue)\n }\n\n const contextValue = useMemo(\n () => ({\n disabledValues: Array.isArray(disabled) ? disabled : [],\n groupDisabled: typeof disabled === 'boolean' ? disabled : false,\n itemClassName,\n orientation,\n selected,\n variant,\n }),\n [orientation, variant, disabled, itemClassName, selected],\n )\n\n return (\n <RadioGroupContext.Provider value={contextValue}>\n <div data-slot='radio-group-field' className='flex w-full flex-col gap-1.5'>\n <RadioGroupPrimitive.Root\n className={cn('flex w-full text-text-primary', orientation === 'vertical' ? 'gap-4 flex-col' : 'gap-5 flex-row', variant === 'unstyled' && 'gap-2.5 w-fit', className)}\n data-state={state}\n data-testid='spectral-radio-group'\n id={groupId}\n aria-invalid={state === 'error' ? true : undefined}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n disabled={contextValue.groupDisabled}\n name={name}\n onValueChange={handleValueChange}\n ref={ref}\n value={selected}\n {...props}\n />\n <ErrorMessage\n dataTestId='spectral-radio-group-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-radio-group-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </RadioGroupContext.Provider>\n )\n}\nRadioGroup.displayName = 'RadioGroup'\n\nconst DEFAULT_TRANSITION: Transition = { type: 'spring', stiffness: 200, damping: 16 }\n\nconst RadioButton = memo(\n ({\n className,\n id,\n isDisabled,\n ref,\n transition = DEFAULT_TRANSITION,\n value,\n ...props\n }: Omit<ComponentProps<typeof RadioGroupPrimitive.Item>, 'asChild'> & {\n isDisabled?: boolean\n ref?: Ref<HTMLButtonElement>\n transition?: Transition\n }) => {\n const prefersReducedMotion = useReducedMotion()\n\n // When reduced motion is preferred, fall back to original non-animated behavior\n if (prefersReducedMotion) {\n return (\n <RadioGroupPrimitive.Item\n className={cn(\n 'h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors',\n 'hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg',\n isDisabled && DISABLED_STYLES,\n className,\n )}\n data-testid='spectral-radio-group-item'\n disabled={isDisabled}\n id={id}\n ref={ref as Ref<ComponentRef<typeof RadioGroupPrimitive.Item>>}\n value={value}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className={cn(`after:inset-0 after:h-2.5 after:w-2.5 after:absolute after:m-auto after:rounded-full after:bg-radio-bg--selected after:content-['']`, isDisabled && DISABLED_STYLES)} />\n </RadioGroupPrimitive.Item>\n )\n }\n\n return (\n <RadioGroupPrimitive.Item value={value} id={id} disabled={isDisabled} asChild {...props}>\n <motion.button\n className={cn(\n 'h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors',\n 'hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg',\n isDisabled && DISABLED_STYLES,\n className,\n )}\n data-testid='spectral-radio-group-item'\n ref={ref}\n whileHover={{ scale: 1.05 }}\n whileTap={{ scale: 0.95 }}\n >\n <RadioGroupPrimitive.Indicator className='relative flex items-center justify-center'>\n <AnimatePresence>\n <motion.div animate={{ opacity: 1, scale: 1 }} className='h-2.5 w-2.5 absolute rounded-full bg-radio-bg--selected' exit={{ opacity: 0, scale: 0 }} initial={{ opacity: 0, scale: 0 }} key='radio-indicator' transition={transition} />\n </AnimatePresence>\n </RadioGroupPrimitive.Indicator>\n </motion.button>\n </RadioGroupPrimitive.Item>\n )\n },\n)\nRadioButton.displayName = 'RadioButton'\n\nconst RadioGroupItem = ({\n children,\n className,\n disabled,\n ref,\n value,\n ...props\n}: RadioGroupItemProps & {\n ref?: Ref<ComponentRef<typeof RadioGroupPrimitive.Item>>\n}): ReactElement => {\n const { disabledValues, groupDisabled, itemClassName, variant, orientation } = useContext(RadioGroupContext)\n const generatedId = useId()\n\n const stringValue = value.toString()\n const id = props.id?.toString() ?? `${stringValue}-${generatedId}`\n const isDisabled = groupDisabled || disabledValues.includes(stringValue) || Boolean(disabled)\n\n if (variant === 'unstyled') {\n return (\n <RadioGroupPrimitive.Item asChild data-testid='spectral-radio-group-item' disabled={isDisabled} id={id} ref={ref} value={stringValue} {...props}>\n <Label className={cn('rounded flex h-fit w-fit border-2 border-transparent data-[state=checked]:border-radio-border--selected', isDisabled && DISABLED_STYLES, itemClassName, className)} data-testid='spectral-radio-group-item-label' htmlFor={id}>\n {children}\n </Label>\n </RadioGroupPrimitive.Item>\n )\n }\n\n return (\n <div className={cn('flex items-center', isDisabled && DISABLED_STYLES, itemClassName, className, orientation)}>\n <RadioButton ref={ref} value={stringValue} id={id} isDisabled={isDisabled} {...props} />\n {children && (\n <Label className={cn('text-md font-normal cursor-pointer', orientation === 'vertical' ? 'ml-2' : 'ml-1')} htmlFor={id}>\n {children}\n </Label>\n )}\n </div>\n )\n}\nRadioGroupItem.displayName = 'RadioGroup.Item'\n\nconst RadioGroupLabel = ({\n ref,\n className,\n ...props\n}: ComponentProps<typeof Label> & {\n ref?: Ref<ComponentRef<typeof Label>>\n}): ReactElement => {\n return <Label ref={ref} data-testid='spectral-radio-group-label' className={cn('text-md font-medium block', className)} {...props} />\n}\nRadioGroupLabel.displayName = 'RadioGroup.Label'\n\nexport { RadioGroup, RadioGroupItem, RadioGroupLabel }\n"],"mappings":";;;;;;;;;;;AA8CA,MAAM,oBAAoB,cAAqC;CAC7D,gBAAgB,EAAE;CAClB,eAAe;CACf,aAAa;CACb,SAAS;CACV,CAAA;AAED,MAAM,kBAAkB;AAExB,MAAM,cACJ,aAGiB;CACjB,MAAM,eAAe,cAAc;CACnC,MAAM,EACJ,WACA,UACA,cACA,eACA,sBAAsB,GACtB,sBAAsB,OACtB,MACA,UACA,eACA,cAAc,YACd,KACA,UAAU,cACV,QAAQ,WACR,UAAU,WACV,gBACA,oBAAoB,iBACpB,GAAG,UACD;CACJ,MAAM,WAAW,eAAgB,gBAAgB,KAAM;CACvD,MAAM,UAAU,eAAe,MAAM,IAAI,KAAI;CAC7C,MAAM,iBAAiB,GAAG,QAAQ;CAClC,MAAM,mBAAmB,GAAG,QAAQ;CACpC,MAAM,YAAY,UAAU,WAAW,eAAe,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClI,MAAM,qBAAqB,cAAsB;AAC/C,gBAAc,UAAS;AACvB,aAAW,UAAS;;CAGtB,MAAM,eAAe,eACZ;EACL,gBAAgB,MAAM,QAAQ,SAAS,GAAG,WAAW,EAAE;EACvD,eAAe,OAAO,aAAa,YAAY,WAAW;EAC1D;EACA;EACA;EACA;EACD,GACD;EAAC;EAAa;EAAS;EAAU;EAAe;EAAS,CAC3D;AAEA,QACE,oBAAC,kBAAkB,UAAnB;EAA4B,OAAO;YACjC,qBAAC,OAAD;GAAK,aAAU;GAAoB,WAAU;aAA7C;IACE,oBAAC,oBAAoB,MAArB;KACE,WAAW,GAAG,iCAAiC,gBAAgB,aAAa,mBAAmB,kBAAkB,YAAY,cAAc,iBAAiB,UAAU;KACtK,cAAY;KAEZ,IAAI;KACJ,gBAAc,UAAU,UAAU,OAAO;KACzC,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;KAC5E,UAAU,aAAa;KACjB;KACN,eAAe;KACV;KACL,OAAO;KACP,GAAI;KACL;IACD,oBAAC,cAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,UAAU,UAAU,eAAe;KACvB;KACrB,qBAAqB,uBAAuB,UAAU;KACvD;IACD,oBAAC,gBAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,UAAU,YAAY,iBAAiB;KAC3B;KACrB,qBAAqB,uBAAuB,UAAU;KACvD;IACE;;EACqB;;AAGhC,WAAW,cAAc;AAEzB,MAAM,qBAAiC;CAAE,MAAM;CAAU,WAAW;CAAK,SAAS;CAAG;AAErF,MAAM,cAAc,MACjB,EACC,WACA,IACA,YACA,KACA,aAAa,oBACb,OACA,GAAG,YAKC;AAIJ,KAH6B,kBAGL,CACtB,QACE,oBAAC,oBAAoB,MAArB;EACE,WAAW,GACT,yIACA,wHACA,uFACA,cAAc,iBACd,UACD;EAED,UAAU;EACN;EACC;EACE;EACP,GAAI;YAEJ,oBAAC,oBAAoB,WAArB,EAA+B,WAAW,GAAG,uIAAuI,cAAc,gBAAgB,EAAG;EAC7L;AAI9B,QACE,oBAAC,oBAAoB,MAArB;EAAiC;EAAW;EAAI,UAAU;EAAY;EAAQ,GAAI;YAChF,oBAAC,OAAO,QAAR;GACE,WAAW,GACT,yIACA,wHACA,uFACA,cAAc,iBACd,UACD;GAEI;GACL,YAAY,EAAE,OAAO,MAAM;GAC3B,UAAU,EAAE,OAAO,KAAM;aAEzB,oBAAC,oBAAoB,WAArB;IAA+B,WAAU;cACvC,oBAAC,iBAAD,YACE,oBAAC,OAAO,KAAR;KAAY,SAAS;MAAE,SAAS;MAAG,OAAO;MAAG;KAAE,WAAU;KAA0D,MAAM;MAAE,SAAS;MAAG,OAAO;MAAG;KAAE,SAAS;MAAE,SAAS;MAAG,OAAO;MAAG;KAAoC;KAAa,EAA3C,kBAA2C,EACtN;IACY;GAClB;EACS;EAGhC;AACA,YAAY,cAAc;AAE1B,MAAM,kBAAkB,EACtB,UACA,WACA,UACA,KACA,OACA,GAAG,YAGe;CAClB,MAAM,EAAE,gBAAgB,eAAe,eAAe,SAAS,gBAAgB,WAAW,kBAAiB;CAC3G,MAAM,cAAc,OAAM;CAE1B,MAAM,cAAc,MAAM,UAAS;CACnC,MAAM,KAAK,MAAM,IAAI,UAAU,IAAI,GAAG,YAAY,GAAG;CACrD,MAAM,aAAa,iBAAiB,eAAe,SAAS,YAAY,IAAI,QAAQ,SAAQ;AAE5F,KAAI,YAAY,WACd,QACE,oBAAC,oBAAoB,MAArB;EAA0B;EAAgD,UAAU;EAAgB;EAAS;EAAK,OAAO;EAAa,GAAI;YACxI,oBAAC,OAAD;GAAO,WAAW,GAAG,2GAA2G,cAAc,iBAAiB,eAAe,UAAU;GAAgD,SAAS;GAC9O;GACI;EACiB;AAI9B,QACE,qBAAC,OAAD;EAAK,WAAW,GAAG,qBAAqB,cAAc,iBAAiB,eAAe,WAAW,YAAY;YAA7G,CACE,oBAAC,aAAD;GAAkB;GAAK,OAAO;GAAiB;GAAgB;GAAY,GAAI;GAAQ,GACtF,YACC,oBAAC,OAAD;GAAO,WAAW,GAAG,sCAAsC,gBAAgB,aAAa,SAAS,OAAO;GAAE,SAAS;GAChH;GACI,EAEN;;;AAGT,eAAe,cAAc;AAE7B,MAAM,mBAAmB,EACvB,KACA,WACA,GAAG,YAGe;AAClB,QAAO,oBAAC,OAAD;EAAY;EAA8C,WAAW,GAAG,6BAA6B,UAAU;EAAE,GAAI;EAAQ;;AAEtI,gBAAgB,cAAc"}
|
package/dist/Select.js
CHANGED
|
@@ -44,27 +44,18 @@ const Select = (allProps) => {
|
|
|
44
44
|
onValueChange?.(nextValue);
|
|
45
45
|
};
|
|
46
46
|
const renderOptions = () => {
|
|
47
|
-
if (isLoading) return /* @__PURE__ */ jsx(LoadingState, {
|
|
48
|
-
|
|
49
|
-
message: loadingMessage
|
|
50
|
-
});
|
|
51
|
-
if (options.length === 0) return /* @__PURE__ */ jsx(EmptyState, {
|
|
52
|
-
"data-testid": "spectral-select-empty",
|
|
53
|
-
message: emptyMessage
|
|
54
|
-
});
|
|
47
|
+
if (isLoading) return /* @__PURE__ */ jsx(LoadingState, { message: loadingMessage });
|
|
48
|
+
if (options.length === 0) return /* @__PURE__ */ jsx(EmptyState, { message: emptyMessage });
|
|
55
49
|
const renderOption = (option) => {
|
|
56
50
|
const isSelected = value === option.value;
|
|
57
51
|
return /* @__PURE__ */ jsxs(SelectPrimitive.Item, {
|
|
58
52
|
className: cn(getOptionClasses(!!option.disabled, false, isSelected), "relative flex w-full cursor-pointer items-center"),
|
|
59
|
-
"data-testid": "spectral-select-item",
|
|
60
53
|
disabled: option.disabled,
|
|
61
54
|
value: option.value,
|
|
62
55
|
children: [/* @__PURE__ */ jsx(SelectPrimitive.ItemText, {
|
|
63
|
-
"data-testid": "spectral-select-item-text",
|
|
64
56
|
className: "block truncate",
|
|
65
57
|
children: option.label
|
|
66
58
|
}), /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, {
|
|
67
|
-
"data-testid": "spectral-select-item-selected-indicator",
|
|
68
59
|
asChild: true,
|
|
69
60
|
children: /* @__PURE__ */ jsx("span", {
|
|
70
61
|
className: "right-2 h-4 w-4 absolute flex items-center justify-center",
|
|
@@ -73,36 +64,24 @@ const Select = (allProps) => {
|
|
|
73
64
|
})]
|
|
74
65
|
}, option.value);
|
|
75
66
|
};
|
|
76
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [ungrouped.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [ungrouped.map(renderOption), Object.keys(groups).length > 0 && /* @__PURE__ */ jsx(SelectPrimitive.Separator, {
|
|
77
|
-
className: "-mx-1 my-1 h-px bg-border-secondary",
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"data-testid": "spectral-select-group-separator"
|
|
85
|
-
}),
|
|
86
|
-
/* @__PURE__ */ jsx(Label, {
|
|
87
|
-
className: cn("px-2 py-1.5 text-base font-semibold text-text-primary", labelClassName),
|
|
88
|
-
"data-testid": "spectral-select-group-label",
|
|
89
|
-
children: groupName
|
|
90
|
-
}),
|
|
91
|
-
groupOptions.map((option) => renderOption(option))
|
|
92
|
-
]
|
|
93
|
-
}, groupName))] });
|
|
67
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [ungrouped.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [ungrouped.map(renderOption), Object.keys(groups).length > 0 && /* @__PURE__ */ jsx(SelectPrimitive.Separator, { className: "-mx-1 my-1 h-px bg-border-secondary" })] }), Object.entries(groups).map(([groupName, groupOptions], groupIndex) => /* @__PURE__ */ jsxs(SelectPrimitive.Group, { children: [
|
|
68
|
+
groupIndex > 0 && /* @__PURE__ */ jsx(SelectPrimitive.Separator, { className: "-mx-1 my-1 h-px bg-border-secondary" }),
|
|
69
|
+
/* @__PURE__ */ jsx(Label, {
|
|
70
|
+
className: cn("px-2 py-1.5 text-base font-semibold text-text-primary", labelClassName),
|
|
71
|
+
children: groupName
|
|
72
|
+
}),
|
|
73
|
+
groupOptions.map((option) => renderOption(option))
|
|
74
|
+
] }, groupName))] });
|
|
94
75
|
};
|
|
95
76
|
return /* @__PURE__ */ jsxs("div", {
|
|
96
77
|
className: "w-full",
|
|
97
78
|
children: [
|
|
98
79
|
label && /* @__PURE__ */ jsx(Label, {
|
|
99
80
|
className: cn("mb-2 block text-text-primary", labelClassName, isDisabled && "text-text-secondary"),
|
|
100
|
-
"data-testid": "spectral-select-label",
|
|
101
81
|
htmlFor: selectId,
|
|
102
82
|
children: label
|
|
103
83
|
}),
|
|
104
84
|
/* @__PURE__ */ jsxs(SelectPrimitive.Root, {
|
|
105
|
-
"data-testid": "spectral-select",
|
|
106
85
|
defaultValue,
|
|
107
86
|
disabled: isDisabled,
|
|
108
87
|
name,
|
|
@@ -119,7 +98,6 @@ const Select = (allProps) => {
|
|
|
119
98
|
className: cn(getTriggerClasses(open, state), "text-input-text data-placeholder:text-input-text-placeholder!", className),
|
|
120
99
|
"data-slot": "select-trigger",
|
|
121
100
|
"data-state": state,
|
|
122
|
-
"data-testid": "spectral-select-trigger",
|
|
123
101
|
id: selectId,
|
|
124
102
|
ref,
|
|
125
103
|
style: getFormFieldCSSProperties(),
|
|
@@ -129,10 +107,7 @@ const Select = (allProps) => {
|
|
|
129
107
|
className: "min-w-0 gap-2 [&>span]:min-w-0 grid w-full cursor-pointer grid-cols-[minmax(0,1fr)_auto] items-center overflow-hidden text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder! [&>span]:block [&>span]:overflow-hidden [&>span]:text-ellipsis [&>span]:whitespace-nowrap [&>span[data-placeholder]]:text-input-text-placeholder!",
|
|
130
108
|
type: "button",
|
|
131
109
|
disabled: isDisabled,
|
|
132
|
-
children: [/* @__PURE__ */ jsx(SelectValue, {
|
|
133
|
-
"data-testid": "spectral-select-value",
|
|
134
|
-
placeholder
|
|
135
|
-
}), /* @__PURE__ */ jsx(SelectPrimitive.Icon, {
|
|
110
|
+
children: [/* @__PURE__ */ jsx(SelectValue, { placeholder }), /* @__PURE__ */ jsx(SelectPrimitive.Icon, {
|
|
136
111
|
asChild: true,
|
|
137
112
|
children: /* @__PURE__ */ jsx("div", {
|
|
138
113
|
className: "flex shrink-0 cursor-pointer items-center",
|
|
@@ -147,14 +122,13 @@ const Select = (allProps) => {
|
|
|
147
122
|
align,
|
|
148
123
|
alignOffset,
|
|
149
124
|
avoidCollisions,
|
|
150
|
-
className: cn("relative z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in
|
|
125
|
+
className: cn("relative z-50 max-h-[min(var(--radix-select-content-available-height),300px)] min-w-32 origin-(--radix-select-content-transform-origin) overflow-hidden pb-1", getDropdownSurfaceClasses(), "motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in 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 motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1"),
|
|
151
126
|
collisionBoundary,
|
|
152
127
|
collisionPadding,
|
|
153
128
|
"data-dropdown-width-mode": dropdownWidthMode,
|
|
154
129
|
"data-dropdown-width-value": dropdownWidthMode === "custom" ? dropdownWidth : void 0,
|
|
155
130
|
id: listboxId,
|
|
156
131
|
"data-slot": "select-content",
|
|
157
|
-
"data-testid": "spectral-select-content",
|
|
158
132
|
position,
|
|
159
133
|
ref: setDropdownElement,
|
|
160
134
|
side,
|
|
@@ -163,7 +137,6 @@ const Select = (allProps) => {
|
|
|
163
137
|
children: [
|
|
164
138
|
/* @__PURE__ */ jsx(SelectPrimitive.ScrollUpButton, {
|
|
165
139
|
className: "py-1 flex cursor-default items-center justify-center",
|
|
166
|
-
"data-testid": "spectral-select-scroll-up-button",
|
|
167
140
|
children: /* @__PURE__ */ jsx(ChevronDownIcon, {
|
|
168
141
|
"aria-hidden": "true",
|
|
169
142
|
className: "rotate-180",
|
|
@@ -174,13 +147,11 @@ const Select = (allProps) => {
|
|
|
174
147
|
asChild: true,
|
|
175
148
|
children: /* @__PURE__ */ jsx("div", {
|
|
176
149
|
className: cn("p-1 overflow-x-hidden overflow-y-auto [&>div]:leading-5", position === "popper" && (dropdownWidth === "trigger" ? "scroll-my-1 h-(--radix-select-trigger-height) w-(--spectral-select-content-width) min-w-(--spectral-select-content-width)" : "scroll-my-1 h-(--radix-select-trigger-height)")),
|
|
177
|
-
"data-testid": "spectral-select-items",
|
|
178
150
|
children: renderOptions()
|
|
179
151
|
})
|
|
180
152
|
}),
|
|
181
153
|
/* @__PURE__ */ jsx(SelectPrimitive.ScrollDownButton, {
|
|
182
154
|
className: "py-1 flex cursor-default items-center justify-center",
|
|
183
|
-
"data-testid": "spectral-select-scroll-down-button",
|
|
184
155
|
children: /* @__PURE__ */ jsx(ChevronDownIcon, {
|
|
185
156
|
"aria-hidden": "true",
|
|
186
157
|
size: 18
|
package/dist/Select.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.js","names":[],"sources":["../src/components/Select/Select.tsx"],"sourcesContent":["import { CheckmarkIcon, ChevronDownIcon, LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { SelectValue } from '@primitives/select'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport {\n EmptyState,\n ErrorMessage,\n getAriaProps,\n getDropdownWidthStyles,\n getDropdownSurfaceClasses,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getOptionClasses,\n getTriggerClasses,\n groupOptions,\n LoadingState,\n WarningMessage,\n useFormFieldId,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useState, type ComponentPropsWithoutRef, type CSSProperties, type ReactNode, type Ref } from 'react'\n\ntype SelectOption = BaseOption\ntype Align = 'start' | 'center' | 'end'\ntype Side = 'top' | 'bottom' | 'left' | 'right'\n\nexport interface SelectProps extends Omit<ComponentPropsWithoutRef<'button'>, 'value' | 'onChange' | 'aria-disabled' | 'aria-invalid' | 'aria-required' | 'aria-describedby' | 'aria-label'>, Omit<BaseFormFieldProps, 'state'> {\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: ReactNode\n id?: string\n label?: string\n labelClassName?: string\n loadingMessage?: string\n onChange?: (value: string) => void\n onValueChange?: (value: string) => void\n options: SelectOption[]\n placeholder?: string\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport interface SelectExtendedProps extends SelectProps {\n align?: Align\n alignOffset?: number\n avoidCollisions?: boolean\n collisionBoundary?: Element | Element[] | null\n collisionPadding?: number | Partial<Record<Side, number>>\n position?: 'popper' | 'item-aligned'\n side?: Side\n sideOffset?: number\n}\n\nexport const Select = (\n allProps: SelectExtendedProps & {\n ref?: Ref<HTMLButtonElement>\n },\n) => {\n const isControlled = 'value' in allProps\n const {\n align = 'start',\n alignOffset = 0,\n avoidCollisions = true,\n className,\n collisionBoundary,\n collisionPadding = 10,\n defaultValue,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n disabled,\n id,\n label,\n labelClassName,\n loadingMessage = 'Loading…',\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n options,\n placeholder = 'Select an option',\n position = 'popper',\n ref,\n required,\n side = 'bottom',\n sideOffset = 4,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const value = isControlled ? (valueProp ?? '') : valueProp\n const [open, setOpen] = useState(false)\n const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(open)\n const selectId = useFormFieldId(id, name)\n const listboxId = `${selectId}-listbox`\n const errorMessageId = getErrorMessageId(selectId)\n const warningMessageId = `${selectId}-warning`\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const { dropdownWidthMode, dropdownWidthStyle, resolvedDropdownWidth } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--radix-select-trigger-width)',\n })\n const selectContentStyle = {\n '--spectral-select-content-width': resolvedDropdownWidth,\n ...(position === 'item-aligned' ? { width: resolvedDropdownWidth } : {}),\n ...dropdownWidthStyle,\n ...dropdownShiftStyle,\n } as CSSProperties\n const isDisabled = Boolean(disabled)\n const isLoading = state === 'loading'\n const isInvalid = state === 'error'\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n const { groups, ungrouped } = groupOptions(options)\n const handleValueChange = (nextValue: string) => {\n onChange?.(nextValue)\n onValueChange?.(nextValue)\n }\n\n const renderOptions = () => {\n if (isLoading) {\n return <LoadingState data-testid='spectral-select-loading' message={loadingMessage} />\n }\n\n if (options.length === 0) {\n return <EmptyState data-testid='spectral-select-empty' message={emptyMessage} />\n }\n\n const renderOption = (option: SelectOption) => {\n const isSelected = value === option.value\n\n return (\n <SelectPrimitive.Item className={cn(getOptionClasses(!!option.disabled, false, isSelected), 'relative flex w-full cursor-pointer items-center')} data-testid='spectral-select-item' disabled={option.disabled} key={option.value} value={option.value}>\n <SelectPrimitive.ItemText data-testid='spectral-select-item-text' className='block truncate'>\n {option.label}\n </SelectPrimitive.ItemText>\n <SelectPrimitive.ItemIndicator data-testid='spectral-select-item-selected-indicator' asChild>\n <span className='right-2 h-4 w-4 absolute flex items-center justify-center'>\n <CheckmarkIcon size={16} />\n </span>\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n )\n }\n\n return (\n <>\n {ungrouped.length > 0 && (\n <>\n {ungrouped.map(renderOption)}\n {Object.keys(groups).length > 0 && <SelectPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-select-separator' />}\n </>\n )}\n\n {Object.entries(groups).map(([groupName, groupOptions], groupIndex) => (\n <SelectPrimitive.Group key={groupName} data-testid='spectral-select-group'>\n {groupIndex > 0 && <SelectPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-select-group-separator' />}\n <Label className={cn('px-2 py-1.5 text-base font-semibold text-text-primary', labelClassName)} data-testid='spectral-select-group-label'>\n {groupName}\n </Label>\n {groupOptions.map((option: BaseOption) => renderOption(option))}\n </SelectPrimitive.Group>\n ))}\n </>\n )\n }\n\n return (\n <div className='w-full'>\n {label && (\n <Label className={cn('mb-2 block text-text-primary', labelClassName, isDisabled && 'text-text-secondary')} data-testid='spectral-select-label' htmlFor={selectId}>\n {label}\n </Label>\n )}\n <SelectPrimitive.Root data-testid='spectral-select' defaultValue={defaultValue} disabled={isDisabled} name={name} onOpenChange={setOpen} onValueChange={handleValueChange} open={open} required={required} value={value}>\n <SelectPrimitive.Trigger\n aria-controls={listboxId}\n aria-expanded={open}\n aria-label={ariaLabel ?? label}\n asChild\n className={cn(getTriggerClasses(open, state), 'text-input-text data-placeholder:text-input-text-placeholder!', className)}\n data-slot='select-trigger'\n data-state={state}\n data-testid='spectral-select-trigger'\n id={selectId}\n ref={ref}\n style={getFormFieldCSSProperties() as CSSProperties}\n {...ariaProps}\n {...props}\n >\n <button\n className='min-w-0 gap-2 [&>span]:min-w-0 grid w-full cursor-pointer grid-cols-[minmax(0,1fr)_auto] items-center overflow-hidden text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder! [&>span]:block [&>span]:overflow-hidden [&>span]:text-ellipsis [&>span]:whitespace-nowrap [&>span[data-placeholder]]:text-input-text-placeholder!'\n type='button'\n disabled={isDisabled}\n >\n <SelectValue data-testid='spectral-select-value' placeholder={placeholder} />\n <SelectPrimitive.Icon asChild>\n <div className='flex shrink-0 cursor-pointer items-center'>{isLoading ? <LoaderIcon size={20} /> : <ChevronDownIcon className={cn('transition-transform duration-200', open && 'rotate-180')} size={20} />}</div>\n </SelectPrimitive.Icon>\n </button>\n </SelectPrimitive.Trigger>\n\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n align={align}\n alignOffset={alignOffset}\n avoidCollisions={avoidCollisions}\n className={cn(\n '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-select-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-select-content-transform-origin) overflow-hidden',\n position === 'popper' && 'data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1',\n )}\n collisionBoundary={collisionBoundary}\n collisionPadding={collisionPadding}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n id={listboxId}\n data-slot='select-content'\n data-testid='spectral-select-content'\n position={position}\n ref={setDropdownElement}\n side={side}\n sideOffset={sideOffset}\n style={selectContentStyle}\n >\n <SelectPrimitive.ScrollUpButton className='py-1 flex cursor-default items-center justify-center' data-testid='spectral-select-scroll-up-button'>\n <ChevronDownIcon aria-hidden='true' className='rotate-180' size={18} />\n </SelectPrimitive.ScrollUpButton>\n\n <SelectPrimitive.Viewport asChild>\n <div\n className={cn(\n 'p-1 overflow-x-hidden overflow-y-auto [&>div]:leading-5',\n position === 'popper' && (dropdownWidth === 'trigger' ? 'scroll-my-1 h-(--radix-select-trigger-height) w-(--spectral-select-content-width) min-w-(--spectral-select-content-width)' : 'scroll-my-1 h-(--radix-select-trigger-height)'),\n )}\n data-testid='spectral-select-items'\n >\n {renderOptions()}\n </div>\n </SelectPrimitive.Viewport>\n\n <SelectPrimitive.ScrollDownButton className='py-1 flex cursor-default items-center justify-center' data-testid='spectral-select-scroll-down-button'>\n <ChevronDownIcon aria-hidden='true' size={18} />\n </SelectPrimitive.ScrollDownButton>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n </SelectPrimitive.Root>\n\n <ErrorMessage\n dataTestId='spectral-select-error-message'\n id={errorMessageId}\n message={isInvalid ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-select-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nSelect.displayName = 'Select'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Select.js","names":[],"sources":["../src/components/Select/Select.tsx"],"sourcesContent":["import { CheckmarkIcon, ChevronDownIcon, LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { SelectValue } from '@primitives/select'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport {\n EmptyState,\n ErrorMessage,\n getAriaProps,\n getDropdownWidthStyles,\n getDropdownSurfaceClasses,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getOptionClasses,\n getTriggerClasses,\n groupOptions,\n LoadingState,\n WarningMessage,\n useFormFieldId,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useState, type ComponentPropsWithoutRef, type CSSProperties, type ReactNode, type Ref } from 'react'\n\ntype SelectOption = BaseOption\ntype Align = 'start' | 'center' | 'end'\ntype Side = 'top' | 'bottom' | 'left' | 'right'\n\nexport interface SelectProps extends Omit<ComponentPropsWithoutRef<'button'>, 'value' | 'onChange' | 'aria-disabled' | 'aria-invalid' | 'aria-required' | 'aria-describedby' | 'aria-label'>, Omit<BaseFormFieldProps, 'state'> {\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: ReactNode\n id?: string\n label?: string\n labelClassName?: string\n loadingMessage?: string\n onChange?: (value: string) => void\n onValueChange?: (value: string) => void\n options: SelectOption[]\n placeholder?: string\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport interface SelectExtendedProps extends SelectProps {\n align?: Align\n alignOffset?: number\n avoidCollisions?: boolean\n collisionBoundary?: Element | Element[] | null\n collisionPadding?: number | Partial<Record<Side, number>>\n position?: 'popper' | 'item-aligned'\n side?: Side\n sideOffset?: number\n}\n\nexport const Select = (\n allProps: SelectExtendedProps & {\n ref?: Ref<HTMLButtonElement>\n },\n) => {\n const isControlled = 'value' in allProps\n const {\n align = 'start',\n alignOffset = 0,\n avoidCollisions = true,\n className,\n collisionBoundary,\n collisionPadding = 10,\n defaultValue,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n disabled,\n id,\n label,\n labelClassName,\n loadingMessage = 'Loading…',\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n options,\n placeholder = 'Select an option',\n position = 'popper',\n ref,\n required,\n side = 'bottom',\n sideOffset = 4,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const value = isControlled ? (valueProp ?? '') : valueProp\n const [open, setOpen] = useState(false)\n const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(open)\n const selectId = useFormFieldId(id, name)\n const listboxId = `${selectId}-listbox`\n const errorMessageId = getErrorMessageId(selectId)\n const warningMessageId = `${selectId}-warning`\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const { dropdownWidthMode, dropdownWidthStyle, resolvedDropdownWidth } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--radix-select-trigger-width)',\n })\n const selectContentStyle = {\n '--spectral-select-content-width': resolvedDropdownWidth,\n ...(position === 'item-aligned' ? { width: resolvedDropdownWidth } : {}),\n ...dropdownWidthStyle,\n ...dropdownShiftStyle,\n } as CSSProperties\n const isDisabled = Boolean(disabled)\n const isLoading = state === 'loading'\n const isInvalid = state === 'error'\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n const { groups, ungrouped } = groupOptions(options)\n const handleValueChange = (nextValue: string) => {\n onChange?.(nextValue)\n onValueChange?.(nextValue)\n }\n\n const renderOptions = () => {\n if (isLoading) {\n return <LoadingState data-testid='spectral-select-loading' message={loadingMessage} />\n }\n\n if (options.length === 0) {\n return <EmptyState data-testid='spectral-select-empty' message={emptyMessage} />\n }\n\n const renderOption = (option: SelectOption) => {\n const isSelected = value === option.value\n\n return (\n <SelectPrimitive.Item className={cn(getOptionClasses(!!option.disabled, false, isSelected), 'relative flex w-full cursor-pointer items-center')} data-testid='spectral-select-item' disabled={option.disabled} key={option.value} value={option.value}>\n <SelectPrimitive.ItemText data-testid='spectral-select-item-text' className='block truncate'>\n {option.label}\n </SelectPrimitive.ItemText>\n <SelectPrimitive.ItemIndicator data-testid='spectral-select-item-selected-indicator' asChild>\n <span className='right-2 h-4 w-4 absolute flex items-center justify-center'>\n <CheckmarkIcon size={16} />\n </span>\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n )\n }\n\n return (\n <>\n {ungrouped.length > 0 && (\n <>\n {ungrouped.map(renderOption)}\n {Object.keys(groups).length > 0 && <SelectPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-select-separator' />}\n </>\n )}\n\n {Object.entries(groups).map(([groupName, groupOptions], groupIndex) => (\n <SelectPrimitive.Group key={groupName} data-testid='spectral-select-group'>\n {groupIndex > 0 && <SelectPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-select-group-separator' />}\n <Label className={cn('px-2 py-1.5 text-base font-semibold text-text-primary', labelClassName)} data-testid='spectral-select-group-label'>\n {groupName}\n </Label>\n {groupOptions.map((option: BaseOption) => renderOption(option))}\n </SelectPrimitive.Group>\n ))}\n </>\n )\n }\n\n return (\n <div className='w-full'>\n {label && (\n <Label className={cn('mb-2 block text-text-primary', labelClassName, isDisabled && 'text-text-secondary')} data-testid='spectral-select-label' htmlFor={selectId}>\n {label}\n </Label>\n )}\n <SelectPrimitive.Root data-testid='spectral-select' defaultValue={defaultValue} disabled={isDisabled} name={name} onOpenChange={setOpen} onValueChange={handleValueChange} open={open} required={required} value={value}>\n <SelectPrimitive.Trigger\n aria-controls={listboxId}\n aria-expanded={open}\n aria-label={ariaLabel ?? label}\n asChild\n className={cn(getTriggerClasses(open, state), 'text-input-text data-placeholder:text-input-text-placeholder!', className)}\n data-slot='select-trigger'\n data-state={state}\n data-testid='spectral-select-trigger'\n id={selectId}\n ref={ref}\n style={getFormFieldCSSProperties() as CSSProperties}\n {...ariaProps}\n {...props}\n >\n <button\n className='min-w-0 gap-2 [&>span]:min-w-0 grid w-full cursor-pointer grid-cols-[minmax(0,1fr)_auto] items-center overflow-hidden text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder! [&>span]:block [&>span]:overflow-hidden [&>span]:text-ellipsis [&>span]:whitespace-nowrap [&>span[data-placeholder]]:text-input-text-placeholder!'\n type='button'\n disabled={isDisabled}\n >\n <SelectValue data-testid='spectral-select-value' placeholder={placeholder} />\n <SelectPrimitive.Icon asChild>\n <div className='flex shrink-0 cursor-pointer items-center'>{isLoading ? <LoaderIcon size={20} /> : <ChevronDownIcon className={cn('transition-transform duration-200', open && 'rotate-180')} size={20} />}</div>\n </SelectPrimitive.Icon>\n </button>\n </SelectPrimitive.Trigger>\n\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n align={align}\n alignOffset={alignOffset}\n avoidCollisions={avoidCollisions}\n className={cn(\n 'relative z-50 max-h-[min(var(--radix-select-content-available-height),300px)] min-w-32 origin-(--radix-select-content-transform-origin) overflow-hidden pb-1',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95',\n 'motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=open]:zoom-in-95 motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2',\n position === 'popper' && 'data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1',\n )}\n collisionBoundary={collisionBoundary}\n collisionPadding={collisionPadding}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n id={listboxId}\n data-slot='select-content'\n data-testid='spectral-select-content'\n position={position}\n ref={setDropdownElement}\n side={side}\n sideOffset={sideOffset}\n style={selectContentStyle}\n >\n <SelectPrimitive.ScrollUpButton className='py-1 flex cursor-default items-center justify-center' data-testid='spectral-select-scroll-up-button'>\n <ChevronDownIcon aria-hidden='true' className='rotate-180' size={18} />\n </SelectPrimitive.ScrollUpButton>\n\n <SelectPrimitive.Viewport asChild>\n <div\n className={cn(\n 'p-1 overflow-x-hidden overflow-y-auto [&>div]:leading-5',\n position === 'popper' && (dropdownWidth === 'trigger' ? 'scroll-my-1 h-(--radix-select-trigger-height) w-(--spectral-select-content-width) min-w-(--spectral-select-content-width)' : 'scroll-my-1 h-(--radix-select-trigger-height)'),\n )}\n data-testid='spectral-select-items'\n >\n {renderOptions()}\n </div>\n </SelectPrimitive.Viewport>\n\n <SelectPrimitive.ScrollDownButton className='py-1 flex cursor-default items-center justify-center' data-testid='spectral-select-scroll-down-button'>\n <ChevronDownIcon aria-hidden='true' size={18} />\n </SelectPrimitive.ScrollDownButton>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n </SelectPrimitive.Root>\n\n <ErrorMessage\n dataTestId='spectral-select-error-message'\n id={errorMessageId}\n message={isInvalid ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-select-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nSelect.displayName = 'Select'\n"],"mappings":"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"}
|
package/dist/Slider.js
CHANGED
|
@@ -71,12 +71,10 @@ const Slider = ({ accessibleName, className, defaultValue, disabled, inputPositi
|
|
|
71
71
|
const inputClasses = "w-10 h-fit px-1 shrink-0 text-center text-sm tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none";
|
|
72
72
|
return /* @__PURE__ */ jsxs("div", {
|
|
73
73
|
className: cn("gap-3 flex items-center", isVertical ? "flex-col" : "w-full", className),
|
|
74
|
-
"data-testid": "spectral-slider-container",
|
|
75
74
|
children: [
|
|
76
75
|
showStartLabel && /* @__PURE__ */ jsx("span", {
|
|
77
76
|
className: labelClasses,
|
|
78
77
|
"data-slot": "slider-label",
|
|
79
|
-
"data-testid": "spectral-slider-label-start",
|
|
80
78
|
children: label?.({
|
|
81
79
|
values: _values,
|
|
82
80
|
min,
|
|
@@ -88,7 +86,6 @@ const Slider = ({ accessibleName, className, defaultValue, disabled, inputPositi
|
|
|
88
86
|
"aria-label": accessibleName ? `${accessibleName} start value` : "Slider start value",
|
|
89
87
|
className: inputClasses,
|
|
90
88
|
"data-slot": "slider-input",
|
|
91
|
-
"data-testid": "spectral-slider-input-start",
|
|
92
89
|
disabled,
|
|
93
90
|
max: _values.length > 1 ? _values[1] - minStepsBetweenThumbs * step : max,
|
|
94
91
|
min,
|
|
@@ -106,7 +103,6 @@ const Slider = ({ accessibleName, className, defaultValue, disabled, inputPositi
|
|
|
106
103
|
"aria-valuenow": _values[0],
|
|
107
104
|
className: "data-[orientation=vertical]:min-h-44 relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
|
|
108
105
|
"data-slot": "slider",
|
|
109
|
-
"data-testid": "spectral-slider",
|
|
110
106
|
disabled,
|
|
111
107
|
max,
|
|
112
108
|
min,
|
|
@@ -120,23 +116,19 @@ const Slider = ({ accessibleName, className, defaultValue, disabled, inputPositi
|
|
|
120
116
|
children: [/* @__PURE__ */ jsx(SliderBase.Track, {
|
|
121
117
|
className: "data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:w-1.5 relative grow overflow-hidden rounded-full bg-slider-track data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full",
|
|
122
118
|
"data-slot": "slider-track",
|
|
123
|
-
"data-testid": "spectral-slider-track",
|
|
124
119
|
children: /* @__PURE__ */ jsx(SliderBase.Range, {
|
|
125
120
|
className: "absolute bg-slider-range data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full",
|
|
126
|
-
"data-slot": "slider-range"
|
|
127
|
-
"data-testid": "spectral-slider-range"
|
|
121
|
+
"data-slot": "slider-range"
|
|
128
122
|
})
|
|
129
123
|
}), Array.from({ length: _values.length }, (_, index) => /* @__PURE__ */ jsx(SliderBase.Thumb, {
|
|
130
124
|
className: "size-5 shadow-sm block shrink-0 rounded-full border border-slider-thumb-border bg-slider-thumb-bg ring-slider-thumb-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50",
|
|
131
|
-
"data-slot": "slider-thumb"
|
|
132
|
-
"data-testid": "spectral-slider-thumb"
|
|
125
|
+
"data-slot": "slider-thumb"
|
|
133
126
|
}, index))]
|
|
134
127
|
}),
|
|
135
128
|
showEndInput && /* @__PURE__ */ jsx(Input, {
|
|
136
129
|
"aria-label": accessibleName ? `${accessibleName} end value` : "Slider end value",
|
|
137
130
|
className: inputClasses,
|
|
138
131
|
"data-slot": "slider-input",
|
|
139
|
-
"data-testid": "spectral-slider-input-end",
|
|
140
132
|
disabled,
|
|
141
133
|
max,
|
|
142
134
|
min: _values[0] + minStepsBetweenThumbs * step,
|
|
@@ -150,7 +142,6 @@ const Slider = ({ accessibleName, className, defaultValue, disabled, inputPositi
|
|
|
150
142
|
showEndLabel && /* @__PURE__ */ jsx("span", {
|
|
151
143
|
className: labelClasses,
|
|
152
144
|
"data-slot": "slider-label",
|
|
153
|
-
"data-testid": "spectral-slider-label-end",
|
|
154
145
|
children: label({
|
|
155
146
|
values: _values,
|
|
156
147
|
min,
|
package/dist/Slider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Slider.js","names":[],"sources":["../src/components/Slider/Slider.tsx"],"sourcesContent":["import { Input } from '@primitives/input'\nimport * as SliderBase from '@radix-ui/react-slider'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useEffect, useMemo, useState, type ChangeEvent, type KeyboardEvent, type ReactNode } from 'react'\n\nexport type SliderLabelPosition = 'end' | 'both'\nexport type SliderInputPosition = 'start' | 'both'\n\nexport interface SliderLabelRenderProps {\n max: number\n min: number\n position: 'start' | 'end'\n values: number[]\n}\n\nexport interface SliderProps {\n accessibleName?: string\n className?: string\n defaultValue?: number[]\n disabled?: boolean\n inputPosition?: SliderInputPosition\n label?: (props: SliderLabelRenderProps) => ReactNode\n labelPosition?: SliderLabelPosition\n max?: number\n min?: number\n minStepsBetweenThumbs?: number\n name?: string\n onValueChange?: (value: number[]) => void\n onValueCommit?: (value: number[]) => void\n orientation?: 'horizontal' | 'vertical'\n step?: number\n value?: number[]\n}\n\nexport const Slider = ({ accessibleName, className, defaultValue, disabled, inputPosition, label, labelPosition, max = 100, min = 0, minStepsBetweenThumbs = 1, name, onValueChange, onValueCommit, orientation = 'horizontal', step = 1, value }: SliderProps) => {\n const isControlled = value !== undefined\n const initialValues = useMemo(\n () => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min]),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n )\n const [internalValues, setInternalValues] = useState(initialValues)\n const _values = isControlled ? value : internalValues\n\n // Local state for input text to allow intermediate typing states\n const [inputTexts, setInputTexts] = useState<string[]>(() => _values.map(String))\n\n // Sync input text when slider values change externally\n useEffect(() => {\n setInputTexts(_values.map(String))\n }, [_values])\n\n const handleValueChange = useCallback(\n (newValues: number[]) => {\n if (!isControlled) {\n setInternalValues(newValues)\n }\n onValueChange?.(newValues)\n },\n [isControlled, onValueChange],\n )\n\n const handleInputTextChange = useCallback(\n (index: number, e: ChangeEvent<HTMLInputElement>) => {\n const newTexts = [...inputTexts]\n newTexts[index] = e.target.value\n setInputTexts(newTexts)\n },\n [inputTexts],\n )\n\n const commitInputValue = useCallback(\n (index: number) => {\n const inputValue = inputTexts[index]\n if (inputValue === '') {\n // Reset to current slider value if empty\n setInputTexts(_values.map(String))\n return\n }\n\n let newValue = parseFloat(inputValue)\n if (isNaN(newValue)) {\n // Reset to current slider value if invalid\n setInputTexts(_values.map(String))\n return\n }\n\n // Clamp to min/max\n newValue = Math.max(min, Math.min(max, newValue))\n\n // Respect minStepsBetweenThumbs for range sliders\n const newValues = [..._values]\n if (index === 0 && _values.length > 1) {\n // Start input: ensure it doesn't exceed end value minus gap\n const maxAllowed = _values[1] - minStepsBetweenThumbs * step\n newValue = Math.min(newValue, maxAllowed)\n } else if (index === 1) {\n // End input: ensure it doesn't go below start value plus gap\n const minAllowed = _values[0] + minStepsBetweenThumbs * step\n newValue = Math.max(newValue, minAllowed)\n }\n\n newValues[index] = newValue\n handleValueChange(newValues)\n onValueCommit?.(newValues)\n },\n [inputTexts, _values, min, max, step, minStepsBetweenThumbs, handleValueChange, onValueCommit],\n )\n\n const handleInputKeyDown = useCallback(\n (index: number, e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n commitInputValue(index)\n e.currentTarget.blur()\n }\n },\n [commitInputValue],\n )\n\n const isVertical = orientation === 'vertical'\n const showStartLabel = labelPosition === 'both'\n const showEndLabel = label && (labelPosition === 'end' || labelPosition === 'both')\n const showStartInput = inputPosition === 'start' || inputPosition === 'both'\n const showEndInput = inputPosition === 'both' && _values.length > 1\n\n const labelClasses = cn('text-slider-label text-sm shrink-0 tabular-nums', isVertical ? 'text-center' : '')\n\n const inputClasses = 'w-10 h-fit px-1 shrink-0 text-center text-sm tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none'\n\n return (\n <div className={cn('gap-3 flex items-center', isVertical ? 'flex-col' : 'w-full', className)} data-testid='spectral-slider-container'>\n {showStartLabel && (\n <span className={labelClasses} data-slot='slider-label' data-testid='spectral-slider-label-start'>\n {label?.({ values: _values, min, max, position: 'start' })}\n </span>\n )}\n\n {showStartInput && (\n <Input\n aria-label={accessibleName ? `${accessibleName} start value` : 'Slider start value'}\n className={inputClasses}\n data-slot='slider-input'\n data-testid='spectral-slider-input-start'\n disabled={disabled}\n max={_values.length > 1 ? _values[1] - minStepsBetweenThumbs * step : max}\n min={min}\n onBlur={() => commitInputValue(0)}\n onChange={(e) => handleInputTextChange(0, e)}\n onKeyDown={(e) => handleInputKeyDown(0, e)}\n step={step}\n type='number'\n value={inputTexts[0] ?? ''}\n />\n )}\n\n <SliderBase.Root\n aria-label={accessibleName}\n aria-valuemax={max}\n aria-valuemin={min}\n aria-valuenow={_values[0]}\n className='data-[orientation=vertical]:min-h-44 relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col'\n data-slot='slider'\n data-testid='spectral-slider'\n disabled={disabled}\n max={max}\n min={min}\n minStepsBetweenThumbs={minStepsBetweenThumbs}\n name={name}\n onValueChange={handleValueChange}\n onValueCommit={onValueCommit}\n orientation={orientation}\n step={step}\n value={_values}\n >\n <SliderBase.Track\n className='data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:w-1.5 relative grow overflow-hidden rounded-full bg-slider-track data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full'\n data-slot='slider-track'\n data-testid='spectral-slider-track'\n >\n <SliderBase.Range className='absolute bg-slider-range data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full' data-slot='slider-range' data-testid='spectral-slider-range' />\n </SliderBase.Track>\n {Array.from({ length: _values.length }, (_, index) => (\n <SliderBase.Thumb\n className='size-5 shadow-sm block shrink-0 rounded-full border border-slider-thumb-border bg-slider-thumb-bg ring-slider-thumb-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50'\n data-slot='slider-thumb'\n data-testid='spectral-slider-thumb'\n key={index}\n />\n ))}\n </SliderBase.Root>\n\n {showEndInput && (\n <Input\n aria-label={accessibleName ? `${accessibleName} end value` : 'Slider end value'}\n className={inputClasses}\n data-slot='slider-input'\n data-testid='spectral-slider-input-end'\n disabled={disabled}\n max={max}\n min={_values[0] + minStepsBetweenThumbs * step}\n onBlur={() => commitInputValue(1)}\n onChange={(e) => handleInputTextChange(1, e)}\n onKeyDown={(e) => handleInputKeyDown(1, e)}\n step={step}\n type='number'\n value={inputTexts[1] ?? ''}\n />\n )}\n\n {showEndLabel && (\n <span className={labelClasses} data-slot='slider-label' data-testid='spectral-slider-label-end'>\n {label({ values: _values, min, max, position: 'end' })}\n </span>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Slider.js","names":[],"sources":["../src/components/Slider/Slider.tsx"],"sourcesContent":["import { Input } from '@primitives/input'\nimport * as SliderBase from '@radix-ui/react-slider'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useEffect, useMemo, useState, type ChangeEvent, type KeyboardEvent, type ReactNode } from 'react'\n\nexport type SliderLabelPosition = 'end' | 'both'\nexport type SliderInputPosition = 'start' | 'both'\n\nexport interface SliderLabelRenderProps {\n max: number\n min: number\n position: 'start' | 'end'\n values: number[]\n}\n\nexport interface SliderProps {\n accessibleName?: string\n className?: string\n defaultValue?: number[]\n disabled?: boolean\n inputPosition?: SliderInputPosition\n label?: (props: SliderLabelRenderProps) => ReactNode\n labelPosition?: SliderLabelPosition\n max?: number\n min?: number\n minStepsBetweenThumbs?: number\n name?: string\n onValueChange?: (value: number[]) => void\n onValueCommit?: (value: number[]) => void\n orientation?: 'horizontal' | 'vertical'\n step?: number\n value?: number[]\n}\n\nexport const Slider = ({ accessibleName, className, defaultValue, disabled, inputPosition, label, labelPosition, max = 100, min = 0, minStepsBetweenThumbs = 1, name, onValueChange, onValueCommit, orientation = 'horizontal', step = 1, value }: SliderProps) => {\n const isControlled = value !== undefined\n const initialValues = useMemo(\n () => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min]),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n )\n const [internalValues, setInternalValues] = useState(initialValues)\n const _values = isControlled ? value : internalValues\n\n // Local state for input text to allow intermediate typing states\n const [inputTexts, setInputTexts] = useState<string[]>(() => _values.map(String))\n\n // Sync input text when slider values change externally\n useEffect(() => {\n setInputTexts(_values.map(String))\n }, [_values])\n\n const handleValueChange = useCallback(\n (newValues: number[]) => {\n if (!isControlled) {\n setInternalValues(newValues)\n }\n onValueChange?.(newValues)\n },\n [isControlled, onValueChange],\n )\n\n const handleInputTextChange = useCallback(\n (index: number, e: ChangeEvent<HTMLInputElement>) => {\n const newTexts = [...inputTexts]\n newTexts[index] = e.target.value\n setInputTexts(newTexts)\n },\n [inputTexts],\n )\n\n const commitInputValue = useCallback(\n (index: number) => {\n const inputValue = inputTexts[index]\n if (inputValue === '') {\n // Reset to current slider value if empty\n setInputTexts(_values.map(String))\n return\n }\n\n let newValue = parseFloat(inputValue)\n if (isNaN(newValue)) {\n // Reset to current slider value if invalid\n setInputTexts(_values.map(String))\n return\n }\n\n // Clamp to min/max\n newValue = Math.max(min, Math.min(max, newValue))\n\n // Respect minStepsBetweenThumbs for range sliders\n const newValues = [..._values]\n if (index === 0 && _values.length > 1) {\n // Start input: ensure it doesn't exceed end value minus gap\n const maxAllowed = _values[1] - minStepsBetweenThumbs * step\n newValue = Math.min(newValue, maxAllowed)\n } else if (index === 1) {\n // End input: ensure it doesn't go below start value plus gap\n const minAllowed = _values[0] + minStepsBetweenThumbs * step\n newValue = Math.max(newValue, minAllowed)\n }\n\n newValues[index] = newValue\n handleValueChange(newValues)\n onValueCommit?.(newValues)\n },\n [inputTexts, _values, min, max, step, minStepsBetweenThumbs, handleValueChange, onValueCommit],\n )\n\n const handleInputKeyDown = useCallback(\n (index: number, e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n commitInputValue(index)\n e.currentTarget.blur()\n }\n },\n [commitInputValue],\n )\n\n const isVertical = orientation === 'vertical'\n const showStartLabel = labelPosition === 'both'\n const showEndLabel = label && (labelPosition === 'end' || labelPosition === 'both')\n const showStartInput = inputPosition === 'start' || inputPosition === 'both'\n const showEndInput = inputPosition === 'both' && _values.length > 1\n\n const labelClasses = cn('text-slider-label text-sm shrink-0 tabular-nums', isVertical ? 'text-center' : '')\n\n const inputClasses = 'w-10 h-fit px-1 shrink-0 text-center text-sm tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none'\n\n return (\n <div className={cn('gap-3 flex items-center', isVertical ? 'flex-col' : 'w-full', className)} data-testid='spectral-slider-container'>\n {showStartLabel && (\n <span className={labelClasses} data-slot='slider-label' data-testid='spectral-slider-label-start'>\n {label?.({ values: _values, min, max, position: 'start' })}\n </span>\n )}\n\n {showStartInput && (\n <Input\n aria-label={accessibleName ? `${accessibleName} start value` : 'Slider start value'}\n className={inputClasses}\n data-slot='slider-input'\n data-testid='spectral-slider-input-start'\n disabled={disabled}\n max={_values.length > 1 ? _values[1] - minStepsBetweenThumbs * step : max}\n min={min}\n onBlur={() => commitInputValue(0)}\n onChange={(e) => handleInputTextChange(0, e)}\n onKeyDown={(e) => handleInputKeyDown(0, e)}\n step={step}\n type='number'\n value={inputTexts[0] ?? ''}\n />\n )}\n\n <SliderBase.Root\n aria-label={accessibleName}\n aria-valuemax={max}\n aria-valuemin={min}\n aria-valuenow={_values[0]}\n className='data-[orientation=vertical]:min-h-44 relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col'\n data-slot='slider'\n data-testid='spectral-slider'\n disabled={disabled}\n max={max}\n min={min}\n minStepsBetweenThumbs={minStepsBetweenThumbs}\n name={name}\n onValueChange={handleValueChange}\n onValueCommit={onValueCommit}\n orientation={orientation}\n step={step}\n value={_values}\n >\n <SliderBase.Track\n className='data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:w-1.5 relative grow overflow-hidden rounded-full bg-slider-track data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full'\n data-slot='slider-track'\n data-testid='spectral-slider-track'\n >\n <SliderBase.Range className='absolute bg-slider-range data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full' data-slot='slider-range' data-testid='spectral-slider-range' />\n </SliderBase.Track>\n {Array.from({ length: _values.length }, (_, index) => (\n <SliderBase.Thumb\n className='size-5 shadow-sm block shrink-0 rounded-full border border-slider-thumb-border bg-slider-thumb-bg ring-slider-thumb-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50'\n data-slot='slider-thumb'\n data-testid='spectral-slider-thumb'\n key={index}\n />\n ))}\n </SliderBase.Root>\n\n {showEndInput && (\n <Input\n aria-label={accessibleName ? `${accessibleName} end value` : 'Slider end value'}\n className={inputClasses}\n data-slot='slider-input'\n data-testid='spectral-slider-input-end'\n disabled={disabled}\n max={max}\n min={_values[0] + minStepsBetweenThumbs * step}\n onBlur={() => commitInputValue(1)}\n onChange={(e) => handleInputTextChange(1, e)}\n onKeyDown={(e) => handleInputKeyDown(1, e)}\n step={step}\n type='number'\n value={inputTexts[1] ?? ''}\n />\n )}\n\n {showEndLabel && (\n <span className={labelClasses} data-slot='slider-label' data-testid='spectral-slider-label-end'>\n {label({ values: _values, min, max, position: 'end' })}\n </span>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
package/dist/Switch.js
CHANGED
|
@@ -20,12 +20,10 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
|
|
|
20
20
|
const isSquared = variant === "squared";
|
|
21
21
|
return /* @__PURE__ */ jsxs("div", {
|
|
22
22
|
className: "flex items-center",
|
|
23
|
-
"data-testid": "spectral-switch-container",
|
|
24
23
|
"data-state": state,
|
|
25
24
|
children: [
|
|
26
25
|
labelPosition === "left" && !hideLabel && resolvedLabelText && /* @__PURE__ */ jsx(Label, {
|
|
27
26
|
className: "mr-2",
|
|
28
|
-
"data-testid": "spectral-switch-label-left",
|
|
29
27
|
htmlFor: switchId,
|
|
30
28
|
children: resolvedLabelText
|
|
31
29
|
}),
|
|
@@ -38,7 +36,6 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
|
|
|
38
36
|
"aria-invalid": state === "error" ? true : void 0,
|
|
39
37
|
"aria-label": ariaLabel ?? (hideLabel ? resolvedLabelText : void 0),
|
|
40
38
|
className: cn("peer inset-0 w-14 focus-visible:ring-ring absolute inline-flex h-[inherit] items-center focus-visible:ring-offset-background data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg/50", "shadow-2xs cursor-pointer rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none", "disabled:cursor-not-allowed disabled:opacity-50", className),
|
|
41
|
-
"data-testid": "spectral-switch",
|
|
42
39
|
disabled: isDisabled,
|
|
43
40
|
id: switchId,
|
|
44
41
|
name,
|
|
@@ -70,7 +67,6 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
|
|
|
70
67
|
"aria-invalid": state === "error" ? true : void 0,
|
|
71
68
|
"aria-label": ariaLabel ?? (hideLabel ? resolvedLabelText : void 0),
|
|
72
69
|
className: cn(isSquared ? "peer h-6 w-10 rounded-sm focus-visible:ring-black inline-flex shrink-0 items-center border-2 border-transparent transition-colors outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg [&_span]:rounded-[4px]" : "focus-visible:ring-ring peer h-6 w-10 shadow-2xs inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg", className),
|
|
73
|
-
"data-testid": "spectral-switch",
|
|
74
70
|
disabled: isDisabled,
|
|
75
71
|
id: switchId,
|
|
76
72
|
name,
|
|
@@ -83,14 +79,12 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
|
|
|
83
79
|
}),
|
|
84
80
|
labelPosition === "right" && !hideLabel && resolvedLabelText && /* @__PURE__ */ jsx(Label, {
|
|
85
81
|
className: "ml-2",
|
|
86
|
-
"data-testid": "spectral-switch-label-right",
|
|
87
82
|
htmlFor: switchId,
|
|
88
83
|
id: `${switchId}-label`,
|
|
89
84
|
children: resolvedLabelText
|
|
90
85
|
}),
|
|
91
86
|
hideLabel && resolvedLabelText && /* @__PURE__ */ jsx(Label, {
|
|
92
87
|
className: "sr-only",
|
|
93
|
-
"data-testid": "spectral-switch-label-hidden",
|
|
94
88
|
htmlFor: switchId,
|
|
95
89
|
children: resolvedLabelText
|
|
96
90
|
}),
|