import { LLSelectBase, type LLSelectBaseSettings, type LLSelectChangeMeta, type LLSelectSettingsInputOf } from './base.js';
/**
 * Trigger display mode of {@link LLSelectMultiple}.
 * - `'count'`: a text summary like "3 / 10 selected".
 * - `'tags'`: one removable chip per chosen item.
 * See {@link LLSelectMultipleSettings.triggerDisplay}.
 * @group Settings
 * @category Multiple
 */
export type LLSelectTriggerDisplay = 'count' | 'tags';
/**
 * Tri-state of the choose-all row (also the `data-chosen-state` attribute
 * value): how much of the VISIBLE enabled subset is currently chosen.
 * @group Settings
 * @category Multiple
 */
export type LLSelectChosenState = 'none' | 'some' | 'all';
/**
 * Context passed to {@link LLSelectMultipleSettings.createTriggerContentElFn}.
 * @group Settings
 * @category Multiple
 */
export interface LLSelectMultipleTriggerContext<T> {
    chosenItems: readonly T[];
    items: readonly T[];
}
/**
 * Resolved (defaults applied) settings for {@link LLSelectMultiple}: the base
 * settings plus the multi-mode fields - the runtime type of `this.settings`,
 * one bag built complete in the constructor.
 * @group Settings
 * @category Multiple
 */
