/** * TyDropdown Web Component * PORTED FROM: clj/ty/components/dropdown.cljs * * A semantic dropdown component with: * - Desktop mode with smart positioning * - Mobile mode with full-screen modal * - Search and filtering capabilities * - Keyboard navigation * - Form association for native form submission * - Rich option support (option, ty-option, ty-tag) * * @example * ```html * * * * * * * * * * *
* * John Doe *
*
*
* * * * * * ``` */ import type { Flavor, Size } from '../types/common.js'; import { TyComponent } from '../base/ty-component.js'; import type { PropertyChange } from '../utils/property-manager.js'; /** * Option data structure */ interface OptionData { value: string; text: string; element: HTMLElement; } /** * Component state structure */ interface DropdownState { open: boolean; search: string; highlightedIndex: number; filteredOptions: OptionData[]; currentValue: string | null; mode: 'desktop' | 'mobile'; } /** * Ty Dropdown Component */ export declare class TyDropdown extends TyComponent { protected static properties: { value: { type: "string"; visual: boolean; formValue: boolean; emitChange: boolean; default: string; }; name: { type: "string"; default: string; }; placeholder: { type: "string"; visual: boolean; default: string; }; label: { type: "string"; visual: boolean; default: string; }; disabled: { type: "boolean"; visual: boolean; default: boolean; }; readonly: { type: "boolean"; visual: boolean; default: boolean; }; required: { type: "boolean"; visual: boolean; default: boolean; }; externalSearch: { type: "boolean"; visual: boolean; default: boolean; aliases: { 'external-search': boolean; }; }; clearable: { type: "boolean"; visual: boolean; default: boolean; aliases: { 'not-clearable': boolean; }; }; size: { type: "string"; visual: boolean; default: string; validate: (v: any) => boolean; coerce: (v: any) => any; }; flavor: { type: "string"; visual: boolean; default: string; validate: (v: any) => boolean; coerce: (v: any) => any; }; debounce: { type: "number"; default: number; validate: (v: any) => boolean; coerce: (v: any) => number; }; loading: { type: "boolean"; visual: boolean; default: boolean; }; }; private _value; private _placeholder; private _label; private _disabled; private _readonly; private _required; private _externalSearch; private _clearable; private _loading; private _size; private _state; private _scrollLockId; private _stubClickHandler; private _outsideClickHandler; private _optionClickHandler; private _searchInputHandler; private _blockSearchClick; private _keyboardHandler; private _clearClickHandler; private _debounce; private _searchDebounceTimer; private _optionsScrollbar; private _childObserver; constructor(); render(): void; /** * Called when component is connected to DOM * TyComponent handles property capture automatically */ protected onConnect(): void; /** * Called when component is disconnected from DOM * Clean up event listeners and timers */ protected onDisconnect(): void; /** * Re-establish the visual selection (selected attribute + slot clone) for the * current value, when the matching option exists in children but isn't yet * marked. Called from the children MutationObserver — covers the case where * a consumer swaps options dynamically (external-search refresh) and wipes * out the previous selection's marker + clone in the process. * * Idempotent — bails when nothing to do, so it's safe to call from the * MutationObserver callback even when the trigger was our own clone work. */ private redisplaySelected; /** * Called when properties change * Handle state synchronization BEFORE render */ protected onPropertiesChanged(changes: PropertyChange[]): void; /** * Toggle the loading visual state on the open popup. * Replaces the options list with a centered spinner; search input stays usable. * Pulls the latest registered loader SVG on each call so registry changes * take effect on the next loading toggle. */ private applyLoadingState; /** * Get the form value for this component * TyComponent calls this automatically when formValue property changes */ protected getFormValue(): FormDataEntryValue | null; /** * Parse dropdown value (single string) */ private parseValue; /** * Initialize component state from attributes */ private initializeState; /** * Update placeholder text in existing rendered HTML * Called when placeholder changes after initial render */ private updatePlaceholderInDOM; /** * Update form value via ElementInternals */ /** * Get all option elements from slot * Supports: