@yamada-ui/autocomplete
Version:
Yamada UI autocomplete component
1 lines • 11.5 kB
Source Map (JSON)
{"version":3,"sources":["../src/use-autocomplete-option.ts"],"sourcesContent":["import type { HTMLUIProps, PropGetter } from \"@yamada-ui/core\"\nimport type { CSSProperties, MouseEvent } from \"react\"\nimport {\n ariaAttr,\n dataAttr,\n handlerAll,\n isArray,\n isHTMLElement,\n isNumber,\n isString,\n isUndefined,\n mergeRefs,\n} from \"@yamada-ui/utils\"\nimport { useCallback, useId, useMemo, useRef } from \"react\"\nimport {\n useAutocompleteContext,\n useAutocompleteDescendant,\n} from \"./autocomplete-context\"\n\nconst isTargetOption = (target: EventTarget | null): boolean =>\n isHTMLElement(target) && !!target.getAttribute(\"role\")?.startsWith(\"option\")\n\nexport interface UseAutocompleteOptionProps\n extends Omit<HTMLUIProps, \"children\" | \"value\"> {\n /**\n * The label of the autocomplete option.\n */\n children?: string\n /**\n * If `true`, the list element will be closed when selected.\n *\n * @default false\n */\n closeOnSelect?: boolean\n /**\n * If `true`, the autocomplete option will be disabled.\n *\n * @default false\n */\n disabled?: boolean\n /**\n * If `true`, the autocomplete option will be focusable.\n *\n * @default false\n */\n focusable?: boolean\n /**\n * If `true`, the autocomplete option will be disabled.\n *\n * @default false\n *\n * @deprecated Use `disabled` instead.\n */\n isDisabled?: boolean\n /**\n * If `true`, the autocomplete option will be focusable.\n *\n * @default false\n *\n * @deprecated Use `focusable` instead.\n */\n isFocusable?: boolean\n /**\n * The value of the autocomplete option.\n */\n value?: string\n}\n\nexport const useAutocompleteOption = (props: UseAutocompleteOptionProps) => {\n const {\n closeOnSelect,\n focusedIndex,\n inputRef,\n omitSelectedValues,\n setFocusedIndex,\n value: selectedValue,\n optionProps,\n onChange,\n onClose,\n onFocusNext,\n } = useAutocompleteContext()\n const uuid = useId()\n const itemRef = useRef<HTMLLIElement>(null)\n const {\n id = uuid,\n children,\n closeOnSelect: customCloseOnSelect,\n isDisabled,\n disabled = isDisabled,\n isFocusable,\n focusable = isFocusable,\n icon: customIcon,\n value: optionValue,\n ...computedProps\n } = { ...optionProps, ...props }\n const trulyDisabled = !!disabled && !focusable\n const { descendants, index, register } = useAutocompleteDescendant({\n disabled: trulyDisabled,\n })\n const values = descendants.values()\n const frontValues = values.slice(0, index)\n const multi = isArray(selectedValue)\n const target = \"target\" in (itemRef.current?.dataset ?? {})\n const focused = index === focusedIndex\n\n const value = useMemo(() => {\n let value = optionValue\n\n if (isUndefined(optionValue)) {\n if (isString(children) || isNumber(children)) {\n value = children.toString()\n } else {\n console.warn(\n `${\n !multi ? \"Autocomplete\" : \"MultiAutocomplete\"\n }: Cannot infer the option value of complex children. Pass a \\`value\\` prop or use a plain string as children to <Option>.`,\n )\n }\n }\n\n return value ?? \"\"\n }, [children, multi, optionValue])\n\n const duplicated = frontValues.some(\n ({ node }) => node.dataset.value === value,\n )\n const selected =\n !duplicated &&\n (!multi ? value === selectedValue : selectedValue.includes(value))\n\n const onClick = useCallback(\n (ev: MouseEvent<HTMLDivElement>) => {\n ev.stopPropagation()\n\n if (disabled || !isTargetOption(ev.currentTarget)) {\n if (inputRef.current) inputRef.current.focus()\n\n return\n }\n\n if (!duplicated) setFocusedIndex(index)\n\n onChange(value)\n\n if (inputRef.current) inputRef.current.focus()\n\n if (customCloseOnSelect ?? closeOnSelect) onClose()\n\n if (omitSelectedValues) onFocusNext(index)\n },\n [\n duplicated,\n onFocusNext,\n omitSelectedValues,\n disabled,\n value,\n setFocusedIndex,\n index,\n onChange,\n customCloseOnSelect,\n closeOnSelect,\n onClose,\n inputRef,\n ],\n )\n\n const getOptionProps: PropGetter = useCallback(\n (props = {}, ref = null) => {\n const hidden = !target || (omitSelectedValues && selected)\n\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n margin: \"-1px\",\n overflow: \"hidden\",\n padding: \"0px\",\n position: \"absolute\",\n whiteSpace: \"nowrap\",\n width: \"1px\",\n }\n\n return {\n ref: mergeRefs(itemRef, ref, register),\n role: \"option\",\n ...computedProps,\n ...props,\n id,\n style: hidden ? style : undefined,\n \"aria-disabled\": ariaAttr(disabled),\n \"aria-hidden\": ariaAttr(hidden),\n \"aria-selected\": selected,\n \"data-disabled\": dataAttr(disabled),\n \"data-duplicated\": dataAttr(duplicated),\n \"data-focus\": dataAttr(focused),\n \"data-target\": dataAttr(true),\n \"data-value\": value,\n tabIndex: -1,\n onClick: handlerAll(computedProps.onClick, props.onClick, onClick),\n }\n },\n [\n id,\n duplicated,\n value,\n computedProps,\n disabled,\n focused,\n selected,\n target,\n omitSelectedValues,\n onClick,\n register,\n ],\n )\n\n return {\n target,\n children,\n customIcon,\n focused,\n omitSelectedValues,\n selected,\n getOptionProps,\n }\n}\n\nexport type UseAutocompleteOptionReturn = ReturnType<\n typeof useAutocompleteOption\n>\n\nexport const useAutocompleteCreate = () => {\n const { hit, onCreate } = useAutocompleteContext()\n\n const getCreateProps: PropGetter = useCallback(\n (props = {}, ref = null) => {\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n margin: \"-1px\",\n overflow: \"hidden\",\n padding: \"0px\",\n position: \"absolute\",\n whiteSpace: \"nowrap\",\n width: \"1px\",\n }\n\n return {\n ref,\n role: \"option\",\n ...props,\n style: hit ? style : undefined,\n \"aria-hidden\": ariaAttr(hit),\n \"data-focus\": dataAttr(!hit),\n tabIndex: -1,\n onClick: handlerAll(props.onClick, onCreate),\n }\n },\n [hit, onCreate],\n )\n\n return { getCreateProps }\n}\n\nexport type UseAutocompleteCreateReturn = ReturnType<\n typeof useAutocompleteCreate\n>\n\nexport const useAutocompleteEmpty = () => {\n const { empty, hit } = useAutocompleteContext()\n\n const getEmptyProps: PropGetter = useCallback(\n (props = {}, ref = null) => {\n const hidden = hit && !empty\n\n const style: CSSProperties = {\n border: \"0px\",\n clip: \"rect(0px, 0px, 0px, 0px)\",\n height: \"1px\",\n margin: \"-1px\",\n overflow: \"hidden\",\n padding: \"0px\",\n position: \"absolute\",\n whiteSpace: \"nowrap\",\n width: \"1px\",\n }\n\n return {\n ref,\n role: \"presentation\",\n ...props,\n style: hidden ? style : undefined,\n \"aria-hidden\": ariaAttr(hidden),\n tabIndex: -1,\n }\n },\n [hit, empty],\n )\n\n return { getEmptyProps }\n}\n\nexport type UseAutocompleteEmptyReturn = ReturnType<typeof useAutocompleteEmpty>\n"],"mappings":"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","names":["value","props"]}