export interface LLSelectMultipleSettings<T, GroupKey = string> extends LLSelectBaseSettings<T, GroupKey> {
    /**
     * Fired when the chosen-items set actually changes. Receives the new set
     * and the PREVIOUS one (the snapshot from before this change) - diff them
     * with `compareFn` to compute added / removed. Does NOT fire on
     * construction nor on a setter call that yields an equivalent set
     * (element-wise compared via `compareFn`, order-sensitive).
     * `null` (default) = no listener.
     * - `meta.source` says who initiated the change: `'user'` for a pointer or
     *   keyboard interaction inside the widget (an option toggle, a tag's
     *   remove button, the clear button, the choose-all row), `'api'` for any
     *   programmatic call. See {@link LLSelectChangeMeta}.
     * @group Events
     */
    onChange: ((chosenItems: readonly T[], previousChosenItems: readonly T[], meta: LLSelectChangeMeta) => void) | null;
    /**
     * Render the trigger's content ELEMENT without subclassing - the setting
     * equivalent of overriding `renderTriggerContent`. Receives the chosen items
     * + items (same convention as `createItemContentElFn`):
     * - `HTMLElement` - inserted into the trigger as-is; you own it. Use this for
     *   real markup such as tag chips.
     * - fn returns `null` - use the default for this render (count summary / tags).
     * - setting is `null` (default) - always use that default rendering.
     * The DEFAULT `renderTriggerContent` checks it first; a subclass override
     * replaces that default entirely and may ignore the setting - override
     * wins, per DESIGN.md "Customization model".
     * @group Trigger
     */
    createTriggerContentElFn: ((ctx: LLSelectMultipleTriggerContext<T>) => HTMLElement | null) | null;
    /**
     * Trigger display mode.
     * - `'count'` (default): a summary like "3 / 10 selected".
     * - `'tags'`: one removable chip per chosen item; its x button removes it.
     * `createTriggerContentElFn` overrides both (full control wins).
     * @group Trigger
     */
    triggerDisplay: LLSelectTriggerDisplay;
    /**
     * Item -> the visible content ELEMENT of its tag chip in `'tags'` mode,
     * without subclassing. Mirrors `createItemContentElFn` (the chip is to the
     * trigger what the option content is to the row):
     * - Return an `HTMLElement` and the library inserts it as the chip's content;
     *   the library still owns the chip container + the remove (x) button + aria.
     * - `null` (setting default, or returned for an item) = plain text from
     *   `itemToString`.
     * - The remove button's accessible name comes from
     *   `itemToTagRemoveButtonAriaLabel` (default `Remove <itemToString>`) -
     *   that is what AT is guaranteed to announce. The chip is a generic `<span>` (ARIA prohibits naming it), so
     *   for icon-only content include your own (visually hidden) text if the
     *   chip should be announced as more than its remove button. See
     *   `docs/llm/A11Y.md` "Tags".
     * @group Trigger
     */
    createTagContentElFn: ((item: T) => HTMLElement | null) | null;
    /**
     * Icon ELEMENT of each tag's remove (x) button in `'tags'` mode, mirroring
     * `createTriggerClearButtonContentElFn` (the clear button's icon hook). The library always owns the
     * button, its click (removes the item + `stopPropagation`), `tabindex="-1"`, and
     * the `aria-label` accessible name (from `itemToTagRemoveButtonAriaLabel`);
     * this only fills the decorative icon.
     * - Return an `HTMLElement` / `SVGElement`: appended inside the button as its icon.
     * - `null` (setting default, or returned for an item): no icon - the theme
     *   draws the x via its CSS glyph (`.llselect-tag-remove-button:empty::before`).
     * @group Trigger
     */
    createTagRemoveButtonContentElFn: ((item: T) => HTMLElement | SVGElement | null) | null;
    /**
     * Hide the rows of chosen items from the popup list.
     * - Default `false`: chosen rows stay listed and show their state.
     * - While `true`, choosing an item removes its row at once and unchoosing
     *   puts it back. Tags, the trigger and `getChosenItems` are unaffected.
     * - When every item is chosen, the popup shows the no-results element.
     * - With `chooseAllRow`, the visible subset is always fully unchosen, so
     *   the row acts as "choose everything still listed", its tri-state never
     *   reaches all-chosen, and it disappears with the last actionable row.
     * - Internals: a `getVisibleItems` subtraction. The default `compareFn`
     *   uses a Set lookup; a custom `compareFn` costs O(visible x chosen).
     *   Either cost is paid once per change of the list or the chosen set -
     *   the result is cached between changes. `toggleItem` swaps its O(1) row
     *   replace for a full rebuild.
     * @group Items
     */
    hideChosenRows: boolean;
    /**
     * Whether the popup shows a choose-all row (the industry's "select all")
     * as the first option of the listbox.
     * - Default `false`.
     * - Activating the row (Enter / click) runs `toggleAllVisible`: it toggles
     *   the visible enabled subset (the matching subset while a filter query
     *   is active). The public `chooseAll` / `unchooseAll` / `toggleAll` keep
     *   their whole-list semantics.
     * - The row is tri-state (none / some / all chosen), carried by the
     *   counting text's numbers and the `data-chosen-state` CSS hook.
     * - Its accessible name comes from `uiTranslationPack.chooseAllRowText`.
     * - See `docs/llm/A11Y.md` "Choose-all".
     * @group Choose-all
     */
    chooseAllRow: boolean;
    /**
     * The choose-all row's visible content ELEMENT, without subclassing - e.g.
     * a tri-state SVG checkbox (`createOutlinedCheckboxSvgEl`) + the counting text. Mirrors
     * `createItemContentElFn`. Only used with `chooseAllRow: true`.
     * - Receives the tri-state and the counts of the visible enabled subset.
     * - Return an `HTMLElement`: inserted as the row's content; the accessible
     *   name stays pinned to `uiTranslationPack.chooseAllRowText` via `aria-label`, so
     *   icon-only content is still announced with the counts.
     * - `null` (setting default, or returned): the default content - just the
     *   plain counting text; its numbers carry the tri-state. The library
     *   ships no default indicator (consistent with items and the arrow);
     *   passing this setting is how one (e.g. `createOutlinedCheckboxSvgEl`)
     *   gets added. See DESIGN.md "Choose-all default: plain counting text".
     * @group Choose-all
     */
    createChooseAllRowContentElFn: ((chosenState: LLSelectChosenState, chosenCount: number, totalCount: number) => HTMLElement | null) | null;
}
/**
 * Constructor-time settings input for {@link LLSelectMultiple}.
 * Every field is optional; missing fields use defaults.
 * @group Settings
 * @category Multiple
 */
export type LLSelectMultipleSettingsInput<T, GroupKey = string> = LLSelectSettingsInputOf<LLSelectMultipleSettings<T, GroupKey>>;
/**
 * Multi-selection select. Clicking an item toggles its membership in the
 * chosen-items set and keeps the popup open. Each item DOM gets
 * `aria-selected="true|false"`; the popup list gets
 * `aria-multiselectable="true"`.
 *
 * Default trigger display is a count summary ("3 / 10 selected" / "All N
 * selected" / placeholder when empty). Pass `createTriggerContentElFn` (or
 * subclass `renderTriggerContent`) to customise (e.g. tag chips).
 *
 * @typeParam T - item type.
 * @typeParam GroupKey - group key type of `itemToGroupKeyFn`; see
 *   {@link LLSelectBase}.
 * @typeParam S - resolved settings type, for subclasses extending the
 *   settings bag; see {@link LLSelectBase}.
 * @group Select classes
 */
