UNPKG

@trail-ui/react

Version:
196 lines (193 loc) 6.24 kB
import { ListBox } from "./chunk-O34YT5G7.mjs"; import { _Spinner } from "./chunk-P3AIC7XZ.mjs"; // src/select/select.tsx import { ChevronDownIcon, ErrorIcon } from "@trail-ui/icons"; import { clsx } from "@trail-ui/shared-utils"; import { select } from "@trail-ui/theme"; import { cloneElement, forwardRef, useEffect, useMemo, useRef, useState } from "react"; import { Select as AriaSelect, Button, Label, Popover, SelectValue, Text } from "react-aria-components"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; function Select(props, ref) { const [isOpen, setIsOpen] = useState(false); const searchRef = useRef(null); const targetRef = useRef(null); const buttonRef = useRef(null); const { children, className, classNames, label, labelId, optionId, description, errorId, errorIcon = /* @__PURE__ */ jsx( ErrorIcon, { className: "h-4 w-4 text-red-800 dark:text-red-600", role: "img", "aria-label": "Error", "aria-hidden": false } ), errorMessage, items, placement = "bottom", isLoading = false, selectorIcon = /* @__PURE__ */ jsx(ChevronDownIcon, { height: 24, width: 24 }), spinnerProps, popoverProps, listBoxProps, ...otherProps } = props; useEffect(() => { var _a; requestAnimationFrame(() => { var _a2; (_a2 = searchRef == null ? void 0 : searchRef.current) == null ? void 0 : _a2.focus(); }); if (!isOpen) { (_a = buttonRef.current) == null ? void 0 : _a.setAttribute( "aria-activedescendant", props.selectedItem ? `listbox-id-option-${props.selectedItem}` : "" ); } }, [isOpen]); const slots = useMemo(() => select(), []); const baseStyles = clsx(classNames == null ? void 0 : classNames.base, className); const clonedIcon = cloneElement(selectorIcon, { "aria-hidden": true, className: slots.selectorIcon({ class: classNames == null ? void 0 : classNames.selectorIcon }) }); const renderIndicator = useMemo(() => { if (isLoading) { return /* @__PURE__ */ jsx( _Spinner, { "aria-hidden": true, color: "current", size: "sm", ...spinnerProps, className: slots.spinner({ class: classNames == null ? void 0 : classNames.spinner }) } ); } return clonedIcon; }, [isLoading, clonedIcon, spinnerProps, slots, classNames == null ? void 0 : classNames.spinner]); useEffect(() => { if (buttonRef.current) buttonRef.current.setAttribute("role", "combobox"); }, []); useEffect(() => { if (buttonRef.current) buttonRef.current.setAttribute( "aria-activedescendant", props.currentFocusedItem ? `listbox-id-option-${props.currentFocusedItem}` : "" ); }, [props.currentFocusedItem]); return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs( AriaSelect, { ref, isOpen, onOpenChange: setIsOpen, ...otherProps, className: slots.base({ class: baseStyles }), children: [ label && /* @__PURE__ */ jsx(Label, { id: labelId, className: slots.label({ class: classNames == null ? void 0 : classNames.label }), children: label }), /* @__PURE__ */ jsxs("div", { className: slots.mainWrapper({ class: classNames == null ? void 0 : classNames.mainWrapper }), children: [ /* @__PURE__ */ jsxs( Button, { id: optionId, ref: buttonRef, "aria-labelledby": labelId ? labelId : optionId, "aria-expanded": isOpen, "aria-controls": "listbox-id", className: slots.trigger({ class: classNames == null ? void 0 : classNames.trigger }), ...errorMessage && { "aria-describedby": errorId }, ...props.isRequired && { "aria-required": true }, children: [ /* @__PURE__ */ jsx(SelectValue, { className: slots.value({ class: classNames == null ? void 0 : classNames.value }) }), /* @__PURE__ */ jsx("span", { className: `${isOpen ? "rotate-[180deg]" : ""}`, children: renderIndicator }) ] } ), errorMessage ? /* @__PURE__ */ jsxs( Text, { id: errorId, slot: "errorMessage", "aria-live": "polite", elementType: "div", className: `${slots.errorMessage({ class: classNames == null ? void 0 : classNames.errorMessage })}`, children: [ errorIcon, /* @__PURE__ */ jsx("span", { children: errorMessage }) ] } ) : description ? /* @__PURE__ */ jsx( Text, { slot: "description", elementType: "div", className: slots.description({ class: classNames == null ? void 0 : classNames.description }), children: /* @__PURE__ */ jsx("span", { children: description }) } ) : null, /* @__PURE__ */ jsx("div", { ref: targetRef }) ] }), /* @__PURE__ */ jsx( Popover, { placement, className: slots.popover({ class: classNames == null ? void 0 : classNames.popover }), isNonModal: true, "aria-labelledby": "", UNSTABLE_portalContainer: targetRef.current || void 0, ...popoverProps, children: /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( "div", { role: "button", className: "z-2 fixed left-[0] top-[0] h-[100vh] w-[100vw]", onClick: () => setIsOpen(false), onKeyDown: () => { }, "aria-label": "Close dropdown", tabIndex: -1 } ), /* @__PURE__ */ jsx(ListBox, { id: "listbox-id", items, ...listBoxProps, children }) ] }) } ) ] } ) }); } var _Select = forwardRef(Select); export { _Select };