From c9f96bbe69129221f3c2e712da67eb7beb4ba01d Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 27 Feb 2026 16:23:58 +0100 Subject: [PATCH] Add render icon property to ha-control-select-menu (#29881) --- src/components/ha-control-select-menu.ts | 48 ++++++---------- .../more-info/controls/more-info-climate.ts | 57 ++++++++++++------- .../more-info/controls/more-info-fan.ts | 32 ++++++----- .../controls/more-info-humidifier.ts | 16 +++--- .../more-info/controls/more-info-light.ts | 16 +++--- .../controls/more-info-water_heater.ts | 14 +++-- .../hui-climate-fan-modes-card-feature.ts | 18 +++--- .../hui-climate-preset-modes-card-feature.ts | 18 +++--- ...ate-swing-horizontal-modes-card-feature.ts | 18 +++--- .../hui-climate-swing-modes-card-feature.ts | 18 +++--- .../hui-fan-preset-modes-card-feature.ts | 18 +++--- .../hui-humidifier-modes-card-feature.ts | 18 +++--- ...ter-heater-operation-modes-card-feature.ts | 18 +++--- 13 files changed, 168 insertions(+), 141 deletions(-) diff --git a/src/components/ha-control-select-menu.ts b/src/components/ha-control-select-menu.ts index 3dc78ef957..7659675391 100644 --- a/src/components/ha-control-select-menu.ts +++ b/src/components/ha-control-select-menu.ts @@ -1,11 +1,9 @@ import { mdiMenuDown } from "@mdi/js"; -import type { HassEntity } from "home-assistant-js-websocket"; +import type { TemplateResult } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, query } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; -import type { HomeAssistant } from "../types"; -import "./ha-attribute-icon"; import "./ha-dropdown"; import "./ha-dropdown-item"; import "./ha-icon"; @@ -16,17 +14,10 @@ export interface SelectOption { value: string; iconPath?: string; icon?: string; - attributeIcon?: { - stateObj: HassEntity; - attribute: string; - attributeValue?: string; - }; } @customElement("ha-control-select-menu") export class HaControlSelectMenu extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - @property({ type: Boolean, attribute: "show-arrow" }) public showArrow = false; @@ -47,6 +38,9 @@ export class HaControlSelectMenu extends LitElement { @property({ attribute: false }) public options: SelectOption[] = []; + @property({ attribute: false }) + public renderIcon?: (value: string) => TemplateResult<1> | typeof nothing; + @query("button") private _triggerButton!: HTMLButtonElement; public override render() { @@ -94,14 +88,8 @@ export class HaControlSelectMenu extends LitElement { ? html`` : option.icon ? html`` - : option.attributeIcon - ? html`` + : this.renderIcon + ? html`${this.renderIcon(option.value)}` : nothing} ${option.label}`; @@ -119,24 +107,20 @@ export class HaControlSelectMenu extends LitElement { } private _renderIcon() { - const { iconPath, icon, attributeIcon } = - this.getValueObject(this.options, this.value) ?? {}; + const value = this.getValueObject(this.options, this.value); const defaultIcon = this.querySelector("[slot='icon']"); return html`
- ${iconPath - ? html`` - : icon - ? html`` - : attributeIcon - ? html`` + ${value?.iconPath + ? html`` + : value?.icon + ? html`` + : this.renderIcon && this.value + ? this.renderIcon(this.value) : defaultIcon ? html`` : nothing} diff --git a/src/dialogs/more-info/controls/more-info-climate.ts b/src/dialogs/more-info/controls/more-info-climate.ts index 79a153e773..01552bc7fd 100644 --- a/src/dialogs/more-info/controls/more-info-climate.ts +++ b/src/dialogs/more-info/controls/more-info-climate.ts @@ -9,6 +9,7 @@ import type { CSSResultGroup, PropertyValues } from "lit"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { supportsFeature } from "../../../common/entity/supports-feature"; +import "../../../components/ha-attribute-icon"; import "../../../components/ha-control-select-menu"; import "../../../components/ha-icon-button-group"; import "../../../components/ha-icon-button-toggle"; @@ -39,6 +40,38 @@ class MoreInfoClimate extends LitElement { @state() private _mainControl: MainControl = "temperature"; + private _renderPresetModeIcon = (value: string) => + html``; + + private _renderFanModeIcon = (value: string) => + html``; + + private _renderSwingModeIcon = (value: string) => + html``; + + private _renderSwingHorizontalModeIcon = (value: string) => + html``; + protected willUpdate(changedProps: PropertyValues): void { if ( changedProps.has("stateObj") && @@ -205,12 +238,8 @@ class MoreInfoClimate extends LitElement { "preset_mode", mode ), - attributeIcon: { - stateObj, - attribute: "preset_mode", - attributeValue: mode, - }, }))} + .renderIcon=${this._renderPresetModeIcon} > @@ -234,12 +263,8 @@ class MoreInfoClimate extends LitElement { "fan_mode", mode ), - attributeIcon: { - stateObj, - attribute: "fan_mode", - attributeValue: mode, - }, }))} + .renderIcon=${this._renderFanModeIcon} > @@ -263,12 +288,8 @@ class MoreInfoClimate extends LitElement { "swing_mode", mode ), - attributeIcon: { - stateObj, - attribute: "swing_mode", - attributeValue: mode, - }, }))} + .renderIcon=${this._renderSwingModeIcon} > + html``; + + private _renderDirectionIcon = (value: string) => + html``; + private _toggle = () => { const service = this.stateObj?.state === "on" ? "turn_off" : "turn_on"; forwardHaptic(this, "light"); @@ -192,15 +208,9 @@ class MoreInfoFan extends LitElement { "preset_mode", mode ), - attributeIcon: this.stateObj - ? { - stateObj: this.stateObj, - attribute: "preset_mode", - attributeValue: mode, - } - : undefined, }) )} + .renderIcon=${this._renderPresetModeIcon} > @@ -226,14 +236,8 @@ class MoreInfoFan extends LitElement { direction ) : direction, - attributeIcon: this.stateObj - ? { - stateObj: this.stateObj, - attribute: "direction", - attributeValue: direction, - } - : undefined, }))} + .renderIcon=${this._renderDirectionIcon} > + html``; + protected willUpdate(changedProps: PropertyValues): void { super.willUpdate(changedProps); if (changedProps.has("stateObj")) { @@ -106,14 +114,8 @@ class MoreInfoHumidifier extends LitElement { mode ) : mode, - attributeIcon: stateObj - ? { - stateObj, - attribute: "mode", - attributeValue: mode, - } - : undefined, })) || []} + .renderIcon=${this._renderModeIcon} > diff --git a/src/dialogs/more-info/controls/more-info-light.ts b/src/dialogs/more-info/controls/more-info-light.ts index 9379c86a24..3035829276 100644 --- a/src/dialogs/more-info/controls/more-info-light.ts +++ b/src/dialogs/more-info/controls/more-info-light.ts @@ -55,6 +55,14 @@ class MoreInfoLight extends LitElement { @state() private _mainControl: MainControl = "brightness"; + private _renderEffectIcon = (value: string) => + html``; + protected updated(changedProps: PropertyValues): void { if (changedProps.has("stateObj")) { this._effect = this.stateObj?.attributes.effect; @@ -271,15 +279,9 @@ class MoreInfoLight extends LitElement { effect ) : effect, - attributeIcon: this.stateObj - ? { - stateObj: this.stateObj, - attribute: "effect", - attributeValue: effect, - } - : undefined, }) )} + .renderIcon=${this._renderEffectIcon} > diff --git a/src/dialogs/more-info/controls/more-info-water_heater.ts b/src/dialogs/more-info/controls/more-info-water_heater.ts index d9d1a0543e..09ba21a381 100644 --- a/src/dialogs/more-info/controls/more-info-water_heater.ts +++ b/src/dialogs/more-info/controls/more-info-water_heater.ts @@ -24,6 +24,14 @@ class MoreInfoWaterHeater extends LitElement { @property({ attribute: false }) public stateObj?: WaterHeaterEntity; + private _renderOperationModeIcon = (value: string) => + html``; + protected render() { if (!this.stateObj) { return nothing; @@ -85,12 +93,8 @@ class MoreInfoWaterHeater extends LitElement { .map((mode) => ({ value: mode, label: this.hass.formatEntityState(stateObj, mode), - attributeIcon: { - stateObj, - attribute: "operation_mode", - attributeValue: mode, - }, }))} + .renderIcon=${this._renderOperationModeIcon} > diff --git a/src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts index 1a7259f12f..fc03ed3fbd 100644 --- a/src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts @@ -49,6 +49,14 @@ class HuiClimateFanModesCardFeature @state() _currentFanMode?: string; + private _renderFanModeIcon = (value: string) => + html``; + private get _stateObj() { if (!this.hass || !this.context || !this.context.entity_id) { return undefined; @@ -175,14 +183,8 @@ class HuiClimateFanModesCardFeature .value=${this._currentFanMode} .disabled=${this._stateObj.state === UNAVAILABLE} @wa-select=${this._valueChanged} - .options=${options.map((option) => ({ - ...option, - attributeIcon: { - stateObj: stateObj, - attribute: "fan_mode", - attributeValue: option.value, - }, - }))} + .options=${options} + .renderIcon=${this._renderFanModeIcon} > `; diff --git a/src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts index d13941c40d..df92172317 100644 --- a/src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts @@ -48,6 +48,14 @@ class HuiClimatePresetModesCardFeature @state() _currentPresetMode?: string; + private _renderPresetModeIcon = (value: string) => + html``; + private get _stateObj() { if (!this.hass || !this.context || !this.context.entity_id) { return undefined; @@ -179,14 +187,8 @@ class HuiClimatePresetModesCardFeature .value=${this._currentPresetMode} .disabled=${this._stateObj.state === UNAVAILABLE} @wa-select=${this._valueChanged} - .options=${options.map((option) => ({ - ...option, - attributeIcon: { - stateObj: stateObj, - attribute: "preset_mode", - attributeValue: option.value, - }, - }))} + .options=${options} + .renderIcon=${this._renderPresetModeIcon} > diff --git a/src/panels/lovelace/card-features/hui-climate-swing-horizontal-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-climate-swing-horizontal-modes-card-feature.ts index cfc0386575..946dd32f95 100644 --- a/src/panels/lovelace/card-features/hui-climate-swing-horizontal-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-climate-swing-horizontal-modes-card-feature.ts @@ -48,6 +48,14 @@ class HuiClimateSwingHorizontalModesCardFeature @state() _currentSwingHorizontalMode?: string; + private _renderSwingHorizontalModeIcon = (value: string) => + html``; + private get _stateObj() { if (!this.hass || !this.context || !this.context.entity_id) { return undefined; @@ -187,14 +195,8 @@ class HuiClimateSwingHorizontalModesCardFeature .value=${this._currentSwingHorizontalMode} .disabled=${this._stateObj.state === UNAVAILABLE} @wa-select=${this._valueChanged} - .options=${options.map((option) => ({ - ...option, - attributeIcon: { - stateObj: stateObj, - attribute: "swing_horizontal_mode", - attributeValue: option.value, - }, - }))} + .options=${options} + .renderIcon=${this._renderSwingHorizontalModeIcon} > diff --git a/src/panels/lovelace/card-features/hui-climate-swing-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-climate-swing-modes-card-feature.ts index 5cc902591c..4b2c9d5ded 100644 --- a/src/panels/lovelace/card-features/hui-climate-swing-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-climate-swing-modes-card-feature.ts @@ -48,6 +48,14 @@ class HuiClimateSwingModesCardFeature @state() _currentSwingMode?: string; + private _renderSwingModeIcon = (value: string) => + html``; + private get _stateObj() { if (!this.hass || !this.context || !this.context.entity_id) { return undefined; @@ -179,14 +187,8 @@ class HuiClimateSwingModesCardFeature .value=${this._currentSwingMode} .disabled=${this._stateObj.state === UNAVAILABLE} @wa-select=${this._valueChanged} - .options=${options.map((option) => ({ - ...option, - attributeIcon: { - stateObj, - attribute: "swing_mode", - attributeValue: option.value, - }, - }))} + .options=${options} + .renderIcon=${this._renderSwingModeIcon} > `; diff --git a/src/panels/lovelace/card-features/hui-fan-preset-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-fan-preset-modes-card-feature.ts index 2f71cadec3..b63acb8aae 100644 --- a/src/panels/lovelace/card-features/hui-fan-preset-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-fan-preset-modes-card-feature.ts @@ -47,6 +47,14 @@ class HuiFanPresetModesCardFeature @state() _currentPresetMode?: string; + private _renderPresetModeIcon = (value: string) => + html``; + private get _stateObj() { if (!this.hass || !this.context || !this.context.entity_id) { return undefined; @@ -173,14 +181,8 @@ class HuiFanPresetModesCardFeature .value=${this._currentPresetMode} .disabled=${this._stateObj.state === UNAVAILABLE} @wa-select=${this._valueChanged} - .options=${options.map((option) => ({ - ...option, - attributeIcon: { - stateObj: stateObj, - attribute: "preset_mode", - attributeValue: option.value, - }, - }))} + .options=${options} + .renderIcon=${this._renderPresetModeIcon} > diff --git a/src/panels/lovelace/card-features/hui-humidifier-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-humidifier-modes-card-feature.ts index 07a10e7848..f65b7582b9 100644 --- a/src/panels/lovelace/card-features/hui-humidifier-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-humidifier-modes-card-feature.ts @@ -48,6 +48,14 @@ class HuiHumidifierModesCardFeature @state() _currentMode?: string; + private _renderModeIcon = (value: string) => + html``; + private get _stateObj() { if (!this.hass || !this.context || !this.context.entity_id) { return undefined; @@ -174,14 +182,8 @@ class HuiHumidifierModesCardFeature .value=${this._currentMode} .disabled=${this._stateObj.state === UNAVAILABLE} @wa-select=${this._valueChanged} - .options=${options.map((option) => ({ - ...option, - attributeIcon: { - stateObj, - attribute: "mode", - attributeValue: option.value, - }, - }))} + .options=${options} + .renderIcon=${this._renderModeIcon} > diff --git a/src/panels/lovelace/card-features/hui-water-heater-operation-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-water-heater-operation-modes-card-feature.ts index 8a9f554b88..7b007ab28e 100644 --- a/src/panels/lovelace/card-features/hui-water-heater-operation-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-water-heater-operation-modes-card-feature.ts @@ -49,6 +49,14 @@ class HuiWaterHeaterOperationModeCardFeature @state() _currentOperationMode?: OperationMode; + private _renderOperationModeIcon = (value: string) => + html``; + private get _stateObj() { if (!this.hass || !this.context || !this.context.entity_id) { return undefined; @@ -153,14 +161,8 @@ class HuiWaterHeaterOperationModeCardFeature .value=${this._currentOperationMode} .disabled=${this._stateObj.state === UNAVAILABLE} @wa-select=${this._valueChanged} - .options=${options.map((option) => ({ - ...option, - attributeIcon: { - stateObj: this._stateObj, - attribute: "operation_mode", - attributeValue: option.value, - }, - }))} + .options=${options} + .renderIcon=${this._renderOperationModeIcon} >