@spear-ai/spectral 1.14.1 → 1.14.3

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 (77) hide show
  1. package/dist/Button.d.ts +4 -0
  2. package/dist/Button.d.ts.map +1 -1
  3. package/dist/Button.js +4 -2
  4. package/dist/Button.js.map +1 -1
  5. package/dist/Checkbox.d.ts +4 -0
  6. package/dist/Checkbox.d.ts.map +1 -1
  7. package/dist/Checkbox.js +7 -3
  8. package/dist/Checkbox.js.map +1 -1
  9. package/dist/Combobox.d.ts +2 -0
  10. package/dist/Combobox.d.ts.map +1 -1
  11. package/dist/Combobox.js +7 -3
  12. package/dist/Combobox.js.map +1 -1
  13. package/dist/ControlGroup/ControlGroupSelect.d.ts +5 -1
  14. package/dist/ControlGroup/ControlGroupSelect.d.ts.map +1 -1
  15. package/dist/ControlGroup/ControlGroupSelect.js +3 -1
  16. package/dist/ControlGroup/ControlGroupSelect.js.map +1 -1
  17. package/dist/ControlGroup.d.ts +4 -0
  18. package/dist/ControlGroup.d.ts.map +1 -1
  19. package/dist/ControlGroup.js +7 -3
  20. package/dist/ControlGroup.js.map +1 -1
  21. package/dist/DateTimePicker.d.ts +4 -0
  22. package/dist/DateTimePicker.d.ts.map +1 -1
  23. package/dist/DateTimePicker.js +4 -2
  24. package/dist/DateTimePicker.js.map +1 -1
  25. package/dist/FormFieldMessage.d.ts +8 -2
  26. package/dist/FormFieldMessage.d.ts.map +1 -1
  27. package/dist/FormFieldMessage.js +13 -7
  28. package/dist/FormFieldMessage.js.map +1 -1
  29. package/dist/Input.js +7 -3
  30. package/dist/Input.js.map +1 -1
  31. package/dist/InputNumeric.d.ts +3 -1
  32. package/dist/InputNumeric.d.ts.map +1 -1
  33. package/dist/InputNumeric.js.map +1 -1
  34. package/dist/InputOTP.d.ts +4 -0
  35. package/dist/InputOTP.d.ts.map +1 -1
  36. package/dist/InputOTP.js +4 -2
  37. package/dist/InputOTP.js.map +1 -1
  38. package/dist/MultiSelect/MultiSelectBase.d.ts +4 -0
  39. package/dist/MultiSelect/MultiSelectBase.d.ts.map +1 -1
  40. package/dist/MultiSelect/MultiSelectBase.js +7 -3
  41. package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
  42. package/dist/RadioButton.d.ts +2 -0
  43. package/dist/RadioButton.d.ts.map +1 -1
  44. package/dist/RadioButton.js +4 -3
  45. package/dist/RadioButton.js.map +1 -1
  46. package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts +3 -1
  47. package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts.map +1 -1
  48. package/dist/RadioButtonGroup/RadioButtonGroupBase.js +8 -5
  49. package/dist/RadioButtonGroup/RadioButtonGroupBase.js.map +1 -1
  50. package/dist/RadioGroup.d.ts +2 -0
  51. package/dist/RadioGroup.d.ts.map +1 -1
  52. package/dist/RadioGroup.js +7 -3
  53. package/dist/RadioGroup.js.map +1 -1
  54. package/dist/Select.js +7 -3
  55. package/dist/Select.js.map +1 -1
  56. package/dist/Switch.d.ts +4 -0
  57. package/dist/Switch.d.ts.map +1 -1
  58. package/dist/Switch.js +7 -3
  59. package/dist/Switch.js.map +1 -1
  60. package/dist/Textarea.d.ts +3 -1
  61. package/dist/Textarea.d.ts.map +1 -1
  62. package/dist/Textarea.js +7 -3
  63. package/dist/Textarea.js.map +1 -1
  64. package/dist/ToggleGroup/ToggleGroupBase.d.ts +6 -3
  65. package/dist/ToggleGroup/ToggleGroupBase.d.ts.map +1 -1
  66. package/dist/ToggleGroup/ToggleGroupBase.js +9 -1
  67. package/dist/ToggleGroup/ToggleGroupBase.js.map +1 -1
  68. package/dist/ToggleGroup/ToggleGroupItem.js +1 -1
  69. package/dist/ToggleGroup/ToggleGroupItem.js.map +1 -1
  70. package/dist/ToggleGroup.js +1 -1
  71. package/dist/ToggleGroup.js.map +1 -1
  72. package/dist/styles/horizon/colors.css +1 -0
  73. package/dist/styles/spectral.css +1 -1
  74. package/dist/utils/formFieldUtils.d.ts +2 -0
  75. package/dist/utils/formFieldUtils.d.ts.map +1 -1
  76. package/dist/utils/formFieldUtils.js.map +1 -1
  77. package/package.json +2 -2
package/dist/Switch.js CHANGED
@@ -10,7 +10,7 @@ import { CheckIcon, XIcon } from "lucide-react";
10
10
 
11
11
  //#region src/components/Switch/Switch.tsx
12
12
  const thumbBase = "bg-switch-thumb--checked data-[state=checked]:bg-switch-thumb pointer-events-none block rounded-full ring-0 transition-transform motion-reduce:transition-none";
13
- const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, label, labelPosition = "right", labelText, name, onChange, ref, required, state = "default", value, variant, warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, ...props }) => {
13
+ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, label, labelPosition = "right", labelText, messageReserveLines = 1, messageReserveSpace = true, name, onChange, ref, required, state = "default", value, variant, warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, ...props }) => {
14
14
  const switchId = useFormFieldId(id, name);
15
15
  const isDisabled = Boolean(disabled);
16
16
  const resolvedLabelText = labelText ?? label;
@@ -97,12 +97,16 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
97
97
  /* @__PURE__ */ jsx(ErrorMessage, {
98
98
  dataTestId: "spectral-switch-error-message",
99
99
  id: errorMessageId,
100
- message: state === "error" ? errorMessage ?? null : null
100
+ message: state === "error" ? errorMessage ?? null : null,
101
+ messageReserveLines,
102
+ messageReserveSpace: messageReserveSpace && state === "error"
101
103
  }),
102
104
  /* @__PURE__ */ jsx(WarningMessage, {
103
105
  dataTestId: "spectral-switch-warning-message",
104
106
  id: warningMessageId,
105
- message: state === "warning" ? warningMessage ?? null : null
107
+ message: state === "warning" ? warningMessage ?? null : null,
108
+ messageReserveLines,
109
+ messageReserveSpace: messageReserveSpace && state === "warning"
106
110
  })
107
111
  ]