export declare class LLSelectMultiple<T = unknown, GroupKey = string, S extends LLSelectMultipleSettings<T, GroupKey> = LLSelectMultipleSettings<T, GroupKey>> extends LLSelectBase<T, GroupKey, S> {
    /**
     * Currently chosen items, in insertion order.
     * @group State (protected)
     */
    protected chosenItems: readonly T[];
    /**
     * Build the control inside `targetEl`.
     * - Settings are resolved once here; missing fields get defaults.
     * - They are frozen afterwards, except `placeholder` and `uiTranslationPack`,
     *   which have runtime setters; the rule is at {@link LLSelectBaseSettings}.
     * - This plain form infers `T` from a typed callback in `settings` whose
     *   signature contains `T` (`itemToStringFn: (u: User) => ...`). With no
     *   such callback, pass `T` explicitly: `new LLSelectMultiple<string>(...)`.
     * @group Lifecycle
     */
    constructor(targetEl: HTMLElement, settings?: LLSelectMultipleSettingsInput<T, GroupKey>);
    /**
     * Subclass form. `subclassSettings` is the typed pass-through for subclasses
     * that extend the settings bag further; see `LLSelectBase`'s `S` param.
     * @group Lifecycle
     */
    constructor(targetEl: HTMLElement, settings?: LLSelectSettingsInputOf<S>, subclassSettings?: Omit<S, keyof LLSelectMultipleSettings<T, GroupKey>>);
    /**
     * Return the currently chosen items (insertion order).
     * @group Selection
     */
    getChosenItems(): readonly T[];
    /**
     * Replace the entire chosen-items list.
     * - The input is copied, and duplicates (per `compareFn`) collapse to
     *   their first occurrence: the chosen items are a set.
     * - Fires `onChange` only when the new list differs from the current one.
     *   The comparison is order-sensitive: chosen order is visible state
     *   (tags render in it).
     * - It ignores disabled state: it can add and drop disabled items, unlike
     *   the `choose*` bulk ops. Assigning to a native `<select>` behaves the
     *   same.
     * @group Selection
     */
    setChosenItems(items: readonly T[]): void;
    /**
     * Whether the given item is currently chosen (via `compareFn`).
     * @group Selection
     */
    isChosen(item: T): boolean;
    private chosenSetCache;
    /** Memoized Set of `chosenItems` for the default-compareFn `isChosen` fast path. */
    private chosenSet;
    /**
     * Toggle the membership of `item` in the chosen-items set. Adds at the end
     * if not present; removes if present. Fires `onChange`.
     * - While `hideChosenRows` is on, the popup list is rebuilt so the row
     *   leaves or re-enters it.
     * @group Selection
     */
    toggleItem(item: T): void;
    /**
     * Choose every enabled item.
     * - It acts on enabled items only, like every `choose*` bulk op. Bulk ops
     *   mirror clicking, and clicking cannot reach disabled items.
     * - Already-chosen disabled items are preserved. To change disabled items
     *   too, use `setChosenItems`.
     * - Fires `onChange` only when the chosen items actually change.
     * @group Selection
     */
    chooseAll(): void;
    /**
     * Unchoose every enabled item.
     * - Already-chosen disabled items are preserved. Bulk ops mirror clicking,
     *   and clicking cannot reach disabled items.
     * - Two paths DO drop them: the clear button, and `setChosenItems([])`.
     * - Fires `onChange` only when the chosen items actually change.
     * @group Selection
     */
    unchooseAll(): void;
    /**
     * Toggle between "all enabled chosen" and "none chosen".
     * - It ignores disabled items, like every `choose*` bulk op.
     * - This is NOT the in-popup choose-all row's action. The row acts on the
     *   visible enabled subset only: see {@link toggleAllVisible}.
     * @group Selection
     */
    toggleAll(): void;
    /**
     * Toggle the visible enabled items between all-chosen and all-unchosen.
     * - This is the choose-all row's action (the `chooseAllRow` setting) as a
     *   public method. The row delegates here.
     * - Acts on exactly the items that satisfy all of the following:
     *   - Visible: the item matches the active filter query. If no query is
     *     active, every item is visible. This is the same list as
     *     `getVisibleItems`.
     *   - Enabled: not disabled via `itemDisabledFn`, and not in a disabled
     *     group.
     * - If all of them are already chosen, it unchooses exactly those.
     * - Otherwise, it chooses the ones still missing.
     * - Choices outside that set (filtered-out or disabled) are preserved
     *   either way.
     * - If no filter query is active, the acted-on set is every enabled item,
     *   the same scope as `toggleAll`.
     * - Fires `onChange` only when the chosen items actually change.
     * - The acted-on set is computed by the overridable method `getVisibleEnabledItems`,
     *   shared with the choose-all row.
     * @group Selection
     */
    toggleAllVisible(): void;
    /**
     * Return the visible enabled subset: the items `toggleAllVisible` and the
     * choose-all row act on.
     * - It is `getVisibleItems()` minus the effectively disabled items
     *   (`itemDisabledFn`, disabled groups).
     * - Both the choose-all row (its counts, tri-state, and click) and
     *   `toggleAllVisible` read this one method, so an override keeps them in
     *   agreement. Example: the tree-select demo subclass narrows it to leaf
     *   nodes.
     * @group Subclassing: semantics
     */
    protected getVisibleEnabledItems(): readonly T[];
    /**
     * hideChosenRows subtraction cache. Every layer above (items, gather,
     * filter) and the chosen set REPLACE their arrays on change, never mutate
     * in place - so two reference checks are a complete validity test and no
     * invalidation wiring is needed.
     */
    private visibleItemsCache;
    /**
     * Return the items the popup list renders, in display order.
     *
     * ```text
     * base visible items   (LLSelectBase.getVisibleItems: gather + filter)
     *   |  minus chosen    (only while hideChosenRows is on; result cached)
     *   v
     * visible items        (this method's return value)
     * ```
     *
     * - Identical to the base behavior, minus the chosen items while
     *   `hideChosenRows` is on.
     * - While `hideChosenRows` is on and something is chosen, it returns a
     *   cached fresh array, not the live internal one.
     * - The subtraction recomputes only when the base list or the chosen set
     *   changed. Calls in between return the same cached array.
     * @group Items
     */
    getVisibleItems(): readonly T[];
    /**
     * Orchestrator: composes `syncEmptyStateToDom` + `commitTriggerContentToDom`
     * to (re)build the trigger from state; touches no DOM directly. Default text
     * is a count summary; override (or pass the `createTriggerContentElFn`
     * setting) to display tags / custom markup / etc.
     *
     * - If 0 items are chosen, the text is `placeholder`.
     * - If n > 0, the text is `uiTranslationPack.triggerCountSummary(n, total)`
     *   (English default: `"n / total selected"`, or `"All n selected"` when
     *   all are chosen).
     * @group Subclassing: rendering
     */
    protected renderTriggerContent(): void;
    /**
     * Build the tag-list element for `'tags'` mode: one chip per chosen item.
     * Override for full control of the chip strip (the trigger-level equivalent
     * of overriding `createItemEl`).
     * @group Subclassing: rendering
     */
    protected createTagsEl(): HTMLElement;
    /**
     * Build one removable tag chip: its content (from `createTagContentEl`, else
     * plain `itemToString`) plus its remove (x) button (from `createTagRemoveButtonEl`).
     * A chip whose item is effectively disabled gets `aria-disabled="true"` +
     * `tagDisabledClass`, and its x turns inert - mirroring a disabled option row.
     * Override for full control of the chip container; override the two sub-parts
     * for content-only / remove-button-only changes.
     * @group Subclassing: rendering
     */
    protected createTagEl(item: T): HTMLElement;
    /**
     * Build one chip's remove (x) button. The library owns the button + its click
     * (`stopPropagation` so it never toggles the popup, then `toggleItem`; a no-op
     * while the whole control OR the item itself is disabled) + `tabindex="-1"` +
     * `aria-label` (from `itemToTagRemoveButtonAriaLabel`). An effectively-disabled
     * item's button also gets `aria-disabled="true"`.
     * `createTagRemoveButtonContentElFn` optionally fills the icon, else the theme's CSS glyph.
     * Mirrors the clear button's `createTriggerClearButtonEl`. Override for full control of
     * the button element.
     * @group Subclassing: rendering
     */
    protected createTagRemoveButtonEl(item: T): HTMLElement;
    /**
     * One chip's remove-button visible content (its x icon). Mirrors
     * `createTriggerClearButtonContentEl`.
     * - Default reads `createTagRemoveButtonContentElFn`; `null` (setting unset,
     *   or returned) = no icon - the theme's CSS glyph draws the x.
     * - Override only when extending; for one-off icons pass the setting.
     * @group Subclassing: rendering
     */
    protected createTagRemoveButtonContentEl(item: T): HTMLElement | SVGElement | null;
    /**
     * Per-chip visible content in `'tags'` mode. Mirrors `createItemContentEl`.
     * Default reads `createTagContentElFn`, else `null` so `createTagEl` falls
     * back to plain text from `itemToString`.
     * @group Subclassing: rendering
     */
    protected createTagContentEl(item: T): HTMLElement | null;
    /**
     * Item -> its remove button's accessible name in `'tags'` mode.
     * - Default: `uiTranslationPack.tagRemoveButtonAriaLabel(itemToString(item))`.
     * - Override only when extending (e.g. a name from another item field);
     *   per-locale text goes through the `uiTranslationPack` setting.
     * @group Subclassing: semantics
     */
    protected itemToTagRemoveButtonAriaLabel(item: T): string;
    /**
     * No selection iff the chosen set is empty. Drives the trigger's `data-empty`.
     * @group Subclassing: semantics
     */
    protected isEmpty(): boolean;
    /**
     * Toggle on click. Multi mode keeps the popup open.
     * @group Subclassing: reactions
     */
    protected onItemActivated(item: T): void;
    /**
     * Clear button empties the chosen-items set to `[]`.
     * @group Subclassing: semantics
     */
    protected clearSelection(): void;
    /**
     * Build the choose-all row (`chooseAllRow` setting) as the listbox's
     * leading `role="option"` row: `data-chosen-state="none|some|all"` (a CSS
     * styling hook), `aria-selected` only when ALL visible
     * enabled items are chosen, accessible name + visible text from
     * `uiTranslationPack.chooseAllRowText(chosenCount, totalCount)` over the visible
     * enabled subset. `null` when the setting is off or nothing is actionable.
     * @group Subclassing: rendering
     */
    protected createPopupListLeadingRowEl(): HTMLElement | null;
    /**
     * The choose-all row's visible content (rich tri-state). Mirrors
     * `createItemContentEl`.
     * - Default reads `createChooseAllRowContentElFn`; `null` (setting unset,
     *   or returned) = the default content: plain text from
     *   `uiTranslationPack.chooseAllRowText`.
     * - Override only when extending; for one-off content pass the setting.
     * @group Subclassing: rendering
     */
    protected createChooseAllRowContentEl(chosenState: LLSelectChosenState, chosenCount: number, totalCount: number): HTMLElement | null;
    /**
     * Activate the choose-all row: delegates to {@link toggleAllVisible}.
     * @group Subclassing: reactions
     */
    protected onLeadingRowActivated(): void;
    /**
     * Mark each item with `aria-selected` reflecting its chosen state.
     * @group Subclassing: rendering
     */
    protected createItemEl(item: T, index: number): HTMLElement;
    /**
     * Re-match the chosen entries against the new list after `setItems`.
     * - Entries the list no longer holds (by `compareFn`) are dropped and
     *   `onChange` fires for the drop.
     * - When the list holds a compareFn-equal but DIFFERENT object (`track by`
     *   style reload: same key, fresh fields), the stored reference is swapped
     *   to the list's object. A reference swap is not a logical change, so it
     *   does not fire `onChange`.
     * - The trigger content re-renders after every `setItems`, swap or not.
     * - Why: the count summary shows the list total, and a custom
     *   `createTriggerContentElFn` receives `items`.
     * - The arrow re-renders only when a chosen entry is dropped, because that
     *   runs the whole trigger.
     * - `triggerDisplay: 'tags'` is opt-in; `'count'` is the default.
     * - When `triggerDisplay` is `'tags'`, that render is one chip per chosen
     *   item per `setItems`, unless `createTriggerContentElFn` replaces the
     *   content.
     * - That cost is acceptable: `setItems` is a bulk call.
     * @group Subclassing: reactions
     */
    protected onItemsChanged(): void;
    /**
     * On open, focus the first chosen item (if present and enabled). Otherwise
     * the FIRST OPTION - which is the choose-all row when rendered (A11Y.md:
     * activedescendant points at the first chosen option, else the first
     * option; the row is the topmost option), so keyboard users discover it
     * immediately. Else the first enabled item. Indices are into
     * `getVisibleItems()`.
     * @group Subclassing: focus
     */
    protected focusInitial(): void;
    private arraysEqual;
    private fireChange;
}
//# sourceMappingURL=multiple.d.ts.map