UNPKG

@mantine/core

Version:

React components library focused on usability, accessibility and developer experience

166 lines (165 loc) 7.51 kB
"use client"; require("../../../_virtual/_rolldown/runtime.cjs"); const require_find_element_in_shadow_dom = require("../../../core/utils/find-element-in-shadow-dom/find-element-in-shadow-dom.cjs"); const require_get_index = require("./get-index/get-index.cjs"); let react = require("react"); let _mantine_hooks = require("@mantine/hooks"); //#region packages/@mantine/core/src/components/Combobox/use-combobox/use-combobox.ts function useCombobox({ defaultOpened, opened, onOpenedChange, onDropdownClose, onDropdownOpen, loop = true, scrollBehavior = "instant" } = {}) { const [dropdownOpened, setDropdownOpened] = (0, _mantine_hooks.useUncontrolled)({ value: opened, defaultValue: defaultOpened, finalValue: false, onChange: onOpenedChange }); const listId = (0, react.useRef)(null); const selectedOptionIndex = (0, react.useRef)(-1); const searchRef = (0, react.useRef)(null); const targetRef = (0, react.useRef)(null); const focusSearchTimeout = (0, react.useRef)(-1); const focusTargetTimeout = (0, react.useRef)(-1); const selectedIndexUpdateTimeout = (0, react.useRef)(-1); const openDropdown = (0, react.useCallback)((eventSource = "unknown") => { if (!dropdownOpened) { setDropdownOpened(true); onDropdownOpen?.(eventSource); } }, [ setDropdownOpened, onDropdownOpen, dropdownOpened ]); const closeDropdown = (0, react.useCallback)((eventSource = "unknown") => { if (dropdownOpened) { setDropdownOpened(false); onDropdownClose?.(eventSource); } }, [ setDropdownOpened, onDropdownClose, dropdownOpened ]); const toggleDropdown = (0, react.useCallback)((eventSource = "unknown") => { if (dropdownOpened) closeDropdown(eventSource); else openDropdown(eventSource); }, [ closeDropdown, openDropdown, dropdownOpened ]); const clearSelectedItem = (0, react.useCallback)(() => { const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); const selected = require_find_element_in_shadow_dom.findElementBySelector(`#${listId.current} [data-combobox-selected]`, root); selected?.removeAttribute("data-combobox-selected"); selected?.removeAttribute("aria-selected"); }, []); const selectOption = (0, react.useCallback)((index) => { const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); const list = require_find_element_in_shadow_dom.findElementBySelector(`#${listId.current}`, root); const items = list ? require_find_element_in_shadow_dom.findElementsBySelector("[data-combobox-option]", list) : null; if (!items) return null; const nextIndex = index >= items.length ? 0 : index < 0 ? items.length - 1 : index; selectedOptionIndex.current = nextIndex; if (items?.[nextIndex] && !items[nextIndex].hasAttribute("data-combobox-disabled")) { clearSelectedItem(); items[nextIndex].setAttribute("data-combobox-selected", "true"); items[nextIndex].setAttribute("aria-selected", "true"); items[nextIndex].scrollIntoView({ block: "nearest", behavior: scrollBehavior }); return items[nextIndex].id; } return null; }, [scrollBehavior, clearSelectedItem]); const selectActiveOption = (0, react.useCallback)(() => { const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); const activeOption = require_find_element_in_shadow_dom.findElementBySelector(`#${listId.current} [data-combobox-active]`, root); if (activeOption) return selectOption(require_find_element_in_shadow_dom.findElementsBySelector(`#${listId.current} [data-combobox-option]`, root).findIndex((option) => option === activeOption)); return selectOption(0); }, [selectOption]); const selectNextOption = (0, react.useCallback)(() => { const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); const items = require_find_element_in_shadow_dom.findElementsBySelector(`#${listId.current} [data-combobox-option]`, root); return selectOption(require_get_index.getNextIndex(selectedOptionIndex.current, items, loop)); }, [selectOption, loop]); const selectPreviousOption = (0, react.useCallback)(() => { const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); const items = require_find_element_in_shadow_dom.findElementsBySelector(`#${listId.current} [data-combobox-option]`, root); return selectOption(require_get_index.getPreviousIndex(selectedOptionIndex.current, items, loop)); }, [selectOption, loop]); const selectFirstOption = (0, react.useCallback)(() => { const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); return selectOption(require_get_index.getFirstIndex(require_find_element_in_shadow_dom.findElementsBySelector(`#${listId.current} [data-combobox-option]`, root))); }, [selectOption]); const updateSelectedOptionIndex = (0, react.useCallback)((target = "selected", options) => { if (typeof target === "number") { selectedOptionIndex.current = target; const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); const items = require_find_element_in_shadow_dom.findElementsBySelector(`#${listId.current} [data-combobox-option]`, root); if (options?.scrollIntoView) items[target]?.scrollIntoView({ block: "nearest", behavior: scrollBehavior }); return; } selectedIndexUpdateTimeout.current = window.setTimeout(() => { const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); const items = require_find_element_in_shadow_dom.findElementsBySelector(`#${listId.current} [data-combobox-option]`, root); const index = items.findIndex((option) => option.hasAttribute(`data-combobox-${target}`)); selectedOptionIndex.current = index; if (options?.scrollIntoView) items[index]?.scrollIntoView({ block: "nearest", behavior: scrollBehavior }); }, 0); }, []); const resetSelectedOption = (0, react.useCallback)(() => { selectedOptionIndex.current = -1; clearSelectedItem(); }, [clearSelectedItem]); const clickSelectedOption = (0, react.useCallback)(() => { const root = require_find_element_in_shadow_dom.getRootElement(targetRef.current); (require_find_element_in_shadow_dom.findElementsBySelector(`#${listId.current} [data-combobox-option]`, root)?.[selectedOptionIndex.current])?.click(); }, []); const setListId = (0, react.useCallback)((id) => { listId.current = id; }, []); const focusSearchInput = (0, react.useCallback)(() => { focusSearchTimeout.current = window.setTimeout(() => searchRef.current?.focus(), 0); }, []); const focusTarget = (0, react.useCallback)(() => { focusTargetTimeout.current = window.setTimeout(() => targetRef.current?.focus(), 0); }, []); const getSelectedOptionIndex = (0, react.useCallback)(() => selectedOptionIndex.current, []); (0, react.useEffect)(() => () => { window.clearTimeout(focusSearchTimeout.current); window.clearTimeout(focusTargetTimeout.current); window.clearTimeout(selectedIndexUpdateTimeout.current); }, []); return { dropdownOpened, openDropdown, closeDropdown, toggleDropdown, selectedOptionIndex: selectedOptionIndex.current, getSelectedOptionIndex, selectOption, selectFirstOption, selectActiveOption, selectNextOption, selectPreviousOption, resetSelectedOption, updateSelectedOptionIndex, listId: listId.current, setListId, clickSelectedOption, searchRef, focusSearchInput, targetRef, focusTarget }; } //#endregion exports.useCombobox = useCombobox; //# sourceMappingURL=use-combobox.cjs.map