import { Combobox as BaseCombobox } from '@base-ui/react/combobox'; import * as React from 'react'; import { type ComboboxOptionsProp } from './use-async-options'; import { type InfiniteOptionsLoader } from './use-infinite-options'; export type ComboboxState = 'completed' | 'error' | 'success' | 'warning'; export interface ComboboxOption { value: string; label: string; disabled?: boolean; /** Any additional key can be used as the `groupBy` field. */ [key: string]: unknown; } /** Matches {@link Input} and {@link Select}, so the three line up in a form. */ declare const comboboxInputStyles: (props?: ({ state?: "error" | "success" | "warning" | "completed" | null | undefined; } & import("class-variance-authority/types").ClassProp) | undefined) => string; declare const comboboxPopupStyles: (props?: import("class-variance-authority/types").ClassProp | undefined) => string; declare const comboboxItemStyles: (props?: import("class-variance-authority/types").ClassProp | undefined) => string; export interface ComboboxProps { /** Required: the label and the help text are associated by id. */ id: string; /** Visible field label. Pass `aria-label` instead when the label is elsewhere. */ label?: React.ReactNode; /** Hint below the field. Replaced by `errorText` in the error state. */ helpText?: React.ReactNode; /** Message shown in the error state, announced when it appears. */ errorText?: React.ReactNode; placeholder?: string; /** * A static array, or a loader called with the search term and an `AbortSignal`. * * The function form is what selects async mode — there is no `async` boolean to keep * in sync with it. In async mode the server does the filtering, so Base UI's own * filter is switched off; a loader that ignores its search term will therefore return * an unfiltered list rather than silently falling back to client filtering. * * Omit it entirely when using `fetchPage`. */ options?: ComboboxOptionsProp; /** * A paginated loader, for lists too long to send at once. Mutually exclusive with a * function-form `options`; if both are given, `options` wins and this is ignored. * * Receives `{ limit, offset, pageToken, searchTerm }` and an `AbortSignal`, and returns * `{ items, hasMore, nextPageToken?, totalNumberOfItems? }`. Both `offset` and * `pageToken` are sent on every call so a server can honor whichever it implements. */ fetchPage?: InfiniteOptionsLoader; /** * Items requested per page in `fetchPage` mode. * @default 100 */ pageSize?: number; /** * Debounce applied to typed input before an async load fires, in ms. * @default 250 */ debounceMs?: number; /** * Let the user commit a value that is not in the list. A `Create "…"` row appears at * the top of the list while the typed text matches no option's label. * @default false */ allowFreeForm?: boolean; /** * Custom values already committed — restored form state, typically. Read once on * mount; see the hook for why re-seeding is not supported. */ initialCustomValues?: string[]; /** * Label for the create row. The default is `Create "…"`. * @default (value) => `Create "${value}"` */ createLabel?: (value: string) => string; /** Shown in place of the list when an async load fails. */ errorState?: React.ReactNode; /** Announced politely while options are loading. */ loadingLabel?: string; value?: string; defaultValue?: string; /** Fires with the chosen value, or `''` when the field is cleared. */ onValueChange?: (value: string) => void; /** * Let typing filter the list. With `false` the field behaves as a Select trigger: * the list stays whole and typing only moves the highlight. * @default true */ autocomplete?: boolean; /** Group options by this key on each option. */ groupBy?: string; /** Visual state. `error` also sets `aria-invalid`. */ state?: ComboboxState; disabled?: boolean; required?: boolean; /** Shown when the filter matches nothing. */ emptyState?: React.ReactNode; /** Applied to the input. */ className?: string; /** Applied to the popup. */ popupClassName?: string; 'aria-label'?: string; } /** * A text field that filters a list and selects one value from it. * * **Portalled.** The popup renders into `document.body`, outside the element carrying * `data-theme`, so the active theme is stamped onto it. * * Filtering, grouping, the empty state and the `aria-activedescendant` wiring come * from Base UI. That last one is the part worth understanding: the input keeps focus * while the list is open, so the highlighted option is announced only through * `aria-activedescendant`. Without it, arrowing through the list is silent to a screen * reader. * * Use a `Combobox` when the list is long enough to need filtering, and a `Select` when * it is not. * * **Three option sources**, selected by which prop is given rather than by a mode flag: * * - a static `options` array, filtered by Base UI; * - a function-form `options` loader, debounced, with the server filtering; * - `fetchPage`, for paginated lists that load more as the popup scrolls. * * `allowFreeForm` layers on top of any of the three, adding a `Create "…"` row while the * typed text matches no option's label. * * @example * @example searchUsers(q, { signal })} /> * @example * @example * @example */ export declare const Combobox: React.ForwardRefExoticComponent>; export { comboboxInputStyles, comboboxItemStyles, comboboxPopupStyles }; export interface ComboboxInputProps extends React.ComponentPropsWithoutRef { } export declare const ComboboxInput: React.ForwardRefExoticComponent>; export interface ComboboxContentProps extends React.ComponentPropsWithoutRef { } /** * The popup, portalled and positioned. * * **Portalled**, so it stamps `data-theme` from `useOptionalTheme()`. The three portal tests for * this component query by `data-slot` rather than by role, because Base UI puts `role="listbox"` on * the inner `List` and not on the popup — a distinction that already made two tests here pass * against the wrong element. */ export declare const ComboboxContent: React.ForwardRefExoticComponent>; export interface ComboboxListProps extends React.ComponentPropsWithoutRef { } /** The listbox. This is the element that carries `role="listbox"`, not the popup. */ export declare const ComboboxList: React.ForwardRefExoticComponent>; export interface ComboboxItemProps extends React.ComponentPropsWithoutRef { } export declare const ComboboxItem: React.ForwardRefExoticComponent>; export interface ComboboxEmptyProps extends React.ComponentPropsWithoutRef { } /** * Shown when filtering matches nothing. * * Base UI renders it only when the list is empty and keeps it out of the listbox, so it is not * announced as a zero-value option — which is what a hand-rolled empty row inside the list does. */ export declare const ComboboxEmpty: React.ForwardRefExoticComponent>; export interface ComboboxValueProps extends React.ComponentPropsWithoutRef { } /** The selected value as text, for a trigger that is not an input. */ export declare const ComboboxValue: typeof BaseCombobox.Value; export interface ComboboxChipsProps extends React.ComponentPropsWithoutRef { } /** The container for a multi-select's chips. */ export declare const ComboboxChips: React.ForwardRefExoticComponent>; export interface ComboboxChipProps extends React.ComponentPropsWithoutRef { } /** * One selected value. * * Includes `Chip.Remove` rather than leaving it to the caller: a chip without a remove control is * a dead end for keyboard users, since the only other way to deselect is to find the row again in * the list. It takes the coarse-pointer touch floor for the same reason every other small control * does. */ export declare const ComboboxChip: React.ForwardRefExoticComponent>; export interface ComboboxChipsInputProps extends ComboboxInputProps { } /** * The input inside a chips container. * * Borderless and auto-sizing: the chips container draws the boundary, so a second one here would * read as a field inside a field. */ export declare const ComboboxChipsInput: React.ForwardRefExoticComponent>; //# sourceMappingURL=combobox.d.ts.map