import { default as React } from 'react'; import { GroupBase, InputActionMeta, MenuListProps, OptionProps, OptionsOrGroups, SelectInstance } from 'react-select'; import { FeedbackTextProps } from '../../../../tedi/components/form/feedback-text/feedback-text'; import { FormLabelProps } from '../../../../tedi/components/form/form-label/form-label'; import { TextProps } from '../../base/typography/text/text'; import { TagEllipsis } from '../../tags/tag/tag'; declare module '../../../../../node_modules/react-select/dist/declarations/src/Select' { interface Props> { inputIsHidden?: boolean; } } export interface SelectProps extends Omit { /** * Unique HTML id for the input. Also used as react-select's `instanceId` for SSR-stable internal IDs. * When omitted, falls back to the surrounding `InputGroup`'s id or a generated `useId()`. */ id?: string; /** Visible label. May be omitted when the surrounding `InputGroup` provides its own label. */ label?: string; /** * The list of selectable options. Pass a flat `ISelectOption[]` for a simple * list, or an array of `IGroupedOptions` (each with its own `options` array) * for a grouped menu. */ options?: OptionsOrGroups>; /** * Used in async mode (`async: true`). * - `true` — call `loadOptions` once on mount with an empty input string * and use the result as the initial option list. * - An array — show these options before the user types anything. * - Omit — start with no options until the user types. */ defaultOptions?: OptionsOrGroups> | boolean; /** Text shown in the field when no value is selected. */ placeholder?: string; /** Extra class on the root wrapper. Use `classNames` for per-subcomponent overrides. */ className?: string; /** * Icon shown on the right of the field as the dropdown indicator. * - `"arrow_drop_down"` (default) — standard select chevron. * - `"search"` — magnifier; useful for combobox-style search fields. * @default 'arrow_drop_down' */ iconName?: 'arrow_drop_down' | 'search'; /** * Fires whenever the selection changes. Receives the new value: * a single `ISelectOption` (single-select), an array (multi-select), * or `null` when cleared. */ onChange?: (value: TSelectValue) => void; /** * Fires whenever the user types in the search input. Receives the new input * string and a `react-select` action descriptor (e.g. `'input-change'`, * `'menu-close'`). Use this to drive controlled search. */ onInputChange?: (value: string, actionMeta: InputActionMeta) => void; /** Controlled search input string. Pair with `onInputChange` to manage it from the parent. */ inputValue?: string; /** * Async option loader. Called with the current search string; resolve the * `callback` with the matching options. Only invoked when `async: true`. */ loadOptions?: (inputValue: string, callback: (options: OptionsOrGroups>) => void) => void; /** When `true`, shows a loading spinner in the indicator area. Useful while async results are pending. */ isLoading?: boolean; /** Uncontrolled initial selection. Ignored when `value` is provided. */ defaultValue?: TSelectValue; /** * Controlled selection. When set, the parent owns the value and must update * it via `onChange`. Use `defaultValue` for uncontrolled usage. */ value?: TSelectValue; /** Disables interaction and applies disabled styling. */ disabled?: boolean; /** Form field name; rendered onto the underlying hidden input for form submission. */ name?: string; /** * Forces error styling. Also set automatically when `helper.type === 'error'`. * @default false */ invalid?: boolean; /** * Forces valid (success) styling. Also set automatically when `helper.type === 'valid'`. * @default false */ valid?: boolean; /** * Helper / feedback text rendered below the field. Set `type` to `'hint'`, * `'error'`, or `'valid'` — the latter two also drive the field's invalid / * valid visual state. */ helper?: FeedbackTextProps; /** * Visual size variant. * - omit — default (40px tall). * - `"small"` — compact (32px tall) for dense layouts. */ size?: 'small'; /** * Switches the underlying component to `react-select`'s `AsyncSelect`. Pair * with `loadOptions` (and optionally `defaultOptions`) to fetch options on * the fly. * @default false */ async?: boolean; /** * Custom renderer for the content of each option in the dropdown. Receives * the full option props from `react-select`; return any React node. Use * `renderValue` if you also want to customise how the selected value * appears in the trigger. */ renderOption?: (props: OptionProps) => JSX.Element; /** * Message shown when the option list is empty (no matches for the search, * or no options at all). Defaults to the localised `select.no-options` * label from `LabelProvider`. */ noOptionsMessage?: (obj: { inputValue: string; }) => React.ReactNode; /** * Message shown while async options are loading. Defaults to the localised * `select.loading` label from `LabelProvider`. */ loadingMessage?: (obj: { inputValue: string; }) => React.ReactNode; /** * Renders custom content underneath the option list, inside the dropdown * (e.g. a "Show more" button or a "powered by" footer). */ renderMessageListFooter?: (props: MenuListProps) => JSX.Element; /** * Enables multi-select mode: the field renders selections as removable * tags and `onChange` receives an array. * @default false */ multiple?: boolean; /** * Layout for selected tags in multi-select mode. * - `"stack"` (default) — tags wrap onto multiple rows. * - `"row"` — tags stay on one row; overflow tags collapse into a `+N` * counter, just like the Angular `multiRow=false` mode. * @default 'stack' */ tagsDirection?: 'stack' | 'row'; /** * Truncate each selected tag's label when it is width-constrained, revealing * the full text in a popover on hover/focus. `end` shows a trailing ellipsis * (`Long label…`); `start` a leading one (`…label`). `false` never truncates — * long labels wrap. Forwarded to each tag's `ellipsis` prop. * @default false */ tagsEllipsis?: TagEllipsis; /** * Layout for the dropdown menu. * - `"menu"` (default): vertical list of options. * - `"grid"`: swatch grid for color / icon pickers and similar compact * pickers. Grid sizing is customizable via the `--tedi-swatch-size`, * `--tedi-swatch-gap`, and `--tedi-swatch-columns` CSS variables on the * menu list element. * @default 'menu' */ dropdownType?: 'menu' | 'grid'; /** * Custom renderer for the trigger value (single-select). Receives the * currently selected option and may return any React node — useful for * color swatches, icons, or any non-text representation in the field. * Ignored in multi-select mode (use `renderOption` for tag rendering). */ renderValue?: (option: ISelectOption) => React.ReactNode; /** * In multi-select mode, prepends a "Select all" toggle to the menu list. * Toggles every enabled option (or, when filtering, every visible enabled * option) on/off. Indeterminate when only some are selected. Ignored when * `multiple` is false. * @default false */ showSelectAll?: boolean; /** * In multi-select mode with grouped options, makes each group heading a * checkbox that toggles the whole group. Indeterminate when only some * options in the group are selected. Ignored when `multiple` is false or * `options` is not grouped. * @default false */ selectableGroups?: boolean; /** * Open the menu automatically when the input first receives focus. * @default false */ openMenuOnFocus?: boolean; /** * Open the menu when the trigger area is clicked. * @default true */ openMenuOnClick?: boolean; /** * Treat the Tab key as a confirm-and-move-on for the currently focused * option (otherwise Tab simply moves focus out of the menu without * selecting). * @default false */ tabSelectsValue?: boolean; /** * Close the menu after each successful selection. Default depends on * `multiple`: `true` for single-select, `false` for multi-select so the * user can pick several options without re-opening. */ closeMenuOnSelect?: boolean; /** * Blur the search input after each selection. Useful if you want to * collapse the cursor immediately on pick. * @default false */ blurInputOnSelect?: boolean; /** * Focus the input on initial mount. * @default false */ autoFocus?: boolean; /** * Whether the value can be cleared via the "×" indicator. The visible * "×" button only appears if `isClearIndicatorVisible` is also `true` * (that prop is now deprecated; see its docstring for migration plans). * Backspace deletion is controlled separately by `backspaceRemovesValue` * (default `false`). * @default true */ isClearable?: boolean; /** * @deprecated This prop will be removed in a future major version. * * `isClearable` and `isClearIndicatorVisible` overlap: `isClearable` already * controls whether the value can be cleared, and `isClearIndicatorVisible` * only adds an extra gate on whether the visible "×" button renders. The * default combination (`isClearable: true`, `isClearIndicatorVisible: false`) * leaves consumers in a state where Backspace clears the value but no * affordance is shown — a hidden interaction. * * In a future major version the prop will be removed and `isClearable` * alone will control both behaviour and visibility (matching `react-select` * and the Angular implementation). For new code, prefer `isClearable` and * leave this prop unset. */ isClearIndicatorVisible?: boolean; /** * Allow filtering the option list by typing. Set to `false` for a pure * dropdown with no search input (e.g. color/icon pickers). * @default true */ isSearchable?: boolean; /** * In multi-select mode, render an "×" remove button on each selected tag * so the user can deselect single options without re-opening the menu. * @default false */ isTagRemovable?: boolean; /** * If `true`, pressing Backspace while the input is empty removes the * last selected value (single-mode: clears it; multi-mode: pops the * last tag). Disabled by default because react-select's upstream * default (`true`) leads to accidental deletions, especially in * multi-select with no visual cue for the affected tag. * @default false */ backspaceRemovesValue?: boolean; /** * Controlled menu open state. When set, the parent owns whether the menu * is showing — pair with `onMenuOpen` / `onMenuClose`. */ menuIsOpen?: boolean; /** Fires when the menu opens (uncontrolled or controlled). */ onMenuOpen?: () => void; /** Fires when the menu closes (uncontrolled or controlled). */ onMenuClose?: () => void; /** Fires when the input loses focus. */ onBlur?: () => void; /** * Hide the underlying text input (its width collapses to 0). Useful when * the field is a pure picker with no typing — the value display still * shows, but the cursor caret area is removed. */ inputIsHidden?: boolean; /** * Typography overrides applied to group headings (when `options` is * grouped). `text` on an individual `IGroupedOptions` entry takes * precedence over this default. * @default { modifiers: 'small', color: 'tertiary' } */ optionGroupHeadingText?: Pick; /** * In async mode, cache the result of each `loadOptions` call by input * string so the same query isn't re-fetched. * @default false */ cacheOptions?: boolean; /** * In single-select mode, render each option with a leading radio button * for a more explicit "pick one" UI. Has no effect in multi-select mode. * @default false */ showRadioButtons?: boolean; /** * Per-subcomponent class overrides forwarded to react-select's `classNames` * map. Each entry adds an extra class onto the corresponding internal * subcomponent; use this for one-off styling without losing the default * `tedi-select__*` BEM classes. */ classNames?: { clearIndicator?: string; container?: string; control?: string; dropdownIndicator?: string; group?: string; groupHeading?: string; indicatorsContainer?: string; indicatorSeparator?: string; input?: string; loadingIndicator?: string; loadingMessage?: string; menu?: string; menuList?: string; menuPortal?: string; multiValue?: string; multiValueLabel?: string; multiValueRemove?: string; noOptionsMessage?: string; option?: string; placeholder?: string; singleValue?: string; valueContainer?: string; }; } /** * One option in the select list. `customData` is a typed escape hatch for * carrying domain data alongside the display label — `renderOption` / * `renderValue` can read it back via `props.data.customData`. */ export interface ISelectOption { /** The string written into the form value when this option is picked. */ value: string; /** Display label. Strings are searchable; React nodes render as-is and aren't filtered by search. */ label: string | React.ReactNode | React.ReactNode[]; /** When `true`, the option appears greyed out and can't be picked. */ isDisabled?: boolean; /** Arbitrary data attached to the option, accessible inside custom renderers. */ customData?: CustomData; } /** * A group of options in a grouped select. Extends react-select's `GroupBase` * with a `text` field that overrides typography for this specific heading. */ export interface IGroupedOptions extends GroupBase { /** Typography override for this group heading. Falls back to `optionGroupHeadingText`. */ text?: Pick; } /** * Shape of the Select's value: a single option (single-select), an array * (multi-select), or `null` when empty. */ export type TSelectValue = ISelectOption | ReadonlyArray> | null; export declare const Select: React.ForwardRefExoticComponent, boolean, IGroupedOptions>>>>; export default Select;