@yamada-ui/autocomplete 2.0.0-next-20240613232518 → 2.0.0-next-20240615222442

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,"sources":["../src/autocomplete-option.tsx","../src/autocomplete-icon.tsx","../src/use-autocomplete.tsx"],"sourcesContent":["import type { CSSUIObject } from \"@yamada-ui/core\"\nimport { ui, forwardRef } from \"@yamada-ui/core\"\nimport { cx } from \"@yamada-ui/utils\"\nimport type { FC, ReactElement } from \"react\"\nimport { AutocompleteItemIcon } from \"./autocomplete-icon\"\nimport type { UseAutocompleteOptionProps } from \"./use-autocomplete\"\nimport {\n useAutocompleteContext,\n useAutocompleteOption,\n} from \"./use-autocomplete\"\n\ntype AutocompleteOptionOptions = {\n /**\n * The autocomplete option icon to use.\n */\n icon?: ReactElement\n}\n\nexport type AutocompleteOptionProps = UseAutocompleteOptionProps &\n AutocompleteOptionOptions\n\nexport const AutocompleteOption = forwardRef<AutocompleteOptionProps, \"li\">(\n ({ className, icon, ...rest }, ref) => {\n const { styles } = useAutocompleteContext()\n const { isSelected, customIcon, children, getOptionProps } =\n useAutocompleteOption(rest)\n\n icon ??= customIcon\n\n const css: CSSUIObject = {\n ...styles.item,\n }\n\n return (\n <ui.li\n className={cx(\"ui-autocomplete__item\", className)}\n __css={css}\n {...getOptionProps({}, ref)}\n >\n {icon !== null ? (\n <AutocompleteItemIcon opacity={isSelected ? 1 : 0}>\n {icon || <CheckIcon />}\n </AutocompleteItemIcon>\n ) : null}\n\n <ui.span style={{ flex: 1 }} data-label>\n {children}\n </ui.span>\n </ui.li>\n )\n },\n)\n\nconst CheckIcon: FC = () => (\n <svg viewBox=\"0 0 14 14\" width=\"1em\" height=\"1em\">\n <polygon\n fill=\"currentColor\"\n points=\"5.5 11.9993304 14 3.49933039 12.5 2 5.5 8.99933039 1.5 4.9968652 0 6.49933039\"\n />\n </svg>\n)\n","import type { CSSUIObject, HTMLUIProps } from \"@yamada-ui/core\"\nimport { ui, forwardRef } from \"@yamada-ui/core\"\nimport { ChevronIcon, CloseIcon } from \"@yamada-ui/icon\"\nimport { useClickable } from \"@yamada-ui/use-clickable\"\nimport { cx, getValidChildren, isValidElement } from \"@yamada-ui/utils\"\nimport type { FC, HTMLAttributes } from \"react\"\nimport { cloneElement, useRef } from \"react\"\nimport { useAutocompleteContext } from \"./use-autocomplete\"\n\nexport type AutocompleteIconProps = HTMLUIProps<\"div\">\n\nexport const AutocompleteIcon = forwardRef<AutocompleteIconProps, \"div\">(\n ({ className, children, __css, ...rest }, ref) => {\n const { styles } = useAutocompleteContext()\n\n const css: CSSUIObject = {\n ...styles.icon,\n ...__css,\n }\n\n const validChildren = getValidChildren(children)\n\n const cloneChildren = validChildren.map((child) =>\n cloneElement(child, {\n focusable: false,\n \"aria-hidden\": true,\n style: {\n maxWidth: \"1em\",\n maxHeight: \"1em\",\n color: \"currentColor\",\n },\n }),\n )\n\n return (\n <ui.div\n ref={ref}\n className={cx(\"ui-autocomplete__icon\", className)}\n __css={css}\n {...rest}\n >\n {isValidElement(children) ? cloneChildren : <ChevronIcon />}\n </ui.div>\n )\n },\n)\n\nexport type AutocompleteClearIconProps = AutocompleteIconProps & {\n disabled?: boolean\n}\n\nexport const AutocompleteClearIcon: FC<AutocompleteClearIconProps> = ({\n className,\n children,\n ...props\n}) => {\n const ref = useRef<HTMLDivElement>(null)\n const { styles } = useAutocompleteContext()\n\n const isDisabled = props.disabled\n\n const rest = useClickable({\n ref,\n isDisabled,\n ...(props as HTMLAttributes<HTMLElement>),\n })\n\n return (\n <AutocompleteIcon\n aria-label=\"Clear value\"\n className={cx(\"ui-autocomplete__icon--clear\", className)}\n __css={styles.clearIcon}\n {...rest}\n >\n {children ?? <CloseIcon w=\"0.5em\" h=\"0.5em\" />}\n </AutocompleteIcon>\n )\n}\n\nexport type AutocompleteItemIconProps = HTMLUIProps<\"span\">\n\nexport const AutocompleteItemIcon = forwardRef<\n AutocompleteItemIconProps,\n \"span\"\n>(({ className, ...rest }, ref) => {\n const { styles } = useAutocompleteContext()\n\n const css: CSSUIObject = {\n ...styles.itemIcon,\n }\n\n return (\n <ui.span\n ref={ref}\n className={cx(\"ui-autocomplete__item-icon\", className)}\n __css={css}\n {...rest}\n />\n )\n})\n","import type { CSSUIObject, HTMLUIProps, UIPropGetter } from \"@yamada-ui/core\"\nimport { layoutStyleProperties } from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\nimport {\n formControlProperties,\n useFormControlProps,\n} from \"@yamada-ui/form-control\"\nimport type { MotionUIPropGetter } from \"@yamada-ui/motion\"\nimport { popoverProperties, type PopoverProps } from \"@yamada-ui/popover\"\nimport { useControllableState } from \"@yamada-ui/use-controllable-state\"\nimport { createDescendant } from \"@yamada-ui/use-descendant\"\nimport { useDisclosure } from \"@yamada-ui/use-disclosure\"\nimport { useOutsideClick } from \"@yamada-ui/use-outside-click\"\nimport type { Dict, Union, DOMAttributes } from \"@yamada-ui/utils\"\nimport {\n ariaAttr,\n createContext,\n dataAttr,\n funcAll,\n getEventRelatedTarget,\n handlerAll,\n isArray,\n isContains,\n isHTMLElement,\n mergeRefs,\n omitObject,\n pickObject,\n splitObject,\n useUnmountEffect,\n useUpdateEffect,\n getValidChildren,\n isUndefined,\n} from \"@yamada-ui/utils\"\nimport type {\n ChangeEvent,\n CSSProperties,\n Dispatch,\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n RefObject,\n SetStateAction,\n} from \"react\"\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\nimport type { AutocompleteOptionProps } from \"./\"\nimport { AutocompleteOption, AutocompleteOptionGroup } from \"./\"\n\ntype AutocompleteBaseItem = Omit<\n AutocompleteOptionProps,\n \"value\" | \"children\"\n> & {\n label?: string\n}\n\ntype AutocompleteItemWithValue = AutocompleteBaseItem & {\n value?: string\n}\n\ntype AutocompleteItemWithItems = AutocompleteBaseItem & {\n items?: AutocompleteItemWithValue[]\n}\n\nexport type AutocompleteItem =\n | AutocompleteItemWithValue\n | AutocompleteItemWithItems\n\nconst kanaMap: Record<string, string> = {\n ガ: \"ガ\",\n ギ: \"ギ\",\n グ: \"グ\",\n ゲ: \"ゲ\",\n ゴ: \"ゴ\",\n ザ: \"ザ\",\n ジ: \"ジ\",\n ズ: \"ズ\",\n ゼ: \"ゼ\",\n ゾ: \"ゾ\",\n ダ: \"ダ\",\n ヂ: \"ヂ\",\n ヅ: \"ヅ\",\n デ: \"デ\",\n ド: \"ド\",\n バ: \"バ\",\n ビ: \"ビ\",\n ブ: \"ブ\",\n ベ: \"ベ\",\n ボ: \"ボ\",\n パ: \"パ\",\n ピ: \"ピ\",\n プ: \"プ\",\n ペ: \"ペ\",\n ポ: \"ポ\",\n ヴ: \"ヴ\",\n ヷ: \"ヷ\",\n ヺ: \"ヺ\",\n ア: \"ア\",\n イ: \"イ\",\n ウ: \"ウ\",\n エ: \"エ\",\n オ: \"オ\",\n カ: \"カ\",\n キ: \"キ\",\n ク: \"ク\",\n ケ: \"ケ\",\n コ: \"コ\",\n サ: \"サ\",\n シ: \"シ\",\n ス: \"ス\",\n セ: \"セ\",\n ソ: \"ソ\",\n タ: \"タ\",\n チ: \"チ\",\n ツ: \"ツ\",\n テ: \"テ\",\n ト: \"ト\",\n ナ: \"ナ\",\n ニ: \"ニ\",\n ヌ: \"ヌ\",\n ネ: \"ネ\",\n ノ: \"ノ\",\n ハ: \"ハ\",\n ヒ: \"ヒ\",\n フ: \"フ\",\n ヘ: \"ヘ\",\n ホ: \"ホ\",\n マ: \"マ\",\n ミ: \"ミ\",\n ム: \"ム\",\n メ: \"メ\",\n モ: \"モ\",\n ヤ: \"ヤ\",\n ユ: \"ユ\",\n ヨ: \"ヨ\",\n ラ: \"ラ\",\n リ: \"リ\",\n ル: \"ル\",\n レ: \"レ\",\n ロ: \"ロ\",\n ワ: \"ワ\",\n ヲ: \"ヲ\",\n ン: \"ン\",\n ァ: \"ァ\",\n ィ: \"ィ\",\n ゥ: \"ゥ\",\n ェ: \"ェ\",\n ォ: \"ォ\",\n ッ: \"ッ\",\n ャ: \"ャ\",\n ュ: \"ュ\",\n ョ: \"ョ\",\n \"。\": \"。\",\n \"、\": \"、\",\n ー: \"ー\",\n \"「\": \"「\",\n \"」\": \"」\",\n \"・\": \"・\",\n}\n\nconst defaultFormat = (value: string) => {\n value = value.replace(/[!-~]/g, (v) =>\n String.fromCharCode(v.charCodeAt(0) - 0xfee0),\n )\n\n const reg = new RegExp(\"(\" + Object.keys(kanaMap).join(\"|\") + \")\", \"g\")\n\n value = value\n .replace(reg, (v) => kanaMap[v])\n .replace(/゙/g, \"゛\")\n .replace(/゚/g, \"゜\")\n\n value = value.toUpperCase()\n\n return value\n}\n\nconst flattenItems = (\n items: AutocompleteItem[],\n): AutocompleteItemWithValue[] => {\n const filterItems = (\n items: AutocompleteItem[] | AutocompleteItemWithValue[],\n ): (AutocompleteItemWithValue | AutocompleteItemWithValue[])[] =>\n items\n .map((item) => {\n const { isDisabled, isFocusable } = item\n const trulyDisabled = !!isDisabled && !isFocusable\n\n if (trulyDisabled) return\n\n if (\"items\" in item) {\n return filterItems(item.items ?? [])\n } else {\n return item as AutocompleteItemWithValue\n }\n })\n .filter(Boolean) as (\n | AutocompleteItemWithValue\n | AutocompleteItemWithValue[]\n )[]\n\n return filterItems(items).flat(Infinity) as AutocompleteItemWithValue[]\n}\n\nconst isTargetOption = (target: EventTarget | null): boolean =>\n isHTMLElement(target) &&\n !!target?.getAttribute(\"role\")?.startsWith(\"autocomplete-item\")\n\nexport const {\n DescendantsContextProvider: AutocompleteDescendantsContextProvider,\n useDescendantsContext: useAutocompleteDescendantsContext,\n useDescendants: useAutocompleteDescendants,\n useDescendant: useAutocompleteDescendant,\n} = createDescendant<HTMLElement>()\n\ntype AutocompleteContext = Omit<\n UseAutocompleteProps,\n \"value\" | \"defaultValue\" | \"onChange\" | \"onCreate\"\n> & {\n value: string | string[]\n label: string | string[] | undefined\n inputValue: string\n isHit: boolean\n isEmpty: boolean\n isAllSelected: boolean\n onChange: (newValue: string) => void\n onChangeLabel: (newValue: string, runOmit?: boolean) => void\n pickOptions: (value: string) => void\n rebirthOptions: (runFocus?: boolean) => void\n inputProps: DOMAttributes\n isOpen: boolean\n onOpen: () => void\n onClose: () => void\n onCreate: () => void\n onFocusFirst: () => void\n onFocusLast: () => void\n onFocusNext: (index?: number) => void\n onFocusPrev: (index?: number) => void\n focusedIndex: number\n setFocusedIndex: Dispatch<SetStateAction<number>>\n listRef: RefObject<HTMLUListElement>\n inputRef: RefObject<HTMLInputElement>\n formControlProps: Record<string, any>\n styles: Record<string, CSSUIObject>\n}\n\nexport const [AutocompleteProvider, useAutocompleteContext] =\n createContext<AutocompleteContext>({\n name: \"AutocompleteContext\",\n errorMessage: `useAutocompleteContext returned is 'undefined'. Seems you forgot to wrap the components in \"<Autocomplete />\" or \"<MultiAutocomplete />\"`,\n })\n\ntype UseAutocompleteBaseProps<T extends string | string[] = string> = Omit<\n PopoverProps,\n | \"initialFocusRef\"\n | \"closeOnButton\"\n | \"trigger\"\n | \"autoFocus\"\n | \"restoreFocus\"\n | \"openDelay\"\n | \"closeDelay\"\n> &\n FormControlOptions & {\n /**\n * The value of the autocomplete.\n */\n value?: T\n /**\n * The initial value of the autocomplete.\n */\n defaultValue?: T\n /**\n * The callback invoked when value state changes.\n */\n onChange?: (value: T) => void\n /**\n * The callback invoked when search input.\n */\n onSearch?: (ev: ChangeEvent<HTMLInputElement>) => void\n /**\n * The callback invoked when autocomplete option created.\n */\n onCreate?: (newItem: AutocompleteItem, newItems: AutocompleteItem[]) => void\n /**\n * Function to format text when search input.\n */\n format?: (value: string) => string\n /**\n * The position to be inserted when the autocomplete option is created.\n *\n * @default 'first'\n */\n insertPositionItem?: Union<\"first\" | \"last\"> | [string, \"first\" | \"last\"]\n /**\n * If `true`, the list element will be closed when value is selected.\n *\n * @default true\n */\n closeOnSelect?: boolean\n /**\n * The message displayed when the search yields no hits.\n *\n * @default 'No results found'\n */\n emptyMessage?: string\n /**\n * If `true`, enables the creation of autocomplete option.\n *\n * @default false\n */\n allowCreate?: boolean\n /**\n * If `true`, enables the free input.\n */\n allowFree?: boolean\n /**\n * If `true`, the selected item(s) will be excluded from the list.\n *\n * @default false\n */\n omitSelectedValues?: boolean\n /**\n * The maximum selectable value.\n */\n maxSelectValues?: number\n /**\n * Props for select option element.\n */\n optionProps?: Omit<AutocompleteOptionProps, \"value\" | \"children\">\n /**\n * If provided, generate options based on items.\n */\n items?: AutocompleteItem[]\n }\n\nexport type UseAutocompleteProps<T extends string | string[] = string> = Omit<\n HTMLUIProps<\"input\">,\n | keyof UseAutocompleteBaseProps\n | \"list\"\n | \"disabled\"\n | \"required\"\n | \"readOnly\"\n | \"size\"\n> &\n UseAutocompleteBaseProps<T>\n\nexport const useAutocomplete = <T extends string | string[] = string>({\n value: valueProp,\n defaultValue,\n onChange: onChangeProp,\n onCreate: onCreateProp,\n onSearch: onSearchProp,\n closeOnSelect = true,\n omitSelectedValues = false,\n maxSelectValues,\n closeOnBlur = true,\n closeOnEsc = true,\n allowCreate = false,\n allowFree = false,\n insertPositionItem = \"first\",\n emptyMessage = \"No results found\",\n format = defaultFormat,\n placement = \"bottom-start\",\n duration = 0.2,\n optionProps,\n placeholder,\n items,\n children,\n isOpen: isOpenProp,\n defaultIsOpen,\n onOpen: onOpenProp,\n onClose: onCloseProp,\n ...rest\n}: UseAutocompleteProps<T>) => {\n rest = useFormControlProps(rest)\n\n const { id } = rest\n\n const { \"aria-readonly\": _ariaReadonly, ...formControlProps } = pickObject(\n rest,\n formControlProperties,\n )\n const [containerProps, inputProps] = splitObject<Dict, string>(\n omitObject(rest, [...popoverProperties, \"onKeyDown\", \"onFocus\"]),\n layoutStyleProperties,\n )\n\n const descendants = useAutocompleteDescendants()\n\n const containerRef = useRef<HTMLDivElement>(null)\n const listRef = useRef<HTMLUListElement>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const timeoutIds = useRef<Set<any>>(new Set([]))\n const isComposition = useRef<boolean>(false)\n const prevValue = useRef<T | undefined>(undefined)\n\n const [resolvedItems, setResolvedItems] = useState<\n AutocompleteItem[] | undefined\n >(items ? JSON.parse(JSON.stringify(items)) : undefined)\n const [value, setValue] = useControllableState({\n value: valueProp,\n defaultValue,\n onChange: onChangeProp,\n })\n const [label, setLabel] = useState<T | undefined>(undefined)\n const [inputValue, setInputValue] = useState<string>(\"\")\n const [focusedIndex, setFocusedIndex] = useState<number>(-1)\n const [isAllSelected, setIsAllSelected] = useState<boolean>(false)\n const [isHit, setIsHit] = useState<boolean>(true)\n const {\n isOpen,\n onOpen: onInternalOpen,\n onClose,\n } = useDisclosure({\n isOpen: isOpenProp,\n defaultIsOpen,\n onOpen: onOpenProp,\n onClose: onCloseProp,\n })\n const isFocused = focusedIndex > -1\n const isCreate = focusedIndex === -2 && allowCreate\n const isMulti = isArray(value)\n const isEmptyValue = !isMulti ? !value : !value.length\n\n const [firstInsertPositionItem, secondInsertPositionItem] = useMemo(() => {\n if (isArray(insertPositionItem)) {\n return insertPositionItem\n } else {\n return [insertPositionItem, \"first\"]\n }\n }, [insertPositionItem])\n\n if (allowCreate && !isUndefined(children)) {\n console.warn(\n `${!isMulti ? \"Autocomplete\" : \"MultiAutocomplete\"}: ${\n !isMulti ? \"Autocomplete\" : \"MultiAutocomplete\"\n } internally prefers 'children'. If 'allowCreate' is true, it will not be reflected correctly. If want to reflect, please set 'items' in props.`,\n )\n }\n\n const selectedValues = descendants.enabledValues(\n ({ node }) => isMulti && value.includes(node.dataset.value ?? \"\"),\n )\n const selectedIndexes = selectedValues.map(({ index }) => index)\n const enabledValues = descendants.enabledValues(\n ({ node, index }) =>\n \"target\" in node.dataset && !selectedIndexes.includes(index),\n )\n\n const validChildren = getValidChildren(children)\n\n const computedChildren = resolvedItems?.map((item, i) => {\n if (\"value\" in item) {\n const { label, value, ...props } = item\n\n return (\n <AutocompleteOption key={i} value={value} {...props}>\n {label}\n </AutocompleteOption>\n )\n } else if (\"items\" in item) {\n const { label, items = [], ...props } = item\n\n return (\n <AutocompleteOptionGroup\n key={i}\n label={label as string}\n {...(props as HTMLUIProps<\"ul\">)}\n >\n {items.map(({ label, value, ...props }, i) => (\n <AutocompleteOption key={i} value={value} {...props}>\n {label}\n </AutocompleteOption>\n ))}\n </AutocompleteOptionGroup>\n )\n }\n })\n\n const isEmpty = !validChildren.length && !computedChildren?.length\n\n const onOpen = useCallback(() => {\n if (formControlProps.disabled || formControlProps.readOnly) return\n\n if (!allowCreate && (isEmpty || isAllSelected)) return\n\n onInternalOpen()\n\n if (inputRef.current) inputRef.current.focus()\n }, [allowCreate, formControlProps, isAllSelected, isEmpty, onInternalOpen])\n\n const onFocusFirst = useCallback(() => {\n const id = setTimeout(() => {\n if (isEmpty || isAllSelected) return\n\n const first = descendants.enabledFirstValue(\n ({ node }) => \"target\" in node.dataset,\n )\n\n if (!first) return\n\n if (!isMulti || !omitSelectedValues) {\n setFocusedIndex(first.index)\n } else {\n if (selectedIndexes.includes(first.index)) {\n const enabledFirst = enabledValues[0]\n\n setFocusedIndex(enabledFirst.index)\n } else {\n setFocusedIndex(first.index)\n }\n }\n })\n\n timeoutIds.current.add(id)\n }, [\n descendants,\n enabledValues,\n isAllSelected,\n isEmpty,\n isMulti,\n omitSelectedValues,\n selectedIndexes,\n ])\n\n const onFocusLast = useCallback(() => {\n const id = setTimeout(() => {\n if (isEmpty || isAllSelected) return\n\n const last = descendants.enabledLastValue(\n ({ node }) => \"target\" in node.dataset,\n )\n\n if (!last) return\n\n if (!isMulti || !omitSelectedValues) {\n setFocusedIndex(last.index)\n } else {\n if (selectedIndexes.includes(last.index)) {\n const enabledLast = enabledValues.reverse()[0]\n\n setFocusedIndex(enabledLast.index)\n } else {\n setFocusedIndex(last.index)\n }\n }\n })\n\n timeoutIds.current.add(id)\n }, [\n descendants,\n enabledValues,\n isAllSelected,\n isEmpty,\n isMulti,\n omitSelectedValues,\n selectedIndexes,\n ])\n\n const onFocusSelected = useCallback(() => {\n const id = setTimeout(() => {\n const values = descendants.enabledValues()\n\n const selected = values.find(({ node }) =>\n !isMulti\n ? node.dataset.value === value\n : value.includes(node.dataset.value ?? \"\"),\n )\n\n if (selected) setFocusedIndex(selected.index)\n })\n\n timeoutIds.current.add(id)\n }, [descendants, isMulti, value])\n\n const onFocusNext = useCallback(\n (index: number = focusedIndex) => {\n const id = setTimeout(() => {\n const next = descendants.enabledNextValue(\n index,\n ({ node }) => \"target\" in node.dataset,\n )\n\n if (!next) return\n\n if (!isMulti || !omitSelectedValues) {\n setFocusedIndex(next.index)\n } else {\n if (selectedIndexes.includes(next.index)) {\n const enabledNext =\n enabledValues.find(({ index }) => next.index < index) ??\n enabledValues[0]\n\n setFocusedIndex(enabledNext.index)\n } else {\n setFocusedIndex(next.index)\n }\n }\n })\n\n timeoutIds.current.add(id)\n },\n [\n descendants,\n enabledValues,\n focusedIndex,\n isMulti,\n omitSelectedValues,\n selectedIndexes,\n ],\n )\n\n const onFocusPrev = useCallback(\n (index: number = focusedIndex) => {\n const id = setTimeout(() => {\n const prev = descendants.enabledPrevValue(\n index,\n ({ node }) => \"target\" in node.dataset,\n )\n\n if (!prev) return\n\n if (!isMulti || !omitSelectedValues) {\n setFocusedIndex(prev.index)\n } else {\n if (selectedIndexes.includes(prev.index)) {\n const enabledPrev =\n enabledValues.reverse().find(({ index }) => index < prev.index) ??\n enabledValues[0]\n\n setFocusedIndex(enabledPrev.index)\n } else {\n setFocusedIndex(prev.index)\n }\n }\n })\n\n timeoutIds.current.add(id)\n },\n [\n descendants,\n enabledValues,\n focusedIndex,\n isMulti,\n omitSelectedValues,\n selectedIndexes,\n ],\n )\n\n const onFocusFirstOrSelected =\n isEmptyValue || omitSelectedValues ? onFocusFirst : onFocusSelected\n const onFocusLastOrSelected =\n isEmptyValue || omitSelectedValues ? onFocusLast : onFocusSelected\n\n const pickOptions = useCallback(\n (value: string) => {\n const values = descendants.values()\n\n let isHit = false\n let isFocused = false\n\n values.forEach(({ node, index }) => {\n if (format(node.textContent ?? \"\").includes(value)) {\n isHit = true\n\n const isDisabled = \"disabled\" in node.dataset\n\n node.dataset.target = \"\"\n\n if (!isFocused && !isDisabled) {\n isFocused = true\n\n setFocusedIndex(index)\n }\n } else {\n delete node.dataset.target\n }\n })\n\n setIsHit(isHit)\n },\n [descendants, format],\n )\n\n const rebirthOptions = useCallback(\n (runFocus = true) => {\n const values = descendants.values()\n\n values.forEach(({ node }) => {\n node.dataset.target = \"\"\n })\n\n if (runFocus) onFocusFirst()\n\n setIsHit(true)\n },\n [descendants, onFocusFirst],\n )\n\n const getSelectedValues = useCallback(\n (newValues: string | string[]) => {\n const enabledValues = descendants.enabledValues()\n\n const resolvedValues = isArray(newValues) ? newValues : [newValues]\n\n const selectedValues = resolvedValues\n .map((value) => {\n const { node } =\n enabledValues.find(({ node }) => node.dataset.value === value) ?? {}\n\n if (node) {\n const el = Array.from(node.children).find(\n (child) => child.getAttribute(\"data-label\") !== null,\n )\n\n return el?.textContent ?? undefined\n } else {\n return allowFree ? value : undefined\n }\n })\n .filter(Boolean) as string[]\n\n return selectedValues\n },\n [allowFree, descendants],\n )\n\n const onChangeLabel = useCallback(\n (newValue: string, runOmit: boolean = true) => {\n const selectedValues = getSelectedValues(newValue)\n\n setLabel((prev) => {\n if (!isMulti) {\n return selectedValues[0] as T\n } else {\n selectedValues.forEach((selectedValue) => {\n const isSelected =\n isArray(prev) && prev.includes(selectedValue ?? \"\")\n\n if (!isSelected) {\n prev = [...(isArray(prev) ? prev : []), selectedValue] as T\n } else if (runOmit) {\n prev = (\n isArray(prev)\n ? prev.filter((value) => value !== selectedValue)\n : undefined\n ) as T\n }\n })\n\n return prev\n }\n })\n },\n [getSelectedValues, isMulti],\n )\n\n const onChange = useCallback(\n (newValue: string, runRebirth: boolean = true) => {\n setValue((prev) => {\n let next: T\n\n if (!isArray(prev)) {\n next = newValue as T\n } else {\n const isSelected = prev.includes(newValue)\n\n if (!isSelected) {\n next = [...prev, newValue] as T\n } else {\n next = prev.filter((value) => value !== newValue) as T\n }\n }\n\n prevValue.current = next\n return next\n })\n\n const isHit =\n descendants\n .values()\n .filter(({ node }) =>\n format(node.textContent ?? \"\").includes(newValue),\n ).length > 0\n\n onChangeLabel(newValue)\n\n if (allowFree || isHit) setInputValue(\"\")\n\n if (isMulti && runRebirth) rebirthOptions(false)\n },\n [\n allowFree,\n isMulti,\n onChangeLabel,\n rebirthOptions,\n setValue,\n descendants,\n format,\n ],\n )\n\n const onSelect = useCallback(() => {\n let enabledValue = descendants.value(focusedIndex)\n\n if (\"disabled\" in (enabledValue?.node.dataset ?? {}))\n enabledValue = undefined\n\n if (!enabledValue) return\n\n const value = enabledValue.node.dataset.value ?? \"\"\n\n onChange(value)\n\n if (closeOnSelect) onClose()\n\n if (omitSelectedValues) onFocusNext()\n }, [\n closeOnSelect,\n descendants,\n focusedIndex,\n omitSelectedValues,\n onChange,\n onClose,\n onFocusNext,\n ])\n\n const onSearch = useCallback(\n (ev: ChangeEvent<HTMLInputElement>) => {\n if (!isOpen) onOpen()\n\n onSearchProp?.(ev)\n\n const value = ev.target.value\n const computedValue = format(value)\n\n if (computedValue) {\n pickOptions(computedValue)\n } else {\n rebirthOptions()\n }\n\n setInputValue(value)\n },\n [isOpen, onOpen, format, onSearchProp, pickOptions, rebirthOptions],\n )\n\n const onCompositionStart = useCallback(() => {\n isComposition.current = true\n }, [])\n\n const onCompositionEnd = useCallback(() => {\n isComposition.current = false\n }, [])\n\n const onCreate = useCallback(() => {\n if (!listRef.current) return\n\n const newItem: AutocompleteItem = { label: inputValue, value: inputValue }\n\n let newItems: AutocompleteItem[] = []\n\n if (resolvedItems) newItems = resolvedItems\n\n if (firstInsertPositionItem === \"first\") {\n newItems = [newItem, ...newItems]\n } else if (firstInsertPositionItem === \"last\") {\n newItems = [...newItems, newItem]\n } else {\n const i = newItems.findIndex(\n ({ label }) => label === firstInsertPositionItem,\n )\n\n const targetItem = newItems[i]\n\n if (i !== -1 && \"items\" in targetItem) {\n if (secondInsertPositionItem === \"first\") {\n targetItem.items = [newItem, ...(targetItem.items ?? [])]\n } else {\n targetItem.items = [...(targetItem.items ?? []), newItem]\n }\n\n newItems[i] = targetItem\n } else {\n console.warn(\n `${\n !isMulti ? \"Autocomplete\" : \"MultiAutocomplete\"\n }: '${firstInsertPositionItem}' specified in insertPositionItem does not exist in the option group.`,\n )\n }\n }\n\n setResolvedItems(newItems)\n onChange(inputValue)\n rebirthOptions(false)\n\n const index = flattenItems(newItems).findIndex(\n ({ value }) => value === inputValue,\n )\n\n setFocusedIndex(index)\n\n onCreateProp?.(newItem, newItems)\n }, [\n inputValue,\n resolvedItems,\n firstInsertPositionItem,\n onChange,\n rebirthOptions,\n onCreateProp,\n secondInsertPositionItem,\n isMulti,\n ])\n\n const onClick = useCallback(() => {\n if (isOpen) {\n if (inputRef.current) inputRef.current.focus()\n } else {\n onOpen()\n\n onFocusFirstOrSelected()\n }\n }, [isOpen, onFocusFirstOrSelected, onOpen])\n\n const onFocus = useCallback(() => {\n if (isOpen) return\n\n onOpen()\n\n onFocusFirstOrSelected()\n }, [isOpen, onFocusFirstOrSelected, onOpen])\n\n const onBlur = useCallback(\n (ev: FocusEvent<HTMLDivElement>) => {\n const relatedTarget = getEventRelatedTarget(ev)\n\n if (isContains(containerRef.current, relatedTarget)) return\n\n if (!closeOnBlur && isHit) return\n\n if (allowFree && !!inputValue) onChange(inputValue, false)\n\n setInputValue(\"\")\n\n if (isOpen) onClose()\n },\n [closeOnBlur, isHit, isOpen, inputValue, allowFree, onClose, onChange],\n )\n\n const onDelete = useCallback(() => {\n if (!isMulti) {\n onChange(\"\")\n } else {\n onChange(value[value.length - 1])\n }\n\n if (!isOpen) onFocus()\n }, [isMulti, isOpen, onChange, onFocus, value])\n\n const onClear = useCallback(\n (ev: MouseEvent<HTMLDivElement>) => {\n ev.stopPropagation()\n\n prevValue.current = [] as unknown as T\n setValue([] as unknown as T)\n setLabel(undefined)\n setInputValue(\"\")\n rebirthOptions()\n\n if (isOpen && inputRef.current) inputRef.current.focus()\n },\n [isOpen, setLabel, setInputValue, setValue, rebirthOptions],\n )\n\n const onKeyDown = useCallback(\n (ev: KeyboardEvent<HTMLDivElement>) => {\n if (ev.key === \" \") ev.key = ev.code\n\n if (formControlProps.disabled || formControlProps.readOnly) return\n if (isComposition.current) return\n\n const enabledDelete = label === inputValue || !inputValue.length\n\n const actions: Record<string, Function | undefined> = {\n ArrowDown: isFocused\n ? () => onFocusNext()\n : !isOpen\n ? funcAll(onOpen, onFocusFirstOrSelected)\n : undefined,\n ArrowUp: isFocused\n ? () => onFocusPrev()\n : !isOpen\n ? funcAll(onOpen, onFocusLastOrSelected)\n : undefined,\n Space: isCreate\n ? onCreate\n : isFocused\n ? onSelect\n : !isOpen\n ? funcAll(onOpen, onFocusFirstOrSelected)\n : undefined,\n Enter: isCreate\n ? onCreate\n : isFocused\n ? onSelect\n : !isOpen\n ? funcAll(onOpen, onFocusFirstOrSelected)\n : allowFree && isMulti\n ? () => {\n if (inputValue) onChange(inputValue)\n\n setFocusedIndex(0)\n }\n : undefined,\n Home: isOpen ? onFocusFirst : undefined,\n End: isOpen ? onFocusLast : undefined,\n Escape: closeOnEsc ? onClose : undefined,\n Backspace: !isEmptyValue && enabledDelete ? onDelete : undefined,\n }\n\n const action = actions[ev.key]\n\n if (!action) return\n\n ev.preventDefault()\n ev.stopPropagation()\n\n action(ev)\n },\n [\n allowFree,\n formControlProps,\n label,\n inputValue,\n onOpen,\n isFocused,\n isMulti,\n onFocusFirstOrSelected,\n onFocusNext,\n onFocusLastOrSelected,\n onFocusPrev,\n isCreate,\n onCreate,\n onSelect,\n isOpen,\n onFocusFirst,\n onFocusLast,\n closeOnEsc,\n onClose,\n isEmptyValue,\n onDelete,\n onChange,\n ],\n )\n\n useEffect(() => {\n if (!isMulti) return\n\n if (!omitSelectedValues && isUndefined(maxSelectValues)) return\n\n const isAll = value.length > 0 && value.length === descendants.count()\n const isMax = value.length === maxSelectValues\n\n if (isAll || isMax) {\n onClose()\n setIsAllSelected(true)\n } else {\n setIsAllSelected(false)\n }\n }, [\n omitSelectedValues,\n value,\n descendants,\n isMulti,\n onClose,\n maxSelectValues,\n ])\n\n useEffect(() => {\n if (isMulti) {\n if (\n JSON.stringify(prevValue.current ?? []) === JSON.stringify(value ?? [])\n )\n return\n\n const label = getSelectedValues(value)\n\n setLabel(label as T)\n } else {\n if (prevValue.current === value) return\n\n onChangeLabel(value, false)\n }\n }, [isMulti, value, onChangeLabel, getSelectedValues])\n\n useUpdateEffect(() => {\n if (isOpen || allowFree) return\n\n setFocusedIndex(-1)\n setInputValue(\"\")\n }, [isOpen])\n\n useUpdateEffect(() => {\n if (!isHit) setFocusedIndex(-2)\n }, [isHit])\n\n useUnmountEffect(() => {\n timeoutIds.current.forEach((id) => clearTimeout(id))\n timeoutIds.current.clear()\n })\n\n useOutsideClick({\n ref: containerRef,\n handler: onClose,\n enabled: isOpen && (closeOnBlur || !isHit),\n })\n\n const getPopoverProps = useCallback(\n (props?: PopoverProps): PopoverProps => ({\n matchWidth: true,\n ...rest,\n ...props,\n isOpen,\n onOpen,\n onClose,\n placement,\n duration,\n trigger: \"never\",\n closeOnButton: false,\n closeOnBlur,\n }),\n [duration, closeOnBlur, isOpen, onClose, onOpen, placement, rest],\n )\n\n const getContainerProps: UIPropGetter = useCallback(\n (props = {}, ref = null) => ({\n ref: mergeRefs(containerRef, ref),\n ...containerProps,\n ...props,\n ...formControlProps,\n onClick: handlerAll(props.onClick, rest.onClick, onClick),\n onBlur: handlerAll(props.onBlur, rest.onBlur, onBlur),\n }),\n\n [containerProps, formControlProps, onBlur, onClick, rest],\n )\n\n const getFieldProps: UIPropGetter = useCallback(\n (props = {}, ref = null) => ({\n ref,\n tabIndex: -1,\n ...props,\n ...formControlProps,\n placeholder,\n \"data-active\": dataAttr(isOpen),\n \"aria-expanded\": dataAttr(isOpen),\n onFocus: handlerAll(props.onFocus, rest.onFocus, onFocus),\n onKeyDown: handlerAll(props.onKeyDown, rest.onKeyDown, onKeyDown),\n }),\n [formControlProps, placeholder, isOpen, rest, onFocus, onKeyDown],\n )\n\n return {\n id,\n descendants,\n value,\n label,\n inputValue,\n isHit,\n isEmpty,\n computedChildren,\n focusedIndex,\n omitSelectedValues,\n closeOnSelect,\n allowCreate,\n allowFree,\n emptyMessage,\n isOpen,\n isAllSelected,\n listRef,\n inputRef,\n optionProps,\n formControlProps,\n setFocusedIndex,\n onChangeLabel,\n onChange,\n onSearch,\n onCreate,\n onClear,\n onCompositionStart,\n onCompositionEnd,\n pickOptions,\n rebirthOptions,\n onOpen,\n onClose,\n onFocusFirst,\n onFocusLast,\n onFocusSelected,\n onFocusNext,\n onFocusPrev,\n getPopoverProps,\n getContainerProps,\n getFieldProps,\n inputProps,\n }\n}\n\nexport type UseAutocompleteReturn = ReturnType<typeof useAutocomplete>\n\nexport const useAutocompleteInput = () => {\n const {\n id,\n inputRef,\n onSearch,\n onCompositionStart,\n onCompositionEnd,\n isAllSelected,\n formControlProps,\n inputProps,\n isOpen,\n } = useAutocompleteContext()\n\n useUpdateEffect(() => {\n if (isAllSelected && inputRef.current) inputRef.current.blur()\n }, [isAllSelected])\n\n const getInputProps: UIPropGetter<\"input\"> = useCallback(\n (props = {}, ref = null) => ({\n ref: mergeRefs(inputRef, ref),\n ...formControlProps,\n role: \"combobox\",\n \"aria-haspopup\": \"listbox\",\n \"aria-autocomplete\": \"list\",\n \"aria-expanded\": isOpen,\n autoCapitalize: \"none\",\n autoComplete: \"off\",\n spellCheck: \"false\",\n ...inputProps,\n ...props,\n id,\n cursor: formControlProps.readOnly ? \"default\" : \"text\",\n pointerEvents:\n formControlProps.disabled || isAllSelected ? \"none\" : \"auto\",\n tabIndex: isAllSelected ? -1 : 0,\n onChange: handlerAll(props.onChange, onSearch),\n onCompositionStart: handlerAll(\n props.onCompositionStart,\n inputProps.onCompositionStart,\n onCompositionStart,\n ),\n onCompositionEnd: handlerAll(\n props.onCompositionEnd,\n inputProps.onCompositionEnd,\n onCompositionEnd,\n ),\n }),\n [\n isOpen,\n inputProps,\n inputRef,\n formControlProps,\n id,\n isAllSelected,\n onSearch,\n onCompositionStart,\n onCompositionEnd,\n ],\n )\n\n return {\n getInputProps,\n }\n}\n\nexport type UseAutocompleteInputReturn = ReturnType<typeof useAutocompleteInput>\n\nexport const useAutocompleteList = () => {\n const { focusedIndex, isOpen, listRef, rebirthOptions } =\n useAutocompleteContext()\n\n const descendants = useAutocompleteDescendantsContext()\n\n const beforeFocusedIndex = useRef<number>(-1)\n const selectedValue = descendants.value(focusedIndex)\n\n const onAnimationComplete = useCallback(() => {\n if (!isOpen) rebirthOptions(false)\n }, [isOpen, rebirthOptions])\n\n useEffect(() => {\n if (!listRef.current || !selectedValue) return\n\n if (beforeFocusedIndex.current === selectedValue.index) return\n\n const parent = listRef.current\n const child = selectedValue.node\n\n const parentHeight = parent.clientHeight\n const viewTop = parent.scrollTop\n const viewBottom = viewTop + parentHeight\n\n const childHeight = child.clientHeight\n const childTop = child.offsetTop\n const childBottom = childTop + childHeight\n\n const isInView = viewTop <= childTop && childBottom <= viewBottom\n\n const isScrollBottom = beforeFocusedIndex.current < selectedValue.index\n\n if (!isInView) {\n if (childBottom <= parentHeight) {\n listRef.current.scrollTo({ top: 0 })\n } else {\n if (!isScrollBottom) {\n listRef.current.scrollTo({ top: childTop + 1 })\n } else {\n listRef.current.scrollTo({ top: childBottom - parentHeight })\n }\n }\n }\n\n beforeFocusedIndex.current = selectedValue.index\n }, [listRef, selectedValue])\n\n useUpdateEffect(() => {\n if (!isOpen) beforeFocusedIndex.current = -1\n }, [isOpen])\n\n const getListProps: MotionUIPropGetter<\"ul\"> = useCallback(\n (props = {}, ref = null) => ({\n as: \"ul\",\n ref: mergeRefs(listRef, ref),\n role: \"select\",\n tabIndex: -1,\n ...props,\n onAnimationComplete: handlerAll(\n props.onAnimationComplete,\n onAnimationComplete,\n ),\n }),\n [listRef, onAnimationComplete],\n )\n\n return {\n getListProps,\n }\n}\n\nexport type UseAutocompleteOptionGroupProps = HTMLUIProps<\"ul\"> & {\n /**\n * The label of the autocomplete option group.\n */\n label: string\n}\n\nexport const useAutocompleteOptionGroup = ({\n label,\n ...rest\n}: UseAutocompleteOptionGroupProps) => {\n const { value, omitSelectedValues } = useAutocompleteContext()\n\n const isMulti = isArray(value)\n\n const descendants = useAutocompleteDescendantsContext()\n\n const values = descendants.values()\n const selectedValues =\n isMulti && omitSelectedValues\n ? descendants.values(({ node }) =>\n value.includes(node.dataset.value ?? \"\"),\n )\n : []\n const selectedIndexes = selectedValues.map(({ index }) => index)\n const childValues = values.filter(\n ({ node, index }) =>\n node.parentElement?.dataset.label === label &&\n !selectedIndexes.includes(index) &&\n \"target\" in node.dataset,\n )\n\n const isEmpty = !childValues.length\n\n const computedRest = splitObject(rest, layoutStyleProperties)\n\n const getContainerProps: UIPropGetter = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n width: \"1px\",\n margin: \"-1px\",\n padding: \"0px\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n position: \"absolute\",\n }\n\n return {\n ref,\n ...props,\n ...computedRest[0],\n style: isEmpty ? style : undefined,\n \"data-label\": label,\n role: \"autocomplete-group-container\",\n }\n },\n [computedRest, isEmpty, label],\n )\n\n const getGroupProps: UIPropGetter = useCallback(\n (props = {}, ref = null) => ({\n ref,\n ...props,\n ...computedRest[1],\n \"data-label\": label,\n role: \"autocomplete-group\",\n }),\n [computedRest, label],\n )\n\n return {\n label,\n getContainerProps,\n getGroupProps,\n }\n}\n\nexport type UseAutocompleteOptionGroupReturn = ReturnType<\n typeof useAutocompleteOptionGroup\n>\n\nexport type UseAutocompleteOptionProps = Omit<\n HTMLUIProps<\"li\">,\n \"value\" | \"children\"\n> & {\n /**\n * The value of the select option.\n */\n value?: string\n /**\n * The label of the select option.\n */\n children?: string\n /**\n * If `true`, the select option will be disabled.\n *\n * @default false\n */\n isDisabled?: boolean\n /**\n * If `true`, the select option will be focusable.\n *\n * @default false\n */\n isFocusable?: boolean\n /**\n * If `true`, the list element will be closed when selected.\n *\n * @default false\n */\n closeOnSelect?: boolean\n}\n\nexport const useAutocompleteOption = (props: UseAutocompleteOptionProps) => {\n const {\n value,\n omitSelectedValues,\n onChange,\n onChangeLabel,\n focusedIndex,\n setFocusedIndex,\n onClose,\n closeOnSelect: generalCloseOnSelect,\n optionProps,\n inputRef,\n onFocusNext,\n } = useAutocompleteContext()\n\n let {\n icon: customIcon,\n isDisabled,\n isFocusable,\n closeOnSelect: customCloseOnSelect,\n children,\n value: optionValue,\n ...computedProps\n } = { ...optionProps, ...props }\n\n const trulyDisabled = !!isDisabled && !isFocusable\n\n const itemRef = useRef<HTMLLIElement>(null)\n\n const { index, register, descendants } = useAutocompleteDescendant({\n disabled: trulyDisabled,\n })\n\n const values = descendants.values()\n const frontValues = values.slice(0, index)\n\n const isMulti = isArray(value)\n const isDuplicated = !isMulti\n ? frontValues.some(({ node }) => node.dataset.value === (optionValue ?? \"\"))\n : false\n\n const isSelected =\n !isDuplicated &&\n (!isMulti\n ? (optionValue ?? \"\") === value\n : value.includes(optionValue ?? \"\"))\n const isTarget = \"target\" in (itemRef.current?.dataset ?? {})\n const isFocused = index === focusedIndex\n\n const onClick = useCallback(\n (ev: MouseEvent<HTMLLIElement>) => {\n ev.stopPropagation()\n\n if (isDisabled) {\n if (inputRef.current) inputRef.current.focus()\n\n return\n }\n\n if (!isTargetOption(ev.currentTarget)) {\n if (inputRef.current) inputRef.current.focus()\n\n return\n }\n\n setFocusedIndex(index)\n\n onChange(optionValue ?? \"\")\n\n if (inputRef.current) inputRef.current.focus()\n\n if (customCloseOnSelect ?? generalCloseOnSelect) onClose()\n\n if (omitSelectedValues) onFocusNext(index)\n },\n [\n onFocusNext,\n omitSelectedValues,\n isDisabled,\n optionValue,\n setFocusedIndex,\n index,\n onChange,\n customCloseOnSelect,\n generalCloseOnSelect,\n onClose,\n inputRef,\n ],\n )\n\n useUpdateEffect(() => {\n if (isSelected) onChangeLabel(optionValue ?? \"\", false)\n }, [optionValue])\n\n const getOptionProps: UIPropGetter<\"li\"> = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n width: \"1px\",\n margin: \"-1px\",\n padding: \"0px\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n position: \"absolute\",\n }\n\n return {\n ref: mergeRefs(itemRef, ref, register),\n ...computedProps,\n ...props,\n role: \"autocomplete-item\",\n tabIndex: -1,\n style:\n !isTarget || (omitSelectedValues && isSelected) ? style : undefined,\n \"data-target\": dataAttr(true),\n \"data-value\": optionValue ?? \"\",\n \"data-focus\": dataAttr(isFocused),\n \"data-disabled\": dataAttr(isDisabled),\n \"aria-checked\": ariaAttr(isSelected),\n \"aria-disabled\": ariaAttr(isDisabled),\n onClick: handlerAll(computedProps.onClick, props.onClick, onClick),\n }\n },\n [\n optionValue,\n computedProps,\n isDisabled,\n isFocused,\n isSelected,\n isTarget,\n omitSelectedValues,\n onClick,\n register,\n ],\n )\n\n return {\n isSelected,\n isFocused,\n customIcon,\n children,\n getOptionProps,\n }\n}\n\nexport type UseAutocompleteOptionReturn = ReturnType<\n typeof useAutocompleteOption\n>\n\nexport const useAutocompleteCreate = () => {\n const { isHit, onCreate } = useAutocompleteContext()\n\n const getCreateProps: UIPropGetter<\"li\"> = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n width: \"1px\",\n margin: \"-1px\",\n padding: \"0px\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n position: \"absolute\",\n }\n\n return {\n ref,\n ...props,\n tabIndex: -1,\n style: isHit ? style : undefined,\n \"data-focus\": dataAttr(!isHit),\n onClick: handlerAll(props.onClick, onCreate),\n }\n },\n [isHit, onCreate],\n )\n\n return { getCreateProps }\n}\n\nexport type UseAutocompleteCreateReturn = ReturnType<\n typeof useAutocompleteCreate\n>\n\nexport const useAutocompleteEmpty = () => {\n const { isHit, isEmpty } = useAutocompleteContext()\n\n const getEmptyProps: UIPropGetter<\"li\"> = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n width: \"1px\",\n margin: \"-1px\",\n padding: \"0px\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n position: \"absolute\",\n }\n\n return {\n ref,\n ...props,\n tabIndex: -1,\n style: isHit && !isEmpty ? style : undefined,\n }\n },\n [isHit, isEmpty],\n )\n\n return { getEmptyProps }\n}\n\nexport type UseAutocompleteEmptyReturn = ReturnType<typeof useAutocompleteEmpty>\n"],"mappings":"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","names":["import_core","import_utils","import_core","import_utils","import_react","props","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/autocomplete-option.tsx","../src/autocomplete-icon.tsx","../src/use-autocomplete.tsx"],"sourcesContent":["import type { CSSUIObject } from \"@yamada-ui/core\"\nimport { ui, forwardRef } from \"@yamada-ui/core\"\nimport { cx } from \"@yamada-ui/utils\"\nimport type { FC, ReactElement } from \"react\"\nimport { AutocompleteItemIcon } from \"./autocomplete-icon\"\nimport type { UseAutocompleteOptionProps } from \"./use-autocomplete\"\nimport {\n useAutocompleteContext,\n useAutocompleteOption,\n} from \"./use-autocomplete\"\n\ntype AutocompleteOptionOptions = {\n /**\n * The autocomplete option icon to use.\n */\n icon?: ReactElement\n}\n\nexport type AutocompleteOptionProps = UseAutocompleteOptionProps &\n AutocompleteOptionOptions\n\nexport const AutocompleteOption = forwardRef<AutocompleteOptionProps, \"li\">(\n ({ className, icon, ...rest }, ref) => {\n const { styles } = useAutocompleteContext()\n const { isSelected, customIcon, children, getOptionProps } =\n useAutocompleteOption(rest)\n\n icon ??= customIcon\n\n const css: CSSUIObject = {\n ...styles.item,\n }\n\n return (\n <ui.li\n className={cx(\"ui-autocomplete__item\", className)}\n __css={css}\n {...getOptionProps({}, ref)}\n >\n {icon !== null ? (\n <AutocompleteItemIcon opacity={isSelected ? 1 : 0}>\n {icon || <CheckIcon />}\n </AutocompleteItemIcon>\n ) : null}\n\n <ui.span style={{ flex: 1 }} data-label>\n {children}\n </ui.span>\n </ui.li>\n )\n },\n)\n\nconst CheckIcon: FC = () => (\n <svg viewBox=\"0 0 14 14\" width=\"1em\" height=\"1em\">\n <polygon\n fill=\"currentColor\"\n points=\"5.5 11.9993304 14 3.49933039 12.5 2 5.5 8.99933039 1.5 4.9968652 0 6.49933039\"\n />\n </svg>\n)\n","import type { CSSUIObject, HTMLUIProps } from \"@yamada-ui/core\"\nimport { ui, forwardRef } from \"@yamada-ui/core\"\nimport { ChevronIcon, CloseIcon } from \"@yamada-ui/icon\"\nimport { useClickable } from \"@yamada-ui/use-clickable\"\nimport { cx, getValidChildren, isValidElement } from \"@yamada-ui/utils\"\nimport type { FC, HTMLAttributes } from \"react\"\nimport { cloneElement, useRef } from \"react\"\nimport { useAutocompleteContext } from \"./use-autocomplete\"\n\nexport type AutocompleteIconProps = HTMLUIProps<\"div\">\n\nexport const AutocompleteIcon = forwardRef<AutocompleteIconProps, \"div\">(\n ({ className, children, __css, ...rest }, ref) => {\n const { styles } = useAutocompleteContext()\n\n const css: CSSUIObject = {\n ...styles.icon,\n ...__css,\n }\n\n const validChildren = getValidChildren(children)\n\n const cloneChildren = validChildren.map((child) =>\n cloneElement(child, {\n focusable: false,\n \"aria-hidden\": true,\n style: {\n maxWidth: \"1em\",\n maxHeight: \"1em\",\n color: \"currentColor\",\n },\n }),\n )\n\n return (\n <ui.div\n ref={ref}\n className={cx(\"ui-autocomplete__icon\", className)}\n __css={css}\n {...rest}\n >\n {isValidElement(children) ? cloneChildren : <ChevronIcon />}\n </ui.div>\n )\n },\n)\n\nexport type AutocompleteClearIconProps = AutocompleteIconProps & {\n disabled?: boolean\n}\n\nexport const AutocompleteClearIcon: FC<AutocompleteClearIconProps> = ({\n className,\n children,\n ...props\n}) => {\n const ref = useRef<HTMLDivElement>(null)\n const { styles } = useAutocompleteContext()\n\n const isDisabled = props.disabled\n\n const rest = useClickable({\n ref,\n isDisabled,\n ...(props as HTMLAttributes<HTMLElement>),\n })\n\n return (\n <AutocompleteIcon\n aria-label=\"Clear value\"\n className={cx(\"ui-autocomplete__icon--clear\", className)}\n __css={styles.clearIcon}\n {...rest}\n >\n {children ?? <CloseIcon w=\"0.5em\" h=\"0.5em\" />}\n </AutocompleteIcon>\n )\n}\n\nexport type AutocompleteItemIconProps = HTMLUIProps<\"span\">\n\nexport const AutocompleteItemIcon = forwardRef<\n AutocompleteItemIconProps,\n \"span\"\n>(({ className, ...rest }, ref) => {\n const { styles } = useAutocompleteContext()\n\n const css: CSSUIObject = {\n ...styles.itemIcon,\n }\n\n return (\n <ui.span\n ref={ref}\n className={cx(\"ui-autocomplete__item-icon\", className)}\n __css={css}\n {...rest}\n />\n )\n})\n","import type { CSSUIObject, HTMLUIProps, UIPropGetter } from \"@yamada-ui/core\"\nimport { layoutStyleProperties } from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\nimport {\n formControlProperties,\n useFormControlProps,\n} from \"@yamada-ui/form-control\"\nimport type { MotionUIPropGetter } from \"@yamada-ui/motion\"\nimport { popoverProperties, type PopoverProps } from \"@yamada-ui/popover\"\nimport { useControllableState } from \"@yamada-ui/use-controllable-state\"\nimport { createDescendant } from \"@yamada-ui/use-descendant\"\nimport { useDisclosure } from \"@yamada-ui/use-disclosure\"\nimport { useOutsideClick } from \"@yamada-ui/use-outside-click\"\nimport type { Dict, Union, DOMAttributes } from \"@yamada-ui/utils\"\nimport {\n ariaAttr,\n createContext,\n dataAttr,\n funcAll,\n getEventRelatedTarget,\n handlerAll,\n isArray,\n isContains,\n isHTMLElement,\n mergeRefs,\n omitObject,\n pickObject,\n splitObject,\n useUnmountEffect,\n useUpdateEffect,\n getValidChildren,\n isUndefined,\n} from \"@yamada-ui/utils\"\nimport type {\n ChangeEvent,\n CSSProperties,\n Dispatch,\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n RefObject,\n SetStateAction,\n} from \"react\"\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\nimport type { AutocompleteOptionProps } from \"./\"\nimport { AutocompleteOption, AutocompleteOptionGroup } from \"./\"\n\ntype AutocompleteBaseItem = Omit<\n AutocompleteOptionProps,\n \"value\" | \"children\"\n> & {\n label?: string\n}\n\ntype AutocompleteItemWithValue = AutocompleteBaseItem & {\n value?: string\n}\n\ntype AutocompleteItemWithItems = AutocompleteBaseItem & {\n items?: AutocompleteItemWithValue[]\n}\n\nexport type AutocompleteItem =\n | AutocompleteItemWithValue\n | AutocompleteItemWithItems\n\nconst kanaMap: Record<string, string> = {\n ガ: \"ガ\",\n ギ: \"ギ\",\n グ: \"グ\",\n ゲ: \"ゲ\",\n ゴ: \"ゴ\",\n ザ: \"ザ\",\n ジ: \"ジ\",\n ズ: \"ズ\",\n ゼ: \"ゼ\",\n ゾ: \"ゾ\",\n ダ: \"ダ\",\n ヂ: \"ヂ\",\n ヅ: \"ヅ\",\n デ: \"デ\",\n ド: \"ド\",\n バ: \"バ\",\n ビ: \"ビ\",\n ブ: \"ブ\",\n ベ: \"ベ\",\n ボ: \"ボ\",\n パ: \"パ\",\n ピ: \"ピ\",\n プ: \"プ\",\n ペ: \"ペ\",\n ポ: \"ポ\",\n ヴ: \"ヴ\",\n ヷ: \"ヷ\",\n ヺ: \"ヺ\",\n ア: \"ア\",\n イ: \"イ\",\n ウ: \"ウ\",\n エ: \"エ\",\n オ: \"オ\",\n カ: \"カ\",\n キ: \"キ\",\n ク: \"ク\",\n ケ: \"ケ\",\n コ: \"コ\",\n サ: \"サ\",\n シ: \"シ\",\n ス: \"ス\",\n セ: \"セ\",\n ソ: \"ソ\",\n タ: \"タ\",\n チ: \"チ\",\n ツ: \"ツ\",\n テ: \"テ\",\n ト: \"ト\",\n ナ: \"ナ\",\n ニ: \"ニ\",\n ヌ: \"ヌ\",\n ネ: \"ネ\",\n ノ: \"ノ\",\n ハ: \"ハ\",\n ヒ: \"ヒ\",\n フ: \"フ\",\n ヘ: \"ヘ\",\n ホ: \"ホ\",\n マ: \"マ\",\n ミ: \"ミ\",\n ム: \"ム\",\n メ: \"メ\",\n モ: \"モ\",\n ヤ: \"ヤ\",\n ユ: \"ユ\",\n ヨ: \"ヨ\",\n ラ: \"ラ\",\n リ: \"リ\",\n ル: \"ル\",\n レ: \"レ\",\n ロ: \"ロ\",\n ワ: \"ワ\",\n ヲ: \"ヲ\",\n ン: \"ン\",\n ァ: \"ァ\",\n ィ: \"ィ\",\n ゥ: \"ゥ\",\n ェ: \"ェ\",\n ォ: \"ォ\",\n ッ: \"ッ\",\n ャ: \"ャ\",\n ュ: \"ュ\",\n ョ: \"ョ\",\n \"。\": \"。\",\n \"、\": \"、\",\n ー: \"ー\",\n \"「\": \"「\",\n \"」\": \"」\",\n \"・\": \"・\",\n}\n\nconst defaultFormat = (value: string) => {\n value = value.replace(/[!-~]/g, (v) =>\n String.fromCharCode(v.charCodeAt(0) - 0xfee0),\n )\n\n const reg = new RegExp(\"(\" + Object.keys(kanaMap).join(\"|\") + \")\", \"g\")\n\n value = value\n .replace(reg, (v) => kanaMap[v])\n .replace(/゙/g, \"゛\")\n .replace(/゚/g, \"゜\")\n\n value = value.toUpperCase()\n\n return value\n}\n\nconst flattenItems = (\n items: AutocompleteItem[],\n): AutocompleteItemWithValue[] => {\n const filterItems = (\n items: AutocompleteItem[] | AutocompleteItemWithValue[],\n ): (AutocompleteItemWithValue | AutocompleteItemWithValue[])[] =>\n items\n .map((item) => {\n const { isDisabled, isFocusable } = item\n const trulyDisabled = !!isDisabled && !isFocusable\n\n if (trulyDisabled) return\n\n if (\"items\" in item) {\n return filterItems(item.items ?? [])\n } else {\n return item as AutocompleteItemWithValue\n }\n })\n .filter(Boolean) as (\n | AutocompleteItemWithValue\n | AutocompleteItemWithValue[]\n )[]\n\n return filterItems(items).flat(Infinity) as AutocompleteItemWithValue[]\n}\n\nconst isTargetOption = (target: EventTarget | null): boolean =>\n isHTMLElement(target) &&\n !!target?.getAttribute(\"role\")?.startsWith(\"autocomplete-item\")\n\nexport const {\n DescendantsContextProvider: AutocompleteDescendantsContextProvider,\n useDescendantsContext: useAutocompleteDescendantsContext,\n useDescendants: useAutocompleteDescendants,\n useDescendant: useAutocompleteDescendant,\n} = createDescendant<HTMLElement>()\n\ntype AutocompleteContext = Omit<\n UseAutocompleteProps,\n \"value\" | \"defaultValue\" | \"onChange\" | \"onCreate\"\n> & {\n value: string | string[]\n label: string | string[] | undefined\n inputValue: string\n isHit: boolean\n isEmpty: boolean\n isAllSelected: boolean\n onChange: (newValue: string) => void\n onChangeLabel: (newValue: string, runOmit?: boolean) => void\n pickOptions: (value: string) => void\n rebirthOptions: (runFocus?: boolean) => void\n inputProps: DOMAttributes\n isOpen: boolean\n onOpen: () => void\n onClose: () => void\n onCreate: () => void\n onFocusFirst: () => void\n onFocusLast: () => void\n onFocusNext: (index?: number) => void\n onFocusPrev: (index?: number) => void\n focusedIndex: number\n setFocusedIndex: Dispatch<SetStateAction<number>>\n listRef: RefObject<HTMLUListElement>\n inputRef: RefObject<HTMLInputElement>\n formControlProps: Record<string, any>\n styles: Record<string, CSSUIObject>\n}\n\nexport const [AutocompleteProvider, useAutocompleteContext] =\n createContext<AutocompleteContext>({\n name: \"AutocompleteContext\",\n errorMessage: `useAutocompleteContext returned is 'undefined'. Seems you forgot to wrap the components in \"<Autocomplete />\" or \"<MultiAutocomplete />\"`,\n })\n\ntype UseAutocompleteBaseProps<T extends string | string[] = string> = Omit<\n PopoverProps,\n | \"initialFocusRef\"\n | \"closeOnButton\"\n | \"trigger\"\n | \"autoFocus\"\n | \"restoreFocus\"\n | \"openDelay\"\n | \"closeDelay\"\n> &\n FormControlOptions & {\n /**\n * The value of the autocomplete.\n */\n value?: T\n /**\n * The initial value of the autocomplete.\n */\n defaultValue?: T\n /**\n * The callback invoked when value state changes.\n */\n onChange?: (value: T) => void\n /**\n * The callback invoked when search input.\n */\n onSearch?: (ev: ChangeEvent<HTMLInputElement>) => void\n /**\n * The callback invoked when autocomplete option created.\n */\n onCreate?: (newItem: AutocompleteItem, newItems: AutocompleteItem[]) => void\n /**\n * Function to format text when search input.\n */\n format?: (value: string) => string\n /**\n * The position to be inserted when the autocomplete option is created.\n *\n * @default 'first'\n */\n insertPositionItem?: Union<\"first\" | \"last\"> | [string, \"first\" | \"last\"]\n /**\n * If `true`, the list element will be closed when value is selected.\n *\n * @default true\n */\n closeOnSelect?: boolean\n /**\n * The message displayed when the search yields no hits.\n *\n * @default 'No results found'\n */\n emptyMessage?: string\n /**\n * If `true`, enables the creation of autocomplete option.\n *\n * @default false\n */\n allowCreate?: boolean\n /**\n * If `true`, enables the free input.\n */\n allowFree?: boolean\n /**\n * If `true`, the selected item(s) will be excluded from the list.\n *\n * @default false\n */\n omitSelectedValues?: boolean\n /**\n * The maximum selectable value.\n */\n maxSelectValues?: number\n /**\n * Props for select option element.\n */\n optionProps?: Omit<AutocompleteOptionProps, \"value\" | \"children\">\n /**\n * If provided, generate options based on items.\n */\n items?: AutocompleteItem[]\n }\n\nexport type UseAutocompleteProps<T extends string | string[] = string> = Omit<\n HTMLUIProps<\"input\">,\n | keyof UseAutocompleteBaseProps\n | \"list\"\n | \"disabled\"\n | \"required\"\n | \"readOnly\"\n | \"size\"\n> &\n UseAutocompleteBaseProps<T>\n\nexport const useAutocomplete = <T extends string | string[] = string>({\n value: valueProp,\n defaultValue,\n onChange: onChangeProp,\n onCreate: onCreateProp,\n onSearch: onSearchProp,\n closeOnSelect = true,\n omitSelectedValues = false,\n maxSelectValues,\n closeOnBlur = true,\n closeOnEsc = true,\n allowCreate = false,\n allowFree = false,\n insertPositionItem = \"first\",\n emptyMessage = \"No results found\",\n format = defaultFormat,\n placement = \"bottom-start\",\n duration = 0.2,\n optionProps,\n placeholder,\n items,\n children,\n isOpen: isOpenProp,\n defaultIsOpen,\n onOpen: onOpenProp,\n onClose: onCloseProp,\n ...rest\n}: UseAutocompleteProps<T>) => {\n rest = useFormControlProps(rest)\n\n const { id } = rest\n\n const { \"aria-readonly\": _ariaReadonly, ...formControlProps } = pickObject(\n rest,\n formControlProperties,\n )\n const [containerProps, inputProps] = splitObject<Dict, string>(\n omitObject(rest, [...popoverProperties, \"onKeyDown\", \"onFocus\"]),\n layoutStyleProperties,\n )\n\n const descendants = useAutocompleteDescendants()\n\n const containerRef = useRef<HTMLDivElement>(null)\n const listRef = useRef<HTMLUListElement>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const timeoutIds = useRef<Set<any>>(new Set([]))\n const isComposition = useRef<boolean>(false)\n const prevValue = useRef<T | undefined>(undefined)\n\n const [resolvedItems, setResolvedItems] = useState<\n AutocompleteItem[] | undefined\n >(items ? JSON.parse(JSON.stringify(items)) : undefined)\n const [value, setValue] = useControllableState({\n value: valueProp,\n defaultValue,\n onChange: onChangeProp,\n })\n const [label, setLabel] = useState<T | undefined>(undefined)\n const [inputValue, setInputValue] = useState<string>(\"\")\n const [focusedIndex, setFocusedIndex] = useState<number>(-1)\n const [isAllSelected, setIsAllSelected] = useState<boolean>(false)\n const [isHit, setIsHit] = useState<boolean>(true)\n const {\n isOpen,\n onOpen: onInternalOpen,\n onClose,\n } = useDisclosure({\n isOpen: isOpenProp,\n defaultIsOpen,\n onOpen: onOpenProp,\n onClose: onCloseProp,\n })\n const isFocused = focusedIndex > -1\n const isCreate = focusedIndex === -2 && allowCreate\n const isMulti = isArray(value)\n const isEmptyValue = !isMulti ? !value : !value.length\n\n const [firstInsertPositionItem, secondInsertPositionItem] = useMemo(() => {\n if (isArray(insertPositionItem)) {\n return insertPositionItem\n } else {\n return [insertPositionItem, \"first\"]\n }\n }, [insertPositionItem])\n\n if (allowCreate && !isUndefined(children)) {\n console.warn(\n `${!isMulti ? \"Autocomplete\" : \"MultiAutocomplete\"}: ${\n !isMulti ? \"Autocomplete\" : \"MultiAutocomplete\"\n } internally prefers 'children'. If 'allowCreate' is true, it will not be reflected correctly. If want to reflect, please set 'items' in props.`,\n )\n }\n\n const selectedValues = descendants.enabledValues(\n ({ node }) => isMulti && value.includes(node.dataset.value ?? \"\"),\n )\n const selectedIndexes = selectedValues.map(({ index }) => index)\n const enabledValues = descendants.enabledValues(\n ({ node, index }) =>\n \"target\" in node.dataset && !selectedIndexes.includes(index),\n )\n\n const validChildren = getValidChildren(children)\n\n const computedChildren = resolvedItems?.map((item, i) => {\n if (\"value\" in item) {\n const { label, value, ...props } = item\n\n return (\n <AutocompleteOption key={i} value={value} {...props}>\n {label}\n </AutocompleteOption>\n )\n } else if (\"items\" in item) {\n const { label, items = [], ...props } = item\n\n return (\n <AutocompleteOptionGroup\n key={i}\n label={label as string}\n {...(props as HTMLUIProps<\"ul\">)}\n >\n {items.map(({ label, value, ...props }, i) => (\n <AutocompleteOption key={i} value={value} {...props}>\n {label}\n </AutocompleteOption>\n ))}\n </AutocompleteOptionGroup>\n )\n }\n })\n\n const isEmpty = !validChildren.length && !computedChildren?.length\n\n const onOpen = useCallback(() => {\n if (formControlProps.disabled || formControlProps.readOnly) return\n\n if (!allowCreate && (isEmpty || isAllSelected)) return\n\n onInternalOpen()\n\n if (inputRef.current) inputRef.current.focus()\n }, [allowCreate, formControlProps, isAllSelected, isEmpty, onInternalOpen])\n\n const onFocusFirst = useCallback(() => {\n const id = setTimeout(() => {\n if (isEmpty || isAllSelected) return\n\n const first = descendants.enabledFirstValue(\n ({ node }) => \"target\" in node.dataset,\n )\n\n if (!first) return\n\n if (!isMulti || !omitSelectedValues) {\n setFocusedIndex(first.index)\n } else {\n if (selectedIndexes.includes(first.index)) {\n const enabledFirst = enabledValues[0]\n\n setFocusedIndex(enabledFirst.index)\n } else {\n setFocusedIndex(first.index)\n }\n }\n })\n\n timeoutIds.current.add(id)\n }, [\n descendants,\n enabledValues,\n isAllSelected,\n isEmpty,\n isMulti,\n omitSelectedValues,\n selectedIndexes,\n ])\n\n const onFocusLast = useCallback(() => {\n const id = setTimeout(() => {\n if (isEmpty || isAllSelected) return\n\n const last = descendants.enabledLastValue(\n ({ node }) => \"target\" in node.dataset,\n )\n\n if (!last) return\n\n if (!isMulti || !omitSelectedValues) {\n setFocusedIndex(last.index)\n } else {\n if (selectedIndexes.includes(last.index)) {\n const enabledLast = enabledValues.reverse()[0]\n\n setFocusedIndex(enabledLast.index)\n } else {\n setFocusedIndex(last.index)\n }\n }\n })\n\n timeoutIds.current.add(id)\n }, [\n descendants,\n enabledValues,\n isAllSelected,\n isEmpty,\n isMulti,\n omitSelectedValues,\n selectedIndexes,\n ])\n\n const onFocusSelected = useCallback(() => {\n const id = setTimeout(() => {\n const values = descendants.enabledValues()\n\n const selected = values.find(({ node }) =>\n !isMulti\n ? node.dataset.value === value\n : value.includes(node.dataset.value ?? \"\"),\n )\n\n if (selected) setFocusedIndex(selected.index)\n })\n\n timeoutIds.current.add(id)\n }, [descendants, isMulti, value])\n\n const onFocusNext = useCallback(\n (index: number = focusedIndex) => {\n const id = setTimeout(() => {\n const next = descendants.enabledNextValue(\n index,\n ({ node }) => \"target\" in node.dataset,\n )\n\n if (!next) return\n\n if (!isMulti || !omitSelectedValues) {\n setFocusedIndex(next.index)\n } else {\n if (selectedIndexes.includes(next.index)) {\n const enabledNext =\n enabledValues.find(({ index }) => next.index < index) ??\n enabledValues[0]\n\n setFocusedIndex(enabledNext.index)\n } else {\n setFocusedIndex(next.index)\n }\n }\n })\n\n timeoutIds.current.add(id)\n },\n [\n descendants,\n enabledValues,\n focusedIndex,\n isMulti,\n omitSelectedValues,\n selectedIndexes,\n ],\n )\n\n const onFocusPrev = useCallback(\n (index: number = focusedIndex) => {\n const id = setTimeout(() => {\n const prev = descendants.enabledPrevValue(\n index,\n ({ node }) => \"target\" in node.dataset,\n )\n\n if (!prev) return\n\n if (!isMulti || !omitSelectedValues) {\n setFocusedIndex(prev.index)\n } else {\n if (selectedIndexes.includes(prev.index)) {\n const enabledPrev =\n enabledValues.reverse().find(({ index }) => index < prev.index) ??\n enabledValues[0]\n\n setFocusedIndex(enabledPrev.index)\n } else {\n setFocusedIndex(prev.index)\n }\n }\n })\n\n timeoutIds.current.add(id)\n },\n [\n descendants,\n enabledValues,\n focusedIndex,\n isMulti,\n omitSelectedValues,\n selectedIndexes,\n ],\n )\n\n const onFocusFirstOrSelected =\n isEmptyValue || omitSelectedValues ? onFocusFirst : onFocusSelected\n const onFocusLastOrSelected =\n isEmptyValue || omitSelectedValues ? onFocusLast : onFocusSelected\n\n const pickOptions = useCallback(\n (value: string) => {\n const values = descendants.values()\n\n let isHit = false\n let isFocused = false\n\n values.forEach(({ node, index }) => {\n if (format(node.textContent ?? \"\").includes(value)) {\n isHit = true\n\n const isDisabled = \"disabled\" in node.dataset\n\n node.dataset.target = \"\"\n\n if (!isFocused && !isDisabled) {\n isFocused = true\n\n setFocusedIndex(index)\n }\n } else {\n delete node.dataset.target\n }\n })\n\n setIsHit(isHit)\n },\n [descendants, format],\n )\n\n const rebirthOptions = useCallback(\n (runFocus = true) => {\n const values = descendants.values()\n\n values.forEach(({ node }) => {\n node.dataset.target = \"\"\n })\n\n if (runFocus) onFocusFirst()\n\n setIsHit(true)\n },\n [descendants, onFocusFirst],\n )\n\n const getSelectedValues = useCallback(\n (newValues: string | string[]) => {\n const enabledValues = descendants.enabledValues()\n\n const resolvedValues = isArray(newValues) ? newValues : [newValues]\n\n const selectedValues = resolvedValues\n .map((value) => {\n const { node } =\n enabledValues.find(({ node }) => node.dataset.value === value) ?? {}\n\n if (node) {\n const el = Array.from(node.children).find(\n (child) => child.getAttribute(\"data-label\") !== null,\n )\n\n return el?.textContent ?? undefined\n } else {\n return allowFree ? value : undefined\n }\n })\n .filter(Boolean) as string[]\n\n return selectedValues\n },\n [allowFree, descendants],\n )\n\n const onChangeLabel = useCallback(\n (newValue: string, runOmit: boolean = true) => {\n const selectedValues = getSelectedValues(newValue)\n\n setLabel((prev) => {\n if (!isMulti) {\n return selectedValues[0] as T\n } else {\n selectedValues.forEach((selectedValue) => {\n const isSelected =\n isArray(prev) && prev.includes(selectedValue ?? \"\")\n\n if (!isSelected) {\n prev = [...(isArray(prev) ? prev : []), selectedValue] as T\n } else if (runOmit) {\n prev = (\n isArray(prev)\n ? prev.filter((value) => value !== selectedValue)\n : undefined\n ) as T\n }\n })\n\n return prev\n }\n })\n },\n [getSelectedValues, isMulti],\n )\n\n const onChange = useCallback(\n (newValue: string, runRebirth: boolean = true) => {\n setValue((prev) => {\n let next: T\n\n if (!isArray(prev)) {\n next = newValue as T\n } else {\n const isSelected = prev.includes(newValue)\n\n if (!isSelected) {\n next = [...prev, newValue] as T\n } else {\n next = prev.filter((value) => value !== newValue) as T\n }\n }\n\n prevValue.current = next\n return next\n })\n\n const isHit =\n descendants\n .values()\n .filter(({ node }) =>\n format(node.textContent ?? \"\").includes(newValue),\n ).length > 0\n\n onChangeLabel(newValue)\n\n if (allowFree || isHit) setInputValue(\"\")\n\n if (isMulti && runRebirth) rebirthOptions(false)\n },\n [\n allowFree,\n isMulti,\n onChangeLabel,\n rebirthOptions,\n setValue,\n descendants,\n format,\n ],\n )\n\n const onSelect = useCallback(() => {\n let enabledValue = descendants.value(focusedIndex)\n\n if (\"disabled\" in (enabledValue?.node.dataset ?? {}))\n enabledValue = undefined\n\n if (!enabledValue) return\n\n const value = enabledValue.node.dataset.value ?? \"\"\n\n onChange(value)\n\n if (closeOnSelect) onClose()\n\n if (omitSelectedValues) onFocusNext()\n }, [\n closeOnSelect,\n descendants,\n focusedIndex,\n omitSelectedValues,\n onChange,\n onClose,\n onFocusNext,\n ])\n\n const onSearch = useCallback(\n (ev: ChangeEvent<HTMLInputElement>) => {\n if (!isOpen) onOpen()\n\n onSearchProp?.(ev)\n\n const value = ev.target.value\n const computedValue = format(value)\n\n if (computedValue) {\n pickOptions(computedValue)\n } else {\n rebirthOptions()\n }\n\n setInputValue(value)\n },\n [isOpen, onOpen, format, onSearchProp, pickOptions, rebirthOptions],\n )\n\n const onCompositionStart = useCallback(() => {\n isComposition.current = true\n }, [])\n\n const onCompositionEnd = useCallback(() => {\n isComposition.current = false\n }, [])\n\n const onCreate = useCallback(() => {\n if (!listRef.current) return\n\n const newItem: AutocompleteItem = { label: inputValue, value: inputValue }\n\n let newItems: AutocompleteItem[] = []\n\n if (resolvedItems) newItems = resolvedItems\n\n if (firstInsertPositionItem === \"first\") {\n newItems = [newItem, ...newItems]\n } else if (firstInsertPositionItem === \"last\") {\n newItems = [...newItems, newItem]\n } else {\n const i = newItems.findIndex(\n ({ label }) => label === firstInsertPositionItem,\n )\n\n const targetItem = newItems[i]\n\n if (i !== -1 && \"items\" in targetItem) {\n if (secondInsertPositionItem === \"first\") {\n targetItem.items = [newItem, ...(targetItem.items ?? [])]\n } else {\n targetItem.items = [...(targetItem.items ?? []), newItem]\n }\n\n newItems[i] = targetItem\n } else {\n console.warn(\n `${\n !isMulti ? \"Autocomplete\" : \"MultiAutocomplete\"\n }: '${firstInsertPositionItem}' specified in insertPositionItem does not exist in the option group.`,\n )\n }\n }\n\n setResolvedItems(newItems)\n onChange(inputValue)\n rebirthOptions(false)\n\n const index = flattenItems(newItems).findIndex(\n ({ value }) => value === inputValue,\n )\n\n setFocusedIndex(index)\n\n onCreateProp?.(newItem, newItems)\n }, [\n inputValue,\n resolvedItems,\n firstInsertPositionItem,\n onChange,\n rebirthOptions,\n onCreateProp,\n secondInsertPositionItem,\n isMulti,\n ])\n\n const onClick = useCallback(() => {\n if (isOpen) {\n if (inputRef.current) inputRef.current.focus()\n } else {\n onOpen()\n\n onFocusFirstOrSelected()\n }\n }, [isOpen, onFocusFirstOrSelected, onOpen])\n\n const onFocus = useCallback(() => {\n if (isOpen) return\n\n onOpen()\n\n onFocusFirstOrSelected()\n }, [isOpen, onFocusFirstOrSelected, onOpen])\n\n const onBlur = useCallback(\n (ev: FocusEvent<HTMLDivElement>) => {\n const relatedTarget = getEventRelatedTarget(ev)\n\n if (isContains(containerRef.current, relatedTarget)) return\n\n if (!closeOnBlur && isHit) return\n\n if (allowFree && !!inputValue) onChange(inputValue, false)\n\n setInputValue(\"\")\n\n if (isOpen) onClose()\n },\n [closeOnBlur, isHit, isOpen, inputValue, allowFree, onClose, onChange],\n )\n\n const onDelete = useCallback(() => {\n if (!isMulti) {\n onChange(\"\")\n } else {\n onChange(value[value.length - 1])\n }\n\n if (!isOpen) onFocus()\n }, [isMulti, isOpen, onChange, onFocus, value])\n\n const onClear = useCallback(\n (ev: MouseEvent<HTMLDivElement>) => {\n ev.stopPropagation()\n\n prevValue.current = [] as unknown as T\n setValue([] as unknown as T)\n setLabel(undefined)\n setInputValue(\"\")\n rebirthOptions()\n\n if (isOpen && inputRef.current) inputRef.current.focus()\n },\n [isOpen, setLabel, setInputValue, setValue, rebirthOptions],\n )\n\n const onKeyDown = useCallback(\n (ev: KeyboardEvent<HTMLDivElement>) => {\n if (ev.key === \" \") ev.key = ev.code\n\n if (formControlProps.disabled || formControlProps.readOnly) return\n if (isComposition.current) return\n\n const enabledDelete = label === inputValue || !inputValue.length\n\n const actions: Record<string, Function | undefined> = {\n ArrowDown: isFocused\n ? () => onFocusNext()\n : !isOpen\n ? funcAll(onOpen, onFocusFirstOrSelected)\n : undefined,\n ArrowUp: isFocused\n ? () => onFocusPrev()\n : !isOpen\n ? funcAll(onOpen, onFocusLastOrSelected)\n : undefined,\n Space: isCreate\n ? onCreate\n : isFocused\n ? onSelect\n : !isOpen\n ? funcAll(onOpen, onFocusFirstOrSelected)\n : undefined,\n Enter: isCreate\n ? onCreate\n : isFocused\n ? onSelect\n : !isOpen\n ? funcAll(onOpen, onFocusFirstOrSelected)\n : allowFree && isMulti\n ? () => {\n if (inputValue) onChange(inputValue)\n\n setFocusedIndex(0)\n }\n : undefined,\n Home: isOpen ? onFocusFirst : undefined,\n End: isOpen ? onFocusLast : undefined,\n Escape: closeOnEsc ? onClose : undefined,\n Backspace: !isEmptyValue && enabledDelete ? onDelete : undefined,\n }\n\n const action = actions[ev.key]\n\n if (!action) return\n\n ev.preventDefault()\n ev.stopPropagation()\n\n action(ev)\n },\n [\n allowFree,\n formControlProps,\n label,\n inputValue,\n onOpen,\n isFocused,\n isMulti,\n onFocusFirstOrSelected,\n onFocusNext,\n onFocusLastOrSelected,\n onFocusPrev,\n isCreate,\n onCreate,\n onSelect,\n isOpen,\n onFocusFirst,\n onFocusLast,\n closeOnEsc,\n onClose,\n isEmptyValue,\n onDelete,\n onChange,\n ],\n )\n\n useEffect(() => {\n if (!isMulti) return\n\n if (!omitSelectedValues && isUndefined(maxSelectValues)) return\n\n const isAll = value.length > 0 && value.length === descendants.count()\n const isMax = value.length === maxSelectValues\n\n if (isAll || isMax) {\n onClose()\n setIsAllSelected(true)\n } else {\n setIsAllSelected(false)\n }\n }, [\n omitSelectedValues,\n value,\n descendants,\n isMulti,\n onClose,\n maxSelectValues,\n ])\n\n useEffect(() => {\n if (isMulti) {\n if (\n JSON.stringify(prevValue.current ?? []) === JSON.stringify(value ?? [])\n )\n return\n\n const label = getSelectedValues(value)\n\n setLabel(label as T)\n } else {\n if (prevValue.current === value) return\n\n onChangeLabel(value, false)\n }\n }, [isMulti, value, onChangeLabel, getSelectedValues])\n\n useUpdateEffect(() => {\n if (isOpen || allowFree) return\n\n setFocusedIndex(-1)\n setInputValue(\"\")\n }, [isOpen])\n\n useUpdateEffect(() => {\n if (!isHit) setFocusedIndex(-2)\n }, [isHit])\n\n useUnmountEffect(() => {\n timeoutIds.current.forEach((id) => clearTimeout(id))\n timeoutIds.current.clear()\n })\n\n useOutsideClick({\n ref: containerRef,\n handler: onClose,\n enabled: isOpen && (closeOnBlur || !isHit),\n })\n\n const getPopoverProps = useCallback(\n (props?: PopoverProps): PopoverProps => ({\n matchWidth: true,\n ...rest,\n ...props,\n isOpen,\n onOpen,\n onClose,\n placement,\n duration,\n trigger: \"never\",\n closeOnButton: false,\n closeOnBlur,\n }),\n [duration, closeOnBlur, isOpen, onClose, onOpen, placement, rest],\n )\n\n const getContainerProps: UIPropGetter = useCallback(\n (props = {}, ref = null) => ({\n ref: mergeRefs(containerRef, ref),\n ...containerProps,\n ...props,\n ...formControlProps,\n onClick: handlerAll(props.onClick, rest.onClick, onClick),\n onBlur: handlerAll(props.onBlur, rest.onBlur, onBlur),\n }),\n\n [containerProps, formControlProps, onBlur, onClick, rest],\n )\n\n const getFieldProps: UIPropGetter = useCallback(\n (props = {}, ref = null) => ({\n ref,\n tabIndex: -1,\n ...props,\n ...formControlProps,\n placeholder,\n \"data-active\": dataAttr(isOpen),\n \"aria-expanded\": dataAttr(isOpen),\n onFocus: handlerAll(props.onFocus, rest.onFocus, onFocus),\n onKeyDown: handlerAll(props.onKeyDown, rest.onKeyDown, onKeyDown),\n }),\n [formControlProps, placeholder, isOpen, rest, onFocus, onKeyDown],\n )\n\n return {\n id,\n descendants,\n value,\n label,\n inputValue,\n isHit,\n isEmpty,\n computedChildren,\n focusedIndex,\n omitSelectedValues,\n closeOnSelect,\n allowCreate,\n allowFree,\n emptyMessage,\n isOpen,\n isAllSelected,\n listRef,\n inputRef,\n optionProps,\n formControlProps,\n setFocusedIndex,\n onChangeLabel,\n onChange,\n onSearch,\n onCreate,\n onClear,\n onCompositionStart,\n onCompositionEnd,\n pickOptions,\n rebirthOptions,\n onOpen,\n onClose,\n onFocusFirst,\n onFocusLast,\n onFocusSelected,\n onFocusNext,\n onFocusPrev,\n getPopoverProps,\n getContainerProps,\n getFieldProps,\n inputProps,\n }\n}\n\nexport type UseAutocompleteReturn = ReturnType<typeof useAutocomplete>\n\nexport const useAutocompleteInput = () => {\n const {\n id,\n inputRef,\n onSearch,\n onCompositionStart,\n onCompositionEnd,\n isAllSelected,\n formControlProps,\n inputProps,\n isOpen,\n } = useAutocompleteContext()\n\n useUpdateEffect(() => {\n if (isAllSelected && inputRef.current) inputRef.current.blur()\n }, [isAllSelected])\n\n const getInputProps: UIPropGetter<\"input\"> = useCallback(\n (props = {}, ref = null) => ({\n ref: mergeRefs(inputRef, ref),\n ...formControlProps,\n role: \"combobox\",\n \"aria-haspopup\": \"listbox\",\n \"aria-autocomplete\": \"list\",\n \"aria-expanded\": isOpen,\n autoCapitalize: \"none\",\n autoComplete: \"off\",\n spellCheck: \"false\",\n ...inputProps,\n ...props,\n id,\n cursor: formControlProps.readOnly ? \"default\" : \"text\",\n pointerEvents:\n formControlProps.disabled || isAllSelected ? \"none\" : \"auto\",\n tabIndex: isAllSelected ? -1 : 0,\n onChange: handlerAll(props.onChange, onSearch),\n onCompositionStart: handlerAll(\n props.onCompositionStart,\n inputProps.onCompositionStart,\n onCompositionStart,\n ),\n onCompositionEnd: handlerAll(\n props.onCompositionEnd,\n inputProps.onCompositionEnd,\n onCompositionEnd,\n ),\n }),\n [\n isOpen,\n inputProps,\n inputRef,\n formControlProps,\n id,\n isAllSelected,\n onSearch,\n onCompositionStart,\n onCompositionEnd,\n ],\n )\n\n return {\n getInputProps,\n }\n}\n\nexport type UseAutocompleteInputReturn = ReturnType<typeof useAutocompleteInput>\n\nexport const useAutocompleteList = () => {\n const { focusedIndex, isOpen, listRef, rebirthOptions } =\n useAutocompleteContext()\n\n const descendants = useAutocompleteDescendantsContext()\n\n const beforeFocusedIndex = useRef<number>(-1)\n const selectedValue = descendants.value(focusedIndex)\n\n const onAnimationComplete = useCallback(() => {\n if (!isOpen) rebirthOptions(false)\n }, [isOpen, rebirthOptions])\n\n useEffect(() => {\n if (!listRef.current || !selectedValue) return\n\n if (beforeFocusedIndex.current === selectedValue.index) return\n\n const parent = listRef.current\n const child = selectedValue.node\n\n const parentHeight = parent.clientHeight\n const viewTop = parent.scrollTop\n const viewBottom = viewTop + parentHeight\n\n const childHeight = child.clientHeight\n const childTop = child.offsetTop\n const childBottom = childTop + childHeight\n\n const isInView = viewTop <= childTop && childBottom <= viewBottom\n\n const isScrollBottom = beforeFocusedIndex.current < selectedValue.index\n\n if (!isInView) {\n if (childBottom <= parentHeight) {\n listRef.current.scrollTo({ top: 0 })\n } else {\n if (!isScrollBottom) {\n listRef.current.scrollTo({ top: childTop + 1 })\n } else {\n listRef.current.scrollTo({ top: childBottom - parentHeight })\n }\n }\n }\n\n beforeFocusedIndex.current = selectedValue.index\n }, [listRef, selectedValue])\n\n useUpdateEffect(() => {\n if (!isOpen) beforeFocusedIndex.current = -1\n }, [isOpen])\n\n const getListProps: MotionUIPropGetter<\"ul\"> = useCallback(\n (props = {}, ref = null) => ({\n as: \"ul\",\n ref: mergeRefs(listRef, ref),\n role: \"select\",\n tabIndex: -1,\n ...props,\n onAnimationComplete: handlerAll(\n props.onAnimationComplete,\n onAnimationComplete,\n ),\n }),\n [listRef, onAnimationComplete],\n )\n\n return {\n getListProps,\n }\n}\n\nexport type UseAutocompleteOptionGroupProps = HTMLUIProps<\"ul\"> & {\n /**\n * The label of the autocomplete option group.\n */\n label: string\n}\n\nexport const useAutocompleteOptionGroup = ({\n label,\n ...rest\n}: UseAutocompleteOptionGroupProps) => {\n const { value, omitSelectedValues } = useAutocompleteContext()\n\n const isMulti = isArray(value)\n\n const descendants = useAutocompleteDescendantsContext()\n\n const values = descendants.values()\n const selectedValues =\n isMulti && omitSelectedValues\n ? descendants.values(({ node }) =>\n value.includes(node.dataset.value ?? \"\"),\n )\n : []\n const selectedIndexes = selectedValues.map(({ index }) => index)\n const childValues = values.filter(\n ({ node, index }) =>\n node.parentElement?.dataset.label === label &&\n !selectedIndexes.includes(index) &&\n \"target\" in node.dataset,\n )\n\n const isEmpty = !childValues.length\n\n const computedRest = splitObject(rest, layoutStyleProperties)\n\n const getContainerProps: UIPropGetter = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n width: \"1px\",\n margin: \"-1px\",\n padding: \"0px\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n position: \"absolute\",\n }\n\n return {\n ref,\n ...props,\n ...computedRest[0],\n style: isEmpty ? style : undefined,\n \"data-label\": label,\n role: \"autocomplete-group-container\",\n }\n },\n [computedRest, isEmpty, label],\n )\n\n const getGroupProps: UIPropGetter = useCallback(\n (props = {}, ref = null) => ({\n ref,\n ...props,\n ...computedRest[1],\n \"data-label\": label,\n role: \"autocomplete-group\",\n }),\n [computedRest, label],\n )\n\n return {\n label,\n getContainerProps,\n getGroupProps,\n }\n}\n\nexport type UseAutocompleteOptionGroupReturn = ReturnType<\n typeof useAutocompleteOptionGroup\n>\n\nexport type UseAutocompleteOptionProps = Omit<\n HTMLUIProps<\"li\">,\n \"value\" | \"children\"\n> & {\n /**\n * The value of the select option.\n */\n value?: string\n /**\n * The label of the select option.\n */\n children?: string\n /**\n * If `true`, the select option will be disabled.\n *\n * @default false\n */\n isDisabled?: boolean\n /**\n * If `true`, the select option will be focusable.\n *\n * @default false\n */\n isFocusable?: boolean\n /**\n * If `true`, the list element will be closed when selected.\n *\n * @default false\n */\n closeOnSelect?: boolean\n}\n\nexport const useAutocompleteOption = (props: UseAutocompleteOptionProps) => {\n const {\n value,\n omitSelectedValues,\n onChange,\n onChangeLabel,\n focusedIndex,\n setFocusedIndex,\n onClose,\n closeOnSelect: generalCloseOnSelect,\n optionProps,\n inputRef,\n onFocusNext,\n } = useAutocompleteContext()\n\n let {\n icon: customIcon,\n isDisabled,\n isFocusable,\n closeOnSelect: customCloseOnSelect,\n children,\n value: optionValue,\n ...computedProps\n } = { ...optionProps, ...props }\n\n const trulyDisabled = !!isDisabled && !isFocusable\n\n const itemRef = useRef<HTMLLIElement>(null)\n\n const { index, register, descendants } = useAutocompleteDescendant({\n disabled: trulyDisabled,\n })\n\n const values = descendants.values()\n const frontValues = values.slice(0, index)\n\n const isMulti = isArray(value)\n const isDuplicated = !isMulti\n ? frontValues.some(({ node }) => node.dataset.value === (optionValue ?? \"\"))\n : false\n\n const isSelected =\n !isDuplicated &&\n (!isMulti\n ? (optionValue ?? \"\") === value\n : value.includes(optionValue ?? \"\"))\n const isTarget = \"target\" in (itemRef.current?.dataset ?? {})\n const isFocused = index === focusedIndex\n\n const onClick = useCallback(\n (ev: MouseEvent<HTMLLIElement>) => {\n ev.stopPropagation()\n\n if (isDisabled) {\n if (inputRef.current) inputRef.current.focus()\n\n return\n }\n\n if (!isTargetOption(ev.currentTarget)) {\n if (inputRef.current) inputRef.current.focus()\n\n return\n }\n\n setFocusedIndex(index)\n\n onChange(optionValue ?? \"\")\n\n if (inputRef.current) inputRef.current.focus()\n\n if (customCloseOnSelect ?? generalCloseOnSelect) onClose()\n\n if (omitSelectedValues) onFocusNext(index)\n },\n [\n onFocusNext,\n omitSelectedValues,\n isDisabled,\n optionValue,\n setFocusedIndex,\n index,\n onChange,\n customCloseOnSelect,\n generalCloseOnSelect,\n onClose,\n inputRef,\n ],\n )\n\n useUpdateEffect(() => {\n if (isSelected) onChangeLabel(optionValue ?? \"\", false)\n }, [optionValue])\n\n const getOptionProps: UIPropGetter<\"li\"> = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n width: \"1px\",\n margin: \"-1px\",\n padding: \"0px\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n position: \"absolute\",\n }\n\n return {\n ref: mergeRefs(itemRef, ref, register),\n ...computedProps,\n ...props,\n role: \"autocomplete-item\",\n tabIndex: -1,\n style:\n !isTarget || (omitSelectedValues && isSelected) ? style : undefined,\n \"data-target\": dataAttr(true),\n \"data-value\": optionValue ?? \"\",\n \"data-focus\": dataAttr(isFocused),\n \"data-disabled\": dataAttr(isDisabled),\n \"aria-checked\": ariaAttr(isSelected),\n \"aria-disabled\": ariaAttr(isDisabled),\n onClick: handlerAll(computedProps.onClick, props.onClick, onClick),\n }\n },\n [\n optionValue,\n computedProps,\n isDisabled,\n isFocused,\n isSelected,\n isTarget,\n omitSelectedValues,\n onClick,\n register,\n ],\n )\n\n return {\n isSelected,\n isFocused,\n customIcon,\n children,\n getOptionProps,\n }\n}\n\nexport type UseAutocompleteOptionReturn = ReturnType<\n typeof useAutocompleteOption\n>\n\nexport const useAutocompleteCreate = () => {\n const { isHit, onCreate } = useAutocompleteContext()\n\n const getCreateProps: UIPropGetter<\"li\"> = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n width: \"1px\",\n margin: \"-1px\",\n padding: \"0px\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n position: \"absolute\",\n }\n\n return {\n ref,\n ...props,\n tabIndex: -1,\n style: isHit ? style : undefined,\n \"data-focus\": dataAttr(!isHit),\n onClick: handlerAll(props.onClick, onCreate),\n }\n },\n [isHit, onCreate],\n )\n\n return { getCreateProps }\n}\n\nexport type UseAutocompleteCreateReturn = ReturnType<\n typeof useAutocompleteCreate\n>\n\nexport const useAutocompleteEmpty = () => {\n const { isHit, isEmpty } = useAutocompleteContext()\n\n const getEmptyProps: UIPropGetter<\"li\"> = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n width: \"1px\",\n margin: \"-1px\",\n padding: \"0px\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n position: \"absolute\",\n }\n\n return {\n ref,\n ...props,\n tabIndex: -1,\n style: isHit && !isEmpty ? style : undefined,\n }\n },\n [isHit, isEmpty],\n )\n\n return { getEmptyProps }\n}\n\nexport type UseAutocompleteEmptyReturn = ReturnType<typeof useAutocompleteEmpty>\n"],"mappings":"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","names":["import_core","import_utils","import_core","import_utils","import_react","props","import_jsx_runtime","import_jsx_runtime"]}
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
  import {
3
3
  AutocompleteOption
4
- } from "./chunk-QF2QXXQH.mjs";
4
+ } from "./chunk-W7B7WEFQ.mjs";
5
5
  export {
6
6
  AutocompleteOption
7
7
  };
