UNPKG

@yamada-ui/react

Version:

React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion

417 lines (413 loc) • 15.1 kB
"use client"; const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs'); const require_context = require('../../utils/context.cjs'); const require_dom = require('../../utils/dom.cjs'); const require_effect = require('../../utils/effect.cjs'); const require_ref = require('../../utils/ref.cjs'); const require_utils_index = require('../../utils/index.cjs'); const require_hooks_use_controllable_state_index = require('../../hooks/use-controllable-state/index.cjs'); const require_i18n_provider = require('../../providers/i18n-provider/i18n-provider.cjs'); const require_use_field_props = require('../field/use-field-props.cjs'); const require_hooks_use_combobox_index = require('../../hooks/use-combobox/index.cjs'); let react = require("react"); react = require_rolldown_runtime.__toESM(react); let react_jsx_runtime = require("react/jsx-runtime"); react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime); //#region src/components/autocomplete/use-autocomplete.tsx const defaultRender = ({ count, focused, index, label, max, separator }) => { const last = count - 1 === index; return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { style: { marginInlineEnd: "var(--gap)" }, children: [label, (!(0, require_utils_index.utils_exports.isNumber)(max) || count < max) && focused || !last ? separator : null] }); }; const getInputValue = (item) => (0, require_utils_index.utils_exports.isString)(item?.label) ? item.label : item?.query ?? ""; const defaultFilter = (inputValue, items, matcher) => { if (!inputValue.length) return items; return items.map((item) => { if ("items" in item) { const items$1 = item.items.filter((item$1) => { if ("query" in item$1) return matcher(inputValue, item$1.query); else if ((0, require_utils_index.utils_exports.isString)(item$1.label)) return matcher(inputValue, item$1.label); }); if (items$1.length) return { ...item, items: items$1 }; } else if ("query" in item) { if (matcher(inputValue, item.query)) return item; } else if ((0, require_utils_index.utils_exports.isString)(item.label)) { if (matcher(inputValue, item.label)) return item; } }).filter(Boolean); }; const defaultMatcher = (input, target) => target?.toLowerCase().includes(input.toLowerCase()) ?? false; const [AutocompleteContext, useAutocompleteContext] = require_context.createContext({ name: "AutocompleteContext" }); const useAutocomplete = (props = {}) => { const { t } = require_i18n_provider.useI18n("autocomplete"); const { props: { id, ref, name, allowCustomValue = false, closeOnChange = false, multiple = false, closeOnSelect = !multiple, defaultInputValue, defaultValue = multiple ? [] : "", disabled, emptyMessage = t("No results found"), filter = defaultFilter, focusOnClear = true, inputValue: inputValueProp, items = [], matcher = defaultMatcher, max, openOnChange = true, openOnClick = true, openOnFocus = true, placeholder, readOnly, render = defaultRender, required, separator = ",", value: valueProp, onChange: onChangeProp, onInputChange: onInputChangeProp,...rest }, ariaProps, dataProps, eventProps } = require_use_field_props.useFieldProps(props); const fieldRef = (0, react.useRef)(null); const contentRef = (0, react.useRef)(null); const inputRef = (0, react.useRef)(null); const focusByClickRef = (0, react.useRef)(false); const valueMap = (0, react.useMemo)(() => { const valueMap$1 = {}; items.forEach((item) => { if ("items" in item) item.items.forEach((item$1) => { item$1.value ??= (0, require_utils_index.utils_exports.isString)(item$1.label) ? item$1.label : void 0; if (!(0, require_utils_index.utils_exports.isUndefined)(item$1.value)) valueMap$1[item$1.value] = item$1; }); else { item.value ??= (0, require_utils_index.utils_exports.isString)(item.label) ? item.label : void 0; if (!(0, require_utils_index.utils_exports.isUndefined)(item.value)) valueMap$1[item.value] = item; } }); return valueMap$1; }, [items]); const [focused, setFocused] = (0, react.useState)(false); const [value, setValue] = require_hooks_use_controllable_state_index.useControllableState({ defaultValue, value: valueProp, onChange: onChangeProp }); const [inputValue, setInputValue] = require_hooks_use_controllable_state_index.useControllableState({ defaultValue: defaultInputValue ?? getInputValue((0, require_utils_index.utils_exports.isArray)(value) ? void 0 : valueMap[value]), value: inputValueProp, onChange: onInputChangeProp }); const onChange = (0, react.useCallback)((selectedValue) => { setValue((prev) => { if ((0, require_utils_index.utils_exports.isArray)(prev)) if (prev.includes(selectedValue)) return prev.filter((prevValue) => prevValue !== selectedValue); else if (!(0, require_utils_index.utils_exports.isNumber)(max) || prev.length < max) return [...prev, selectedValue]; else return prev; else return selectedValue; }); if ((0, require_utils_index.utils_exports.isArray)(value)) setInputValue(""); else { const item = valueMap[selectedValue]; setInputValue(getInputValue(item)); } }, [ max, setInputValue, setValue, value, valueMap ]); const { activeDescendant, descendants, interactive, open, getContentProps: getComboboxContentProps, getSeparatorProps, getTriggerProps, popoverProps, onActiveDescendant, onClose, onOpen, onOpenWithActiveDescendant, onSelect } = require_hooks_use_combobox_index.useCombobox({ closeOnSelect, disabled, initialFocusValue: (0, require_utils_index.utils_exports.isArray)(value) ? value[0] : value, openOnClick: false, openOnEnter: false, openOnSpace: false, readOnly, selectFocusRef: inputRef, selectOnSpace: false, onChange, ...ariaProps, ...dataProps, ...eventProps, ...rest }); const filteredItems = (0, react.useMemo)(() => { if (!items.length) return []; return filter(inputValue, items, matcher); }, [ filter, inputValue, items, matcher ]); const resolvedItems = (0, react.useMemo)(() => { return filteredItems.length ? filteredItems : [{ "data-empty": "", label: emptyMessage }]; }, [filteredItems, emptyMessage]); const empty = (0, react.useMemo)(() => !resolvedItems.filter(({ hidden }) => !hidden).length, [resolvedItems]); const children = (0, react.useMemo)(() => { if (!(0, require_utils_index.utils_exports.isArray)(value)) return null; const count = value.length; return value.map((value$1, index) => { const item = valueMap[value$1] ?? { label: value$1, value: value$1 }; const onClear$1 = (ev) => { ev?.preventDefault(); ev?.stopPropagation(); if (item.value) onChange(item.value); }; const component = render({ count, focused, index, max, separator, onClear: onClear$1, ...item }); if ((0, react.isValidElement)(component)) return (0, react.cloneElement)(component, { ...component.props, key: index }); else return component; }); }, [ focused, max, onChange, render, separator, value, valueMap ]); const hasValues = (0, require_utils_index.utils_exports.isArray)(value) && !!value.length; const onInputChange = (0, react.useCallback)((ev) => { if ((0, require_utils_index.utils_exports.isArray)(value) && value.length === max) return; if ((0, require_utils_index.utils_exports.runIfFn)(closeOnChange, ev)) onClose(); else if ((0, require_utils_index.utils_exports.runIfFn)(openOnChange, ev)) onOpen(); activeDescendant.current = null; const inputValue$1 = ev.target.value; setInputValue(inputValue$1); if (inputValue$1.length || (0, require_utils_index.utils_exports.isArray)(value)) return; setValue(""); }, [ activeDescendant, closeOnChange, max, onClose, onOpen, openOnChange, setInputValue, setValue, value ]); const onKeyDown = (0, react.useCallback)((ev) => { if (disabled || require_dom.isComposing(ev)) return; const inputValue$1 = (0, require_utils_index.utils_exports.cast)(ev.target).value; require_dom.runKeyAction(ev, { Backspace: (ev$1) => { if (!(0, require_utils_index.utils_exports.isArray)(value)) return; if (!!inputValue$1.length) return; ev$1.preventDefault(); setValue((prev) => prev.slice(0, -1)); }, Enter: (ev$1) => { if (!open || !inputValue$1.length || activeDescendant.current) return; const item = filteredItems[0]; if (!item) { if (!allowCustomValue || !(0, require_utils_index.utils_exports.isArray)(value)) return; ev$1.preventDefault(); onSelect(inputValue$1); } else { ev$1.preventDefault(); if ("items" in item) onSelect(item.items[0]?.value); else onSelect(item.value); } } }, { preventDefault: false }); }, [ activeDescendant, allowCustomValue, disabled, filteredItems, onSelect, open, setValue, value ]); const onClick = (0, react.useCallback)(() => { if (!interactive) return; focusByClickRef.current = true; inputRef.current?.focus(); if (openOnClick) onOpenWithActiveDescendant(descendants.enabledFirstValue); }, [ descendants, interactive, onOpenWithActiveDescendant, openOnClick ]); const onMouseDown = (0, react.useCallback)((ev) => { if (!openOnFocus) return; ev.preventDefault(); ev.stopPropagation(); }, [openOnFocus]); const onFocus = (0, react.useCallback)((ev) => { ev.preventDefault(); ev.stopPropagation(); setFocused(true); if (openOnFocus && !focusByClickRef.current) onOpenWithActiveDescendant(descendants.enabledFirstValue); focusByClickRef.current = false; }, [ openOnFocus, onOpenWithActiveDescendant, descendants.enabledFirstValue ]); const onBlur = (0, react.useCallback)((ev) => { setFocused(false); if ((0, require_utils_index.utils_exports.contains)(fieldRef.current, ev.relatedTarget) || (0, require_utils_index.utils_exports.contains)(contentRef.current, ev.relatedTarget)) ev.preventDefault(); else if ((0, require_utils_index.utils_exports.isArray)(value)) setInputValue(""); else if (allowCustomValue) { if (inputValue) setValue(inputValue); } else { const item = valueMap[value]; setInputValue(getInputValue(item)); } }, [ allowCustomValue, inputValue, setInputValue, setValue, value, valueMap ]); const onClear = (0, react.useCallback)(() => { if (!interactive) return; setValue((prev) => (0, require_utils_index.utils_exports.isArray)(prev) ? [] : ""); setInputValue(""); if (focusOnClear) inputRef.current?.focus(); }, [ focusOnClear, interactive, setInputValue, setValue ]); require_effect.useUpdateEffect(() => { if ((0, require_utils_index.utils_exports.isArray)(valueProp)) return; setInputValue(getInputValue(valueProp ? valueMap[valueProp] : void 0)); }, [valueProp]); const getRootProps = (0, react.useCallback)((props$1) => ({ ...dataProps, ...props$1 }), [dataProps]); const getFieldProps = (0, react.useCallback)(({ ref: ref$1,...props$1 } = {}) => getTriggerProps({ ref: require_ref.mergeRefs(ref$1, fieldRef), tabIndex: -1, ...props$1, onClick: (0, require_utils_index.utils_exports.handlerAll)(props$1.onClick, onClick) }), [getTriggerProps, onClick]); const getInputProps = (0, react.useCallback)((props$1 = {}) => ({ id, ref: require_ref.mergeRefs(props$1.ref, ref, inputRef), name, style: { ...!focused && (0, require_utils_index.utils_exports.isArray)(value) && !!value.length ? require_dom.visuallyHiddenAttributes.style : {}, ...props$1.style }, "data-max": (0, require_utils_index.utils_exports.dataAttr)((0, require_utils_index.utils_exports.isArray)(value) && (0, require_utils_index.utils_exports.isNumber)(max) && value.length >= max), autoCapitalize: "off", autoComplete: "off", autoCorrect: "off", disabled, placeholder: hasValues ? void 0 : placeholder, readOnly, required, spellCheck: false, value: inputValue, ...dataProps, ...props$1, onBlur: (0, require_utils_index.utils_exports.handlerAll)(props$1.onBlur, onBlur), onChange: (0, require_utils_index.utils_exports.handlerAll)(props$1.onChange, onInputChange), onFocus: (0, require_utils_index.utils_exports.handlerAll)(props$1.onFocus, onFocus), onKeyDown: (0, require_utils_index.utils_exports.handlerAll)(props$1.onKeyDown, onKeyDown), onMouseDown: (0, require_utils_index.utils_exports.handlerAll)(props$1.onMouseDown, onMouseDown) }), [ dataProps, disabled, focused, hasValues, id, inputValue, max, name, onBlur, onFocus, onInputChange, onKeyDown, onMouseDown, placeholder, readOnly, ref, required, value ]); const getContentProps = (0, react.useCallback)(({ ref: ref$1,...props$1 } = {}) => getComboboxContentProps({ ref: require_ref.mergeRefs(ref$1, contentRef), hidden: empty, ...props$1 }), [empty, getComboboxContentProps]); const getIconProps = (0, react.useCallback)((props$1) => ({ ...dataProps, ...props$1 }), [dataProps]); return { children, descendants, inputValue, interactive, items: resolvedItems, max, open, setInputValue, setValue, value, valueMap, getClearIconProps: (0, react.useCallback)((props$1 = {}) => getIconProps({ "aria-disabled": (0, require_utils_index.utils_exports.ariaAttr)(!interactive), "aria-label": t("Clear value"), role: "button", tabIndex: interactive ? 0 : -1, ...props$1, onClick: (0, require_utils_index.utils_exports.handlerAll)(props$1.onClick, onClear), onKeyDown: (0, require_utils_index.utils_exports.handlerAll)(props$1.onKeyDown, (ev) => require_dom.runKeyAction(ev, { Enter: onClear, Space: onClear })) }), [ getIconProps, interactive, onClear, t ]), getContentProps, getFieldProps, getIconProps, getInputProps, getRootProps, getSeparatorProps, popoverProps, onActiveDescendant, onChange, onClose, onInputChange, onOpen, onSelect }; }; const useAutocompleteOption = ({ children, closeOnSelect, disabled, hidden, value,...rest } = {}) => { const { max, value: selectedValue } = useAutocompleteContext(); value ??= (0, require_utils_index.utils_exports.isString)(children) ? children : void 0; const selected = (0, require_utils_index.utils_exports.isArray)(selectedValue) ? !(0, require_utils_index.utils_exports.isUndefined)(value) && selectedValue.includes(value) : selectedValue === value; const completed = (0, require_utils_index.utils_exports.isNumber)(max) && (0, require_utils_index.utils_exports.isArray)(selectedValue) && selectedValue.length >= max; const { getIndicatorProps, getItemProps } = require_hooks_use_combobox_index.useComboboxItem({ children, closeOnSelect, disabled: disabled || hidden || completed && !selected, hidden, selected, value, ...rest }); return { getIndicatorProps, getOptionProps: (0, react.useCallback)((props = {}) => getItemProps(props), [getItemProps]) }; }; //#endregion exports.AutocompleteContext = AutocompleteContext; exports.useAutocomplete = useAutocomplete; exports.useAutocompleteContext = useAutocompleteContext; exports.useAutocompleteOption = useAutocompleteOption; //# sourceMappingURL=use-autocomplete.cjs.map