@yamada-ui/autocomplete
Version:
Yamada UI autocomplete component
228 lines (226 loc) • 5.96 kB
JavaScript
"use client"
import {
useAutocompleteContext,
useAutocompleteDescendant
} from "./chunk-X5V76SN2.mjs";
// src/use-autocomplete-option.ts
import {
ariaAttr,
dataAttr,
handlerAll,
isArray,
isHTMLElement,
isNumber,
isString,
isUndefined,
mergeRefs
} from "@yamada-ui/utils";
import { useCallback, useId, useMemo, useRef } from "react";
var isTargetOption = (target) => {
var _a;
return isHTMLElement(target) && !!((_a = target.getAttribute("role")) == null ? void 0 : _a.startsWith("option"));
};
var useAutocompleteOption = (props) => {
var _a, _b;
const {
closeOnSelect,
focusedIndex,
inputRef,
omitSelectedValues,
setFocusedIndex,
value: selectedValue,
optionProps,
onChange,
onClose,
onFocusNext
} = useAutocompleteContext();
const uuid = useId();
const itemRef = useRef(null);
const {
id = uuid,
children,
closeOnSelect: customCloseOnSelect,
isDisabled,
disabled = isDisabled,
isFocusable,
focusable = isFocusable,
icon: customIcon,
value: optionValue,
...computedProps
} = { ...optionProps, ...props };
const trulyDisabled = !!disabled && !focusable;
const { descendants, index, register } = useAutocompleteDescendant({
disabled: trulyDisabled
});
const values = descendants.values();
const frontValues = values.slice(0, index);
const multi = isArray(selectedValue);
const target = "target" in ((_b = (_a = itemRef.current) == null ? void 0 : _a.dataset) != null ? _b : {});
const focused = index === focusedIndex;
const value = useMemo(() => {
let value2 = optionValue;
if (isUndefined(optionValue)) {
if (isString(children) || isNumber(children)) {
value2 = children.toString();
} else {
console.warn(
`${!multi ? "Autocomplete" : "MultiAutocomplete"}: Cannot infer the option value of complex children. Pass a \`value\` prop or use a plain string as children to <Option>.`
);
}
}
return value2 != null ? value2 : "";
}, [children, multi, optionValue]);
const duplicated = frontValues.some(
({ node }) => node.dataset.value === value
);
const selected = !duplicated && (!multi ? value === selectedValue : selectedValue.includes(value));
const onClick = useCallback(
(ev) => {
ev.stopPropagation();
if (disabled || !isTargetOption(ev.currentTarget)) {
if (inputRef.current) inputRef.current.focus();
return;
}
if (!duplicated) setFocusedIndex(index);
onChange(value);
if (inputRef.current) inputRef.current.focus();
if (customCloseOnSelect != null ? customCloseOnSelect : closeOnSelect) onClose();
if (omitSelectedValues) onFocusNext(index);
},
[
duplicated,
onFocusNext,
omitSelectedValues,
disabled,
value,
setFocusedIndex,
index,
onChange,
customCloseOnSelect,
closeOnSelect,
onClose,
inputRef
]
);
const getOptionProps = useCallback(
(props2 = {}, ref = null) => {
const hidden = !target || omitSelectedValues && selected;
const style = {
border: "0px",
clip: "rect(0px, 0px, 0px, 0px)",
height: "1px",
margin: "-1px",
overflow: "hidden",
padding: "0px",
position: "absolute",
whiteSpace: "nowrap",
width: "1px"
};
return {
ref: mergeRefs(itemRef, ref, register),
role: "option",
...computedProps,
...props2,
id,
style: hidden ? style : void 0,
"aria-disabled": ariaAttr(disabled),
"aria-hidden": ariaAttr(hidden),
"aria-selected": selected,
"data-disabled": dataAttr(disabled),
"data-duplicated": dataAttr(duplicated),
"data-focus": dataAttr(focused),
"data-target": dataAttr(true),
"data-value": value,
tabIndex: -1,
onClick: handlerAll(computedProps.onClick, props2.onClick, onClick)
};
},
[
id,
duplicated,
value,
computedProps,
disabled,
focused,
selected,
target,
omitSelectedValues,
onClick,
register
]
);
return {
target,
children,
customIcon,
focused,
omitSelectedValues,
selected,
getOptionProps
};
};
var useAutocompleteCreate = () => {
const { hit, onCreate } = useAutocompleteContext();
const getCreateProps = useCallback(
(props = {}, ref = null) => {
const style = {
border: "0px",
clip: "rect(0px, 0px, 0px, 0px)",
height: "1px",
margin: "-1px",
overflow: "hidden",
padding: "0px",
position: "absolute",
whiteSpace: "nowrap",
width: "1px"
};
return {
ref,
role: "option",
...props,
style: hit ? style : void 0,
"aria-hidden": ariaAttr(hit),
"data-focus": dataAttr(!hit),
tabIndex: -1,
onClick: handlerAll(props.onClick, onCreate)
};
},
[hit, onCreate]
);
return { getCreateProps };
};
var useAutocompleteEmpty = () => {
const { empty, hit } = useAutocompleteContext();
const getEmptyProps = useCallback(
(props = {}, ref = null) => {
const hidden = hit && !empty;
const style = {
border: "0px",
clip: "rect(0px, 0px, 0px, 0px)",
height: "1px",
margin: "-1px",
overflow: "hidden",
padding: "0px",
position: "absolute",
whiteSpace: "nowrap",
width: "1px"
};
return {
ref,
role: "presentation",
...props,
style: hidden ? style : void 0,
"aria-hidden": ariaAttr(hidden),
tabIndex: -1
};
},
[hit, empty]
);
return { getEmptyProps };
};
export {
useAutocompleteOption,
useAutocompleteCreate,
useAutocompleteEmpty
};
//# sourceMappingURL=chunk-NC62LKUX.mjs.map