import "@material/mwc-list/mwc-list-item";
import { mdiClose } from "@mdi/js";
import { css, html, LitElement } from "lit";
import { customElement, property, query } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { stopPropagation } from "../../common/dom/stop_propagation";
import type { SelectOption, SelectSelector } from "../../data/selector";
import type { HomeAssistant } from "../../types";
import "../ha-checkbox";
import "../ha-chip";
import "../ha-chip-set";
import type { HaComboBox } from "../ha-combo-box";
import "../ha-formfield";
import "../ha-radio";
import "../ha-select";
@customElement("ha-selector-select")
export class HaSelectSelector extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public selector!: SelectSelector;
@property() public value?: string | string[];
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
@query("ha-combo-box", true) private comboBox!: HaComboBox;
private _filter = "";
protected render() {
const options = this.selector.select.options.map((option) =>
typeof option === "object" ? option : { value: option, label: option }
);
if (!this.selector.select.custom_value && this._mode === "list") {
if (!this.selector.select.multiple || this.required) {
return html`
${this.label}
${options.map(
(item: SelectOption) => html`
`
)}
${this._renderHelper()}
`;
}
return html`
${this.label}${options.map(
(item: SelectOption) => html`
`
)}
${this._renderHelper()}
`;
}
if (this.selector.select.multiple) {
const value =
!this.value || this.value === "" ? [] : (this.value as string[]);
return html`
${value?.map(
(item, idx) =>
html`
${options.find((option) => option.value === item)?.label ||
item}
`
)}
!this.value?.includes(item.value))}
@filter-changed=${this._filterChanged}
@value-changed=${this._comboBoxValueChanged}
>
`;
}
if (this.selector.select.custom_value) {
if (
this.value !== undefined &&
!options.find((option) => option.value === this.value)
) {
options.unshift({ value: this.value, label: this.value });
}
return html`
`;
}
return html`
${options.map(
(item: SelectOption) => html`
${item.label}
`
)}
`;
}
private _renderHelper() {
return this.helper
? html`${this.helper}`
: "";
}
private get _mode(): "list" | "dropdown" {
return (
this.selector.select.mode ||
(this.selector.select.options.length < 6 ? "list" : "dropdown")
);
}
private _valueChanged(ev) {
ev.stopPropagation();
const value = ev.detail?.value || ev.target.value;
if (this.disabled || !value) {
return;
}
fireEvent(this, "value-changed", {
value: value,
});
}
private _checkboxChanged(ev) {
ev.stopPropagation();
if (this.disabled) {
return;
}
let newValue: string[];
const value: string = ev.target.value;
const checked = ev.target.checked;
if (checked) {
if (!this.value) {
newValue = [value];
} else if (this.value.includes(value)) {
return;
} else {
newValue = [...this.value, value];
}
} else {
if (!this.value?.includes(value)) {
return;
}
newValue = (this.value as string[]).filter((v) => v !== value);
}
fireEvent(this, "value-changed", {
value: newValue,
});
}
private async _removeItem(ev) {
const value: string[] = [...(this.value! as string[])];
value.splice(ev.target.idx, 1);
fireEvent(this, "value-changed", {
value,
});
await this.updateComplete;
this._filterChanged();
}
private _comboBoxValueChanged(ev: CustomEvent): void {
ev.stopPropagation();
const newValue = ev.detail.value;
if (this.disabled || newValue === "") {
return;
}
if (!this.selector.select.multiple) {
fireEvent(this, "value-changed", {
value: newValue,
});
return;
}
if (newValue !== undefined && this.value?.includes(newValue)) {
return;
}
setTimeout(() => {
this._filterChanged();
this.comboBox.setInputValue("");
}, 0);
const currentValue =
!this.value || this.value === "" ? [] : (this.value as string[]);
fireEvent(this, "value-changed", {
value: [...currentValue, newValue],
});
}
private _filterChanged(ev?: CustomEvent): void {
this._filter = ev?.detail.value || "";
const filteredItems = this.comboBox.items?.filter((item) => {
if (this.selector.select.multiple && this.value?.includes(item.value)) {
return false;
}
const label = item.label || item.value;
return label.toLowerCase().includes(this._filter?.toLowerCase());
});
if (this._filter && this.selector.select.custom_value) {
filteredItems?.unshift({ label: this._filter, value: this._filter });
}
this.comboBox.filteredItems = filteredItems;
}
static styles = css`
ha-select,
mwc-formfield,
ha-formfield {
display: block;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-selector-select": HaSelectSelector;
}
}