@spear-ai/spectral 1.14.2 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/Button.d.ts +0 -6
  2. package/dist/Button.d.ts.map +1 -1
  3. package/dist/Button.js +36 -51
  4. package/dist/Button.js.map +1 -1
  5. package/dist/Checkbox.js +3 -3
  6. package/dist/Checkbox.js.map +1 -1
  7. package/dist/Combobox.js +3 -3
  8. package/dist/Combobox.js.map +1 -1
  9. package/dist/ControlGroup/ControlGroupSelect.d.ts +1 -1
  10. package/dist/ControlGroup/ControlGroupSelect.js +1 -1
  11. package/dist/ControlGroup/ControlGroupSelect.js.map +1 -1
  12. package/dist/ControlGroup.d.ts.map +1 -1
  13. package/dist/ControlGroup.js +3 -3
  14. package/dist/ControlGroup.js.map +1 -1
  15. package/dist/DateTimePicker.js +1 -1
  16. package/dist/DateTimePicker.js.map +1 -1
  17. package/dist/FormFieldMessage.js +1 -1
  18. package/dist/FormFieldMessage.js.map +1 -1
  19. package/dist/Input.js +3 -3
  20. package/dist/Input.js.map +1 -1
  21. package/dist/InputNumeric.d.ts +4 -2
  22. package/dist/InputNumeric.d.ts.map +1 -1
  23. package/dist/InputNumeric.js +3 -1
  24. package/dist/InputNumeric.js.map +1 -1
  25. package/dist/InputOTP.js +1 -1
  26. package/dist/InputOTP.js.map +1 -1
  27. package/dist/MultiSelect/MultiSelectBase.js +3 -3
  28. package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
  29. package/dist/RadioGroup.js +3 -3
  30. package/dist/RadioGroup.js.map +1 -1
  31. package/dist/Select.js +3 -3
  32. package/dist/Select.js.map +1 -1
  33. package/dist/Switch.js +3 -3
  34. package/dist/Switch.js.map +1 -1
  35. package/dist/Textarea.d.ts +1 -1
  36. package/dist/Textarea.js +3 -3
  37. package/dist/Textarea.js.map +1 -1
  38. package/dist/index.js +1 -1
  39. package/dist/styles/spectral.css +1 -1
  40. package/package.json +1 -1
@@ -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 = true,\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='space-y-1.5 w-full'>\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 dataTestId='spectral-radio-group-error-message' id={errorMessageId} message={state === 'error' ? errorMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace} />\n <WarningMessage dataTestId='spectral-radio-group-warning-message' id={warningMessageId} message={state === 'warning' ? warningMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace} />\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='space-y-1.5 w-full'>\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 dataTestId='spectral-radio-group-error-message' id={errorMessageId} message={state === 'error' ? errorMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'error'} />\n <WarningMessage dataTestId='spectral-radio-group-warning-message' id={warningMessageId} message={state === 'warning' ? warningMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'warning'} />\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,CAAC;AAEF,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,KAAK;CAC9C,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,UAAU;AACxB,aAAW,UAAU;;CAGvB,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,CAC1D;AAED,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;KACZ,eAAY;KACZ,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;KACJ;IACF,oBAAC,cAAD;KAAc,YAAW;KAAqC,IAAI;KAAgB,SAAS,UAAU,UAAU,eAAe;KAA2B;KAAqB,qBAAqB,uBAAuB,UAAU;KAAW;IAC/O,oBAAC,gBAAD;KAAgB,YAAW;KAAuC,IAAI;KAAkB,SAAS,UAAU,YAAY,iBAAiB;KAA2B;KAAqB,qBAAqB,uBAAuB,UAAU;KAAa;IACvP;;EACqB;;AAGjC,WAAW,cAAc;AAEzB,MAAM,qBAAiC;CAAE,MAAM;CAAU,WAAW;CAAK,SAAS;CAAI;AAEtF,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;EACD,eAAY;EACZ,UAAU;EACN;EACC;EACE;EACP,GAAI;YAEJ,oBAAC,oBAAoB,WAArB,EAA+B,WAAW,GAAG,uIAAuI,cAAc,gBAAgB,EAAI;EAC7L;AAI/B,QACE,oBAAC,oBAAoB,MAArB;EAAiC;EAAW;EAAI,UAAU;EAAY;EAAQ,GAAI;YAChF,oBAAC,OAAO,QAAR;GACE,WAAW,GACT,yIACA,wHACA,uFACA,cAAc,iBACd,UACD;GACD,eAAY;GACP;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;KAAc,EAA5C,kBAA4C,EACtN;IACY;GAClB;EACS;EAGhC;AACD,YAAY,cAAc;AAE1B,MAAM,kBAAkB,EACtB,UACA,WACA,UACA,KACA,OACA,GAAG,YAGe;CAClB,MAAM,EAAE,gBAAgB,eAAe,eAAe,SAAS,gBAAgB,WAAW,kBAAkB;CAC5G,MAAM,cAAc,OAAO;CAE3B,MAAM,cAAc,MAAM,UAAU;CACpC,MAAM,KAAK,MAAM,IAAI,UAAU,IAAI,GAAG,YAAY,GAAG;CACrD,MAAM,aAAa,iBAAiB,eAAe,SAAS,YAAY,IAAI,QAAQ,SAAS;AAE7F,KAAI,YAAY,WACd,QACE,oBAAC,oBAAoB,MAArB;EAA0B;EAAQ,eAAY;EAA4B,UAAU;EAAgB;EAAS;EAAK,OAAO;EAAa,GAAI;YACxI,oBAAC,OAAD;GAAO,WAAW,GAAG,2GAA2G,cAAc,iBAAiB,eAAe,UAAU;GAAE,eAAY;GAAkC,SAAS;GAC9O;GACK;EACiB;AAI/B,QACE,qBAAC,OAAD;EAAK,WAAW,GAAG,qBAAqB,cAAc,iBAAiB,eAAe,WAAW,YAAY;YAA7G,CACE,oBAAC,aAAD;GAAkB;GAAK,OAAO;GAAiB;GAAgB;GAAY,GAAI;GAAS,GACvF,YACC,oBAAC,OAAD;GAAO,WAAW,GAAG,sCAAsC,gBAAgB,aAAa,SAAS,OAAO;GAAE,SAAS;GAChH;GACK,EAEN;;;AAGV,eAAe,cAAc;AAE7B,MAAM,mBAAmB,EACvB,KACA,WACA,GAAG,YAGe;AAClB,QAAO,oBAAC,OAAD;EAAY;EAAK,eAAY;EAA6B,WAAW,GAAG,6BAA6B,UAAU;EAAE,GAAI;EAAS;;AAEvI,gBAAgB,cAAc"}
package/dist/Select.js CHANGED
@@ -15,7 +15,7 @@ import * as SelectPrimitive from "@radix-ui/react-select";
15
15
  //#region src/components/Select/Select.tsx
