UNPKG

@ariakit/react-core

Version:

Ariakit React core

264 lines (262 loc) 8.26 kB
"use client"; import { SelectArrow } from "../__chunks/FLBH5CWF.js"; import { SelectScopedContextProvider, useSelectProviderContext } from "../__chunks/LM7KIZUU.js"; import "../__chunks/A5NH37Z4.js"; import { useCompositeTypeahead } from "../__chunks/OYOFZOGB.js"; import { usePopoverDisclosure } from "../__chunks/4I4MLMKD.js"; import "../__chunks/HMCFFQCB.js"; import "../__chunks/ZTXFEM5L.js"; import "../__chunks/NMGNQVTG.js"; import "../__chunks/5VQZOHHZ.js"; import "../__chunks/Y67KZUMI.js"; import "../__chunks/T2AZQXQU.js"; import "../__chunks/ABN76PSX.js"; import "../__chunks/APTFW6PT.js"; import "../__chunks/XCKGTAUF.js"; import "../__chunks/2W3RN7C5.js"; import "../__chunks/OE2EFRVA.js"; import "../__chunks/SWN3JYXT.js"; import "../__chunks/5CPL3B7G.js"; import { createElement, createHook, forwardRef } from "../__chunks/VOQWLFSQ.js"; import { useBooleanEvent, useEvent, useMergeRefs, useWrapElement } from "../__chunks/5GGHRIN3.js"; import "../__chunks/SK3NAZA3.js"; import { __objRest, __spreadProps, __spreadValues } from "../__chunks/3YLGPPWQ.js"; // src/select/select.tsx import { toArray } from "@ariakit/core/utils/array"; import { getPopupRole } from "@ariakit/core/utils/dom"; import { queueBeforeEvent } from "@ariakit/core/utils/events"; import { invariant } from "@ariakit/core/utils/misc"; import { useEffect, useMemo, useRef, useState } from "react"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; var TagName = "button"; function getSelectedValues(select) { return Array.from(select.selectedOptions).map((option) => option.value); } function nextWithValue(store, next) { return () => { const nextId = next(); if (!nextId) return; let i = 0; let nextItem = store.item(nextId); const firstItem = nextItem; while (nextItem && nextItem.value == null) { const nextId2 = next(++i); if (!nextId2) return; nextItem = store.item(nextId2); if (nextItem === firstItem) break; } return nextItem == null ? void 0 : nextItem.id; }; } var useSelect = createHook(function useSelect2(_a) { var _b = _a, { store, name, form, required, showOnKeyDown = true, moveOnKeyDown = true, toggleOnPress = true, toggleOnClick = toggleOnPress } = _b, props = __objRest(_b, [ "store", "name", "form", "required", "showOnKeyDown", "moveOnKeyDown", "toggleOnPress", "toggleOnClick" ]); const context = useSelectProviderContext(); store = store || context; invariant( store, process.env.NODE_ENV !== "production" && "Select must receive a `store` prop or be wrapped in a SelectProvider component." ); const onKeyDownProp = props.onKeyDown; const showOnKeyDownProp = useBooleanEvent(showOnKeyDown); const moveOnKeyDownProp = useBooleanEvent(moveOnKeyDown); const placement = store.useState("placement"); const dir = placement.split("-")[0]; const value = store.useState("value"); const multiSelectable = Array.isArray(value); const onKeyDown = useEvent((event) => { var _a2; onKeyDownProp == null ? void 0 : onKeyDownProp(event); if (event.defaultPrevented) return; if (!store) return; const { orientation, items: items2, activeId } = store.getState(); const isVertical = orientation !== "horizontal"; const isHorizontal = orientation !== "vertical"; const isGrid = !!((_a2 = items2.find((item) => !item.disabled && item.value != null)) == null ? void 0 : _a2.rowId); const moveKeyMap = { ArrowUp: (isGrid || isVertical) && nextWithValue(store, store.up), ArrowRight: (isGrid || isHorizontal) && nextWithValue(store, store.next), ArrowDown: (isGrid || isVertical) && nextWithValue(store, store.down), ArrowLeft: (isGrid || isHorizontal) && nextWithValue(store, store.previous) }; const getId = moveKeyMap[event.key]; if (getId && moveOnKeyDownProp(event)) { event.preventDefault(); store.move(getId()); } const isTopOrBottom = dir === "top" || dir === "bottom"; const isLeft = dir === "left"; const isRight = dir === "right"; const canShowKeyMap = { ArrowDown: isTopOrBottom, ArrowUp: isTopOrBottom, ArrowLeft: isLeft, ArrowRight: isRight }; const canShow = canShowKeyMap[event.key]; if (canShow && showOnKeyDownProp(event)) { event.preventDefault(); store.move(activeId); queueBeforeEvent(event.currentTarget, "keyup", store.show); } }); props = useWrapElement( props, (element) => /* @__PURE__ */ jsx(SelectScopedContextProvider, { value: store, children: element }), [store] ); const [autofill, setAutofill] = useState(false); const nativeSelectChangedRef = useRef(false); useEffect(() => { const nativeSelectChanged = nativeSelectChangedRef.current; nativeSelectChangedRef.current = false; if (nativeSelectChanged) return; setAutofill(false); }, [value]); const labelId = store.useState((state) => { var _a2; return (_a2 = state.labelElement) == null ? void 0 : _a2.id; }); const label = props["aria-label"]; const labelledBy = props["aria-labelledby"] || labelId; const items = store.useState((state) => { if (!name) return; return state.items; }); const values = useMemo(() => { return [...new Set(items == null ? void 0 : items.map((i) => i.value).filter((v) => v != null))]; }, [items]); props = useWrapElement( props, (element) => { if (!name) return element; return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs( "select", { style: { border: 0, clip: "rect(0 0 0 0)", height: "1px", margin: "-1px", overflow: "hidden", padding: 0, position: "absolute", whiteSpace: "nowrap", width: "1px" }, tabIndex: -1, "aria-hidden": true, "aria-label": label, "aria-labelledby": labelledBy, name, form, required, disabled: props.disabled, value, multiple: multiSelectable, onFocus: () => { var _a2; return (_a2 = store == null ? void 0 : store.getState().selectElement) == null ? void 0 : _a2.focus(); }, onChange: (event) => { nativeSelectChangedRef.current = true; setAutofill(true); store == null ? void 0 : store.setValue( multiSelectable ? getSelectedValues(event.target) : event.target.value ); }, children: [ toArray(value).map((value2) => { if (value2 == null) return null; if (values.includes(value2)) return null; return /* @__PURE__ */ jsx("option", { value: value2, children: value2 }, value2); }), values.map((value2) => /* @__PURE__ */ jsx("option", { value: value2, children: value2 }, value2)) ] } ), element ] }); }, [ store, label, labelledBy, name, form, required, value, multiSelectable, values, props.disabled ] ); const children = /* @__PURE__ */ jsxs(Fragment, { children: [ value, /* @__PURE__ */ jsx(SelectArrow, {}) ] }); const contentElement = store.useState("contentElement"); props = __spreadProps(__spreadValues({ role: "combobox", "aria-autocomplete": "none", "aria-labelledby": labelId, "aria-haspopup": getPopupRole(contentElement, "listbox"), "data-autofill": autofill || void 0, "data-name": name, children }, props), { ref: useMergeRefs(store.setSelectElement, props.ref), onKeyDown }); props = usePopoverDisclosure(__spreadValues({ store, toggleOnClick }, props)); props = useCompositeTypeahead(__spreadValues({ store }, props)); return props; }); var Select = forwardRef(function Select2(props) { const htmlProps = useSelect(props); return createElement(TagName, htmlProps); }); export { Select, useSelect };