import clsx from "clsx"; import * as React from "react"; import type { ListBoxItemProps, SelectProps } from "react-aria-components"; import { Autocomplete, Button, Header, Input, Label, ListBox, ListBoxItem, ListBoxSection, ListLayout, Popover, SearchField, Select, SelectStateContext, SelectValue, useFilter, Virtualizer, } from "react-aria-components"; import { useTranslation } from "react-i18next"; import { SendouBottomTexts } from "~/components/elements/BottomTexts"; import { SendouButton } from "~/components/elements/Button"; import { ChevronUpDownIcon } from "~/components/icons/ChevronUpDown"; import { Image } from "../Image"; import { CrossIcon } from "../icons/Cross"; import { SearchIcon } from "../icons/Search"; import styles from "./Select.module.css"; export interface SendouSelectProps extends Omit, "children"> { label?: string; description?: string; errorText?: string; bottomText?: string; items?: Iterable; children: React.ReactNode | ((item: T) => React.ReactNode); search?: { placeholder?: string; }; popoverClassName?: string; /** Value of the search input, used for controlled components */ searchInputValue?: string; /** Callback for when the search input value changes. When defined `items` has to be filtered on the caller side (automatic filtering in component disabled). */ onSearchInputChange?: (value: string) => void; clearable?: boolean; } /** * A customizable select component with optional search functionality. Virtualizes the list of items for performance. * * @example * ```tsx * * {({ key, ...item }) => ( * * {item.name} * * )} * * ``` */ export function SendouSelect({ label, description, errorText, bottomText, children, items, search, popoverClassName, searchInputValue, onSearchInputChange, clearable = false, className, ...props }: SendouSelectProps) { const { t } = useTranslation(["common"]); const { contains } = useFilter({ sensitivity: "base" }); const isControlled = !!onSearchInputChange; const handleOpenChange = (isOpen: boolean) => { if (!isControlled) return; if (!isOpen) { onSearchInputChange(""); } }; return ( ) : null} (
{t("common:noResults")}
)} > {children}
); } interface SendouSelectItemProps extends ListBoxItemProps {} export function SendouSelectItem(props: SendouSelectItemProps) { return ( clsx(styles.item, { [styles.itemFocused]: isFocused, [styles.itemSelected]: isSelected, }) } /> ); } interface SendouSelectItemSectionProps { heading: string; headingImgPath?: string; children: React.ReactNode; className?: string; } export function SendouSelectItemSection({ heading, headingImgPath, children, className, }: SendouSelectItemSectionProps) { return (
{headingImgPath ? ( ) : null} {heading}
{children}
); } function SelectClearButton() { const state = React.useContext(SelectStateContext); if (!state?.selectedKey) return null; return ( } onPress={() => state?.setSelectedKey(null)} className={styles.clearButton} > Clear ); }