import type { PropertyValues, TemplateResult } from "lit"; import { XmField } from "../field/index.js"; import type { XmOverlay } from "../overlay/index.js"; import "../primitives/index.js"; import "../overlay/index.js"; import "../checkbox/index.js"; import "../text-field/index.js"; import "../icon/index.js"; export interface MultiSelectOption { label: string; value: string | number; disabled?: boolean; /** Trailing muted metadata on the option row (e.g. a facet count, `"100 000"`). */ meta?: string; /** Section heading this option sits under. Consecutive options sharing a section render below one header row. Sections are drawn for the plain list only — above the 200-row virtualization threshold the headers are dropped so the uniform row stride holds. */ section?: string; } interface OptionRow { opt: MultiSelectOption; pinned: boolean; } export interface MultiSelectOptionContext { selected: boolean; active: boolean; disabled: boolean; query: string; } /** * @fires change - Fired on every toggle; `detail.value` is the full selection as an Array. * @fires xm-multi-select-search - Server mode: debounced search intent (`detail.query`); also fired on open with the current query. The consumer fetches and sets `.options` with the matching set. * @fires xm-multi-select-load-more - Server mode: fired once per page when the listbox scrolls near its end and `options.length < totalItems` (`detail = { query, offset }`). The consumer appends the next page to `.options`. */ export declare class XmMultiSelect extends XmField { static styles: CSSStyleSheet[]; /** The option model — `{ label, value, disabled? }` shared with xm-select / radio-group. */ options: MultiSelectOption[]; /** Shown on the trigger when nothing is selected. */ placeholder: string; /** Selection cap (0 = uncapped). At the cap, unselected options disable; selected stay removable. */ max: number; /** Render the in-panel search filter. */ searchable: boolean; /** Dock the panel in place of the combobox trigger — an always-open filter rail (ADR 0031). Search, bulk actions, recents, sections, virtualization and the selection contract are unchanged; only the trigger and the overlay drop away, and the listbox becomes the focus target. */ inline: boolean; /** Option values pinned under a "Recent" header above the full list; suppressed while a search query is active. */ recent: (string | number)[]; /** Render the "Select all" / "Clear" bulk-action row. "Select all" operates on the search-filtered set and respects `max`. */ bulkActions: boolean; /** Server mode (ADR 0023): the backend owns filtering — client-side label matching is off, the search emits `xm-multi-select-search`, and scrolling near the end emits `xm-multi-select-load-more`. */ server: boolean; /** Signal a consumer fetch in flight (server-mode search, or any options refresh): rows already present dim to ghost ink, skeleton rows fade in under them, and "No matches" is suppressed. Distinct from the inherited field-level `loading`, which disables the whole control. */ optionsLoading: boolean; /** Debounce for `xm-multi-select-search` in milliseconds. */ searchDebounce: number; /** Server mode: total backend match count for the current query. Drives the "Showing N of M matches" note and load-more paging (0 = unknown/complete). */ totalItems: number; /** Escape hatch for custom option-row content (mirrors data-table's `renderCell`, ADR 0008/0024): given the option and its render state, returns the row body after the presentational checkbox. The `li`, checkbox, a11y wiring, and toggle stay component-owned. With a virtualized list (>200 rows) the returned content must keep a uniform single-row height. */ renderOption?: ((option: MultiSelectOption, ctx: MultiSelectOptionContext) => unknown) | undefined; protected _open: boolean; protected _activeIndex: number; protected _selected: Set; protected _query: string; protected _capNote: string; protected _scrollTop: number; protected _viewH: number; protected _stride: number; protected _chipFit: number; protected _control: HTMLElement | null; protected _overlay: XmOverlay | null; protected _search: HTMLElement | null; private _typeahead; private _typeaheadTimer; private _searchTimer; private _loadMoreKey; private _labelByValue; private _chipResizeObserver; private _chipMeasureTarget; private _rowsCache; private _rowsCacheOptions; private _rowsCacheRecent; private _rowsCacheQuery; private _rowsCacheServer; private _settleRects; connectedCallback(): void; private _focusTarget; protected willUpdate(changed: PropertyValues): void; private get _reducedMotion(); private _settleTracks; private _captureSettleRects; private _motionMs; private _playSettle; disconnectedCallback(): void; protected updated(changed: PropertyValues): void; private _measureListbox; private _scrollVirtualActiveIntoView; /** The selected primitives, in option order — values no longer present in `options` (e.g. selected under a previous server search) persist after, in selection order. The typed multi-value accessor (the inherited string `value` stays a comma-joined mirror for plain consumers). */ get selectedValues(): (string | number)[]; /** Read: the selected primitives in option order (values missing from `options` persist after, in selection order). Write (controlled, ADR 0026): replaces the selection wholesale, syncs the form value, and re-renders — without emitting `change` (no controlled echo) — so a consumer can drive the selection from its own state instead of key-remounting. */ set selectedValues(values: (string | number)[]); private _seedFromValue; private _absorbOptionLabels; private _labelFor; private _syncChipMeasurement; private _measureChips; private get _q(); private _matches; private get _atCap(); private _optDisabled; protected get _rows(): OptionRow[]; private get _navigable(); private get _matchCount(); private _nextNavigable; private _toggleValue; private _toggleIndex; private _selectAllVisible; private _clearSelection; private _syncForm; private _emitChange; private _onDocPointerDown; private _openList; private _closeList; private _onOverlayClose; private _onControlClick; private _onChipRemove; private _onControlKeydown; private _onListKeydown; private _onSearchKeydown; private _onSearchInput; private _emitSearch; private _onListScroll; private _maybeLoadMore; private _typeAhead; protected renderControl(): TemplateResult; private _renderInline; private _renderTriggerChip; private _renderPanel; private _renderMainRows; private _renderSkeletonRows; private _renderNote; private _renderRow; } declare global { interface HTMLElementTagNameMap { "xm-multi-select": XmMultiSelect; } } export {};