import SelectStyles from "../styles/SelectStyles.wrn" component AdvancedSelect { outputs { search(payload: { value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) select(payload: { value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) change(payload: { value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) clear(payload: { value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) open(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) close(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) load(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) error(payload: { error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string) } props { size: string = "default" color: string = "primary" label: string = "Advanced Select" name: string = "" value: string = "" values: unknown[] = [] options: unknown[] = [] groups: unknown[] = [] placeholder: string = "Select an option" placeholderIcon: string = "" searchPlaceholder: string = "Search options…" multiple: boolean = false searchable: boolean = true defaultOpen: boolean = false clearable: boolean = true allowEmpty: boolean = true tags: boolean = false disabled: boolean = false required: boolean = false invalid: boolean = false validationMessage: string = "" helpText: string = "" loading: boolean = false loadingLabel: string = "Loading options…" emptyLabel: string = "No options found" selectedOptionsLabel: string = "Selected options" clearLabel: string = "Clear selection" createLabel: string = "Create" loadMoreLabel: string = "Load more" searchMode: string = "contains" searchFields: string = "label,description" minSearchLength: number = 0 searchResultLimit: number = 0 maxSelections: number = 0 showCounter: boolean = false counterTemplate: string = "{selected} selected" optionTemplate: string = "default" selectedTemplate: string = "default" closeOnSelect: boolean = true scrollToSelected: boolean = true fixed: boolean = false placement: string = "bottom" remote: boolean = false remoteUrl: string = "" remoteQueryParam: string = "q" remoteDebounce: number = 250 remoteAutoLoad: boolean = true infinite: boolean = false hasMore: boolean = false page: number = 1 class: string = "" } state open = defaultOpen state query: string = "" state activeIndex: number = -1 state selectedValue = value state selectedValues = values functions { shared function allOptions() { return [...groups.flatMap((group) => group.options || []), ...options] } shared function searchableText(option) { return ((option.label || "") + " " + (option.description || "")).toLowerCase() } shared function matches(option) { if (!query || query.length < Number(minSearchLength || 0)) { return true } if (searchMode === "startsWith") { return searchableText(option).startsWith(query.toLowerCase()) } if (searchMode === "exact") { return searchableText(option) === query.toLowerCase() } return searchableText(option).includes(query.toLowerCase()) } shared function matchingOptions(list) { return list.filter((option) => matches(option)) } shared function visibleOptions(list) { if (searchResultLimit > 0) { return matchingOptions(list).slice(0, Number(searchResultLimit)) } return matchingOptions(list) } shared function flatVisibleOptions() { return visibleOptions(allOptions()) } shared function isSelected(option) { return ( multiple ? selectedValues.includes(option.value) : selectedValue === option.value ) } shared function selectedOptions() { return allOptions().filter((option) => isSelected(option)) } shared function selectedCount() { return multiple ? selectedValues.length : selectedValue ? 1 : 0 } shared function counterText() { return ( maxSelections ? selectedCount() + " / " + maxSelections + " selected" : selectedCount() + " selected" ) } shared function selectedText() { return ( multiple ? selectedValues.join(", ") : selectedOptions().length ? selectedOptions()[0].label : "" ) } shared function triggerText() { return selectedCount() ? selectedText() : placeholder } shared function canSelect(option) { if (option.disabled) { return false } if (!multiple || isSelected(option)) { return true } if (maxSelections <= 0) { return true } return selectedCount() < maxSelections } shared function chooseSingle(option) { if (!canSelect(option)) { return } selectedValue = option.value query = "" if (closeOnSelect) { open = false } } shared function chooseMultiple(option) { if (!canSelect(option)) { return } if (isSelected(option)) { selectedValues = selectedValues.filter((item) => item !== option.value) } else { selectedValues = selectedValues.concat([option.value]) } query = "" } shared function chooseOption(option) { if (multiple) { chooseMultiple(option) return } chooseSingle(option) } client function clearSelection(event) { event.stopPropagation() selectedValue = "" selectedValues = [] query = "" open = false } shared function toggle() { if (disabled) { return; }; open = !open; activeIndex = open && flatVisibleOptions().length ? 0 : -1; } shared function moveActive(direction) { if (!flatVisibleOptions().length) { return } activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length } client function handleKeydown(event) { if (disabled) { return } if (event.key === "ArrowDown") { event.preventDefault() if (!open) { open = true } moveActive(1) } else if (event.key === "ArrowUp") { event.preventDefault() if (!open) { open = true } moveActive(-1) } else if (event.key === "Enter" || event.key === " ") { event.preventDefault() if (!open) { open = true } else if (activeIndex >= 0) { chooseOption(flatVisibleOptions()[activeIndex]) } } else if (event.key === "Escape") { open = false } else if (event.key === "Home" && open) { event.preventDefault() activeIndex = 0 } else if (event.key === "End" && open) { event.preventDefault() activeIndex = flatVisibleOptions().length - 1 } } shared function optionIndex(option) { return flatVisibleOptions().findIndex((item) => item.value === option.value) } } view {
{counterText()}
{#if searchable} {/if}
Enter at least {minSearchLength} characters.
{loadingLabel}
{#each groups as group} {#if visibleOptions(group.options || []).length}
{group.label}
{#each group.options || [] as option} {/each}
{/if} {/each} {#each options as option} {/each} {#if !loading && !flatVisibleOptions().length}
{emptyLabel}
{/if}
{#if tags && query && !allOptions().some((option) => option.label.toLowerCase() === query.toLowerCase())} {/if}
{#if helpText && !validationMessage}{helpText}{/if} {validationMessage}