16
16
  const Select = (allProps) => {
17
17
  const isControlled = "value" in allProps;
18
- const { align = "start", alignOffset = 0, avoidCollisions = true, className, collisionBoundary, collisionPadding = 10, defaultValue, dropdownWidth = "trigger", emptyMessage = "No options found", errorMessage, disabled, id, label, labelClassName, loadingMessage = "Loading…", messageReserveLines = 1, messageReserveSpace = true, name, onChange, onValueChange, options = [], placeholder = "Select an option", position = "popper", ref, required, side = "bottom", sideOffset = 4, state = "default", value: valueProp, warningMessage, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, ...props } = allProps;
18
+ const { align = "start", alignOffset = 0, avoidCollisions = true, className, collisionBoundary, collisionPadding = 10, defaultValue, dropdownWidth = "trigger", emptyMessage = "No options found", errorMessage, disabled, id, label, labelClassName, loadingMessage = "Loading…", messageReserveLines = 1, messageReserveSpace = false, name, onChange, onValueChange, options = [], placeholder = "Select an option", position = "popper", ref, required, side = "bottom", sideOffset = 4, state = "default", value: valueProp, warningMessage, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, ...props } = allProps;
19
19
  const value = isControlled ? valueProp ?? "" : valueProp;
20
20
  const [open, setOpen] = useState(false);
21
21
  const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(open);
@@ -195,14 +195,14 @@ const Select = (allProps) => {
195
195
  id: errorMessageId,
196
196
  message: isInvalid ? errorMessage ?? null : null,
197
197
  messageReserveLines,
198
- messageReserveSpace
198
+ messageReserveSpace: messageReserveSpace && state === "error"
199
199
  }),
200
200
  /* @__PURE__ */ jsx(WarningMessage, {
201
201
  dataTestId: "spectral-select-warning-message",
202
202
  id: warningMessageId,
203
203
  message: state === "warning" ? warningMessage ?? null : null,
204
204
  messageReserveLines,
205
- messageReserveSpace
205
+ messageReserveSpace: messageReserveSpace && state === "warning"
206
206
  })
207
207
  ]
208
208
  });
@@ -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 = true,\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 role='combobox'\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',\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 dataTestId='spectral-select-error-message' id={errorMessageId} message={isInvalid ? (errorMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace} />\n <WarningMessage dataTestId='spectral-select-warning-message' id={warningMessageId} message={state === 'warning' ? (warningMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace} />\n </div>\n )\n}\nSelect.displayName = 'Select'\n"],"mappings":";;;;;;;;;;;;;;;AA2DA,MAAa,UACX,aAGG;CACH,MAAM,eAAe,WAAW;CAChC,MAAM,EACJ,QAAQ,SACR,cAAc,GACd,kBAAkB,MAClB,WACA,mBACA,mBAAmB,IACnB,cACA,gBAAgB,WAChB,eAAe,oBACf,cACA,UACA,IACA,OACA,gBACA,iBAAiB,YACjB,sBAAsB,GACtB,sBAAsB,MACtB,MACA,UACA,eACA,UAAU,EAAE,EACZ,cAAc,oBACd,WAAW,UACX,KACA,UACA,OAAO,UACP,aAAa,GACb,QAAQ,WACR,OAAO,WACP,gBACA,cAAc,WACd,oBAAoB,iBACpB,GAAG,UACD;CACJ,MAAM,QAAQ,eAAgB,aAAa,KAAM;CACjD,MAAM,CAAC,MAAM,WAAW,SAAS,MAAM;CACvC,MAAM,EAAE,oBAAoB,uBAAuB,+BAA+B,KAAK;CACvF,MAAM,WAAW,eAAe,IAAI,KAAK;CACzC,MAAM,YAAY,GAAG,SAAS;CAC9B,MAAM,iBAAiB,kBAAkB,SAAS;CAClD,MAAM,mBAAmB,GAAG,SAAS;CACrC,MAAM,YAAY,UAAU,WAAW,eAAe,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClI,MAAM,EAAE,mBAAmB,oBAAoB,0BAA0B,uBAAuB;EAC9F;EACA,cAAc;EACf,CAAC;CACF,MAAM,qBAAqB;EACzB,mCAAmC;EACnC,GAAI,aAAa,iBAAiB,EAAE,OAAO,uBAAuB,GAAG,EAAE;EACvE,GAAG;EACH,GAAG;EACJ;CACD,MAAM,aAAa,QAAQ,SAAS;CACpC,MAAM,YAAY,UAAU;CAC5B,MAAM,YAAY,UAAU;CAC5B,MAAM,YAAY,aAAa,OAAO,iBAAiB,UAAU,UAAU;CAC3E,MAAM,EAAE,QAAQ,cAAc,aAAa,QAAQ;CACnD,MAAM,qBAAqB,cAAsB;AAC/C,aAAW,UAAU;AACrB,kBAAgB,UAAU;;CAG5B,MAAM,sBAAsB;AAC1B,MAAI,UACF,QAAO,oBAAC,cAAD;GAAc,eAAY;GAA0B,SAAS;GAAkB;AAGxF,MAAI,QAAQ,WAAW,EACrB,QAAO,oBAAC,YAAD;GAAY,eAAY;GAAwB,SAAS;GAAgB;EAGlF,MAAM,gBAAgB,WAAyB;GAC7C,MAAM,aAAa,UAAU,OAAO;AAEpC,UACE,qBAAC,gBAAgB,MAAjB;IAAsB,WAAW,GAAG,iBAAiB,CAAC,CAAC,OAAO,UAAU,OAAO,WAAW,EAAE,mDAAmD;IAAE,eAAY;IAAuB,UAAU,OAAO;IAA6B,OAAO,OAAO;cAAhP,CACE,oBAAC,gBAAgB,UAAjB;KAA0B,eAAY;KAA4B,WAAU;eACzE,OAAO;KACiB,GAC3B,oBAAC,gBAAgB,eAAjB;KAA+B,eAAY;KAA0C;eACnF,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,eAAD,EAAe,MAAM,IAAM;MACtB;KACuB,EACX;MAT6L,OAAO,MASpM;;AAI3B,SACE,4CACG,UAAU,SAAS,KAClB,4CACG,UAAU,IAAI,aAAa,EAC3B,OAAO,KAAK,OAAO,CAAC,SAAS,KAAK,oBAAC,gBAAgB,WAAjB;GAA2B,WAAU;GAAsC,eAAY;GAA8B,EACvJ,KAGJ,OAAO,QAAQ,OAAO,CAAC,KAAK,CAAC,WAAW,eAAe,eACtD,qBAAC,gBAAgB,OAAjB;GAAuC,eAAY;aAAnD;IACG,aAAa,KAAK,oBAAC,gBAAgB,WAAjB;KAA2B,WAAU;KAAsC,eAAY;KAAoC;IAC9I,oBAAC,OAAD;KAAO,WAAW,GAAG,yDAAyD,eAAe;KAAE,eAAY;eACxG;KACK;IACP,aAAa,KAAK,WAAuB,aAAa,OAAO,CAAC;IACzC;KANI,UAMJ,CACxB,CACD;;AAIP,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,oBAAC,OAAD;IAAO,WAAW,GAAG,gCAAgC,gBAAgB,cAAc,sBAAsB;IAAE,eAAY;IAAwB,SAAS;cACrJ;IACK;GAEV,qBAAC,gBAAgB,MAAjB;IAAsB,eAAY;IAAgC;IAAc,UAAU;IAAkB;IAAM,cAAc;IAAS,eAAe;IAAyB;IAAgB;IAAiB;cAAlN,CACE,oBAAC,gBAAgB,SAAjB;KACE,iBAAe;KACf,iBAAe;KACf,cAAY,aAAa;KACzB;KACA,WAAW,GAAG,kBAAkB,MAAM,MAAM,EAAE,iEAAiE,UAAU;KACzH,aAAU;KACV,cAAY;KACZ,eAAY;KACZ,IAAI;KACC;KACL,MAAK;KACL,OAAO,2BAA2B;KAClC,GAAI;KACJ,GAAI;eAEJ,qBAAC,UAAD;MACE,WAAU;MACV,MAAK;MACL,UAAU;gBAHZ,CAKE,oBAAC,aAAD;OAAa,eAAY;OAAqC;OAAe,GAC7E,oBAAC,gBAAgB,MAAjB;OAAsB;iBACpB,oBAAC,OAAD;QAAK,WAAU;kBAA6C,YAAY,oBAAC,YAAD,EAAY,MAAM,IAAM,IAAG,oBAAC,iBAAD;SAAiB,WAAW,GAAG,qCAAqC,QAAQ,aAAa;SAAE,MAAM;SAAM;QAAO;OAC5L,EAChB;;KACe,GAE1B,oBAAC,gBAAgB,QAAjB,YACE,qBAAC,gBAAgB,SAAjB;KACS;KACM;KACI;KACjB,WAAW,GACT,sGACA,2BAA2B,EAC3B,2KACA,yKACA,6EACA,aAAa,YAAY,kEAC1B;KACkB;KACD;KAClB,4BAA0B;KAC1B,6BAA2B,sBAAsB,WAAW,gBAAgB;KAC5E,IAAI;KACJ,aAAU;KACV,eAAY;KACF;KACV,KAAK;KACC;KACM;KACZ,OAAO;eAvBT;MAyBE,oBAAC,gBAAgB,gBAAjB;OAAgC,WAAU;OAAuD,eAAY;iBAC3G,oBAAC,iBAAD;QAAiB,eAAY;QAAO,WAAU;QAAa,MAAM;QAAM;OACxC;MAEjC,oBAAC,gBAAgB,UAAjB;OAA0B;iBACxB,oBAAC,OAAD;QACE,WAAW,GACT,yCACA,aAAa,aAAa,kBAAkB,YAAY,8HAA8H,iDACvL;QACD,eAAY;kBAEX,eAAe;QACZ;OACmB;MAE3B,oBAAC,gBAAgB,kBAAjB;OAAkC,WAAU;OAAuD,eAAY;iBAC7G,oBAAC,iBAAD;QAAiB,eAAY;QAAO,MAAM;QAAM;OACf;MACX;QACH,EACJ;;GAEvB,oBAAC,cAAD;IAAc,YAAW;IAAgC,IAAI;IAAgB,SAAS,YAAa,gBAAgB,OAAQ;IAA2B;IAA0C;IAAuB;GACvN,oBAAC,gBAAD;IAAgB,YAAW;IAAkC,IAAI;IAAkB,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IAA2B;IAA0C;IAAuB;GACrO;;;AAGV,OAAO,cAAc"}
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 role='combobox'\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',\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 dataTestId='spectral-select-error-message' id={errorMessageId} message={isInvalid ? (errorMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'error'} />\n <WarningMessage dataTestId='spectral-select-warning-message' id={warningMessageId} message={state === 'warning' ? (warningMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'warning'} />\n </div>\n )\n}\nSelect.displayName = 'Select'\n"],"mappings":"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"}
package/dist/Switch.js CHANGED
@@ -10,7 +10,7 @@ import { CheckIcon, XIcon } from "lucide-react";
10
10
 