@@ -329,8 +329,7 @@ var flattenItems = (items) => {
329
329
  var _a;
330
330
  const { isDisabled, isFocusable } = item;
331
331
  const trulyDisabled = !!isDisabled && !isFocusable;
332
- if (trulyDisabled)
333
- return;
332
+ if (trulyDisabled) return;
334
333
  if ("items" in item) {
335
334
  return filterItems((_a = item.items) != null ? _a : []);
336
335
  } else {
@@ -465,23 +464,18 @@ var useAutocomplete = ({
465
464
  });
466
465
  const isEmpty = !validChildren.length && !(computedChildren == null ? void 0 : computedChildren.length);
467
466
  const onOpen = (0, import_react.useCallback)(() => {
468
- if (formControlProps.disabled || formControlProps.readOnly)
469
- return;
470
- if (!allowCreate && (isEmpty || isAllSelected))
471
- return;
467
+ if (formControlProps.disabled || formControlProps.readOnly) return;
468
+ if (!allowCreate && (isEmpty || isAllSelected)) return;
472
469
  onInternalOpen();
473
- if (inputRef.current)
474
- inputRef.current.focus();
470
+ if (inputRef.current) inputRef.current.focus();
475
471
  }, [allowCreate, formControlProps, isAllSelected, isEmpty, onInternalOpen]);
476
472
  const onFocusFirst = (0, import_react.useCallback)(() => {
477
473
  const id2 = setTimeout(() => {
478
- if (isEmpty || isAllSelected)
479
- return;
474
+ if (isEmpty || isAllSelected) return;
480
475
  const first = descendants.enabledFirstValue(
481
476
  ({ node }) => "target" in node.dataset
482
477
  );
483
- if (!first)
484
- return;
478
+ if (!first) return;
485
479
  if (!isMulti || !omitSelectedValues) {
486
480
  setFocusedIndex(first.index);
487
481
  } else {
@@ -505,13 +499,11 @@ var useAutocomplete = ({
505
499
  ]);
506
500
  const onFocusLast = (0, import_react.useCallback)(() => {
507
501
  const id2 = setTimeout(() => {
508
- if (isEmpty || isAllSelected)
509
- return;
502
+ if (isEmpty || isAllSelected) return;
510
503
  const last = descendants.enabledLastValue(
511
504
  ({ node }) => "target" in node.dataset
512
505
  );
513
- if (!last)
514
- return;
506
+ if (!last) return;
515
507
  if (!isMulti || !omitSelectedValues) {
516
508
  setFocusedIndex(last.index);
517
509
  } else {
@@ -542,8 +534,7 @@ var useAutocomplete = ({
542
534
  return !isMulti ? node.dataset.value === value : value.includes((_a = node.dataset.value) != null ? _a : "");
543
535
  }
544
536
  );
545
- if (selected)
546
- setFocusedIndex(selected.index);
537
+ if (selected) setFocusedIndex(selected.index);
547
538
  });
548
539
  timeoutIds.current.add(id2);
549
540
  }, [descendants, isMulti, value]);
@@ -555,8 +546,7 @@ var useAutocomplete = ({
555
546
  index,
556
547
  ({ node }) => "target" in node.dataset
557
548
  );
558
- if (!next)
559
- return;
549
+ if (!next) return;
560
550
  if (!isMulti || !omitSelectedValues) {
561
551
  setFocusedIndex(next.index);
562
552
  } else {
@@ -587,8 +577,7 @@ var useAutocomplete = ({
587
577
  index,
588
578
  ({ node }) => "target" in node.dataset
589
579
  );
590
- if (!prev)
591
- return;
580
+ if (!prev) return;
592
581
  if (!isMulti || !omitSelectedValues) {
593
582
  setFocusedIndex(prev.index);
594
583
  } else {
@@ -642,8 +631,7 @@ var useAutocomplete = ({
642
631
  values.forEach(({ node }) => {
643
632
  node.dataset.target = "";
644
633
  });
645
- if (runFocus)
646
- onFocusFirst();
634
+ if (runFocus) onFocusFirst();
647
635
  setIsHit(true);
648
636
  },
649
637
  [descendants, onFocusFirst]
@@ -713,10 +701,8 @@ var useAutocomplete = ({
713
701
  }
714
702
  ).length > 0;
715
703
  onChangeLabel(newValue);
716
- if (allowFree || isHit2)
717
- setInputValue("");
718
- if (isMulti && runRebirth)
719
- rebirthOptions(false);
704
+ if (allowFree || isHit2) setInputValue("");
705
+ if (isMulti && runRebirth) rebirthOptions(false);
720
706
  },
721
707
  [
722
708
  allowFree,
@@ -733,14 +719,11 @@ var useAutocomplete = ({
733
719
  let enabledValue = descendants.value(focusedIndex);
734
720
  if ("disabled" in ((_a = enabledValue == null ? void 0 : enabledValue.node.dataset) != null ? _a : {}))
735
721
  enabledValue = void 0;
736
- if (!enabledValue)
737
- return;
722
+ if (!enabledValue) return;
738
723
  const value2 = (_b = enabledValue.node.dataset.value) != null ? _b : "";
739
724
  onChange(value2);
740
- if (closeOnSelect)
741
- onClose();
742
- if (omitSelectedValues)
743
- onFocusNext();
725
+ if (closeOnSelect) onClose();
726
+ if (omitSelectedValues) onFocusNext();
744
727
  }, [
745
728
  closeOnSelect,
746
729
  descendants,
@@ -752,8 +735,7 @@ var useAutocomplete = ({
752
735
  ]);
753
736
  const onSearch = (0, import_react.useCallback)(
754
737
  (ev) => {
755
- if (!isOpen)
756
- onOpen();
738
+ if (!isOpen) onOpen();
757
739
  onSearchProp == null ? void 0 : onSearchProp(ev);
758
740
  const value2 = ev.target.value;
759
741
  const computedValue = format(value2);
@@ -774,12 +756,10 @@ var useAutocomplete = ({
774
756
  }, []);
775
757
  const onCreate = (0, import_react.useCallback)(() => {
776
758
  var _a, _b;
777
- if (!listRef.current)
778
- return;
759
+ if (!listRef.current) return;
779
760
  const newItem = { label: inputValue, value: inputValue };
780
761
  let newItems = [];
781
- if (resolvedItems)
782
- newItems = resolvedItems;
762
+ if (resolvedItems) newItems = resolvedItems;
783
763
  if (firstInsertPositionItem === "first") {
784
764
  newItems = [newItem, ...newItems];
785
765
  } else if (firstInsertPositionItem === "last") {
@@ -822,31 +802,25 @@ var useAutocomplete = ({
822
802
  ]);
823
803
  const onClick = (0, import_react.useCallback)(() => {
824
804
  if (isOpen) {
825
- if (inputRef.current)
826
- inputRef.current.focus();
805
+ if (inputRef.current) inputRef.current.focus();
827
806
  } else {
828
807
  onOpen();
829
808
  onFocusFirstOrSelected();
830
809
  }
831
810
  }, [isOpen, onFocusFirstOrSelected, onOpen]);
832
811
  const onFocus = (0, import_react.useCallback)(() => {
833
- if (isOpen)
834
- return;
812
+ if (isOpen) return;
835
813
  onOpen();
836
814
  onFocusFirstOrSelected();
837
815
  }, [isOpen, onFocusFirstOrSelected, onOpen]);
838
816
  const onBlur = (0, import_react.useCallback)(
839
817
  (ev) => {
840
818
  const relatedTarget = (0, import_utils6.getEventRelatedTarget)(ev);
841
- if ((0, import_utils6.isContains)(containerRef.current, relatedTarget))
842
- return;
843
- if (!closeOnBlur && isHit)
844
- return;
845
- if (allowFree && !!inputValue)
846
- onChange(inputValue, false);
819
+ if ((0, import_utils6.isContains)(containerRef.current, relatedTarget)) return;
820
+ if (!closeOnBlur && isHit) return;
821
+ if (allowFree && !!inputValue) onChange(inputValue, false);
847
822
  setInputValue("");
848
- if (isOpen)
849
- onClose();
823
+ if (isOpen) onClose();
850
824
  },
851
825
  [closeOnBlur, isHit, isOpen, inputValue, allowFree, onClose, onChange]
852
826
  );
@@ -856,8 +830,7 @@ var useAutocomplete = ({
856
830
  } else {
857
831
  onChange(value[value.length - 1]);
858
832
  }
859
- if (!isOpen)
860
- onFocus();
833
+ if (!isOpen) onFocus();
861
834
  }, [isMulti, isOpen, onChange, onFocus, value]);
862
835
  const onClear = (0, import_react.useCallback)(
863
836
  (ev) => {
@@ -867,27 +840,22 @@ var useAutocomplete = ({
867
840
  setLabel(void 0);
868
841
  setInputValue("");
869
842
  rebirthOptions();
870
- if (isOpen && inputRef.current)
871
- inputRef.current.focus();
843
+ if (isOpen && inputRef.current) inputRef.current.focus();
872
844
  },
873
845
  [isOpen, setLabel, setInputValue, setValue, rebirthOptions]
874
846
  );
875
847
  const onKeyDown = (0, import_react.useCallback)(
876
848
  (ev) => {
877
- if (ev.key === " ")
878
- ev.key = ev.code;
879
- if (formControlProps.disabled || formControlProps.readOnly)
880
- return;
881
- if (isComposition.current)
882
- return;
849
+ if (ev.key === " ") ev.key = ev.code;
850
+ if (formControlProps.disabled || formControlProps.readOnly) return;
851
+ if (isComposition.current) return;
883
852
  const enabledDelete = label === inputValue || !inputValue.length;
884
853
  const actions = {
885
854
  ArrowDown: isFocused ? () => onFocusNext() : !isOpen ? (0, import_utils6.funcAll)(onOpen, onFocusFirstOrSelected) : void 0,
886
855
  ArrowUp: isFocused ? () => onFocusPrev() : !isOpen ? (0, import_utils6.funcAll)(onOpen, onFocusLastOrSelected) : void 0,
887
856
  Space: isCreate ? onCreate : isFocused ? onSelect : !isOpen ? (0, import_utils6.funcAll)(onOpen, onFocusFirstOrSelected) : void 0,
888
857
  Enter: isCreate ? onCreate : isFocused ? onSelect : !isOpen ? (0, import_utils6.funcAll)(onOpen, onFocusFirstOrSelected) : allowFree && isMulti ? () => {
889
- if (inputValue)
890
- onChange(inputValue);
858
+ if (inputValue) onChange(inputValue);
891
859
  setFocusedIndex(0);
892
860
  } : void 0,
893
861
  Home: isOpen ? onFocusFirst : void 0,
@@ -896,8 +864,7 @@ var useAutocomplete = ({
896
864
  Backspace: !isEmptyValue && enabledDelete ? onDelete : void 0
897
865
  };
898
866
  const action = actions[ev.key];
899
- if (!action)
900
- return;
867
+ if (!action) return;
901
868
  ev.preventDefault();
902
869
  ev.stopPropagation();
903
870
  action(ev);
@@ -928,10 +895,8 @@ var useAutocomplete = ({
928
895
  ]
929
896
  );
930
897
  (0, import_react.useEffect)(() => {
931
- if (!isMulti)
932
- return;
933
- if (!omitSelectedValues && (0, import_utils6.isUndefined)(maxSelectValues))
934
- return;
898
+ if (!isMulti) return;
899
+ if (!omitSelectedValues && (0, import_utils6.isUndefined)(maxSelectValues)) return;
935
900
  const isAll = value.length > 0 && value.length === descendants.count();
936
901
  const isMax = value.length === maxSelectValues;
937
902
  if (isAll || isMax) {
@@ -956,20 +921,17 @@ var useAutocomplete = ({
956
921
  const label2 = getSelectedValues(value);
957
922
  setLabel(label2);
958
923
  } else {
959
- if (prevValue.current === value)
960
- return;
924
+ if (prevValue.current === value) return;
961
925
  onChangeLabel(value, false);
962
926
  }
963
927
  }, [isMulti, value, onChangeLabel, getSelectedValues]);
964
928
  (0, import_utils6.useUpdateEffect)(() => {
965
- if (isOpen || allowFree)
966
- return;
929
+ if (isOpen || allowFree) return;
967
930
  setFocusedIndex(-1);
968
931
  setInputValue("");
969
932
  }, [isOpen]);
970
933
  (0, import_utils6.useUpdateEffect)(() => {
971
- if (!isHit)
972
- setFocusedIndex(-2);
934
+ if (!isHit) setFocusedIndex(-2);
973
935
  }, [isHit]);
974
936
  (0, import_utils6.useUnmountEffect)(() => {
975
937
  timeoutIds.current.forEach((id2) => clearTimeout(id2));
@@ -1078,8 +1040,7 @@ var useAutocompleteInput = () => {
1078
1040
  isOpen
1079
1041
  } = useAutocompleteContext();
1080
1042
  (0, import_utils6.useUpdateEffect)(() => {
1081
- if (isAllSelected && inputRef.current)
1082
- inputRef.current.blur();
1043
+ if (isAllSelected && inputRef.current) inputRef.current.blur();
1083
1044
  }, [isAllSelected]);
1084
1045
  const getInputProps = (0, import_react.useCallback)(
1085
1046
  (props = {}, ref = null) => ({
@@ -1132,14 +1093,11 @@ var useAutocompleteList = () => {
1132
1093
  const beforeFocusedIndex = (0, import_react.useRef)(-1);
1133
1094
  const selectedValue = descendants.value(focusedIndex);
1134
1095
  const onAnimationComplete = (0, import_react.useCallback)(() => {
1135
- if (!isOpen)
1136
- rebirthOptions(false);
1096
+ if (!isOpen) rebirthOptions(false);
1137
1097
  }, [isOpen, rebirthOptions]);
1138
1098
  (0, import_react.useEffect)(() => {
1139
- if (!listRef.current || !selectedValue)
1140
- return;
1141
- if (beforeFocusedIndex.current === selectedValue.index)
1142
- return;
1099
+ if (!listRef.current || !selectedValue) return;
1100
+ if (beforeFocusedIndex.current === selectedValue.index) return;
1143
1101
  const parent = listRef.current;
1144
1102
  const child = selectedValue.node;
1145
1103
  const parentHeight = parent.clientHeight;
@@ -1164,8 +1122,7 @@ var useAutocompleteList = () => {
1164
1122
  beforeFocusedIndex.current = selectedValue.index;
1165
1123
  }, [listRef, selectedValue]);
1166
1124
  (0, import_utils6.useUpdateEffect)(() => {
1167
- if (!isOpen)
1168
- beforeFocusedIndex.current = -1;
1125
+ if (!isOpen) beforeFocusedIndex.current = -1;
1169
1126
  }, [isOpen]);
1170
1127
  const getListProps = (0, import_react.useCallback)(
1171
1128
  (props = {}, ref = null) => ({
@@ -1288,23 +1245,18 @@ var useAutocompleteOption = (props) => {
1288
1245
  (ev) => {
1289
1246
  ev.stopPropagation();
1290
1247
  if (isDisabled) {
1291
- if (inputRef.current)
1292
- inputRef.current.focus();
1248
+ if (inputRef.current) inputRef.current.focus();
1293
1249
  return;
1294
1250
  }
1295
1251
  if (!isTargetOption(ev.currentTarget)) {
1296
- if (inputRef.current)
1297
- inputRef.current.focus();
1252
+ if (inputRef.current) inputRef.current.focus();
1298
1253
  return;
1299
1254
  }
1300
1255
  setFocusedIndex(index);
1301
1256
  onChange(optionValue != null ? optionValue : "");
1302
- if (inputRef.current)
1303
- inputRef.current.focus();
1304
- if (customCloseOnSelect != null ? customCloseOnSelect : generalCloseOnSelect)
1305
- onClose();
1306
- if (omitSelectedValues)
1307
- onFocusNext(index);
1257
+ if (inputRef.current) inputRef.current.focus();
1258
+ if (customCloseOnSelect != null ? customCloseOnSelect : generalCloseOnSelect) onClose();
1259
+ if (omitSelectedValues) onFocusNext(index);
1308
1260
  },
1309
1261
  [
1310
1262
  onFocusNext,
@@ -1321,8 +1273,7 @@ var useAutocompleteOption = (props) => {
1321
1273
  ]
1322
1274
  );
1323
1275
  (0, import_utils6.useUpdateEffect)(() => {
1324
- if (isSelected)
1325
- onChangeLabel(optionValue != null ? optionValue : "", false);
1276
+ if (isSelected) onChangeLabel(optionValue != null ? optionValue : "", false);
1326
1277
  }, [optionValue]);
1327
1278
  const getOptionProps = (0, import_react.useCallback)(
1328
1279
  (props2 = {}, ref = null) => {