diff --git a/src/components/entity/ha-statistic-combo-box.ts b/src/components/entity/ha-statistic-combo-box.ts deleted file mode 100644 index eaddfe7ddd..0000000000 --- a/src/components/entity/ha-statistic-combo-box.ts +++ /dev/null @@ -1,481 +0,0 @@ -import { mdiChartLine, mdiHelpCircle, mdiShape } from "@mdi/js"; -import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit"; -import Fuse from "fuse.js"; -import type { HassEntity } from "home-assistant-js-websocket"; -import type { PropertyValues, TemplateResult } from "lit"; -import { html, LitElement, nothing } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { ensureArray } from "../../common/array/ensure-array"; -import { fireEvent } from "../../common/dom/fire_event"; -import { computeAreaName } from "../../common/entity/compute_area_name"; -import { computeDeviceName } from "../../common/entity/compute_device_name"; -import { computeEntityName } from "../../common/entity/compute_entity_name"; -import { computeStateName } from "../../common/entity/compute_state_name"; -import { getEntityContext } from "../../common/entity/context/get_entity_context"; -import { caseInsensitiveStringCompare } from "../../common/string/compare"; -import { computeRTL } from "../../common/util/compute_rtl"; -import { domainToName } from "../../data/integration"; -import type { StatisticsMetaData } from "../../data/recorder"; -import { getStatisticIds, getStatisticLabel } from "../../data/recorder"; -import { HaFuse } from "../../resources/fuse"; -import type { HomeAssistant, ValueChangedEvent } from "../../types"; -import "../ha-combo-box"; -import type { HaComboBox } from "../ha-combo-box"; -import "../ha-combo-box-item"; -import "../ha-svg-icon"; -import "./state-badge"; -import { documentationUrl } from "../../util/documentation-url"; - -type StatisticItemType = "entity" | "external" | "no_state"; - -interface StatisticItem { - // Force empty label to always display empty value by default in the search field - id: string; - statistic_id?: string; - label: ""; - primary: string; - secondary?: string; - search_labels?: string[]; - sorting_label?: string; - icon_path?: string; - type?: StatisticItemType; - stateObj?: HassEntity; -} - -const MISSING_ID = "___missing-entity___"; - -const TYPE_ORDER = ["entity", "external", "no_state"] as StatisticItemType[]; - -@customElement("ha-statistic-combo-box") -export class HaStatisticComboBox extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property() public label?: string; - - @property() public value?: string; - - @property({ attribute: "statistic-types" }) - public statisticTypes?: "mean" | "sum"; - - @property({ type: Boolean, attribute: "allow-custom-entity" }) - public allowCustomEntity; - - @property({ attribute: false, type: Array }) - public statisticIds?: StatisticsMetaData[]; - - @property({ type: Boolean }) public disabled = false; - - /** - * Show only statistics natively stored with these units of measurements. - * @type {Array} - * @attr include-statistics-unit-of-measurement - */ - @property({ - type: Array, - attribute: "include-statistics-unit-of-measurement", - }) - public includeStatisticsUnitOfMeasurement?: string | string[]; - - /** - * Show only statistics with these unit classes. - * @attr include-unit-class - */ - @property({ attribute: "include-unit-class" }) - public includeUnitClass?: string | string[]; - - /** - * Show only statistics with these device classes. - * @attr include-device-class - */ - @property({ attribute: "include-device-class" }) - public includeDeviceClass?: string | string[]; - - /** - * Show only statistics on entities. - * @type {Boolean} - * @attr entities-only - */ - @property({ type: Boolean, attribute: "entities-only" }) - public entitiesOnly = false; - - /** - * List of statistics to be excluded. - * @type {Array} - * @attr exclude-statistics - */ - @property({ type: Array, attribute: "exclude-statistics" }) - public excludeStatistics?: string[]; - - @property({ attribute: false }) public helpMissingEntityUrl = - "/more-info/statistics/"; - - @state() private _opened = false; - - @query("ha-combo-box", true) public comboBox!: HaComboBox; - - private _initialItems = false; - - private _items: StatisticItem[] = []; - - protected firstUpdated(changedProperties: PropertyValues): void { - super.firstUpdated(changedProperties); - this.hass.loadBackendTranslation("title"); - } - - private _rowRenderer: ComboBoxLitRenderer = ( - item, - { index } - ) => { - const showEntityId = this.hass.userData?.showEntityIdPicker; - return html` - - ${item.icon_path - ? html` - - ` - : item.stateObj - ? html` - - ` - : nothing} - ${item.primary} - ${item.secondary - ? html`${item.secondary}` - : nothing} - ${item.id && showEntityId - ? html` - ${item.statistic_id} - ` - : nothing} - - `; - }; - - private _getItems = memoizeOne( - ( - _opened: boolean, - hass: this["hass"], - statisticIds: StatisticsMetaData[], - includeStatisticsUnitOfMeasurement?: string | string[], - includeUnitClass?: string | string[], - includeDeviceClass?: string | string[], - entitiesOnly?: boolean, - excludeStatistics?: string[], - value?: string - ): StatisticItem[] => { - if (!statisticIds.length) { - return [ - { - id: "", - label: "", - primary: this.hass.localize( - "ui.components.statistic-picker.no_statistics" - ), - }, - ]; - } - - if (includeStatisticsUnitOfMeasurement) { - const includeUnits: (string | null)[] = ensureArray( - includeStatisticsUnitOfMeasurement - ); - statisticIds = statisticIds.filter((meta) => - includeUnits.includes(meta.statistics_unit_of_measurement) - ); - } - if (includeUnitClass) { - const includeUnitClasses: (string | null)[] = - ensureArray(includeUnitClass); - statisticIds = statisticIds.filter((meta) => - includeUnitClasses.includes(meta.unit_class) - ); - } - if (includeDeviceClass) { - const includeDeviceClasses: (string | null)[] = - ensureArray(includeDeviceClass); - statisticIds = statisticIds.filter((meta) => { - const stateObj = this.hass.states[meta.statistic_id]; - if (!stateObj) { - return true; - } - return includeDeviceClasses.includes( - stateObj.attributes.device_class || "" - ); - }); - } - - const isRTL = computeRTL(this.hass); - - const output: StatisticItem[] = []; - statisticIds.forEach((meta) => { - if ( - excludeStatistics && - meta.statistic_id !== value && - excludeStatistics.includes(meta.statistic_id) - ) { - return; - } - const stateObj = this.hass.states[meta.statistic_id]; - - if (!stateObj) { - if (!entitiesOnly) { - const id = meta.statistic_id; - const label = getStatisticLabel(this.hass, meta.statistic_id, meta); - const type = - meta.statistic_id.includes(":") && - !meta.statistic_id.includes(".") - ? "external" - : "no_state"; - - if (type === "no_state") { - output.push({ - id, - primary: label, - secondary: this.hass.localize( - "ui.components.statistic-picker.no_state" - ), - label: "", - type, - sorting_label: label, - search_labels: [label, id], - icon_path: mdiShape, - }); - } else if (type === "external") { - const domain = id.split(":")[0]; - const domainName = domainToName(this.hass.localize, domain); - output.push({ - id, - statistic_id: id, - primary: label, - secondary: domainName, - label: "", - type, - sorting_label: label, - search_labels: [label, domainName, id], - icon_path: mdiChartLine, - }); - } - } - return; - } - const id = meta.statistic_id; - - const { area, device } = getEntityContext(stateObj, hass); - - const friendlyName = computeStateName(stateObj); // Keep this for search - const entityName = computeEntityName(stateObj, hass); - const deviceName = device ? computeDeviceName(device) : undefined; - const areaName = area ? computeAreaName(area) : undefined; - - const primary = entityName || deviceName || id; - const secondary = [areaName, entityName ? deviceName : undefined] - .filter(Boolean) - .join(isRTL ? " ◂ " : " ▸ "); - - output.push({ - id, - statistic_id: id, - label: "", - primary, - secondary, - stateObj: stateObj, - type: "entity", - sorting_label: [deviceName, entityName].join("_"), - search_labels: [ - entityName, - deviceName, - areaName, - friendlyName, - id, - ].filter(Boolean) as string[], - }); - }); - - if (!output.length) { - return [ - { - id: "", - primary: this.hass.localize( - "ui.components.statistic-picker.no_match" - ), - label: "", - }, - ]; - } - - if (output.length > 1) { - output.sort((a, b) => { - const aPrefix = TYPE_ORDER.indexOf(a.type || "no_state"); - const bPrefix = TYPE_ORDER.indexOf(b.type || "no_state"); - - return caseInsensitiveStringCompare( - `${aPrefix}_${a.sorting_label || ""}`, - `${bPrefix}_${b.sorting_label || ""}`, - this.hass.locale.language - ); - }); - } - - output.push({ - id: MISSING_ID, - primary: this.hass.localize( - "ui.components.statistic-picker.missing_entity" - ), - label: "", - icon_path: mdiHelpCircle, - }); - - return output; - } - ); - - public async open() { - await this.updateComplete; - await this.comboBox?.open(); - } - - public async focus() { - await this.updateComplete; - await this.comboBox?.focus(); - } - - protected shouldUpdate(changedProps: PropertyValues) { - if ( - changedProps.has("value") || - changedProps.has("label") || - changedProps.has("disabled") - ) { - return true; - } - return !(!changedProps.has("_opened") && this._opened); - } - - public willUpdate(changedProps: PropertyValues) { - if ( - (!this.hasUpdated && !this.statisticIds) || - changedProps.has("statisticTypes") - ) { - this._getStatisticIds(); - } - - if ( - this.statisticIds && - (!this._initialItems || (changedProps.has("_opened") && this._opened)) - ) { - this._items = this._getItems( - this._opened, - this.hass, - this.statisticIds!, - this.includeStatisticsUnitOfMeasurement, - this.includeUnitClass, - this.includeDeviceClass, - this.entitiesOnly, - this.excludeStatistics, - this.value - ); - if (this._initialItems) { - this.comboBox.filteredItems = this._items; - } - this._initialItems = true; - } - } - - protected render(): TemplateResult | typeof nothing { - if (this._items.length === 0) { - return nothing; - } - - return html` - - `; - } - - private async _getStatisticIds() { - this.statisticIds = await getStatisticIds(this.hass, this.statisticTypes); - } - - private get _value() { - return this.value || ""; - } - - private _statisticChanged(ev: ValueChangedEvent) { - ev.stopPropagation(); - let newValue = ev.detail.value; - if (newValue === MISSING_ID) { - newValue = ""; - window.open( - documentationUrl(this.hass, this.helpMissingEntityUrl), - "_blank" - ); - } - - if (newValue !== this._value) { - this._setValue(newValue); - } - } - - private _openedChanged(ev: ValueChangedEvent) { - this._opened = ev.detail.value; - } - - private _fuseIndex = memoizeOne((states: StatisticItem[]) => - Fuse.createIndex(["search_labels"], states) - ); - - private _filterChanged(ev: CustomEvent): void { - if (!this._opened) return; - - const target = ev.target as HaComboBox; - const filterString = ev.detail.value.trim().toLowerCase() as string; - - const index = this._fuseIndex(this._items); - const fuse = new HaFuse(this._items, {}, index); - - const results = fuse.multiTermsSearch(filterString); - - if (results) { - target.filteredItems = results.map((result) => result.item); - } else { - target.filteredItems = this._items; - } - } - - private _setValue(value: string) { - this.value = value; - setTimeout(() => { - fireEvent(this, "value-changed", { value }); - fireEvent(this, "change"); - }, 0); - } -} - -declare global { - interface HTMLElementTagNameMap { - "ha-statistic-combo-box": HaStatisticComboBox; - } -} diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index b3c9145055..3b6e262fc3 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -1,45 +1,45 @@ -import { mdiChartLine, mdiClose, mdiMenuDown, mdiShape } from "@mdi/js"; -import type { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light"; +import { mdiChartLine, mdiHelpCircle, mdiShape } from "@mdi/js"; +import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit"; import type { HassEntity } from "home-assistant-js-websocket"; -import { - css, - html, - LitElement, - nothing, - type CSSResultGroup, - type PropertyValues, -} from "lit"; -import { customElement, property, query, state } from "lit/decorators"; +import { html, LitElement, nothing, type PropertyValues } from "lit"; +import { customElement, property, query } from "lit/decorators"; 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"; import { computeAreaName } from "../../common/entity/compute_area_name"; import { computeDeviceName } from "../../common/entity/compute_device_name"; import { computeEntityName } from "../../common/entity/compute_entity_name"; +import { computeStateName } from "../../common/entity/compute_state_name"; import { getEntityContext } from "../../common/entity/context/get_entity_context"; import { computeRTL } from "../../common/util/compute_rtl"; -import { debounce } from "../../common/util/debounce"; import { domainToName } from "../../data/integration"; import { getStatisticIds, getStatisticLabel, type StatisticsMetaData, } from "../../data/recorder"; -import type { HomeAssistant } from "../../types"; +import type { HomeAssistant, ValueChangedEvent } from "../../types"; +import { documentationUrl } from "../../util/documentation-url"; import "../ha-combo-box-item"; +import "../ha-generic-picker"; +import type { HaGenericPicker } from "../ha-generic-picker"; import "../ha-icon-button"; import "../ha-input-helper-text"; -import type { HaMdListItem } from "../ha-md-list-item"; +import type { PickerComboBoxItem } from "../ha-picker-combo-box"; +import type { PickerValueRenderer } from "../ha-picker-field"; import "../ha-svg-icon"; -import "./ha-statistic-combo-box"; -import type { HaStatisticComboBox } from "./ha-statistic-combo-box"; import "./state-badge"; -interface StatisticItem { - primary: string; - secondary?: string; - iconPath?: string; +const TYPE_ORDER = ["entity", "external", "no_state"] as StatisticItemType[]; + +const MISSING_ID = "___missing-entity___"; + +type StatisticItemType = "entity" | "external" | "no_state"; + +interface StatisticComboBoxItem extends PickerComboBoxItem { + statistic_id?: string; stateObj?: HassEntity; + type?: StatisticItemType; } @customElement("ha-statistic-picker") @@ -70,6 +70,9 @@ export class HaStatisticPicker extends LitElement { @property({ attribute: false, type: Array }) public statisticIds?: StatisticsMetaData[]; + @property({ attribute: false }) public helpMissingEntityUrl = + "/more-info/statistics/"; + /** * Show only statistics natively stored with these units of measurements. * @type {Array} @@ -114,11 +117,7 @@ export class HaStatisticPicker extends LitElement { @property({ attribute: "hide-clear-icon", type: Boolean }) public hideClearIcon = false; - @query("#anchor") private _anchor?: HaMdListItem; - - @query("#input") private _input?: HaStatisticComboBox; - - @state() private _opened = false; + @query("ha-generic-picker") private _picker?: HaGenericPicker; public willUpdate(changedProps: PropertyValues) { if ( @@ -133,6 +132,165 @@ export class HaStatisticPicker extends LitElement { this.statisticIds = await getStatisticIds(this.hass, this.statisticTypes); } + private _getItems = () => + this._getStatisticsItems( + this.hass, + this.statisticIds, + this.includeStatisticsUnitOfMeasurement, + this.includeUnitClass, + this.includeDeviceClass, + this.entitiesOnly, + this.excludeStatistics, + this.value + ); + + private _getAdditionalItems(): StatisticComboBoxItem[] { + return [ + { + id: MISSING_ID, + primary: this.hass.localize( + "ui.components.statistic-picker.missing_entity" + ), + icon_path: mdiHelpCircle, + }, + ]; + } + + private _getStatisticsItems = memoizeOne( + ( + hass: HomeAssistant, + statisticIds?: StatisticsMetaData[], + includeStatisticsUnitOfMeasurement?: string | string[], + includeUnitClass?: string | string[], + includeDeviceClass?: string | string[], + entitiesOnly?: boolean, + excludeStatistics?: string[], + value?: string + ): StatisticComboBoxItem[] => { + if (!statisticIds) { + return []; + } + + if (includeStatisticsUnitOfMeasurement) { + const includeUnits: (string | null)[] = ensureArray( + includeStatisticsUnitOfMeasurement + ); + statisticIds = statisticIds.filter((meta) => + includeUnits.includes(meta.statistics_unit_of_measurement) + ); + } + if (includeUnitClass) { + const includeUnitClasses: (string | null)[] = + ensureArray(includeUnitClass); + statisticIds = statisticIds.filter((meta) => + includeUnitClasses.includes(meta.unit_class) + ); + } + if (includeDeviceClass) { + const includeDeviceClasses: (string | null)[] = + ensureArray(includeDeviceClass); + statisticIds = statisticIds.filter((meta) => { + const stateObj = this.hass.states[meta.statistic_id]; + if (!stateObj) { + return true; + } + return includeDeviceClasses.includes( + stateObj.attributes.device_class || "" + ); + }); + } + + const isRTL = computeRTL(this.hass); + + const output: StatisticComboBoxItem[] = []; + + statisticIds.forEach((meta) => { + if ( + excludeStatistics && + meta.statistic_id !== value && + excludeStatistics.includes(meta.statistic_id) + ) { + return; + } + const stateObj = this.hass.states[meta.statistic_id]; + + if (!stateObj) { + if (!entitiesOnly) { + const id = meta.statistic_id; + const label = getStatisticLabel(this.hass, meta.statistic_id, meta); + const type = + meta.statistic_id.includes(":") && + !meta.statistic_id.includes(".") + ? "external" + : "no_state"; + + const sortingPrefix = `${TYPE_ORDER.indexOf(type)}`; + if (type === "no_state") { + output.push({ + id, + primary: label, + secondary: this.hass.localize( + "ui.components.statistic-picker.no_state" + ), + type, + sorting_label: [sortingPrefix, label].join("_"), + search_labels: [label, id], + icon_path: mdiShape, + }); + } else if (type === "external") { + const domain = id.split(":")[0]; + const domainName = domainToName(this.hass.localize, domain); + output.push({ + id, + statistic_id: id, + primary: label, + secondary: domainName, + type, + sorting_label: [sortingPrefix, label].join("_"), + search_labels: [label, domainName, id], + icon_path: mdiChartLine, + }); + } + } + return; + } + const id = meta.statistic_id; + + const { area, device } = getEntityContext(stateObj, hass); + + const friendlyName = computeStateName(stateObj); // Keep this for search + const entityName = computeEntityName(stateObj, hass); + const deviceName = device ? computeDeviceName(device) : undefined; + const areaName = area ? computeAreaName(area) : undefined; + + const primary = entityName || deviceName || id; + const secondary = [areaName, entityName ? deviceName : undefined] + .filter(Boolean) + .join(isRTL ? " ◂ " : " ▸ "); + + const sortingPrefix = `${TYPE_ORDER.indexOf("entity")}`; + output.push({ + id, + statistic_id: id, + primary, + secondary, + stateObj: stateObj, + type: "entity", + sorting_label: [sortingPrefix, deviceName, entityName].join("_"), + search_labels: [ + entityName, + deviceName, + areaName, + friendlyName, + id, + ].filter(Boolean) as string[], + }); + }); + + return output; + } + ); + private _statisticMetaData = memoizeOne( (statisticId: string, statisticIds: StatisticsMetaData[]) => { if (!statisticIds) { @@ -144,26 +302,11 @@ export class HaStatisticPicker extends LitElement { } ); - private _renderContent() { - const statisticId = this.value || ""; - - if (!this.value) { - return html` - ${this.placeholder ?? - this.hass.localize( - "ui.components.statistic-picker.placeholder" - )} - - `; - } + private _valueRenderer: PickerValueRenderer = (value) => { + const statisticId = value; const item = this._computeItem(statisticId); - const showClearIcon = - !this.required && !this.disabled && !this.hideClearIcon; - return html` ${item.stateObj ? html` @@ -173,29 +316,19 @@ export class HaStatisticPicker extends LitElement { slot="start" > ` - : item.iconPath - ? html`` + : item.icon_path + ? html` + + ` : nothing} ${item.primary} ${item.secondary ? html`${item.secondary}` : nothing} - ${showClearIcon - ? html`` - : nothing} - `; - } + }; - private _computeItem(statisticId: string): StatisticItem { + private _computeItem(statisticId: string): StatisticComboBoxItem { const stateObj = this.hass.states[statisticId]; if (stateObj) { @@ -211,11 +344,24 @@ export class HaStatisticPicker extends LitElement { const secondary = [areaName, entityName ? deviceName : undefined] .filter(Boolean) .join(isRTL ? " ◂ " : " ▸ "); + const friendlyName = computeStateName(stateObj); // Keep this for search + const sortingPrefix = `${TYPE_ORDER.indexOf("entity")}`; return { + id: statisticId, + statistic_id: statisticId, primary, secondary, - stateObj, + stateObj: stateObj, + type: "entity", + sorting_label: [sortingPrefix, deviceName, entityName].join("_"), + search_labels: [ + entityName, + deviceName, + areaName, + friendlyName, + statisticId, + ].filter(Boolean) as string[], }; } @@ -230,175 +376,124 @@ export class HaStatisticPicker extends LitElement { : "no_state"; if (type === "external") { + const sortingPrefix = `${TYPE_ORDER.indexOf("external")}`; const label = getStatisticLabel(this.hass, statisticId, statistic); const domain = statisticId.split(":")[0]; const domainName = domainToName(this.hass.localize, domain); return { + id: statisticId, + statistic_id: statisticId, primary: label, secondary: domainName, - iconPath: mdiChartLine, + type: "external", + sorting_label: [sortingPrefix, label].join("_"), + search_labels: [label, domainName, statisticId], + icon_path: mdiChartLine, }; } } + const sortingPrefix = `${TYPE_ORDER.indexOf("external")}`; + const label = getStatisticLabel(this.hass, statisticId, statistic); + return { - primary: statisticId, - iconPath: mdiShape, + id: statisticId, + primary: label, + secondary: this.hass.localize("ui.components.statistic-picker.no_state"), + type: "no_state", + sorting_label: [sortingPrefix, label].join("_"), + search_labels: [label, statisticId], + icon_path: mdiShape, }; } - protected render() { + private _rowRenderer: ComboBoxLitRenderer = ( + item, + { index } + ) => { + const showEntityId = this.hass.userData?.showEntityIdPicker; return html` - ${this.label ? html`` : nothing} -
- ${!this._opened + + ${item.icon_path ? html` - - ${this._renderContent()} - + ` - : html` - - `} - ${this._renderHelper()} -
+ : item.stateObj + ? html` + + ` + : nothing} + ${item.primary} + ${item.secondary || item.type + ? html`${item.secondary} - ${item.type}` + : nothing} + ${item.statistic_id && showEntityId + ? html` + ${item.statistic_id} + ` + : nothing} + + `; + }; + + protected render() { + const placeholder = + this.placeholder ?? + this.hass.localize("ui.components.statistic-picker.placeholder"); + const notFoundLabel = this.hass.localize( + "ui.components.statistic-picker.no_match" + ); + + return html` + + `; } - private _renderHelper() { - return this.helper - ? html`${this.helper}` - : nothing; - } + private _valueChanged(ev: ValueChangedEvent) { + ev.stopPropagation(); + const value = ev.detail.value; - private _clear(e) { - e.stopPropagation(); - this.value = undefined; - fireEvent(this, "value-changed", { value: undefined }); - fireEvent(this, "change"); - } - - private async _showPicker() { - if (this.disabled) { + if (value === MISSING_ID) { + window.open( + documentationUrl(this.hass, this.helpMissingEntityUrl), + "_blank" + ); return; } - this._opened = true; + + this.value = value; + fireEvent(this, "value-changed", { value }); + } + + public async open() { await this.updateComplete; - this._input?.focus(); - this._input?.open(); - } - - // Multiple calls to _openedChanged can be triggered in quick succession - // when the menu is opened - private _debounceOpenedChanged = debounce( - (ev) => this._openedChanged(ev), - 10 - ); - - private async _openedChanged(ev: ComboBoxLightOpenedChangedEvent) { - const opened = ev.detail.value; - if (this._opened && !opened) { - this._opened = false; - await this.updateComplete; - this._anchor?.focus(); - } - } - - static get styles(): CSSResultGroup { - return [ - css` - .container { - position: relative; - display: block; - } - ha-combo-box-item { - background-color: var(--mdc-text-field-fill-color, whitesmoke); - border-radius: 4px; - border-end-end-radius: 0; - border-end-start-radius: 0; - --md-list-item-one-line-container-height: 56px; - --md-list-item-two-line-container-height: 56px; - --md-list-item-top-space: 8px; - --md-list-item-bottom-space: 8px; - --md-list-item-leading-space: 8px; - --md-list-item-trailing-space: 8px; - --ha-md-list-item-gap: 8px; - /* Remove the default focus ring */ - --md-focus-ring-width: 0px; - --md-focus-ring-duration: 0s; - } - - /* Add Similar focus style as the text field */ - ha-combo-box-item:after { - display: block; - content: ""; - position: absolute; - pointer-events: none; - bottom: 0; - left: 0; - right: 0; - height: 1px; - width: 100%; - background-color: var( - --mdc-text-field-idle-line-color, - rgba(0, 0, 0, 0.42) - ); - transform: - height 180ms ease-in-out, - background-color 180ms ease-in-out; - } - - ha-combo-box-item:focus:after { - height: 2px; - background-color: var(--mdc-theme-primary); - } - - ha-combo-box-item ha-svg-icon[slot="start"] { - margin: 0 4px; - } - .clear { - margin: 0 -8px; - --mdc-icon-button-size: 32px; - --mdc-icon-size: 20px; - } - .edit { - --mdc-icon-size: 20px; - width: 32px; - } - label { - display: block; - margin: 0 0 8px; - } - .placeholder { - color: var(--secondary-text-color); - padding: 0 8px; - } - `, - ]; + await this._picker?.open(); } }