import { Check, ChevronDown } from "lucide-react"; import { useRef } from "react"; import { AriaComboBoxProps, AriaListBoxOptions, useButton, useComboBox, useFilter, useId, useListBox, useOption, } from "react-aria"; import { Item, ListState, Node, useComboBoxState } from "react-stately"; import Popover from "~/components/Popover"; import cn from "~/utils/cn"; export interface SelectProps extends AriaComboBoxProps { className?: string; } function Select(props: SelectProps) { const { contains } = useFilter({ sensitivity: "base" }); const state = useComboBoxState({ ...props, defaultFilter: contains }); const id = useId(props.id); const buttonRef = useRef(null); const inputRef = useRef(null); const listBoxRef = useRef(null); const popoverRef = useRef(null); const { buttonProps: triggerProps, inputProps, listBoxProps, labelProps, descriptionProps, } = useComboBox( { ...props, inputRef, buttonRef, listBoxRef, popoverRef, }, state, ); const { buttonProps } = useButton(triggerProps, buttonRef); return (
{props.description && (
{props.description}
)} {state.isOpen && ( )}
); } interface ListBoxProps extends AriaListBoxOptions { listBoxRef: React.RefObject; state: ListState; } function ListBox(props: ListBoxProps) { const { listBoxRef, state } = props; const { listBoxProps } = useListBox(props, state, listBoxRef); return (
    {[...state.collection].map((item) => (
); } interface OptionProps { item: Node; state: ListState; } function Option({ item, state }: OptionProps) { const ref = useRef(null); const { optionProps, isDisabled, isSelected, isFocused } = useOption( { key: item.key, }, state, ref, ); return (
  • {item.rendered} {isSelected && }
  • ); } export default Object.assign(Select, { Item });