diff --git a/src/components/ha-selector/ha-selector-select.ts b/src/components/ha-selector/ha-selector-select.ts index 845df8c7cf..4a93bf095e 100644 --- a/src/components/ha-selector/ha-selector-select.ts +++ b/src/components/ha-selector/ha-selector-select.ts @@ -1,7 +1,8 @@ import { mdiDragHorizontalVariant } from "@mdi/js"; import { LitElement, css, html, nothing } from "lit"; -import { customElement, property, query } from "lit/decorators"; +import { customElement, property } from "lit/decorators"; import { repeat } from "lit/directives/repeat"; +import memoizeOne from "memoize-one"; import { ensureArray } from "../../common/array/ensure-array"; import { fireEvent } from "../../common/dom/fire_event"; import { stopPropagation } from "../../common/dom/stop_propagation"; @@ -11,9 +12,8 @@ import type { HomeAssistant } from "../../types"; import "../chips/ha-chip-set"; import "../chips/ha-input-chip"; import "../ha-checkbox"; -import "../ha-combo-box"; -import type { HaComboBox } from "../ha-combo-box"; import "../ha-formfield"; +import "../ha-generic-picker"; import "../ha-input-helper-text"; import "../ha-list-item"; import "../ha-radio"; @@ -40,8 +40,6 @@ export class HaSelectSelector extends LitElement { @property({ type: Boolean }) public required = true; - @query("ha-combo-box", true) private comboBox!: HaComboBox; - private _itemMoved(ev: CustomEvent): void { ev.stopPropagation(); const { oldIndex, newIndex } = ev.detail; @@ -59,15 +57,8 @@ export class HaSelectSelector extends LitElement { }); } - private _filter = ""; - protected render() { - const options = - this.selector.select?.options?.map((option) => - typeof option === "object" - ? (option as SelectOption) - : ({ value: option, label: option } as SelectOption) - ) || []; + const options = this._getOptions(this.selector); const translationKey = this.selector.select?.translation_key; @@ -165,10 +156,6 @@ export class HaSelectSelector extends LitElement { const value = !this.value || this.value === "" ? [] : ensureArray(this.value); - const optionItems = options.filter( - (option) => !option.disabled && !value?.includes(option.value) - ); - return html` ${value?.length ? html` @@ -212,50 +199,33 @@ export class HaSelectSelector extends LitElement { ` : nothing} - + > `; } if (this.selector.select?.custom_value) { - if ( - this.value !== undefined && - !Array.isArray(this.value) && - !options.find((option) => option.value === this.value) - ) { - options.unshift({ value: this.value, label: this.value }); - } - - const optionItems = options.filter((option) => !option.disabled); - return html` - + allow-custom-value + > `; } @@ -274,7 +244,7 @@ export class HaSelectSelector extends LitElement { > ${options.map( (item: SelectOption) => html` - ${item.label} ` @@ -291,6 +261,30 @@ export class HaSelectSelector extends LitElement { : ""; } + private _getOptions = memoizeOne( + (selector: SelectSelector) => + selector.select?.options?.map((option) => + typeof option === "object" + ? (option as SelectOption) + : ({ value: option, label: option } as SelectOption) + ) || [] + ); + + private _getItems = memoizeOne( + (options: SelectOption[], value?: string[], multiple = false) => { + const filteredOptions = options.filter((option) => + !option.disabled && !multiple ? true : !value?.includes(option.value) + ); + + return () => + filteredOptions.map((option) => ({ + id: option.value, + primary: option.label, + sorting_label: option.label, + })); + } + ); + private get _mode(): "list" | "dropdown" | "box" { return ( this.selector.select?.mode || @@ -355,8 +349,6 @@ export class HaSelectSelector extends LitElement { fireEvent(this, "value-changed", { value, }); - await this.updateComplete; - this._filterChanged(); } private _comboBoxValueChanged(ev: CustomEvent): void { @@ -374,49 +366,17 @@ export class HaSelectSelector extends LitElement { return; } - const currentValue = - !this.value || this.value === "" ? [] : ensureArray(this.value); + const currentValue = !this.value ? [] : ensureArray(this.value); if (newValue !== undefined && currentValue.includes(newValue)) { return; } - setTimeout(() => { - this._filterChanged(); - this.comboBox.setInputValue(""); - }, 0); - fireEvent(this, "value-changed", { value: [...currentValue, newValue], }); } - private _openedChanged(ev?: CustomEvent): void { - if (ev?.detail.value) { - this._filterChanged(); - } - } - - private _filterChanged(ev?: CustomEvent): void { - this._filter = ev?.detail.value || ""; - - const filteredItems = this.comboBox.items?.filter((item) => { - const label = item.label || item.value; - return label.toLowerCase().includes(this._filter?.toLowerCase()); - }); - - if ( - this._filter && - this.selector.select?.custom_value && - filteredItems && - !filteredItems.some((item) => (item.label || item.value) === this._filter) - ) { - filteredItems.unshift({ label: this._filter, value: this._filter }); - } - - this.comboBox.filteredItems = filteredItems; - } - static styles = css` :host { position: relative;