@spear-ai/spectral 1.20.2 → 1.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/Checkbox.js +3 -3
  2. package/dist/Checkbox.js.map +1 -1
  3. package/dist/Combobox.d.ts.map +1 -1
  4. package/dist/Combobox.js +2 -2
  5. package/dist/Combobox.js.map +1 -1
  6. package/dist/DateTimePicker/Calendar.d.ts +13 -1
  7. package/dist/DateTimePicker/Calendar.d.ts.map +1 -1
  8. package/dist/DateTimePicker/Calendar.js +11 -4
  9. package/dist/DateTimePicker/Calendar.js.map +1 -1
  10. package/dist/DateTimePicker/DateTimeDisplayInput.d.ts +1 -1
  11. package/dist/DateTimePicker/DateTimeDisplayInput.d.ts.map +1 -1
  12. package/dist/DateTimePicker/DateTimeDisplayInput.js +3 -3
  13. package/dist/DateTimePicker/DateTimeDisplayInput.js.map +1 -1
  14. package/dist/DateTimePicker.d.ts +13 -2
  15. package/dist/DateTimePicker.d.ts.map +1 -1
  16. package/dist/DateTimePicker.js +9 -5
  17. package/dist/DateTimePicker.js.map +1 -1
  18. package/dist/Input.d.ts +1 -1
  19. package/dist/Input.d.ts.map +1 -1
  20. package/dist/Input.js +24 -17
  21. package/dist/Input.js.map +1 -1
  22. package/dist/InputOTP.d.ts +2 -0
  23. package/dist/InputOTP.d.ts.map +1 -1
  24. package/dist/InputOTP.js +52 -40
  25. package/dist/InputOTP.js.map +1 -1
  26. package/dist/InputSearch.d.ts.map +1 -1
  27. package/dist/InputSearch.js +3 -2
  28. package/dist/InputSearch.js.map +1 -1
  29. package/dist/MultiSelect/MultiSelectBase.js +5 -4
  30. package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
  31. package/dist/RadialMenu.d.ts.map +1 -1
  32. package/dist/RadialMenu.js.map +1 -1
  33. package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts +1 -1
  34. package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts.map +1 -1
  35. package/dist/RadioButtonGroup/RadioButtonGroupBase.js +3 -3
  36. package/dist/RadioButtonGroup/RadioButtonGroupBase.js.map +1 -1
  37. package/dist/RadioButtonGroup.d.ts +1 -1
  38. package/dist/RadioGroup.d.ts +1 -1
  39. package/dist/RadioGroup.d.ts.map +1 -1
  40. package/dist/RadioGroup.js +3 -3
  41. package/dist/RadioGroup.js.map +1 -1
  42. package/dist/Select.d.ts.map +1 -1
  43. package/dist/Select.js +4 -4
  44. package/dist/Select.js.map +1 -1
  45. package/dist/Slider.js +1 -1
  46. package/dist/Slider.js.map +1 -1
  47. package/dist/Switch.d.ts +2 -2
  48. package/dist/Switch.d.ts.map +1 -1
  49. package/dist/Switch.js +4 -4
  50. package/dist/Switch.js.map +1 -1
  51. package/dist/Textarea.d.ts +3 -3
  52. package/dist/Textarea.d.ts.map +1 -1
  53. package/dist/Textarea.js +4 -3
  54. package/dist/Textarea.js.map +1 -1
  55. package/dist/Toast.d.ts +2 -0
  56. package/dist/Toast.d.ts.map +1 -1
  57. package/dist/Toast.js +8 -5
  58. package/dist/Toast.js.map +1 -1
  59. package/dist/primitives/input.d.ts.map +1 -1
  60. package/dist/primitives/input.js +2 -0
  61. package/dist/primitives/input.js.map +1 -1
  62. package/dist/primitives/textarea.d.ts.map +1 -1
  63. package/dist/primitives/textarea.js +2 -0
  64. package/dist/primitives/textarea.js.map +1 -1
  65. package/dist/styles/spectral.css +1 -1
  66. package/dist/utils/formFieldUtils.d.ts +9 -1
  67. package/dist/utils/formFieldUtils.d.ts.map +1 -1
  68. package/dist/utils/formFieldUtils.js +19 -2
  69. package/dist/utils/formFieldUtils.js.map +1 -1
  70. package/package.json +1 -1
package/dist/Select.js CHANGED
@@ -4,7 +4,7 @@ import { ChevronDownIcon } from "./Icons/ChevronDownIcon.js";
4
4
  import { LoaderIcon } from "./Icons/LoaderIcon.js";
5
5
  import { cn } from "./utils/twUtils.js";
6
6
  import { ErrorMessage, WarningMessage } from "./FormFieldMessage.js";
7
- import { EmptyState, LoadingState, getAriaProps, getDropdownSurfaceClasses, getDropdownWidthStyles, getErrorMessageId, getFormFieldCSSProperties, getOptionClasses, getTriggerClasses, groupOptions, useFormFieldId } from "./utils/formFieldUtils.js";
7
+ import { EmptyState, LoadingState, getAriaProps, getDropdownSurfaceClasses, getDropdownWidthStyles, getErrorMessageId, getFormFieldCSSProperties, getOptionClasses, getTriggerClasses, getWarningMessageId, groupOptions, useFormFieldId } from "./utils/formFieldUtils.js";
8
8
  import { Label } from "./Label.js";
9
9
  import { useAutoDropdownHorizontalShift } from "./utils/dropdownPositioning.js";
10
10
  import { SelectValue } from "./primitives/select.js";
@@ -22,7 +22,7 @@ const Select = (allProps) => {
22
22
  const selectId = useFormFieldId(id, name);
23
23
  const listboxId = `${selectId}-listbox`;
24
24
  const errorMessageId = getErrorMessageId(selectId);
25
- const warningMessageId = `${selectId}-warning`;
25
+ const warningMessageId = getWarningMessageId(selectId);
26
26
  const messageId = state === "error" && errorMessage ? errorMessageId : state === "warning" && warningMessage ? warningMessageId : void 0;
27
27
  const { dropdownWidthMode, dropdownWidthStyle, resolvedDropdownWidth } = getDropdownWidthStyles({
28
28
  dropdownWidth,
@@ -122,13 +122,13 @@ const Select = (allProps) => {
122
122
  align,
123
123
  alignOffset,
124
124
  avoidCollisions,
125
- className: cn("relative z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in", getDropdownSurfaceClasses(), "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", "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", "min-w-32 origin-(--radix-select-content-transform-origin) overflow-hidden", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1"),
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"),
126
126
  collisionBoundary,
127
127
  collisionPadding,
128
128
  "data-dropdown-width-mode": dropdownWidthMode,
129
129
  "data-dropdown-width-value": dropdownWidthMode === "custom" ? dropdownWidth : void 0,
130
- id: listboxId,
131
130
  "data-slot": "select-content",
131
+ id: listboxId,
132
132
  position,
133
133
  ref: setDropdownElement,
134
134
  side,
@@ -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 getDropdownSurfaceClasses,\n getDropdownWidthStyles,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getOptionClasses,\n getTriggerClasses,\n getWarningMessageId,\n groupOptions,\n LoadingState,\n useFormFieldId,\n WarningMessage,\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 = getWarningMessageId(selectId)\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 data-slot='select-content'\n data-testid='spectral-select-content'\n id={listboxId}\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
@@ -121,7 +121,7 @@ const Slider = ({ accessibleName, className, defaultValue, disabled, inputPositi
121
121
  "data-slot": "slider-range"
122
122
  })
123
123
  }), Array.from({ length: _values.length }, (_, index) => /* @__PURE__ */ jsx(SliderBase.Thumb, {
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",
124
+ className: "size-4 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,ring] hover:ring-4 focus-visible:ring-4 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50",
125
125
  "data-slot": "slider-thumb"
126
126
  }, index))]
127
127
  }),