11
11
  //#region src/components/Switch/Switch.tsx
12
12
  const thumbBase = "bg-switch-thumb--checked data-[state=checked]:bg-switch-thumb pointer-events-none block rounded-full ring-0 transition-transform motion-reduce:transition-none";
13
- const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, label, labelPosition = "right", labelText, messageReserveLines = 1, messageReserveSpace = true, name, onChange, ref, required, state = "default", value, variant, warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, ...props }) => {
13
+ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, label, labelPosition = "right", labelText, messageReserveLines = 1, messageReserveSpace = false, name, onChange, ref, required, state = "default", value, variant, warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, ...props }) => {
14
14
  const switchId = useFormFieldId(id, name);
15
15
  const isDisabled = Boolean(disabled);
16
16
  const resolvedLabelText = labelText ?? label;
@@ -99,14 +99,14 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
99
99
  id: errorMessageId,
100
100
  message: state === "error" ? errorMessage ?? null : null,
101
101
  messageReserveLines,
102
- messageReserveSpace
102
+ messageReserveSpace: messageReserveSpace && state === "error"
103
103
  }),
104
104
  /* @__PURE__ */ jsx(WarningMessage, {
105
105
  dataTestId: "spectral-switch-warning-message",
106
106
  id: warningMessageId,
107
107
  message: state === "warning" ? warningMessage ?? null : null,
108
108
  messageReserveLines,
109
- messageReserveSpace
109
+ messageReserveSpace: messageReserveSpace && state === "warning"
110
110
  })
111
111
  ]
