mirror of
https://github.com/home-assistant/frontend.git
synced 2025-12-20 02:38:53 +00:00
Migrate ha-selector-select to use ha-generic-picker component (#28614)
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import { mdiDragHorizontalVariant } from "@mdi/js";
|
import { mdiDragHorizontalVariant } from "@mdi/js";
|
||||||
import { LitElement, css, html, nothing } from "lit";
|
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 { repeat } from "lit/directives/repeat";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
import { ensureArray } from "../../common/array/ensure-array";
|
import { ensureArray } from "../../common/array/ensure-array";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { stopPropagation } from "../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../common/dom/stop_propagation";
|
||||||
@@ -11,9 +12,8 @@ import type { HomeAssistant } from "../../types";
|
|||||||
import "../chips/ha-chip-set";
|
import "../chips/ha-chip-set";
|
||||||
import "../chips/ha-input-chip";
|
import "../chips/ha-input-chip";
|
||||||
import "../ha-checkbox";
|
import "../ha-checkbox";
|
||||||
import "../ha-combo-box";
|
|
||||||
import type { HaComboBox } from "../ha-combo-box";
|
|
||||||
import "../ha-formfield";
|
import "../ha-formfield";
|
||||||
|
import "../ha-generic-picker";
|
||||||
import "../ha-input-helper-text";
|
import "../ha-input-helper-text";
|
||||||
import "../ha-list-item";
|
import "../ha-list-item";
|
||||||
import "../ha-radio";
|
import "../ha-radio";
|
||||||
@@ -40,8 +40,6 @@ export class HaSelectSelector extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public required = true;
|
@property({ type: Boolean }) public required = true;
|
||||||
|
|
||||||
@query("ha-combo-box", true) private comboBox!: HaComboBox;
|
|
||||||
|
|
||||||
private _itemMoved(ev: CustomEvent): void {
|
private _itemMoved(ev: CustomEvent): void {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
const { oldIndex, newIndex } = ev.detail;
|
const { oldIndex, newIndex } = ev.detail;
|
||||||
@@ -59,15 +57,8 @@ export class HaSelectSelector extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _filter = "";
|
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
const options =
|
const options = this._getOptions(this.selector);
|
||||||
this.selector.select?.options?.map((option) =>
|
|
||||||
typeof option === "object"
|
|
||||||
? (option as SelectOption)
|
|
||||||
: ({ value: option, label: option } as SelectOption)
|
|
||||||
) || [];
|
|
||||||
|
|
||||||
const translationKey = this.selector.select?.translation_key;
|
const translationKey = this.selector.select?.translation_key;
|
||||||
|
|
||||||
@@ -165,10 +156,6 @@ export class HaSelectSelector extends LitElement {
|
|||||||
const value =
|
const value =
|
||||||
!this.value || this.value === "" ? [] : ensureArray(this.value);
|
!this.value || this.value === "" ? [] : ensureArray(this.value);
|
||||||
|
|
||||||
const optionItems = options.filter(
|
|
||||||
(option) => !option.disabled && !value?.includes(option.value)
|
|
||||||
);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${value?.length
|
${value?.length
|
||||||
? html`
|
? html`
|
||||||
@@ -212,50 +199,33 @@ export class HaSelectSelector extends LitElement {
|
|||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
|
|
||||||
<ha-combo-box
|
<ha-generic-picker
|
||||||
item-value-path="value"
|
|
||||||
item-label-path="label"
|
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.label=${this.label}
|
|
||||||
.helper=${this.helper}
|
.helper=${this.helper}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.required=${this.required && !value.length}
|
.required=${this.required && !value.length}
|
||||||
.value=${""}
|
.value=${""}
|
||||||
.items=${optionItems}
|
.addButtonLabel=${this.label}
|
||||||
|
.getItems=${this._getItems(options, value, true)}
|
||||||
.allowCustomValue=${this.selector.select.custom_value ?? false}
|
.allowCustomValue=${this.selector.select.custom_value ?? false}
|
||||||
@filter-changed=${this._filterChanged}
|
|
||||||
@value-changed=${this._comboBoxValueChanged}
|
@value-changed=${this._comboBoxValueChanged}
|
||||||
@opened-changed=${this._openedChanged}
|
></ha-generic-picker>
|
||||||
></ha-combo-box>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selector.select?.custom_value) {
|
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`
|
return html`
|
||||||
<ha-combo-box
|
<ha-generic-picker
|
||||||
item-value-path="value"
|
|
||||||
item-label-path="label"
|
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.label=${this.label}
|
.label=${this.label}
|
||||||
.helper=${this.helper}
|
.helper=${this.helper}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.required=${this.required}
|
.required=${this.required}
|
||||||
.items=${optionItems}
|
.getItems=${this._getItems(options)}
|
||||||
.value=${this.value}
|
.value=${this.value as string | undefined}
|
||||||
@filter-changed=${this._filterChanged}
|
|
||||||
@value-changed=${this._comboBoxValueChanged}
|
@value-changed=${this._comboBoxValueChanged}
|
||||||
@opened-changed=${this._openedChanged}
|
allow-custom-value
|
||||||
></ha-combo-box>
|
></ha-generic-picker>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +244,7 @@ export class HaSelectSelector extends LitElement {
|
|||||||
>
|
>
|
||||||
${options.map(
|
${options.map(
|
||||||
(item: SelectOption) => html`
|
(item: SelectOption) => html`
|
||||||
<ha-list-item .value=${item.value} .disabled=${item.disabled}
|
<ha-list-item .value=${item.value} .disabled=${!!item.disabled}
|
||||||
>${item.label}</ha-list-item
|
>${item.label}</ha-list-item
|
||||||
>
|
>
|
||||||
`
|
`
|
||||||
@@ -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" {
|
private get _mode(): "list" | "dropdown" | "box" {
|
||||||
return (
|
return (
|
||||||
this.selector.select?.mode ||
|
this.selector.select?.mode ||
|
||||||
@@ -355,8 +349,6 @@ export class HaSelectSelector extends LitElement {
|
|||||||
fireEvent(this, "value-changed", {
|
fireEvent(this, "value-changed", {
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
await this.updateComplete;
|
|
||||||
this._filterChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _comboBoxValueChanged(ev: CustomEvent): void {
|
private _comboBoxValueChanged(ev: CustomEvent): void {
|
||||||
@@ -374,49 +366,17 @@ export class HaSelectSelector extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentValue =
|
const currentValue = !this.value ? [] : ensureArray(this.value);
|
||||||
!this.value || this.value === "" ? [] : ensureArray(this.value);
|
|
||||||
|
|
||||||
if (newValue !== undefined && currentValue.includes(newValue)) {
|
if (newValue !== undefined && currentValue.includes(newValue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this._filterChanged();
|
|
||||||
this.comboBox.setInputValue("");
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
fireEvent(this, "value-changed", {
|
fireEvent(this, "value-changed", {
|
||||||
value: [...currentValue, newValue],
|
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`
|
static styles = css`
|
||||||
:host {
|
:host {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
Reference in New Issue
Block a user