@spear-ai/spectral 1.16.5 → 1.16.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"InputSearch.d.ts","names":[],"sources":["../src/components/InputSearch/InputSearch.tsx"],"mappings":";;;;;;KA0BY,iBAAA,GAAoB,UAAA;AAAA,UAEf,gBAAA,SAAyB,IAAA,CAAK,kBAAA;EAC7C,SAAA;EACA,iBAAA,IAAqB,KAAA,aAAkB,SAAA;EACvC,aAAA;EACA,YAAA;EACA,aAAA,GAAgB,aAAA;EAChB,YAAA;EACA,UAAA;EACA,cAAA;EACA,QAAA,IAAY,KAAA;EACZ,QAAA,IAAY,KAAA;EACZ,aAAA,IAAiB,KAAA;EACjB,OAAA,EAAS,iBAAA;EACT,WAAA;EACA,YAAA,IAAgB,MAAA,EAAQ,iBAAA,KAAsB,SAAA;EAC9C,cAAA;EACA,KAAA,GAAQ,OAAA,CAAQ,cAAA;EAChB,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAajB,SAAA;EACA,iBAAA;EACA,aAAA;EACA,YAAA;EACA,QAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;EACA,EAAA;EACA,UAAA;EACA,KAAA;EACA,cAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA;EACA,aAAA;EACA,OAAA;EACA,WAAA;EACA,GAAA;EACA,YAAA;EACA,QAAA;EACA,cAAA;EACA,KAAA;EACA,KAAA,EAAO,SAAA;EACP,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN;AAAA,GACb,gBAAA;EAAqB,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,IAAiB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"InputSearch.d.ts","names":[],"sources":["../src/components/InputSearch/InputSearch.tsx"],"mappings":";;;;;;KA0BY,iBAAA,GAAoB,UAAA;AAAA,UAEf,gBAAA,SAAyB,IAAA,CAAK,kBAAA;EAC7C,SAAA;EACA,iBAAA,IAAqB,KAAA,aAAkB,SAAA;EACvC,aAAA;EACA,YAAA;EACA,aAAA,GAAgB,aAAA;EAChB,YAAA;EACA,UAAA;EACA,cAAA;EACA,QAAA,IAAY,KAAA;EACZ,QAAA,IAAY,KAAA;EACZ,aAAA,IAAiB,KAAA;EACjB,WAAA;EACA,OAAA,EAAS,iBAAA;EACT,WAAA;EACA,YAAA,IAAgB,MAAA,EAAQ,iBAAA,KAAsB,SAAA;EAC9C,cAAA;EACA,KAAA,GAAQ,OAAA,CAAQ,cAAA;EAChB,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAajB,SAAA;EACA,iBAAA;EACA,aAAA;EACA,YAAA;EACA,QAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;EACA,EAAA;EACA,UAAA;EACA,KAAA;EACA,cAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA;EACA,aAAA;EACA,WAAA;EACA,OAAA;EACA,WAAA;EACA,GAAA;EACA,YAAA;EACA,QAAA;EACA,cAAA;EACA,KAAA;EACA,KAAA,EAAO,SAAA;EACP,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN;AAAA,GACb,gBAAA;EAAqB,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,IAAiB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
@@ -12,11 +12,11 @@ import { useUncontrolledState } from "./hooks/useUncontrolledState.js";
12
12
  import { Label } from "./Label.js";
13
13
  import { useAutoDropdownHorizontalShift } from "./utils/dropdownPositioning.js";
14
14
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
15
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
16
16
  import { createPortal } from "react-dom";
17
17
 
18
18
  //#region src/components/InputSearch/InputSearch.tsx
19
- const defaultCreateOptionLabel = (query) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(PlusIcon, {
19
+ const defaultCreateOptionLabel = (query) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(PlusIcon, {
20
20
  size: 16,
21
21
  className: "shrink-0"
22
22
  }), /* @__PURE__ */ jsxs("span", {
@@ -30,7 +30,7 @@ const defaultCreateOptionLabel = (query) => /* @__PURE__ */ jsxs(Fragment, { chi
30
30
  ]
31
31
  })]
32
32
  })] });
