/** * Single-choice entry from a fixed list. * * @packageDocumentation */ import type { ColumnDropdownOption } from '../../types/column.types'; import { AbstractCellEditor, type EditorParams } from './base/abstract-editor'; /** * The bag the {@link SelectEditorParams.options} function form receives — the * full editor params, so an option list can depend on the row being edited * ("which warehouses stock *this* product"). */ export type SelectOptionsContext = EditorParams; /** `cellEditorParams` for {@link SelectEditor}. */ export interface SelectEditorParams { /** * The choices, either literal or computed per cell. * * Omit it and the editor falls back to `ColumnDef.dropdownOptions`, then to * `ColumnDef.enumOptions` — the two places a column already declares its * domain. A column that has either of those needs no `cellEditorParams` at * all, and the same list drives the cell's badge renderer and its set filter, * so the three cannot drift apart. */ readonly options?: readonly ColumnDropdownOption[] | ((context: SelectOptionsContext) => readonly ColumnDropdownOption[]); /** * For a column whose cells hold objects: the property that identifies the * option. Defaults to `ColumnDef.objectValueKey`, then to `'value'`. * * When the cell value is an object, the *option object* is committed rather * than its key, so the cell keeps whatever else it carried (a label, a colour, * an id) instead of collapsing to a bare string. */ readonly valueKey?: string; /** * Label for the blank choice. Shown only when a blank choice is present — see * {@link allowEmpty}. * * @default 'Select…' — a blank choice with no text is announced as an empty * option, which is indistinguishable from a rendering fault. Supply your own * wording here; the core ships no translation layer. */ readonly placeholder?: string; /** * Offer a blank choice, letting the user clear the cell. * * @default false, but a blank choice is added regardless when the cell's * current value matches no option — see the class note on why that matters. */ readonly allowEmpty?: boolean; /** * Commit the edit as soon as an option is picked, instead of waiting for * `Enter`. * * A `` over a column's option list. * * ### Why native * A custom listbox would be prettier and would cost keyboard support, type-ahead, * screen-reader semantics, and — on a phone — the platform's own wheel picker, * all of which would then have to be rebuilt and maintained. The native control * gets those right by construction, and a column that genuinely needs search or * remote options has {@link AutocompleteEditor} instead. * * ### The unmatched-value trap * A ``. * * ### One `Enter`, not two * The dropped-open list is drawn by the operating system, so the `Enter` that * chooses an option inside it is consumed there and never reaches the page. The * session therefore closes on the control's `change` event, which fires for a * mouse pick and a keyboard pick alike — see * {@link SelectEditorParams.commitOnChange}. * * The one platform caveat: where arrowing a *closed* `` that is * not yet in the document has nowhere to anchor its list, and `showPicker` * rejects a disconnected element outright. */ afterGuiAttached(): void; /** * The chosen option's value — or the option object itself for an * object-valued column, and `null` when the blank choice is selected. */ getValue(): unknown; /** Builds one `