@trail-ui/react
Version:
182 lines (179 loc) • 6.35 kB
JavaScript
import {
ListBox
} from "./chunk-O34YT5G7.mjs";
import {
_Input
} from "./chunk-VGAQK5WY.mjs";
import {
_Spinner
} from "./chunk-JT3O22CN.mjs";
// src/select/select.tsx
import { ChevronDownIcon, ChevronUpIcon, ErrorIcon, SearchIcon } 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 { jsx, jsxs } from "react/jsx-runtime";
function Select(props, ref) {
const [isOpen, setIsOpen] = useState(false);
const [noResultsFound, setNoResultsFound] = useState(false);
const [filteredResults, setFilteredResults] = useState([]);
const searchRef = useRef(null);
const {
children,
className,
classNames,
label,
description,
errorMessage,
items,
placement = "bottom",
isLoading = false,
isSearchable = true,
selectorIcon = isOpen ? /* @__PURE__ */ jsx(ChevronUpIcon, { height: 24, width: 24 }) : /* @__PURE__ */ jsx(ChevronDownIcon, { height: 24, width: 24 }),
spinnerProps,
popoverProps,
listBoxProps,
...otherProps
} = props;
const onInputChange = (value) => {
if (Array.isArray(children)) {
const filteredResults2 = children.filter((item) => {
return item.props.children.toLowerCase().includes(value.toLowerCase());
});
setFilteredResults(filteredResults2);
setNoResultsFound(filteredResults2.length === 0 && value.length > 0);
}
};
useEffect(() => {
setFilteredResults([]);
setNoResultsFound(false);
requestAnimationFrame(() => {
var _a;
(_a = searchRef == null ? void 0 : searchRef.current) == null ? void 0 : _a.focus();
});
}, [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]);
return /* @__PURE__ */ jsxs(
AriaSelect,
{
ref,
isOpen,
onOpenChange: setIsOpen,
className: slots.base({ class: baseStyles }),
...otherProps,
children: [
label && /* @__PURE__ */ jsx(Label, { 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 }),
role: "combobox",
"aria-expanded": isOpen,
"aria-controls": "listbox-id",
children: [
/* @__PURE__ */ jsxs(Button, { className: slots.trigger({ class: classNames == null ? void 0 : classNames.trigger }), children: [
/* @__PURE__ */ jsx(SelectValue, { className: slots.value({ class: classNames == null ? void 0 : classNames.value }) }),
renderIndicator
] }),
errorMessage ? /* @__PURE__ */ jsxs(
Text,
{
slot: "errorMessage",
elementType: "div",
className: `${slots.errorMessage({ class: classNames == null ? void 0 : classNames.errorMessage })} flex gap-1`,
children: [
/* @__PURE__ */ jsx(
ErrorIcon,
{
height: 16,
width: 16,
className: "text-red-800 dark:text-red-600",
role: "img",
"aria-label": "Error",
"aria-hidden": "false"
}
),
/* @__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__ */ jsxs(
Popover,
{
placement,
className: slots.popover({ class: classNames == null ? void 0 : classNames.popover }),
...popoverProps,
children: [
isSearchable && /* @__PURE__ */ jsxs("div", { className: "w-full px-2 pb-2", children: [
/* @__PURE__ */ jsx(
_Input,
{
ref: searchRef,
variant: "compact",
"aria-label": "Search",
placeholder: "Search",
startContent: /* @__PURE__ */ jsx(SearchIcon, { height: 16, width: 16 }),
onChange: (e) => onInputChange(e.target.value),
className: slots.searchInput({ class: classNames == null ? void 0 : classNames.searchInput })
}
),
noResultsFound && /* @__PURE__ */ jsx("p", { className: "mt-4 text-center text-sm text-neutral-400", children: "No results found" })
] }),
/* @__PURE__ */ jsx(ListBox, { id: "listbox-id", ...listBoxProps, items, children: (filteredResults == null ? void 0 : filteredResults.length) > 0 ? filteredResults : noResultsFound ? [] : children })
]
}
)
]
}
);
}
var _Select = forwardRef(Select);
export {
_Select
};