112
112
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","names":["SwitchBase"],"sources":["../src/components/Switch/Switch.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { CheckIcon, XIcon } from 'lucide-react'\nimport { type Ref } from 'react'\nimport { Switch as SwitchBase, SwitchThumb, type SwitchProps as SwitchBaseProps } from './SwitchBase'\n\ntype SwitchVisualState = Exclude<FormFieldState, 'disabled'>\n\nexport type SwitchProps = Omit<SwitchBaseProps, 'onCheckedChange'> & {\n 'aria-describedby'?: string\n 'aria-label'?: string\n errorMessage?: BaseFormFieldProps['errorMessage']\n hideLabel?: boolean\n id?: string\n label?: string\n labelPosition?: 'left' | 'right'\n labelText?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (checked: boolean) => void\n ref?: Ref<HTMLButtonElement>\n required?: boolean\n state?: SwitchVisualState\n value?: string\n variant?: 'default' | 'squared' | 'permanent-indicator'\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst thumbBase = 'bg-switch-thumb--checked data-[state=checked]:bg-switch-thumb pointer-events-none block rounded-full ring-0 transition-transform motion-reduce:transition-none'\n\nexport const Switch = ({\n className,\n disabled,\n errorMessage,\n hideLabel = false,\n id,\n label,\n labelPosition = 'right',\n labelText,\n messageReserveLines = 1,\n messageReserveSpace = true,\n name,\n onChange,\n ref,\n required,\n state = 'default',\n value,\n variant,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n ...props\n}: SwitchProps) => {\n const switchId = useFormFieldId(id, name)\n const isDisabled = Boolean(disabled)\n const resolvedLabelText = labelText ?? label\n const errorMessageId = `${switchId}-error`\n const warningMessageId = `${switchId}-warning`\n const messageId = state === 'error' && errorMessage && errorMessageId ? errorMessageId : state === 'warning' && warningMessage && warningMessageId ? warningMessageId : undefined\n const isSquared = variant === 'squared'\n const isPermanentIndicator = variant === 'permanent-indicator'\n\n return (\n <div className='flex items-center' data-testid='spectral-switch-container' data-state={state}>\n {labelPosition === 'left' && !hideLabel && resolvedLabelText && (\n <Label className='mr-2' data-testid='spectral-switch-label-left' htmlFor={switchId}>\n {resolvedLabelText}\n </Label>\n )}\n\n {isPermanentIndicator ? (\n <div className='h-7 text-sm font-medium relative inline-grid grid-cols-[1fr_1fr] items-center'>\n <SwitchBase\n aria-required={required}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n className={cn(\n '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',\n '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',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n data-testid='spectral-switch'\n disabled={isDisabled}\n id={switchId}\n name={name}\n onCheckedChange={onChange}\n ref={ref}\n required={required}\n value={value}\n {...props}\n >\n <SwitchThumb className={cn(thumbBase, 'size-6.5 shadow-xs relative z-10 duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] data-[state=checked]:translate-x-[26px] motion-reduce:duration-0 data-[state=checked]:rtl:translate-x-[-26px]')} />\n </SwitchBase>\n <span className='ml-0.5 min-w-8 peer-data-[state=unchecked]:translate-x-6 peer-data-[state=unchecked]:rtl:-translate-x-6 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:invisible motion-reduce:transition-none motion-reduce:duration-0'>\n <XIcon aria-hidden='true' className='size-4' />\n </span>\n <span className='min-w-8 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:-translate-x-full peer-data-[state=checked]:text-background peer-data-[state=unchecked]:invisible motion-reduce:transition-none motion-reduce:duration-0 peer-data-[state=checked]:rtl:translate-x-full'>\n <CheckIcon aria-hidden='true' className='size-4' />\n </span>\n </div>\n ) : (\n <SwitchBase\n aria-required={required}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n className={cn(\n isSquared\n ? 'peer h-6 w-10 rounded-sm focus-visible:ring-black inline-flex shrink-0 items-center border-2 border-transparent transition-all 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]'\n : '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',\n className,\n )}\n data-testid='spectral-switch'\n disabled={isDisabled}\n id={switchId}\n name={name}\n onCheckedChange={onChange}\n ref={ref}\n required={required}\n value={value}\n {...props}\n >\n <SwitchThumb className={cn(thumbBase, isSquared ? 'size-5 shadow-xs data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4' : 'h-5 w-5 shadow-lg data-[state=checked]:translate-x-4')} />\n </SwitchBase>\n )}\n\n {labelPosition === 'right' && !hideLabel && resolvedLabelText && (\n <Label className='ml-2' data-testid='spectral-switch-label-right' htmlFor={switchId} id={`${switchId}-label`}>\n {resolvedLabelText}\n </Label>\n )}\n\n {hideLabel && resolvedLabelText && (\n <Label className='sr-only' data-testid='spectral-switch-label-hidden' htmlFor={switchId}>\n {resolvedLabelText}\n </Label>\n )}\n <ErrorMessage dataTestId='spectral-switch-error-message' id={errorMessageId} message={state === 'error' ? (errorMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace} />\n <WarningMessage dataTestId='spectral-switch-warning-message' id={warningMessageId} message={state === 'warning' ? (warningMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace} />\n </div>\n )\n}\nSwitch.displayName = 'Switch'\n"],"mappings":";;;;;;;;;;;AA6BA,MAAM,YAAY;AAElB,MAAa,UAAU,EACrB,WACA,UACA,cACA,YAAY,OACZ,IACA,OACA,gBAAgB,SAChB,WACA,sBAAsB,GACtB,sBAAsB,MACtB,MACA,UACA,KACA,UACA,QAAQ,WACR,OACA,SACA,gBACA,oBAAoB,iBACpB,cAAc,WACd,GAAG,YACc;CACjB,MAAM,WAAW,eAAe,IAAI,KAAK;CACzC,MAAM,aAAa,QAAQ,SAAS;CACpC,MAAM,oBAAoB,aAAa;CACvC,MAAM,iBAAiB,GAAG,SAAS;CACnC,MAAM,mBAAmB,GAAG,SAAS;CACrC,MAAM,YAAY,UAAU,WAAW,gBAAgB,iBAAiB,iBAAiB,UAAU,aAAa,kBAAkB,mBAAmB,mBAAmB;CACxK,MAAM,YAAY,YAAY;AAG9B,QACE,qBAAC,OAAD;EAAK,WAAU;EAAoB,eAAY;EAA4B,cAAY;YAAvF;GACG,kBAAkB,UAAU,CAAC,aAAa,qBACzC,oBAAC,OAAD;IAAO,WAAU;IAAO,eAAY;IAA6B,SAAS;cACvE;IACK;GAPe,YAAY,wBAWnC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAACA,UAAD;MACE,iBAAe;MACf,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;MAC5E,gBAAc,UAAU,UAAU,OAAO;MACzC,cAAY,cAAc,YAAY,oBAAoB;MAC1D,WAAW,GACT,kNACA,oKACA,mDACA,UACD;MACD,eAAY;MACZ,UAAU;MACV,IAAI;MACE;MACN,iBAAiB;MACZ;MACK;MACH;MACP,GAAI;gBAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,gMAAgM,EAAI;MAC/N;KACb,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,OAAD;OAAO,eAAY;OAAO,WAAU;OAAW;MAC1C;KACP,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD;OAAW,eAAY;OAAO,WAAU;OAAW;MAC9C;KACH;QAEN,oBAACA,UAAD;IACE,iBAAe;IACf,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;IAC5E,gBAAc,UAAU,UAAU,OAAO;IACzC,cAAY,cAAc,YAAY,oBAAoB;IAC1D,WAAW,GACT,YACI,+TACA,gZACJ,UACD;IACD,eAAY;IACZ,UAAU;IACV,IAAI;IACE;IACN,iBAAiB;IACZ;IACK;IACH;IACP,GAAI;cAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,YAAY,gGAAgG,uDAAuD,EAAI;IAClM;GAGd,kBAAkB,WAAW,CAAC,aAAa,qBAC1C,oBAAC,OAAD;IAAO,WAAU;IAAO,eAAY;IAA8B,SAAS;IAAU,IAAI,GAAG,SAAS;cAClG;IACK;GAGT,aAAa,qBACZ,oBAAC,OAAD;IAAO,WAAU;IAAU,eAAY;IAA+B,SAAS;cAC5E;IACK;GAEV,oBAAC,cAAD;IAAc,YAAW;IAAgC,IAAI;IAAgB,SAAS,UAAU,UAAW,gBAAgB,OAAQ;IAA2B;IAA0C;IAAuB;GAC/N,oBAAC,gBAAD;IAAgB,YAAW;IAAkC,IAAI;IAAkB,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IAA2B;IAA0C;IAAuB;GACrO;;;AAGV,OAAO,cAAc"}
1
+ {"version":3,"file":"Switch.js","names":["SwitchBase"],"sources":["../src/components/Switch/Switch.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { CheckIcon, XIcon } from 'lucide-react'\nimport { type Ref } from 'react'\nimport { Switch as SwitchBase, SwitchThumb, type SwitchProps as SwitchBaseProps } from './SwitchBase'\n\ntype SwitchVisualState = Exclude<FormFieldState, 'disabled'>\n\nexport type SwitchProps = Omit<SwitchBaseProps, 'onCheckedChange'> & {\n 'aria-describedby'?: string\n 'aria-label'?: string\n errorMessage?: BaseFormFieldProps['errorMessage']\n hideLabel?: boolean\n id?: string\n label?: string\n labelPosition?: 'left' | 'right'\n labelText?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (checked: boolean) => void\n ref?: Ref<HTMLButtonElement>\n required?: boolean\n state?: SwitchVisualState\n value?: string\n variant?: 'default' | 'squared' | 'permanent-indicator'\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst thumbBase = 'bg-switch-thumb--checked data-[state=checked]:bg-switch-thumb pointer-events-none block rounded-full ring-0 transition-transform motion-reduce:transition-none'\n\nexport const Switch = ({\n className,\n disabled,\n errorMessage,\n hideLabel = false,\n id,\n label,\n labelPosition = 'right',\n labelText,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n ref,\n required,\n state = 'default',\n value,\n variant,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n ...props\n}: SwitchProps) => {\n const switchId = useFormFieldId(id, name)\n const isDisabled = Boolean(disabled)\n const resolvedLabelText = labelText ?? label\n const errorMessageId = `${switchId}-error`\n const warningMessageId = `${switchId}-warning`\n const messageId = state === 'error' && errorMessage && errorMessageId ? errorMessageId : state === 'warning' && warningMessage && warningMessageId ? warningMessageId : undefined\n const isSquared = variant === 'squared'\n const isPermanentIndicator = variant === 'permanent-indicator'\n\n return (\n <div className='flex items-center' data-testid='spectral-switch-container' data-state={state}>\n {labelPosition === 'left' && !hideLabel && resolvedLabelText && (\n <Label className='mr-2' data-testid='spectral-switch-label-left' htmlFor={switchId}>\n {resolvedLabelText}\n </Label>\n )}\n\n {isPermanentIndicator ? (\n <div className='h-7 text-sm font-medium relative inline-grid grid-cols-[1fr_1fr] items-center'>\n <SwitchBase\n aria-required={required}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n className={cn(\n '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',\n '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',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n data-testid='spectral-switch'\n disabled={isDisabled}\n id={switchId}\n name={name}\n onCheckedChange={onChange}\n ref={ref}\n required={required}\n value={value}\n {...props}\n >\n <SwitchThumb className={cn(thumbBase, 'size-6.5 shadow-xs relative z-10 duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] data-[state=checked]:translate-x-[26px] motion-reduce:duration-0 data-[state=checked]:rtl:translate-x-[-26px]')} />\n </SwitchBase>\n <span className='ml-0.5 min-w-8 peer-data-[state=unchecked]:translate-x-6 peer-data-[state=unchecked]:rtl:-translate-x-6 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:invisible motion-reduce:transition-none motion-reduce:duration-0'>\n <XIcon aria-hidden='true' className='size-4' />\n </span>\n <span className='min-w-8 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:-translate-x-full peer-data-[state=checked]:text-background peer-data-[state=unchecked]:invisible motion-reduce:transition-none motion-reduce:duration-0 peer-data-[state=checked]:rtl:translate-x-full'>\n <CheckIcon aria-hidden='true' className='size-4' />\n </span>\n </div>\n ) : (\n <SwitchBase\n aria-required={required}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n className={cn(\n isSquared\n ? 'peer h-6 w-10 rounded-sm focus-visible:ring-black inline-flex shrink-0 items-center border-2 border-transparent transition-all 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]'\n : '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',\n className,\n )}\n data-testid='spectral-switch'\n disabled={isDisabled}\n id={switchId}\n name={name}\n onCheckedChange={onChange}\n ref={ref}\n required={required}\n value={value}\n {...props}\n >\n <SwitchThumb className={cn(thumbBase, isSquared ? 'size-5 shadow-xs data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4' : 'h-5 w-5 shadow-lg data-[state=checked]:translate-x-4')} />\n </SwitchBase>\n )}\n\n {labelPosition === 'right' && !hideLabel && resolvedLabelText && (\n <Label className='ml-2' data-testid='spectral-switch-label-right' htmlFor={switchId} id={`${switchId}-label`}>\n {resolvedLabelText}\n </Label>\n )}\n\n {hideLabel && resolvedLabelText && (\n <Label className='sr-only' data-testid='spectral-switch-label-hidden' htmlFor={switchId}>\n {resolvedLabelText}\n </Label>\n )}\n <ErrorMessage dataTestId='spectral-switch-error-message' id={errorMessageId} message={state === 'error' ? (errorMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'error'} />\n <WarningMessage dataTestId='spectral-switch-warning-message' id={warningMessageId} message={state === 'warning' ? (warningMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'warning'} />\n </div>\n )\n}\nSwitch.displayName = 'Switch'\n"],"mappings":";;;;;;;;;;;AA6BA,MAAM,YAAY;AAElB,MAAa,UAAU,EACrB,WACA,UACA,cACA,YAAY,OACZ,IACA,OACA,gBAAgB,SAChB,WACA,sBAAsB,GACtB,sBAAsB,OACtB,MACA,UACA,KACA,UACA,QAAQ,WACR,OACA,SACA,gBACA,oBAAoB,iBACpB,cAAc,WACd,GAAG,YACc;CACjB,MAAM,WAAW,eAAe,IAAI,KAAK;CACzC,MAAM,aAAa,QAAQ,SAAS;CACpC,MAAM,oBAAoB,aAAa;CACvC,MAAM,iBAAiB,GAAG,SAAS;CACnC,MAAM,mBAAmB,GAAG,SAAS;CACrC,MAAM,YAAY,UAAU,WAAW,gBAAgB,iBAAiB,iBAAiB,UAAU,aAAa,kBAAkB,mBAAmB,mBAAmB;CACxK,MAAM,YAAY,YAAY;AAG9B,QACE,qBAAC,OAAD;EAAK,WAAU;EAAoB,eAAY;EAA4B,cAAY;YAAvF;GACG,kBAAkB,UAAU,CAAC,aAAa,qBACzC,oBAAC,OAAD;IAAO,WAAU;IAAO,eAAY;IAA6B,SAAS;cACvE;IACK;GAPe,YAAY,wBAWnC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAACA,UAAD;MACE,iBAAe;MACf,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;MAC5E,gBAAc,UAAU,UAAU,OAAO;MACzC,cAAY,cAAc,YAAY,oBAAoB;MAC1D,WAAW,GACT,kNACA,oKACA,mDACA,UACD;MACD,eAAY;MACZ,UAAU;MACV,IAAI;MACE;MACN,iBAAiB;MACZ;MACK;MACH;MACP,GAAI;gBAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,gMAAgM,EAAI;MAC/N;KACb,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,OAAD;OAAO,eAAY;OAAO,WAAU;OAAW;MAC1C;KACP,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD;OAAW,eAAY;OAAO,WAAU;OAAW;MAC9C;KACH;QAEN,oBAACA,UAAD;IACE,iBAAe;IACf,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;IAC5E,gBAAc,UAAU,UAAU,OAAO;IACzC,cAAY,cAAc,YAAY,oBAAoB;IAC1D,WAAW,GACT,YACI,+TACA,gZACJ,UACD;IACD,eAAY;IACZ,UAAU;IACV,IAAI;IACE;IACN,iBAAiB;IACZ;IACK;IACH;IACP,GAAI;cAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,YAAY,gGAAgG,uDAAuD,EAAI;IAClM;GAGd,kBAAkB,WAAW,CAAC,aAAa,qBAC1C,oBAAC,OAAD;IAAO,WAAU;IAAO,eAAY;IAA8B,SAAS;IAAU,IAAI,GAAG,SAAS;cAClG;IACK;GAGT,aAAa,qBACZ,oBAAC,OAAD;IAAO,WAAU;IAAU,eAAY;IAA+B,SAAS;cAC5E;IACK;GAEV,oBAAC,cAAD;IAAc,YAAW;IAAgC,IAAI;IAAgB,SAAS,UAAU,UAAW,gBAAgB,OAAQ;IAA2B;IAAqB,qBAAqB,uBAAuB,UAAU;IAAW;GACpP,oBAAC,gBAAD;IAAgB,YAAW;IAAkC,IAAI;IAAkB,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IAA2B;IAAqB,qBAAqB,uBAAuB,UAAU;IAAa;GAC5P;;;AAGV,OAAO,cAAc"}
@@ -12,7 +12,7 @@ type TextareaProps = Omit<ComponentProps<'textarea'>, 'onChange'> & {
12
12
  label: string;
13
13
  labelClassName?: string;
14
14
  maxLength?: number | undefined; /** Number of message lines to reserve (default: 1). */
15
- messageReserveLines?: number; /** Whether to keep message space reserved when hidden (default: true). */
15
+ messageReserveLines?: number; /** Whether to keep message space reserved when hidden (default: false). */
16
16
  messageReserveSpace?: boolean;
17
17
  name: string;
18
18
  onBlur?: (e: FocusEvent<HTMLTextAreaElement>) => void;
package/dist/Textarea.js CHANGED
@@ -19,7 +19,7 @@ const getCounterClasses = (currentLength, maxLength) => {
19
19
  return cn("absolute bottom-2 right-3 text-xs pointer-events-none z-10 tabular-nums", currentLength >= maxLength ? "text-danger-400" : "text-text-secondary");
20
20
  };
21
21
  const Textarea = (allProps) => {
22
- const { ref, autoComplete, className, defaultValue, disabled, errorMessage, id, label, labelClassName, maxLength = 280, messageReserveLines = 1, messageReserveSpace = true, name, onBlur, onChange, onFocus, placeholder, required, state = "default", value: valueProp, warningMessage, ...props } = allProps;
22
+ const { ref, autoComplete, className, defaultValue, disabled, errorMessage, id, label, labelClassName, maxLength = 280, messageReserveLines = 1, messageReserveSpace = false, name, onBlur, onChange, onFocus, placeholder, required, state = "default", value: valueProp, warningMessage, ...props } = allProps;
23
23
  const textareaId = useFormFieldId(id, name);
24
24
  const errorMessageId = getErrorMessageId(textareaId);
25
25
  const warningMessageId = `${textareaId}-warning`;
@@ -105,14 +105,14 @@ const Textarea = (allProps) => {
105
105
  id: errorMessageId,
106
106
  message: state === "error" ? errorMessage : null,
107
107
  messageReserveLines,
108
- messageReserveSpace
108
+ messageReserveSpace: messageReserveSpace && state === "error"
109
109
  }),
110
110
  /* @__PURE__ */ jsx(WarningMessage, {
111
111
  dataTestId: "spectral-textarea-warning-message",
112
112
  id: warningMessageId,
113
113
  message: state === "warning" ? warningMessage : null,
114
114
  messageReserveLines,
115
- messageReserveSpace
115
+ messageReserveSpace: messageReserveSpace && state === "warning"
116
116
  })
117
117
  ]
118
118
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.js","names":[],"sources":["../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, getAriaProps, getErrorMessageId, getTextareaClasses, useFormFieldId, useFormFieldState, WarningMessage, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useRef, type ComponentProps, type CSSProperties, type FocusEvent, type Ref } from 'react'\nimport { useTextarea } from './TextareaUtils'\n\nexport type TextareaState = FormFieldState\n\ntype AutoCompleteValue = 'on' | 'off' | 'name' | 'email' | 'username' | 'street-address' | (string & {})\n\nexport type TextareaProps = Omit<ComponentProps<'textarea'>, 'onChange'> & {\n className?: string | undefined\n errorMessage?: BaseFormFieldProps['errorMessage']\n id?: string | undefined\n label: string\n labelClassName?: string\n maxLength?: number | undefined\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: true). */\n messageReserveSpace?: boolean\n name: string\n onBlur?: (e: FocusEvent<HTMLTextAreaElement>) => void\n onChange?: (value: string) => void\n onFocus?: (e: FocusEvent<HTMLTextAreaElement>) => void\n placeholder?: string | undefined\n required?: boolean\n state?: TextareaState\n value?: string | undefined\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst LOADING_ICON_CLASSES = 'absolute right-4 top-4'\n\nconst getAutoCompleteValue = (autoComplete?: string): AutoCompleteValue => {\n if (autoComplete) return autoComplete\n return 'off'\n}\n\nconst getCounterClasses = (currentLength: number, maxLength: number): string => {\n const baseClasses = 'absolute bottom-2 right-3 text-xs pointer-events-none z-10 tabular-nums'\n const colorClass = currentLength >= maxLength ? 'text-danger-400' : 'text-text-secondary'\n return cn(baseClasses, colorClass)\n}\n\nexport const Textarea = (\n allProps: TextareaProps & {\n ref?: Ref<HTMLTextAreaElement>\n },\n) => {\n const {\n ref,\n autoComplete,\n className,\n defaultValue,\n disabled,\n errorMessage,\n id,\n label,\n labelClassName,\n maxLength = 280,\n messageReserveLines = 1,\n messageReserveSpace = true,\n name,\n onBlur,\n onChange,\n onFocus,\n placeholder,\n required,\n state = 'default',\n value: valueProp,\n warningMessage,\n ...props\n } = allProps\n const textareaId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(textareaId)\n const warningMessageId = `${textareaId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const internalRef = useRef<HTMLTextAreaElement>(null)\n const textareaRef = ref ?? internalRef\n const normalizedDefaultValue = typeof defaultValue === 'string' ? defaultValue : defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ''\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue: normalizedDefaultValue,\n onChange,\n })\n\n const { handleFocus, handleBlur, handleChange, handlePaste } = useTextarea({\n maxLength,\n value,\n onChange: setValue,\n onFocus,\n onBlur,\n })\n\n const { isDisabled, isLoading } = useFormFieldState(disabled, state)\n const ariaProps = getAriaProps(state, props['aria-describedby'], required, messageId)\n const currentLength = value?.length || 0\n const textareaClasses = getTextareaClasses(state, className)\n\n const getCSSCustomProperties = () => ({\n '--textarea-min-height': '6rem',\n '--textarea-max-height': '12rem',\n '--textarea-border-radius': '0.5rem',\n })\n\n return (\n <div className='w-full'>\n {label && (\n <Label data-testid='spectral-textarea-label' htmlFor={textareaId} className={cn('mb-2 block', isDisabled && 'cursor-not-allowed opacity-50', labelClassName)}>\n {label}\n </Label>\n )}\n <div className='relative'>\n <textarea\n aria-multiline='true'\n autoComplete={getAutoCompleteValue(autoComplete)}\n className={textareaClasses}\n data-state={state}\n data-testid='spectral-textarea'\n disabled={isDisabled}\n id={textareaId}\n name={name}\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n onPaste={handlePaste}\n placeholder={placeholder}\n ref={textareaRef}\n required={required}\n spellCheck='true'\n style={getCSSCustomProperties() as CSSProperties}\n value={value}\n {...ariaProps}\n {...props}\n />\n\n {isLoading && (\n <div className={LOADING_ICON_CLASSES} data-testid='spectral-textarea-loading-icon'>\n <LoaderIcon size={24} />\n </div>\n )}\n\n <div\n // oxlint will throw an error when passing ternaries in for aria-label\n aria-label={currentLength + ' of ' + maxLength + ' characters used'}\n aria-live='polite'\n className={getCounterClasses(currentLength, maxLength)}\n data-testid='spectral-textarea-counter'\n role='status'\n >\n {currentLength}/{maxLength}\n </div>\n </div>\n\n <ErrorMessage dataTestId='spectral-textarea-error-message' id={errorMessageId} message={state === 'error' ? errorMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace} />\n <WarningMessage dataTestId='spectral-textarea-warning-message' id={warningMessageId} message={state === 'warning' ? warningMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace} />\n </div>\n )\n}\nTextarea.displayName = 'Textarea'\n"],"mappings":";;;;;;;;;;;;AAkCA,MAAM,uBAAuB;AAE7B,MAAM,wBAAwB,iBAA6C;AACzE,KAAI,aAAc,QAAO;AACzB,QAAO;;AAGT,MAAM,qBAAqB,eAAuB,cAA8B;AAG9E,QAAO,GAAG,2EADS,iBAAiB,YAAY,oBAAoB,sBAClC;;AAGpC,MAAa,YACX,aAGG;CACH,MAAM,EACJ,KACA,cACA,WACA,cACA,UACA,cACA,IACA,OACA,gBACA,YAAY,KACZ,sBAAsB,GACtB,sBAAsB,MACtB,MACA,QACA,UACA,SACA,aACA,UACA,QAAQ,WACR,OAAO,WACP,gBACA,GAAG,UACD;CACJ,MAAM,aAAa,eAAe,IAAI,KAAK;CAC3C,MAAM,iBAAiB,kBAAkB,WAAW;CACpD,MAAM,mBAAmB,GAAG,WAAW;CACvC,MAAM,YAAY,UAAU,UAAU,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClH,MAAM,cAAc,OAA4B,KAAK;CACrD,MAAM,cAAc,OAAO;CAE3B,MAAM,CAAC,OAAO,YAAY,qBAA6B;EACrD,OAAO;EACP,cAH6B,OAAO,iBAAiB,WAAW,eAAe,iBAAiB,UAAa,iBAAiB,OAAO,OAAO,aAAa,GAAG;EAI5J;EACD,CAAC;CAEF,MAAM,EAAE,aAAa,YAAY,cAAc,gBAAgB,YAAY;EACzE;EACA;EACA,UAAU;EACV;EACA;EACD,CAAC;CAEF,MAAM,EAAE,YAAY,cAAc,kBAAkB,UAAU,MAAM;CACpE,MAAM,YAAY,aAAa,OAAO,MAAM,qBAAqB,UAAU,UAAU;CACrF,MAAM,gBAAgB,OAAO,UAAU;CACvC,MAAM,kBAAkB,mBAAmB,OAAO,UAAU;CAE5D,MAAM,gCAAgC;EACpC,yBAAyB;EACzB,yBAAyB;EACzB,4BAA4B;EAC7B;AAED,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,oBAAC,OAAD;IAAO,eAAY;IAA0B,SAAS;IAAY,WAAW,GAAG,cAAc,cAAc,iCAAiC,eAAe;cACzJ;IACK;GAEV,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,YAAD;MACE,kBAAe;MACf,cAAc,qBAAqB,aAAa;MAChD,WAAW;MACX,cAAY;MACZ,eAAY;MACZ,UAAU;MACV,IAAI;MACE;MACN,QAAQ;MACR,UAAU;MACV,SAAS;MACT,SAAS;MACI;MACb,KAAK;MACK;MACV,YAAW;MACX,OAAO,wBAAwB;MACxB;MACP,GAAI;MACJ,GAAI;MACJ;KAED,aACC,oBAAC,OAAD;MAAK,WAAW;MAAsB,eAAY;gBAChD,oBAAC,YAAD,EAAY,MAAM,IAAM;MACpB;KAGR,qBAAC,OAAD;MAEE,cAAY,gBAAgB,SAAS,YAAY;MACjD,aAAU;MACV,WAAW,kBAAkB,eAAe,UAAU;MACtD,eAAY;MACZ,MAAK;gBANP;OAQG;OAAc;OAAE;OACb;;KACF;;GAEN,oBAAC,cAAD;IAAc,YAAW;IAAkC,IAAI;IAAgB,SAAS,UAAU,UAAU,eAAe;IAA2B;IAA0C;IAAuB;GACvN,oBAAC,gBAAD;IAAgB,YAAW;IAAoC,IAAI;IAAkB,SAAS,UAAU,YAAY,iBAAiB;IAA2B;IAA0C;IAAuB;GAC7N;;;AAGV,SAAS,cAAc"}
1
+ {"version":3,"file":"Textarea.js","names":[],"sources":["../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, getAriaProps, getErrorMessageId, getTextareaClasses, useFormFieldId, useFormFieldState, WarningMessage, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useRef, type ComponentProps, type CSSProperties, type FocusEvent, type Ref } from 'react'\nimport { useTextarea } from './TextareaUtils'\n\nexport type TextareaState = FormFieldState\n\ntype AutoCompleteValue = 'on' | 'off' | 'name' | 'email' | 'username' | 'street-address' | (string & {})\n\nexport type TextareaProps = Omit<ComponentProps<'textarea'>, 'onChange'> & {\n className?: string | undefined\n errorMessage?: BaseFormFieldProps['errorMessage']\n id?: string | undefined\n label: string\n labelClassName?: string\n maxLength?: number | undefined\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: false). */\n messageReserveSpace?: boolean\n name: string\n onBlur?: (e: FocusEvent<HTMLTextAreaElement>) => void\n onChange?: (value: string) => void\n onFocus?: (e: FocusEvent<HTMLTextAreaElement>) => void\n placeholder?: string | undefined\n required?: boolean\n state?: TextareaState\n value?: string | undefined\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst LOADING_ICON_CLASSES = 'absolute right-4 top-4'\n\nconst getAutoCompleteValue = (autoComplete?: string): AutoCompleteValue => {\n if (autoComplete) return autoComplete\n return 'off'\n}\n\nconst getCounterClasses = (currentLength: number, maxLength: number): string => {\n const baseClasses = 'absolute bottom-2 right-3 text-xs pointer-events-none z-10 tabular-nums'\n const colorClass = currentLength >= maxLength ? 'text-danger-400' : 'text-text-secondary'\n return cn(baseClasses, colorClass)\n}\n\nexport const Textarea = (\n allProps: TextareaProps & {\n ref?: Ref<HTMLTextAreaElement>\n },\n) => {\n const {\n ref,\n autoComplete,\n className,\n defaultValue,\n disabled,\n errorMessage,\n id,\n label,\n labelClassName,\n maxLength = 280,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onBlur,\n onChange,\n onFocus,\n placeholder,\n required,\n state = 'default',\n value: valueProp,\n warningMessage,\n ...props\n } = allProps\n const textareaId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(textareaId)\n const warningMessageId = `${textareaId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const internalRef = useRef<HTMLTextAreaElement>(null)\n const textareaRef = ref ?? internalRef\n const normalizedDefaultValue = typeof defaultValue === 'string' ? defaultValue : defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ''\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue: normalizedDefaultValue,\n onChange,\n })\n\n const { handleFocus, handleBlur, handleChange, handlePaste } = useTextarea({\n maxLength,\n value,\n onChange: setValue,\n onFocus,\n onBlur,\n })\n\n const { isDisabled, isLoading } = useFormFieldState(disabled, state)\n const ariaProps = getAriaProps(state, props['aria-describedby'], required, messageId)\n const currentLength = value?.length || 0\n const textareaClasses = getTextareaClasses(state, className)\n\n const getCSSCustomProperties = () => ({\n '--textarea-min-height': '6rem',\n '--textarea-max-height': '12rem',\n '--textarea-border-radius': '0.5rem',\n })\n\n return (\n <div className='w-full'>\n {label && (\n <Label data-testid='spectral-textarea-label' htmlFor={textareaId} className={cn('mb-2 block', isDisabled && 'cursor-not-allowed opacity-50', labelClassName)}>\n {label}\n </Label>\n )}\n <div className='relative'>\n <textarea\n aria-multiline='true'\n autoComplete={getAutoCompleteValue(autoComplete)}\n className={textareaClasses}\n data-state={state}\n data-testid='spectral-textarea'\n disabled={isDisabled}\n id={textareaId}\n name={name}\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n onPaste={handlePaste}\n placeholder={placeholder}\n ref={textareaRef}\n required={required}\n spellCheck='true'\n style={getCSSCustomProperties() as CSSProperties}\n value={value}\n {...ariaProps}\n {...props}\n />\n\n {isLoading && (\n <div className={LOADING_ICON_CLASSES} data-testid='spectral-textarea-loading-icon'>\n <LoaderIcon size={24} />\n </div>\n )}\n\n <div\n // oxlint will throw an error when passing ternaries in for aria-label\n aria-label={currentLength + ' of ' + maxLength + ' characters used'}\n aria-live='polite'\n className={getCounterClasses(currentLength, maxLength)}\n data-testid='spectral-textarea-counter'\n role='status'\n >\n {currentLength}/{maxLength}\n </div>\n </div>\n\n <ErrorMessage dataTestId='spectral-textarea-error-message' id={errorMessageId} message={state === 'error' ? errorMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'error'} />\n <WarningMessage dataTestId='spectral-textarea-warning-message' id={warningMessageId} message={state === 'warning' ? warningMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'warning'} />\n </div>\n )\n}\nTextarea.displayName = 'Textarea'\n"],"mappings":";;;;;;;;;;;;AAkCA,MAAM,uBAAuB;AAE7B,MAAM,wBAAwB,iBAA6C;AACzE,KAAI,aAAc,QAAO;AACzB,QAAO;;AAGT,MAAM,qBAAqB,eAAuB,cAA8B;AAG9E,QAAO,GAAG,2EADS,iBAAiB,YAAY,oBAAoB,sBAClC;;AAGpC,MAAa,YACX,aAGG;CACH,MAAM,EACJ,KACA,cACA,WACA,cACA,UACA,cACA,IACA,OACA,gBACA,YAAY,KACZ,sBAAsB,GACtB,sBAAsB,OACtB,MACA,QACA,UACA,SACA,aACA,UACA,QAAQ,WACR,OAAO,WACP,gBACA,GAAG,UACD;CACJ,MAAM,aAAa,eAAe,IAAI,KAAK;CAC3C,MAAM,iBAAiB,kBAAkB,WAAW;CACpD,MAAM,mBAAmB,GAAG,WAAW;CACvC,MAAM,YAAY,UAAU,UAAU,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClH,MAAM,cAAc,OAA4B,KAAK;CACrD,MAAM,cAAc,OAAO;CAE3B,MAAM,CAAC,OAAO,YAAY,qBAA6B;EACrD,OAAO;EACP,cAH6B,OAAO,iBAAiB,WAAW,eAAe,iBAAiB,UAAa,iBAAiB,OAAO,OAAO,aAAa,GAAG;EAI5J;EACD,CAAC;CAEF,MAAM,EAAE,aAAa,YAAY,cAAc,gBAAgB,YAAY;EACzE;EACA;EACA,UAAU;EACV;EACA;EACD,CAAC;CAEF,MAAM,EAAE,YAAY,cAAc,kBAAkB,UAAU,MAAM;CACpE,MAAM,YAAY,aAAa,OAAO,MAAM,qBAAqB,UAAU,UAAU;CACrF,MAAM,gBAAgB,OAAO,UAAU;CACvC,MAAM,kBAAkB,mBAAmB,OAAO,UAAU;CAE5D,MAAM,gCAAgC;EACpC,yBAAyB;EACzB,yBAAyB;EACzB,4BAA4B;EAC7B;AAED,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,oBAAC,OAAD;IAAO,eAAY;IAA0B,SAAS;IAAY,WAAW,GAAG,cAAc,cAAc,iCAAiC,eAAe;cACzJ;IACK;GAEV,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,YAAD;MACE,kBAAe;MACf,cAAc,qBAAqB,aAAa;MAChD,WAAW;MACX,cAAY;MACZ,eAAY;MACZ,UAAU;MACV,IAAI;MACE;MACN,QAAQ;MACR,UAAU;MACV,SAAS;MACT,SAAS;MACI;MACb,KAAK;MACK;MACV,YAAW;MACX,OAAO,wBAAwB;MACxB;MACP,GAAI;MACJ,GAAI;MACJ;KAED,aACC,oBAAC,OAAD;MAAK,WAAW;MAAsB,eAAY;gBAChD,oBAAC,YAAD,EAAY,MAAM,IAAM;MACpB;KAGR,qBAAC,OAAD;MAEE,cAAY,gBAAgB,SAAS,YAAY;MACjD,aAAU;MACV,WAAW,kBAAkB,eAAe,UAAU;MACtD,eAAY;MACZ,MAAK;gBANP;OAQG;OAAc;OAAE;OACb;;KACF;;GAEN,oBAAC,cAAD;IAAc,YAAW;IAAkC,IAAI;IAAgB,SAAS,UAAU,UAAU,eAAe;IAA2B;IAAqB,qBAAqB,uBAAuB,UAAU;IAAW;GAC5O,oBAAC,gBAAD;IAAgB,YAAW;IAAoC,IAAI;IAAkB,SAAS,UAAU,YAAY,iBAAiB;IAA2B;IAAqB,qBAAqB,uBAAuB,UAAU;IAAa;GACpP;;;AAGV,SAAS,cAAc"}
package/dist/index.js CHANGED
@@ -86,11 +86,11 @@ import { Accordion } from "./Accordion.js";
86
86
  import { Alert } from "./Alert.js";
87
87
  import { Avatar } from "./Avatar.js";
88
88
  import { Badge } from "./Badge.js";
89
- import { ErrorMessage, WarningMessage } from "./FormFieldMessage.js";
90
89
  import { Button } from "./Button.js";
91
90
  import { Separator } from "./Separator.js";
92
91
  import { ButtonGroup, ButtonGroupItem, ButtonGroupSeparator } from "./ButtonGroup.js";
93
92
  import { ButtonIcon } from "./ButtonIcon.js";
93
+ import { ErrorMessage, WarningMessage } from "./FormFieldMessage.js";
94
94
  import { useUncontrolledState } from "./hooks/useUncontrolledState.js";
95
95
  import { Checkbox } from "./Checkbox.js";
96
96
  import { Label } from "./Label.js";