108
112
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","names":["SwitchBase"],"sources":["../src/components/Switch/Switch.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { CheckIcon, XIcon } from 'lucide-react'\nimport { type Ref } from 'react'\nimport { Switch as SwitchBase, SwitchThumb, type SwitchProps as SwitchBaseProps } from './SwitchBase'\n\ntype SwitchVisualState = Exclude<FormFieldState, 'disabled'>\n\nexport type SwitchProps = Omit<SwitchBaseProps, 'onCheckedChange'> & {\n 'aria-describedby'?: string\n 'aria-label'?: string\n errorMessage?: BaseFormFieldProps['errorMessage']\n hideLabel?: boolean\n id?: string\n label?: string\n labelPosition?: 'left' | 'right'\n labelText?: string\n 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 name,\n onChange,\n ref,\n required,\n state = 'default',\n value,\n variant,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n ...props\n}: SwitchProps) => {\n const switchId = useFormFieldId(id, name)\n const isDisabled = Boolean(disabled)\n const resolvedLabelText = labelText ?? label\n const errorMessageId = `${switchId}-error`\n const warningMessageId = `${switchId}-warning`\n const messageId = state === 'error' && errorMessage && errorMessageId ? errorMessageId : state === 'warning' && warningMessage && warningMessageId ? warningMessageId : undefined\n const isSquared = variant === 'squared'\n const isPermanentIndicator = variant === 'permanent-indicator'\n\n return (\n <div className='flex items-center' data-testid='spectral-switch-container' data-state={state}>\n {labelPosition === 'left' && !hideLabel && resolvedLabelText && (\n <Label className='mr-2' data-testid='spectral-switch-label-left' htmlFor={switchId}>\n {resolvedLabelText}\n </Label>\n )}\n\n {isPermanentIndicator ? (\n <div className='h-7 text-sm font-medium relative inline-grid grid-cols-[1fr_1fr] items-center'>\n <SwitchBase\n aria-required={required}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n className={cn(\n 'peer inset-0 w-14 focus-visible:ring-ring absolute inline-flex h-[inherit] items-center focus-visible:ring-offset-background data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg/50',\n 'shadow-2xs cursor-pointer rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n data-testid='spectral-switch'\n disabled={isDisabled}\n id={switchId}\n name={name}\n onCheckedChange={onChange}\n ref={ref}\n required={required}\n value={value}\n {...props}\n >\n <SwitchThumb className={cn(thumbBase, 'size-6.5 shadow-xs relative z-10 duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] data-[state=checked]:translate-x-[26px] motion-reduce:duration-0 data-[state=checked]:rtl:translate-x-[-26px]')} />\n </SwitchBase>\n <span className='ml-0.5 min-w-8 peer-data-[state=unchecked]:translate-x-6 peer-data-[state=unchecked]:rtl:-translate-x-6 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:invisible motion-reduce:transition-none motion-reduce:duration-0'>\n <XIcon aria-hidden='true' className='size-4' />\n </span>\n <span className='min-w-8 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:-translate-x-full peer-data-[state=checked]:text-background peer-data-[state=unchecked]:invisible motion-reduce:transition-none motion-reduce:duration-0 peer-data-[state=checked]:rtl:translate-x-full'>\n <CheckIcon aria-hidden='true' className='size-4' />\n </span>\n </div>\n ) : (\n <SwitchBase\n aria-required={required}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n className={cn(\n isSquared\n ? 'peer h-6 w-10 rounded-sm focus-visible:ring-black inline-flex shrink-0 items-center border-2 border-transparent transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg [&_span]:rounded-[4px]'\n : 'focus-visible:ring-ring peer h-6 w-10 shadow-2xs inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg',\n className,\n )}\n data-testid='spectral-switch'\n disabled={isDisabled}\n id={switchId}\n name={name}\n onCheckedChange={onChange}\n ref={ref}\n required={required}\n value={value}\n {...props}\n >\n <SwitchThumb className={cn(thumbBase, isSquared ? 'size-5 shadow-xs data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4' : 'h-5 w-5 shadow-lg data-[state=checked]:translate-x-4')} />\n </SwitchBase>\n )}\n\n {labelPosition === 'right' && !hideLabel && resolvedLabelText && (\n <Label className='ml-2' data-testid='spectral-switch-label-right' htmlFor={switchId} id={`${switchId}-label`}>\n {resolvedLabelText}\n </Label>\n )}\n\n {hideLabel && resolvedLabelText && (\n <Label className='sr-only' data-testid='spectral-switch-label-hidden' htmlFor={switchId}>\n {resolvedLabelText}\n </Label>\n )}\n <ErrorMessage dataTestId='spectral-switch-error-message' id={errorMessageId} message={state === 'error' ? (errorMessage ?? null) : null} />\n <WarningMessage dataTestId='spectral-switch-warning-message' id={warningMessageId} message={state === 'warning' ? (warningMessage ?? null) : null} />\n </div>\n )\n}\nSwitch.displayName = 'Switch'\n"],"mappings":";;;;;;;;;;;AA2BA,MAAM,YAAY;AAElB,MAAa,UAAU,EACrB,WACA,UACA,cACA,YAAY,OACZ,IACA,OACA,gBAAgB,SAChB,WACA,MACA,UACA,KACA,UACA,QAAQ,WACR,OACA,SACA,gBACA,oBAAoB,iBACpB,cAAc,WACd,GAAG,YACc;CACjB,MAAM,WAAW,eAAe,IAAI,KAAK;CACzC,MAAM,aAAa,QAAQ,SAAS;CACpC,MAAM,oBAAoB,aAAa;CACvC,MAAM,iBAAiB,GAAG,SAAS;CACnC,MAAM,mBAAmB,GAAG,SAAS;CACrC,MAAM,YAAY,UAAU,WAAW,gBAAgB,iBAAiB,iBAAiB,UAAU,aAAa,kBAAkB,mBAAmB,mBAAmB;CACxK,MAAM,YAAY,YAAY;AAG9B,QACE,qBAAC,OAAD;EAAK,WAAU;EAAoB,eAAY;EAA4B,cAAY;YAAvF;GACG,kBAAkB,UAAU,CAAC,aAAa,qBACzC,oBAAC,OAAD;IAAO,WAAU;IAAO,eAAY;IAA6B,SAAS;cACvE;IACK;GAPe,YAAY,wBAWnC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAACA,UAAD;MACE,iBAAe;MACf,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;MAC5E,gBAAc,UAAU,UAAU,OAAO;MACzC,cAAY,cAAc,YAAY,oBAAoB;MAC1D,WAAW,GACT,kNACA,oKACA,mDACA,UACD;MACD,eAAY;MACZ,UAAU;MACV,IAAI;MACE;MACN,iBAAiB;MACZ;MACK;MACH;MACP,GAAI;gBAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,gMAAgM,EAAI;MAC/N;KACb,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,OAAD;OAAO,eAAY;OAAO,WAAU;OAAW;MAC1C;KACP,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD;OAAW,eAAY;OAAO,WAAU;OAAW;MAC9C;KACH;QAEN,oBAACA,UAAD;IACE,iBAAe;IACf,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;IAC5E,gBAAc,UAAU,UAAU,OAAO;IACzC,cAAY,cAAc,YAAY,oBAAoB;IAC1D,WAAW,GACT,YACI,+TACA,gZACJ,UACD;IACD,eAAY;IACZ,UAAU;IACV,IAAI;IACE;IACN,iBAAiB;IACZ;IACK;IACH;IACP,GAAI;cAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,YAAY,gGAAgG,uDAAuD,EAAI;IAClM;GAGd,kBAAkB,WAAW,CAAC,aAAa,qBAC1C,oBAAC,OAAD;IAAO,WAAU;IAAO,eAAY;IAA8B,SAAS;IAAU,IAAI,GAAG,SAAS;cAClG;IACK;GAGT,aAAa,qBACZ,oBAAC,OAAD;IAAO,WAAU;IAAU,eAAY;IAA+B,SAAS;cAC5E;IACK;GAEV,oBAAC,cAAD;IAAc,YAAW;IAAgC,IAAI;IAAgB,SAAS,UAAU,UAAW,gBAAgB,OAAQ;IAAQ;GAC3I,oBAAC,gBAAD;IAAgB,YAAW;IAAkC,IAAI;IAAkB,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IAAQ;GACjJ;;;AAGV,OAAO,cAAc"}
1
+ {"version":3,"file":"Switch.js","names":["SwitchBase"],"sources":["../src/components/Switch/Switch.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { CheckIcon, XIcon } from 'lucide-react'\nimport { type Ref } from 'react'\nimport { Switch as SwitchBase, SwitchThumb, type SwitchProps as SwitchBaseProps } from './SwitchBase'\n\ntype SwitchVisualState = Exclude<FormFieldState, 'disabled'>\n\nexport type SwitchProps = Omit<SwitchBaseProps, 'onCheckedChange'> & {\n 'aria-describedby'?: string\n 'aria-label'?: string\n errorMessage?: BaseFormFieldProps['errorMessage']\n hideLabel?: boolean\n id?: string\n label?: string\n labelPosition?: 'left' | 'right'\n labelText?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (checked: boolean) => void\n ref?: Ref<HTMLButtonElement>\n required?: boolean\n state?: SwitchVisualState\n value?: string\n variant?: 'default' | 'squared' | 'permanent-indicator'\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst thumbBase = 'bg-switch-thumb--checked data-[state=checked]:bg-switch-thumb pointer-events-none block rounded-full ring-0 transition-transform motion-reduce:transition-none'\n\nexport const Switch = ({\n className,\n disabled,\n errorMessage,\n hideLabel = false,\n id,\n label,\n labelPosition = 'right',\n labelText,\n messageReserveLines = 1,\n messageReserveSpace = true,\n name,\n onChange,\n ref,\n required,\n state = 'default',\n value,\n variant,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n ...props\n}: SwitchProps) => {\n const switchId = useFormFieldId(id, name)\n const isDisabled = Boolean(disabled)\n const resolvedLabelText = labelText ?? label\n const errorMessageId = `${switchId}-error`\n const warningMessageId = `${switchId}-warning`\n const messageId = state === 'error' && errorMessage && errorMessageId ? errorMessageId : state === 'warning' && warningMessage && warningMessageId ? warningMessageId : undefined\n const isSquared = variant === 'squared'\n const isPermanentIndicator = variant === 'permanent-indicator'\n\n return (\n <div className='flex items-center' data-testid='spectral-switch-container' data-state={state}>\n {labelPosition === 'left' && !hideLabel && resolvedLabelText && (\n <Label className='mr-2' data-testid='spectral-switch-label-left' htmlFor={switchId}>\n {resolvedLabelText}\n </Label>\n )}\n\n {isPermanentIndicator ? (\n <div className='h-7 text-sm font-medium relative inline-grid grid-cols-[1fr_1fr] items-center'>\n <SwitchBase\n aria-required={required}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n className={cn(\n 'peer inset-0 w-14 focus-visible:ring-ring absolute inline-flex h-[inherit] items-center focus-visible:ring-offset-background data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg/50',\n 'shadow-2xs cursor-pointer rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n data-testid='spectral-switch'\n disabled={isDisabled}\n id={switchId}\n name={name}\n onCheckedChange={onChange}\n ref={ref}\n required={required}\n value={value}\n {...props}\n >\n <SwitchThumb className={cn(thumbBase, 'size-6.5 shadow-xs relative z-10 duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] data-[state=checked]:translate-x-[26px] motion-reduce:duration-0 data-[state=checked]:rtl:translate-x-[-26px]')} />\n </SwitchBase>\n <span className='ml-0.5 min-w-8 peer-data-[state=unchecked]:translate-x-6 peer-data-[state=unchecked]:rtl:-translate-x-6 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:invisible motion-reduce:transition-none motion-reduce:duration-0'>\n <XIcon aria-hidden='true' className='size-4' />\n </span>\n <span className='min-w-8 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:-translate-x-full peer-data-[state=checked]:text-background peer-data-[state=unchecked]:invisible motion-reduce:transition-none motion-reduce:duration-0 peer-data-[state=checked]:rtl:translate-x-full'>\n <CheckIcon aria-hidden='true' className='size-4' />\n </span>\n </div>\n ) : (\n <SwitchBase\n aria-required={required}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (hideLabel ? resolvedLabelText : undefined)}\n className={cn(\n isSquared\n ? 'peer h-6 w-10 rounded-sm focus-visible:ring-black inline-flex shrink-0 items-center border-2 border-transparent transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg [&_span]:rounded-[4px]'\n : 'focus-visible:ring-ring peer h-6 w-10 shadow-2xs inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg',\n className,\n )}\n data-testid='spectral-switch'\n disabled={isDisabled}\n id={switchId}\n name={name}\n onCheckedChange={onChange}\n ref={ref}\n required={required}\n value={value}\n {...props}\n >\n <SwitchThumb className={cn(thumbBase, isSquared ? 'size-5 shadow-xs data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4' : 'h-5 w-5 shadow-lg data-[state=checked]:translate-x-4')} />\n </SwitchBase>\n )}\n\n {labelPosition === 'right' && !hideLabel && resolvedLabelText && (\n <Label className='ml-2' data-testid='spectral-switch-label-right' htmlFor={switchId} id={`${switchId}-label`}>\n {resolvedLabelText}\n </Label>\n )}\n\n {hideLabel && resolvedLabelText && (\n <Label className='sr-only' data-testid='spectral-switch-label-hidden' htmlFor={switchId}>\n {resolvedLabelText}\n </Label>\n )}\n <ErrorMessage dataTestId='spectral-switch-error-message' id={errorMessageId} message={state === 'error' ? (errorMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'error'} />\n <WarningMessage dataTestId='spectral-switch-warning-message' id={warningMessageId} message={state === 'warning' ? (warningMessage ?? null) : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'warning'} />\n </div>\n )\n}\nSwitch.displayName = 'Switch'\n"],"mappings":";;;;;;;;;;;AA6BA,MAAM,YAAY;AAElB,MAAa,UAAU,EACrB,WACA,UACA,cACA,YAAY,OACZ,IACA,OACA,gBAAgB,SAChB,WACA,sBAAsB,GACtB,sBAAsB,MACtB,MACA,UACA,KACA,UACA,QAAQ,WACR,OACA,SACA,gBACA,oBAAoB,iBACpB,cAAc,WACd,GAAG,YACc;CACjB,MAAM,WAAW,eAAe,IAAI,KAAK;CACzC,MAAM,aAAa,QAAQ,SAAS;CACpC,MAAM,oBAAoB,aAAa;CACvC,MAAM,iBAAiB,GAAG,SAAS;CACnC,MAAM,mBAAmB,GAAG,SAAS;CACrC,MAAM,YAAY,UAAU,WAAW,gBAAgB,iBAAiB,iBAAiB,UAAU,aAAa,kBAAkB,mBAAmB,mBAAmB;CACxK,MAAM,YAAY,YAAY;AAG9B,QACE,qBAAC,OAAD;EAAK,WAAU;EAAoB,eAAY;EAA4B,cAAY;YAAvF;GACG,kBAAkB,UAAU,CAAC,aAAa,qBACzC,oBAAC,OAAD;IAAO,WAAU;IAAO,eAAY;IAA6B,SAAS;cACvE;IACK;GAPe,YAAY,wBAWnC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAACA,UAAD;MACE,iBAAe;MACf,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;MAC5E,gBAAc,UAAU,UAAU,OAAO;MACzC,cAAY,cAAc,YAAY,oBAAoB;MAC1D,WAAW,GACT,kNACA,oKACA,mDACA,UACD;MACD,eAAY;MACZ,UAAU;MACV,IAAI;MACE;MACN,iBAAiB;MACZ;MACK;MACH;MACP,GAAI;gBAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,gMAAgM,EAAI;MAC/N;KACb,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,OAAD;OAAO,eAAY;OAAO,WAAU;OAAW;MAC1C;KACP,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD;OAAW,eAAY;OAAO,WAAU;OAAW;MAC9C;KACH;QAEN,oBAACA,UAAD;IACE,iBAAe;IACf,oBAAkB,CAAC,WAAW,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;IAC5E,gBAAc,UAAU,UAAU,OAAO;IACzC,cAAY,cAAc,YAAY,oBAAoB;IAC1D,WAAW,GACT,YACI,+TACA,gZACJ,UACD;IACD,eAAY;IACZ,UAAU;IACV,IAAI;IACE;IACN,iBAAiB;IACZ;IACK;IACH;IACP,GAAI;cAEJ,oBAAC,aAAD,EAAa,WAAW,GAAG,WAAW,YAAY,gGAAgG,uDAAuD,EAAI;IAClM;GAGd,kBAAkB,WAAW,CAAC,aAAa,qBAC1C,oBAAC,OAAD;IAAO,WAAU;IAAO,eAAY;IAA8B,SAAS;IAAU,IAAI,GAAG,SAAS;cAClG;IACK;GAGT,aAAa,qBACZ,oBAAC,OAAD;IAAO,WAAU;IAAU,eAAY;IAA+B,SAAS;cAC5E;IACK;GAEV,oBAAC,cAAD;IAAc,YAAW;IAAgC,IAAI;IAAgB,SAAS,UAAU,UAAW,gBAAgB,OAAQ;IAA2B;IAAqB,qBAAqB,uBAAuB,UAAU;IAAW;GACpP,oBAAC,gBAAD;IAAgB,YAAW;IAAkC,IAAI;IAAkB,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IAA2B;IAAqB,qBAAqB,uBAAuB,UAAU;IAAa;GAC5P;;;AAGV,OAAO,cAAc"}
@@ -11,7 +11,9 @@ type TextareaProps = Omit<ComponentProps<'textarea'>, 'onChange'> & {
11
11
  id?: string | undefined;
12
12
  label: string;
13
13
  labelClassName?: string;
14
- maxLength?: number | undefined;
14
+ maxLength?: number | undefined; /** Number of message lines to reserve (default: 1). */
15
+ messageReserveLines?: number; /** Whether to keep message space reserved when hidden (default: true). */
16
+ messageReserveSpace?: boolean;
15
17
  name: string;
16
18
  onBlur?: (e: FocusEvent<HTMLTextAreaElement>) => void;
17
19
  onChange?: (value: string) => 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;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,EAAA;EACA,KAAA;EACA,cAAA;EACA,SAAA,uBANU;EAQV,mBAAA;EAEA,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
@@ -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, name, onBlur, onChange, onFocus, placeholder, required, state = "default", value: valueProp, warningMessage, ...props } = allProps;
22
+ const { ref, autoComplete, className, defaultValue, disabled, errorMessage, id, label, labelClassName, maxLength = 280, messageReserveLines = 1, messageReserveSpace = true, 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`;
@@ -103,12 +103,16 @@ const Textarea = (allProps) => {
103
103
  /* @__PURE__ */ jsx(ErrorMessage, {
104
104
  dataTestId: "spectral-textarea-error-message",
105
105
  id: errorMessageId,
106
- message: state === "error" ? errorMessage : null
106
+ message: state === "error" ? errorMessage : null,
107
+ messageReserveLines,
108
+ messageReserveSpace: messageReserveSpace && state === "error"
107
109
  }),
108
110
  /* @__PURE__ */ jsx(WarningMessage, {
109
111
  dataTestId: "spectral-textarea-warning-message",
110
112
  id: warningMessageId,
111
- message: state === "warning" ? warningMessage : null
113
+ message: state === "warning" ? warningMessage : null,
114
+ messageReserveLines,
115
+ messageReserveSpace: messageReserveSpace && state === "warning"
112
116
  })
113
117
  ]
114
118
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.js","names":[],"sources":["../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, getAriaProps, getErrorMessageId, getTextareaClasses, useFormFieldId, useFormFieldState, WarningMessage, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useRef, type ComponentProps, type CSSProperties, type FocusEvent, type Ref } from 'react'\nimport { useTextarea } from './TextareaUtils'\n\nexport type TextareaState = FormFieldState\n\ntype AutoCompleteValue = 'on' | 'off' | 'name' | 'email' | 'username' | 'street-address' | (string & {})\n\nexport type TextareaProps = Omit<ComponentProps<'textarea'>, 'onChange'> & {\n className?: string | undefined\n errorMessage?: BaseFormFieldProps['errorMessage']\n id?: string | undefined\n label: string\n labelClassName?: string\n maxLength?: number | undefined\n 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 { ref, autoComplete, className, defaultValue, disabled, errorMessage, id, label, labelClassName, maxLength = 280, name, onBlur, onChange, onFocus, placeholder, required, state = 'default', value: valueProp, warningMessage, ...props } = allProps\n const textareaId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(textareaId)\n const warningMessageId = `${textareaId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const internalRef = useRef<HTMLTextAreaElement>(null)\n const textareaRef = ref ?? internalRef\n const normalizedDefaultValue = typeof defaultValue === 'string' ? defaultValue : defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ''\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue: normalizedDefaultValue,\n onChange,\n })\n\n const { handleFocus, handleBlur, handleChange, handlePaste } = useTextarea({\n maxLength,\n value,\n onChange: setValue,\n onFocus,\n onBlur,\n })\n\n const { isDisabled, isLoading } = useFormFieldState(disabled, state)\n const ariaProps = getAriaProps(state, props['aria-describedby'], required, messageId)\n const currentLength = value?.length || 0\n const textareaClasses = getTextareaClasses(state, className)\n\n const getCSSCustomProperties = () => ({\n '--textarea-min-height': '6rem',\n '--textarea-max-height': '12rem',\n '--textarea-border-radius': '0.5rem',\n })\n\n return (\n <div className='w-full'>\n {label && (\n <Label data-testid='spectral-textarea-label' htmlFor={textareaId} className={cn('mb-2 block', isDisabled && 'cursor-not-allowed opacity-50', labelClassName)}>\n {label}\n </Label>\n )}\n <div className='relative'>\n <textarea\n aria-multiline='true'\n autoComplete={getAutoCompleteValue(autoComplete)}\n className={textareaClasses}\n data-state={state}\n data-testid='spectral-textarea'\n disabled={isDisabled}\n id={textareaId}\n name={name}\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n onPaste={handlePaste}\n placeholder={placeholder}\n ref={textareaRef}\n required={required}\n spellCheck='true'\n style={getCSSCustomProperties() as CSSProperties}\n value={value}\n {...ariaProps}\n {...props}\n />\n\n {isLoading && (\n <div className={LOADING_ICON_CLASSES} data-testid='spectral-textarea-loading-icon'>\n <LoaderIcon size={24} />\n </div>\n )}\n\n <div\n // oxlint will throw an error when passing ternaries in for aria-label\n aria-label={currentLength + ' of ' + maxLength + ' characters used'}\n aria-live='polite'\n className={getCounterClasses(currentLength, maxLength)}\n data-testid='spectral-textarea-counter'\n role='status'\n >\n {currentLength}/{maxLength}\n </div>\n </div>\n\n <ErrorMessage dataTestId='spectral-textarea-error-message' id={errorMessageId} message={state === 'error' ? errorMessage : null} />\n <WarningMessage dataTestId='spectral-textarea-warning-message' id={warningMessageId} message={state === 'warning' ? warningMessage : null} />\n </div>\n )\n}\nTextarea.displayName = 'Textarea'\n"],"mappings":";;;;;;;;;;;;AA8BA,MAAM,uBAAuB;AAE7B,MAAM,wBAAwB,iBAA6C;AACzE,KAAI,aAAc,QAAO;AACzB,QAAO;;AAGT,MAAM,qBAAqB,eAAuB,cAA8B;AAG9E,QAAO,GAAG,2EADS,iBAAiB,YAAY,oBAAoB,sBAClC;;AAGpC,MAAa,YACX,aAGG;CACH,MAAM,EAAE,KAAK,cAAc,WAAW,cAAc,UAAU,cAAc,IAAI,OAAO,gBAAgB,YAAY,KAAK,MAAM,QAAQ,UAAU,SAAS,aAAa,UAAU,QAAQ,WAAW,OAAO,WAAW,gBAAgB,GAAG,UAAU;CAClP,MAAM,aAAa,eAAe,IAAI,KAAK;CAC3C,MAAM,iBAAiB,kBAAkB,WAAW;CACpD,MAAM,mBAAmB,GAAG,WAAW;CACvC,MAAM,YAAY,UAAU,UAAU,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClH,MAAM,cAAc,OAA4B,KAAK;CACrD,MAAM,cAAc,OAAO;CAE3B,MAAM,CAAC,OAAO,YAAY,qBAA6B;EACrD,OAAO;EACP,cAH6B,OAAO,iBAAiB,WAAW,eAAe,iBAAiB,UAAa,iBAAiB,OAAO,OAAO,aAAa,GAAG;EAI5J;EACD,CAAC;CAEF,MAAM,EAAE,aAAa,YAAY,cAAc,gBAAgB,YAAY;EACzE;EACA;EACA,UAAU;EACV;EACA;EACD,CAAC;CAEF,MAAM,EAAE,YAAY,cAAc,kBAAkB,UAAU,MAAM;CACpE,MAAM,YAAY,aAAa,OAAO,MAAM,qBAAqB,UAAU,UAAU;CACrF,MAAM,gBAAgB,OAAO,UAAU;CACvC,MAAM,kBAAkB,mBAAmB,OAAO,UAAU;CAE5D,MAAM,gCAAgC;EACpC,yBAAyB;EACzB,yBAAyB;EACzB,4BAA4B;EAC7B;AAED,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,oBAAC,OAAD;IAAO,eAAY;IAA0B,SAAS;IAAY,WAAW,GAAG,cAAc,cAAc,iCAAiC,eAAe;cACzJ;IACK;GAEV,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,YAAD;MACE,kBAAe;MACf,cAAc,qBAAqB,aAAa;MAChD,WAAW;MACX,cAAY;MACZ,eAAY;MACZ,UAAU;MACV,IAAI;MACE;MACN,QAAQ;MACR,UAAU;MACV,SAAS;MACT,SAAS;MACI;MACb,KAAK;MACK;MACV,YAAW;MACX,OAAO,wBAAwB;MACxB;MACP,GAAI;MACJ,GAAI;MACJ;KAED,aACC,oBAAC,OAAD;MAAK,WAAW;MAAsB,eAAY;gBAChD,oBAAC,YAAD,EAAY,MAAM,IAAM;MACpB;KAGR,qBAAC,OAAD;MAEE,cAAY,gBAAgB,SAAS,YAAY;MACjD,aAAU;MACV,WAAW,kBAAkB,eAAe,UAAU;MACtD,eAAY;MACZ,MAAK;gBANP;OAQG;OAAc;OAAE;OACb;;KACF;;GAEN,oBAAC,cAAD;IAAc,YAAW;IAAkC,IAAI;IAAgB,SAAS,UAAU,UAAU,eAAe;IAAQ;GACnI,oBAAC,gBAAD;IAAgB,YAAW;IAAoC,IAAI;IAAkB,SAAS,UAAU,YAAY,iBAAiB;IAAQ;GACzI;;;AAGV,SAAS,cAAc"}
1
+ {"version":3,"file":"Textarea.js","names":[],"sources":["../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import { LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, getAriaProps, getErrorMessageId, getTextareaClasses, useFormFieldId, useFormFieldState, WarningMessage, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useRef, type ComponentProps, type CSSProperties, type FocusEvent, type Ref } from 'react'\nimport { useTextarea } from './TextareaUtils'\n\nexport type TextareaState = FormFieldState\n\ntype AutoCompleteValue = 'on' | 'off' | 'name' | 'email' | 'username' | 'street-address' | (string & {})\n\nexport type TextareaProps = Omit<ComponentProps<'textarea'>, 'onChange'> & {\n className?: string | undefined\n errorMessage?: BaseFormFieldProps['errorMessage']\n id?: string | undefined\n label: string\n labelClassName?: string\n maxLength?: number | undefined\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: true). */\n messageReserveSpace?: boolean\n name: string\n onBlur?: (e: FocusEvent<HTMLTextAreaElement>) => void\n onChange?: (value: string) => void\n onFocus?: (e: FocusEvent<HTMLTextAreaElement>) => void\n placeholder?: string | undefined\n required?: boolean\n state?: TextareaState\n value?: string | undefined\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst LOADING_ICON_CLASSES = 'absolute right-4 top-4'\n\nconst getAutoCompleteValue = (autoComplete?: string): AutoCompleteValue => {\n if (autoComplete) return autoComplete\n return 'off'\n}\n\nconst getCounterClasses = (currentLength: number, maxLength: number): string => {\n const baseClasses = 'absolute bottom-2 right-3 text-xs pointer-events-none z-10 tabular-nums'\n const colorClass = currentLength >= maxLength ? 'text-danger-400' : 'text-text-secondary'\n return cn(baseClasses, colorClass)\n}\n\nexport const Textarea = (\n allProps: TextareaProps & {\n ref?: Ref<HTMLTextAreaElement>\n },\n) => {\n const {\n ref,\n autoComplete,\n className,\n defaultValue,\n disabled,\n errorMessage,\n id,\n label,\n labelClassName,\n maxLength = 280,\n messageReserveLines = 1,\n messageReserveSpace = true,\n name,\n onBlur,\n onChange,\n onFocus,\n placeholder,\n required,\n state = 'default',\n value: valueProp,\n warningMessage,\n ...props\n } = allProps\n const textareaId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(textareaId)\n const warningMessageId = `${textareaId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const internalRef = useRef<HTMLTextAreaElement>(null)\n const textareaRef = ref ?? internalRef\n const normalizedDefaultValue = typeof defaultValue === 'string' ? defaultValue : defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ''\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue: normalizedDefaultValue,\n onChange,\n })\n\n const { handleFocus, handleBlur, handleChange, handlePaste } = useTextarea({\n maxLength,\n value,\n onChange: setValue,\n onFocus,\n onBlur,\n })\n\n const { isDisabled, isLoading } = useFormFieldState(disabled, state)\n const ariaProps = getAriaProps(state, props['aria-describedby'], required, messageId)\n const currentLength = value?.length || 0\n const textareaClasses = getTextareaClasses(state, className)\n\n const getCSSCustomProperties = () => ({\n '--textarea-min-height': '6rem',\n '--textarea-max-height': '12rem',\n '--textarea-border-radius': '0.5rem',\n })\n\n return (\n <div className='w-full'>\n {label && (\n <Label data-testid='spectral-textarea-label' htmlFor={textareaId} className={cn('mb-2 block', isDisabled && 'cursor-not-allowed opacity-50', labelClassName)}>\n {label}\n </Label>\n )}\n <div className='relative'>\n <textarea\n aria-multiline='true'\n autoComplete={getAutoCompleteValue(autoComplete)}\n className={textareaClasses}\n data-state={state}\n data-testid='spectral-textarea'\n disabled={isDisabled}\n id={textareaId}\n name={name}\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n onPaste={handlePaste}\n placeholder={placeholder}\n ref={textareaRef}\n required={required}\n spellCheck='true'\n style={getCSSCustomProperties() as CSSProperties}\n value={value}\n {...ariaProps}\n {...props}\n />\n\n {isLoading && (\n <div className={LOADING_ICON_CLASSES} data-testid='spectral-textarea-loading-icon'>\n <LoaderIcon size={24} />\n </div>\n )}\n\n <div\n // oxlint will throw an error when passing ternaries in for aria-label\n aria-label={currentLength + ' of ' + maxLength + ' characters used'}\n aria-live='polite'\n className={getCounterClasses(currentLength, maxLength)}\n data-testid='spectral-textarea-counter'\n role='status'\n >\n {currentLength}/{maxLength}\n </div>\n </div>\n\n <ErrorMessage dataTestId='spectral-textarea-error-message' id={errorMessageId} message={state === 'error' ? errorMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'error'} />\n <WarningMessage dataTestId='spectral-textarea-warning-message' id={warningMessageId} message={state === 'warning' ? warningMessage : null} messageReserveLines={messageReserveLines} messageReserveSpace={messageReserveSpace && state === 'warning'} />\n </div>\n )\n}\nTextarea.displayName = 'Textarea'\n"],"mappings":";;;;;;;;;;;;AAkCA,MAAM,uBAAuB;AAE7B,MAAM,wBAAwB,iBAA6C;AACzE,KAAI,aAAc,QAAO;AACzB,QAAO;;AAGT,MAAM,qBAAqB,eAAuB,cAA8B;AAG9E,QAAO,GAAG,2EADS,iBAAiB,YAAY,oBAAoB,sBAClC;;AAGpC,MAAa,YACX,aAGG;CACH,MAAM,EACJ,KACA,cACA,WACA,cACA,UACA,cACA,IACA,OACA,gBACA,YAAY,KACZ,sBAAsB,GACtB,sBAAsB,MACtB,MACA,QACA,UACA,SACA,aACA,UACA,QAAQ,WACR,OAAO,WACP,gBACA,GAAG,UACD;CACJ,MAAM,aAAa,eAAe,IAAI,KAAK;CAC3C,MAAM,iBAAiB,kBAAkB,WAAW;CACpD,MAAM,mBAAmB,GAAG,WAAW;CACvC,MAAM,YAAY,UAAU,UAAU,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClH,MAAM,cAAc,OAA4B,KAAK;CACrD,MAAM,cAAc,OAAO;CAE3B,MAAM,CAAC,OAAO,YAAY,qBAA6B;EACrD,OAAO;EACP,cAH6B,OAAO,iBAAiB,WAAW,eAAe,iBAAiB,UAAa,iBAAiB,OAAO,OAAO,aAAa,GAAG;EAI5J;EACD,CAAC;CAEF,MAAM,EAAE,aAAa,YAAY,cAAc,gBAAgB,YAAY;EACzE;EACA;EACA,UAAU;EACV;EACA;EACD,CAAC;CAEF,MAAM,EAAE,YAAY,cAAc,kBAAkB,UAAU,MAAM;CACpE,MAAM,YAAY,aAAa,OAAO,MAAM,qBAAqB,UAAU,UAAU;CACrF,MAAM,gBAAgB,OAAO,UAAU;CACvC,MAAM,kBAAkB,mBAAmB,OAAO,UAAU;CAE5D,MAAM,gCAAgC;EACpC,yBAAyB;EACzB,yBAAyB;EACzB,4BAA4B;EAC7B;AAED,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,oBAAC,OAAD;IAAO,eAAY;IAA0B,SAAS;IAAY,WAAW,GAAG,cAAc,cAAc,iCAAiC,eAAe;cACzJ;IACK;GAEV,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,YAAD;MACE,kBAAe;MACf,cAAc,qBAAqB,aAAa;MAChD,WAAW;MACX,cAAY;MACZ,eAAY;MACZ,UAAU;MACV,IAAI;MACE;MACN,QAAQ;MACR,UAAU;MACV,SAAS;MACT,SAAS;MACI;MACb,KAAK;MACK;MACV,YAAW;MACX,OAAO,wBAAwB;MACxB;MACP,GAAI;MACJ,GAAI;MACJ;KAED,aACC,oBAAC,OAAD;MAAK,WAAW;MAAsB,eAAY;gBAChD,oBAAC,YAAD,EAAY,MAAM,IAAM;MACpB;KAGR,qBAAC,OAAD;MAEE,cAAY,gBAAgB,SAAS,YAAY;MACjD,aAAU;MACV,WAAW,kBAAkB,eAAe,UAAU;MACtD,eAAY;MACZ,MAAK;gBANP;OAQG;OAAc;OAAE;OACb;;KACF;;GAEN,oBAAC,cAAD;IAAc,YAAW;IAAkC,IAAI;IAAgB,SAAS,UAAU,UAAU,eAAe;IAA2B;IAAqB,qBAAqB,uBAAuB,UAAU;IAAW;GAC5O,oBAAC,gBAAD;IAAgB,YAAW;IAAoC,IAAI;IAAkB,SAAS,UAAU,YAAY,iBAAiB;IAA2B;IAAqB,qBAAqB,uBAAuB,UAAU;IAAa;GACpP;;;AAGV,SAAS,cAAc"}
@@ -6,19 +6,22 @@ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
6
6
  type Orientation = 'horizontal' | 'vertical';
7
7
  interface CommonGroupProps {
8
8
  className?: string;
9
- defaultValue?: string | string[];
10
9
  disabled?: boolean;
11
10
  loop?: boolean;
12
11
  name?: string;
13
- onValueChange?: (v: string | string[]) => void;
14
12
  orientation?: Orientation;
15
- value?: string | string[];
16
13
  }
17
14
  type SingleProps = CommonGroupProps & {
15
+ defaultValue?: string;
16
+ onValueChange?: (v: string) => void;
18
17
  type?: 'single';
18
+ value?: string;
19
19
  };
20
20
  type MultipleProps = CommonGroupProps & {
21
+ defaultValue?: string[];
22
+ onValueChange?: (v: string[]) => void;
21
23
  type: 'multiple';
24
+ value?: string[];
22
25
  };
23
26
  type ToggleGroupProps = (SingleProps | MultipleProps) & Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>;
24
27
  interface ItemRenderProps {
@@ -1 +1 @@
1
- {"version":3,"file":"ToggleGroupBase.d.ts","names":[],"sources":["../../src/components/ToggleGroup/ToggleGroupBase.tsx"],"mappings":";;;;;KAKK,WAAA;AAAA,UAEY,gBAAA;EACf,SAAA;EACA,YAAA;EACA,QAAA;EACA,IAAA;EACA,IAAA;EACA,aAAA,IAAiB,CAAA;EACjB,WAAA,GAAc,WAAA;EACd,KAAA;AAAA;AAAA,KAGU,WAAA,GAAc,gBAAA;EACxB,IAAA;AAAA;AAAA,KAGU,aAAA,GAAgB,gBAAA;EAC1B,IAAA;AAAA;AAAA,KAGU,gBAAA,IAAoB,WAAA,GAAc,aAAA,IAAiB,IAAA,CAAK,cAAA,CAAe,cAAA;AAAA,UAElE,eAAA;EACf,QAAA,GAAW,SAAA;EACX,SAAA;EACA,QAAA;EACA,KAAA;AAAA;AAAA,cAiBW,eAAA,GAAe,KAAA,EAAW,gBAAA,GAAmB,MAAA,gCAAiC,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,KA0F/E,oBAAA,GAAuB,IAAA,CAAK,oBAAA,CAAqB,iBAAA,oEAC3D,eAAA;mFAEE,OAAA,YA3HE;EA6HF,cAAA;AAAA;AAAA,cAGS,mBAAA;EAAmB,GAAA;EAAA,KAAA;EAAA,QAAA;EAAA,SAAA;EAAA,QAAA;EAAA,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAS7B,oBAAA;EACD,GAAA,GAAM,GAAA,CAAI,iBAAA;AAAA,MACX,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"ToggleGroupBase.d.ts","names":[],"sources":["../../src/components/ToggleGroup/ToggleGroupBase.tsx"],"mappings":";;;;;KAKK,WAAA;AAAA,UAEY,gBAAA;EACf,SAAA;EACA,QAAA;EACA,IAAA;EACA,IAAA;EACA,WAAA,GAAc,WAAA;AAAA;AAAA,KAGJ,WAAA,GAAc,gBAAA;EACxB,YAAA;EACA,aAAA,IAAiB,CAAA;EACjB,IAAA;EACA,KAAA;AAAA;AAAA,KAGU,aAAA,GAAgB,gBAAA;EAC1B,YAAA;EACA,aAAA,IAAiB,CAAA;EACjB,IAAA;EACA,KAAA;AAAA;AAAA,KAGU,gBAAA,IAAoB,WAAA,GAAc,aAAA,IAAiB,IAAA,CAAK,cAAA,CAAe,cAAA;AAAA,UAElE,eAAA;EACf,QAAA,GAAW,SAAA;EACX,SAAA;EACA,QAAA;EACA,KAAA;AAAA;AAAA,cAiBW,eAAA,GAAe,KAAA,EAAW,gBAAA,GAAmB,MAAA,gCAAiC,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,KAwG/E,oBAAA,GAAuB,IAAA,CAAK,oBAAA,CAAqB,iBAAA,oEAC3D,eAAA;EA1IA,iFA4IE,OAAA,YA5IG;EA8IH,cAAA;AAAA;AAAA,cAGS,mBAAA;EAAmB,GAAA;EAAA,KAAA;EAAA,QAAA;EAAA,SAAA;EAAA,QAAA;EAAA,SAAA;EAAA,OAAA;EAAA,GAAA;AAAA,GAS7B,oBAAA;EACD,GAAA,GAAM,GAAA,CAAI,iBAAA;AAAA,MACX,oBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -9,9 +9,17 @@ const GroupContext = createContext(null);
9
9
  const ToggleGroupBase = (props) => {
10
10
  const { className, defaultValue, disabled: groupDisabled = false, loop = true, name, onValueChange, orientation = "horizontal", type = "single", value: valueProp, "data-variant": dataVariant, "data-size": dataSize, "data-slot": dataSlot, "data-layout": dataLayout, ...rest } = props;
11
11
  const isMultiple = type === "multiple";
12
+ const handleValueChange = useCallback((next) => {
13
+ if (!onValueChange) return;
14
+ if (isMultiple) {
15
+ onValueChange(next);
16
+ return;
17
+ }
18
+ onValueChange(next);
19
+ }, [isMultiple, onValueChange]);
12
20
  const [value, setValue] = useUncontrolledState({
13
21
  defaultValue: typeof defaultValue !== "undefined" ? defaultValue : isMultiple ? [] : "",
14
- onChange: onValueChange,
22
+ onChange: handleValueChange,
15
23
  value: valueProp
16
24
  });
17
25
  const registry = useRef([]);
@@ -1 +1 @@
1
- {"version":3,"file":"ToggleGroupBase.js","names":[],"sources":["../../src/components/ToggleGroup/ToggleGroupBase.tsx"],"sourcesContent":["import { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { clamp } from '@utils/sharedUtils'\nimport { createContext, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, type ButtonHTMLAttributes, type HTMLAttributes, type KeyboardEvent, type MouseEvent, type ReactNode, type Ref } from 'react'\n\ntype VoidFn = () => void\ntype Orientation = 'horizontal' | 'vertical'\n\nexport interface CommonGroupProps {\n className?: string\n defaultValue?: string | string[]\n disabled?: boolean\n loop?: boolean\n name?: string\n onValueChange?: (v: string | string[]) => void\n orientation?: Orientation\n value?: string | string[]\n}\n\nexport type SingleProps = CommonGroupProps & {\n type?: 'single'\n}\n\nexport type MultipleProps = CommonGroupProps & {\n type: 'multiple'\n}\n\nexport type ToggleGroupProps = (SingleProps | MultipleProps) & Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>\n\nexport interface ItemRenderProps {\n children?: ReactNode\n className?: string\n disabled?: boolean\n value: string\n}\n\nconst GroupContext = createContext<{\n focusItemByIndex: (index: number) => void\n groupDisabled: boolean\n loop: boolean\n isItemPressed: (val: string) => boolean\n itemsSnapshot: () => { val: string; el: HTMLButtonElement | null; disabled: boolean }[]\n name?: string\n orientation: Orientation\n register: (val: string, el: HTMLButtonElement | null) => VoidFn\n setValue: (next: string | string[]) => void\n type: 'single' | 'multiple'\n value: string | string[]\n} | null>(null)\n\nexport const ToggleGroupBase = (props: ToggleGroupProps & Record<`data-${string}`, unknown>) => {\n const {\n className,\n defaultValue,\n disabled: groupDisabled = false,\n loop = true,\n name,\n onValueChange,\n orientation = 'horizontal',\n type = 'single',\n value: valueProp,\n 'data-variant': dataVariant,\n 'data-size': dataSize,\n 'data-slot': dataSlot,\n 'data-layout': dataLayout,\n ...rest\n } = props\n\n const isMultiple = type === 'multiple'\n\n const [value, setValue] = useUncontrolledState<string | string[]>({\n defaultValue: typeof defaultValue !== 'undefined' ? defaultValue : isMultiple ? [] : '',\n onChange: onValueChange,\n value: valueProp,\n })\n\n const registry = useRef<{ val: string; el: HTMLButtonElement | null; disabled: boolean }[]>([])\n\n const register = useCallback((val: string, el: HTMLButtonElement | null) => {\n const entry = { val, el, disabled: !!el?.disabled }\n registry.current = [...registry.current.filter((i) => i.val !== val), entry]\n return () => {\n registry.current = registry.current.filter((i) => i.val !== val)\n }\n }, [])\n\n const itemsSnapshot = useCallback(() => registry.current.slice(), [])\n\n const isItemPressed = useCallback(\n (val: string) => {\n if (isMultiple) return Array.isArray(value) && value.includes(val)\n return value === val\n },\n [isMultiple, value],\n )\n\n const setValueSafe = useCallback((next: string | string[]) => setValue(next), [setValue])\n\n const focusItemByIndex = useCallback(\n (index: number) => {\n const items = registry.current\n if (items.length === 0) return\n const last = items.length - 1\n const clamped = loop ? ((index % items.length) + items.length) % items.length : clamp(index, 0, last)\n const target = items[clamped]\n target?.el?.focus()\n },\n [loop],\n )\n\n const ctx = useMemo(\n () => ({\n focusItemByIndex,\n groupDisabled,\n isItemPressed,\n itemsSnapshot,\n loop,\n name,\n orientation,\n register,\n setValue: setValueSafe,\n type,\n value,\n }),\n [focusItemByIndex, groupDisabled, isItemPressed, itemsSnapshot, loop, name, orientation, register, setValueSafe, type, value],\n )\n\n const hiddenName = name\n\n return (\n <div className={className} data-disabled={groupDisabled ? '' : undefined} data-layout={dataLayout} data-orientation={orientation} data-size={dataSize} data-slot={dataSlot} data-variant={dataVariant} role='group' {...rest}>\n <GroupContext.Provider value={ctx}>{props.children}</GroupContext.Provider>\n\n {hiddenName && type === 'single' && typeof value === 'string' ? <input type='hidden' name={hiddenName} value={value} /> : null}\n\n {hiddenName && type === 'multiple' && Array.isArray(value) ? value.map((v) => <input key={v} type='hidden' name={hiddenName + '[]'} value={v} />) : null}\n </div>\n )\n}\n\nexport type ToggleGroupItemProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'onPressedChange' | 'pressed' | 'defaultPressed'> &\n ItemRenderProps & {\n /** @deprecated This prop is ignored - pressed state is managed by ToggleGroup */\n pressed?: boolean\n /** @deprecated This prop is ignored - pressed state is managed by ToggleGroup */\n defaultPressed?: boolean\n }\n\nexport const ToggleGroupItemBase = function ToggleGroupItem({\n ref,\n value,\n disabled,\n className,\n children,\n onKeyDown,\n onClick,\n ...rest\n}: ToggleGroupItemProps & {\n ref?: Ref<HTMLButtonElement>\n}) {\n const ctx = useContext(GroupContext)\n if (!ctx) throw new Error('ToggleGroupItem must be used within ToggleGroup')\n\n const { type, orientation, groupDisabled, setValue, isItemPressed, itemsSnapshot, register } = ctx\n\n const btnRef = useRef<HTMLButtonElement | null>(null)\n useImperativeHandle(ref, () => {\n if (!btnRef.current) {\n throw new Error('ToggleGroupItem button ref is not set')\n }\n return btnRef.current\n })\n\n useEffect(() => register(value, btnRef.current), [register, value])\n\n const pressed = isItemPressed(value)\n\n const toggleMe = useCallback(() => {\n if (groupDisabled || disabled) return\n if (type === 'single') setValue(pressed ? '' : value)\n else {\n const current = ctx.value as string[]\n const next = pressed ? current.filter((v) => v !== value) : [...current, value]\n setValue(next)\n }\n }, [ctx.value, disabled, groupDisabled, pressed, setValue, type, value])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (onKeyDown) onKeyDown(e)\n if (e.defaultPrevented) return\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault()\n toggleMe()\n return\n }\n const items = itemsSnapshot()\n const index = items.findIndex((i) => i.val === value)\n const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'\n const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'\n if (e.key === prevKey) {\n e.preventDefault()\n ctx.focusItemByIndex(index - 1)\n } else if (e.key === nextKey) {\n e.preventDefault()\n ctx.focusItemByIndex(index + 1)\n } else if (e.key === 'Home') {\n e.preventDefault()\n ctx.focusItemByIndex(0)\n } else if (e.key === 'End') {\n e.preventDefault()\n ctx.focusItemByIndex(items.length - 1)\n }\n },\n [ctx, itemsSnapshot, onKeyDown, orientation, toggleMe, value],\n )\n\n const handleClick = useCallback(\n (e: MouseEvent<HTMLButtonElement>) => {\n if (onClick) onClick(e)\n if (e.defaultPrevented) return\n toggleMe()\n },\n [onClick, toggleMe],\n )\n\n return (\n <button aria-pressed={pressed} className={className} data-disabled={groupDisabled || disabled ? '' : undefined} data-state={pressed ? 'on' : 'off'} disabled={groupDisabled || disabled} onClick={handleClick} onKeyDown={handleKeyDown} ref={btnRef} type='button' {...rest}>\n {children}\n </button>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ToggleGroupBase.js","names":[],"sources":["../../src/components/ToggleGroup/ToggleGroupBase.tsx"],"sourcesContent":["import { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { clamp } from '@utils/sharedUtils'\nimport { createContext, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, type ButtonHTMLAttributes, type HTMLAttributes, type KeyboardEvent, type MouseEvent, type ReactNode, type Ref } from 'react'\n\ntype VoidFn = () => void\ntype Orientation = 'horizontal' | 'vertical'\n\nexport interface CommonGroupProps {\n className?: string\n disabled?: boolean\n loop?: boolean\n name?: string\n orientation?: Orientation\n}\n\nexport type SingleProps = CommonGroupProps & {\n defaultValue?: string\n onValueChange?: (v: string) => void\n type?: 'single'\n value?: string\n}\n\nexport type MultipleProps = CommonGroupProps & {\n defaultValue?: string[]\n onValueChange?: (v: string[]) => void\n type: 'multiple'\n value?: string[]\n}\n\nexport type ToggleGroupProps = (SingleProps | MultipleProps) & Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>\n\nexport interface ItemRenderProps {\n children?: ReactNode\n className?: string\n disabled?: boolean\n value: string\n}\n\nconst GroupContext = createContext<{\n focusItemByIndex: (index: number) => void\n groupDisabled: boolean\n loop: boolean\n isItemPressed: (val: string) => boolean\n itemsSnapshot: () => { val: string; el: HTMLButtonElement | null; disabled: boolean }[]\n name?: string\n orientation: Orientation\n register: (val: string, el: HTMLButtonElement | null) => VoidFn\n setValue: (next: string | string[]) => void\n type: 'single' | 'multiple'\n value: string | string[]\n} | null>(null)\n\nexport const ToggleGroupBase = (props: ToggleGroupProps & Record<`data-${string}`, unknown>) => {\n const {\n className,\n defaultValue,\n disabled: groupDisabled = false,\n loop = true,\n name,\n onValueChange,\n orientation = 'horizontal',\n type = 'single',\n value: valueProp,\n 'data-variant': dataVariant,\n 'data-size': dataSize,\n 'data-slot': dataSlot,\n 'data-layout': dataLayout,\n ...rest\n } = props\n\n const isMultiple = type === 'multiple'\n\n const handleValueChange = useCallback(\n (next: string | string[]) => {\n if (!onValueChange) return\n if (isMultiple) {\n const onValueChangeMultiple = onValueChange as (v: string[]) => void\n onValueChangeMultiple(next as string[])\n return\n }\n const onValueChangeSingle = onValueChange as (v: string) => void\n onValueChangeSingle(next as string)\n },\n [isMultiple, onValueChange],\n )\n\n const [value, setValue] = useUncontrolledState<string | string[]>({\n defaultValue: typeof defaultValue !== 'undefined' ? defaultValue : isMultiple ? [] : '',\n onChange: handleValueChange,\n value: valueProp,\n })\n\n const registry = useRef<{ val: string; el: HTMLButtonElement | null; disabled: boolean }[]>([])\n\n const register = useCallback((val: string, el: HTMLButtonElement | null) => {\n const entry = { val, el, disabled: !!el?.disabled }\n registry.current = [...registry.current.filter((i) => i.val !== val), entry]\n return () => {\n registry.current = registry.current.filter((i) => i.val !== val)\n }\n }, [])\n\n const itemsSnapshot = useCallback(() => registry.current.slice(), [])\n\n const isItemPressed = useCallback(\n (val: string) => {\n if (isMultiple) return Array.isArray(value) && value.includes(val)\n return value === val\n },\n [isMultiple, value],\n )\n\n const setValueSafe = useCallback((next: string | string[]) => setValue(next), [setValue])\n\n const focusItemByIndex = useCallback(\n (index: number) => {\n const items = registry.current\n if (items.length === 0) return\n const last = items.length - 1\n const clamped = loop ? ((index % items.length) + items.length) % items.length : clamp(index, 0, last)\n const target = items[clamped]\n target?.el?.focus()\n },\n [loop],\n )\n\n const ctx = useMemo(\n () => ({\n focusItemByIndex,\n groupDisabled,\n isItemPressed,\n itemsSnapshot,\n loop,\n name,\n orientation,\n register,\n setValue: setValueSafe,\n type,\n value,\n }),\n [focusItemByIndex, groupDisabled, isItemPressed, itemsSnapshot, loop, name, orientation, register, setValueSafe, type, value],\n )\n\n const hiddenName = name\n\n return (\n <div className={className} data-disabled={groupDisabled ? '' : undefined} data-layout={dataLayout} data-orientation={orientation} data-size={dataSize} data-slot={dataSlot} data-variant={dataVariant} role='group' {...rest}>\n <GroupContext.Provider value={ctx}>{props.children}</GroupContext.Provider>\n\n {hiddenName && type === 'single' && typeof value === 'string' ? <input type='hidden' name={hiddenName} value={value} /> : null}\n\n {hiddenName && type === 'multiple' && Array.isArray(value) ? value.map((v) => <input key={v} type='hidden' name={hiddenName + '[]'} value={v} />) : null}\n </div>\n )\n}\n\nexport type ToggleGroupItemProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'onPressedChange' | 'pressed' | 'defaultPressed'> &\n ItemRenderProps & {\n /** @deprecated This prop is ignored - pressed state is managed by ToggleGroup */\n pressed?: boolean\n /** @deprecated This prop is ignored - pressed state is managed by ToggleGroup */\n defaultPressed?: boolean\n }\n\nexport const ToggleGroupItemBase = function ToggleGroupItem({\n ref,\n value,\n disabled,\n className,\n children,\n onKeyDown,\n onClick,\n ...rest\n}: ToggleGroupItemProps & {\n ref?: Ref<HTMLButtonElement>\n}) {\n const ctx = useContext(GroupContext)\n if (!ctx) throw new Error('ToggleGroupItem must be used within ToggleGroup')\n\n const { type, orientation, groupDisabled, setValue, isItemPressed, itemsSnapshot, register } = ctx\n\n const btnRef = useRef<HTMLButtonElement | null>(null)\n useImperativeHandle(ref, () => {\n if (!btnRef.current) {\n throw new Error('ToggleGroupItem button ref is not set')\n }\n return btnRef.current\n })\n\n useEffect(() => register(value, btnRef.current), [register, value])\n\n const pressed = isItemPressed(value)\n\n const toggleMe = useCallback(() => {\n if (groupDisabled || disabled) return\n if (type === 'single') setValue(pressed ? '' : value)\n else {\n const current = ctx.value as string[]\n const next = pressed ? current.filter((v) => v !== value) : [...current, value]\n setValue(next)\n }\n }, [ctx.value, disabled, groupDisabled, pressed, setValue, type, value])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (onKeyDown) onKeyDown(e)\n if (e.defaultPrevented) return\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault()\n toggleMe()\n return\n }\n const items = itemsSnapshot()\n const index = items.findIndex((i) => i.val === value)\n const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'\n const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'\n if (e.key === prevKey) {\n e.preventDefault()\n ctx.focusItemByIndex(index - 1)\n } else if (e.key === nextKey) {\n e.preventDefault()\n ctx.focusItemByIndex(index + 1)\n } else if (e.key === 'Home') {\n e.preventDefault()\n ctx.focusItemByIndex(0)\n } else if (e.key === 'End') {\n e.preventDefault()\n ctx.focusItemByIndex(items.length - 1)\n }\n },\n [ctx, itemsSnapshot, onKeyDown, orientation, toggleMe, value],\n )\n\n const handleClick = useCallback(\n (e: MouseEvent<HTMLButtonElement>) => {\n if (onClick) onClick(e)\n if (e.defaultPrevented) return\n toggleMe()\n },\n [onClick, toggleMe],\n )\n\n return (\n <button aria-pressed={pressed} className={className} data-disabled={groupDisabled || disabled ? '' : undefined} data-state={pressed ? 'on' : 'off'} disabled={groupDisabled || disabled} onClick={handleClick} onKeyDown={handleKeyDown} ref={btnRef} type='button' {...rest}>\n {children}\n </button>\n )\n}\n"],"mappings":"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"}
@@ -20,7 +20,7 @@ const ToggleGroupItem = ({ activeColor, activeTextColor, children, className, la
20
20
  variant: resolvedVariant,
21
21
  size: resolvedSize,
22
22
  layout: resolvedLayout
23
- }), "group rounded-none shadow-none focus:z-10 focus-visible:z-10 data-[variant=outline]:border-toggle-border data-[variant=outline]:data-[state=on]:border-toggle-border--active", className),
23
+ }), "group rounded-none shadow-none focus:z-10 focus-visible:z-10 data-[variant=outline]:border-toggle-border data-[variant=outline]:hover:border-toggle-border data-[variant=outline]:data-[state=on]:border-selected-primary data-[variant=outline]:data-[state=on]:hover:border-selected-primary", className),
24
24
  "data-layout": resolvedLayout,
25
25
  "data-size": resolvedSize,
26
26
  "data-slot": "toggle-group-item",
@@ -1 +1 @@
1
- {"version":3,"file":"ToggleGroupItem.js","names":[],"sources":["../../src/components/ToggleGroup/ToggleGroupItem.tsx"],"sourcesContent":["import { getActiveColorStyle, toggleVariants, type ActiveColor } from '@components/Toggle/Toggle'\nimport { cn } from '@utils/twUtils'\nimport { type VariantProps } from 'class-variance-authority'\nimport { useContext, type ComponentProps, type Ref } from 'react'\nimport { ToggleGroupContext } from './ToggleGroup.context'\nimport { ToggleGroupItemBase } from './ToggleGroupBase'\n\nexport type ToggleGroupItemProps = ComponentProps<typeof ToggleGroupItemBase> &\n VariantProps<typeof toggleVariants> & {\n activeColor?: ActiveColor\n activeTextColor?: ActiveColor\n }\n\nexport const ToggleGroupItem = ({\n activeColor,\n activeTextColor,\n children,\n className,\n layout,\n ref,\n size,\n style,\n value,\n variant,\n ...props\n}: ToggleGroupItemProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const context = useContext(ToggleGroupContext)\n const resolvedVariant = variant ?? context.variant\n const resolvedSize = size ?? context.size\n const resolvedLayout = layout ?? context.layout\n const resolvedActiveColor = activeColor ?? context.activeColor\n const resolvedActiveTextColor = activeTextColor ?? context.activeTextColor\n\n return (\n <ToggleGroupItemBase\n className={cn(\n toggleVariants({\n variant: resolvedVariant,\n size: resolvedSize,\n layout: resolvedLayout,\n }),\n 'group rounded-none shadow-none focus:z-10 focus-visible:z-10 data-[variant=outline]:border-toggle-border data-[variant=outline]:data-[state=on]:border-toggle-border--active',\n className,\n )}\n data-layout={resolvedLayout}\n data-size={resolvedSize}\n data-slot='toggle-group-item'\n data-testid='spectral-toggle-group-item'\n data-variant={resolvedVariant}\n ref={ref}\n style={{ ...getActiveColorStyle(resolvedActiveColor, resolvedActiveTextColor), ...style }}\n value={value}\n {...props}\n >\n {children}\n </ToggleGroupItemBase>\n )\n}\n\nToggleGroupItem.displayName = 'ToggleGroupItem'\n"],"mappings":";;;;;;;;;;AAaA,MAAa,mBAAmB,EAC9B,aACA,iBACA,UACA,WACA,QACA,KACA,MACA,OACA,OACA,SACA,GAAG,YAGC;CACJ,MAAM,UAAU,WAAW,mBAAmB;CAC9C,MAAM,kBAAkB,WAAW,QAAQ;CAC3C,MAAM,eAAe,QAAQ,QAAQ;CACrC,MAAM,iBAAiB,UAAU,QAAQ;CACzC,MAAM,sBAAsB,eAAe,QAAQ;CACnD,MAAM,0BAA0B,mBAAmB,QAAQ;AAE3D,QACE,oBAAC,qBAAD;EACE,WAAW,GACT,eAAe;GACb,SAAS;GACT,MAAM;GACN,QAAQ;GACT,CAAC,EACF,gLACA,UACD;EACD,eAAa;EACb,aAAW;EACX,aAAU;EACV,eAAY;EACZ,gBAAc;EACT;EACL,OAAO;GAAE,GAAG,oBAAoB,qBAAqB,wBAAwB;GAAE,GAAG;GAAO;EAClF;EACP,GAAI;EAEH;EACmB;;AAI1B,gBAAgB,cAAc"}
1
+ {"version":3,"file":"ToggleGroupItem.js","names":[],"sources":["../../src/components/ToggleGroup/ToggleGroupItem.tsx"],"sourcesContent":["import { getActiveColorStyle, toggleVariants, type ActiveColor } from '@components/Toggle/Toggle'\nimport { cn } from '@utils/twUtils'\nimport { type VariantProps } from 'class-variance-authority'\nimport { useContext, type ComponentProps, type Ref } from 'react'\nimport { ToggleGroupContext } from './ToggleGroup.context'\nimport { ToggleGroupItemBase } from './ToggleGroupBase'\n\nexport type ToggleGroupItemProps = ComponentProps<typeof ToggleGroupItemBase> &\n VariantProps<typeof toggleVariants> & {\n activeColor?: ActiveColor\n activeTextColor?: ActiveColor\n }\n\nexport const ToggleGroupItem = ({\n activeColor,\n activeTextColor,\n children,\n className,\n layout,\n ref,\n size,\n style,\n value,\n variant,\n ...props\n}: ToggleGroupItemProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const context = useContext(ToggleGroupContext)\n const resolvedVariant = variant ?? context.variant\n const resolvedSize = size ?? context.size\n const resolvedLayout = layout ?? context.layout\n const resolvedActiveColor = activeColor ?? context.activeColor\n const resolvedActiveTextColor = activeTextColor ?? context.activeTextColor\n\n return (\n <ToggleGroupItemBase\n className={cn(\n toggleVariants({\n variant: resolvedVariant,\n size: resolvedSize,\n layout: resolvedLayout,\n }),\n 'group rounded-none shadow-none focus:z-10 focus-visible:z-10 data-[variant=outline]:border-toggle-border data-[variant=outline]:hover:border-toggle-border data-[variant=outline]:data-[state=on]:border-selected-primary data-[variant=outline]:data-[state=on]:hover:border-selected-primary',\n className,\n )}\n data-layout={resolvedLayout}\n data-size={resolvedSize}\n data-slot='toggle-group-item'\n data-testid='spectral-toggle-group-item'\n data-variant={resolvedVariant}\n ref={ref}\n style={{ ...getActiveColorStyle(resolvedActiveColor, resolvedActiveTextColor), ...style }}\n value={value}\n {...props}\n >\n {children}\n </ToggleGroupItemBase>\n )\n}\n\nToggleGroupItem.displayName = 'ToggleGroupItem'\n"],"mappings":";;;;;;;;;;AAaA,MAAa,mBAAmB,EAC9B,aACA,iBACA,UACA,WACA,QACA,KACA,MACA,OACA,OACA,SACA,GAAG,YAGC;CACJ,MAAM,UAAU,WAAW,mBAAmB;CAC9C,MAAM,kBAAkB,WAAW,QAAQ;CAC3C,MAAM,eAAe,QAAQ,QAAQ;CACrC,MAAM,iBAAiB,UAAU,QAAQ;CACzC,MAAM,sBAAsB,eAAe,QAAQ;CACnD,MAAM,0BAA0B,mBAAmB,QAAQ;AAE3D,QACE,oBAAC,qBAAD;EACE,WAAW,GACT,eAAe;GACb,SAAS;GACT,MAAM;GACN,QAAQ;GACT,CAAC,EACF,kSACA,UACD;EACD,eAAa;EACb,aAAW;EACX,aAAU;EACV,eAAY;EACZ,gBAAc;EACT;EACL,OAAO;GAAE,GAAG,oBAAoB,qBAAqB,wBAAwB;GAAE,GAAG;GAAO;EAClF;EACP,GAAI;EAEH;EACmB;;AAI1B,gBAAgB,cAAc"}
@@ -11,7 +11,7 @@ import "class-variance-authority";
11
11
  //#region src/components/ToggleGroup/ToggleGroup.tsx
12
12
  const ToggleGroup = ({ className, variant, size, layout, activeColor, activeTextColor, orientation, children, ...props }) => {
13
13
  return /* @__PURE__ */ jsx(ToggleGroupBase, {
14
- className: cn(`group/toggle-group rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md data-[variant='outline']:gap-0 flex h-fit w-fit items-center data-[layout='expanded']:w-full data-[variant='outline']:[--color-toggle-border:var(--color-toggle-outline-border)] data-[variant='outline']:[&_button:not(:first-of-type)]:border-l-0`, className),
14
+ className: cn(`group/toggle-group rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md data-[variant='outline']:gap-0 flex h-fit w-fit items-center data-[layout='expanded']:w-full data-[variant='outline']:[--color-toggle-border:var(--color-toggle-outline-border)] data-[variant='outline']:[&_button:not(:first-of-type)]:border-l-0 data-[variant='outline']:[&_button:not(:last-of-type)]:[border-right-color:var(--color-toggle-outline-divider)] data-[variant='outline']:[&_button[data-state='on']:not(:last-of-type)]:[border-right-color:var(--color-toggle-border--active)]`, className),
15
15
  "data-layout": layout,
16
16
  "data-size": size,
17
17
  "data-slot": "toggle-group",
@@ -1 +1 @@
1
- {"version":3,"file":"ToggleGroup.js","names":[],"sources":["../src/components/ToggleGroup/ToggleGroup.tsx"],"sourcesContent":["import { type ActiveColor, type toggleVariants } from '@components/Toggle/Toggle'\nimport { cn } from '@utils/twUtils'\nimport { type VariantProps } from 'class-variance-authority'\nimport { type ComponentProps } from 'react'\nimport { ToggleGroupContext } from './ToggleGroup.context'\nimport { ToggleGroupBase } from './ToggleGroupBase'\nexport { ToggleGroupItem, type ToggleGroupItemProps } from './ToggleGroupItem'\nexport { ToggleGroupSplitMenuItem, type ToggleGroupSplitMenuItemProps } from './ToggleGroupSplitMenuItem'\n\nexport type ToggleGroupProps = ComponentProps<typeof ToggleGroupBase> &\n VariantProps<typeof toggleVariants> & {\n activeColor?: ActiveColor\n activeTextColor?: ActiveColor\n }\n\nexport const ToggleGroup = ({ className, variant, size, layout, activeColor, activeTextColor, orientation, children, ...props }: ToggleGroupProps) => {\n return (\n <ToggleGroupBase\n className={cn(\n `group/toggle-group rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md data-[variant='outline']:gap-0 flex h-fit w-fit items-center data-[layout='expanded']:w-full data-[variant='outline']:[--color-toggle-border:var(--color-toggle-outline-border)] data-[variant='outline']:[&_button:not(:first-of-type)]:border-l-0`,\n className,\n )}\n data-layout={layout}\n data-size={size}\n data-slot='toggle-group'\n data-testid='spectral-toggle-group'\n data-variant={variant}\n orientation={orientation}\n {...props}\n >\n <ToggleGroupContext.Provider value={{ variant, size, layout, activeColor, activeTextColor, orientation }}>{children}</ToggleGroupContext.Provider>\n </ToggleGroupBase>\n )\n}\n"],"mappings":";;;;;;;;;;;AAeA,MAAa,eAAe,EAAE,WAAW,SAAS,MAAM,QAAQ,aAAa,iBAAiB,aAAa,UAAU,GAAG,YAA8B;AACpJ,QACE,oBAAC,iBAAD;EACE,WAAW,GACT,gWACA,UACD;EACD,eAAa;EACb,aAAW;EACX,aAAU;EACV,eAAY;EACZ,gBAAc;EACD;EACb,GAAI;YAEJ,oBAAC,mBAAmB,UAApB;GAA6B,OAAO;IAAE;IAAS;IAAM;IAAQ;IAAa;IAAiB;IAAa;GAAG;GAAuC;EAClI"}
1
+ {"version":3,"file":"ToggleGroup.js","names":[],"sources":["../src/components/ToggleGroup/ToggleGroup.tsx"],"sourcesContent":["import { type ActiveColor, type toggleVariants } from '@components/Toggle/Toggle'\nimport { cn } from '@utils/twUtils'\nimport { type VariantProps } from 'class-variance-authority'\nimport { type ComponentProps } from 'react'\nimport { ToggleGroupContext } from './ToggleGroup.context'\nimport { ToggleGroupBase } from './ToggleGroupBase'\nexport { ToggleGroupItem, type ToggleGroupItemProps } from './ToggleGroupItem'\nexport { ToggleGroupSplitMenuItem, type ToggleGroupSplitMenuItemProps } from './ToggleGroupSplitMenuItem'\n\nexport type ToggleGroupProps = ComponentProps<typeof ToggleGroupBase> &\n VariantProps<typeof toggleVariants> & {\n activeColor?: ActiveColor\n activeTextColor?: ActiveColor\n }\n\nexport const ToggleGroup = ({ className, variant, size, layout, activeColor, activeTextColor, orientation, children, ...props }: ToggleGroupProps) => {\n return (\n <ToggleGroupBase\n className={cn(\n `group/toggle-group rounded-md [&_button:first-of-type]:rounded-l-md [&_button:last-of-type]:rounded-r-md data-[variant='outline']:gap-0 flex h-fit w-fit items-center data-[layout='expanded']:w-full data-[variant='outline']:[--color-toggle-border:var(--color-toggle-outline-border)] data-[variant='outline']:[&_button:not(:first-of-type)]:border-l-0 data-[variant='outline']:[&_button:not(:last-of-type)]:[border-right-color:var(--color-toggle-outline-divider)] data-[variant='outline']:[&_button[data-state='on']:not(:last-of-type)]:[border-right-color:var(--color-toggle-border--active)]`,\n className,\n )}\n data-layout={layout}\n data-size={size}\n data-slot='toggle-group'\n data-testid='spectral-toggle-group'\n data-variant={variant}\n orientation={orientation}\n {...props}\n >\n <ToggleGroupContext.Provider value={{ variant, size, layout, activeColor, activeTextColor, orientation }}>{children}</ToggleGroupContext.Provider>\n </ToggleGroupBase>\n )\n}\n"],"mappings":";;;;;;;;;;;AAeA,MAAa,eAAe,EAAE,WAAW,SAAS,MAAM,QAAQ,aAAa,iBAAiB,aAAa,UAAU,GAAG,YAA8B;AACpJ,QACE,oBAAC,iBAAD;EACE,WAAW,GACT,glBACA,UACD;EACD,eAAa;EACb,aAAW;EACX,aAAU;EACV,eAAY;EACZ,gBAAc;EACD;EACb,GAAI;YAEJ,oBAAC,mBAAmB,UAApB;GAA6B,OAAO;IAAE;IAAS;IAAM;IAAQ;IAAa;IAAiB;IAAa;GAAG;GAAuC;EAClI"}
@@ -213,6 +213,7 @@
213
213
  --color-toggle-text--hover: var(--horizon-color-neutral-200);
214
214
  --color-toggle-text--active: var(--horizon-color-neutral-50);
215
215
  --color-toggle-outline-border: var(--horizon-color-neutral-700);
216
+ --color-toggle-outline-divider: var(--horizon-color-neutral-600);
216
217
  --color-toggle-outline-border--hover: var(--horizon-color-neutral-400);
217
218
  --color-toggle-group-bg: var(--horizon-color-level-five);
218
219