@@ -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":";;;;;;;;AAkCA,MAAa,UAAU,EAAE,gBAAgB,WAAW,cAAc,UAAU,eAAe,OAAO,eAAe,MAAM,KAAK,MAAM,GAAG,wBAAwB,GAAG,MAAM,eAAe,eAAe,cAAc,cAAc,OAAO,GAAG,YAAyB;CACjQ,MAAM,eAAe,UAAU;CAM/B,MAAM,CAAC,gBAAgB,qBAAqB,SALtB,cACb,MAAM,QAAQ,MAAM,GAAG,QAAQ,MAAM,QAAQ,aAAa,GAAG,eAAe,CAAC,IAAI,EAExF,EAAE,CAE8D,CAAA;CAClE,MAAM,UAAU,eAAe,QAAQ;CAGvC,MAAM,CAAC,YAAY,iBAAiB,eAAyB,QAAQ,IAAI,OAAO,CAAA;AAGhF,iBAAgB;AACd,gBAAc,QAAQ,IAAI,OAAO,CAAA;IAChC,CAAC,QAAQ,CAAA;CAEZ,MAAM,oBAAoB,aACvB,cAAwB;AACvB,MAAI,CAAC,aACH,mBAAkB,UAAS;AAE7B,kBAAgB,UAAS;IAE3B,CAAC,cAAc,cAAc,CAC/B;CAEA,MAAM,wBAAwB,aAC3B,OAAe,MAAqC;EACnD,MAAM,WAAW,CAAC,GAAG,WAAU;AAC/B,WAAS,SAAS,EAAE,OAAO;AAC3B,gBAAc,SAAQ;IAExB,CAAC,WAAW,CACd;CAEA,MAAM,mBAAmB,aACtB,UAAkB;EACjB,MAAM,aAAa,WAAW;AAC9B,MAAI,eAAe,IAAI;AAErB,iBAAc,QAAQ,IAAI,OAAO,CAAA;AACjC;;EAGF,IAAI,WAAW,WAAW,WAAU;AACpC,MAAI,MAAM,SAAS,EAAE;AAEnB,iBAAc,QAAQ,IAAI,OAAO,CAAA;AACjC;;AAIF,aAAW,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,SAAS,CAAA;EAGhD,MAAM,YAAY,CAAC,GAAG,QAAO;AAC7B,MAAI,UAAU,KAAK,QAAQ,SAAS,GAAG;GAErC,MAAM,aAAa,QAAQ,KAAK,wBAAwB;AACxD,cAAW,KAAK,IAAI,UAAU,WAAU;aAC/B,UAAU,GAAG;GAEtB,MAAM,aAAa,QAAQ,KAAK,wBAAwB;AACxD,cAAW,KAAK,IAAI,UAAU,WAAU;;AAG1C,YAAU,SAAS;AACnB,oBAAkB,UAAS;AAC3B,kBAAgB,UAAS;IAE3B;EAAC;EAAY;EAAS;EAAK;EAAK;EAAM;EAAuB;EAAmB;EAAc,CAChG;CAEA,MAAM,qBAAqB,aACxB,OAAe,MAAuC;AACrD,MAAI,EAAE,QAAQ,SAAS;AACrB,oBAAiB,MAAK;AACtB,KAAE,cAAc,MAAK;;IAGzB,CAAC,iBAAiB,CACpB;CAEA,MAAM,aAAa,gBAAgB;CACnC,MAAM,iBAAiB,kBAAkB;CACzC,MAAM,eAAe,UAAU,kBAAkB,SAAS,kBAAkB;CAC5E,MAAM,iBAAiB,kBAAkB,WAAW,kBAAkB;CACtE,MAAM,eAAe,kBAAkB,UAAU,QAAQ,SAAS;CAElE,MAAM,eAAe,GAAG,mDAAmD,aAAa,gBAAgB,GAAE;CAE1G,MAAM,eAAe;AAErB,QACE,qBAAC,OAAD;EAAK,WAAW,GAAG,2BAA2B,aAAa,aAAa,UAAU,UAAU;YAA5F;GACG,kBACC,oBAAC,QAAD;IAAM,WAAW;IAAc,aAAU;cACtC,QAAQ;KAAE,QAAQ;KAAS;KAAK;KAAK,UAAU;KAAS,CAAC;IACtD;GAGP,kBACC,oBAAC,OAAD;IACE,cAAY,iBAAiB,GAAG,eAAe,gBAAgB;IAC/D,WAAW;IACX,aAAU;IAEA;IACV,KAAK,QAAQ,SAAS,IAAI,QAAQ,KAAK,wBAAwB,OAAO;IACjE;IACL,cAAc,iBAAiB,EAAE;IACjC,WAAW,MAAM,sBAAsB,GAAG,EAAE;IAC5C,YAAY,MAAM,mBAAmB,GAAG,EAAE;IACpC;IACN,MAAK;IACL,OAAO,WAAW,MAAM;IACzB;GAGH,qBAAC,WAAW,MAAZ;IACE,cAAY;IACZ,iBAAe;IACf,iBAAe;IACf,iBAAe,QAAQ;IACvB,WAAU;IACV,aAAU;IAEA;IACL;IACA;IACkB;IACjB;IACN,eAAe;IACA;IACF;IACP;IACN,OAAO;cAjBT,CAmBE,oBAAC,WAAW,OAAZ;KACE,WAAU;KACV,aAAU;eAGV,oBAAC,WAAW,OAAZ;MAAkB,WAAU;MAAmG,aAAU;MAAoD;KAC7K,GACjB,MAAM,KAAK,EAAE,QAAQ,QAAQ,QAAQ,GAAG,GAAG,UAC1C,oBAAC,WAAW,OAAZ;KACE,WAAU;KACV,aAAU;KAGX,EADM,MACN,CACD,CACa;;GAEhB,gBACC,oBAAC,OAAD;IACE,cAAY,iBAAiB,GAAG,eAAe,cAAc;IAC7D,WAAW;IACX,aAAU;IAEA;IACL;IACL,KAAK,QAAQ,KAAK,wBAAwB;IAC1C,cAAc,iBAAiB,EAAE;IACjC,WAAW,MAAM,sBAAsB,GAAG,EAAE;IAC5C,YAAY,MAAM,mBAAmB,GAAG,EAAE;IACpC;IACN,MAAK;IACL,OAAO,WAAW,MAAM;IACzB;GAGF,gBACC,oBAAC,QAAD;IAAM,WAAW;IAAc,aAAU;cACtC,MAAM;KAAE,QAAQ;KAAS;KAAK;KAAK,UAAU;KAAO,CAAC;IAClD;GAEL"}
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 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-4 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,ring] 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.d.ts CHANGED
@@ -7,8 +7,6 @@ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
7
7
  //#region src/components/Switch/Switch.d.ts
8
8
  type SwitchVisualState = Exclude<FormFieldState, 'disabled'>;
