@spear-ai/spectral 1.15.1 → 1.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Accordion.js +3 -3
- package/dist/Accordion.js.map +1 -1
- package/dist/Alert/AlertBase.js +1 -1
- package/dist/Alert/AlertBase.js.map +1 -1
- package/dist/Alert.js +3 -3
- package/dist/Alert.js.map +1 -1
- package/dist/Avatar.d.ts.map +1 -1
- package/dist/Avatar.js +17 -10
- package/dist/Avatar.js.map +1 -1
- package/dist/ButtonGroup/ButtonGroupButton.js +1 -1
- package/dist/ButtonGroup/ButtonGroupButton.js.map +1 -1
- package/dist/ControlGroup.js +1 -1
- package/dist/ControlGroup.js.map +1 -1
- package/dist/DateTimePicker/Calendar.js +1 -1
- package/dist/DateTimePicker/Calendar.js.map +1 -1
- package/dist/Dialog.d.ts +1 -0
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Dialog.js +7 -6
- package/dist/Dialog.js.map +1 -1
- package/dist/Drawer.d.ts.map +1 -1
- package/dist/Drawer.js +27 -23
- package/dist/Drawer.js.map +1 -1
- package/dist/Input.js +1 -1
- package/dist/Input.js.map +1 -1
- package/dist/MultiSelect/MultiSelectBase.js +3 -2
- package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
- package/dist/RadioGroup.js +1 -1
- package/dist/RadioGroup.js.map +1 -1
- package/dist/Switch.js +4 -4
- package/dist/Switch.js.map +1 -1
- package/dist/Tabs/TabsBase.d.ts.map +1 -1
- package/dist/Tabs/TabsBase.js +10 -56
- package/dist/Tabs/TabsBase.js.map +1 -1
- package/dist/Tabs.js +1 -1
- package/dist/Tabs.js.map +1 -1
- package/dist/ToggleGroup/ToggleGroupItem.js +1 -1
- package/dist/ToggleGroup/ToggleGroupItem.js.map +1 -1
- package/dist/Tooltip.js +1 -1
- package/dist/Tooltip.js.map +1 -1
- package/dist/Tray.d.ts.map +1 -1
- package/dist/Tray.js +11 -49
- package/dist/Tray.js.map +1 -1
- package/dist/styles/horizon/base.css +18 -7
- package/dist/styles/horizon/colors.css +3 -1
- package/dist/styles/spectral.css +1 -1
- package/package.json +1 -1
package/dist/Drawer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer.js","names":["DrawerBase"],"sources":["../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import { SpectralProvider } from '@components/SpectralProvider/SpectralProvider'\nimport { type ReactNode } from 'react'\nimport { Drawer as DrawerBase } from 'vaul'\n\nexport interface DrawerProps {\n children?: ReactNode\n defaultOpen?: boolean\n description?: string\n direction?: 'left' | 'right' | 'top' | 'bottom'\n dismissible?: boolean\n modal?: boolean\n onOpenChange?: (open: boolean) => void\n open?: boolean\n size?: string\n title?: string\n trigger: ReactNode\n}\n\nexport const Drawer = ({ children, defaultOpen = false, description, direction = 'right', dismissible = true, modal = true, onOpenChange, open, size = '380px', title, trigger }: DrawerProps) => {\n const baseStyles = 'font-sans! fixed'\n const hasTitle = typeof title === 'string' && title.trim().length > 0\n const hasDescription = typeof description === 'string' && description.trim().length > 0\n\n const directionStyles = {\n left: {\n className:
|
|
1
|
+
{"version":3,"file":"Drawer.js","names":["DrawerBase"],"sources":["../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import { SpectralProvider } from '@components/SpectralProvider/SpectralProvider'\nimport { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\nimport { Drawer as DrawerBase } from 'vaul'\n\nexport interface DrawerProps {\n children?: ReactNode\n defaultOpen?: boolean\n description?: string\n direction?: 'left' | 'right' | 'top' | 'bottom'\n dismissible?: boolean\n modal?: boolean\n onOpenChange?: (open: boolean) => void\n open?: boolean\n size?: string\n title?: string\n trigger: ReactNode\n}\n\nexport const Drawer = ({ children, defaultOpen = false, description, direction = 'right', dismissible = true, modal = true, onOpenChange, open, size = '380px', title, trigger }: DrawerProps) => {\n const baseStyles = 'font-sans! fixed'\n const hasTitle = typeof title === 'string' && title.trim().length > 0\n const hasDescription = typeof description === 'string' && description.trim().length > 0\n\n const directionStyles = {\n left: {\n className: cn(baseStyles, 'top-0 bottom-0 left-0 shadow-[20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n right: {\n className: cn(baseStyles, 'top-0 bottom-0 right-0 shadow-[-20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n top: {\n className: cn(baseStyles, 'top-0 left-0 right-0 shadow-[0_20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n bottom: {\n className: cn(baseStyles, 'bottom-0 left-0 right-0 shadow-[0_-20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n }\n\n const { className, style } = directionStyles[direction]\n\n return (\n <SpectralProvider>\n <DrawerBase.Root\n data-testid='spectral-drawer'\n defaultOpen={defaultOpen}\n direction={direction}\n dismissible={dismissible}\n modal={modal}\n onOpenChange={onOpenChange}\n open={open}\n >\n <DrawerBase.Trigger\n asChild\n data-testid='spectral-drawer-trigger'\n >\n {trigger}\n </DrawerBase.Trigger>\n <DrawerBase.Portal>\n <DrawerBase.Overlay\n className='inset-0 fixed bg-transparent'\n data-testid='spectral-drawer-overlay'\n />\n <DrawerBase.Content\n asChild\n aria-label={!hasTitle && !hasDescription ? 'Drawer' : undefined}\n className={`z-10 flex flex-col overscroll-contain bg-drawer-bg **:box-border focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent ${className}`}\n style={style}\n data-testid='spectral-drawer-content'\n >\n <div className='min-h-0 flex h-full flex-col'>\n <DrawerBase.Close />\n {hasTitle && (\n <DrawerBase.Title\n className='px-3 pt-4 text-lg font-medium text-text-primary'\n data-testid='spectral-drawer-title'\n >\n {title}\n </DrawerBase.Title>\n )}\n {hasDescription && (\n <DrawerBase.Description\n className='mb-2 px-3 text-xs! text-text-secondary! uppercase'\n data-testid='spectral-drawer-description'\n >\n {description}\n </DrawerBase.Description>\n )}\n <div\n className='py-2 px-3 min-w-0 [&>*]:min-w-0 [&_*]:min-w-0 min-h-0 flex-1 overflow-x-hidden overflow-y-auto overscroll-contain *:box-border'\n data-testid='spectral-drawer-body'\n >\n {children}\n </div>\n </div>\n </DrawerBase.Content>\n </DrawerBase.Portal>\n </DrawerBase.Root>\n </SpectralProvider>\n )\n}\n"],"mappings":";;;;;;;;AAmBA,MAAa,UAAU,EAAE,UAAU,cAAc,OAAO,aAAa,YAAY,SAAS,cAAc,MAAM,QAAQ,MAAM,cAAc,MAAM,OAAO,SAAS,OAAO,cAA2B;CAChM,MAAM,aAAa;CACnB,MAAM,WAAW,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS;CACpE,MAAM,iBAAiB,OAAO,gBAAgB,YAAY,YAAY,MAAM,CAAC,SAAS;CAqBtF,MAAM,EAAE,WAAW,UAAU;EAlB3B,MAAM;GACJ,WAAW,GAAG,YAAY,mEAAmE;GAC7F,OAAO,EAAE,OAAO,MAAM;GACvB;EACD,OAAO;GACL,WAAW,GAAG,YAAY,qEAAqE;GAC/F,OAAO,EAAE,OAAO,MAAM;GACvB;EACD,KAAK;GACH,WAAW,GAAG,YAAY,kEAAkE;GAC5F,OAAO,EAAE,QAAQ,MAAM;GACxB;EACD,QAAQ;GACN,WAAW,GAAG,YAAY,sEAAsE;GAChG,OAAO,EAAE,QAAQ,MAAM;GACxB;EAGyC,CAAC;AAE7C,QACE,oBAAC,kBAAD,YACE,qBAACA,SAAW,MAAZ;EACE,eAAY;EACC;EACF;EACE;EACN;EACO;EACR;YAPR,CASE,oBAACA,SAAW,SAAZ;GACE;GACA,eAAY;aAEX;GACkB,GACrB,qBAACA,SAAW,QAAZ,aACE,oBAACA,SAAW,SAAZ;GACE,WAAU;GACV,eAAY;GACZ,GACF,oBAACA,SAAW,SAAZ;GACE;GACA,cAAY,CAAC,YAAY,CAAC,iBAAiB,WAAW;GACtD,WAAW,8KAA8K;GAClL;GACP,eAAY;aAEZ,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAACA,SAAW,OAAZ,EAAoB;KACnB,YACC,oBAACA,SAAW,OAAZ;MACE,WAAU;MACV,eAAY;gBAEX;MACgB;KAEpB,kBACC,oBAACA,SAAW,aAAZ;MACE,WAAU;MACV,eAAY;gBAEX;MACsB;KAE3B,oBAAC,OAAD;MACE,WAAU;MACV,eAAY;MAEX;MACG;KACF;;GACa,EACH,IACJ;KACD"}
|
package/dist/Input.js
CHANGED
|
@@ -135,7 +135,7 @@ const Input = (allProps) => {
|
|
|
135
135
|
const inputClasses = cn(getInputClasses(state, className), "[text-indent:var(--prefix-width)]", showClearButtonNow && "pr-10", usesTabularNumbers && "tabular-nums");
|
|
136
136
|
const prefixClasses = cn("inset-y-0 left-4 text-base pointer-events-none absolute flex items-center text-input-text-prefix opacity-100 peer-disabled:opacity-50");
|
|
137
137
|
return /* @__PURE__ */ jsxs("div", {
|
|
138
|
-
className: "
|
|
138
|
+
className: "gap-1.5 flex w-full flex-col",
|
|
139
139
|
"data-testid": "spectral-input-container",
|
|
140
140
|
children: [label && /* @__PURE__ */ jsx(Label, {
|
|
141
141
|
className: cn("mb-2 block", labelClassName, isDisabled && "cursor-not-allowed text-input-text--disabled placeholder:text-input-text-placeholder"),
|
package/dist/Input.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.js","names":[],"sources":["../src/components/Input/Input.tsx"],"sourcesContent":["import { CheckCircleIcon, CloseCircleIcon, ErrorIcon, EyeClosedIcon, EyeOpenIcon, LoaderIcon, WarningIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, WarningMessage, getAriaProps, getFormFieldCSSProperties, getInputClasses, useFormFieldId, useFormFieldState, type BaseFormFieldProps } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useRef, type ChangeEvent, type CSSProperties, type FocusEvent, type InputHTMLAttributes, type ReactElement, type Ref } from 'react'\nimport { useClearOnFocus, usePasswordVisibility, usePrefixWidth } from './InputUtils'\n\nexport type InputType = 'text' | 'email' | 'url' | 'tel' | 'password' | 'number' | 'date' | 'datetime-local'\n\nexport type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'id' | 'onChange'> &\n BaseFormFieldProps & {\n className?: string\n clearOnFocus?: boolean\n endIcon?: ReactElement\n labelClassName?: string\n onBlur?: (e: FocusEvent<HTMLInputElement>) => void\n onChange?: (value: string) => void\n onFocus?: (e: FocusEvent<HTMLInputElement>) => void\n placeholder?: string\n prefix?: string\n showClearButton?: boolean\n showStateIcon?: boolean\n startIcon?: ReactElement\n suppressHydrationWarning?: boolean\n type?: InputType\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n }\n\nconst mergeRefs = <T,>(...refs: (Ref<T> | undefined)[]): Ref<T> => {\n return (value: T | null) => {\n refs.forEach((ref) => {\n if (!ref) return\n if (typeof ref === 'function') {\n ref(value)\n } else {\n ;(ref as { current: T | null }).current = value\n }\n })\n }\n}\n\nconst getAutoCompleteValue = (type: InputType): string => {\n const autoCompleteMap: Record<InputType, string> = {\n date: 'off',\n email: 'email',\n number: 'off',\n password: 'current-password',\n tel: 'tel',\n text: 'off',\n url: 'url',\n 'datetime-local': 'off',\n }\n return autoCompleteMap[type] || 'off'\n}\n\nexport const Input = (\n allProps: InputProps & {\n ref?: Ref<HTMLInputElement>\n },\n): ReactElement => {\n const {\n className,\n clearOnFocus = false,\n defaultValue,\n disabled,\n endIcon,\n errorMessage,\n id,\n label,\n labelClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onBlur,\n onChange,\n onFocus,\n placeholder,\n prefix,\n ref,\n required,\n showClearButton = false,\n showStateIcon = true,\n startIcon,\n state = 'default',\n suppressHydrationWarning = true,\n type = 'text',\n value: valueProp,\n warningMessage,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const inputId = useFormFieldId(id, name)\n const errorMessageId = `${inputId}-error`\n const warningMessageId = `${inputId}-warning`\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\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 internalRef = useRef<HTMLInputElement>(null)\n const inputRef = mergeRefs(ref, internalRef)\n\n const { isVisible, toggleVisibility, inputType } = usePasswordVisibility()\n const { prefixWidth, prefixRef } = usePrefixWidth(prefix)\n const { handleFocus: clearOnFocusHandler } = useClearOnFocus(clearOnFocus, (e: ChangeEvent<HTMLInputElement>) => setValue(e.target.value))\n\n const handleBlur = useCallback(\n (e: FocusEvent<HTMLInputElement>): void => {\n onBlur?.(e)\n },\n [onBlur],\n )\n\n const handleFocus = useCallback(\n (e: FocusEvent<HTMLInputElement>): void => {\n clearOnFocusHandler(e, onFocus)\n },\n [clearOnFocusHandler, onFocus],\n )\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>): void => {\n const newValue = e.target.value\n setValue(newValue)\n },\n [setValue],\n )\n\n const handleClear = useCallback((): void => {\n const element = internalRef.current\n if (element) {\n setValue('')\n element.focus()\n }\n }, [setValue])\n\n const showClearButtonNow = showClearButton && value.length > 0\n\n const getEndIcon = (): ReactElement | null => {\n const iconClasses = 'absolute right-4 top-1/2 -translate-y-1/2 text-input-icon hover:text-input-icon--hover focus:outline-none cursor-pointer'\n\n const iconComponents = {\n password: () => (\n <button\n aria-controls={inputId}\n aria-label={isVisible ? `Hide ${label ?? 'password'}` : `Show ${label ?? 'password'}`}\n aria-pressed={isVisible}\n className={iconClasses}\n data-testid='spectral-input-password-toggle'\n onClick={toggleVisibility}\n type='button'\n >\n {isVisible ? <EyeClosedIcon size={22} /> : <EyeOpenIcon size={22} />}\n </button>\n ),\n clear: () => (\n <button\n aria-label={String(`Clear ${label ?? 'input'}`)}\n className={iconClasses}\n data-testid='spectral-input-clear-button'\n onClick={handleClear}\n type='button'\n >\n <CloseCircleIcon size={24} />\n </button>\n ),\n loading: () => (\n <div\n className='right-4 text-input-icon absolute top-1/2 -translate-y-1/2'\n data-testid='spectral-input-loading-icon'\n >\n <LoaderIcon size={24} />\n </div>\n ),\n error: () => (\n <div\n className='right-4 absolute top-1/2 -translate-y-1/2 text-danger-400'\n data-testid='spectral-input-error-icon'\n >\n <ErrorIcon size={24} />\n </div>\n ),\n success: () => (\n <div\n className='right-4 absolute top-1/2 -translate-y-1/2 text-success-400'\n data-testid='spectral-input-success-icon'\n >\n <CheckCircleIcon size={24} />\n </div>\n ),\n warning: () => (\n <div\n className='right-4 absolute top-1/2 -translate-y-1/2 text-warning-400'\n data-testid='spectral-input-warning-icon'\n >\n <WarningIcon size={24} />\n </div>\n ),\n }\n\n if (endIcon) return <div className='right-4 text-input-icon absolute top-1/2 -translate-y-1/2'>{endIcon}</div>\n if (type === 'password') return iconComponents.password()\n if (showClearButtonNow) return iconComponents.clear()\n if (isLoading) return iconComponents.loading()\n if (!showStateIcon && (state === 'success' || state === 'warning' || state === 'error')) return null\n if (state === 'success') return iconComponents.success()\n if (state === 'warning') return iconComponents.warning()\n if (state === 'error') return iconComponents.error()\n\n return null\n }\n\n const getStartIcon = (): ReactElement | null => {\n if (startIcon) return startIcon\n return null\n }\n\n const usesTabularNumbers = type === 'number' || type === 'date' || type === 'datetime-local'\n const inputClasses = cn(getInputClasses(state, className), '[text-indent:var(--prefix-width)]', showClearButtonNow && 'pr-10', usesTabularNumbers && 'tabular-nums')\n\n const prefixClasses = cn('inset-y-0 left-4 text-base pointer-events-none absolute flex items-center text-input-text-prefix opacity-100 peer-disabled:opacity-50')\n\n return (\n <div\n className='space-y-1.5 w-full'\n data-testid='spectral-input-container'\n >\n {label && (\n <Label\n className={cn('mb-2 block', labelClassName, isDisabled && 'cursor-not-allowed text-input-text--disabled placeholder:text-input-text-placeholder')}\n data-testid='spectral-input-label'\n htmlFor={inputId}\n >\n {label}\n </Label>\n )}\n <div\n className='relative'\n data-testid='spectral-input-wrapper'\n >\n <div className='relative'>\n {getStartIcon()}\n {prefix && (\n <span\n ref={prefixRef}\n className={prefixClasses}\n >\n {prefix}\n </span>\n )}\n <input\n aria-label={ariaLabel ?? label}\n autoComplete={getAutoCompleteValue(type)}\n className={inputClasses}\n data-state={state}\n data-testid='spectral-input'\n disabled={isDisabled}\n id={inputId}\n name={name}\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n placeholder={placeholder ?? label}\n ref={inputRef}\n required={required}\n style={\n getFormFieldCSSProperties({\n '--prefix-width': prefix ? `${prefixWidth}px` : '0',\n }) as CSSProperties\n }\n suppressHydrationWarning={suppressHydrationWarning}\n type={type === 'password' ? inputType : type}\n value={value}\n {...ariaProps}\n {...props}\n />\n {getEndIcon()}\n </div>\n\n <ErrorMessage\n dataTestId='spectral-input-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-input-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </div>\n )\n}\nInput.displayName = 'Input'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Input.js","names":[],"sources":["../src/components/Input/Input.tsx"],"sourcesContent":["import { CheckCircleIcon, CloseCircleIcon, ErrorIcon, EyeClosedIcon, EyeOpenIcon, LoaderIcon, WarningIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, WarningMessage, getAriaProps, getFormFieldCSSProperties, getInputClasses, useFormFieldId, useFormFieldState, type BaseFormFieldProps } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useRef, type ChangeEvent, type CSSProperties, type FocusEvent, type InputHTMLAttributes, type ReactElement, type Ref } from 'react'\nimport { useClearOnFocus, usePasswordVisibility, usePrefixWidth } from './InputUtils'\n\nexport type InputType = 'text' | 'email' | 'url' | 'tel' | 'password' | 'number' | 'date' | 'datetime-local'\n\nexport type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'id' | 'onChange'> &\n BaseFormFieldProps & {\n className?: string\n clearOnFocus?: boolean\n endIcon?: ReactElement\n labelClassName?: string\n onBlur?: (e: FocusEvent<HTMLInputElement>) => void\n onChange?: (value: string) => void\n onFocus?: (e: FocusEvent<HTMLInputElement>) => void\n placeholder?: string\n prefix?: string\n showClearButton?: boolean\n showStateIcon?: boolean\n startIcon?: ReactElement\n suppressHydrationWarning?: boolean\n type?: InputType\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n }\n\nconst mergeRefs = <T,>(...refs: (Ref<T> | undefined)[]): Ref<T> => {\n return (value: T | null) => {\n refs.forEach((ref) => {\n if (!ref) return\n if (typeof ref === 'function') {\n ref(value)\n } else {\n ;(ref as { current: T | null }).current = value\n }\n })\n }\n}\n\nconst getAutoCompleteValue = (type: InputType): string => {\n const autoCompleteMap: Record<InputType, string> = {\n date: 'off',\n email: 'email',\n number: 'off',\n password: 'current-password',\n tel: 'tel',\n text: 'off',\n url: 'url',\n 'datetime-local': 'off',\n }\n return autoCompleteMap[type] || 'off'\n}\n\nexport const Input = (\n allProps: InputProps & {\n ref?: Ref<HTMLInputElement>\n },\n): ReactElement => {\n const {\n className,\n clearOnFocus = false,\n defaultValue,\n disabled,\n endIcon,\n errorMessage,\n id,\n label,\n labelClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onBlur,\n onChange,\n onFocus,\n placeholder,\n prefix,\n ref,\n required,\n showClearButton = false,\n showStateIcon = true,\n startIcon,\n state = 'default',\n suppressHydrationWarning = true,\n type = 'text',\n value: valueProp,\n warningMessage,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const inputId = useFormFieldId(id, name)\n const errorMessageId = `${inputId}-error`\n const warningMessageId = `${inputId}-warning`\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\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 internalRef = useRef<HTMLInputElement>(null)\n const inputRef = mergeRefs(ref, internalRef)\n\n const { isVisible, toggleVisibility, inputType } = usePasswordVisibility()\n const { prefixWidth, prefixRef } = usePrefixWidth(prefix)\n const { handleFocus: clearOnFocusHandler } = useClearOnFocus(clearOnFocus, (e: ChangeEvent<HTMLInputElement>) => setValue(e.target.value))\n\n const handleBlur = useCallback(\n (e: FocusEvent<HTMLInputElement>): void => {\n onBlur?.(e)\n },\n [onBlur],\n )\n\n const handleFocus = useCallback(\n (e: FocusEvent<HTMLInputElement>): void => {\n clearOnFocusHandler(e, onFocus)\n },\n [clearOnFocusHandler, onFocus],\n )\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>): void => {\n const newValue = e.target.value\n setValue(newValue)\n },\n [setValue],\n )\n\n const handleClear = useCallback((): void => {\n const element = internalRef.current\n if (element) {\n setValue('')\n element.focus()\n }\n }, [setValue])\n\n const showClearButtonNow = showClearButton && value.length > 0\n\n const getEndIcon = (): ReactElement | null => {\n const iconClasses = 'absolute right-4 top-1/2 -translate-y-1/2 text-input-icon hover:text-input-icon--hover focus:outline-none cursor-pointer'\n\n const iconComponents = {\n password: () => (\n <button\n aria-controls={inputId}\n aria-label={isVisible ? `Hide ${label ?? 'password'}` : `Show ${label ?? 'password'}`}\n aria-pressed={isVisible}\n className={iconClasses}\n data-testid='spectral-input-password-toggle'\n onClick={toggleVisibility}\n type='button'\n >\n {isVisible ? <EyeClosedIcon size={22} /> : <EyeOpenIcon size={22} />}\n </button>\n ),\n clear: () => (\n <button\n aria-label={String(`Clear ${label ?? 'input'}`)}\n className={iconClasses}\n data-testid='spectral-input-clear-button'\n onClick={handleClear}\n type='button'\n >\n <CloseCircleIcon size={24} />\n </button>\n ),\n loading: () => (\n <div\n className='right-4 text-input-icon absolute top-1/2 -translate-y-1/2'\n data-testid='spectral-input-loading-icon'\n >\n <LoaderIcon size={24} />\n </div>\n ),\n error: () => (\n <div\n className='right-4 absolute top-1/2 -translate-y-1/2 text-danger-400'\n data-testid='spectral-input-error-icon'\n >\n <ErrorIcon size={24} />\n </div>\n ),\n success: () => (\n <div\n className='right-4 absolute top-1/2 -translate-y-1/2 text-success-400'\n data-testid='spectral-input-success-icon'\n >\n <CheckCircleIcon size={24} />\n </div>\n ),\n warning: () => (\n <div\n className='right-4 absolute top-1/2 -translate-y-1/2 text-warning-400'\n data-testid='spectral-input-warning-icon'\n >\n <WarningIcon size={24} />\n </div>\n ),\n }\n\n if (endIcon) return <div className='right-4 text-input-icon absolute top-1/2 -translate-y-1/2'>{endIcon}</div>\n if (type === 'password') return iconComponents.password()\n if (showClearButtonNow) return iconComponents.clear()\n if (isLoading) return iconComponents.loading()\n if (!showStateIcon && (state === 'success' || state === 'warning' || state === 'error')) return null\n if (state === 'success') return iconComponents.success()\n if (state === 'warning') return iconComponents.warning()\n if (state === 'error') return iconComponents.error()\n\n return null\n }\n\n const getStartIcon = (): ReactElement | null => {\n if (startIcon) return startIcon\n return null\n }\n\n const usesTabularNumbers = type === 'number' || type === 'date' || type === 'datetime-local'\n const inputClasses = cn(getInputClasses(state, className), '[text-indent:var(--prefix-width)]', showClearButtonNow && 'pr-10', usesTabularNumbers && 'tabular-nums')\n\n const prefixClasses = cn('inset-y-0 left-4 text-base pointer-events-none absolute flex items-center text-input-text-prefix opacity-100 peer-disabled:opacity-50')\n\n return (\n <div\n className='gap-1.5 flex w-full flex-col'\n data-testid='spectral-input-container'\n >\n {label && (\n <Label\n className={cn('mb-2 block', labelClassName, isDisabled && 'cursor-not-allowed text-input-text--disabled placeholder:text-input-text-placeholder')}\n data-testid='spectral-input-label'\n htmlFor={inputId}\n >\n {label}\n </Label>\n )}\n <div\n className='relative'\n data-testid='spectral-input-wrapper'\n >\n <div className='relative'>\n {getStartIcon()}\n {prefix && (\n <span\n ref={prefixRef}\n className={prefixClasses}\n >\n {prefix}\n </span>\n )}\n <input\n aria-label={ariaLabel ?? label}\n autoComplete={getAutoCompleteValue(type)}\n className={inputClasses}\n data-state={state}\n data-testid='spectral-input'\n disabled={isDisabled}\n id={inputId}\n name={name}\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n placeholder={placeholder ?? label}\n ref={inputRef}\n required={required}\n style={\n getFormFieldCSSProperties({\n '--prefix-width': prefix ? `${prefixWidth}px` : '0',\n }) as CSSProperties\n }\n suppressHydrationWarning={suppressHydrationWarning}\n type={type === 'password' ? inputType : type}\n value={value}\n {...ariaProps}\n {...props}\n />\n {getEndIcon()}\n </div>\n\n <ErrorMessage\n dataTestId='spectral-input-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-input-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </div>\n )\n}\nInput.displayName = 'Input'\n"],"mappings":"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"}
|
|
@@ -232,8 +232,8 @@ const MultiSelectBase = ({ className, clearAllLabel = "Clear all", closeOnSelect
|
|
|
232
232
|
children: [/* @__PURE__ */ jsx("span", {
|
|
233
233
|
className: "truncate",
|
|
234
234
|
children: option.label
|
|
235
|
-
}), /* @__PURE__ */ jsx("
|
|
236
|
-
"aria-
|
|
235
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
236
|
+
"aria-label": `Remove ${option.label}`,
|
|
237
237
|
className: "hover:text-danger rounded-sm cursor-pointer",
|
|
238
238
|
"data-testid": "spectral-multiselect-remove-item-button",
|
|
239
239
|
onClick: (e) => {
|
|
@@ -244,6 +244,7 @@ const MultiSelectBase = ({ className, clearAllLabel = "Clear all", closeOnSelect
|
|
|
244
244
|
onPointerDown: (e) => {
|
|
245
245
|
e.stopPropagation();
|
|
246
246
|
},
|
|
247
|
+
type: "button",
|
|
247
248
|
children: /* @__PURE__ */ jsx(CloseIcon, { size: 12 })
|
|
248
249
|
})]
|
|
249
250
|
}, val);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelectBase.js","names":[],"sources":["../../src/components/MultiSelect/MultiSelectBase.tsx"],"sourcesContent":["import { CheckmarkIcon, ChevronDownIcon, CloseIcon, SearchIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport * as Popover from '@radix-ui/react-popover'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport { EmptyState, ErrorMessage, getAriaProps, getDropdownSurfaceClasses, getDropdownWidthStyles, getErrorMessageId, getTriggerClasses, LoadingState, WarningMessage, useFormFieldId, type BaseFormFieldProps, type DropdownWidth, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useEffect, useId, useMemo, useRef, useState, type ButtonHTMLAttributes, type ChangeEvent, type CSSProperties, type KeyboardEvent, type Ref } from 'react'\n\nexport type MultiSelectState = Exclude<FormFieldState, 'disabled'>\n\nexport interface MultiSelectOption {\n disabled?: boolean\n group?: string\n label: string\n value: string\n}\n\nexport interface MultiSelectBaseProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'onChange'> {\n clearAllLabel?: string\n closeOnSelect?: boolean\n dropdownWidth?: DropdownWidth\n emptyMessage?: string\n errorMessage?: BaseFormFieldProps['errorMessage']\n id?: string\n label?: string\n loadingMessage?: string\n maxCount?: number\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name?: string\n defaultValue?: string[]\n onChange?: (value: string[]) => void\n options: MultiSelectOption[]\n placeholder?: string\n required?: boolean\n searchPlaceholder?: string\n showClearAll?: boolean\n showSearch?: boolean\n showSelectAll?: boolean\n selectAllLabel?: string\n sortAlphabetically?: boolean\n state?: MultiSelectState\n value?: string[]\n warningMessage?: BaseFormFieldProps['errorMessage']\n 'aria-label'?: string\n 'aria-describedby'?: string\n}\n\nconst ICON_SIZE = 'h-4 w-4'\n\nconst getDropdownClasses = (): string => {\n return cn(\n 'max-h-80 z-50 overflow-hidden',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in',\n 'motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:fade-in-0',\n 'motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:zoom-in-95',\n 'motion-safe:data-[side=bottom]:slide-in-from-top-2',\n 'motion-safe:data-[side=top]:slide-in-from-bottom-2',\n 'origin-(--radix-popover-content-transform-origin)',\n )\n}\n\ntype FocusableItem = { type: 'search' } | { type: 'select-all' } | { type: 'option'; index: number; value: string } | { type: 'clear-all' }\n\nconst useKeyboardNavigation = (\n options: MultiSelectOption[],\n onClearAll: () => void,\n onClose: () => void,\n onSelect: (value: string) => void,\n onSelectAll: () => void,\n searchInputRef: React.RefObject<HTMLInputElement | null>,\n showSearch: boolean,\n showSelectAll: boolean,\n showClearAll: boolean,\n) => {\n const [focusedIndex, setFocusedIndex] = useState(-1)\n\n // Build a flat list of all focusable items\n const focusableItems = useMemo((): FocusableItem[] => {\n const items: FocusableItem[] = []\n\n if (showSearch) {\n items.push({ type: 'search' })\n }\n\n if (showSelectAll) {\n items.push({ type: 'select-all' })\n }\n\n options.forEach((option, index) => {\n if (!option.disabled) {\n items.push({ type: 'option', index, value: option.value })\n }\n })\n\n if (showClearAll) {\n items.push({ type: 'clear-all' })\n }\n\n return items\n }, [options, showSearch, showSelectAll, showClearAll])\n\n // Focus the appropriate element when focusedIndex changes\n const focusCurrentItem = useCallback(\n (index: number) => {\n if (index < 0 || index >= focusableItems.length) return\n const item = focusableItems[index]\n if (item.type === 'search') {\n searchInputRef.current?.focus()\n }\n },\n [focusableItems, searchInputRef],\n )\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n const currentItem = focusedIndex >= 0 && focusedIndex < focusableItems.length ? focusableItems[focusedIndex] : null\n\n // Don't prevent default for space in search input (allow typing spaces)\n if (event.key === ' ' && currentItem?.type === 'search') {\n return\n }\n\n // Don't prevent default for Enter in search input (allow form submission behavior)\n if (event.key === 'Enter' && currentItem?.type === 'search') {\n return\n }\n\n const keyHandlers: Record<string, () => void> = {\n ArrowDown: () => {\n event.preventDefault()\n const newIndex = Math.min(focusedIndex + 1, focusableItems.length - 1)\n setFocusedIndex(newIndex)\n focusCurrentItem(newIndex)\n },\n ArrowUp: () => {\n event.preventDefault()\n const newIndex = Math.max(focusedIndex - 1, 0)\n setFocusedIndex(newIndex)\n focusCurrentItem(newIndex)\n },\n Tab: () => {\n // Allow Tab to cycle through focusable items\n if (event.shiftKey) {\n if (focusedIndex <= 0) {\n // At start, close dropdown and return to trigger\n onClose()\n } else {\n event.preventDefault()\n const newIndex = focusedIndex - 1\n setFocusedIndex(newIndex)\n focusCurrentItem(newIndex)\n }\n } else {\n if (focusedIndex >= focusableItems.length - 1) {\n // At end, close dropdown and move to next element\n onClose()\n } else {\n event.preventDefault()\n const newIndex = focusedIndex + 1\n setFocusedIndex(newIndex)\n focusCurrentItem(newIndex)\n }\n }\n },\n Enter: () => {\n event.preventDefault()\n if (focusedIndex >= 0 && focusedIndex < focusableItems.length) {\n const item = focusableItems[focusedIndex]\n if (item.type === 'select-all') {\n onSelectAll()\n } else if (item.type === 'clear-all') {\n onClearAll()\n } else if (item.type === 'option') {\n onSelect(item.value)\n }\n }\n },\n ' ': () => {\n event.preventDefault()\n if (focusedIndex >= 0 && focusedIndex < focusableItems.length) {\n const item = focusableItems[focusedIndex]\n if (item.type === 'select-all') {\n onSelectAll()\n } else if (item.type === 'clear-all') {\n onClearAll()\n } else if (item.type === 'option') {\n onSelect(item.value)\n }\n }\n },\n Escape: () => {\n event.preventDefault()\n onClose()\n },\n }\n\n const handler = keyHandlers[event.key]\n if (handler) {\n handler()\n }\n },\n [focusableItems, focusedIndex, onSelect, onSelectAll, onClearAll, onClose, focusCurrentItem],\n )\n\n // Get the option index for visual focus styling (accounting for select-all offset)\n const getOptionFocusIndex = useCallback(\n (optionIndex: number): boolean => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return false\n const item = focusableItems[focusedIndex]\n return item.type === 'option' && item.index === optionIndex\n },\n [focusedIndex, focusableItems],\n )\n\n const isSearchFocused = useMemo(() => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return false\n return focusableItems[focusedIndex].type === 'search'\n }, [focusedIndex, focusableItems])\n\n const isSelectAllFocused = useMemo(() => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return false\n return focusableItems[focusedIndex].type === 'select-all'\n }, [focusedIndex, focusableItems])\n\n const isClearAllFocused = useMemo(() => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return false\n return focusableItems[focusedIndex].type === 'clear-all'\n }, [focusedIndex, focusableItems])\n\n const focusedOptionValue = useMemo(() => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return null\n const item = focusableItems[focusedIndex]\n return item.type === 'option' ? item.value : null\n }, [focusedIndex, focusableItems])\n\n return {\n focusedIndex,\n setFocusedIndex,\n handleKeyDown,\n getOptionFocusIndex,\n isSearchFocused,\n isSelectAllFocused,\n isClearAllFocused,\n focusedOptionValue,\n }\n}\n\nexport const MultiSelectBase = ({\n className,\n clearAllLabel = 'Clear all',\n closeOnSelect = false,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n defaultValue = [],\n disabled,\n id,\n label,\n loadingMessage = 'Loading options…',\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxCount = 3,\n name,\n onChange,\n options = [],\n placeholder = 'Select options',\n ref,\n searchPlaceholder = 'Search options…',\n selectAllLabel = 'Select all',\n showClearAll = true,\n showSearch = true,\n showSelectAll = true,\n sortAlphabetically = false,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n ...props\n}: MultiSelectBaseProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const generatedId = useId()\n const fallbackName = name ?? `multiselect-${generatedId}`\n const multiSelectId = useFormFieldId(id, fallbackName)\n const listboxId = `${multiSelectId}-listbox`\n const errorMessageId = getErrorMessageId(multiSelectId)\n const warningMessageId = `${multiSelectId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n\n const [isOpen, setIsOpen] = useState(false)\n const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(isOpen)\n const [searchValue, setSearchValue] = useState('')\n const [value, setValue] = useUncontrolledState<string[]>({\n value: valueProp,\n defaultValue,\n onChange,\n })\n\n const searchInputRef = useRef<HTMLInputElement>(null)\n\n const isDisabled = Boolean(disabled)\n const isLoading = state === 'loading'\n const ariaProps = getAriaProps(state, ariaDescribedBy, props.required, messageId)\n const { dropdownOverflowStyle, dropdownWidthMode, resolvedDropdownWidth } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--radix-popover-trigger-width)',\n })\n\n const filteredOptions = useMemo(() => {\n let filtered = options.filter((option) => option.label.toLowerCase().includes(searchValue.toLowerCase()))\n\n if (sortAlphabetically) {\n filtered = [...filtered].sort((a, b) => a.label.localeCompare(b.label))\n }\n\n return filtered\n }, [options, searchValue, sortAlphabetically])\n\n const groupedOptions = useMemo(() => {\n const groups: Record<string, MultiSelectOption[]> = {}\n const ungrouped: MultiSelectOption[] = []\n\n filteredOptions.forEach((option) => {\n if (option.group) {\n if (!groups[option.group]) {\n groups[option.group] = []\n }\n groups[option.group].push(option)\n } else {\n ungrouped.push(option)\n }\n })\n\n return { groups, ungrouped, hasGroups: Object.keys(groups).length > 0 }\n }, [filteredOptions])\n\n const toggleOption = useCallback(\n (optionValue: string) => {\n const option = options.find((o) => o.value === optionValue)\n if (option?.disabled) return\n\n const newValue = value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue]\n\n setValue(newValue)\n\n if (closeOnSelect) {\n setIsOpen(false)\n }\n },\n [closeOnSelect, options, setValue, value],\n )\n\n const handleSelectAll = useCallback(() => {\n const allValues = options.filter((o) => !o.disabled).map((o) => o.value)\n const isAllSelected = allValues.every((v) => value.includes(v))\n\n if (isAllSelected) {\n setValue([])\n } else {\n setValue(allValues)\n }\n }, [options, setValue, value])\n\n const handleClearAll = useCallback(() => {\n setValue([])\n }, [setValue])\n\n // Check if all non-disabled options are selected\n const allSelectableValues = useMemo(() => options.filter((o) => !o.disabled).map((o) => o.value), [options])\n const isAllSelected = allSelectableValues.length > 0 && allSelectableValues.every((v) => value.includes(v))\n\n const { focusedOptionValue, getOptionFocusIndex, handleKeyDown, isSelectAllFocused, setFocusedIndex } = useKeyboardNavigation(\n filteredOptions,\n handleClearAll,\n () => setIsOpen(false),\n toggleOption,\n handleSelectAll,\n searchInputRef,\n showSearch,\n showSelectAll,\n false, // No separate clear-all button in dropdown\n )\n\n // Set initial focus index when dropdown opens/closes\n useEffect(() => {\n if (isOpen) {\n setFocusedIndex(0)\n } else {\n setFocusedIndex(-1)\n }\n }, [isOpen, setFocusedIndex])\n\n const handleSearchChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n setSearchValue(e.target.value)\n }, [])\n\n const renderSelectedItems = () => {\n if (value.length === 0) {\n return <span className='min-h-8 flex items-center text-input-text-placeholder'>{placeholder}</span>\n }\n\n const displayedValues = value.slice(0, maxCount)\n const remainingCount = value.length - maxCount\n\n return (\n <div className='gap-1 flex flex-wrap items-center overflow-hidden'>\n {displayedValues.map((val) => {\n const option = options.find((o) => o.value === val)\n if (!option) return null\n\n return (\n <span\n className='gap-1 px-2 py-1 rounded-md text-xs max-w-48 inline-flex items-center bg-input-bg--selected text-input-text'\n key={val}\n >\n <span className='truncate'>{option.label}</span>\n <span\n aria-hidden='true'\n className='hover:text-danger rounded-sm cursor-pointer'\n data-testid='spectral-multiselect-remove-item-button'\n onClick={(e) => {\n e.preventDefault()\n e.stopPropagation()\n toggleOption(val)\n }}\n onPointerDown={(e) => {\n e.stopPropagation()\n }}\n >\n <CloseIcon size={12} />\n </span>\n </span>\n )\n })}\n {remainingCount > 0 && <span className='text-input-text-secondary text-xs py-1 flex items-center tabular-nums'>+{remainingCount} more</span>}\n </div>\n )\n }\n\n const renderOption = (option: MultiSelectOption, index: number) => {\n const isSelected = value.includes(option.value)\n const isFocused = getOptionFocusIndex(index)\n const optionId = `${listboxId}-option-${option.value}`\n\n return (\n <button\n aria-selected={isSelected}\n className={cn(\n 'my-0.5 first:mt-0 last:mb-0 gap-3 rounded-sm px-3 py-2 text-sm flex w-full items-center text-left hover:bg-input-bg--hover focus-visible:bg-input-bg--hover focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',\n isFocused && 'bg-input-bg--hover',\n isSelected && 'font-medium text-input-text',\n )}\n disabled={option.disabled}\n id={optionId}\n key={option.value}\n onClick={() => toggleOption(option.value)}\n role='option'\n type='button'\n >\n <div\n data-testid='spectral-multiselect-selected-indicator'\n className={cn('w-4 h-4 rounded flex items-center justify-center border border-input-border', isSelected && 'bg-primary border-primary')}\n >\n {isSelected && <CheckmarkIcon size={12} />}\n </div>\n <span>{option.label}</span>\n </button>\n )\n }\n\n const getCSSCustomProperties = () => ({\n '--multiselect-border-radius': '0.5rem',\n '--multiselect-trigger-height': '3rem',\n '--multiselect-dropdown-max-height': '20rem',\n })\n\n return (\n <div\n className='w-full'\n data-testid='spectral-multiselect-root'\n >\n {label && (\n <Label\n className={cn('mb-2 block text-text-primary', isDisabled && 'text-text-secondary')}\n data-testid='spectral-multiselect-label'\n htmlFor={multiSelectId}\n >\n {label}\n </Label>\n )}\n <Popover.Root\n open={isOpen}\n onOpenChange={setIsOpen}\n >\n <div\n className='relative'\n data-testid='spectral-multiselect-wrapper'\n onKeyDown={isOpen ? handleKeyDown : undefined}\n role='none'\n >\n <Popover.Trigger asChild>\n <button\n aria-activedescendant={isOpen && focusedOptionValue ? `${listboxId}-option-${focusedOptionValue}` : undefined}\n aria-controls={isOpen ? listboxId : undefined}\n aria-expanded={isOpen}\n aria-label={ariaLabel ?? label}\n className={cn(getTriggerClasses(isOpen, state, className), 'max-h-22 py-2 text-sm')}\n data-state={state}\n data-testid='spectral-multiselect-trigger'\n disabled={isDisabled}\n id={multiSelectId}\n name={name}\n ref={ref}\n role='combobox' // oxlint-disable-line jsx-a11y/prefer-tag-over-role -- trigger uses button-based combobox semantics for listbox popup\n style={getCSSCustomProperties() as CSSProperties}\n type='button'\n {...ariaProps}\n {...props}\n >\n <div\n className='min-w-0 flex-1 overflow-hidden'\n data-testid='spectral-multiselect-selected-items'\n >\n {renderSelectedItems()}\n </div>\n <div className='gap-2 ml-2 flex shrink-0 items-center'>\n <ChevronDownIcon\n className={cn('text-input-icon transition-transform duration-200', isOpen && 'rotate-180')}\n size={20}\n />\n </div>\n </button>\n </Popover.Trigger>\n {showClearAll && value.length > 0 && (\n <button\n aria-label='Clear all selections'\n className='right-10 text-input-icon hover:text-input-icon--hover rounded-sm absolute top-1/2 z-10 -translate-y-1/2 cursor-pointer focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-50'\n data-testid='spectral-multiselect-clear-all-button'\n disabled={isDisabled}\n onClick={(e) => {\n e.stopPropagation()\n handleClearAll()\n document.getElementById(multiSelectId)?.focus()\n }}\n type='button'\n >\n <CloseIcon size={12} />\n </button>\n )}\n\n <Popover.Portal>\n <Popover.Content\n align='start'\n avoidCollisions\n className={getDropdownClasses()}\n collisionPadding={10}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-multiselect-dropdown'\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n if (showSearch) {\n searchInputRef.current?.focus()\n }\n }}\n side='bottom'\n sideOffset={4}\n ref={setDropdownElement}\n style={{\n width: resolvedDropdownWidth,\n ...(dropdownWidth === 'trigger' ? {} : dropdownOverflowStyle),\n ...dropdownShiftStyle,\n }}\n >\n <div className='p-1'>\n {showSearch && (\n <div className='mb-2 relative'>\n <SearchIcon className={cn(ICON_SIZE, 'left-3 text-input-icon absolute top-1/2 -translate-y-1/2')} />\n <input\n aria-label='Search options'\n className='pl-9 pr-3 py-2 text-sm rounded-md focus-visible:ring-black w-full border border-input-border bg-input-bg focus-visible:border-input-border--focus focus-visible:ring-1 focus-visible:outline-none'\n data-testid='spectral-multiselect-search-input'\n onChange={handleSearchChange}\n placeholder={searchPlaceholder}\n ref={searchInputRef}\n type='text'\n value={searchValue}\n />\n </div>\n )}\n <div\n aria-multiselectable='true'\n className='max-h-64 overflow-y-auto'\n id={listboxId}\n role='listbox' // oxlint-disable-line jsx-a11y/prefer-tag-over-role -- custom multi-select uses ARIA listbox semantics with option children\n >\n {isLoading ? (\n <LoadingState\n className='text-sm'\n message={loadingMessage}\n data-testid='spectral-multiselect-loading'\n />\n ) : filteredOptions.length === 0 ? (\n <EmptyState\n className='text-sm'\n data-testid='spectral-multiselect-empty-message'\n message={emptyMessage}\n />\n ) : (\n <>\n {showSelectAll && (\n <div className='mb-1'>\n <button\n className={cn(\n 'my-0.5 first:mt-0 last:mb-0 gap-3 rounded-sm px-3 py-2 text-sm font-medium text-input-text-secondary flex w-full items-center hover:bg-input-bg--hover focus-visible:bg-input-bg--hover focus-visible:outline-none',\n isSelectAllFocused && 'bg-input-bg--hover',\n )}\n data-testid='spectral-multiselect-select-all-button'\n onClick={handleSelectAll}\n type='button'\n >\n {isAllSelected ? clearAllLabel : selectAllLabel}\n </button>\n <div className='mx-3 my-1 h-px bg-input-border' />\n </div>\n )}\n\n {groupedOptions.ungrouped.length > 0 && <div className='mb-1'>{groupedOptions.ungrouped.map((option, index) => renderOption(option, index))}</div>}\n\n {Object.entries(groupedOptions.groups).map(([groupName, groupOptions]) => (\n <div\n key={groupName}\n className='mb-1'\n data-testid='spectral-multiselect-group'\n >\n {(groupedOptions.ungrouped.length > 0 || Object.keys(groupedOptions.groups).indexOf(groupName) > 0) && <div className='mx-3 my-1 h-px bg-input-border' />}\n <div\n data-testid='spectral-multiselect-group-name'\n className='px-3 py-1 text-xs font-semibold text-input-text-secondary tracking-wide uppercase'\n >\n {groupName}\n </div>\n {groupOptions.map((option, _index) => renderOption(option, filteredOptions.indexOf(option)))}\n </div>\n ))}\n </>\n )}\n </div>\n </div>\n </Popover.Content>\n </Popover.Portal>\n </div>\n </Popover.Root>\n\n <ErrorMessage\n dataTestId='spectral-multiselect-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-multiselect-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nMultiSelectBase.displayName = 'MultiSelectBase'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MultiSelectBase.js","names":[],"sources":["../../src/components/MultiSelect/MultiSelectBase.tsx"],"sourcesContent":["import { CheckmarkIcon, ChevronDownIcon, CloseIcon, SearchIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport * as Popover from '@radix-ui/react-popover'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport { EmptyState, ErrorMessage, getAriaProps, getDropdownSurfaceClasses, getDropdownWidthStyles, getErrorMessageId, getTriggerClasses, LoadingState, WarningMessage, useFormFieldId, type BaseFormFieldProps, type DropdownWidth, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useEffect, useId, useMemo, useRef, useState, type ButtonHTMLAttributes, type ChangeEvent, type CSSProperties, type KeyboardEvent, type Ref } from 'react'\n\nexport type MultiSelectState = Exclude<FormFieldState, 'disabled'>\n\nexport interface MultiSelectOption {\n disabled?: boolean\n group?: string\n label: string\n value: string\n}\n\nexport interface MultiSelectBaseProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'onChange'> {\n clearAllLabel?: string\n closeOnSelect?: boolean\n dropdownWidth?: DropdownWidth\n emptyMessage?: string\n errorMessage?: BaseFormFieldProps['errorMessage']\n id?: string\n label?: string\n loadingMessage?: string\n maxCount?: number\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name?: string\n defaultValue?: string[]\n onChange?: (value: string[]) => void\n options: MultiSelectOption[]\n placeholder?: string\n required?: boolean\n searchPlaceholder?: string\n showClearAll?: boolean\n showSearch?: boolean\n showSelectAll?: boolean\n selectAllLabel?: string\n sortAlphabetically?: boolean\n state?: MultiSelectState\n value?: string[]\n warningMessage?: BaseFormFieldProps['errorMessage']\n 'aria-label'?: string\n 'aria-describedby'?: string\n}\n\nconst ICON_SIZE = 'h-4 w-4'\n\nconst getDropdownClasses = (): string => {\n return cn(\n 'max-h-80 z-50 overflow-hidden',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in',\n 'motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:fade-in-0',\n 'motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:zoom-in-95',\n 'motion-safe:data-[side=bottom]:slide-in-from-top-2',\n 'motion-safe:data-[side=top]:slide-in-from-bottom-2',\n 'origin-(--radix-popover-content-transform-origin)',\n )\n}\n\ntype FocusableItem = { type: 'search' } | { type: 'select-all' } | { type: 'option'; index: number; value: string } | { type: 'clear-all' }\n\nconst useKeyboardNavigation = (\n options: MultiSelectOption[],\n onClearAll: () => void,\n onClose: () => void,\n onSelect: (value: string) => void,\n onSelectAll: () => void,\n searchInputRef: React.RefObject<HTMLInputElement | null>,\n showSearch: boolean,\n showSelectAll: boolean,\n showClearAll: boolean,\n) => {\n const [focusedIndex, setFocusedIndex] = useState(-1)\n\n // Build a flat list of all focusable items\n const focusableItems = useMemo((): FocusableItem[] => {\n const items: FocusableItem[] = []\n\n if (showSearch) {\n items.push({ type: 'search' })\n }\n\n if (showSelectAll) {\n items.push({ type: 'select-all' })\n }\n\n options.forEach((option, index) => {\n if (!option.disabled) {\n items.push({ type: 'option', index, value: option.value })\n }\n })\n\n if (showClearAll) {\n items.push({ type: 'clear-all' })\n }\n\n return items\n }, [options, showSearch, showSelectAll, showClearAll])\n\n // Focus the appropriate element when focusedIndex changes\n const focusCurrentItem = useCallback(\n (index: number) => {\n if (index < 0 || index >= focusableItems.length) return\n const item = focusableItems[index]\n if (item.type === 'search') {\n searchInputRef.current?.focus()\n }\n },\n [focusableItems, searchInputRef],\n )\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n const currentItem = focusedIndex >= 0 && focusedIndex < focusableItems.length ? focusableItems[focusedIndex] : null\n\n // Don't prevent default for space in search input (allow typing spaces)\n if (event.key === ' ' && currentItem?.type === 'search') {\n return\n }\n\n // Don't prevent default for Enter in search input (allow form submission behavior)\n if (event.key === 'Enter' && currentItem?.type === 'search') {\n return\n }\n\n const keyHandlers: Record<string, () => void> = {\n ArrowDown: () => {\n event.preventDefault()\n const newIndex = Math.min(focusedIndex + 1, focusableItems.length - 1)\n setFocusedIndex(newIndex)\n focusCurrentItem(newIndex)\n },\n ArrowUp: () => {\n event.preventDefault()\n const newIndex = Math.max(focusedIndex - 1, 0)\n setFocusedIndex(newIndex)\n focusCurrentItem(newIndex)\n },\n Tab: () => {\n // Allow Tab to cycle through focusable items\n if (event.shiftKey) {\n if (focusedIndex <= 0) {\n // At start, close dropdown and return to trigger\n onClose()\n } else {\n event.preventDefault()\n const newIndex = focusedIndex - 1\n setFocusedIndex(newIndex)\n focusCurrentItem(newIndex)\n }\n } else {\n if (focusedIndex >= focusableItems.length - 1) {\n // At end, close dropdown and move to next element\n onClose()\n } else {\n event.preventDefault()\n const newIndex = focusedIndex + 1\n setFocusedIndex(newIndex)\n focusCurrentItem(newIndex)\n }\n }\n },\n Enter: () => {\n event.preventDefault()\n if (focusedIndex >= 0 && focusedIndex < focusableItems.length) {\n const item = focusableItems[focusedIndex]\n if (item.type === 'select-all') {\n onSelectAll()\n } else if (item.type === 'clear-all') {\n onClearAll()\n } else if (item.type === 'option') {\n onSelect(item.value)\n }\n }\n },\n ' ': () => {\n event.preventDefault()\n if (focusedIndex >= 0 && focusedIndex < focusableItems.length) {\n const item = focusableItems[focusedIndex]\n if (item.type === 'select-all') {\n onSelectAll()\n } else if (item.type === 'clear-all') {\n onClearAll()\n } else if (item.type === 'option') {\n onSelect(item.value)\n }\n }\n },\n Escape: () => {\n event.preventDefault()\n onClose()\n },\n }\n\n const handler = keyHandlers[event.key]\n if (handler) {\n handler()\n }\n },\n [focusableItems, focusedIndex, onSelect, onSelectAll, onClearAll, onClose, focusCurrentItem],\n )\n\n // Get the option index for visual focus styling (accounting for select-all offset)\n const getOptionFocusIndex = useCallback(\n (optionIndex: number): boolean => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return false\n const item = focusableItems[focusedIndex]\n return item.type === 'option' && item.index === optionIndex\n },\n [focusedIndex, focusableItems],\n )\n\n const isSearchFocused = useMemo(() => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return false\n return focusableItems[focusedIndex].type === 'search'\n }, [focusedIndex, focusableItems])\n\n const isSelectAllFocused = useMemo(() => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return false\n return focusableItems[focusedIndex].type === 'select-all'\n }, [focusedIndex, focusableItems])\n\n const isClearAllFocused = useMemo(() => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return false\n return focusableItems[focusedIndex].type === 'clear-all'\n }, [focusedIndex, focusableItems])\n\n const focusedOptionValue = useMemo(() => {\n if (focusedIndex < 0 || focusedIndex >= focusableItems.length) return null\n const item = focusableItems[focusedIndex]\n return item.type === 'option' ? item.value : null\n }, [focusedIndex, focusableItems])\n\n return {\n focusedIndex,\n setFocusedIndex,\n handleKeyDown,\n getOptionFocusIndex,\n isSearchFocused,\n isSelectAllFocused,\n isClearAllFocused,\n focusedOptionValue,\n }\n}\n\nexport const MultiSelectBase = ({\n className,\n clearAllLabel = 'Clear all',\n closeOnSelect = false,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n defaultValue = [],\n disabled,\n id,\n label,\n loadingMessage = 'Loading options…',\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxCount = 3,\n name,\n onChange,\n options = [],\n placeholder = 'Select options',\n ref,\n searchPlaceholder = 'Search options…',\n selectAllLabel = 'Select all',\n showClearAll = true,\n showSearch = true,\n showSelectAll = true,\n sortAlphabetically = false,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n ...props\n}: MultiSelectBaseProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const generatedId = useId()\n const fallbackName = name ?? `multiselect-${generatedId}`\n const multiSelectId = useFormFieldId(id, fallbackName)\n const listboxId = `${multiSelectId}-listbox`\n const errorMessageId = getErrorMessageId(multiSelectId)\n const warningMessageId = `${multiSelectId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n\n const [isOpen, setIsOpen] = useState(false)\n const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(isOpen)\n const [searchValue, setSearchValue] = useState('')\n const [value, setValue] = useUncontrolledState<string[]>({\n value: valueProp,\n defaultValue,\n onChange,\n })\n\n const searchInputRef = useRef<HTMLInputElement>(null)\n\n const isDisabled = Boolean(disabled)\n const isLoading = state === 'loading'\n const ariaProps = getAriaProps(state, ariaDescribedBy, props.required, messageId)\n const { dropdownOverflowStyle, dropdownWidthMode, resolvedDropdownWidth } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--radix-popover-trigger-width)',\n })\n\n const filteredOptions = useMemo(() => {\n let filtered = options.filter((option) => option.label.toLowerCase().includes(searchValue.toLowerCase()))\n\n if (sortAlphabetically) {\n filtered = [...filtered].sort((a, b) => a.label.localeCompare(b.label))\n }\n\n return filtered\n }, [options, searchValue, sortAlphabetically])\n\n const groupedOptions = useMemo(() => {\n const groups: Record<string, MultiSelectOption[]> = {}\n const ungrouped: MultiSelectOption[] = []\n\n filteredOptions.forEach((option) => {\n if (option.group) {\n if (!groups[option.group]) {\n groups[option.group] = []\n }\n groups[option.group].push(option)\n } else {\n ungrouped.push(option)\n }\n })\n\n return { groups, ungrouped, hasGroups: Object.keys(groups).length > 0 }\n }, [filteredOptions])\n\n const toggleOption = useCallback(\n (optionValue: string) => {\n const option = options.find((o) => o.value === optionValue)\n if (option?.disabled) return\n\n const newValue = value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue]\n\n setValue(newValue)\n\n if (closeOnSelect) {\n setIsOpen(false)\n }\n },\n [closeOnSelect, options, setValue, value],\n )\n\n const handleSelectAll = useCallback(() => {\n const allValues = options.filter((o) => !o.disabled).map((o) => o.value)\n const isAllSelected = allValues.every((v) => value.includes(v))\n\n if (isAllSelected) {\n setValue([])\n } else {\n setValue(allValues)\n }\n }, [options, setValue, value])\n\n const handleClearAll = useCallback(() => {\n setValue([])\n }, [setValue])\n\n // Check if all non-disabled options are selected\n const allSelectableValues = useMemo(() => options.filter((o) => !o.disabled).map((o) => o.value), [options])\n const isAllSelected = allSelectableValues.length > 0 && allSelectableValues.every((v) => value.includes(v))\n\n const { focusedOptionValue, getOptionFocusIndex, handleKeyDown, isSelectAllFocused, setFocusedIndex } = useKeyboardNavigation(\n filteredOptions,\n handleClearAll,\n () => setIsOpen(false),\n toggleOption,\n handleSelectAll,\n searchInputRef,\n showSearch,\n showSelectAll,\n false, // No separate clear-all button in dropdown\n )\n\n // Set initial focus index when dropdown opens/closes\n useEffect(() => {\n if (isOpen) {\n setFocusedIndex(0)\n } else {\n setFocusedIndex(-1)\n }\n }, [isOpen, setFocusedIndex])\n\n const handleSearchChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n setSearchValue(e.target.value)\n }, [])\n\n const renderSelectedItems = () => {\n if (value.length === 0) {\n return <span className='min-h-8 flex items-center text-input-text-placeholder'>{placeholder}</span>\n }\n\n const displayedValues = value.slice(0, maxCount)\n const remainingCount = value.length - maxCount\n\n return (\n <div className='gap-1 flex flex-wrap items-center overflow-hidden'>\n {displayedValues.map((val) => {\n const option = options.find((o) => o.value === val)\n if (!option) return null\n\n return (\n <span\n className='gap-1 px-2 py-1 rounded-md text-xs max-w-48 inline-flex items-center bg-input-bg--selected text-input-text'\n key={val}\n >\n <span className='truncate'>{option.label}</span>\n <button\n aria-label={`Remove ${option.label}`}\n className='hover:text-danger rounded-sm cursor-pointer'\n data-testid='spectral-multiselect-remove-item-button'\n onClick={(e) => {\n e.preventDefault()\n e.stopPropagation()\n toggleOption(val)\n }}\n onPointerDown={(e) => {\n e.stopPropagation()\n }}\n type='button'\n >\n <CloseIcon size={12} />\n </button>\n </span>\n )\n })}\n {remainingCount > 0 && <span className='text-input-text-secondary text-xs py-1 flex items-center tabular-nums'>+{remainingCount} more</span>}\n </div>\n )\n }\n\n const renderOption = (option: MultiSelectOption, index: number) => {\n const isSelected = value.includes(option.value)\n const isFocused = getOptionFocusIndex(index)\n const optionId = `${listboxId}-option-${option.value}`\n\n return (\n <button\n aria-selected={isSelected}\n className={cn(\n 'my-0.5 first:mt-0 last:mb-0 gap-3 rounded-sm px-3 py-2 text-sm flex w-full items-center text-left hover:bg-input-bg--hover focus-visible:bg-input-bg--hover focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',\n isFocused && 'bg-input-bg--hover',\n isSelected && 'font-medium text-input-text',\n )}\n disabled={option.disabled}\n id={optionId}\n key={option.value}\n onClick={() => toggleOption(option.value)}\n role='option'\n type='button'\n >\n <div\n data-testid='spectral-multiselect-selected-indicator'\n className={cn('w-4 h-4 rounded flex items-center justify-center border border-input-border', isSelected && 'bg-primary border-primary')}\n >\n {isSelected && <CheckmarkIcon size={12} />}\n </div>\n <span>{option.label}</span>\n </button>\n )\n }\n\n const getCSSCustomProperties = () => ({\n '--multiselect-border-radius': '0.5rem',\n '--multiselect-trigger-height': '3rem',\n '--multiselect-dropdown-max-height': '20rem',\n })\n\n return (\n <div\n className='w-full'\n data-testid='spectral-multiselect-root'\n >\n {label && (\n <Label\n className={cn('mb-2 block text-text-primary', isDisabled && 'text-text-secondary')}\n data-testid='spectral-multiselect-label'\n htmlFor={multiSelectId}\n >\n {label}\n </Label>\n )}\n <Popover.Root\n open={isOpen}\n onOpenChange={setIsOpen}\n >\n <div\n className='relative'\n data-testid='spectral-multiselect-wrapper'\n onKeyDown={isOpen ? handleKeyDown : undefined}\n role='none'\n >\n <Popover.Trigger asChild>\n <button\n aria-activedescendant={isOpen && focusedOptionValue ? `${listboxId}-option-${focusedOptionValue}` : undefined}\n aria-controls={isOpen ? listboxId : undefined}\n aria-expanded={isOpen}\n aria-label={ariaLabel ?? label}\n className={cn(getTriggerClasses(isOpen, state, className), 'max-h-22 py-2 text-sm')}\n data-state={state}\n data-testid='spectral-multiselect-trigger'\n disabled={isDisabled}\n id={multiSelectId}\n name={name}\n ref={ref}\n role='combobox' // oxlint-disable-line jsx-a11y/prefer-tag-over-role -- trigger uses button-based combobox semantics for listbox popup\n style={getCSSCustomProperties() as CSSProperties}\n type='button'\n {...ariaProps}\n {...props}\n >\n <div\n className='min-w-0 flex-1 overflow-hidden'\n data-testid='spectral-multiselect-selected-items'\n >\n {renderSelectedItems()}\n </div>\n <div className='gap-2 ml-2 flex shrink-0 items-center'>\n <ChevronDownIcon\n className={cn('text-input-icon transition-transform duration-200', isOpen && 'rotate-180')}\n size={20}\n />\n </div>\n </button>\n </Popover.Trigger>\n {showClearAll && value.length > 0 && (\n <button\n aria-label='Clear all selections'\n className='right-10 text-input-icon hover:text-input-icon--hover rounded-sm absolute top-1/2 z-10 -translate-y-1/2 cursor-pointer focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-50'\n data-testid='spectral-multiselect-clear-all-button'\n disabled={isDisabled}\n onClick={(e) => {\n e.stopPropagation()\n handleClearAll()\n document.getElementById(multiSelectId)?.focus()\n }}\n type='button'\n >\n <CloseIcon size={12} />\n </button>\n )}\n\n <Popover.Portal>\n <Popover.Content\n align='start'\n avoidCollisions\n className={getDropdownClasses()}\n collisionPadding={10}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-multiselect-dropdown'\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n if (showSearch) {\n searchInputRef.current?.focus()\n }\n }}\n side='bottom'\n sideOffset={4}\n ref={setDropdownElement}\n style={{\n width: resolvedDropdownWidth,\n ...(dropdownWidth === 'trigger' ? {} : dropdownOverflowStyle),\n ...dropdownShiftStyle,\n }}\n >\n <div className='p-1'>\n {showSearch && (\n <div className='mb-2 relative'>\n <SearchIcon className={cn(ICON_SIZE, 'left-3 text-input-icon absolute top-1/2 -translate-y-1/2')} />\n <input\n aria-label='Search options'\n className='pl-9 pr-3 py-2 text-sm rounded-md focus-visible:ring-black w-full border border-input-border bg-input-bg focus-visible:border-input-border--focus focus-visible:ring-1 focus-visible:outline-none'\n data-testid='spectral-multiselect-search-input'\n onChange={handleSearchChange}\n placeholder={searchPlaceholder}\n ref={searchInputRef}\n type='text'\n value={searchValue}\n />\n </div>\n )}\n <div\n aria-multiselectable='true'\n className='max-h-64 overflow-y-auto'\n id={listboxId}\n role='listbox' // oxlint-disable-line jsx-a11y/prefer-tag-over-role -- custom multi-select uses ARIA listbox semantics with option children\n >\n {isLoading ? (\n <LoadingState\n className='text-sm'\n message={loadingMessage}\n data-testid='spectral-multiselect-loading'\n />\n ) : filteredOptions.length === 0 ? (\n <EmptyState\n className='text-sm'\n data-testid='spectral-multiselect-empty-message'\n message={emptyMessage}\n />\n ) : (\n <>\n {showSelectAll && (\n <div className='mb-1'>\n <button\n className={cn(\n 'my-0.5 first:mt-0 last:mb-0 gap-3 rounded-sm px-3 py-2 text-sm font-medium text-input-text-secondary flex w-full items-center hover:bg-input-bg--hover focus-visible:bg-input-bg--hover focus-visible:outline-none',\n isSelectAllFocused && 'bg-input-bg--hover',\n )}\n data-testid='spectral-multiselect-select-all-button'\n onClick={handleSelectAll}\n type='button'\n >\n {isAllSelected ? clearAllLabel : selectAllLabel}\n </button>\n <div className='mx-3 my-1 h-px bg-input-border' />\n </div>\n )}\n\n {groupedOptions.ungrouped.length > 0 && <div className='mb-1'>{groupedOptions.ungrouped.map((option, index) => renderOption(option, index))}</div>}\n\n {Object.entries(groupedOptions.groups).map(([groupName, groupOptions]) => (\n <div\n key={groupName}\n className='mb-1'\n data-testid='spectral-multiselect-group'\n >\n {(groupedOptions.ungrouped.length > 0 || Object.keys(groupedOptions.groups).indexOf(groupName) > 0) && <div className='mx-3 my-1 h-px bg-input-border' />}\n <div\n data-testid='spectral-multiselect-group-name'\n className='px-3 py-1 text-xs font-semibold text-input-text-secondary tracking-wide uppercase'\n >\n {groupName}\n </div>\n {groupOptions.map((option, _index) => renderOption(option, filteredOptions.indexOf(option)))}\n </div>\n ))}\n </>\n )}\n </div>\n </div>\n </Popover.Content>\n </Popover.Portal>\n </div>\n </Popover.Root>\n\n <ErrorMessage\n dataTestId='spectral-multiselect-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-multiselect-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nMultiSelectBase.displayName = 'MultiSelectBase'\n"],"mappings":"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"}
|
package/dist/RadioGroup.js
CHANGED
|
@@ -46,7 +46,7 @@ const RadioGroup = (allProps) => {
|
|
|
46
46
|
value: contextValue,
|
|
47
47
|
children: /* @__PURE__ */ jsxs("div", {
|
|
48
48
|
"data-slot": "radio-group-field",
|
|
49
|
-
className: "
|
|
49
|
+
className: "gap-1.5 flex w-full flex-col",
|
|
50
50
|
children: [
|
|
51
51
|
/* @__PURE__ */ jsx(RadioGroupPrimitive.Root, {
|
|
52
52
|
className: cn("flex w-full text-text-primary", orientation === "vertical" ? "gap-4 flex-col" : "gap-5 flex-row", variant === "unstyled" && "gap-2.5 w-fit", className),
|
package/dist/RadioGroup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.js","names":[],"sources":["../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { AnimatePresence, motion, useReducedMotion, type Transition } from 'motion/react'\nimport { createContext, memo, useContext, useId, useMemo, type ComponentProps, type ComponentRef, type ReactElement, type ReactNode, type Ref } from 'react'\n\ntype RadioGroupVariant = 'default' | 'unstyled'\n\nexport interface RadioGroupProps extends Omit<ComponentProps<typeof RadioGroupPrimitive.Root>, 'onChange' | 'disabled'> {\n 'aria-describedby'?: string\n 'aria-label'?: string\n className?: string\n disabled?: boolean | string[]\n errorMessage?: BaseFormFieldProps['errorMessage']\n itemClassName?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name: string\n onChange?: (selected: string) => void\n onValueChange: (selected: string) => void\n orientation?: 'horizontal' | 'vertical'\n required?: boolean\n selected?: string\n state?: FormFieldState\n variant?: RadioGroupVariant\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport interface RadioGroupItemProps extends ComponentProps<typeof RadioGroupPrimitive.Item> {\n className?: string\n children?: ReactNode\n description?: string | ReactNode\n id?: string\n value: string\n}\n\ninterface RadioGroupContextType {\n disabledValues: string[]\n groupDisabled: boolean\n itemClassName?: string\n orientation: 'horizontal' | 'vertical'\n selected?: string\n variant: RadioGroupVariant\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextType>({\n disabledValues: [],\n groupDisabled: false,\n orientation: 'vertical',\n variant: 'default',\n})\n\nconst DISABLED_STYLES = 'pointer-events-none opacity-60'\n\nconst RadioGroup = (\n allProps: RadioGroupProps & {\n ref?: Ref<ComponentRef<typeof RadioGroupPrimitive.Root>>\n },\n): ReactElement => {\n const isControlled = 'selected' in allProps\n const {\n className,\n disabled,\n errorMessage,\n itemClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n orientation = 'vertical',\n ref,\n selected: selectedProp,\n state = 'default',\n variant = 'default',\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const selected = isControlled ? (selectedProp ?? '') : selectedProp\n const groupId = useFormFieldId(props.id, name)\n const errorMessageId = `${groupId}-error`\n const warningMessageId = `${groupId}-warning`\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const handleValueChange = (nextValue: string) => {\n onValueChange(nextValue)\n onChange?.(nextValue)\n }\n\n const contextValue = useMemo(\n () => ({\n disabledValues: Array.isArray(disabled) ? disabled : [],\n groupDisabled: typeof disabled === 'boolean' ? disabled : false,\n itemClassName,\n orientation,\n selected,\n variant,\n }),\n [orientation, variant, disabled, itemClassName, selected],\n )\n\n return (\n <RadioGroupContext.Provider value={contextValue}>\n <div\n data-slot='radio-group-field'\n className='space-y-1.5 w-full'\n >\n <RadioGroupPrimitive.Root\n className={cn('flex w-full text-text-primary', orientation === 'vertical' ? 'gap-4 flex-col' : 'gap-5 flex-row', variant === 'unstyled' && 'gap-2.5 w-fit', className)}\n data-state={state}\n data-testid='spectral-radio-group'\n id={groupId}\n aria-invalid={state === 'error' ? true : undefined}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n disabled={contextValue.groupDisabled}\n name={name}\n onValueChange={handleValueChange}\n ref={ref}\n value={selected}\n {...props}\n />\n <ErrorMessage\n dataTestId='spectral-radio-group-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-radio-group-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </RadioGroupContext.Provider>\n )\n}\nRadioGroup.displayName = 'RadioGroup'\n\nconst DEFAULT_TRANSITION: Transition = { type: 'spring', stiffness: 200, damping: 16 }\n\nconst RadioButton = memo(\n ({\n className,\n id,\n isDisabled,\n ref,\n transition = DEFAULT_TRANSITION,\n value,\n ...props\n }: Omit<ComponentProps<typeof RadioGroupPrimitive.Item>, 'asChild'> & {\n isDisabled?: boolean\n ref?: Ref<HTMLButtonElement>\n transition?: Transition\n }) => {\n const prefersReducedMotion = useReducedMotion()\n\n // When reduced motion is preferred, fall back to original non-animated behavior\n if (prefersReducedMotion) {\n return (\n <RadioGroupPrimitive.Item\n className={cn(\n 'h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors',\n 'hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg',\n isDisabled && DISABLED_STYLES,\n className,\n )}\n data-testid='spectral-radio-group-item'\n disabled={isDisabled}\n id={id}\n ref={ref as Ref<ComponentRef<typeof RadioGroupPrimitive.Item>>}\n value={value}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className={cn(`after:inset-0 after:h-2.5 after:w-2.5 after:absolute after:m-auto after:rounded-full after:bg-radio-bg--selected after:content-['']`, isDisabled && DISABLED_STYLES)} />\n </RadioGroupPrimitive.Item>\n )\n }\n\n return (\n <RadioGroupPrimitive.Item\n value={value}\n id={id}\n disabled={isDisabled}\n asChild\n {...props}\n >\n <motion.button\n className={cn(\n 'h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors',\n 'hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg',\n isDisabled && DISABLED_STYLES,\n className,\n )}\n data-testid='spectral-radio-group-item'\n ref={ref}\n whileHover={{ scale: 1.05 }}\n whileTap={{ scale: 0.95 }}\n >\n <RadioGroupPrimitive.Indicator className='relative flex items-center justify-center'>\n <AnimatePresence>\n <motion.div\n animate={{ opacity: 1, scale: 1 }}\n className='h-2.5 w-2.5 absolute rounded-full bg-radio-bg--selected'\n exit={{ opacity: 0, scale: 0 }}\n initial={{ opacity: 0, scale: 0 }}\n key='radio-indicator'\n transition={transition}\n />\n </AnimatePresence>\n </RadioGroupPrimitive.Indicator>\n </motion.button>\n </RadioGroupPrimitive.Item>\n )\n },\n)\nRadioButton.displayName = 'RadioButton'\n\nconst RadioGroupItem = ({\n children,\n className,\n disabled,\n ref,\n value,\n ...props\n}: RadioGroupItemProps & {\n ref?: Ref<ComponentRef<typeof RadioGroupPrimitive.Item>>\n}): ReactElement => {\n const { disabledValues, groupDisabled, itemClassName, variant, orientation } = useContext(RadioGroupContext)\n const generatedId = useId()\n\n const stringValue = value.toString()\n const id = props.id?.toString() ?? `${stringValue}-${generatedId}`\n const isDisabled = groupDisabled || disabledValues.includes(stringValue) || Boolean(disabled)\n\n if (variant === 'unstyled') {\n return (\n <RadioGroupPrimitive.Item\n asChild\n data-testid='spectral-radio-group-item'\n disabled={isDisabled}\n id={id}\n ref={ref}\n value={stringValue}\n {...props}\n >\n <Label\n className={cn('rounded flex h-fit w-fit border-2 border-transparent data-[state=checked]:border-radio-border--selected', isDisabled && DISABLED_STYLES, itemClassName, className)}\n data-testid='spectral-radio-group-item-label'\n htmlFor={id}\n >\n {children}\n </Label>\n </RadioGroupPrimitive.Item>\n )\n }\n\n return (\n <div className={cn('flex items-center', isDisabled && DISABLED_STYLES, itemClassName, className, orientation)}>\n <RadioButton\n ref={ref}\n value={stringValue}\n id={id}\n isDisabled={isDisabled}\n {...props}\n />\n {children && (\n <Label\n className={cn('text-md font-normal cursor-pointer', orientation === 'vertical' ? 'ml-2' : 'ml-1')}\n htmlFor={id}\n >\n {children}\n </Label>\n )}\n </div>\n )\n}\nRadioGroupItem.displayName = 'RadioGroup.Item'\n\nconst RadioGroupLabel = ({\n ref,\n className,\n ...props\n}: ComponentProps<typeof Label> & {\n ref?: Ref<ComponentRef<typeof Label>>\n}): ReactElement => {\n return (\n <Label\n ref={ref}\n data-testid='spectral-radio-group-label'\n className={cn('text-md font-medium block', className)}\n {...props}\n />\n )\n}\nRadioGroupLabel.displayName = 'RadioGroup.Label'\n\nexport { RadioGroup, RadioGroupItem, RadioGroupLabel }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RadioGroup.js","names":[],"sources":["../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { AnimatePresence, motion, useReducedMotion, type Transition } from 'motion/react'\nimport { createContext, memo, useContext, useId, useMemo, type ComponentProps, type ComponentRef, type ReactElement, type ReactNode, type Ref } from 'react'\n\ntype RadioGroupVariant = 'default' | 'unstyled'\n\nexport interface RadioGroupProps extends Omit<ComponentProps<typeof RadioGroupPrimitive.Root>, 'onChange' | 'disabled'> {\n 'aria-describedby'?: string\n 'aria-label'?: string\n className?: string\n disabled?: boolean | string[]\n errorMessage?: BaseFormFieldProps['errorMessage']\n itemClassName?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name: string\n onChange?: (selected: string) => void\n onValueChange: (selected: string) => void\n orientation?: 'horizontal' | 'vertical'\n required?: boolean\n selected?: string\n state?: FormFieldState\n variant?: RadioGroupVariant\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport interface RadioGroupItemProps extends ComponentProps<typeof RadioGroupPrimitive.Item> {\n className?: string\n children?: ReactNode\n description?: string | ReactNode\n id?: string\n value: string\n}\n\ninterface RadioGroupContextType {\n disabledValues: string[]\n groupDisabled: boolean\n itemClassName?: string\n orientation: 'horizontal' | 'vertical'\n selected?: string\n variant: RadioGroupVariant\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextType>({\n disabledValues: [],\n groupDisabled: false,\n orientation: 'vertical',\n variant: 'default',\n})\n\nconst DISABLED_STYLES = 'pointer-events-none opacity-60'\n\nconst RadioGroup = (\n allProps: RadioGroupProps & {\n ref?: Ref<ComponentRef<typeof RadioGroupPrimitive.Root>>\n },\n): ReactElement => {\n const isControlled = 'selected' in allProps\n const {\n className,\n disabled,\n errorMessage,\n itemClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n orientation = 'vertical',\n ref,\n selected: selectedProp,\n state = 'default',\n variant = 'default',\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const selected = isControlled ? (selectedProp ?? '') : selectedProp\n const groupId = useFormFieldId(props.id, name)\n const errorMessageId = `${groupId}-error`\n const warningMessageId = `${groupId}-warning`\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const handleValueChange = (nextValue: string) => {\n onValueChange(nextValue)\n onChange?.(nextValue)\n }\n\n const contextValue = useMemo(\n () => ({\n disabledValues: Array.isArray(disabled) ? disabled : [],\n groupDisabled: typeof disabled === 'boolean' ? disabled : false,\n itemClassName,\n orientation,\n selected,\n variant,\n }),\n [orientation, variant, disabled, itemClassName, selected],\n )\n\n return (\n <RadioGroupContext.Provider value={contextValue}>\n <div\n data-slot='radio-group-field'\n className='gap-1.5 flex w-full flex-col'\n >\n <RadioGroupPrimitive.Root\n className={cn('flex w-full text-text-primary', orientation === 'vertical' ? 'gap-4 flex-col' : 'gap-5 flex-row', variant === 'unstyled' && 'gap-2.5 w-fit', className)}\n data-state={state}\n data-testid='spectral-radio-group'\n id={groupId}\n aria-invalid={state === 'error' ? true : undefined}\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n disabled={contextValue.groupDisabled}\n name={name}\n onValueChange={handleValueChange}\n ref={ref}\n value={selected}\n {...props}\n />\n <ErrorMessage\n dataTestId='spectral-radio-group-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-radio-group-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </RadioGroupContext.Provider>\n )\n}\nRadioGroup.displayName = 'RadioGroup'\n\nconst DEFAULT_TRANSITION: Transition = { type: 'spring', stiffness: 200, damping: 16 }\n\nconst RadioButton = memo(\n ({\n className,\n id,\n isDisabled,\n ref,\n transition = DEFAULT_TRANSITION,\n value,\n ...props\n }: Omit<ComponentProps<typeof RadioGroupPrimitive.Item>, 'asChild'> & {\n isDisabled?: boolean\n ref?: Ref<HTMLButtonElement>\n transition?: Transition\n }) => {\n const prefersReducedMotion = useReducedMotion()\n\n // When reduced motion is preferred, fall back to original non-animated behavior\n if (prefersReducedMotion) {\n return (\n <RadioGroupPrimitive.Item\n className={cn(\n 'h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors',\n 'hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg',\n isDisabled && DISABLED_STYLES,\n className,\n )}\n data-testid='spectral-radio-group-item'\n disabled={isDisabled}\n id={id}\n ref={ref as Ref<ComponentRef<typeof RadioGroupPrimitive.Item>>}\n value={value}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className={cn(`after:inset-0 after:h-2.5 after:w-2.5 after:absolute after:m-auto after:rounded-full after:bg-radio-bg--selected after:content-['']`, isDisabled && DISABLED_STYLES)} />\n </RadioGroupPrimitive.Item>\n )\n }\n\n return (\n <RadioGroupPrimitive.Item\n value={value}\n id={id}\n disabled={isDisabled}\n asChild\n {...props}\n >\n <motion.button\n className={cn(\n 'h-4.5 w-4.5 border-border-subtle ring-black relative aspect-square cursor-pointer rounded-full border-2 bg-radio-bg transition-colors',\n 'hover:border-radio-border--hover focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'data-[state=checked]:border-radio-border--selected data-[state=checked]:bg-radio-bg',\n isDisabled && DISABLED_STYLES,\n className,\n )}\n data-testid='spectral-radio-group-item'\n ref={ref}\n whileHover={{ scale: 1.05 }}\n whileTap={{ scale: 0.95 }}\n >\n <RadioGroupPrimitive.Indicator className='relative flex items-center justify-center'>\n <AnimatePresence>\n <motion.div\n animate={{ opacity: 1, scale: 1 }}\n className='h-2.5 w-2.5 absolute rounded-full bg-radio-bg--selected'\n exit={{ opacity: 0, scale: 0 }}\n initial={{ opacity: 0, scale: 0 }}\n key='radio-indicator'\n transition={transition}\n />\n </AnimatePresence>\n </RadioGroupPrimitive.Indicator>\n </motion.button>\n </RadioGroupPrimitive.Item>\n )\n },\n)\nRadioButton.displayName = 'RadioButton'\n\nconst RadioGroupItem = ({\n children,\n className,\n disabled,\n ref,\n value,\n ...props\n}: RadioGroupItemProps & {\n ref?: Ref<ComponentRef<typeof RadioGroupPrimitive.Item>>\n}): ReactElement => {\n const { disabledValues, groupDisabled, itemClassName, variant, orientation } = useContext(RadioGroupContext)\n const generatedId = useId()\n\n const stringValue = value.toString()\n const id = props.id?.toString() ?? `${stringValue}-${generatedId}`\n const isDisabled = groupDisabled || disabledValues.includes(stringValue) || Boolean(disabled)\n\n if (variant === 'unstyled') {\n return (\n <RadioGroupPrimitive.Item\n asChild\n data-testid='spectral-radio-group-item'\n disabled={isDisabled}\n id={id}\n ref={ref}\n value={stringValue}\n {...props}\n >\n <Label\n className={cn('rounded flex h-fit w-fit border-2 border-transparent data-[state=checked]:border-radio-border--selected', isDisabled && DISABLED_STYLES, itemClassName, className)}\n data-testid='spectral-radio-group-item-label'\n htmlFor={id}\n >\n {children}\n </Label>\n </RadioGroupPrimitive.Item>\n )\n }\n\n return (\n <div className={cn('flex items-center', isDisabled && DISABLED_STYLES, itemClassName, className, orientation)}>\n <RadioButton\n ref={ref}\n value={stringValue}\n id={id}\n isDisabled={isDisabled}\n {...props}\n />\n {children && (\n <Label\n className={cn('text-md font-normal cursor-pointer', orientation === 'vertical' ? 'ml-2' : 'ml-1')}\n htmlFor={id}\n >\n {children}\n </Label>\n )}\n </div>\n )\n}\nRadioGroupItem.displayName = 'RadioGroup.Item'\n\nconst RadioGroupLabel = ({\n ref,\n className,\n ...props\n}: ComponentProps<typeof Label> & {\n ref?: Ref<ComponentRef<typeof Label>>\n}): ReactElement => {\n return (\n <Label\n ref={ref}\n data-testid='spectral-radio-group-label'\n className={cn('text-md font-medium block', className)}\n {...props}\n />\n )\n}\nRadioGroupLabel.displayName = 'RadioGroup.Label'\n\nexport { RadioGroup, RadioGroupItem, RadioGroupLabel }\n"],"mappings":"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"}
|
package/dist/Switch.js
CHANGED
|
@@ -47,17 +47,17 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
|
|
|
47
47
|
required,
|
|
48
48
|
value,
|
|
49
49
|
...props,
|
|
50
|
-
children: /* @__PURE__ */ jsx(SwitchThumb, { className: cn(thumbBase, "size-6.5 shadow-xs relative z-10 duration-
|
|
50
|
+
children: /* @__PURE__ */ jsx(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]") })
|
|
51
51
|
}),
|
|
52
52
|
/* @__PURE__ */ jsx("span", {
|
|
53
|
-
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-
|
|
53
|
+
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",
|
|
54
54
|
children: /* @__PURE__ */ jsx(XIcon, {
|
|
55
55
|
"aria-hidden": "true",
|
|
56
56
|
className: "size-4"
|
|
57
57
|
})
|
|
58
58
|
}),
|
|
59
59
|
/* @__PURE__ */ jsx("span", {
|
|
60
|
-
className: "min-w-8 motion-reduce:translate-x-0 pointer-events-none relative flex items-center justify-center text-center transition-transform duration-
|
|
60
|
+
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",
|
|
61
61
|
children: /* @__PURE__ */ jsx(CheckIcon, {
|
|
62
62
|
"aria-hidden": "true",
|
|
63
63
|
className: "size-4"
|
|
@@ -69,7 +69,7 @@ const Switch = ({ className, disabled, errorMessage, hideLabel = false, id, labe
|
|
|
69
69
|
"aria-describedby": [messageId, ariaDescribedBy].filter(Boolean).join(" ") || void 0,
|
|
70
70
|
"aria-invalid": state === "error" ? true : void 0,
|
|
71
71
|
"aria-label": ariaLabel ?? (hideLabel ? resolvedLabelText : void 0),
|
|
72
|
-
className: cn(isSquared ? "peer h-6 w-10 rounded-sm focus-visible:ring-black inline-flex shrink-0 items-center border-2 border-transparent transition-
|
|
72
|
+
className: cn(isSquared ? "peer h-6 w-10 rounded-sm focus-visible:ring-black inline-flex shrink-0 items-center border-2 border-transparent transition-colors outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg [&_span]:rounded-[4px]" : "focus-visible:ring-ring peer h-6 w-10 shadow-2xs inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-switch-bg--checked data-[state=unchecked]:bg-switch-bg", className),
|
|
73
73
|
"data-testid": "spectral-switch",
|
|
74
74
|
disabled: isDisabled,
|
|
75
75
|
id: switchId,
|
package/dist/Switch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.js","names":["SwitchBase"],"sources":["../src/components/Switch/Switch.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { CheckIcon, XIcon } from 'lucide-react'\nimport { type Ref } from 'react'\nimport { Switch as SwitchBase, SwitchThumb, type SwitchProps as SwitchBaseProps } from './SwitchBase'\n\ntype SwitchVisualState = Exclude<FormFieldState, 'disabled'>\n\nexport type SwitchProps = Omit<SwitchBaseProps, 'onCheckedChange'> & {\n 'aria-describedby'?: string\n 'aria-label'?: string\n errorMessage?: BaseFormFieldProps['errorMessage']\n hideLabel?: boolean\n id?: string\n label?: string\n labelPosition?: 'left' | 'right'\n labelText?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (checked: boolean) => void\n ref?: Ref<HTMLButtonElement>\n required?: boolean\n state?: SwitchVisualState\n value?: string\n variant?: 'default' | 'squared' | 'permanent-indicator'\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst thumbBase = 'bg-switch-thumb--checked data-[state=checked]:bg-switch-thumb pointer-events-none block rounded-full ring-0 transition-transform motion-reduce:transition-none'\n\nexport const Switch = ({\n className,\n disabled,\n errorMessage,\n hideLabel = false,\n id,\n label,\n labelPosition = 'right',\n labelText,\n messageReserveLines = 1,\n messageReserveSpace = 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\n className='flex items-center'\n data-testid='spectral-switch-container'\n data-state={state}\n >\n {labelPosition === 'left' && !hideLabel && resolvedLabelText && (\n <Label\n className='mr-2'\n data-testid='spectral-switch-label-left'\n htmlFor={switchId}\n >\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\n aria-hidden='true'\n className='size-4'\n />\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\n aria-hidden='true'\n className='size-4'\n />\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\n className='ml-2'\n data-testid='spectral-switch-label-right'\n htmlFor={switchId}\n id={`${switchId}-label`}\n >\n {resolvedLabelText}\n </Label>\n )}\n\n {hideLabel && resolvedLabelText && (\n <Label\n className='sr-only'\n data-testid='spectral-switch-label-hidden'\n htmlFor={switchId}\n >\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,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;EACE,WAAU;EACV,eAAY;EACZ,cAAY;YAHd;GAKG,kBAAkB,UAAU,CAAC,aAAa,qBACzC,oBAAC,OAAD;IACE,WAAU;IACV,eAAY;IACZ,SAAS;cAER;IACK;GAfe,YAAY,wBAmBnC,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;OACE,eAAY;OACZ,WAAU;OACV;MACG;KACP,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD;OACE,eAAY;OACZ,WAAU;OACV;MACG;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;IACE,WAAU;IACV,eAAY;IACZ,SAAS;IACT,IAAI,GAAG,SAAS;cAEf;IACK;GAGT,aAAa,qBACZ,oBAAC,OAAD;IACE,WAAU;IACV,eAAY;IACZ,SAAS;cAER;IACK;GAEV,oBAAC,cAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,UAAW,gBAAgB,OAAQ;IACjC;IACrB,qBAAqB,uBAAuB,UAAU;IACtD;GACF,oBAAC,gBAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IACrC;IACrB,qBAAqB,uBAAuB,UAAU;IACtD;GACE;;;AAGV,OAAO,cAAc"}
|
|
1
|
+
{"version":3,"file":"Switch.js","names":["SwitchBase"],"sources":["../src/components/Switch/Switch.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { CheckIcon, XIcon } from 'lucide-react'\nimport { type Ref } from 'react'\nimport { Switch as SwitchBase, SwitchThumb, type SwitchProps as SwitchBaseProps } from './SwitchBase'\n\ntype SwitchVisualState = Exclude<FormFieldState, 'disabled'>\n\nexport type SwitchProps = Omit<SwitchBaseProps, 'onCheckedChange'> & {\n 'aria-describedby'?: string\n 'aria-label'?: string\n errorMessage?: BaseFormFieldProps['errorMessage']\n hideLabel?: boolean\n id?: string\n label?: string\n labelPosition?: 'left' | 'right'\n labelText?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (checked: boolean) => void\n ref?: Ref<HTMLButtonElement>\n required?: boolean\n state?: SwitchVisualState\n value?: string\n variant?: 'default' | 'squared' | 'permanent-indicator'\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst thumbBase = 'bg-switch-thumb--checked data-[state=checked]:bg-switch-thumb pointer-events-none block rounded-full ring-0 transition-transform motion-reduce:transition-none'\n\nexport const Switch = ({\n className,\n disabled,\n errorMessage,\n hideLabel = false,\n id,\n label,\n labelPosition = 'right',\n labelText,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n ref,\n required,\n state = 'default',\n value,\n variant,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n ...props\n}: SwitchProps) => {\n const switchId = useFormFieldId(id, name)\n const isDisabled = Boolean(disabled)\n const resolvedLabelText = labelText ?? label\n const errorMessageId = `${switchId}-error`\n const warningMessageId = `${switchId}-warning`\n const messageId = state === 'error' && errorMessage && errorMessageId ? errorMessageId : state === 'warning' && warningMessage && warningMessageId ? warningMessageId : undefined\n const isSquared = variant === 'squared'\n const isPermanentIndicator = variant === 'permanent-indicator'\n\n return (\n <div\n className='flex items-center'\n data-testid='spectral-switch-container'\n data-state={state}\n >\n {labelPosition === 'left' && !hideLabel && resolvedLabelText && (\n <Label\n className='mr-2'\n data-testid='spectral-switch-label-left'\n htmlFor={switchId}\n >\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\n aria-hidden='true'\n className='size-4'\n />\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\n aria-hidden='true'\n className='size-4'\n />\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\n className='ml-2'\n data-testid='spectral-switch-label-right'\n htmlFor={switchId}\n id={`${switchId}-label`}\n >\n {resolvedLabelText}\n </Label>\n )}\n\n {hideLabel && resolvedLabelText && (\n <Label\n className='sr-only'\n data-testid='spectral-switch-label-hidden'\n htmlFor={switchId}\n >\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,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;EACE,WAAU;EACV,eAAY;EACZ,cAAY;YAHd;GAKG,kBAAkB,UAAU,CAAC,aAAa,qBACzC,oBAAC,OAAD;IACE,WAAU;IACV,eAAY;IACZ,SAAS;cAER;IACK;GAfe,YAAY,wBAmBnC,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,uKAAuK,EAAI;MACtM;KACb,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,OAAD;OACE,eAAY;OACZ,WAAU;OACV;MACG;KACP,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD;OACE,eAAY;OACZ,WAAU;OACV;MACG;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,kUACA,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;IACE,WAAU;IACV,eAAY;IACZ,SAAS;IACT,IAAI,GAAG,SAAS;cAEf;IACK;GAGT,aAAa,qBACZ,oBAAC,OAAD;IACE,WAAU;IACV,eAAY;IACZ,SAAS;cAER;IACK;GAEV,oBAAC,cAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,UAAW,gBAAgB,OAAQ;IACjC;IACrB,qBAAqB,uBAAuB,UAAU;IACtD;GACF,oBAAC,gBAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,UAAU,YAAa,kBAAkB,OAAQ;IACrC;IACrB,qBAAqB,uBAAuB,UAAU;IACtD;GACE;;;AAGV,OAAO,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabsBase.d.ts","names":[],"sources":["../../src/components/Tabs/TabsBase.tsx"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"TabsBase.d.ts","names":[],"sources":["../../src/components/Tabs/TabsBase.tsx"],"mappings":";;;;;;UAKiB,gBAAA;EACf,cAAA;EACA,MAAA;EACA,GAAA;EACA,QAAA;EACA,aAAA,GAAgB,KAAA;EAChB,WAAA;EACA,SAAA,GAAY,SAAA;EACZ,KAAA;AAAA;AAAA,cAGW,WAAA,EAAW,OAAA,CAAA,OAAA,CAAA,gBAAA;AAAA,cAEX,cAAA,GAAc,aAAA,cAAqC,gBAAA;AAAA,UAQ/C,aAAA,SAAsB,IAAA,CAAK,wBAAA;EAC1C,aAAA,IAAiB,KAAA;EACjB,cAAA;EACA,YAAA;EACA,QAAA,EAAU,SAAA;EACV,GAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA,GAAY,SAAA;EACZ,KAAA;AAAA;AAAA,cAGW,QAAA;EAAQ,GAAA;EAAA,cAAA;EAAA,QAAA;EAAA,YAAA;EAAA,GAAA;EAAA,QAAA;EAAA,aAAA;EAAA,WAAA;EAAA,SAAA;EAAA,KAAA,EAAA,eAAA;EAAA,GAAA;AAAA,GAYlB,aAAA;EACD,GAAA,GAAM,GAAA,CAAI,WAAA;AAAA,MACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,UA6CgB,aAAA,SAAsB,IAAA,CAAK,wBAAA;EAC1C,QAAA,GAAW,SAAA;EACX,IAAA;EACA,SAAA,GAAY,SAAA;AAAA;AAAA,cAGD,QAAA;EAAQ,GAAA;EAAA,QAAA;EAAA,SAAA;EAAA,IAAA;EAAA,SAAA;EAAA,GAAA;AAAA,GAOlB,aAAA;EACD,GAAA,GAAM,GAAA,CAAI,WAAA;AAAA,MACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,UA2IgB,gBAAA,SAAyB,wBAAA;EACxC,KAAA;EACA,QAAA;AAAA;AAAA,cAGW,WAAA;EAAW,GAAA;EAAA,SAAA;EAAA,KAAA,EAAA,YAAA;EAAA,OAAA;EAAA,SAAA;EAAA,QAAA,EAAA,eAAA;EAAA,GAAA;AAAA,GAQrB,gBAAA;EACD,GAAA,GAAM,GAAA,CAAI,WAAA;AAAA,MACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,UAsEgB,yBAAA;EACf,QAAA,EAAU,SAAA;EACV,SAAA;AAAA;AAAA,cAGW,oBAAA;EAAoB,GAAA;EAAA,QAAA;EAAA;AAAA,GAI9B,yBAAA;EACD,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,MACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,UAmCgB,gBAAA,SAAyB,wBAAA;EACxC,KAAA;EACA,UAAA;AAAA;AAAA,cAGW,WAAA;EAAW,GAAA;EAAA,SAAA;EAAA,KAAA,EAAA,YAAA;EAAA,UAAA;EAAA,GAAA;AAAA,GAMrB,gBAAA;EACD,GAAA,GAAM,GAAA,CAAI,WAAA;AAAA,MACX,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|