import { html, nothing, type TemplateResult } from 'lit'; import type { NuiType } from '../../types/nui-type.js'; import { isOptionDisabled, isValueSelected, resolveOptionLabel, resolveOptionValue, } from './listbox-options.js'; import type { ListboxOption, ListboxPrimitive, ListboxValue } from './types.js'; export interface NuiListboxViewState { options: ListboxOption[]; visibleOptions: ListboxOption[]; optionLabel: string; optionValue: string; optionDisabled: string; value: ListboxValue; multiple: boolean; disabled: boolean; invalid: boolean; readonly: boolean; filter: boolean; filterPlaceholder: string; filterValue: string; listScrollHeight: string; striped: boolean; checkmark: boolean; highlightOnSelect: boolean; emptyMessage: string; emptyFilterMessage: string; fluid: boolean; tabindex: number; ariaLabel: string; ariaLabelledby: string; focusedIndex: number; nuiType: NuiType; listboxClass: string; } export interface ListboxRenderHandlers { onFilterInput: (event: Event) => void; onOptionClick: (index: number) => void; onListFocus: () => void; } export function getListboxClass(listboxClass: string): string { return ['nui-listbox', listboxClass].filter(Boolean).join(' '); } function renderOption( state: NuiListboxViewState, option: ListboxOption, index: number, handlers: ListboxRenderHandlers, ): TemplateResult { const optionVal = resolveOptionValue( option, state.optionValue, state.optionLabel, ); const selected = isValueSelected(state.value, optionVal, state.multiple); const disabled = state.disabled || isOptionDisabled(option, state.optionDisabled); const focused = state.focusedIndex === index; return html`
  • handlers.onOptionClick(index)} > ${ state.checkmark ? html` ` : nothing } ${resolveOptionLabel(option, state.optionLabel)}
  • `; } export function renderListbox( state: NuiListboxViewState, handlers: ListboxRenderHandlers, ): TemplateResult { const showEmptyFilter = state.filter && state.filterValue.trim().length > 0; const emptyText = showEmptyFilter ? state.emptyFilterMessage : state.emptyMessage; const listStyle = `max-height:${state.listScrollHeight}`; return html`
    ${ state.filter ? html`
    ` : nothing }
    `; } export function getOptionValueAt( options: ListboxOption[], index: number, optionValue: string, optionLabel: string, ): ListboxPrimitive | null { const option = options[index]; if (!option) { return null; } return resolveOptionValue(option, optionValue, optionLabel); }