/** * Select — a picker with one trigger and three ways of showing its options. * * Which one is right depends on what surrounds the trigger, not on what the * options are, which is why it is a prop rather than three components: * * - `sheet` (default) takes the bottom of the screen. Best for a long list, or * on a small screen where an anchored panel would cover the thing you are * choosing for. * - `inline` expands the list in normal layout flow. Everything below moves * down. Right inside a settings list, where that reads as the row growing; * wrong anywhere the shift is jarring. * - `overlay` floats the list above the page through a portal, anchored to the * trigger and flipped above it when there is no room below. Nothing else on * the screen moves. * * ```tsx * * ``` * * Past a couple of dozen options, scrolling stops being a way of finding * anything: pass `searchable` and the list gets a filter above it, matching on * the option labels. The filter narrows what is *shown* — the declared options * are still the source of truth, so nothing has to be lifted into state to make * it work. * * A list long enough to need a filter is usually long enough to want dividing, * so options can be wrapped in `Select.Group` under a heading. Grouping is * presentational — the value is still a flat string — and the filter reaches * through it, dropping any group the query empties rather than leaving a * heading standing over nothing. */ import { type ReactNode } from 'react'; export type SelectPresentation = 'sheet' | 'inline' | 'overlay'; /** * The filter field's text, from inside an open Select. * * Select can only filter the options it renders itself. A caller who hands it * a virtualized list is rendering their own rows, from their own data, and * this is how they get the query to filter that data with — `Select.Item` * still works wherever those rows put it, because selection travels by * context rather than by position. * * ```tsx * function Options() { * const { query } = useSelectSearch(); * const rows = useMemo(() => filter(timezones, query), [query]); * return ( * } * /> * ); * } * ``` * * `setQuery` is there for a caller who wants to clear or seed the field. */ export declare function useSelectSearch(): { query: string; setQuery: (query: string) => void; }; export interface SelectItemProps { value: string; label: string; /** Extra classes for the option row. */ className?: string; /** Extra classes for the option's label. */ labelClassName?: string; /** * Shows the option but refuses it — a plan above the current tier, a region * with nothing in stock. Kept in the list rather than dropped from it, because * an option that vanishes reads as one that never existed. */ disabled?: boolean; } /** Declarative option. Rendered inside whichever surface is presenting. */ declare function SelectItem({ value, label, disabled, className, labelClassName }: SelectItemProps): import("react").JSX.Element; declare namespace SelectItem { var displayName: string; } export interface SelectGroupProps { /** * Heading over the run of options. Announced as a header, so a screen reader * reaching the group is told what it is before walking into it. */ label?: string; /** Extra classes for the group wrapper. */ className?: string; /** Extra classes for the heading. */ labelClassName?: string; children: ReactNode; } /** * A titled run of options. * * Purely a way of arranging the list: a grouped Select still reports one flat * string, and `Select.Item` needs to know nothing about being inside one. */ declare function SelectGroup({ label, className, labelClassName, children }: SelectGroupProps): import("react").JSX.Element; declare namespace SelectGroup { var displayName: string; } export interface SelectProps { /** * Extra classes for the wrapper around the trigger — the box the select * occupies in your layout, which is where margins and widths belong. To * restyle the field itself, use `triggerClassName`. */ className?: string; /** The selected option's `value`. Leave unset for the placeholder. */ value?: string; /** * What the trigger shows for the current `value`. * * Select reads the label off its `Select.Item` children, which it cannot do * when a list component renders those rows — the elements do not exist until * the list decides to draw them, and the selected one may be scrolled far * out of view. Pass the label yourself in that case; otherwise leave it * unset and the trigger will find it. */ valueLabel?: string; /** Called with the `value` of the option that was picked. */ onValueChange: (value: string) => void; /** Shown on the trigger while nothing is selected. */ placeholder?: string; /** Refuses the trigger and dims it. The options cannot be opened. */ disabled?: boolean; /** Extra classes for the trigger — the field you press to open the list. */ triggerClassName?: string; /** Extra classes for the selected option's text on the trigger. */ valueClassName?: string; /** Extra classes for the placeholder text on the trigger. */ placeholderClassName?: string; /** * Extra classes for the surface the options sit on. In `sheet` the sheet is * that surface, so this reaches the block of options inside it instead. */ listClassName?: string; /** Extra classes for the row the filter field sits in. `searchable` only. */ searchClassName?: string; /** Extra classes for the filter field itself. `searchable` only. */ searchInputClassName?: string; /** * Extra classes for the box drawn around the filter field — its fill, border * and radius. `searchable` only. */ searchContainerClassName?: string; /** Extra classes for the message shown when the filter matches nothing. */ emptyClassName?: string; /** * Where the options appear. `sheet` takes the bottom of the screen, `inline` * expands the list in layout flow, `overlay` floats it above the page * anchored to the trigger. */ presentation?: SelectPresentation; /** Sheet title shown above the options. `sheet` presentation only. */ title?: string; /** * Width of the floating list. `trigger` matches the trigger, `content` sizes * to the longest option, or pass a pixel value. `overlay` only. */ contentWidth?: 'trigger' | 'content' | number; /** Gap between the trigger and the floating list. `overlay` only. */ offset?: number; /** Called when the options open or close. */ onOpenChange?: (open: boolean) => void; /** * Put a filter above the options, matching case-insensitively on any part of * an option's label. For a list long enough that scrolling it is not finding * anything — countries, currencies, a repository's branches. * * The field is not focused on open: on a phone that would throw the keyboard * over the very list you are trying to look at. */ searchable?: boolean; /** Placeholder for the filter field. `searchable` only. */ searchPlaceholder?: string; /** Shown in place of the list when the filter matches nothing. */ emptyMessage?: string; /** * Render the platform's own picker instead of the trigger-and-list pair. * Requires the optional `@expo/ui` package; without it this prop does * nothing. * * **Theme tokens do not apply** — the platform draws the picker, so * `className`, `title` and `presentation` are ignored. `Select.Item` * children still declare the options. */ native?: boolean; /** * Native picker style. `menu` is a compact button opening a dropdown; * `wheel` is an always-visible rotor (iOS; falls back to `menu` elsewhere). */ nativeAppearance?: 'menu' | 'wheel'; children: ReactNode; } declare function SelectRoot({ className, value, valueLabel, onValueChange, placeholder, disabled, triggerClassName, valueClassName, placeholderClassName, listClassName, searchClassName, searchInputClassName, searchContainerClassName, emptyClassName, presentation, title, contentWidth, offset, onOpenChange, searchable, searchPlaceholder, emptyMessage, native, nativeAppearance, children, }: SelectProps): import("react").JSX.Element; export declare const Select: typeof SelectRoot & { Item: typeof SelectItem; Group: typeof SelectGroup; }; export {}; //# sourceMappingURL=index.d.ts.map