9
9
  type SwitchProps = Omit<SwitchProps$1, 'onCheckedChange'> & {
10
- 'aria-describedby'?: string;
11
- 'aria-label'?: string;
12
10
  errorMessage?: BaseFormFieldProps['errorMessage'];
13
11
  hideLabel?: boolean;
14
12
  id?: string;
@@ -24,6 +22,8 @@ type SwitchProps = Omit<SwitchProps$1, 'onCheckedChange'> & {
24
22
  value?: string;
25
23
  variant?: 'default' | 'squared' | 'permanent-indicator';
26
24
  warningMessage?: BaseFormFieldProps['errorMessage'];
25
+ 'aria-describedby'?: string;
26
+ 'aria-label'?: string;
27
27
  };
28
28
  declare function Switch({
29
29
  className,
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.d.ts","names":[],"sources":["../src/components/Switch/Switch.tsx"],"mappings":";;;;;;;KAOK,iBAAA,GAAoB,OAAA,CAAQ,cAAA;AAAA,KAErB,WAAA,GAAc,IAAA,CAAK,aAAA;EAC7B,kBAAA;EACA,YAAA;EACA,YAAA,GAAe,kBAAA;EACf,SAAA;EACA,EAAA;EACA,KAAA;EACA,aAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,QAAA,IAAY,OAAA;EACZ,GAAA,GAAM,GAAA,CAAI,iBAAA;EACV,QAAA;EACA,KAAA,GAAQ,iBAAA;EACR,KAAA;EACA,OAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAMjB,SAAA;EACA,QAAA;EACA,YAAA;EACA,SAAA;EACA,EAAA;EACA,KAAA;EACA,aAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,QAAA;EACA,GAAA;EACA,QAAA;EACA,KAAA;EACA,KAAA;EACA,OAAA;EACA,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN,SAAA;EAAA,GACX;AAAA,GACF,WAAA,GAAW,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"Switch.d.ts","names":[],"sources":["../src/components/Switch/Switch.tsx"],"mappings":";;;;;;;KAOK,iBAAA,GAAoB,OAAA,CAAQ,cAAA;AAAA,KAErB,WAAA,GAAc,IAAA,CAAK,aAAA;EAC7B,YAAA,GAAe,kBAAA;EACf,SAAA;EACA,EAAA;EACA,KAAA;EACA,aAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,QAAA,IAAY,OAAA;EACZ,GAAA,GAAM,GAAA,CAAI,iBAAA;EACV,QAAA;EACA,KAAA,GAAQ,iBAAA;EACR,KAAA;EACA,OAAA;EACA,cAAA,GAAiB,kBAAA;EACjB,kBAAA;EACA,YAAA;AAAA;AAAA;EAMA,SAAA;EACA,QAAA;EACA,YAAA;EACA,SAAA;EACA,EAAA;EACA,KAAA;EACA,aAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,QAAA;EACA,GAAA;EACA,QAAA;EACA,KAAA;EACA,KAAA;EACA,OAAA;EACA,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN,SAAA;EAAA,GACX;AAAA,GACF,WAAA,GAAW,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
package/dist/Switch.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { cn } from "./utils/twUtils.js";
3
3
  import { ErrorMessage, WarningMessage } from "./FormFieldMessage.js";
4
- import { useFormFieldId } from "./utils/formFieldUtils.js";
4
+ import { getErrorMessageId, getWarningMessageId, useFormFieldId } from "./utils/formFieldUtils.js";
5
5
  import { Label } from "./Label.js";
6
6
  import { Switch as Switch$1, SwitchThumb } from "./Switch/SwitchBase.js";
7
7
  import "react";
@@ -14,8 +14,8 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
14
14
  const switchId = useFormFieldId(id, name);
15
15
  const isDisabled = Boolean(disabled);
16
16
  const resolvedLabelText = labelText ?? label;
17
- const errorMessageId = `${switchId}-error`;
18
- const warningMessageId = `${switchId}-warning`;
17
+ const errorMessageId = getErrorMessageId(switchId);
18
+ const warningMessageId = getWarningMessageId(switchId);
19
19
  const messageId = state === "error" && errorMessage && errorMessageId ? errorMessageId : state === "warning" && warningMessage && warningMessageId ? warningMessageId : void 0;
20
20
  const isSquared = variant === "squared";
21
21
  return /* @__PURE__ */ jsxs("div", {
@@ -31,10 +31,10 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
31
31
  className: "h-7 text-sm font-medium relative inline-grid grid-cols-[1fr_1fr] items-center",
32
32
  children: [
33
33
  /* @__PURE__ */ jsx(Switch$1, {
34
- "aria-required": required,
35
34
  "aria-describedby": [messageId, ariaDescribedBy].filter(Boolean).join(" ") || void 0,
36
35
  "aria-invalid": state === "error" ? true : void 0,
37
36
  "aria-label": ariaLabel ?? (hideLabel ? resolvedLabelText : void 0),
37
+ "aria-required": required,
38
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),
39
39
  disabled: isDisabled,
40
40
  id: switchId,
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","names":[],"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-200 ease-out 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-200 ease-out 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-200 ease-out 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-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]'\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\n dataTestId='spectral-switch-error-message'\n id={errorMessageId}\n message={state === 'error' ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-switch-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}\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,KAAI;CACxC,MAAM,aAAa,QAAQ,SAAQ;CACnC,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;EAA4D,cAAY;YAAvF;GACG,kBAAkB,UAAU,CAAC,aAAa,qBACzC,oBAAC,OAAD;IAAO,WAAU;IAAgD,SAAS;cACvE;IACI;GAPgB,YAAY,wBAWnC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,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;MAED,UAAU;MACV,IAAI;MACE;MACN,iBAAiB;MACZ;MACK;MACH;MACP,GAAI;gBAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,uKAAuK,EAAG;MACtM;KACZ,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,OAAD;OAAO,eAAY;OAAO,WAAU;OAAU;MAC1C;KACN,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD;OAAW,eAAY;OAAO,WAAU;OAAU;MAC9C;KACH;QAEL,oBAAC,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,kUACA,gZACJ,UACD;IAED,UAAU;IACV,IAAI;IACE;IACN,iBAAiB;IACZ;IACK;IACH;IACP,GAAI;cAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,YAAY,gGAAgG,uDAAuD,EAAG;IAClM;GAGb,kBAAkB,WAAW,CAAC,aAAa,qBAC1C,oBAAC,OAAD;IAAO,WAAU;IAAiD,SAAS;IAAU,IAAI,GAAG,SAAS;cAClG;IACI;GAGR,aAAa,qBACZ,oBAAC,OAAD;IAAO,WAAU;IAAqD,SAAS;cAC5E;IACI;GAET,oBAAC,cAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,UAAW,gBAAgB,OAAQ;IACjC;IACrB,qBAAqB,uBAAuB,UAAU;IACvD;GACD,oBAAC,gBAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IACrC;IACrB,qBAAqB,uBAAuB,UAAU;IACvD;GACE;;;AAGT,OAAO,cAAc"}
1
+ {"version":3,"file":"Switch.js","names":[],"sources":["../src/components/Switch/Switch.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { ErrorMessage, getErrorMessageId, getWarningMessageId, useFormFieldId, WarningMessage, 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 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 'aria-describedby'?: string\n 'aria-label'?: string\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 = getErrorMessageId(switchId)\n const warningMessageId = getWarningMessageId(switchId)\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-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n aria-required={required}\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-200 ease-out 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-200 ease-out 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-200 ease-out 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-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]'\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\n dataTestId='spectral-switch-error-message'\n id={errorMessageId}\n message={state === 'error' ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-switch-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}\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,KAAI;CACxC,MAAM,aAAa,QAAQ,SAAQ;CACnC,MAAM,oBAAoB,aAAa;CACvC,MAAM,iBAAiB,kBAAkB,SAAQ;CACjD,MAAM,mBAAmB,oBAAoB,SAAQ;CACrD,MAAM,YAAY,UAAU,WAAW,gBAAgB,iBAAiB,iBAAiB,UAAU,aAAa,kBAAkB,mBAAmB,mBAAmB;CACxK,MAAM,YAAY,YAAY;AAG9B,QACE,qBAAC,OAAD;EAAK,WAAU;EAA4D,cAAY;YAAvF;GACG,kBAAkB,UAAU,CAAC,aAAa,qBACzC,oBAAC,OAAD;IAAO,WAAU;IAAgD,SAAS;cACvE;IACI;GAPgB,YAAY,wBAWnC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,UAAD;MACE,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;MAC5E,gBAAc,UAAU,UAAU,OAAO;MACzC,cAAY,cAAc,YAAY,oBAAoB;MAC1D,iBAAe;MACf,WAAW,GACT,kNACA,oKACA,mDACA,UACD;MAED,UAAU;MACV,IAAI;MACE;MACN,iBAAiB;MACZ;MACK;MACH;MACP,GAAI;gBAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,uKAAuK,EAAG;MACtM;KACZ,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,OAAD;OAAO,eAAY;OAAO,WAAU;OAAU;MAC1C;KACN,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD;OAAW,eAAY;OAAO,WAAU;OAAU;MAC9C;KACH;QAEL,oBAAC,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,kUACA,gZACJ,UACD;IAED,UAAU;IACV,IAAI;IACE;IACN,iBAAiB;IACZ;IACK;IACH;IACP,GAAI;cAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,YAAY,gGAAgG,uDAAuD,EAAG;IAClM;GAGb,kBAAkB,WAAW,CAAC,aAAa,qBAC1C,oBAAC,OAAD;IAAO,WAAU;IAAiD,SAAS;IAAU,IAAI,GAAG,SAAS;cAClG;IACI;GAGR,aAAa,qBACZ,oBAAC,OAAD;IAAO,WAAU;IAAqD,SAAS;cAC5E;IACI;GAET,oBAAC,cAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,UAAW,gBAAgB,OAAQ;IACjC;IACrB,qBAAqB,uBAAuB,UAAU;IACvD;GACD,oBAAC,gBAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IACrC;IACrB,qBAAqB,uBAAuB,UAAU;IACvD;GACE;;;AAGT,OAAO,cAAc"}
@@ -8,12 +8,12 @@ type TextareaState = FormFieldState;
8
8
  type TextareaProps = Omit<ComponentProps<'textarea'>, 'onChange'> & {
9
9
  className?: string | undefined;
10
10
  errorMessage?: BaseFormFieldProps['errorMessage'];
11
+ hideCounter?: boolean;
11
12
  id?: string | undefined;
12
13
  label: string;
13
14
  labelClassName?: string;
14
- maxLength?: number | undefined; /** Controls visibility of the bottom-right character counter (default: true). */
15
- showCounter?: boolean; /** Number of message lines to reserve (default: 1). */
16
- messageReserveLines?: number; /** Whether to keep message space reserved when hidden (default: false). */
15
+ maxLength?: number | undefined;
16
+ messageReserveLines?: number;
17
17
  messageReserveSpace?: boolean;
18
18
  name: string;
19
19
  onBlur?: (e: FocusEvent<HTMLTextAreaElement>) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.d.ts","names":[],"sources":["../src/components/Textarea/Textarea.tsx"],"mappings":";;;;;;KAQY,aAAA,GAAgB,cAAA;AAAA,KAIhB,aAAA,GAAgB,IAAA,CAAK,cAAA;EAC/B,SAAA;EACA,YAAA,GAAe,kBAAA;EACf,EAAA;EACA,KAAA;EACA,cAAA;EACA,SAAA,uBANU;EAQV,WAAA;EAEA,mBAAA,WAV0B;EAY1B,mBAAA;EACA,IAAA;EACA,MAAA,IAAU,CAAA,EAAG,UAAA,CAAW,mBAAA;EACxB,QAAA,IAAY,KAAA;EACZ,OAAA,IAAW,CAAA,EAAG,UAAA,CAAW,mBAAA;EACzB,WAAA;EACA,QAAA;EACA,KAAA,GAAQ,aAAA;EACR,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA,0BAiBjB,QAAA,EAAU,aAAA;EACR,GAAA,GAAM,GAAA,CAAI,mBAAA;AAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"Textarea.d.ts","names":[],"sources":["../src/components/Textarea/Textarea.tsx"],"mappings":";;;;;;KAQY,aAAA,GAAgB,cAAA;AAAA,KAIhB,aAAA,GAAgB,IAAA,CAAK,cAAA;EAC/B,SAAA;EACA,YAAA,GAAe,kBAAA;EACf,WAAA;EACA,EAAA;EACA,KAAA;EACA,cAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,MAAA,IAAU,CAAA,EAAG,UAAA,CAAW,mBAAA;EACxB,QAAA,IAAY,KAAA;EACZ,OAAA,IAAW,CAAA,EAAG,UAAA,CAAW,mBAAA;EACzB,WAAA;EACA,QAAA;EACA,KAAA,GAAQ,aAAA;EACR,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA,0BAiBjB,QAAA,EAAU,aAAA;EACR,GAAA,GAAM,GAAA,CAAI,mBAAA;AAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
package/dist/Textarea.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { LoaderIcon } from "./Icons/LoaderIcon.js";
3
3
  import { cn } from "./utils/twUtils.js";
4
4
  import { ErrorMessage, WarningMessage } from "./FormFieldMessage.js";
5
- import { getAriaProps, getErrorMessageId, getTextareaClasses, useFormFieldId, useFormFieldState } from "./utils/formFieldUtils.js";
5
+ import { getAriaProps, getErrorMessageId, getPasswordManagerIgnoreProps, getTextareaClasses, useFormFieldId, useFormFieldState } from "./utils/formFieldUtils.js";
6
6
  import { useUncontrolledState } from "./hooks/useUncontrolledState.js";
7
7
  import { Label } from "./Label.js";
8
8
  import { useTextarea } from "./Textarea/TextareaUtils.js";
@@ -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 = false, name, onBlur, onChange, onFocus, placeholder, required, showCounter = true, state = "default", value: valueProp, warningMessage, ...props } = allProps;
22
+ const { ref, autoComplete, className, defaultValue, disabled, errorMessage, hideCounter = false, 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`;
@@ -76,6 +76,7 @@ const Textarea = (allProps) => {
76
76
  spellCheck: "true",
77
77
  style: getCSSCustomProperties(),
78
78
  value,
79
+ ...getPasswordManagerIgnoreProps(),
79
80
  ...ariaProps,
80
81
  ...props
81
82
  }),
@@ -83,7 +84,7 @@ const Textarea = (allProps) => {
83
84
  className: LOADING_ICON_CLASSES,
84
85
  children: /* @__PURE__ */ jsx(LoaderIcon, { size: 24 })
85
86
  }),
86
- showCounter && /* @__PURE__ */ jsxs("div", {
87
+ !hideCounter && /* @__PURE__ */ jsxs("div", {
87
88
  "aria-label": currentLength + " of " + maxLength + " characters used",
88
89
  "aria-live": "polite",
89
90
  className: getCounterClasses(currentLength, maxLength),
@@ -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 /** Controls visibility of the bottom-right character counter (default: true). */\n showCounter?: boolean\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 showCounter = true,\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\n data-testid='spectral-textarea-label'\n htmlFor={textareaId}\n className={cn('mb-2 block', isDisabled && 'cursor-not-allowed opacity-50', labelClassName)}\n >\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 {showCounter && (\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 )}\n </div>\n\n <ErrorMessage\n dataTestId='spectral-textarea-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-textarea-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nTextarea.displayName = 'Textarea'\n"],"mappings":";;;;;;;;;;;;AAoCA,MAAM,uBAAuB;AAE7B,MAAM,wBAAwB,iBAA6C;AACzE,KAAI,aAAc,QAAO;AACzB,QAAO;;AAGT,MAAM,qBAAqB,eAAuB,cAA8B;AAG9E,QAAO,GAAG,2EADS,iBAAiB,YAAY,oBAAoB,sBACnC;;AAGnC,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,cAAc,MACd,QAAQ,WACR,OAAO,WACP,gBACA,GAAG,UACD;CACJ,MAAM,aAAa,eAAe,IAAI,KAAI;CAC1C,MAAM,iBAAiB,kBAAkB,WAAU;CACnD,MAAM,mBAAmB,GAAG,WAAW;CACvC,MAAM,YAAY,UAAU,UAAU,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClH,MAAM,cAAc,OAA4B,KAAI;CACpD,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,CAAA;CAED,MAAM,EAAE,aAAa,YAAY,cAAc,gBAAgB,YAAY;EACzE;EACA;EACA,UAAU;EACV;EACA;EACD,CAAA;CAED,MAAM,EAAE,YAAY,cAAc,kBAAkB,UAAU,MAAK;CACnE,MAAM,YAAY,aAAa,OAAO,MAAM,qBAAqB,UAAU,UAAS;CACpF,MAAM,gBAAgB,OAAO,UAAU;CACvC,MAAM,kBAAkB,mBAAmB,OAAO,UAAS;CAE3D,MAAM,gCAAgC;EACpC,yBAAyB;EACzB,yBAAyB;EACzB,4BAA4B;EAC7B;AAED,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,oBAAC,OAAD;IAEE,SAAS;IACT,WAAW,GAAG,cAAc,cAAc,iCAAiC,eAAe;cAEzF;IACI;GAET,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,YAAD;MACE,kBAAe;MACf,cAAc,qBAAqB,aAAa;MAChD,WAAW;MACX,cAAY;MAEZ,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;MACL;KAEA,aACC,oBAAC,OAAD;MAAK,WAAW;gBACd,oBAAC,YAAD,EAAY,MAAM,IAAK;MACpB;KAGN,eACC,qBAAC,OAAD;MAEE,cAAY,gBAAgB,SAAS,YAAY;MACjD,aAAU;MACV,WAAW,kBAAkB,eAAe,UAAU;MAEtD,MAAK;gBANP;OAQG;OAAc;OAAE;OACd;;KAEJ;;GAEL,oBAAC,cAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,UAAU,eAAe;IACvB;IACrB,qBAAqB,uBAAuB,UAAU;IACvD;GACD,oBAAC,gBAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,YAAY,iBAAiB;IAC3B;IACrB,qBAAqB,uBAAuB,UAAU;IACvD;GACE;;;AAGT,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, getPasswordManagerIgnoreProps, 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 hideCounter?: boolean\n id?: string | undefined\n label: string\n labelClassName?: string\n maxLength?: number | undefined\n messageReserveLines?: number\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 hideCounter = false,\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\n data-testid='spectral-textarea-label'\n htmlFor={textareaId}\n className={cn('mb-2 block', isDisabled && 'cursor-not-allowed opacity-50', labelClassName)}\n >\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 {...getPasswordManagerIgnoreProps()}\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 {!hideCounter && (\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 )}\n </div>\n <ErrorMessage\n dataTestId='spectral-textarea-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-textarea-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nTextarea.displayName = 'Textarea'\n"],"mappings":";;;;;;;;;;;;AAiCA,MAAM,uBAAuB;AAE7B,MAAM,wBAAwB,iBAA6C;AACzE,KAAI,aAAc,QAAO;AACzB,QAAO;;AAGT,MAAM,qBAAqB,eAAuB,cAA8B;AAG9E,QAAO,GAAG,2EADS,iBAAiB,YAAY,oBAAoB,sBACnC;;AAGnC,MAAa,YACX,aAGG;CACH,MAAM,EACJ,KACA,cACA,WACA,cACA,UACA,cACA,cAAc,OACd,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,KAAI;CAC1C,MAAM,iBAAiB,kBAAkB,WAAU;CACnD,MAAM,mBAAmB,GAAG,WAAW;CACvC,MAAM,YAAY,UAAU,UAAU,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClH,MAAM,cAAc,OAA4B,KAAI;CACpD,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,CAAA;CAED,MAAM,EAAE,aAAa,YAAY,cAAc,gBAAgB,YAAY;EACzE;EACA;EACA,UAAU;EACV;EACA;EACD,CAAA;CAED,MAAM,EAAE,YAAY,cAAc,kBAAkB,UAAU,MAAK;CACnE,MAAM,YAAY,aAAa,OAAO,MAAM,qBAAqB,UAAU,UAAS;CACpF,MAAM,gBAAgB,OAAO,UAAU;CACvC,MAAM,kBAAkB,mBAAmB,OAAO,UAAS;CAE3D,MAAM,gCAAgC;EACpC,yBAAyB;EACzB,yBAAyB;EACzB,4BAA4B;EAC7B;AAED,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,oBAAC,OAAD;IAEE,SAAS;IACT,WAAW,GAAG,cAAc,cAAc,iCAAiC,eAAe;cAEzF;IACI;GAET,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,YAAD;MACE,kBAAe;MACf,cAAc,qBAAqB,aAAa;MAChD,WAAW;MACX,cAAY;MAEZ,UAAU;MACV,IAAI;MACE;MACN,QAAQ;MACR,UAAU;MACV,SAAS;MACT,SAAS;MACI;MACb,KAAK;MACK;MACV,YAAW;MACX,OAAO,wBAAwB;MACxB;MACP,GAAI,+BAA+B;MACnC,GAAI;MACJ,GAAI;MACL;KAEA,aACC,oBAAC,OAAD;MAAK,WAAW;gBACd,oBAAC,YAAD,EAAY,MAAM,IAAK;MACpB;KAGN,CAAC,eACA,qBAAC,OAAD;MAEE,cAAY,gBAAgB,SAAS,YAAY;MACjD,aAAU;MACV,WAAW,kBAAkB,eAAe,UAAU;MAEtD,MAAK;gBANP;OAQG;OAAc;OAAE;OACd;;KAEJ;;GACL,oBAAC,cAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,UAAU,eAAe;IACvB;IACrB,qBAAqB,uBAAuB,UAAU;IACvD;GACD,oBAAC,gBAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,YAAY,iBAAiB;IAC3B;IACrB,qBAAqB,uBAAuB,UAAU;IACvD;GACE;;;AAGT,SAAS,cAAc"}
package/dist/Toast.d.ts CHANGED
@@ -18,6 +18,7 @@ interface ToastProps extends VariantProps<typeof toastVariants> {
18
18
  icon?: ReactNode;
19
19
  id?: string | number;
20
20
  onAutoClose?: () => void;
21
+ onDismiss?: () => void;
21
22
  position?: ToastPosition;
22
23
  variant?: ToastVariant;
23
24
  }
@@ -60,6 +61,7 @@ declare const toast: ((messageOrOptions: string | ToastProps, options?: ToastDef
60
61
  error: (messageOrOptions: string | Omit<ToastProps, 'variant'>, options?: ToastVariantOptions) => string | number;
61
62
  info: (messageOrOptions: string | Omit<ToastProps, 'variant'>, options?: ToastVariantOptions) => string | number;
62
63
  warning: (messageOrOptions: string | Omit<ToastProps, 'variant'>, options?: ToastVariantOptions) => string | number;
64
+ dismiss: (id?: number | string) => string | number;
63
65
  };
64
66
  //#endregion
65
67
  export { Toast, ToastProps, ToasterProps, toast };
@@ -1 +1 @@
1
- {"version":3,"file":"Toast.d.ts","names":[],"sources":["../src/components/Toast/Toast.tsx"],"mappings":";;;;;;;;KAMK,YAAA;AAAA,KACA,aAAA;AAAA,UAEY,UAAA,SAAmB,YAAA,QAAoB,aAAA;EACtD,iBAAA,YAA6B,SAAA;EAC7B,SAAA;EACA,kBAAA;EACA,UAAA;EACA,OAAA,YAAmB,SAAA;EACnB,QAAA;EACA,IAAA,GAAO,SAAA;EACP,EAAA;EACA,WAAA;EACA,QAAA,GAAW,aAAA;EACX,OAAA,GAAU,YAAA;AAAA;AAAA,UAGK,YAAA,SAAqB,IAAA,CAAK,cAAA;EACzC,GAAA;EACA,MAAA;EACA,QAAA,GAAW,aAAA;EACX,aAAA;AAAA;AAAA,KAGG,mBAAA,GAAsB,IAAA,CAAK,UAAA;AAAA,KAC3B,mBAAA,GAAsB,IAAA,CAAK,UAAA;AAAA,cAG1B,aAAA,GAAa,KAAA;;IAajB,iCAAA,CAAA,SAAA;AAAA,cAyGW,KAAA;EAAA;;;;;;;;KArDV,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;;;OA3B6F,YAAA,GAAY,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;cAoFzG,KAAA,IAAK,gBAAA,WAtB4B,UAAA,EAAU,OAAA,GAAW,mBAAA;uCAS9B,IAAA,CAAK,UAAA,cAAsB,OAAA,GAAW,mBAAA"}
1
+ {"version":3,"file":"Toast.d.ts","names":[],"sources":["../src/components/Toast/Toast.tsx"],"mappings":";;;;;;;;KAMK,YAAA;AAAA,KACA,aAAA;AAAA,UAEY,UAAA,SAAmB,YAAA,QAAoB,aAAA;EACtD,iBAAA,YAA6B,SAAA;EAC7B,SAAA;EACA,kBAAA;EACA,UAAA;EACA,OAAA,YAAmB,SAAA;EACnB,QAAA;EACA,IAAA,GAAO,SAAA;EACP,EAAA;EACA,WAAA;EACA,SAAA;EACA,QAAA,GAAW,aAAA;EACX,OAAA,GAAU,YAAA;AAAA;AAAA,UAGK,YAAA,SAAqB,IAAA,CAAK,cAAA;EACzC,GAAA;EACA,MAAA;EACA,QAAA,GAAW,aAAA;EACX,aAAA;AAAA;AAAA,KAGG,mBAAA,GAAsB,IAAA,CAAK,UAAA;AAAA,KAC3B,mBAAA,GAAsB,IAAA,CAAK,UAAA;AAAA,cAG1B,aAAA,GAAa,KAAA;;IAajB,iCAAA,CAAA,SAAA;AAAA,cA4GW,KAAA;EAAA;;;;;;;;KAxDV,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;;;OA3B6F,YAAA,GAAY,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;cAuFzG,KAAA,IAAK,gBAAA,WAtB4B,UAAA,EAAU,OAAA,GAAW,mBAAA;uCAS9B,IAAA,CAAK,UAAA,cAAsB,OAAA,GAAW,mBAAA"}
package/dist/Toast.js CHANGED
@@ -80,20 +80,22 @@ const ToastComponent = ({ additionalMessage, className, containerAriaLabel = "No
80
80
  });
81
81
  };
82
82
  ToastComponent.displayName = "Toast";
83
- const showToast = ({ additionalMessage, className, containerAriaLabel, dataTestId, duration = 4e3, icon, message, onAutoClose, position, variant = "default" }) => {
84
- return toast$1.custom((id) => /* @__PURE__ */ jsx(ToastComponent, {
83
+ const showToast = ({ additionalMessage, className, containerAriaLabel, dataTestId, duration = 4e3, icon, id, message, onAutoClose, onDismiss, position, variant = "default" }) => {
84
+ return toast$1.custom((toastId) => /* @__PURE__ */ jsx(ToastComponent, {
85
85
  additionalMessage,
86
86
  className,
87
87
  containerAriaLabel,
88
88
  dataTestId,
89
89
  icon,
90
- id,
90
+ id: toastId,
91
91
  message,
92
92
  variant
93
93
  }), {
94
94
  duration,
95
95
  onAutoClose,
96
- position
96
+ onDismiss,
97
+ position,
98
+ ...id !== void 0 && { id }
97
99
  });
98
100
  };
99
101
  const toastBase = (messageOrOptions, options = {}) => {
@@ -121,7 +123,8 @@ const toast = Object.assign(toastBase, {
121
123
  success: createVariantToast("success"),
122
124
  error: createVariantToast("error"),
123
125
  info: createVariantToast("info"),
124
- warning: createVariantToast("warning")
126
+ warning: createVariantToast("warning"),
127
+ dismiss: toast$1.dismiss
125
128
  });
126
129
 
127
130
  //#endregion
package/dist/Toast.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Toast.js","names":[],"sources":["../src/components/Toast/Toast.tsx"],"sourcesContent":["import { CheckSquareIcon, CloseCircleIcon, InfoIcon, WarningIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { type ReactNode } from 'react'\nimport { toast as sonnerToast, Toaster as SonnerToaster, type ToasterProps as SonnerToasterProps } from 'sonner'\n\ntype ToastVariant = 'default' | 'success' | 'error' | 'info' | 'warning'\ntype ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\n\nexport interface ToastProps extends VariantProps<typeof toastVariants> {\n additionalMessage?: string | ReactNode\n className?: string\n containerAriaLabel?: string\n dataTestId?: string\n message?: string | ReactNode\n duration?: number\n icon?: ReactNode\n id?: string | number\n onAutoClose?: () => void\n position?: ToastPosition\n variant?: ToastVariant\n}\n\nexport interface ToasterProps extends Omit<SonnerToasterProps, 'toastOptions'> {\n gap?: number\n offset?: number | string\n position?: ToastPosition\n visibleToasts?: number\n}\n\ntype ToastDefaultOptions = Omit<ToastProps, 'message'>\ntype ToastVariantOptions = Omit<ToastProps, 'message' | 'variant'>\ntype ToastVariantShorthand = Exclude<ToastVariant, 'default'>\n\nconst toastVariants = cva('rounded-md px-4 py-3 text-sm gap-3 shadow-elevation-2 flex max-w-[420px] min-w-[300px] items-start border', {\n variants: {\n variant: {\n default: 'border-toast-border bg-toast-bg text-toast-text',\n success: 'border-toast-success-border bg-toast-success-bg text-toast-success-text',\n error: 'border-toast-danger-border bg-toast-danger-bg text-toast-danger-text',\n info: 'border-toast-info-border bg-toast-info-bg text-toast-info-text',\n warning: 'border-toast-warning-border bg-toast-warning-bg text-toast-warning-text',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n})\n\nconst messageVariants = cva('font-semibold', {\n variants: {\n variant: {\n default: 'text-toast-text',\n success: 'text-toast-success-text',\n error: 'text-toast-danger-text',\n info: 'text-toast-info-text',\n warning: 'text-toast-warning-text',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n})\n\nconst variantIcons: Record<ToastVariant, ReactNode> = {\n default: null,\n success: <CheckSquareIcon className='size-5 shrink-0 text-toast-success-icon' />,\n info: <InfoIcon className='size-5 shrink-0 text-toast-info-icon' />,\n warning: <WarningIcon className='size-5 shrink-0 text-toast-warning-icon' />,\n error: <CloseCircleIcon className='size-5 shrink-0 text-toast-danger-icon' />,\n}\n\nconst ToastProvider = ({ gap = 14, offset = 32, position = 'bottom-right', visibleToasts = 3, ...props }: ToasterProps) => {\n return (\n <SonnerToaster\n gap={gap}\n offset={offset}\n position={position}\n visibleToasts={visibleToasts}\n toastOptions={{\n unstyled: true,\n classNames: {\n toast: 'bg-black rounded-lg',\n },\n }}\n {...props}\n />\n )\n}\nToastProvider.displayName = 'Toast.Provider'\n\nconst ToastComponent = ({\n additionalMessage,\n className,\n containerAriaLabel = 'Notification',\n dataTestId,\n icon,\n message,\n variant = 'default',\n}: ToastProps) => {\n const resolvedVariant = variant ?? 'default'\n const displayIcon = icon ?? variantIcons[resolvedVariant]\n const hasIcon = Boolean(displayIcon)\n\n return (\n <div aria-label={containerAriaLabel} className={cn(toastVariants({ variant: resolvedVariant }), className)} data-variant={resolvedVariant} data-testid={dataTestId ?? `spectral-toast-${resolvedVariant}`} role='status' aria-live='polite'>\n <div className='flex flex-col'>\n <div className='flex items-center gap-3'>\n {displayIcon && (\n <div aria-hidden='true'>\n {displayIcon}\n </div>\n )}\n <p className={messageVariants({ variant: resolvedVariant })}>{message}</p>\n </div>\n {additionalMessage && (\n <div className={cn('mt-1 text-text-primary', hasIcon && 'pl-8')} data-testid='spectral-toast-additional-content'>\n {typeof additionalMessage === 'string' ? <p>{additionalMessage}</p> : <>{additionalMessage}</>}\n </div>\n )}\n </div>\n </div>\n )\n}\nToastComponent.displayName = 'Toast'\n\nconst showToast = ({ additionalMessage, className, containerAriaLabel, dataTestId, duration = 4000, icon, message, onAutoClose, position, variant = 'default' }: ToastProps) => {\n return sonnerToast.custom((id) => <ToastComponent additionalMessage={additionalMessage} className={className} containerAriaLabel={containerAriaLabel} dataTestId={dataTestId} icon={icon} id={id} message={message} variant={variant} />, {\n duration,\n onAutoClose,\n position,\n })\n}\n\nconst toastBase = (messageOrOptions: string | ToastProps, options: ToastDefaultOptions = {}) => {\n if (typeof messageOrOptions === 'string') {\n return showToast({ ...options, message: messageOrOptions })\n }\n\n return showToast(messageOrOptions)\n}\n\nconst createVariantToast = (variant: ToastVariantShorthand) => {\n return (messageOrOptions: string | Omit<ToastProps, 'variant'>, options: ToastVariantOptions = {}) => {\n if (typeof messageOrOptions === 'string') {\n return showToast({ ...options, message: messageOrOptions, variant })\n }\n\n return showToast({ ...messageOrOptions, variant })\n }\n}\n\nexport const Toast = Object.assign(ToastComponent, {\n Provider: ToastProvider,\n})\n\nexport const toast = Object.assign(toastBase, {\n success: createVariantToast('success'),\n error: createVariantToast('error'),\n info: createVariantToast('info'),\n warning: createVariantToast('warning'),\n})\n"],"mappings":";;;;;;;;;;;;AAkCA,MAAM,gBAAgB,IAAI,6GAA6G;CACrI,UAAU,EACR,SAAS;EACP,SAAS;EACT,SAAS;EACT,OAAO;EACP,MAAM;EACN,SAAS;EACV,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CAAA;AAED,MAAM,kBAAkB,IAAI,iBAAiB;CAC3C,UAAU,EACR,SAAS;EACP,SAAS;EACT,SAAS;EACT,OAAO;EACP,MAAM;EACN,SAAS;EACV,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CAAA;AAED,MAAM,eAAgD;CACpD,SAAS;CACT,SAAS,oBAAC,iBAAD,EAAiB,WAAU,2CAA4C;CAChF,MAAM,oBAAC,UAAD,EAAU,WAAU,wCAAyC;CACnE,SAAS,oBAAC,aAAD,EAAa,WAAU,2CAA4C;CAC5E,OAAO,oBAAC,iBAAD,EAAiB,WAAU,0CAA2C;CAC/E;AAEA,MAAM,iBAAiB,EAAE,MAAM,IAAI,SAAS,IAAI,WAAW,gBAAgB,gBAAgB,GAAG,GAAG,YAA0B;AACzH,QACE,oBAAC,SAAD;EACO;EACG;EACE;EACK;EACf,cAAc;GACZ,UAAU;GACV,YAAY,EACV,OAAO,uBACR;GACF;EACD,GAAI;EACL;;AAGL,cAAc,cAAc;AAE5B,MAAM,kBAAkB,EACtB,mBACA,WACA,qBAAqB,gBACrB,YACA,MACA,SACA,UAAU,gBACM;CAChB,MAAM,kBAAkB,WAAW;CACnC,MAAM,cAAc,QAAQ,aAAa;CACzC,MAAM,UAAU,QAAQ,YAAW;AAEnC,QACE,oBAAC,OAAD;EAAK,cAAY;EAAoB,WAAW,GAAG,cAAc,EAAE,SAAS,iBAAiB,CAAC,EAAE,UAAU;EAAE,gBAAc;EAAiF,MAAK;EAAS,aAAU;YACjO,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,eACC,oBAAC,OAAD;KAAK,eAAY;eACd;KACE,GAEP,oBAAC,KAAD;KAAG,WAAW,gBAAgB,EAAE,SAAS,iBAAiB,CAAC;eAAG;KAAW,EACtE;OACJ,qBACC,oBAAC,OAAD;IAAK,WAAW,GAAG,0BAA0B,WAAW,OAAO;cAC5D,OAAO,sBAAsB,WAAW,oBAAC,KAAD,YAAI,mBAAsB,IAAG,4CAAG,mBAAqB;IAC3F,EAEJ;;EACF;;AAGT,eAAe,cAAc;AAE7B,MAAM,aAAa,EAAE,mBAAmB,WAAW,oBAAoB,YAAY,WAAW,KAAM,MAAM,SAAS,aAAa,UAAU,UAAU,gBAA4B;AAC9K,QAAO,QAAY,QAAQ,OAAO,oBAAC,gBAAD;EAAmC;EAA8B;EAA+B;EAAgC;EAAkB;EAAU;EAAa;EAAkB;EAAW,GAAE;EACxO;EACA;EACA;EACD,CAAA;;AAGH,MAAM,aAAa,kBAAuC,UAA+B,EAAE,KAAK;AAC9F,KAAI,OAAO,qBAAqB,SAC9B,QAAO,UAAU;EAAE,GAAG;EAAS,SAAS;EAAkB,CAAA;AAG5D,QAAO,UAAU,iBAAgB;;AAGnC,MAAM,sBAAsB,YAAmC;AAC7D,SAAQ,kBAAwD,UAA+B,EAAE,KAAK;AACpG,MAAI,OAAO,qBAAqB,SAC9B,QAAO,UAAU;GAAE,GAAG;GAAS,SAAS;GAAkB;GAAS,CAAA;AAGrE,SAAO,UAAU;GAAE,GAAG;GAAkB;GAAS,CAAA;;;AAIrD,MAAa,QAAQ,OAAO,OAAO,gBAAgB,EACjD,UAAU,eACX,CAAA;AAED,MAAa,QAAQ,OAAO,OAAO,WAAW;CAC5C,SAAS,mBAAmB,UAAU;CACtC,OAAO,mBAAmB,QAAQ;CAClC,MAAM,mBAAmB,OAAO;CAChC,SAAS,mBAAmB,UAAU;CACvC,CAAA"}
1
+ {"version":3,"file":"Toast.js","names":[],"sources":["../src/components/Toast/Toast.tsx"],"sourcesContent":["import { CheckSquareIcon, CloseCircleIcon, InfoIcon, WarningIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { type ReactNode } from 'react'\nimport { toast as sonnerToast, Toaster as SonnerToaster, type ToasterProps as SonnerToasterProps } from 'sonner'\n\ntype ToastVariant = 'default' | 'success' | 'error' | 'info' | 'warning'\ntype ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\n\nexport interface ToastProps extends VariantProps<typeof toastVariants> {\n additionalMessage?: string | ReactNode\n className?: string\n containerAriaLabel?: string\n dataTestId?: string\n message?: string | ReactNode\n duration?: number\n icon?: ReactNode\n id?: string | number\n onAutoClose?: () => void\n onDismiss?: () => void\n position?: ToastPosition\n variant?: ToastVariant\n}\n\nexport interface ToasterProps extends Omit<SonnerToasterProps, 'toastOptions'> {\n gap?: number\n offset?: number | string\n position?: ToastPosition\n visibleToasts?: number\n}\n\ntype ToastDefaultOptions = Omit<ToastProps, 'message'>\ntype ToastVariantOptions = Omit<ToastProps, 'message' | 'variant'>\ntype ToastVariantShorthand = Exclude<ToastVariant, 'default'>\n\nconst toastVariants = cva('rounded-md px-4 py-3 text-sm gap-3 shadow-elevation-2 flex max-w-[420px] min-w-[300px] items-start border', {\n variants: {\n variant: {\n default: 'border-toast-border bg-toast-bg text-toast-text',\n success: 'border-toast-success-border bg-toast-success-bg text-toast-success-text',\n error: 'border-toast-danger-border bg-toast-danger-bg text-toast-danger-text',\n info: 'border-toast-info-border bg-toast-info-bg text-toast-info-text',\n warning: 'border-toast-warning-border bg-toast-warning-bg text-toast-warning-text',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n})\n\nconst messageVariants = cva('font-semibold', {\n variants: {\n variant: {\n default: 'text-toast-text',\n success: 'text-toast-success-text',\n error: 'text-toast-danger-text',\n info: 'text-toast-info-text',\n warning: 'text-toast-warning-text',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n})\n\nconst variantIcons: Record<ToastVariant, ReactNode> = {\n default: null,\n success: <CheckSquareIcon className='size-5 shrink-0 text-toast-success-icon' />,\n info: <InfoIcon className='size-5 shrink-0 text-toast-info-icon' />,\n warning: <WarningIcon className='size-5 shrink-0 text-toast-warning-icon' />,\n error: <CloseCircleIcon className='size-5 shrink-0 text-toast-danger-icon' />,\n}\n\nconst ToastProvider = ({ gap = 14, offset = 32, position = 'bottom-right', visibleToasts = 3, ...props }: ToasterProps) => {\n return (\n <SonnerToaster\n gap={gap}\n offset={offset}\n position={position}\n visibleToasts={visibleToasts}\n toastOptions={{\n unstyled: true,\n classNames: {\n toast: 'bg-black rounded-lg',\n },\n }}\n {...props}\n />\n )\n}\nToastProvider.displayName = 'Toast.Provider'\n\nconst ToastComponent = ({\n additionalMessage,\n className,\n containerAriaLabel = 'Notification',\n dataTestId,\n icon,\n message,\n variant = 'default',\n}: ToastProps) => {\n const resolvedVariant = variant ?? 'default'\n const displayIcon = icon ?? variantIcons[resolvedVariant]\n const hasIcon = Boolean(displayIcon)\n\n return (\n <div aria-label={containerAriaLabel} className={cn(toastVariants({ variant: resolvedVariant }), className)} data-variant={resolvedVariant} data-testid={dataTestId ?? `spectral-toast-${resolvedVariant}`} role='status' aria-live='polite'>\n <div className='flex flex-col'>\n <div className='flex items-center gap-3'>\n {displayIcon && (\n <div aria-hidden='true'>\n {displayIcon}\n </div>\n )}\n <p className={messageVariants({ variant: resolvedVariant })}>{message}</p>\n </div>\n {additionalMessage && (\n <div className={cn('mt-1 text-text-primary', hasIcon && 'pl-8')} data-testid='spectral-toast-additional-content'>\n {typeof additionalMessage === 'string' ? <p>{additionalMessage}</p> : <>{additionalMessage}</>}\n </div>\n )}\n </div>\n </div>\n )\n}\nToastComponent.displayName = 'Toast'\n\nconst showToast = ({ additionalMessage, className, containerAriaLabel, dataTestId, duration = 4000, icon, id, message, onAutoClose, onDismiss, position, variant = 'default' }: ToastProps) => {\n return sonnerToast.custom((toastId) => <ToastComponent additionalMessage={additionalMessage} className={className} containerAriaLabel={containerAriaLabel} dataTestId={dataTestId} icon={icon} id={toastId} message={message} variant={variant} />, {\n duration,\n onAutoClose,\n onDismiss,\n position,\n // Spreading an explicit `id: undefined` would clobber Sonner's generated id\n ...(id !== undefined && { id }),\n })\n}\n\nconst toastBase = (messageOrOptions: string | ToastProps, options: ToastDefaultOptions = {}) => {\n if (typeof messageOrOptions === 'string') {\n return showToast({ ...options, message: messageOrOptions })\n }\n\n return showToast(messageOrOptions)\n}\n\nconst createVariantToast = (variant: ToastVariantShorthand) => {\n return (messageOrOptions: string | Omit<ToastProps, 'variant'>, options: ToastVariantOptions = {}) => {\n if (typeof messageOrOptions === 'string') {\n return showToast({ ...options, message: messageOrOptions, variant })\n }\n\n return showToast({ ...messageOrOptions, variant })\n }\n}\n\nexport const Toast = Object.assign(ToastComponent, {\n Provider: ToastProvider,\n})\n\nexport const toast = Object.assign(toastBase, {\n success: createVariantToast('success'),\n error: createVariantToast('error'),\n info: createVariantToast('info'),\n warning: createVariantToast('warning'),\n dismiss: sonnerToast.dismiss,\n})\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","names":[],"sources":["../../src/primitives/input.tsx"],"mappings":";;;;;KAGY,SAAA;AAAA,UAEK,UAAA,SAAmB,cAAA;EAClC,SAAA;EACA,IAAA,GAAO,SAAA;AAAA;AAAA,cAGI,KAAA;EAAK,SAAA;EAAA,IAAA;EAAA,GAAA;AAAA,GAAmC,UAAA,KAAU,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"input.d.ts","names":[],"sources":["../../src/primitives/input.tsx"],"mappings":";;;;;KAIY,SAAA;AAAA,UAEK,UAAA,SAAmB,cAAA;EAClC,SAAA;EACA,IAAA,GAAO,SAAA;AAAA;AAAA,cAGI,KAAA;EAAK,SAAA;EAAA,IAAA;EAAA,GAAA;AAAA,GAAmC,UAAA,KAAU,oBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { cn } from "../utils/twUtils.js";
3
+ import { getPasswordManagerIgnoreProps } from "../utils/formFieldUtils.js";
3
4
  import "react";
4
5
  import { jsx } from "react/jsx-runtime";
5
6
 
@@ -9,6 +10,7 @@ const Input = ({ className, type, ...props }) => {
9
10
  className: cn("h-9 min-w-0 rounded-md w-full border border-input-border selection:bg-input-bg--selected selection:text-input-text file:text-input-text placeholder:text-input-text-placeholder", "px-3 py-1 text-base shadow-xs file:h-7 transition-[color,box-shadow] file:inline-flex file:border-0 hover:border-input-border--hover focus:border-input-border--focus focus:outline-none", "file:text-sm file:font-medium file:bg-transparent focus-visible:outline focus-visible:outline-accent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", "focus-visible:outline-offset-2 aria-invalid:border-danger-400 aria-invalid:ring-danger-400", className),
10
11
  "data-slot": "input-primitive",
11
12
  type,
13
+ ...getPasswordManagerIgnoreProps(type),
12
14
  ...props
13
15
  });
14
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","names":[],"sources":["../../src/primitives/input.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport type InputType = 'text' | 'email' | 'url' | 'tel' | 'password' | 'number' | 'date' | 'datetime-local'\n\nexport interface InputProps extends ComponentProps<'input'> {\n className?: string\n type?: InputType\n}\n\nexport const Input = ({ className, type, ...props }: InputProps) => {\n return (\n <input\n className={cn(\n 'h-9 min-w-0 rounded-md w-full border border-input-border selection:bg-input-bg--selected selection:text-input-text file:text-input-text placeholder:text-input-text-placeholder',\n 'px-3 py-1 text-base shadow-xs file:h-7 transition-[color,box-shadow] file:inline-flex file:border-0 hover:border-input-border--hover focus:border-input-border--focus focus:outline-none',\n 'file:text-sm file:font-medium file:bg-transparent focus-visible:outline focus-visible:outline-accent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',\n 'focus-visible:outline-offset-2 aria-invalid:border-danger-400 aria-invalid:ring-danger-400',\n className,\n )}\n data-slot='input-primitive'\n type={type}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;AAUA,MAAa,SAAS,EAAE,WAAW,MAAM,GAAG,YAAwB;AAClE,QACE,oBAAC,SAAD;EACE,WAAW,GACT,mLACA,4LACA,qLACA,8FACA,UACD;EACD,aAAU;EACJ;EACN,GAAI;EACJ"}
1
+ {"version":3,"file":"input.js","names":[],"sources":["../../src/primitives/input.tsx"],"sourcesContent":["import { getPasswordManagerIgnoreProps } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport type InputType = 'text' | 'email' | 'url' | 'tel' | 'password' | 'number' | 'date' | 'datetime-local'\n\nexport interface InputProps extends ComponentProps<'input'> {\n className?: string\n type?: InputType\n}\n\nexport const Input = ({ className, type, ...props }: InputProps) => {\n return (\n <input\n className={cn(\n 'h-9 min-w-0 rounded-md w-full border border-input-border selection:bg-input-bg--selected selection:text-input-text file:text-input-text placeholder:text-input-text-placeholder',\n 'px-3 py-1 text-base shadow-xs file:h-7 transition-[color,box-shadow] file:inline-flex file:border-0 hover:border-input-border--hover focus:border-input-border--focus focus:outline-none',\n 'file:text-sm file:font-medium file:bg-transparent focus-visible:outline focus-visible:outline-accent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',\n 'focus-visible:outline-offset-2 aria-invalid:border-danger-400 aria-invalid:ring-danger-400',\n className,\n )}\n data-slot='input-primitive'\n type={type}\n {...getPasswordManagerIgnoreProps(type)}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;;AAWA,MAAa,SAAS,EAAE,WAAW,MAAM,GAAG,YAAwB;AAClE,QACE,oBAAC,SAAD;EACE,WAAW,GACT,mLACA,4LACA,qLACA,8FACA,UACD;EACD,aAAU;EACJ;EACN,GAAI,8BAA8B,KAAK;EACvC,GAAI;EACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.d.ts","names":[],"sources":["../../src/primitives/textarea.tsx"],"mappings":";;;;;cAGa,QAAA;EAAQ,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,iBAA0B,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"textarea.d.ts","names":[],"sources":["../../src/primitives/textarea.tsx"],"mappings":";;;;;cAIa,QAAA;EAAQ,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,iBAA0B,oBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { cn } from "../utils/twUtils.js";
3
+ import { getPasswordManagerIgnoreProps } from "../utils/formFieldUtils.js";
3
4
  import "react";
4
5
  import { jsx } from "react/jsx-runtime";
5
6
 
@@ -8,6 +9,7 @@ const Textarea = ({ className, ...props }) => {
8
9
  return /* @__PURE__ */ jsx("textarea", {
9
10
  className: cn("min-h-16 rounded-md px-3 py-2 text-base shadow-xs md:text-sm flex field-sizing-content w-full border border-input-border bg-transparent outline-transparent transition-[color,box-shadow] placeholder:text-input-text-placeholder focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:outline-offset-2 aria-invalid:outline-danger-400", className),
10
11
  "data-slot": "textarea",
12
+ ...getPasswordManagerIgnoreProps(),
11
13
  ...props
12
14
  });
13
15
  };
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","names":[],"sources":["../../src/primitives/textarea.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport const Textarea = ({ className, ...props }: ComponentProps<'textarea'>) => {\n return (\n <textarea\n className={cn(\n 'min-h-16 rounded-md px-3 py-2 text-base shadow-xs md:text-sm flex field-sizing-content w-full border border-input-border bg-transparent outline-transparent transition-[color,box-shadow] placeholder:text-input-text-placeholder focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:outline-offset-2 aria-invalid:outline-danger-400',\n className,\n )}\n data-slot='textarea'\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;AAGA,MAAa,YAAY,EAAE,WAAW,GAAG,YAAwC;AAC/E,QACE,oBAAC,YAAD;EACE,WAAW,GACT,uaACA,UACD;EACD,aAAU;EACV,GAAI;EACJ"}
1
+ {"version":3,"file":"textarea.js","names":[],"sources":["../../src/primitives/textarea.tsx"],"sourcesContent":["import { getPasswordManagerIgnoreProps } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport const Textarea = ({ className, ...props }: ComponentProps<'textarea'>) => {\n return (\n <textarea\n className={cn(\n 'min-h-16 rounded-md px-3 py-2 text-base shadow-xs md:text-sm flex field-sizing-content w-full border border-input-border bg-transparent outline-transparent transition-[color,box-shadow] placeholder:text-input-text-placeholder focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:outline-offset-2 aria-invalid:outline-danger-400',\n className,\n )}\n data-slot='textarea'\n {...getPasswordManagerIgnoreProps()}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;;AAIA,MAAa,YAAY,EAAE,WAAW,GAAG,YAAwC;AAC/E,QACE,oBAAC,YAAD;EACE,WAAW,GACT,uaACA,UACD;EACD,aAAU;EACV,GAAI,+BAA+B;EACnC,GAAI;EACJ"}