import { ReactiveController, ReactiveControllerHost } from 'lit'; import { VirtualTrigger } from '../../overlay/virtual-trigger'; import type { TriggerConfig, TriggerOption } from '../types'; export interface TriggerMenuHost extends ReactiveControllerHost { allowElements: boolean; disabled: boolean; readonly: boolean; pending: boolean; shadowRoot: ShadowRoot | null; addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; dispatchEvent(event: Event): boolean; requestUpdate(): void; insertElement(elementType: string, label: string, data: unknown, icon?: unknown): string; focus(): void; } /** * Manages trigger menu detection, overlay positioning, option filtering, * and keyboard navigation. * * Supports arbitrary trigger keys via a `TriggerConfig[]` — no longer * hardcoded to `@` and `/`. */ export declare class TriggerMenuController implements ReactiveController { private _host; private _triggers; /** Currently active trigger key, or null when no menu is open. */ activeTrigger: string | null; /** Text typed after the trigger key (used for filtering). */ searchString: string; /** Virtual anchor element for the overlay. */ virtualElement: VirtualTrigger | null; /** * Index of the currently highlighted option in the filtered list. * -1 means nothing explicitly selected (but first item is visually active). */ highlightedIndex: number; /** * Suppresses pointer-based highlighting after keyboard navigation * until the user actually moves the mouse. Prevents scroll-induced * `pointerenter` from stealing the highlight. */ pointerMovedSinceKeyNav: boolean; /** Index of the option currently under the pointer, -1 when none. */ hoveredIndex: number; /** Filtered options for the active trigger, computed on each search change. */ filteredOptions: TriggerOption[]; /** Reference to the contenteditable element. */ richInputElement: HTMLDivElement | null; constructor(host: TriggerMenuHost); hostConnected(): void; hostDisconnected(): void; get triggers(): TriggerConfig[]; set triggers(value: TriggerConfig[]); /** * Get the TriggerConfig for the currently active trigger. */ get activeConfig(): TriggerConfig | undefined; /** * Whether any trigger configs are defined. */ get hasTriggers(): boolean; /** * Check if a given trigger key has a slot defined. */ getSlotName(triggerKey: string): string | undefined; /** * Get all distinct slot names across all trigger configs. */ get allSlotNames(): string[]; /** * Called on each input event in the rich input. When no menu is open, detects * trigger keys typed at a word boundary; when open, updates the search string. */ handleInput(inputEvent?: InputEvent): void; open(triggerKey: string): void; close(): void; /** * Handle keydown events in the rich input when a trigger menu is open. * Returns true if the event was consumed (caller should preventDefault). */ handleKeydown(e: KeyboardEvent): boolean; /** * Handle the overlay's closed event. */ handleOverlayClosed: () => void; /** * Handle keydown inside the overlay (e.g. Escape from slotted content). */ handleOverlayKeydown: (e: KeyboardEvent) => void; private _detectTrigger; private _extractTriggerSearchFromContent; private _isTriggerKey; private _updateFilteredOptions; /** * Find the first non-header option index starting from (and including) `start`. * Returns -1 if none found. */ private _findSelectableIndex; handlePointerMove: () => void; private _moveHighlight; private _selectHighlighted; selectOption(option: TriggerOption): void; private _handleTriggerSelect; private _handleDocumentPointerDown; private _dispatchChange; }