33
- const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel, creatingLabel = "Creating…", defaultValue = "", disabled, dropdownWidth = "trigger", emptyMessage = "No options found", errorMessage, id, isCreating = false, label, labelClassName, messageReserveLines = 1, messageReserveSpace = false, name, onChange, onCreate, onValueChange, options, placeholder = "Search…", ref, renderOption, required, showSearchIcon = true, state = "default", value: valueProp, warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel }) => {
33
+ const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel, creatingLabel = "Creating…", defaultValue = "", disabled, dropdownWidth = "trigger", emptyMessage = "No options found", errorMessage, id, isCreating = false, label, labelClassName, messageReserveLines = 1, messageReserveSpace = false, name, onChange, onCreate, onValueChange, openOnFocus = false, options, placeholder = "Search…", ref, renderOption, required, showSearchIcon = true, state = "default", value: valueProp, warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel }) => {
34
34
  if (!label && !ariaLabel) console.warn("InputSearch: provide either `label` or `aria-label` for an accessible name.");
35
35
  const fieldId = useFormFieldId(id, name);
36
36
  const listboxId = `${fieldId}-listbox`;
@@ -69,7 +69,7 @@ const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel,
69
69
  const showCreateOption = onCreate !== void 0 && trimmedQuery.length > 0 && !exactMatch;
70
70
  const createOptionIndex = showCreateOption ? filteredOptions.length : -1;
71
71
  const totalItems = filteredOptions.length + (showCreateOption ? 1 : 0);
72
- const showDropdown = isFocused && !isDisabled && !isLoading;
72
+ const showDropdown = isFocused && !isDisabled && !isLoading && (openOnFocus || trimmedQuery.length > 0);
73
73
  const showEmptyState = showDropdown && totalItems === 0;
74
74
  const { dropdownShiftStyle, recalculateDropdownPosition, setDropdownElement } = useAutoDropdownHorizontalShift(showDropdown);
75
75
  const updateDropdownPosition = useCallback(() => {
@@ -185,9 +185,8 @@ const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel,
185
185
  blurTimeoutRef.current = null;
186
186
  setIsFocused(false);
187
187
  setHighlightedIndex(-1);
188
- setQuery(selectedOption?.label ?? "");
189
188
  }, 150);
190
- }, [selectedOption]);
189
+ }, []);
191
190
  const handleClear = useCallback(() => {
192
191
  setValue("");
193
192
  setQuery("");
@@ -297,7 +296,7 @@ const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel,
297
296
  id: listboxId,
298
297
  ref: listRef,
299
298
  role: "listbox",
300
- children: showEmptyState ? /* @__PURE__ */ jsx(EmptyState, { message: emptyMessage }) : /* @__PURE__ */ jsxs(Fragment, { children: [filteredOptions.map((option, index) => {
299
+ children: showEmptyState ? /* @__PURE__ */ jsx(EmptyState, { message: emptyMessage }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [filteredOptions.map((option, index) => {
301
300
  const isHighlighted = index === highlightedIndex;
302
301
  const isSelected = option.value === value;
303
302
  return /* @__PURE__ */ jsx("button", {
@@ -1 +1 @@
1
- {"version":3,"file":"InputSearch.js","names":[],"sources":["../src/components/InputSearch/InputSearch.tsx"],"sourcesContent":["import { CloseCircleIcon, ErrorIcon, LoaderIcon, PlusIcon, SearchIcon, WarningIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport {\n EmptyState,\n ErrorMessage,\n WarningMessage,\n getAriaProps,\n getDropdownSurfaceClasses,\n getDropdownWidthStyles,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getInputClasses,\n getOptionClasses,\n useFormFieldId,\n useFormFieldState,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent, type ReactNode, type Ref } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport type InputSearchOption = BaseOption\n\nexport interface InputSearchProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'> {\n className?: string\n createOptionLabel?: (query: string) => ReactNode\n creatingLabel?: string\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: string\n isCreating?: boolean\n labelClassName?: string\n onChange?: (value: string) => void\n onCreate?: (query: string) => void\n onValueChange?: (value: string) => void\n options: InputSearchOption[]\n placeholder?: string\n renderOption?: (option: InputSearchOption) => ReactNode\n showSearchIcon?: boolean\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst defaultCreateOptionLabel = (query: string): ReactNode => (\n <>\n <PlusIcon size={16} className='shrink-0' />\n <span className='truncate'>\n Create <span className='font-semibold'>&ldquo;{query}&rdquo;</span>\n </span>\n </>\n)\n\nexport const InputSearch = ({\n className,\n createOptionLabel = defaultCreateOptionLabel,\n creatingLabel = 'Creating…',\n defaultValue = '',\n disabled,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n id,\n isCreating = false,\n label,\n labelClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onCreate,\n onValueChange,\n options,\n placeholder = 'Search…',\n ref,\n renderOption,\n required,\n showSearchIcon = true,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n}: InputSearchProps & { ref?: Ref<HTMLDivElement> }) => {\n if (process.env.NODE_ENV !== 'production' && !label && !ariaLabel) {\n // eslint-disable-next-line no-console\n console.warn('InputSearch: provide either `label` or `aria-label` for an accessible name.')\n }\n\n const fieldId = useFormFieldId(id, name)\n const listboxId = `${fieldId}-listbox`\n const errorMessageId = getErrorMessageId(fieldId)\n const warningMessageId = `${fieldId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue,\n onChange: (nextValue) => {\n if (onChange) {\n onChange(nextValue)\n } else {\n onValueChange?.(nextValue)\n }\n },\n })\n\n const [query, setQuery] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const [dropdownPosition, setDropdownPosition] = useState<{ top: number; left: number; width: number } | null>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const listRef = useRef<HTMLDivElement>(null)\n const blurTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const triggerRef = useRef<HTMLDivElement>(null)\n\n const selectedOption = useMemo(() => options.find((option) => option.value === value) ?? null, [options, value])\n\n useEffect(() => {\n if (!isFocused) {\n setQuery(selectedOption?.label ?? '')\n }\n }, [selectedOption, isFocused])\n\n const trimmedQuery = query.trim()\n\n const filteredOptions = useMemo(() => {\n if (trimmedQuery.length === 0) return options\n const lower = trimmedQuery.toLowerCase()\n return options.filter((option) => option.label.toLowerCase().includes(lower))\n }, [trimmedQuery, options])\n\n const exactMatch = useMemo(() => options.some((option) => option.label.toLowerCase() === trimmedQuery.toLowerCase()), [options, trimmedQuery])\n\n const showCreateOption = onCreate !== undefined && trimmedQuery.length > 0 && !exactMatch\n const createOptionIndex = showCreateOption ? filteredOptions.length : -1\n const totalItems = filteredOptions.length + (showCreateOption ? 1 : 0)\n const showDropdown = isFocused && !isDisabled && !isLoading\n const showEmptyState = showDropdown && totalItems === 0\n\n const { dropdownShiftStyle, recalculateDropdownPosition, setDropdownElement } = useAutoDropdownHorizontalShift(showDropdown)\n\n const updateDropdownPosition = useCallback(() => {\n const trigger = triggerRef.current\n if (!trigger) return\n const rect = trigger.getBoundingClientRect()\n setDropdownPosition({\n top: rect.bottom + 4,\n left: rect.left,\n width: rect.width,\n })\n recalculateDropdownPosition()\n }, [recalculateDropdownPosition])\n\n useLayoutEffect(() => {\n if (!showDropdown) {\n setDropdownPosition(null)\n return\n }\n updateDropdownPosition()\n const handle = () => updateDropdownPosition()\n window.addEventListener('scroll', handle, true)\n window.addEventListener('resize', handle)\n return () => {\n window.removeEventListener('scroll', handle, true)\n window.removeEventListener('resize', handle)\n }\n }, [showDropdown, updateDropdownPosition])\n\n useLayoutEffect(() => {\n if (!showDropdown) return\n updateDropdownPosition()\n }, [showDropdown, updateDropdownPosition, filteredOptions.length, showCreateOption])\n\n useEffect(() => {\n setHighlightedIndex(-1)\n }, [filteredOptions.length, showCreateOption])\n\n useEffect(() => {\n if (highlightedIndex < 0 || !listRef.current) return\n const element = listRef.current.querySelector<HTMLElement>(`[data-index='${highlightedIndex}']`)\n element?.scrollIntoView({ block: 'nearest' })\n }, [highlightedIndex])\n\n useEffect(\n () => () => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n }\n },\n [],\n )\n\n const commitSelection = useCallback(\n (option: InputSearchOption) => {\n if (option.disabled) return\n setValue(option.value)\n setQuery(option.label)\n setIsFocused(false)\n setHighlightedIndex(-1)\n inputRef.current?.blur()\n },\n [setValue],\n )\n\n const commitCreate = useCallback(() => {\n if (!onCreate || isCreating || trimmedQuery.length === 0) return\n onCreate(trimmedQuery)\n }, [onCreate, isCreating, trimmedQuery])\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n switch (event.key) {\n case 'ArrowDown': {\n if (totalItems === 0) return\n event.preventDefault()\n setHighlightedIndex((prev) => (prev < totalItems - 1 ? prev + 1 : prev))\n break\n }\n case 'ArrowUp': {\n if (totalItems === 0) return\n event.preventDefault()\n setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : 0))\n break\n }\n case 'Enter': {\n if (totalItems === 0) return\n event.preventDefault()\n if (highlightedIndex >= 0 && highlightedIndex < filteredOptions.length) {\n const option = filteredOptions[highlightedIndex]\n if (option) commitSelection(option)\n } else if (highlightedIndex === createOptionIndex && !isCreating) {\n commitCreate()\n }\n break\n }\n case 'Escape': {\n event.preventDefault()\n setIsFocused(false)\n setHighlightedIndex(-1)\n if (selectedOption) setQuery(selectedOption.label)\n inputRef.current?.blur()\n break\n }\n default:\n break\n }\n },\n [totalItems, filteredOptions, highlightedIndex, createOptionIndex, commitSelection, commitCreate, isCreating, selectedOption],\n )\n\n const handleFocus = useCallback(() => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n blurTimeoutRef.current = null\n }\n setIsFocused(true)\n setQuery('')\n }, [])\n\n const handleBlur = useCallback(() => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n }\n blurTimeoutRef.current = setTimeout(() => {\n blurTimeoutRef.current = null\n setIsFocused(false)\n setHighlightedIndex(-1)\n setQuery(selectedOption?.label ?? '')\n }, 150)\n }, [selectedOption])\n\n const handleClear = useCallback(() => {\n setValue('')\n setQuery('')\n inputRef.current?.focus()\n }, [setValue])\n\n const showClearButton = !isLoading && !isDisabled && (value.length > 0 || (isFocused && query.length > 0))\n\n const { dropdownWidthMode, dropdownWidthStyle } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: '100%',\n })\n\n const inputClasses = cn(getInputClasses(state, className), 'pe-12', showSearchIcon && 'ps-11', showClearButton && 'pe-10', state === 'loading' && 'cursor-wait')\n\n return (\n <div className='flex w-full flex-col gap-1.5' data-testid='spectral-input-search-container' ref={ref}>\n {label && (\n <Label className={cn('mb-2 block', labelClassName, isDisabled && 'cursor-not-allowed text-input-text--disabled')} data-testid='spectral-input-search-label' htmlFor={fieldId}>\n {label}\n </Label>\n )}\n\n <div className='relative' data-testid='spectral-input-search-wrapper' ref={triggerRef}>\n <div className='relative'>\n {showSearchIcon && (\n <span aria-hidden='true' className='left-4 text-input-icon absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-icon'>\n <SearchIcon size={20} />\n </span>\n )}\n\n <input\n aria-activedescendant={highlightedIndex >= 0 ? `${fieldId}-option-${highlightedIndex}` : undefined}\n aria-autocomplete='list'\n aria-controls={listboxId}\n aria-expanded={showDropdown}\n // oxlint-disable-next-line jsx-a11y/role-supports-aria-props -- Valid per WAI-ARIA 1.2 Combobox pattern\n aria-haspopup='listbox'\n aria-label={ariaLabel ?? label}\n autoComplete='off'\n className={inputClasses}\n data-state={state}\n data-testid='spectral-input-search'\n disabled={isDisabled || isLoading}\n id={fieldId}\n name={name}\n onBlur={handleBlur}\n onChange={(event) => {\n setQuery(event.target.value)\n if (!isFocused) setIsFocused(true)\n }}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n ref={inputRef}\n required={required}\n role='combobox'\n style={getFormFieldCSSProperties() as CSSProperties}\n type='text'\n value={query}\n {...ariaProps}\n />\n\n {showClearButton ? (\n <button\n aria-label={`Clear ${label ?? 'search'}`}\n className='right-4 text-input-icon hover:text-input-icon--hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus rounded-sm absolute top-1/2 -translate-y-1/2 cursor-pointer'\n data-testid='spectral-input-search-clear-button'\n onClick={handleClear}\n // Prevent input blur from firing before click resolves\n onMouseDown={(event) => event.preventDefault()}\n type='button'\n >\n <CloseCircleIcon size={20} />\n </button>\n ) : state === 'loading' ? (\n <div className='right-4 text-input-icon absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-loading-icon'>\n <LoaderIcon className='motion-safe:animate-spin' size={20} />\n </div>\n ) : state === 'error' ? (\n <div className='right-4 text-danger-400 absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-error-icon'>\n <ErrorIcon size={20} />\n </div>\n ) : state === 'warning' ? (\n <div className='right-4 text-warning-400 absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-warning-icon'>\n <WarningIcon size={20} />\n </div>\n ) : null}\n </div>\n\n </div>\n\n {showDropdown && dropdownPosition && typeof document !== 'undefined'\n ? createPortal(\n <div\n className={cn('origin-top p-1 z-50 fixed', getDropdownSurfaceClasses(), 'max-h-72 overflow-hidden', 'motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95 motion-safe:slide-in-from-top-2')}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-input-search-content'\n ref={setDropdownElement}\n style={{\n top: `${dropdownPosition.top}px`,\n left: `${dropdownPosition.left}px`,\n ...(dropdownWidthMode === 'trigger' ? { width: `${dropdownPosition.width}px` } : (dropdownWidthStyle as CSSProperties)),\n ...dropdownShiftStyle,\n }}\n >\n <div\n className='max-h-[17.5rem] overflow-y-auto'\n id={listboxId}\n ref={listRef}\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- WAI-ARIA combobox pattern requires role='listbox' on the popup\n role='listbox'\n >\n {showEmptyState ? (\n <EmptyState message={emptyMessage} />\n ) : (\n <>\n {filteredOptions.map((option, index) => {\n const isHighlighted = index === highlightedIndex\n const isSelected = option.value === value\n return (\n <button\n aria-selected={isSelected}\n className={cn(getOptionClasses(!!option.disabled, isHighlighted, isSelected), 'text-left')}\n data-highlighted={isHighlighted ? '' : undefined}\n data-index={index}\n data-testid='spectral-input-search-item'\n disabled={option.disabled}\n id={`${fieldId}-option-${index}`}\n key={option.value}\n onMouseDown={(event) => {\n event.preventDefault()\n commitSelection(option)\n }}\n onMouseEnter={() => setHighlightedIndex(index)}\n role='option'\n tabIndex={-1}\n type='button'\n >\n <span className='min-w-0 flex-1 truncate'>{renderOption ? renderOption(option) : option.label}</span>\n </button>\n )\n })}\n\n {showCreateOption && (\n <button\n aria-selected={createOptionIndex === highlightedIndex}\n className={cn(getOptionClasses(isCreating, createOptionIndex === highlightedIndex, false), 'gap-2 text-left text-accent font-medium')}\n data-highlighted={createOptionIndex === highlightedIndex ? '' : undefined}\n data-index={createOptionIndex}\n data-testid='spectral-input-search-create-option'\n disabled={isCreating}\n id={`${fieldId}-option-${createOptionIndex}`}\n onMouseDown={(event) => {\n event.preventDefault()\n commitCreate()\n }}\n onMouseEnter={() => setHighlightedIndex(createOptionIndex)}\n role='option'\n tabIndex={-1}\n type='button'\n >\n {isCreating ? (\n <span className='gap-2 flex items-center'>\n <LoaderIcon className='shrink-0 motion-safe:animate-spin' size={16} />\n <span>{creatingLabel}</span>\n </span>\n ) : (\n <span className='gap-2 flex items-center min-w-0'>{createOptionLabel(trimmedQuery)}</span>\n )}\n </button>\n )}\n </>\n )}\n </div>\n </div>,\n document.body,\n )\n : null}\n\n <ErrorMessage\n dataTestId='spectral-input-search-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-search-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}\nInputSearch.displayName = 'InputSearch'\n"],"mappings":"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"}
1
+ {"version":3,"file":"InputSearch.js","names":[],"sources":["../src/components/InputSearch/InputSearch.tsx"],"sourcesContent":["import { CloseCircleIcon, ErrorIcon, LoaderIcon, PlusIcon, SearchIcon, WarningIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport {\n EmptyState,\n ErrorMessage,\n WarningMessage,\n getAriaProps,\n getDropdownSurfaceClasses,\n getDropdownWidthStyles,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getInputClasses,\n getOptionClasses,\n useFormFieldId,\n useFormFieldState,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent, type ReactNode, type Ref } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport type InputSearchOption = BaseOption\n\nexport interface InputSearchProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'> {\n className?: string\n createOptionLabel?: (query: string) => ReactNode\n creatingLabel?: string\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: string\n isCreating?: boolean\n labelClassName?: string\n onChange?: (value: string) => void\n onCreate?: (query: string) => void\n onValueChange?: (value: string) => void\n openOnFocus?: boolean\n options: InputSearchOption[]\n placeholder?: string\n renderOption?: (option: InputSearchOption) => ReactNode\n showSearchIcon?: boolean\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst defaultCreateOptionLabel = (query: string): ReactNode => (\n <>\n <PlusIcon size={16} className='shrink-0' />\n <span className='truncate'>\n Create <span className='font-semibold'>&ldquo;{query}&rdquo;</span>\n </span>\n </>\n)\n\nexport const InputSearch = ({\n className,\n createOptionLabel = defaultCreateOptionLabel,\n creatingLabel = 'Creating…',\n defaultValue = '',\n disabled,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n id,\n isCreating = false,\n label,\n labelClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onCreate,\n onValueChange,\n openOnFocus = false,\n options,\n placeholder = 'Search…',\n ref,\n renderOption,\n required,\n showSearchIcon = true,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n}: InputSearchProps & { ref?: Ref<HTMLDivElement> }) => {\n if (process.env.NODE_ENV !== 'production' && !label && !ariaLabel) {\n // eslint-disable-next-line no-console\n console.warn('InputSearch: provide either `label` or `aria-label` for an accessible name.')\n }\n\n const fieldId = useFormFieldId(id, name)\n const listboxId = `${fieldId}-listbox`\n const errorMessageId = getErrorMessageId(fieldId)\n const warningMessageId = `${fieldId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue,\n onChange: (nextValue) => {\n if (onChange) {\n onChange(nextValue)\n } else {\n onValueChange?.(nextValue)\n }\n },\n })\n\n const [query, setQuery] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const [dropdownPosition, setDropdownPosition] = useState<{ top: number; left: number; width: number } | null>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const listRef = useRef<HTMLDivElement>(null)\n const blurTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const triggerRef = useRef<HTMLDivElement>(null)\n\n const selectedOption = useMemo(() => options.find((option) => option.value === value) ?? null, [options, value])\n\n useEffect(() => {\n if (!isFocused) {\n setQuery(selectedOption?.label ?? '')\n }\n }, [selectedOption, isFocused])\n\n const trimmedQuery = query.trim()\n\n const filteredOptions = useMemo(() => {\n if (trimmedQuery.length === 0) return options\n const lower = trimmedQuery.toLowerCase()\n return options.filter((option) => option.label.toLowerCase().includes(lower))\n }, [trimmedQuery, options])\n\n const exactMatch = useMemo(() => options.some((option) => option.label.toLowerCase() === trimmedQuery.toLowerCase()), [options, trimmedQuery])\n\n const showCreateOption = onCreate !== undefined && trimmedQuery.length > 0 && !exactMatch\n const createOptionIndex = showCreateOption ? filteredOptions.length : -1\n const totalItems = filteredOptions.length + (showCreateOption ? 1 : 0)\n const showDropdown = isFocused && !isDisabled && !isLoading && (openOnFocus || trimmedQuery.length > 0)\n const showEmptyState = showDropdown && totalItems === 0\n\n const { dropdownShiftStyle, recalculateDropdownPosition, setDropdownElement } = useAutoDropdownHorizontalShift(showDropdown)\n\n const updateDropdownPosition = useCallback(() => {\n const trigger = triggerRef.current\n if (!trigger) return\n const rect = trigger.getBoundingClientRect()\n setDropdownPosition({\n top: rect.bottom + 4,\n left: rect.left,\n width: rect.width,\n })\n recalculateDropdownPosition()\n }, [recalculateDropdownPosition])\n\n useLayoutEffect(() => {\n if (!showDropdown) {\n setDropdownPosition(null)\n return\n }\n updateDropdownPosition()\n const handle = () => updateDropdownPosition()\n window.addEventListener('scroll', handle, true)\n window.addEventListener('resize', handle)\n return () => {\n window.removeEventListener('scroll', handle, true)\n window.removeEventListener('resize', handle)\n }\n }, [showDropdown, updateDropdownPosition])\n\n useLayoutEffect(() => {\n if (!showDropdown) return\n updateDropdownPosition()\n }, [showDropdown, updateDropdownPosition, filteredOptions.length, showCreateOption])\n\n useEffect(() => {\n setHighlightedIndex(-1)\n }, [filteredOptions.length, showCreateOption])\n\n useEffect(() => {\n if (highlightedIndex < 0 || !listRef.current) return\n const element = listRef.current.querySelector<HTMLElement>(`[data-index='${highlightedIndex}']`)\n element?.scrollIntoView({ block: 'nearest' })\n }, [highlightedIndex])\n\n useEffect(\n () => () => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n }\n },\n [],\n )\n\n const commitSelection = useCallback(\n (option: InputSearchOption) => {\n if (option.disabled) return\n setValue(option.value)\n setQuery(option.label)\n setIsFocused(false)\n setHighlightedIndex(-1)\n inputRef.current?.blur()\n },\n [setValue],\n )\n\n const commitCreate = useCallback(() => {\n if (!onCreate || isCreating || trimmedQuery.length === 0) return\n onCreate(trimmedQuery)\n }, [onCreate, isCreating, trimmedQuery])\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n switch (event.key) {\n case 'ArrowDown': {\n if (totalItems === 0) return\n event.preventDefault()\n setHighlightedIndex((prev) => (prev < totalItems - 1 ? prev + 1 : prev))\n break\n }\n case 'ArrowUp': {\n if (totalItems === 0) return\n event.preventDefault()\n setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : 0))\n break\n }\n case 'Enter': {\n if (totalItems === 0) return\n event.preventDefault()\n if (highlightedIndex >= 0 && highlightedIndex < filteredOptions.length) {\n const option = filteredOptions[highlightedIndex]\n if (option) commitSelection(option)\n } else if (highlightedIndex === createOptionIndex && !isCreating) {\n commitCreate()\n }\n break\n }\n case 'Escape': {\n event.preventDefault()\n setIsFocused(false)\n setHighlightedIndex(-1)\n if (selectedOption) setQuery(selectedOption.label)\n inputRef.current?.blur()\n break\n }\n default:\n break\n }\n },\n [totalItems, filteredOptions, highlightedIndex, createOptionIndex, commitSelection, commitCreate, isCreating, selectedOption],\n )\n\n const handleFocus = useCallback(() => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n blurTimeoutRef.current = null\n }\n setIsFocused(true)\n setQuery('')\n }, [])\n\n const handleBlur = useCallback(() => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n }\n blurTimeoutRef.current = setTimeout(() => {\n blurTimeoutRef.current = null\n // Don't write to `query` here — the useEffect tied to selectedOption + isFocused\n // is the single source of truth for the visible query when the field isn't focused.\n // Setting it from this stale closure causes off-by-one display after selection.\n setIsFocused(false)\n setHighlightedIndex(-1)\n }, 150)\n }, [])\n\n const handleClear = useCallback(() => {\n setValue('')\n setQuery('')\n inputRef.current?.focus()\n }, [setValue])\n\n const showClearButton = !isLoading && !isDisabled && (value.length > 0 || (isFocused && query.length > 0))\n\n const { dropdownWidthMode, dropdownWidthStyle } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: '100%',\n })\n\n const inputClasses = cn(getInputClasses(state, className), 'pe-12', showSearchIcon && 'ps-11', showClearButton && 'pe-10', state === 'loading' && 'cursor-wait')\n\n return (\n <div className='flex w-full flex-col gap-1.5' data-testid='spectral-input-search-container' ref={ref}>\n {label && (\n <Label className={cn('mb-2 block', labelClassName, isDisabled && 'cursor-not-allowed text-input-text--disabled')} data-testid='spectral-input-search-label' htmlFor={fieldId}>\n {label}\n </Label>\n )}\n\n <div className='relative' data-testid='spectral-input-search-wrapper' ref={triggerRef}>\n <div className='relative'>\n {showSearchIcon && (\n <span aria-hidden='true' className='left-4 text-input-icon absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-icon'>\n <SearchIcon size={20} />\n </span>\n )}\n\n <input\n aria-activedescendant={highlightedIndex >= 0 ? `${fieldId}-option-${highlightedIndex}` : undefined}\n aria-autocomplete='list'\n aria-controls={listboxId}\n aria-expanded={showDropdown}\n // oxlint-disable-next-line jsx-a11y/role-supports-aria-props -- Valid per WAI-ARIA 1.2 Combobox pattern\n aria-haspopup='listbox'\n aria-label={ariaLabel ?? label}\n autoComplete='off'\n className={inputClasses}\n data-state={state}\n data-testid='spectral-input-search'\n disabled={isDisabled || isLoading}\n id={fieldId}\n name={name}\n onBlur={handleBlur}\n onChange={(event) => {\n setQuery(event.target.value)\n if (!isFocused) setIsFocused(true)\n }}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n ref={inputRef}\n required={required}\n role='combobox'\n style={getFormFieldCSSProperties() as CSSProperties}\n type='text'\n value={query}\n {...ariaProps}\n />\n\n {showClearButton ? (\n <button\n aria-label={`Clear ${label ?? 'search'}`}\n className='right-4 text-input-icon hover:text-input-icon--hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus rounded-sm absolute top-1/2 -translate-y-1/2 cursor-pointer'\n data-testid='spectral-input-search-clear-button'\n onClick={handleClear}\n // Prevent input blur from firing before click resolves\n onMouseDown={(event) => event.preventDefault()}\n type='button'\n >\n <CloseCircleIcon size={20} />\n </button>\n ) : state === 'loading' ? (\n <div className='right-4 text-input-icon absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-loading-icon'>\n <LoaderIcon className='motion-safe:animate-spin' size={20} />\n </div>\n ) : state === 'error' ? (\n <div className='right-4 text-danger-400 absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-error-icon'>\n <ErrorIcon size={20} />\n </div>\n ) : state === 'warning' ? (\n <div className='right-4 text-warning-400 absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-warning-icon'>\n <WarningIcon size={20} />\n </div>\n ) : null}\n </div>\n\n </div>\n\n {showDropdown && dropdownPosition && typeof document !== 'undefined'\n ? createPortal(\n <div\n className={cn('origin-top p-1 z-50 fixed', getDropdownSurfaceClasses(), 'max-h-72 overflow-hidden', 'motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95 motion-safe:slide-in-from-top-2')}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-input-search-content'\n ref={setDropdownElement}\n style={{\n top: `${dropdownPosition.top}px`,\n left: `${dropdownPosition.left}px`,\n ...(dropdownWidthMode === 'trigger' ? { width: `${dropdownPosition.width}px` } : (dropdownWidthStyle as CSSProperties)),\n ...dropdownShiftStyle,\n }}\n >\n <div\n className='max-h-[17.5rem] overflow-y-auto'\n id={listboxId}\n ref={listRef}\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- WAI-ARIA combobox pattern requires role='listbox' on the popup\n role='listbox'\n >\n {showEmptyState ? (\n <EmptyState message={emptyMessage} />\n ) : (\n <>\n {filteredOptions.map((option, index) => {\n const isHighlighted = index === highlightedIndex\n const isSelected = option.value === value\n return (\n <button\n aria-selected={isSelected}\n className={cn(getOptionClasses(!!option.disabled, isHighlighted, isSelected), 'text-left')}\n data-highlighted={isHighlighted ? '' : undefined}\n data-index={index}\n data-testid='spectral-input-search-item'\n disabled={option.disabled}\n id={`${fieldId}-option-${index}`}\n key={option.value}\n onMouseDown={(event) => {\n event.preventDefault()\n commitSelection(option)\n }}\n onMouseEnter={() => setHighlightedIndex(index)}\n role='option'\n tabIndex={-1}\n type='button'\n >\n <span className='min-w-0 flex-1 truncate'>{renderOption ? renderOption(option) : option.label}</span>\n </button>\n )\n })}\n\n {showCreateOption && (\n <button\n aria-selected={createOptionIndex === highlightedIndex}\n className={cn(getOptionClasses(isCreating, createOptionIndex === highlightedIndex, false), 'gap-2 text-left text-accent font-medium')}\n data-highlighted={createOptionIndex === highlightedIndex ? '' : undefined}\n data-index={createOptionIndex}\n data-testid='spectral-input-search-create-option'\n disabled={isCreating}\n id={`${fieldId}-option-${createOptionIndex}`}\n onMouseDown={(event) => {\n event.preventDefault()\n commitCreate()\n }}\n onMouseEnter={() => setHighlightedIndex(createOptionIndex)}\n role='option'\n tabIndex={-1}\n type='button'\n >\n {isCreating ? (\n <span className='gap-2 flex items-center'>\n <LoaderIcon className='shrink-0 motion-safe:animate-spin' size={16} />\n <span>{creatingLabel}</span>\n </span>\n ) : (\n <span className='gap-2 flex items-center min-w-0'>{createOptionLabel(trimmedQuery)}</span>\n )}\n </button>\n )}\n </>\n )}\n </div>\n </div>,\n document.body,\n )\n : null}\n\n <ErrorMessage\n dataTestId='spectral-input-search-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-search-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}\nInputSearch.displayName = 'InputSearch'\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkDA,MAAM,4BAA4B,UAChC,8CACE,oBAAC,UAAD;CAAU,MAAM;CAAI,WAAU;CAAa,GAC3C,qBAAC,QAAD;CAAM,WAAU;WAAhB,CAA2B,WAClB,qBAAC,QAAD;EAAM,WAAU;YAAhB;GAAgC;GAAQ;GAAM;GAAc;IAC9D;GACN;AAGL,MAAa,eAAe,EAC1B,WACA,oBAAoB,0BACpB,gBAAgB,aAChB,eAAe,IACf,UACA,gBAAgB,WAChB,eAAe,oBACf,cACA,IACA,aAAa,OACb,OACA,gBACA,sBAAsB,GACtB,sBAAsB,OACtB,MACA,UACA,UACA,eACA,cAAc,OACd,SACA,cAAc,WACd,KACA,cACA,UACA,iBAAiB,MACjB,QAAQ,WACR,OAAO,WACP,gBACA,oBAAoB,iBACpB,cAAc,gBACwC;AACtD,KAA6C,CAAC,SAAS,CAAC,UAEtD,SAAQ,KAAK,8EAA8E;CAG7F,MAAM,UAAU,eAAe,IAAI,KAAK;CACxC,MAAM,YAAY,GAAG,QAAQ;CAC7B,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,mBAAmB,GAAG,QAAQ;CACpC,MAAM,YAAY,UAAU,UAAU,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;CAClH,MAAM,EAAE,YAAY,WAAW,cAAc,kBAAkB,UAAU,MAAM;CAC/E,MAAM,YAAY,aAAa,OAAO,iBAAiB,UAAU,UAAU;CAE3E,MAAM,CAAC,OAAO,YAAY,qBAA6B;EACrD,OAAO;EACP;EACA,WAAW,cAAc;AACvB,OAAI,SACF,UAAS,UAAU;OAEnB,iBAAgB,UAAU;;EAG/B,CAAC;CAEF,MAAM,CAAC,OAAO,YAAY,SAAS,GAAG;CACtC,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,GAAG;CAC5D,MAAM,CAAC,kBAAkB,uBAAuB,SAA8D,KAAK;CACnH,MAAM,WAAW,OAAyB,KAAK;CAC/C,MAAM,UAAU,OAAuB,KAAK;CAC5C,MAAM,iBAAiB,OAA6C,KAAK;CACzE,MAAM,aAAa,OAAuB,KAAK;CAE/C,MAAM,iBAAiB,cAAc,QAAQ,MAAM,WAAW,OAAO,UAAU,MAAM,IAAI,MAAM,CAAC,SAAS,MAAM,CAAC;AAEhH,iBAAgB;AACd,MAAI,CAAC,UACH,UAAS,gBAAgB,SAAS,GAAG;IAEtC,CAAC,gBAAgB,UAAU,CAAC;CAE/B,MAAM,eAAe,MAAM,MAAM;CAEjC,MAAM,kBAAkB,cAAc;AACpC,MAAI,aAAa,WAAW,EAAG,QAAO;EACtC,MAAM,QAAQ,aAAa,aAAa;AACxC,SAAO,QAAQ,QAAQ,WAAW,OAAO,MAAM,aAAa,CAAC,SAAS,MAAM,CAAC;IAC5E,CAAC,cAAc,QAAQ,CAAC;CAE3B,MAAM,aAAa,cAAc,QAAQ,MAAM,WAAW,OAAO,MAAM,aAAa,KAAK,aAAa,aAAa,CAAC,EAAE,CAAC,SAAS,aAAa,CAAC;CAE9I,MAAM,mBAAmB,aAAa,UAAa,aAAa,SAAS,KAAK,CAAC;CAC/E,MAAM,oBAAoB,mBAAmB,gBAAgB,SAAS;CACtE,MAAM,aAAa,gBAAgB,UAAU,mBAAmB,IAAI;CACpE,MAAM,eAAe,aAAa,CAAC,cAAc,CAAC,cAAc,eAAe,aAAa,SAAS;CACrG,MAAM,iBAAiB,gBAAgB,eAAe;CAEtD,MAAM,EAAE,oBAAoB,6BAA6B,uBAAuB,+BAA+B,aAAa;CAE5H,MAAM,yBAAyB,kBAAkB;EAC/C,MAAM,UAAU,WAAW;AAC3B,MAAI,CAAC,QAAS;EACd,MAAM,OAAO,QAAQ,uBAAuB;AAC5C,sBAAoB;GAClB,KAAK,KAAK,SAAS;GACnB,MAAM,KAAK;GACX,OAAO,KAAK;GACb,CAAC;AACF,+BAA6B;IAC5B,CAAC,4BAA4B,CAAC;AAEjC,uBAAsB;AACpB,MAAI,CAAC,cAAc;AACjB,uBAAoB,KAAK;AACzB;;AAEF,0BAAwB;EACxB,MAAM,eAAe,wBAAwB;AAC7C,SAAO,iBAAiB,UAAU,QAAQ,KAAK;AAC/C,SAAO,iBAAiB,UAAU,OAAO;AACzC,eAAa;AACX,UAAO,oBAAoB,UAAU,QAAQ,KAAK;AAClD,UAAO,oBAAoB,UAAU,OAAO;;IAE7C,CAAC,cAAc,uBAAuB,CAAC;AAE1C,uBAAsB;AACpB,MAAI,CAAC,aAAc;AACnB,0BAAwB;IACvB;EAAC;EAAc;EAAwB,gBAAgB;EAAQ;EAAiB,CAAC;AAEpF,iBAAgB;AACd,sBAAoB,GAAG;IACtB,CAAC,gBAAgB,QAAQ,iBAAiB,CAAC;AAE9C,iBAAgB;AACd,MAAI,mBAAmB,KAAK,CAAC,QAAQ,QAAS;AAE9C,EADgB,QAAQ,QAAQ,cAA2B,gBAAgB,iBAAiB,IACrF,EAAE,eAAe,EAAE,OAAO,WAAW,CAAC;IAC5C,CAAC,iBAAiB,CAAC;AAEtB,uBACc;AACV,MAAI,eAAe,YAAY,KAC7B,cAAa,eAAe,QAAQ;IAGxC,EAAE,CACH;CAED,MAAM,kBAAkB,aACrB,WAA8B;AAC7B,MAAI,OAAO,SAAU;AACrB,WAAS,OAAO,MAAM;AACtB,WAAS,OAAO,MAAM;AACtB,eAAa,MAAM;AACnB,sBAAoB,GAAG;AACvB,WAAS,SAAS,MAAM;IAE1B,CAAC,SAAS,CACX;CAED,MAAM,eAAe,kBAAkB;AACrC,MAAI,CAAC,YAAY,cAAc,aAAa,WAAW,EAAG;AAC1D,WAAS,aAAa;IACrB;EAAC;EAAU;EAAY;EAAa,CAAC;CAExC,MAAM,gBAAgB,aACnB,UAA2C;AAC1C,UAAQ,MAAM,KAAd;GACE,KAAK;AACH,QAAI,eAAe,EAAG;AACtB,UAAM,gBAAgB;AACtB,yBAAqB,SAAU,OAAO,aAAa,IAAI,OAAO,IAAI,KAAM;AACxE;GAEF,KAAK;AACH,QAAI,eAAe,EAAG;AACtB,UAAM,gBAAgB;AACtB,yBAAqB,SAAU,OAAO,IAAI,OAAO,IAAI,EAAG;AACxD;GAEF,KAAK;AACH,QAAI,eAAe,EAAG;AACtB,UAAM,gBAAgB;AACtB,QAAI,oBAAoB,KAAK,mBAAmB,gBAAgB,QAAQ;KACtE,MAAM,SAAS,gBAAgB;AAC/B,SAAI,OAAQ,iBAAgB,OAAO;eAC1B,qBAAqB,qBAAqB,CAAC,WACpD,eAAc;AAEhB;GAEF,KAAK;AACH,UAAM,gBAAgB;AACtB,iBAAa,MAAM;AACnB,wBAAoB,GAAG;AACvB,QAAI,eAAgB,UAAS,eAAe,MAAM;AAClD,aAAS,SAAS,MAAM;AACxB;GAEF,QACE;;IAGN;EAAC;EAAY;EAAiB;EAAkB;EAAmB;EAAiB;EAAc;EAAY;EAAe,CAC9H;CAED,MAAM,cAAc,kBAAkB;AACpC,MAAI,eAAe,YAAY,MAAM;AACnC,gBAAa,eAAe,QAAQ;AACpC,kBAAe,UAAU;;AAE3B,eAAa,KAAK;AAClB,WAAS,GAAG;IACX,EAAE,CAAC;CAEN,MAAM,aAAa,kBAAkB;AACnC,MAAI,eAAe,YAAY,KAC7B,cAAa,eAAe,QAAQ;AAEtC,iBAAe,UAAU,iBAAiB;AACxC,kBAAe,UAAU;AAIzB,gBAAa,MAAM;AACnB,uBAAoB,GAAG;KACtB,IAAI;IACN,EAAE,CAAC;CAEN,MAAM,cAAc,kBAAkB;AACpC,WAAS,GAAG;AACZ,WAAS,GAAG;AACZ,WAAS,SAAS,OAAO;IACxB,CAAC,SAAS,CAAC;CAEd,MAAM,kBAAkB,CAAC,aAAa,CAAC,eAAe,MAAM,SAAS,KAAM,aAAa,MAAM,SAAS;CAEvG,MAAM,EAAE,mBAAmB,uBAAuB,uBAAuB;EACvE;EACA,cAAc;EACf,CAAC;CAEF,MAAM,eAAe,GAAG,gBAAgB,OAAO,UAAU,EAAE,SAAS,kBAAkB,SAAS,mBAAmB,SAAS,UAAU,aAAa,cAAc;AAEhK,QACE,qBAAC,OAAD;EAAK,WAAU;EAA+B,eAAY;EAAuC;YAAjG;GACG,SACC,oBAAC,OAAD;IAAO,WAAW,GAAG,cAAc,gBAAgB,cAAc,+CAA+C;IAAE,eAAY;IAA8B,SAAS;cAClK;IACK;GAGV,oBAAC,OAAD;IAAK,WAAU;IAAW,eAAY;IAAgC,KAAK;cACzE,qBAAC,OAAD;KAAK,WAAU;eAAf;MACG,kBACC,oBAAC,QAAD;OAAM,eAAY;OAAO,WAAU;OAA2D,eAAY;iBACxG,oBAAC,YAAD,EAAY,MAAM,IAAM;OACnB;MAGT,oBAAC,SAAD;OACE,yBAAuB,oBAAoB,IAAI,GAAG,QAAQ,UAAU,qBAAqB;OACzF,qBAAkB;OAClB,iBAAe;OACf,iBAAe;OAEf,iBAAc;OACd,cAAY,aAAa;OACzB,cAAa;OACb,WAAW;OACX,cAAY;OACZ,eAAY;OACZ,UAAU,cAAc;OACxB,IAAI;OACE;OACN,QAAQ;OACR,WAAW,UAAU;AACnB,iBAAS,MAAM,OAAO,MAAM;AAC5B,YAAI,CAAC,UAAW,cAAa,KAAK;;OAEpC,SAAS;OACT,WAAW;OACE;OACb,KAAK;OACK;OACV,MAAK;OACL,OAAO,2BAA2B;OAClC,MAAK;OACL,OAAO;OACP,GAAI;OACJ;MAED,kBACC,oBAAC,UAAD;OACE,cAAY,SAAS,SAAS;OAC9B,WAAU;OACV,eAAY;OACZ,SAAS;OAET,cAAc,UAAU,MAAM,gBAAgB;OAC9C,MAAK;iBAEL,oBAAC,iBAAD,EAAiB,MAAM,IAAM;OACtB,IACP,UAAU,YACZ,oBAAC,OAAD;OAAK,WAAU;OAA4D,eAAY;iBACrF,oBAAC,YAAD;QAAY,WAAU;QAA2B,MAAM;QAAM;OACzD,IACJ,UAAU,UACZ,oBAAC,OAAD;OAAK,WAAU;OAA4D,eAAY;iBACrF,oBAAC,WAAD,EAAW,MAAM,IAAM;OACnB,IACJ,UAAU,YACZ,oBAAC,OAAD;OAAK,WAAU;OAA6D,eAAY;iBACtF,oBAAC,aAAD,EAAa,MAAM,IAAM;OACrB,IACJ;MACA;;IAEF;GAEL,gBAAgB,oBAAoB,OAAO,aAAa,cACrD,aACE,oBAAC,OAAD;IACE,WAAW,GAAG,6BAA6B,2BAA2B,EAAE,4BAA4B,sGAAsG;IAC1M,4BAA0B;IAC1B,6BAA2B,sBAAsB,WAAW,gBAAgB;IAC5E,eAAY;IACZ,KAAK;IACL,OAAO;KACL,KAAK,GAAG,iBAAiB,IAAI;KAC7B,MAAM,GAAG,iBAAiB,KAAK;KAC/B,GAAI,sBAAsB,YAAY,EAAE,OAAO,GAAG,iBAAiB,MAAM,KAAK,GAAI;KAClF,GAAG;KACJ;cAED,oBAAC,OAAD;KACE,WAAU;KACV,IAAI;KACJ,KAAK;KAEL,MAAK;eAEJ,iBACC,oBAAC,YAAD,EAAY,SAAS,cAAgB,IAErC,8CACG,gBAAgB,KAAK,QAAQ,UAAU;MACxC,MAAM,gBAAgB,UAAU;MAChC,MAAM,aAAa,OAAO,UAAU;AACpC,aACE,oBAAC,UAAD;OACE,iBAAe;OACf,WAAW,GAAG,iBAAiB,CAAC,CAAC,OAAO,UAAU,eAAe,WAAW,EAAE,YAAY;OAC1F,oBAAkB,gBAAgB,KAAK;OACvC,cAAY;OACZ,eAAY;OACZ,UAAU,OAAO;OACjB,IAAI,GAAG,QAAQ,UAAU;OAEzB,cAAc,UAAU;AACtB,cAAM,gBAAgB;AACtB,wBAAgB,OAAO;;OAEzB,oBAAoB,oBAAoB,MAAM;OAC9C,MAAK;OACL,UAAU;OACV,MAAK;iBAEL,oBAAC,QAAD;QAAM,WAAU;kBAA2B,eAAe,aAAa,OAAO,GAAG,OAAO;QAAa;OAC9F,EAXF,OAAO,MAWL;OAEX,EAEC,oBACC,oBAAC,UAAD;MACE,iBAAe,sBAAsB;MACrC,WAAW,GAAG,iBAAiB,YAAY,sBAAsB,kBAAkB,MAAM,EAAE,0CAA0C;MACrI,oBAAkB,sBAAsB,mBAAmB,KAAK;MAChE,cAAY;MACZ,eAAY;MACZ,UAAU;MACV,IAAI,GAAG,QAAQ,UAAU;MACzB,cAAc,UAAU;AACtB,aAAM,gBAAgB;AACtB,qBAAc;;MAEhB,oBAAoB,oBAAoB,kBAAkB;MAC1D,MAAK;MACL,UAAU;MACV,MAAK;gBAEJ,aACC,qBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,oBAAC,YAAD;QAAY,WAAU;QAAoC,MAAM;QAAM,GACtE,oBAAC,QAAD,YAAO,eAAqB,EACvB;WAEP,oBAAC,QAAD;OAAM,WAAU;iBAAmC,kBAAkB,aAAa;OAAQ;MAErF,EAEV;KAED;IACF,GACN,SAAS,KACV,GACD;GAEJ,oBAAC,cAAD;IACE,YAAW;IACX,IAAI;IACJ,SAAS,YAAa,gBAAgB,OAAQ;IACzB;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,YAAY,cAAc"}
@@ -10,7 +10,7 @@ import { useUncontrolledState } from "../hooks/useUncontrolledState.js";
10
10
  import { Label } from "../Label.js";
11
11
  import { useAutoDropdownHorizontalShift } from "../utils/dropdownPositioning.js";
12
12
  import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
13
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
14
14
  import * as Popover from "@radix-ui/react-popover";
15
15
 
16
16
  //#region src/components/MultiSelect/MultiSelectBase.tsx
@@ -393,7 +393,7 @@ const MultiSelectBase = ({ className, clearAllLabel = "Clear all", closeOnSelect
393
393
  className: "text-sm",
394
394
  "data-testid": "spectral-multiselect-empty-message",
395
395
  message: emptyMessage
396
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [
396
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
397
397
  showSelectAll && /* @__PURE__ */ jsxs("div", {
398
398
  className: "mb-1",
399
399
  children: [/* @__PURE__ */ jsx("button", {
package/dist/Select.js CHANGED
@@ -9,7 +9,7 @@ import { Label } from "./Label.js";
9
9
  import { useAutoDropdownHorizontalShift } from "./utils/dropdownPositioning.js";
10
10
  import { SelectValue } from "./primitives/select.js";
11
11
  import { useState } from "react";
12
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
13
13
  import * as SelectPrimitive from "@radix-ui/react-select";
14
14
 
15
15
  //#region src/components/Select/Select.tsx
@@ -73,7 +73,7 @@ const Select = (allProps) => {
73
73
  })]
74
74
  }, option.value);
75
75
  };
76
- return /* @__PURE__ */ jsxs(Fragment, { children: [ungrouped.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [ungrouped.map(renderOption), Object.keys(groups).length > 0 && /* @__PURE__ */ jsx(SelectPrimitive.Separator, {
76
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [ungrouped.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [ungrouped.map(renderOption), Object.keys(groups).length > 0 && /* @__PURE__ */ jsx(SelectPrimitive.Separator, {
77
77
  className: "-mx-1 my-1 h-px bg-border-secondary",
78
78
  "data-testid": "spectral-select-separator"
79
79
  })] }), Object.entries(groups).map(([groupName, groupOptions], groupIndex) => /* @__PURE__ */ jsxs(SelectPrimitive.Group, {
@@ -1 +1 @@
1
- {"version":3,"file":"Select.js","names":[],"sources":["../src/components/Select/Select.tsx"],"sourcesContent":["import { CheckmarkIcon, ChevronDownIcon, LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { SelectValue } from '@primitives/select'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport {\n EmptyState,\n ErrorMessage,\n getAriaProps,\n getDropdownWidthStyles,\n getDropdownSurfaceClasses,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getOptionClasses,\n getTriggerClasses,\n groupOptions,\n LoadingState,\n WarningMessage,\n useFormFieldId,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useState, type ComponentPropsWithoutRef, type CSSProperties, type ReactNode, type Ref } from 'react'\n\ntype SelectOption = BaseOption\ntype Align = 'start' | 'center' | 'end'\ntype Side = 'top' | 'bottom' | 'left' | 'right'\n\nexport interface SelectProps extends Omit<ComponentPropsWithoutRef<'button'>, 'value' | 'onChange' | 'aria-disabled' | 'aria-invalid' | 'aria-required' | 'aria-describedby' | 'aria-label'>, Omit<BaseFormFieldProps, 'state'> {\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: ReactNode\n id?: string\n label?: string\n labelClassName?: string\n loadingMessage?: string\n onChange?: (value: string) => void\n onValueChange?: (value: string) => void\n options: SelectOption[]\n placeholder?: string\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport interface SelectExtendedProps extends SelectProps {\n align?: Align\n alignOffset?: number\n avoidCollisions?: boolean\n collisionBoundary?: Element | Element[] | null\n collisionPadding?: number | Partial<Record<Side, number>>\n position?: 'popper' | 'item-aligned'\n side?: Side\n sideOffset?: number\n}\n\nexport const Select = (\n allProps: SelectExtendedProps & {\n ref?: Ref<HTMLButtonElement>\n },\n) => {\n const isControlled = 'value' in allProps\n const {\n align = 'start',\n alignOffset = 0,\n avoidCollisions = true,\n className,\n collisionBoundary,\n collisionPadding = 10,\n defaultValue,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n disabled,\n id,\n label,\n labelClassName,\n loadingMessage = 'Loading…',\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n options,\n placeholder = 'Select an option',\n position = 'popper',\n ref,\n required,\n side = 'bottom',\n sideOffset = 4,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const value = isControlled ? (valueProp ?? '') : valueProp\n const [open, setOpen] = useState(false)\n const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(open)\n const selectId = useFormFieldId(id, name)\n const listboxId = `${selectId}-listbox`\n const errorMessageId = getErrorMessageId(selectId)\n const warningMessageId = `${selectId}-warning`\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const { dropdownWidthMode, dropdownWidthStyle, resolvedDropdownWidth } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--radix-select-trigger-width)',\n })\n const selectContentStyle = {\n '--spectral-select-content-width': resolvedDropdownWidth,\n ...(position === 'item-aligned' ? { width: resolvedDropdownWidth } : {}),\n ...dropdownWidthStyle,\n ...dropdownShiftStyle,\n } as CSSProperties\n const isDisabled = Boolean(disabled)\n const isLoading = state === 'loading'\n const isInvalid = state === 'error'\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n const { groups, ungrouped } = groupOptions(options)\n const handleValueChange = (nextValue: string) => {\n onChange?.(nextValue)\n onValueChange?.(nextValue)\n }\n\n const renderOptions = () => {\n if (isLoading) {\n return <LoadingState data-testid='spectral-select-loading' message={loadingMessage} />\n }\n\n if (options.length === 0) {\n return <EmptyState data-testid='spectral-select-empty' message={emptyMessage} />\n }\n\n const renderOption = (option: SelectOption) => {\n const isSelected = value === option.value\n\n return (\n <SelectPrimitive.Item className={cn(getOptionClasses(!!option.disabled, false, isSelected), 'relative flex w-full cursor-pointer items-center')} data-testid='spectral-select-item' disabled={option.disabled} key={option.value} value={option.value}>\n <SelectPrimitive.ItemText data-testid='spectral-select-item-text' className='block truncate'>\n {option.label}\n </SelectPrimitive.ItemText>\n <SelectPrimitive.ItemIndicator data-testid='spectral-select-item-selected-indicator' asChild>\n <span className='right-2 h-4 w-4 absolute flex items-center justify-center'>\n <CheckmarkIcon size={16} />\n </span>\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n )\n }\n\n return (\n <>\n {ungrouped.length > 0 && (\n <>\n {ungrouped.map(renderOption)}\n {Object.keys(groups).length > 0 && <SelectPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-select-separator' />}\n </>\n )}\n\n {Object.entries(groups).map(([groupName, groupOptions], groupIndex) => (\n <SelectPrimitive.Group key={groupName} data-testid='spectral-select-group'>\n {groupIndex > 0 && <SelectPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-select-group-separator' />}\n <Label className={cn('px-2 py-1.5 text-base font-semibold text-text-primary', labelClassName)} data-testid='spectral-select-group-label'>\n {groupName}\n </Label>\n {groupOptions.map((option: BaseOption) => renderOption(option))}\n </SelectPrimitive.Group>\n ))}\n </>\n )\n }\n\n return (\n <div className='w-full'>\n {label && (\n <Label className={cn('mb-2 block text-text-primary', labelClassName, isDisabled && 'text-text-secondary')} data-testid='spectral-select-label' htmlFor={selectId}>\n {label}\n </Label>\n )}\n <SelectPrimitive.Root data-testid='spectral-select' defaultValue={defaultValue} disabled={isDisabled} name={name} onOpenChange={setOpen} onValueChange={handleValueChange} open={open} required={required} value={value}>\n <SelectPrimitive.Trigger\n aria-controls={listboxId}\n aria-expanded={open}\n aria-label={ariaLabel ?? label}\n asChild\n className={cn(getTriggerClasses(open, state), 'text-input-text data-placeholder:text-input-text-placeholder!', className)}\n data-slot='select-trigger'\n data-state={state}\n data-testid='spectral-select-trigger'\n id={selectId}\n ref={ref}\n style={getFormFieldCSSProperties() as CSSProperties}\n {...ariaProps}\n {...props}\n >\n <button\n className='min-w-0 gap-2 [&>span]:min-w-0 grid w-full cursor-pointer grid-cols-[minmax(0,1fr)_auto] items-center overflow-hidden text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder! [&>span]:block [&>span]:overflow-hidden [&>span]:text-ellipsis [&>span]:whitespace-nowrap [&>span[data-placeholder]]:text-input-text-placeholder!'\n type='button'\n disabled={isDisabled}\n >\n <SelectValue data-testid='spectral-select-value' placeholder={placeholder} />\n <SelectPrimitive.Icon asChild>\n <div className='flex shrink-0 cursor-pointer items-center'>{isLoading ? <LoaderIcon size={20} /> : <ChevronDownIcon className={cn('transition-transform duration-200', open && 'rotate-180')} size={20} />}</div>\n </SelectPrimitive.Icon>\n </button>\n </SelectPrimitive.Trigger>\n\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n align={align}\n alignOffset={alignOffset}\n avoidCollisions={avoidCollisions}\n className={cn(\n 'relative z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=open]:zoom-in-95',\n 'max-h-[min(var(--radix-select-content-available-height),300px)] motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2',\n 'min-w-32 origin-(--radix-select-content-transform-origin) overflow-hidden',\n position === 'popper' && 'data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1',\n )}\n collisionBoundary={collisionBoundary}\n collisionPadding={collisionPadding}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n id={listboxId}\n data-slot='select-content'\n data-testid='spectral-select-content'\n position={position}\n ref={setDropdownElement}\n side={side}\n sideOffset={sideOffset}\n style={selectContentStyle}\n >\n <SelectPrimitive.ScrollUpButton className='py-1 flex cursor-default items-center justify-center' data-testid='spectral-select-scroll-up-button'>\n <ChevronDownIcon aria-hidden='true' className='rotate-180' size={18} />\n </SelectPrimitive.ScrollUpButton>\n\n <SelectPrimitive.Viewport asChild>\n <div\n className={cn(\n 'p-1 overflow-x-hidden overflow-y-auto',\n position === 'popper' && (dropdownWidth === 'trigger' ? 'scroll-my-1 h-(--radix-select-trigger-height) w-(--spectral-select-content-width) min-w-(--spectral-select-content-width)' : 'scroll-my-1 h-(--radix-select-trigger-height)'),\n )}\n data-testid='spectral-select-items'\n >\n {renderOptions()}\n </div>\n </SelectPrimitive.Viewport>\n\n <SelectPrimitive.ScrollDownButton className='py-1 flex cursor-default items-center justify-center' data-testid='spectral-select-scroll-down-button'>\n <ChevronDownIcon aria-hidden='true' size={18} />\n </SelectPrimitive.ScrollDownButton>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n </SelectPrimitive.Root>\n\n <ErrorMessage\n dataTestId='spectral-select-error-message'\n id={errorMessageId}\n message={isInvalid ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-select-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nSelect.displayName = 'Select'\n"],"mappings":"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"}
1
+ {"version":3,"file":"Select.js","names":[],"sources":["../src/components/Select/Select.tsx"],"sourcesContent":["import { CheckmarkIcon, ChevronDownIcon, LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { SelectValue } from '@primitives/select'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport {\n EmptyState,\n ErrorMessage,\n getAriaProps,\n getDropdownWidthStyles,\n getDropdownSurfaceClasses,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getOptionClasses,\n getTriggerClasses,\n groupOptions,\n LoadingState,\n WarningMessage,\n useFormFieldId,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useState, type ComponentPropsWithoutRef, type CSSProperties, type ReactNode, type Ref } from 'react'\n\ntype SelectOption = BaseOption\ntype Align = 'start' | 'center' | 'end'\ntype Side = 'top' | 'bottom' | 'left' | 'right'\n\nexport interface SelectProps extends Omit<ComponentPropsWithoutRef<'button'>, 'value' | 'onChange' | 'aria-disabled' | 'aria-invalid' | 'aria-required' | 'aria-describedby' | 'aria-label'>, Omit<BaseFormFieldProps, 'state'> {\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: ReactNode\n id?: string\n label?: string\n labelClassName?: string\n loadingMessage?: string\n onChange?: (value: string) => void\n onValueChange?: (value: string) => void\n options: SelectOption[]\n placeholder?: string\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport interface SelectExtendedProps extends SelectProps {\n align?: Align\n alignOffset?: number\n avoidCollisions?: boolean\n collisionBoundary?: Element | Element[] | null\n collisionPadding?: number | Partial<Record<Side, number>>\n position?: 'popper' | 'item-aligned'\n side?: Side\n sideOffset?: number\n}\n\nexport const Select = (\n allProps: SelectExtendedProps & {\n ref?: Ref<HTMLButtonElement>\n },\n) => {\n const isControlled = 'value' in allProps\n const {\n align = 'start',\n alignOffset = 0,\n avoidCollisions = true,\n className,\n collisionBoundary,\n collisionPadding = 10,\n defaultValue,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n disabled,\n id,\n label,\n labelClassName,\n loadingMessage = 'Loading…',\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n options,\n placeholder = 'Select an option',\n position = 'popper',\n ref,\n required,\n side = 'bottom',\n sideOffset = 4,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n ...props\n } = allProps\n const value = isControlled ? (valueProp ?? '') : valueProp\n const [open, setOpen] = useState(false)\n const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(open)\n const selectId = useFormFieldId(id, name)\n const listboxId = `${selectId}-listbox`\n const errorMessageId = getErrorMessageId(selectId)\n const warningMessageId = `${selectId}-warning`\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const { dropdownWidthMode, dropdownWidthStyle, resolvedDropdownWidth } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--radix-select-trigger-width)',\n })\n const selectContentStyle = {\n '--spectral-select-content-width': resolvedDropdownWidth,\n ...(position === 'item-aligned' ? { width: resolvedDropdownWidth } : {}),\n ...dropdownWidthStyle,\n ...dropdownShiftStyle,\n } as CSSProperties\n const isDisabled = Boolean(disabled)\n const isLoading = state === 'loading'\n const isInvalid = state === 'error'\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n const { groups, ungrouped } = groupOptions(options)\n const handleValueChange = (nextValue: string) => {\n onChange?.(nextValue)\n onValueChange?.(nextValue)\n }\n\n const renderOptions = () => {\n if (isLoading) {\n return <LoadingState data-testid='spectral-select-loading' message={loadingMessage} />\n }\n\n if (options.length === 0) {\n return <EmptyState data-testid='spectral-select-empty' message={emptyMessage} />\n }\n\n const renderOption = (option: SelectOption) => {\n const isSelected = value === option.value\n\n return (\n <SelectPrimitive.Item className={cn(getOptionClasses(!!option.disabled, false, isSelected), 'relative flex w-full cursor-pointer items-center')} data-testid='spectral-select-item' disabled={option.disabled} key={option.value} value={option.value}>\n <SelectPrimitive.ItemText data-testid='spectral-select-item-text' className='block truncate'>\n {option.label}\n </SelectPrimitive.ItemText>\n <SelectPrimitive.ItemIndicator data-testid='spectral-select-item-selected-indicator' asChild>\n <span className='right-2 h-4 w-4 absolute flex items-center justify-center'>\n <CheckmarkIcon size={16} />\n </span>\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n )\n }\n\n return (\n <>\n {ungrouped.length > 0 && (\n <>\n {ungrouped.map(renderOption)}\n {Object.keys(groups).length > 0 && <SelectPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-select-separator' />}\n </>\n )}\n\n {Object.entries(groups).map(([groupName, groupOptions], groupIndex) => (\n <SelectPrimitive.Group key={groupName} data-testid='spectral-select-group'>\n {groupIndex > 0 && <SelectPrimitive.Separator className='-mx-1 my-1 h-px bg-border-secondary' data-testid='spectral-select-group-separator' />}\n <Label className={cn('px-2 py-1.5 text-base font-semibold text-text-primary', labelClassName)} data-testid='spectral-select-group-label'>\n {groupName}\n </Label>\n {groupOptions.map((option: BaseOption) => renderOption(option))}\n </SelectPrimitive.Group>\n ))}\n </>\n )\n }\n\n return (\n <div className='w-full'>\n {label && (\n <Label className={cn('mb-2 block text-text-primary', labelClassName, isDisabled && 'text-text-secondary')} data-testid='spectral-select-label' htmlFor={selectId}>\n {label}\n </Label>\n )}\n <SelectPrimitive.Root data-testid='spectral-select' defaultValue={defaultValue} disabled={isDisabled} name={name} onOpenChange={setOpen} onValueChange={handleValueChange} open={open} required={required} value={value}>\n <SelectPrimitive.Trigger\n aria-controls={listboxId}\n aria-expanded={open}\n aria-label={ariaLabel ?? label}\n asChild\n className={cn(getTriggerClasses(open, state), 'text-input-text data-placeholder:text-input-text-placeholder!', className)}\n data-slot='select-trigger'\n data-state={state}\n data-testid='spectral-select-trigger'\n id={selectId}\n ref={ref}\n style={getFormFieldCSSProperties() as CSSProperties}\n {...ariaProps}\n {...props}\n >\n <button\n className='min-w-0 gap-2 [&>span]:min-w-0 grid w-full cursor-pointer grid-cols-[minmax(0,1fr)_auto] items-center overflow-hidden text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder! [&>span]:block [&>span]:overflow-hidden [&>span]:text-ellipsis [&>span]:whitespace-nowrap [&>span[data-placeholder]]:text-input-text-placeholder!'\n type='button'\n disabled={isDisabled}\n >\n <SelectValue data-testid='spectral-select-value' placeholder={placeholder} />\n <SelectPrimitive.Icon asChild>\n <div className='flex shrink-0 cursor-pointer items-center'>{isLoading ? <LoaderIcon size={20} /> : <ChevronDownIcon className={cn('transition-transform duration-200', open && 'rotate-180')} size={20} />}</div>\n </SelectPrimitive.Icon>\n </button>\n </SelectPrimitive.Trigger>\n\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n align={align}\n alignOffset={alignOffset}\n avoidCollisions={avoidCollisions}\n className={cn(\n 'relative z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=open]:zoom-in-95',\n 'max-h-[min(var(--radix-select-content-available-height),300px)] motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2',\n 'min-w-32 origin-(--radix-select-content-transform-origin) overflow-hidden',\n position === 'popper' && 'data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1',\n )}\n collisionBoundary={collisionBoundary}\n collisionPadding={collisionPadding}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n id={listboxId}\n data-slot='select-content'\n data-testid='spectral-select-content'\n position={position}\n ref={setDropdownElement}\n side={side}\n sideOffset={sideOffset}\n style={selectContentStyle}\n >\n <SelectPrimitive.ScrollUpButton className='py-1 flex cursor-default items-center justify-center' data-testid='spectral-select-scroll-up-button'>\n <ChevronDownIcon aria-hidden='true' className='rotate-180' size={18} />\n </SelectPrimitive.ScrollUpButton>\n\n <SelectPrimitive.Viewport asChild>\n <div\n className={cn(\n 'p-1 overflow-x-hidden overflow-y-auto',\n position === 'popper' && (dropdownWidth === 'trigger' ? 'scroll-my-1 h-(--radix-select-trigger-height) w-(--spectral-select-content-width) min-w-(--spectral-select-content-width)' : 'scroll-my-1 h-(--radix-select-trigger-height)'),\n )}\n data-testid='spectral-select-items'\n >\n {renderOptions()}\n </div>\n </SelectPrimitive.Viewport>\n\n <SelectPrimitive.ScrollDownButton className='py-1 flex cursor-default items-center justify-center' data-testid='spectral-select-scroll-down-button'>\n <ChevronDownIcon aria-hidden='true' size={18} />\n </SelectPrimitive.ScrollDownButton>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n </SelectPrimitive.Root>\n\n <ErrorMessage\n dataTestId='spectral-select-error-message'\n id={errorMessageId}\n message={isInvalid ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-select-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nSelect.displayName = 'Select'\n"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  import { Slot } from "../primitives/slot.js";
3
3
  import { useUncontrolledState } from "../hooks/useUncontrolledState.js";
4
4
  import { createContext, useCallback, useContext, useEffect, useId, useRef } from "react";
5
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
6
 
7
7
  //#region src/components/Switch/SwitchBase.tsx
8
8
  const SwitchCtx = createContext(null);
@@ -59,7 +59,7 @@ const Switch = ({ asChild, checked, children, className, defaultChecked = false,
59
59
  checked: isChecked,
60
60
  disabled
61
61
  },
62
- children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Comp, {
62
+ children: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Comp, {
63
63
  "aria-checked": isChecked,
64
64
  className,
65
65
  "data-disabled": disabled ?? void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"SwitchBase.js","names":[],"sources":["../../src/components/Switch/SwitchBase.tsx"],"sourcesContent":["import { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { Slot, type AsChildProp } from '@primitives/slot'\nimport { createContext, useCallback, useContext, useEffect, useId, useRef, type ButtonHTMLAttributes, type ElementType, type HTMLAttributes, type KeyboardEvent, type MouseEvent, type Ref } from 'react'\n\ninterface Ctx {\n checked: boolean\n disabled: boolean | undefined\n}\n\nconst SwitchCtx = createContext<Ctx | null>(null)\n\ntype BaseButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'value'>\n\nexport interface SwitchProps extends BaseButtonProps, AsChildProp {\n checked?: boolean\n defaultChecked?: boolean\n form?: string\n name?: string\n onCheckedChange?: (checked: boolean) => void\n required?: boolean\n value?: string\n}\n\nexport const Switch = ({\n asChild,\n checked,\n children,\n className,\n defaultChecked = false,\n disabled,\n form,\n id,\n name,\n onCheckedChange,\n onClick,\n onKeyDown,\n ref,\n required,\n value = 'on',\n ...rest\n}: SwitchProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const inputRef = useRef<HTMLInputElement | null>(null)\n const autoId = useId()\n const resolvedId = id ?? `swt-${autoId}`\n\n const [isChecked, setIsChecked] = useUncontrolledState<boolean>({\n value: checked,\n defaultValue: defaultChecked,\n onChange: onCheckedChange,\n })\n\n // form reset -> restore default\n useEffect(() => {\n const formEl = inputRef.current?.form ?? null\n if (!formEl) return\n const handleReset = () => setIsChecked(defaultChecked)\n formEl.addEventListener('reset', handleReset)\n return () => formEl.removeEventListener('reset', handleReset)\n }, [defaultChecked, setIsChecked])\n\n const emitFormChange = useCallback((checkedValue: boolean) => {\n const el = inputRef.current\n if (!el) return\n el.checked = checkedValue\n const ev = new Event('change', { bubbles: true })\n el.dispatchEvent(ev)\n }, [])\n\n const toggle = useCallback(() => {\n if (disabled) return\n const newChecked = !isChecked\n setIsChecked(newChecked)\n queueMicrotask(() => emitFormChange(newChecked))\n }, [disabled, emitFormChange, isChecked, setIsChecked])\n\n const handleClick = useCallback(\n (e: MouseEvent<HTMLButtonElement>) => {\n onClick?.(e)\n if (e.defaultPrevented) return\n toggle()\n },\n [onClick, toggle],\n )\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(e)\n if (e.defaultPrevented) return\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault()\n toggle()\n }\n },\n [onKeyDown, toggle],\n )\n\n const Comp: ElementType = asChild ? Slot : 'button'\n\n return (\n <SwitchCtx.Provider value={{ checked: isChecked, disabled }}>\n <>\n <Comp aria-checked={isChecked} className={className} data-disabled={disabled ?? undefined} data-state={isChecked ? 'checked' : 'unchecked'} disabled={disabled} id={resolvedId} onClick={handleClick} onKeyDown={handleKeyDown} ref={ref} role='switch' type='button' {...rest}>\n {children}\n </Comp>\n {/* hidden input outside <button> — <input> inside <button> is invalid HTML.\n The form attribute handles cross-form association without nesting. */}\n <input\n aria-hidden='true'\n checked={isChecked}\n disabled={disabled}\n form={form}\n name={name}\n readOnly\n ref={inputRef}\n required={required}\n tabIndex={-1}\n type='checkbox'\n value={value}\n style={{\n height: 0,\n opacity: 0,\n pointerEvents: 'none',\n position: 'absolute',\n width: 0,\n }}\n />\n </>\n </SwitchCtx.Provider>\n )\n}\nSwitch.displayName = 'Switch'\n\nexport type SwitchThumbProps = HTMLAttributes<HTMLSpanElement> & AsChildProp\n\nexport const SwitchThumb = ({\n asChild,\n className,\n ref,\n ...props\n}: SwitchThumbProps & {\n ref?: Ref<HTMLSpanElement>\n}) => {\n const ctx = useContext(SwitchCtx)\n if (!ctx) throw new Error('SwitchThumb must be used within Switch')\n\n const Comp: ElementType = asChild ? Slot : 'span'\n\n return <Comp className={className} data-disabled={ctx.disabled ?? undefined} data-state={ctx.checked ? 'checked' : 'unchecked'} ref={ref} {...props} />\n}\nSwitchThumb.displayName = 'SwitchThumb'\n"],"mappings":";;;;;;;AASA,MAAM,YAAY,cAA0B,KAAK;AAcjD,MAAa,UAAU,EACrB,SACA,SACA,UACA,WACA,iBAAiB,OACjB,UACA,MACA,IACA,MACA,iBACA,SACA,WACA,KACA,UACA,QAAQ,MACR,GAAG,WAGC;CACJ,MAAM,WAAW,OAAgC,KAAK;CACtD,MAAM,SAAS,OAAO;CACtB,MAAM,aAAa,MAAM,OAAO;CAEhC,MAAM,CAAC,WAAW,gBAAgB,qBAA8B;EAC9D,OAAO;EACP,cAAc;EACd,UAAU;EACX,CAAC;AAGF,iBAAgB;EACd,MAAM,SAAS,SAAS,SAAS,QAAQ;AACzC,MAAI,CAAC,OAAQ;EACb,MAAM,oBAAoB,aAAa,eAAe;AACtD,SAAO,iBAAiB,SAAS,YAAY;AAC7C,eAAa,OAAO,oBAAoB,SAAS,YAAY;IAC5D,CAAC,gBAAgB,aAAa,CAAC;CAElC,MAAM,iBAAiB,aAAa,iBAA0B;EAC5D,MAAM,KAAK,SAAS;AACpB,MAAI,CAAC,GAAI;AACT,KAAG,UAAU;EACb,MAAM,KAAK,IAAI,MAAM,UAAU,EAAE,SAAS,MAAM,CAAC;AACjD,KAAG,cAAc,GAAG;IACnB,EAAE,CAAC;CAEN,MAAM,SAAS,kBAAkB;AAC/B,MAAI,SAAU;EACd,MAAM,aAAa,CAAC;AACpB,eAAa,WAAW;AACxB,uBAAqB,eAAe,WAAW,CAAC;IAC/C;EAAC;EAAU;EAAgB;EAAW;EAAa,CAAC;CAEvD,MAAM,cAAc,aACjB,MAAqC;AACpC,YAAU,EAAE;AACZ,MAAI,EAAE,iBAAkB;AACxB,UAAQ;IAEV,CAAC,SAAS,OAAO,CAClB;CAED,MAAM,gBAAgB,aACnB,MAAwC;AACvC,cAAY,EAAE;AACd,MAAI,EAAE,iBAAkB;AACxB,MAAI,EAAE,QAAQ,OAAO,EAAE,QAAQ,SAAS;AACtC,KAAE,gBAAgB;AAClB,WAAQ;;IAGZ,CAAC,WAAW,OAAO,CACpB;CAED,MAAM,OAAoB,UAAU,OAAO;AAE3C,QACE,oBAAC,UAAU,UAAX;EAAoB,OAAO;GAAE,SAAS;GAAW;GAAU;YACzD,4CACE,oBAAC,MAAD;GAAM,gBAAc;GAAsB;GAAW,iBAAe,YAAY;GAAW,cAAY,YAAY,YAAY;GAAuB;GAAU,IAAI;GAAY,SAAS;GAAa,WAAW;GAAoB;GAAK,MAAK;GAAS,MAAK;GAAS,GAAI;GACvQ;GACI,GAGP,oBAAC,SAAD;GACE,eAAY;GACZ,SAAS;GACC;GACJ;GACA;GACN;GACA,KAAK;GACK;GACV,UAAU;GACV,MAAK;GACE;GACP,OAAO;IACL,QAAQ;IACR,SAAS;IACT,eAAe;IACf,UAAU;IACV,OAAO;IACR;GACD,EACD;EACgB;;AAGzB,OAAO,cAAc;AAIrB,MAAa,eAAe,EAC1B,SACA,WACA,KACA,GAAG,YAGC;CACJ,MAAM,MAAM,WAAW,UAAU;AACjC,KAAI,CAAC,IAAK,OAAM,IAAI,MAAM,yCAAyC;AAInE,QAAO,oBAFmB,UAAU,OAAO,QAEpC;EAAiB;EAAW,iBAAe,IAAI,YAAY;EAAW,cAAY,IAAI,UAAU,YAAY;EAAkB;EAAK,GAAI;EAAS;;AAEzJ,YAAY,cAAc"}
1
+ {"version":3,"file":"SwitchBase.js","names":[],"sources":["../../src/components/Switch/SwitchBase.tsx"],"sourcesContent":["import { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { Slot, type AsChildProp } from '@primitives/slot'\nimport { createContext, useCallback, useContext, useEffect, useId, useRef, type ButtonHTMLAttributes, type ElementType, type HTMLAttributes, type KeyboardEvent, type MouseEvent, type Ref } from 'react'\n\ninterface Ctx {\n checked: boolean\n disabled: boolean | undefined\n}\n\nconst SwitchCtx = createContext<Ctx | null>(null)\n\ntype BaseButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'value'>\n\nexport interface SwitchProps extends BaseButtonProps, AsChildProp {\n checked?: boolean\n defaultChecked?: boolean\n form?: string\n name?: string\n onCheckedChange?: (checked: boolean) => void\n required?: boolean\n value?: string\n}\n\nexport const Switch = ({\n asChild,\n checked,\n children,\n className,\n defaultChecked = false,\n disabled,\n form,\n id,\n name,\n onCheckedChange,\n onClick,\n onKeyDown,\n ref,\n required,\n value = 'on',\n ...rest\n}: SwitchProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const inputRef = useRef<HTMLInputElement | null>(null)\n const autoId = useId()\n const resolvedId = id ?? `swt-${autoId}`\n\n const [isChecked, setIsChecked] = useUncontrolledState<boolean>({\n value: checked,\n defaultValue: defaultChecked,\n onChange: onCheckedChange,\n })\n\n // form reset -> restore default\n useEffect(() => {\n const formEl = inputRef.current?.form ?? null\n if (!formEl) return\n const handleReset = () => setIsChecked(defaultChecked)\n formEl.addEventListener('reset', handleReset)\n return () => formEl.removeEventListener('reset', handleReset)\n }, [defaultChecked, setIsChecked])\n\n const emitFormChange = useCallback((checkedValue: boolean) => {\n const el = inputRef.current\n if (!el) return\n el.checked = checkedValue\n const ev = new Event('change', { bubbles: true })\n el.dispatchEvent(ev)\n }, [])\n\n const toggle = useCallback(() => {\n if (disabled) return\n const newChecked = !isChecked\n setIsChecked(newChecked)\n queueMicrotask(() => emitFormChange(newChecked))\n }, [disabled, emitFormChange, isChecked, setIsChecked])\n\n const handleClick = useCallback(\n (e: MouseEvent<HTMLButtonElement>) => {\n onClick?.(e)\n if (e.defaultPrevented) return\n toggle()\n },\n [onClick, toggle],\n )\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(e)\n if (e.defaultPrevented) return\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault()\n toggle()\n }\n },\n [onKeyDown, toggle],\n )\n\n const Comp: ElementType = asChild ? Slot : 'button'\n\n return (\n <SwitchCtx.Provider value={{ checked: isChecked, disabled }}>\n <>\n <Comp aria-checked={isChecked} className={className} data-disabled={disabled ?? undefined} data-state={isChecked ? 'checked' : 'unchecked'} disabled={disabled} id={resolvedId} onClick={handleClick} onKeyDown={handleKeyDown} ref={ref} role='switch' type='button' {...rest}>\n {children}\n </Comp>\n {/* hidden input outside <button> — <input> inside <button> is invalid HTML.\n The form attribute handles cross-form association without nesting. */}\n <input\n aria-hidden='true'\n checked={isChecked}\n disabled={disabled}\n form={form}\n name={name}\n readOnly\n ref={inputRef}\n required={required}\n tabIndex={-1}\n type='checkbox'\n value={value}\n style={{\n height: 0,\n opacity: 0,\n pointerEvents: 'none',\n position: 'absolute',\n width: 0,\n }}\n />\n </>\n </SwitchCtx.Provider>\n )\n}\nSwitch.displayName = 'Switch'\n\nexport type SwitchThumbProps = HTMLAttributes<HTMLSpanElement> & AsChildProp\n\nexport const SwitchThumb = ({\n asChild,\n className,\n ref,\n ...props\n}: SwitchThumbProps & {\n ref?: Ref<HTMLSpanElement>\n}) => {\n const ctx = useContext(SwitchCtx)\n if (!ctx) throw new Error('SwitchThumb must be used within Switch')\n\n const Comp: ElementType = asChild ? Slot : 'span'\n\n return <Comp className={className} data-disabled={ctx.disabled ?? undefined} data-state={ctx.checked ? 'checked' : 'unchecked'} ref={ref} {...props} />\n}\nSwitchThumb.displayName = 'SwitchThumb'\n"],"mappings":";;;;;;;AASA,MAAM,YAAY,cAA0B,KAAK;AAcjD,MAAa,UAAU,EACrB,SACA,SACA,UACA,WACA,iBAAiB,OACjB,UACA,MACA,IACA,MACA,iBACA,SACA,WACA,KACA,UACA,QAAQ,MACR,GAAG,WAGC;CACJ,MAAM,WAAW,OAAgC,KAAK;CACtD,MAAM,SAAS,OAAO;CACtB,MAAM,aAAa,MAAM,OAAO;CAEhC,MAAM,CAAC,WAAW,gBAAgB,qBAA8B;EAC9D,OAAO;EACP,cAAc;EACd,UAAU;EACX,CAAC;AAGF,iBAAgB;EACd,MAAM,SAAS,SAAS,SAAS,QAAQ;AACzC,MAAI,CAAC,OAAQ;EACb,MAAM,oBAAoB,aAAa,eAAe;AACtD,SAAO,iBAAiB,SAAS,YAAY;AAC7C,eAAa,OAAO,oBAAoB,SAAS,YAAY;IAC5D,CAAC,gBAAgB,aAAa,CAAC;CAElC,MAAM,iBAAiB,aAAa,iBAA0B;EAC5D,MAAM,KAAK,SAAS;AACpB,MAAI,CAAC,GAAI;AACT,KAAG,UAAU;EACb,MAAM,KAAK,IAAI,MAAM,UAAU,EAAE,SAAS,MAAM,CAAC;AACjD,KAAG,cAAc,GAAG;IACnB,EAAE,CAAC;CAEN,MAAM,SAAS,kBAAkB;AAC/B,MAAI,SAAU;EACd,MAAM,aAAa,CAAC;AACpB,eAAa,WAAW;AACxB,uBAAqB,eAAe,WAAW,CAAC;IAC/C;EAAC;EAAU;EAAgB;EAAW;EAAa,CAAC;CAEvD,MAAM,cAAc,aACjB,MAAqC;AACpC,YAAU,EAAE;AACZ,MAAI,EAAE,iBAAkB;AACxB,UAAQ;IAEV,CAAC,SAAS,OAAO,CAClB;CAED,MAAM,gBAAgB,aACnB,MAAwC;AACvC,cAAY,EAAE;AACd,MAAI,EAAE,iBAAkB;AACxB,MAAI,EAAE,QAAQ,OAAO,EAAE,QAAQ,SAAS;AACtC,KAAE,gBAAgB;AAClB,WAAQ;;IAGZ,CAAC,WAAW,OAAO,CACpB;CAED,MAAM,OAAoB,UAAU,OAAO;AAE3C,QACE,oBAAC,UAAU,UAAX;EAAoB,OAAO;GAAE,SAAS;GAAW;GAAU;YACzD,8CACE,oBAAC,MAAD;GAAM,gBAAc;GAAsB;GAAW,iBAAe,YAAY;GAAW,cAAY,YAAY,YAAY;GAAuB;GAAU,IAAI;GAAY,SAAS;GAAa,WAAW;GAAoB;GAAK,MAAK;GAAS,MAAK;GAAS,GAAI;GACvQ;GACI,GAGP,oBAAC,SAAD;GACE,eAAY;GACZ,SAAS;GACC;GACJ;GACA;GACN;GACA,KAAK;GACK;GACV,UAAU;GACV,MAAK;GACE;GACP,OAAO;IACL,QAAQ;IACR,SAAS;IACT,eAAe;IACf,UAAU;IACV,OAAO;IACR;GACD,EACD;EACgB;;AAGzB,OAAO,cAAc;AAIrB,MAAa,eAAe,EAC1B,SACA,WACA,KACA,GAAG,YAGC;CACJ,MAAM,MAAM,WAAW,UAAU;AACjC,KAAI,CAAC,IAAK,OAAM,IAAI,MAAM,yCAAyC;AAInE,QAAO,oBAFmB,UAAU,OAAO,QAEpC;EAAiB;EAAW,iBAAe,IAAI,YAAY;EAAW,cAAY,IAAI,UAAU,YAAY;EAAkB;EAAK,GAAI;EAAS;;AAEzJ,YAAY,cAAc"}
@@ -7,7 +7,7 @@ import { ToggleGroupContext } from "../components/ToggleGroup/ToggleGroup.contex
7
7
  import { ToggleGroupItem } from "./ToggleGroupItem.js";
8
8
  import { DropdownMenu } from "../DropdownMenu.js";
9
9
  import { useContext, useRef, useState } from "react";
10
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
11
 
12
12
  //#region src/components/ToggleGroup/ToggleGroupSplitMenuItem.tsx
13
13
  const ToggleGroupSplitMenuItem = ({ activeColor, activeTextColor, children, className, dropdownAlign = "end", dropdownAriaLabel, dropdownButtonClassName, dropdownButtonStyle, dropdownCollisionPadding = 12, dropdownOptions, dropdownSide = "bottom", dropdownValue, dropdownValueLabel, layout, onDropdownValueChange, onKeyDown, size, style, triggerIcon = /* @__PURE__ */ jsx(ChevronDownIcon, { size: 16 }), value, variant, ...props }) => {
@@ -87,7 +87,7 @@ const ToggleGroupSplitMenuItem = ({ activeColor, activeTextColor, children, clas
87
87
  }
88
88
  if (onKeyDown) onKeyDown(event);
89
89
  };
90
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ToggleGroupItem, {
90
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ToggleGroupItem, {
91
91
  activeColor: resolvedActiveColor,
92
92
  activeTextColor: resolvedActiveTextColor,
93
93
  "aria-label": props["aria-label"] ? `${props["aria-label"]}${dropdownValueLabel ? `, ${dropdownValueLabel}` : ""}` : void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"ToggleGroupSplitMenuItem.js","names":[],"sources":["../../src/components/ToggleGroup/ToggleGroupSplitMenuItem.tsx"],"sourcesContent":["import { DropdownMenu, type DropdownMenuOption, type DropdownMenuProps } from '@components/DropdownMenu/DropdownMenu'\nimport { ChevronDownIcon } from '@components/Icons'\nimport { toggleVariants } from '@components/Toggle/Toggle'\nimport { getActiveColorStyle } from '@utils/activeColorStyle'\nimport { cn } from '@utils/twUtils'\nimport { useContext, useRef, useState, type CSSProperties, type KeyboardEvent, type ReactNode } from 'react'\nimport { ToggleGroupContext } from './ToggleGroup.context'\nimport { ToggleGroupItem, type ToggleGroupItemProps } from './ToggleGroupItem'\n\nexport interface ToggleGroupSplitMenuItemProps extends Omit<ToggleGroupItemProps, 'children'> {\n children: ReactNode\n dropdownAlign?: DropdownMenuProps['align']\n dropdownAriaLabel: string\n dropdownButtonClassName?: string\n dropdownCollisionPadding?: DropdownMenuProps['collisionPadding']\n dropdownButtonStyle?: CSSProperties\n dropdownOptions: DropdownMenuOption[]\n dropdownSide?: DropdownMenuProps['side']\n dropdownValue?: string | string[]\n dropdownValueLabel?: string\n onDropdownValueChange?: (value: string | string[]) => void\n triggerIcon?: ReactNode\n}\n\nexport const ToggleGroupSplitMenuItem = ({\n activeColor,\n activeTextColor,\n children,\n className,\n dropdownAlign = 'end',\n dropdownAriaLabel,\n dropdownButtonClassName,\n dropdownButtonStyle,\n dropdownCollisionPadding = 12,\n dropdownOptions,\n dropdownSide = 'bottom',\n dropdownValue,\n dropdownValueLabel,\n layout,\n onDropdownValueChange,\n onKeyDown,\n size,\n style,\n triggerIcon = <ChevronDownIcon size={16} />,\n value,\n variant,\n ...props\n}: ToggleGroupSplitMenuItemProps) => {\n const [open, setOpen] = useState(false)\n const dropdownContentRef = useRef<HTMLDivElement | null>(null)\n const primaryButtonRef = useRef<HTMLButtonElement | null>(null)\n const chevronButtonRef = useRef<HTMLButtonElement | null>(null)\n const openerRef = useRef<'primary' | 'chevron' | null>(null)\n const isDisabled = props.disabled ?? false\n const context = useContext(ToggleGroupContext)\n const resolvedVariant = variant ?? context.variant\n const resolvedSize = size ?? context.size\n const resolvedLayout = layout ?? context.layout\n const resolvedOrientation = context.orientation ?? 'horizontal'\n const resolvedActiveColor = activeColor ?? context.activeColor\n const resolvedActiveTextColor = activeTextColor ?? context.activeTextColor\n const sharedActiveStyle = {\n ...getActiveColorStyle(resolvedActiveColor, resolvedActiveTextColor),\n ...style,\n }\n\n const focusFirstEnabledDropdownItem = (focusTarget: 'first' | 'last' = 'first'): void => {\n const content = dropdownContentRef.current\n if (!content) return\n\n const menuItemSelector = '[role=\"menuitem\"]:not([data-disabled]), [role=\"menuitemcheckbox\"]:not([data-disabled]), [role=\"menuitemradio\"]:not([data-disabled])'\n const enabledItems = Array.from(content.querySelectorAll<HTMLElement>(menuItemSelector))\n if (enabledItems.length === 0) return\n\n if (focusTarget === 'last') {\n enabledItems[enabledItems.length - 1]?.focus()\n return\n }\n\n enabledItems[0]?.focus()\n }\n\n const openMenu = (opener: 'primary' | 'chevron'): void => {\n openerRef.current = opener\n setOpen(true)\n setTimeout(() => {\n focusFirstEnabledDropdownItem('first')\n }, 0)\n }\n\n const restoreFocusToOpener = (): void => {\n const opener = openerRef.current\n const focusTarget = opener === 'primary' ? primaryButtonRef.current : chevronButtonRef.current\n openerRef.current = null\n focusTarget?.focus()\n }\n\n const handleDropdownOpenChange = (nextOpen: boolean): void => {\n if (nextOpen) {\n openerRef.current ??= 'chevron'\n setOpen(true)\n setTimeout(() => {\n focusFirstEnabledDropdownItem('first')\n }, 0)\n return\n }\n\n setOpen(false)\n restoreFocusToOpener()\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (event.key === 'ArrowDown' && resolvedOrientation !== 'vertical') {\n event.preventDefault()\n openMenu('primary')\n if (onKeyDown) onKeyDown(event)\n return\n }\n\n if (onKeyDown) onKeyDown(event)\n }\n\n const handleDropdownTriggerKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (open && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {\n event.preventDefault()\n focusFirstEnabledDropdownItem(event.key === 'ArrowUp' ? 'last' : 'first')\n if (onKeyDown) onKeyDown(event)\n return\n }\n\n const isOpenMenuKey = event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ' || event.key === 'Space' || event.key === 'Spacebar'\n\n if (isOpenMenuKey) {\n event.preventDefault()\n openMenu('chevron')\n if (onKeyDown) onKeyDown(event)\n return\n }\n\n if (onKeyDown) onKeyDown(event)\n }\n\n const toggleAriaLabel = props['aria-label'] ? `${props['aria-label']}${dropdownValueLabel ? `, ${dropdownValueLabel}` : ''}` : undefined\n\n return (\n <>\n <ToggleGroupItem\n activeColor={resolvedActiveColor}\n activeTextColor={resolvedActiveTextColor}\n aria-label={toggleAriaLabel}\n className={cn('peer/spectral-split-menu rounded-r-none! border-r-0', className)}\n layout={resolvedLayout}\n onKeyDown={handleKeyDown}\n ref={primaryButtonRef}\n size={resolvedSize}\n style={sharedActiveStyle}\n value={value}\n variant={resolvedVariant}\n {...(({ 'aria-label': _, ...rest }) => rest)(props)}\n >\n {children}\n </ToggleGroupItem>\n\n <DropdownMenu\n align={dropdownAlign}\n asChild\n collisionPadding={dropdownCollisionPadding}\n disabled={isDisabled}\n dropdownContentRef={dropdownContentRef}\n onOpenChange={handleDropdownOpenChange}\n onValueChange={onDropdownValueChange}\n open={open}\n options={dropdownOptions}\n side={dropdownSide}\n trigger={\n <button\n aria-expanded={open}\n aria-haspopup='menu'\n aria-label={dropdownAriaLabel}\n className={cn(\n toggleVariants({\n layout: resolvedLayout,\n size: resolvedSize,\n variant: resolvedVariant,\n }),\n 'px-1 min-w-6 data-[size=sm]:min-w-5 data-[size=sm]:px-0.5 relative rounded-none border-l-0 shadow-none',\n 'data-[size=lg]:min-w-7 data-[size=lg]:px-1.5 data-[variant=outline]:border-toggle-border data-[variant=divided]:border-toggle-border',\n 'hover:opacity-100! data-[variant=outline]:hover:border-toggle-border data-[variant=divided]:hover:border-toggle-border',\n 'before:inset-y-2 before:left-0 before:pointer-events-none before:absolute before:w-px before:bg-border-secondary/6',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'peer-data-[state=on]/spectral-split-menu:border-toggle-border--active!',\n 'peer-data-[state=on]/spectral-split-menu:bg-toggle-bg--active',\n 'peer-data-[state=on]/spectral-split-menu:hover:border-toggle-border--active!',\n 'peer-data-[state=on]/spectral-split-menu:hover:bg-toggle-bg--active!',\n 'peer-data-[state=on]/spectral-split-menu:text-toggle-text--active',\n 'peer-data-[state=on]/spectral-split-menu:hover:text-toggle-text--active!',\n dropdownButtonClassName,\n )}\n data-layout={resolvedLayout}\n data-size={resolvedSize}\n data-variant={resolvedVariant}\n disabled={isDisabled}\n onKeyDown={handleDropdownTriggerKeyDown}\n onPointerDown={() => {\n openerRef.current = 'chevron'\n }}\n ref={chevronButtonRef}\n style={{ ...sharedActiveStyle, ...dropdownButtonStyle }}\n type='button'\n >\n {triggerIcon}\n </button>\n }\n value={dropdownValue}\n />\n </>\n )\n}\n\nToggleGroupSplitMenuItem.displayName = 'ToggleGroupSplitMenuItem'\n"],"mappings":"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"}
1
+ {"version":3,"file":"ToggleGroupSplitMenuItem.js","names":[],"sources":["../../src/components/ToggleGroup/ToggleGroupSplitMenuItem.tsx"],"sourcesContent":["import { DropdownMenu, type DropdownMenuOption, type DropdownMenuProps } from '@components/DropdownMenu/DropdownMenu'\nimport { ChevronDownIcon } from '@components/Icons'\nimport { toggleVariants } from '@components/Toggle/Toggle'\nimport { getActiveColorStyle } from '@utils/activeColorStyle'\nimport { cn } from '@utils/twUtils'\nimport { useContext, useRef, useState, type CSSProperties, type KeyboardEvent, type ReactNode } from 'react'\nimport { ToggleGroupContext } from './ToggleGroup.context'\nimport { ToggleGroupItem, type ToggleGroupItemProps } from './ToggleGroupItem'\n\nexport interface ToggleGroupSplitMenuItemProps extends Omit<ToggleGroupItemProps, 'children'> {\n children: ReactNode\n dropdownAlign?: DropdownMenuProps['align']\n dropdownAriaLabel: string\n dropdownButtonClassName?: string\n dropdownCollisionPadding?: DropdownMenuProps['collisionPadding']\n dropdownButtonStyle?: CSSProperties\n dropdownOptions: DropdownMenuOption[]\n dropdownSide?: DropdownMenuProps['side']\n dropdownValue?: string | string[]\n dropdownValueLabel?: string\n onDropdownValueChange?: (value: string | string[]) => void\n triggerIcon?: ReactNode\n}\n\nexport const ToggleGroupSplitMenuItem = ({\n activeColor,\n activeTextColor,\n children,\n className,\n dropdownAlign = 'end',\n dropdownAriaLabel,\n dropdownButtonClassName,\n dropdownButtonStyle,\n dropdownCollisionPadding = 12,\n dropdownOptions,\n dropdownSide = 'bottom',\n dropdownValue,\n dropdownValueLabel,\n layout,\n onDropdownValueChange,\n onKeyDown,\n size,\n style,\n triggerIcon = <ChevronDownIcon size={16} />,\n value,\n variant,\n ...props\n}: ToggleGroupSplitMenuItemProps) => {\n const [open, setOpen] = useState(false)\n const dropdownContentRef = useRef<HTMLDivElement | null>(null)\n const primaryButtonRef = useRef<HTMLButtonElement | null>(null)\n const chevronButtonRef = useRef<HTMLButtonElement | null>(null)\n const openerRef = useRef<'primary' | 'chevron' | null>(null)\n const isDisabled = props.disabled ?? false\n const context = useContext(ToggleGroupContext)\n const resolvedVariant = variant ?? context.variant\n const resolvedSize = size ?? context.size\n const resolvedLayout = layout ?? context.layout\n const resolvedOrientation = context.orientation ?? 'horizontal'\n const resolvedActiveColor = activeColor ?? context.activeColor\n const resolvedActiveTextColor = activeTextColor ?? context.activeTextColor\n const sharedActiveStyle = {\n ...getActiveColorStyle(resolvedActiveColor, resolvedActiveTextColor),\n ...style,\n }\n\n const focusFirstEnabledDropdownItem = (focusTarget: 'first' | 'last' = 'first'): void => {\n const content = dropdownContentRef.current\n if (!content) return\n\n const menuItemSelector = '[role=\"menuitem\"]:not([data-disabled]), [role=\"menuitemcheckbox\"]:not([data-disabled]), [role=\"menuitemradio\"]:not([data-disabled])'\n const enabledItems = Array.from(content.querySelectorAll<HTMLElement>(menuItemSelector))\n if (enabledItems.length === 0) return\n\n if (focusTarget === 'last') {\n enabledItems[enabledItems.length - 1]?.focus()\n return\n }\n\n enabledItems[0]?.focus()\n }\n\n const openMenu = (opener: 'primary' | 'chevron'): void => {\n openerRef.current = opener\n setOpen(true)\n setTimeout(() => {\n focusFirstEnabledDropdownItem('first')\n }, 0)\n }\n\n const restoreFocusToOpener = (): void => {\n const opener = openerRef.current\n const focusTarget = opener === 'primary' ? primaryButtonRef.current : chevronButtonRef.current\n openerRef.current = null\n focusTarget?.focus()\n }\n\n const handleDropdownOpenChange = (nextOpen: boolean): void => {\n if (nextOpen) {\n openerRef.current ??= 'chevron'\n setOpen(true)\n setTimeout(() => {\n focusFirstEnabledDropdownItem('first')\n }, 0)\n return\n }\n\n setOpen(false)\n restoreFocusToOpener()\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (event.key === 'ArrowDown' && resolvedOrientation !== 'vertical') {\n event.preventDefault()\n openMenu('primary')\n if (onKeyDown) onKeyDown(event)\n return\n }\n\n if (onKeyDown) onKeyDown(event)\n }\n\n const handleDropdownTriggerKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (open && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {\n event.preventDefault()\n focusFirstEnabledDropdownItem(event.key === 'ArrowUp' ? 'last' : 'first')\n if (onKeyDown) onKeyDown(event)\n return\n }\n\n const isOpenMenuKey = event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ' || event.key === 'Space' || event.key === 'Spacebar'\n\n if (isOpenMenuKey) {\n event.preventDefault()\n openMenu('chevron')\n if (onKeyDown) onKeyDown(event)\n return\n }\n\n if (onKeyDown) onKeyDown(event)\n }\n\n const toggleAriaLabel = props['aria-label'] ? `${props['aria-label']}${dropdownValueLabel ? `, ${dropdownValueLabel}` : ''}` : undefined\n\n return (\n <>\n <ToggleGroupItem\n activeColor={resolvedActiveColor}\n activeTextColor={resolvedActiveTextColor}\n aria-label={toggleAriaLabel}\n className={cn('peer/spectral-split-menu rounded-r-none! border-r-0', className)}\n layout={resolvedLayout}\n onKeyDown={handleKeyDown}\n ref={primaryButtonRef}\n size={resolvedSize}\n style={sharedActiveStyle}\n value={value}\n variant={resolvedVariant}\n {...(({ 'aria-label': _, ...rest }) => rest)(props)}\n >\n {children}\n </ToggleGroupItem>\n\n <DropdownMenu\n align={dropdownAlign}\n asChild\n collisionPadding={dropdownCollisionPadding}\n disabled={isDisabled}\n dropdownContentRef={dropdownContentRef}\n onOpenChange={handleDropdownOpenChange}\n onValueChange={onDropdownValueChange}\n open={open}\n options={dropdownOptions}\n side={dropdownSide}\n trigger={\n <button\n aria-expanded={open}\n aria-haspopup='menu'\n aria-label={dropdownAriaLabel}\n className={cn(\n toggleVariants({\n layout: resolvedLayout,\n size: resolvedSize,\n variant: resolvedVariant,\n }),\n 'px-1 min-w-6 data-[size=sm]:min-w-5 data-[size=sm]:px-0.5 relative rounded-none border-l-0 shadow-none',\n 'data-[size=lg]:min-w-7 data-[size=lg]:px-1.5 data-[variant=outline]:border-toggle-border data-[variant=divided]:border-toggle-border',\n 'hover:opacity-100! data-[variant=outline]:hover:border-toggle-border data-[variant=divided]:hover:border-toggle-border',\n 'before:inset-y-2 before:left-0 before:pointer-events-none before:absolute before:w-px before:bg-border-secondary/6',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent',\n 'peer-data-[state=on]/spectral-split-menu:border-toggle-border--active!',\n 'peer-data-[state=on]/spectral-split-menu:bg-toggle-bg--active',\n 'peer-data-[state=on]/spectral-split-menu:hover:border-toggle-border--active!',\n 'peer-data-[state=on]/spectral-split-menu:hover:bg-toggle-bg--active!',\n 'peer-data-[state=on]/spectral-split-menu:text-toggle-text--active',\n 'peer-data-[state=on]/spectral-split-menu:hover:text-toggle-text--active!',\n dropdownButtonClassName,\n )}\n data-layout={resolvedLayout}\n data-size={resolvedSize}\n data-variant={resolvedVariant}\n disabled={isDisabled}\n onKeyDown={handleDropdownTriggerKeyDown}\n onPointerDown={() => {\n openerRef.current = 'chevron'\n }}\n ref={chevronButtonRef}\n style={{ ...sharedActiveStyle, ...dropdownButtonStyle }}\n type='button'\n >\n {triggerIcon}\n </button>\n }\n value={dropdownValue}\n />\n </>\n )\n}\n\nToggleGroupSplitMenuItem.displayName = 'ToggleGroupSplitMenuItem'\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import "react";
3
- import { Fragment, jsx } from "react/jsx-runtime";
3
+ import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
4
4
 
5
5
  //#region src/components/SpectralProvider/SpectralProvider.tsx
6
6
  /**
@@ -21,7 +21,7 @@ import { Fragment, jsx } from "react/jsx-runtime";
21
21
  * ```
22
22
  */
23
23
  const SpectralProvider = ({ children, className = "", isolated = true }) => {
24
- if (!isolated) return /* @__PURE__ */ jsx(Fragment, { children });
24
+ if (!isolated) return /* @__PURE__ */ jsx(Fragment$1, { children });
25
25
  return /* @__PURE__ */ jsx("div", {
26
26
  className: `spectral-root ${className}`,
27
27
  children
@@ -1 +1 @@
1
- {"version":3,"file":"SpectralProvider.js","names":[],"sources":["../../../src/components/SpectralProvider/SpectralProvider.tsx"],"sourcesContent":["import { type FC, type ReactNode } from 'react'\n\nexport interface SpectralProviderProps {\n children: ReactNode\n className?: string\n /**\n * Adds a wrapper div with spectral-root class for CSS isolation.\n * Set to false if you want to manage CSS specificity yourself.\n * @default true\n */\n isolated?: boolean\n}\n\n/**\n * Optional provider component for Spectral components.\n * Provides CSS isolation when needed to prevent style conflicts.\n *\n * @example\n * ```tsx\n * // With isolation (recommended for apps with conflicting styles)\n * <SpectralProvider>\n * <Button>Click me</Button>\n * </SpectralProvider>\n *\n * // Without wrapper (when you have full control over styles)\n * <SpectralProvider isolated={false}>\n * <Button>Click me</Button>\n * </SpectralProvider>\n * ```\n */\nexport const SpectralProvider: FC<SpectralProviderProps> = ({ children, className = '', isolated = true }) => {\n if (!isolated) {\n return <>{children}</>\n }\n\n return <div className={`spectral-root ${className}`}>{children}</div>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,MAAa,oBAA+C,EAAE,UAAU,YAAY,IAAI,WAAW,WAAW;AAC5G,KAAI,CAAC,SACH,QAAO,gCAAG,UAAY;AAGxB,QAAO,oBAAC,OAAD;EAAK,WAAW,iBAAiB;EAAc;EAAe"}
1
+ {"version":3,"file":"SpectralProvider.js","names":[],"sources":["../../../src/components/SpectralProvider/SpectralProvider.tsx"],"sourcesContent":["import { type FC, type ReactNode } from 'react'\n\nexport interface SpectralProviderProps {\n children: ReactNode\n className?: string\n /**\n * Adds a wrapper div with spectral-root class for CSS isolation.\n * Set to false if you want to manage CSS specificity yourself.\n * @default true\n */\n isolated?: boolean\n}\n\n/**\n * Optional provider component for Spectral components.\n * Provides CSS isolation when needed to prevent style conflicts.\n *\n * @example\n * ```tsx\n * // With isolation (recommended for apps with conflicting styles)\n * <SpectralProvider>\n * <Button>Click me</Button>\n * </SpectralProvider>\n *\n * // Without wrapper (when you have full control over styles)\n * <SpectralProvider isolated={false}>\n * <Button>Click me</Button>\n * </SpectralProvider>\n * ```\n */\nexport const SpectralProvider: FC<SpectralProviderProps> = ({ children, className = '', isolated = true }) => {\n if (!isolated) {\n return <>{children}</>\n }\n\n return <div className={`spectral-root ${className}`}>{children}</div>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,MAAa,oBAA+C,EAAE,UAAU,YAAY,IAAI,WAAW,WAAW;AAC5G,KAAI,CAAC,SACH,QAAO,kCAAG,UAAY;AAGxB,QAAO,oBAAC,OAAD;EAAK,WAAW,iBAAiB;EAAc;EAAe"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { cloneElement, isValidElement } from "react";
3
- import { Fragment, jsx } from "react/jsx-runtime";
3
+ import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
4
4
 
5
5
  //#region src/primitives/slot.tsx
6
6
  const composeEventHandlers = (childHandler, slotHandler, { checkForDefaultPrevented = true } = {}) => {
@@ -19,7 +19,7 @@ const mergeRefs = (...refs) => {
19
19
  };
20
20
  };
21
21
  const Slottable = (props) => {
22
- return /* @__PURE__ */ jsx(Fragment, { children: props.children });
22
+ return /* @__PURE__ */ jsx(Fragment$1, { children: props.children });
23
23
  };
24
24
  const Slot = function Slot({ children, ref: forwardedRef, ...slotProps }) {
25
25
  if (!isValidElement(children)) {
@@ -1 +1 @@
1
- {"version":3,"file":"slot.js","names":[],"sources":["../../src/primitives/slot.tsx"],"sourcesContent":["import { cloneElement, isValidElement, type CSSProperties, type HTMLAttributes, type ReactElement, type ReactNode, type Ref, type SyntheticEvent } from 'react'\n\nconst composeEventHandlers = <E extends SyntheticEvent>(childHandler?: (event: E) => void, slotHandler?: (event: E) => void, { checkForDefaultPrevented = true } = {}): ((event: E) => void) => {\n return (event: E) => {\n childHandler?.(event)\n if (!checkForDefaultPrevented || !event.defaultPrevented) {\n slotHandler?.(event)\n }\n }\n}\n\nconst mergeRefs = <T,>(...refs: (Ref<T> | undefined)[]) => {\n return (node: T) => {\n for (const ref of refs) {\n if (!ref) continue\n if (typeof ref === 'function') {\n ref(node)\n } else if (typeof ref === 'object' && 'current' in ref) {\n ;(ref as { current: T | null }).current = node\n }\n }\n }\n}\n\ntype SlotBaseProps = HTMLAttributes<HTMLElement> & {\n children?: ReactNode\n}\n\nexport const Slottable = (props: { children?: ReactNode }) => {\n return <>{props.children}</>\n}\n\nexport const Slot = function Slot({\n children,\n ref: forwardedRef,\n ...slotProps\n}: SlotBaseProps & {\n ref?: Ref<HTMLElement>\n}) {\n if (!isValidElement(children)) {\n if (children === null || children === undefined) return null\n\n return <span {...slotProps} ref={forwardedRef as Ref<HTMLSpanElement>} />\n }\n\n const child = children as ReactElement<Record<string, unknown>>\n const childProps = child.props ?? {}\n\n const mergedProps: Record<string, unknown> = { ...childProps, ...slotProps }\n\n for (const [key, value] of Object.entries(slotProps)) {\n const isEvent = key.startsWith('on') && typeof value === 'function'\n if (isEvent) {\n const childHandler = (childProps as Record<string, unknown>)[key]\n if (typeof childHandler === 'function') {\n ;(mergedProps as Record<string, unknown>)[key] = composeEventHandlers(childHandler as (e: SyntheticEvent) => void, value as (e: SyntheticEvent) => void)\n } else {\n ;(mergedProps as Record<string, unknown>)[key] = value as (e: SyntheticEvent) => void\n }\n }\n }\n\n const childClassName = (childProps['className'] as string | undefined) || ''\n if (childClassName && slotProps.className) {\n ;(mergedProps as Record<string, unknown>).className = `${childClassName} ${slotProps.className}`\n }\n\n const childStyle = childProps['style'] as CSSProperties | undefined\n if (childStyle && slotProps.style) {\n ;(mergedProps as Record<string, unknown>).style = { ...childStyle, ...slotProps.style }\n }\n\n const childRef = (child as unknown as { ref?: Ref<HTMLElement> }).ref\n ;(mergedProps as Record<string, unknown>).ref = mergeRefs(childRef, forwardedRef)\n\n return cloneElement(child, mergedProps as Partial<typeof child.props>)\n}\nSlot.displayName = 'Slot'\n\nexport interface AsChildProp {\n asChild?: boolean\n}\n"],"mappings":";;;;;AAEA,MAAM,wBAAkD,cAAmC,aAAkC,EAAE,2BAA2B,SAAS,EAAE,KAA2B;AAC9L,SAAQ,UAAa;AACnB,iBAAe,MAAM;AACrB,MAAI,CAAC,4BAA4B,CAAC,MAAM,iBACtC,eAAc,MAAM;;;AAK1B,MAAM,aAAiB,GAAG,SAAiC;AACzD,SAAQ,SAAY;AAClB,OAAK,MAAM,OAAO,MAAM;AACtB,OAAI,CAAC,IAAK;AACV,OAAI,OAAO,QAAQ,WACjB,KAAI,KAAK;YACA,OAAO,QAAQ,YAAY,aAAa,IAChD,CAAC,IAA8B,UAAU;;;;AAUlD,MAAa,aAAa,UAAoC;AAC5D,QAAO,0CAAG,MAAM,UAAY;;AAG9B,MAAa,OAAO,SAAS,KAAK,EAChC,UACA,KAAK,cACL,GAAG,aAGF;AACD,KAAI,CAAC,eAAe,SAAS,EAAE;AAC7B,MAAI,aAAa,QAAQ,aAAa,OAAW,QAAO;AAExD,SAAO,oBAAC,QAAD;GAAM,GAAI;GAAW,KAAK;GAAwC;;CAG3E,MAAM,QAAQ;CACd,MAAM,aAAa,MAAM,SAAS,EAAE;CAEpC,MAAM,cAAuC;EAAE,GAAG;EAAY,GAAG;EAAW;AAE5E,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,UAAU,CAElD,KADgB,IAAI,WAAW,KAAK,IAAI,OAAO,UAAU,YAC5C;EACX,MAAM,eAAgB,WAAuC;AAC7D,MAAI,OAAO,iBAAiB,WACzB,CAAC,YAAwC,OAAO,qBAAqB,cAA6C,MAAqC;MAEvJ,CAAC,YAAwC,OAAO;;CAKvD,MAAM,iBAAkB,WAAW,gBAAuC;AAC1E,KAAI,kBAAkB,UAAU,UAC7B,CAAC,YAAwC,YAAY,GAAG,eAAe,GAAG,UAAU;CAGvF,MAAM,aAAa,WAAW;AAC9B,KAAI,cAAc,UAAU,MACzB,CAAC,YAAwC,QAAQ;EAAE,GAAG;EAAY,GAAG,UAAU;EAAO;CAGzF,MAAM,WAAY,MAAgD;AACjE,CAAC,YAAwC,MAAM,UAAU,UAAU,aAAa;AAEjF,QAAO,aAAa,OAAO,YAA2C;;AAExE,KAAK,cAAc"}
1
+ {"version":3,"file":"slot.js","names":[],"sources":["../../src/primitives/slot.tsx"],"sourcesContent":["import { cloneElement, isValidElement, type CSSProperties, type HTMLAttributes, type ReactElement, type ReactNode, type Ref, type SyntheticEvent } from 'react'\n\nconst composeEventHandlers = <E extends SyntheticEvent>(childHandler?: (event: E) => void, slotHandler?: (event: E) => void, { checkForDefaultPrevented = true } = {}): ((event: E) => void) => {\n return (event: E) => {\n childHandler?.(event)\n if (!checkForDefaultPrevented || !event.defaultPrevented) {\n slotHandler?.(event)\n }\n }\n}\n\nconst mergeRefs = <T,>(...refs: (Ref<T> | undefined)[]) => {\n return (node: T) => {\n for (const ref of refs) {\n if (!ref) continue\n if (typeof ref === 'function') {\n ref(node)\n } else if (typeof ref === 'object' && 'current' in ref) {\n ;(ref as { current: T | null }).current = node\n }\n }\n }\n}\n\ntype SlotBaseProps = HTMLAttributes<HTMLElement> & {\n children?: ReactNode\n}\n\nexport const Slottable = (props: { children?: ReactNode }) => {\n return <>{props.children}</>\n}\n\nexport const Slot = function Slot({\n children,\n ref: forwardedRef,\n ...slotProps\n}: SlotBaseProps & {\n ref?: Ref<HTMLElement>\n}) {\n if (!isValidElement(children)) {\n if (children === null || children === undefined) return null\n\n return <span {...slotProps} ref={forwardedRef as Ref<HTMLSpanElement>} />\n }\n\n const child = children as ReactElement<Record<string, unknown>>\n const childProps = child.props ?? {}\n\n const mergedProps: Record<string, unknown> = { ...childProps, ...slotProps }\n\n for (const [key, value] of Object.entries(slotProps)) {\n const isEvent = key.startsWith('on') && typeof value === 'function'\n if (isEvent) {\n const childHandler = (childProps as Record<string, unknown>)[key]\n if (typeof childHandler === 'function') {\n ;(mergedProps as Record<string, unknown>)[key] = composeEventHandlers(childHandler as (e: SyntheticEvent) => void, value as (e: SyntheticEvent) => void)\n } else {\n ;(mergedProps as Record<string, unknown>)[key] = value as (e: SyntheticEvent) => void\n }\n }\n }\n\n const childClassName = (childProps['className'] as string | undefined) || ''\n if (childClassName && slotProps.className) {\n ;(mergedProps as Record<string, unknown>).className = `${childClassName} ${slotProps.className}`\n }\n\n const childStyle = childProps['style'] as CSSProperties | undefined\n if (childStyle && slotProps.style) {\n ;(mergedProps as Record<string, unknown>).style = { ...childStyle, ...slotProps.style }\n }\n\n const childRef = (child as unknown as { ref?: Ref<HTMLElement> }).ref\n ;(mergedProps as Record<string, unknown>).ref = mergeRefs(childRef, forwardedRef)\n\n return cloneElement(child, mergedProps as Partial<typeof child.props>)\n}\nSlot.displayName = 'Slot'\n\nexport interface AsChildProp {\n asChild?: boolean\n}\n"],"mappings":";;;;;AAEA,MAAM,wBAAkD,cAAmC,aAAkC,EAAE,2BAA2B,SAAS,EAAE,KAA2B;AAC9L,SAAQ,UAAa;AACnB,iBAAe,MAAM;AACrB,MAAI,CAAC,4BAA4B,CAAC,MAAM,iBACtC,eAAc,MAAM;;;AAK1B,MAAM,aAAiB,GAAG,SAAiC;AACzD,SAAQ,SAAY;AAClB,OAAK,MAAM,OAAO,MAAM;AACtB,OAAI,CAAC,IAAK;AACV,OAAI,OAAO,QAAQ,WACjB,KAAI,KAAK;YACA,OAAO,QAAQ,YAAY,aAAa,IAChD,CAAC,IAA8B,UAAU;;;;AAUlD,MAAa,aAAa,UAAoC;AAC5D,QAAO,4CAAG,MAAM,UAAY;;AAG9B,MAAa,OAAO,SAAS,KAAK,EAChC,UACA,KAAK,cACL,GAAG,aAGF;AACD,KAAI,CAAC,eAAe,SAAS,EAAE;AAC7B,MAAI,aAAa,QAAQ,aAAa,OAAW,QAAO;AAExD,SAAO,oBAAC,QAAD;GAAM,GAAI;GAAW,KAAK;GAAwC;;CAG3E,MAAM,QAAQ;CACd,MAAM,aAAa,MAAM,SAAS,EAAE;CAEpC,MAAM,cAAuC;EAAE,GAAG;EAAY,GAAG;EAAW;AAE5E,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,UAAU,CAElD,KADgB,IAAI,WAAW,KAAK,IAAI,OAAO,UAAU,YAC5C;EACX,MAAM,eAAgB,WAAuC;AAC7D,MAAI,OAAO,iBAAiB,WACzB,CAAC,YAAwC,OAAO,qBAAqB,cAA6C,MAAqC;MAEvJ,CAAC,YAAwC,OAAO;;CAKvD,MAAM,iBAAkB,WAAW,gBAAuC;AAC1E,KAAI,kBAAkB,UAAU,UAC7B,CAAC,YAAwC,YAAY,GAAG,eAAe,GAAG,UAAU;CAGvF,MAAM,aAAa,WAAW;AAC9B,KAAI,cAAc,UAAU,MACzB,CAAC,YAAwC,QAAQ;EAAE,GAAG;EAAY,GAAG,UAAU;EAAO;CAGzF,MAAM,WAAY,MAAgD;AACjE,CAAC,YAAwC,MAAM,UAAU,UAAU,aAAa;AAEjF,QAAO,aAAa,OAAO,YAA2C;;AAExE,KAAK,cAAc"}