/** * TyMultiselect Web Component * PORTED FROM: clj/ty/components/multiselect.cljs * * A multiselect dropdown component using ty-tag for selections with: * - Tag-only options (only ty-tag elements supported) * - Multiple selection with visual tags * - Desktop mode with smart positioning * - Mobile mode with full-screen modal * - Search and filtering capabilities * - Keyboard navigation * - Form association for native form submission with multiple values * - Scroll locking when dropdown is open * - Outside click to close * * @example * ```html * * * JavaScript * TypeScript * Python * * * * * JavaScript * TypeScript * Python * * * * * *
* * 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'; /** * Tag data structure */ interface TagData { value: string; text: string; element: HTMLElement; } /** * Component state structure */ interface MultiselectState { open: boolean; search: string; highlightedIndex: number; filteredTags: TagData[]; selectedValues: string[]; mode: 'desktop' | 'mobile'; expandedSection: 'selected' | 'available'; } /** * Ty Multiselect Component */ export declare class TyMultiselect extends TyComponent { protected static properties: { value: { type: "string"; visual: boolean; formValue: boolean; emitChange: boolean; default: string; coerce: (v: any) => 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; }; searchable: { type: "boolean"; visual: boolean; default: boolean; aliases: { 'not-searchable': 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; }; delay: { type: "number"; default: number; validate: (v: any) => boolean; coerce: (v: any) => number; }; 'selected-label': { type: "string"; visual: boolean; default: string; }; 'available-label': { type: "string"; visual: boolean; default: string; }; 'no-selection-message': { type: "string"; visual: boolean; default: string; }; 'no-options-message': { type: "string"; visual: boolean; default: string; }; }; private _value; private _name; private _placeholder; private _label; private _disabled; private _readonly; private _required; private _searchable; private _size; private _flavor; private _selectedLabel; private _availableLabel; private _noSelectionMessage; private _noOptionsMessage; private _state; set expandedSection(value: 'selected' | 'available'); get expandedSection(): 'selected' | 'available'; private _stubClickHandler; private _outsideClickHandler; private _tagClickHandler; private _tagDismissHandler; private _searchInputHandler; private _blockSearchClick; private _keyboardHandler; private _delay; private _searchDebounceTimer; private _optionsScrollbar; constructor(); /** * 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; /** * Called when properties change * Handle state synchronization BEFORE render */ protected onPropertiesChanged(changes: PropertyChange[]): void; /** * Get the form value for this component * Returns FormData with multiple entries (HTMX standard) */ protected getFormValue(): FormDataEntryValue | FormData | null; /** * Parse multiselect value (comma-separated string to array) */ private parseValue; /** * Initialize component state from attributes * Reads from both property and attribute (like ClojureScript version) */ private initializeState; /** * Get all ty-tag elements from the component (ALL slots) */ private getTagElements; /** * Extract value and text from a ty-tag element */ private getTagData; /** * Select a tag - set selected state, move to selected slot, make dismissible */ private selectTag; /** * Deselect a tag - remove selected state, remove from selected slot, remove dismissible */ private deselectTag; /** * Get array of currently selected values from tags (ALWAYS reads from DOM) */ private getSelectedValues; /** * Check if all available tags are selected */ private allTagsSelected; /** * Sync tag selection states with desired values */ private syncSelectedTags; /** * Central update function - synchronizes everything * Uses TyComponent's property system for proper lifecycle */ private updateComponentValue; /** * Calculate and set dropdown position with smart direction detection */ private calculatePosition; private _setupOptionsScrollbar; private _destroyOptionsScrollbar; /** * Open dropdown dialog (desktop mode) * Using element - scroll locking handled natively */ private openDropdown; /** * Close dropdown dialog (desktop mode) * Using element - scroll unlocking handled natively */ private closeDropdown; /** * Open mobile modal (mobile mode) * Now using element for native z-index management */ private openMobileModal; /** * Close mobile modal (mobile mode) * Now using element for native management */ private closeMobileModal; private handleStubClick; private handleOutsideClick; private handleTagClick; private handleTagDismiss; private blockSearchClick; private handleSearchInput; private handleKeyboard; /** * Filter tags based on search query */ private filterTags; /** * Update visibility of tags based on filtered list */ private updateTagVisibility; /** * Show/hide the dropdown options area */ private updateOptionsVisibility; /** * Clear all tag highlights */ private clearHighlights; /** * Highlight tag at specific index */ private highlightTag; /** * Dispatch search event for external search handling * With optional delay/debounce support */ private dispatchSearchEvent; /** * Fire the actual search event */ private fireSearchEvent; /** * Dispatch custom change event */ private dispatchChangeEvent; /** * Main render method (required by TyComponent) * Delegates to mode-specific renderer */ protected render(): void; /** * Setup event listeners */ private setupEventListeners; /** * Build CSS class list for stub */ private buildStubClasses; /** * Render desktop mode with dialog */ private renderDesktop; /** * Render mobile mode with full-screen modal * Following dropdown.ts mobile structure */ private renderMobile; /** * Setup event listeners for mobile mode * Using element - backdrop clicks handled natively */ private setupMobileEventListeners; /** * Handle mobile stub click - open modal */ private handleMobileStubClick; /** * Handle mobile tag click - select and potentially close */ private handleMobileTagClick; /** * Toggle section expansion (mobile only) * Clicking expanded section collapses it and expands the other * Clicking collapsed section expands it and collapses the other */ private toggleSection; /** * Sync section states to DOM without toggle logic */ private syncSectionStates; /** * Update mobile selected section state (collapsed view, empty states, etc.) */ private updateMobileSelectedState; /** * Update selection display (show/hide placeholder) * Matches dropdown.ts pattern - uses CSS via has-selection class */ private updateSelectionDisplay; get value(): string; set value(val: string); get name(): string; set name(val: string); get placeholder(): string; set placeholder(val: string); get label(): string; set label(val: string); get disabled(): boolean; set disabled(value: boolean); get readonly(): boolean; set readonly(value: boolean); get required(): boolean; set required(value: boolean); get searchable(): boolean; set searchable(value: boolean); get delay(): number; set delay(value: number | string); get size(): Size; set size(value: Size); get flavor(): Flavor; set flavor(value: Flavor); get form(): HTMLFormElement | null; } export {}; //# sourceMappingURL=multiselect.d.ts.map