@trail-ui/react
Version:
228 lines (225 loc) • 7.42 kB
JavaScript
import {
InternalListBoxContext
} from "./chunk-O34YT5G7.mjs";
import {
ListBoxSelectedIcon
} from "./chunk-DVXK43TK.mjs";
import {
replaceSpacesWithHyphens
} from "./chunk-4CU75PXA.mjs";
// src/select-combobox/select-combobox.tsx
import { ChevronDownIcon, ErrorIcon } from "@trail-ui/icons";
import { clsx } from "@trail-ui/shared-utils";
import {
selectComboBox,
selectComboboxItem
} from "@trail-ui/theme";
import {
forwardRef,
useContext,
useEffect,
useMemo,
useRef,
useState
} from "react";
import {
Button,
ComboBox,
Input,
Label,
Popover,
Text,
ListBox,
ListBoxItem
} from "react-aria-components";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
function SelectCombobox({
label,
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,
children,
className,
classNames,
placeholder,
items,
...props
}, ref) {
const baseStyles = clsx(classNames == null ? void 0 : classNames.base, className);
const slots = useMemo(() => selectComboBox(), []);
const targetRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
const inputRef = useRef(null);
const dropdownButtonRef = useRef(null);
useEffect(() => {
var _a;
(_a = dropdownButtonRef.current) == null ? void 0 : _a.setAttribute("aria-hidden", "true");
}, []);
useEffect(() => {
var _a;
if (inputRef.current) {
inputRef.current.setAttribute(
"aria-activedescendant",
props.selectedKey ? `${label ? `${replaceSpacesWithHyphens(label)}-` : ""}listbox-option-${(_a = String(props.selectedKey)) == null ? void 0 : _a.toLocaleLowerCase()}` : ""
);
}
}, [isOpen]);
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(
ComboBox,
{
...props,
ref,
className: slots.base({
className: baseStyles
}),
onOpenChange: setIsOpen,
children: [
label && /* @__PURE__ */ jsx(
Label,
{
className: slots.label({ class: classNames == null ? void 0 : classNames.label }),
id: `${label ? replaceSpacesWithHyphens(label) : "combobox"}-label`,
children: label
}
),
/* @__PURE__ */ jsxs(
"div",
{
className: slots.inputWrapper({
class: classNames == null ? void 0 : classNames.inputWrapper
}),
children: [
/* @__PURE__ */ jsx(
Input,
{
ref: inputRef,
placeholder,
"aria-autocomplete": "list",
"aria-describedby": errorId,
"aria-haspopup": "listbox",
"aria-controls": label ? `${replaceSpacesWithHyphens(label)}-listbox` : "",
className: slots.input({
class: classNames == null ? void 0 : classNames.input
}),
...props.isRequired && { "aria-required": true },
"aria-activedescendant": props.currentFocusedItem ? `${label ? `${replaceSpacesWithHyphens(label)}-` : ""}listbox-option-${String(props.currentFocusedItem).toLocaleLowerCase()}` : ""
}
),
/* @__PURE__ */ jsx(
Button,
{
ref: dropdownButtonRef,
excludeFromTabOrder: true,
className: `${slots.inputTrigger({ class: classNames == null ? void 0 : classNames.inputTrigger })}`,
"aria-label": label ? `${label} Options` : "",
children: /* @__PURE__ */ jsx(ChevronDownIcon, { height: 24, width: 24, className: "text-neutral-800" })
}
)
]
}
),
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 })
]
}
),
/* @__PURE__ */ jsx("div", { ref: targetRef }),
/* @__PURE__ */ jsx(
Popover,
{
className: slots.popover({ class: classNames == null ? void 0 : classNames.popover }),
UNSTABLE_portalContainer: targetRef.current || void 0,
children: /* @__PURE__ */ jsx(
ListBox,
{
id: label ? `${replaceSpacesWithHyphens(label)}-listbox` : "",
"aria-label": label,
className: slots.listBox({ class: classNames == null ? void 0 : classNames.listBox }),
"aria-labelledby": "",
children
}
)
}
)
]
}
) });
}
function SelectComboboxItem(props) {
const context = useContext(InternalListBoxContext);
const {
children,
description,
startContent,
endContent,
selectedIcon,
className,
classNames = context.itemClasses,
...otherProps
} = props;
const baseStyles = clsx(classNames == null ? void 0 : classNames.base, className);
const slots = useMemo(() => selectComboboxItem(), []);
return /* @__PURE__ */ jsx(ListBoxItem, { ...otherProps, className: slots.base({ class: baseStyles }), children: ({ isSelected, isDisabled, selectionMode, isFocused }) => {
if (isFocused && props.textValue && props.onFocusChange) {
props.onFocusChange(props.textValue);
}
const selectedContent = () => {
const defaultIcon = /* @__PURE__ */ jsx(ListBoxSelectedIcon, { isSelected });
if (typeof selectedIcon === "function") {
return selectedIcon({ icon: defaultIcon, isSelected, isDisabled });
}
if (selectedIcon)
return selectedIcon;
return defaultIcon;
};
return /* @__PURE__ */ jsxs(Fragment, { children: [
startContent,
description ? /* @__PURE__ */ jsxs("div", { className: slots.wrapper({ class: classNames == null ? void 0 : classNames.wrapper }), children: [
/* @__PURE__ */ jsx(Text, { slot: "label", className: slots.title({ class: classNames == null ? void 0 : classNames.title }), children }),
/* @__PURE__ */ jsx(
Text,
{
slot: "description",
className: slots.description({
class: classNames == null ? void 0 : classNames.description
}),
children: description
}
)
] }) : /* @__PURE__ */ jsx(Text, { slot: "label", className: slots.title({ class: classNames == null ? void 0 : classNames.title }), children }),
isSelected && selectionMode !== "none" && /* @__PURE__ */ jsx(
"span",
{
"aria-hidden": "true",
className: slots.selectedIcon({
class: classNames == null ? void 0 : classNames.selectedIcon
}),
children: selectedContent()
}
),
endContent
] });
} });
}
var _SelectCombobox = forwardRef(SelectCombobox);
export {
SelectComboboxItem,
_SelectCombobox
};