import "./option_list.css"; import type * as React from "react"; import { type ReactNode } from "react"; import { useRender } from "@base-ui/react/use-render"; import { type StyleProps } from "./style_props"; import type { SelectOption, SelectValue, SelectOnValueChange } from "./select"; /** `none`: a visually hidden input owns the keyboard, so arrows and type-to-find work with no field shown. * `internal`: its own search field. */ export type OptionListSearch = { mode: "none"; } | { mode: "internal"; placeholder?: string; }; export interface OptionListModelParams { options: (SelectOption | undefined | false)[]; multi?: MULTI; value?: SelectValue | null; onValueChange?: SelectOnValueChange; /** Multi: commit on close. Single: fired with the picked value after a pick. */ onClose?: SelectOnValueChange; /** Single-select: a named leading row answering `null`. */ clearable?: boolean; emptyLabel?: string; /** Dismiss the surrounding surface (Escape, Tab, a single pick). */ onRequestClose?: () => void; allowCustom?: boolean; customOptionLabel?: (query: string) => string | null; customOptionPlacement?: "top" | "bottom"; onCustomCommit?: (rawQuery: string) => void; enableSelectAll?: boolean; /** Its presence turns the local filter off: `options` is the answer, and refiltering would drop rows * matched on what this list cannot see. */ onSearchChange?: (query: string) => void; /** `list` (default): a row per option. `grid`: a tile per option for choices by shape, where names force * reading before comparing; the tile draws `renderOptionContent`, the label is its name, and a caption * names the highlighted tile. */ layout?: "list" | "grid"; } export interface OptionListBodyProps extends StyleProps { search: OptionListSearch; testID?: string; /** Rich row content; falls back to the label. */ renderOptionContent?: (option: SelectOption) => ReactNode; getOptionDescription?: (option: SelectOption) => string | undefined; loading?: boolean; emptyText?: string; /** Multi only: values some edited things carry, drawn as a mixed tick; not in `value`, so pressing * selects. */ indeterminateValues?: readonly T[]; accessibilityLabel?: string; selectAllLabel?: string; deselectAllLabel?: string; ref?: React.Ref; render?: useRender.RenderProp; } export interface OptionListModel { /** Spread onto a Base UI `Combobox.Root`. */ root: { items: string[]; multiple: boolean; value: string[] | string | null; onValueChange: (next: string[] | string | null) => void; inputValue: string; onInputValueChange: (next: string) => void; itemToStringLabel: (item: string) => string; filter: (item: string, query: string) => boolean; grid: boolean; onItemHighlighted: (item: string | undefined) => void; }; view: { optionOf: (item: string) => SelectOption | undefined; labelOf: (item: string) => string; isCustom: (item: string) => boolean; selectedOf: (item: string) => boolean; multi: boolean; selectAll: () => void; deselectAll: () => void; showSelectAll: boolean; showDeselectAll: boolean; hasSelection: boolean; itemCount: number; grid: boolean; }; /** Escape or an outside dismissal: closes and commits. */ requestClose: () => void; ownsClose: boolean; /** A ref, so a pointer crossing tiles re-renders only the caption. */ highlight: React.RefObject<((item: string | undefined) => void) | null>; } /** The kit's option shape in Base UI's terms — collection, filter, and what a pick means (create, clear, a * multi toggle that stays open). Keyboard, highlight and scroll are Base UI's. A hook because inline and * popup hosts share it. */ export declare function useOptionListModel(params: OptionListModelParams, locale: { emptyOption: string; }, /** Who announces a close: an inline list itself, since Base UI disables its own dismissal for `inline`; * a popup list takes it from `onOpenChange` and must not announce twice, or commit-on-close writes * twice. */ host: { ownsClose: boolean; }): OptionListModel; /** Everything inside a `Combobox.Root`: `OptionList` hosts it inline, `Select` in its popup. */ export declare function OptionListBody(props: OptionListBodyProps & { model: OptionListModel; }): React.ReactElement>;