import '../nui-icon/nui-icon.js'; import { html, nothing, type TemplateResult } from 'lit'; import type { NuiType } from '../../types/nui-type.js'; import { isOptionDisabled, resolveOptionLabel, resolveOptionValue, } from './auto-complete-options.js'; import type { AutoCompleteDropdownMode, AutoCompleteSize, AutoCompleteSuggestion, AutoCompleteVariant, } from './types.js'; export interface NuiAutoCompleteViewState { suggestions: AutoCompleteSuggestion[]; visibleSuggestions: AutoCompleteSuggestion[]; query: string; optionLabel: string; optionValue: string; optionDisabled: string; placeholder: string; disabled: boolean; invalid: boolean; readonly: boolean; fluid: boolean; size: AutoCompleteSize | ''; variant: AutoCompleteVariant | ''; dropdown: boolean; dropdownMode: AutoCompleteDropdownMode; panelScrollHeight: string; emptyMessage: string; dropdownIcon: string; overlayVisible: boolean; focusedIndex: number; name: string; inputId: string; ariaLabel: string; ariaLabelledby: string; nuiType: NuiType; autoCompleteClass: string; } export interface AutoCompleteRenderHandlers { onInput: (event: Event) => void; onChange: (event: Event) => void; onFocus: (event: Event) => void; onBlur: (event: Event) => void; onKeydown: (event: KeyboardEvent) => void; onDropdownClick: (event: Event) => void; onOptionClick: (index: number) => void; onOptionMouseDown: (event: Event) => void; } export function getAutoCompleteClass(autoCompleteClass: string): string { return ['nui-auto-complete', autoCompleteClass].filter(Boolean).join(' '); } function getListboxId(inputId: string): string { return inputId ? `${inputId}-listbox` : 'nui-auto-complete-listbox'; } export function renderAutoComplete( state: NuiAutoCompleteViewState, handlers: AutoCompleteRenderHandlers, ): TemplateResult { const listboxId = getListboxId(state.inputId); const activeDescendant = state.focusedIndex >= 0 ? `${listboxId}-option-${state.focusedIndex}` : nothing; return html`
${ state.dropdown ? html` ` : nothing }
${ state.overlayVisible ? html`
${ state.visibleSuggestions.length ? state.visibleSuggestions.map((option, index) => { const disabled = isOptionDisabled( option, state.optionDisabled, ); const selected = state.focusedIndex === index; return html` `; }) : html`
${state.emptyMessage}
` }
` : nothing }
`; } export function getSelectedSuggestionValue( state: Pick< NuiAutoCompleteViewState, 'visibleSuggestions' | 'optionLabel' | 'optionValue' >, index: number, ): string { const option = state.visibleSuggestions[index]; if (!option) { return ''; } return String( resolveOptionValue(option, state.optionValue, state.optionLabel), ); }