@trail-ui/react
Version:
196 lines (193 loc) • 6.24 kB
JavaScript
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
};