diff --git a/gallery/src/pages/misc/entity-state.ts b/gallery/src/pages/misc/entity-state.ts index 1ab1d7df15..857e432a28 100644 --- a/gallery/src/pages/misc/entity-state.ts +++ b/gallery/src/pages/misc/entity-state.ts @@ -344,6 +344,7 @@ export class DemoEntityState extends LitElement { title: "Icon", template: (entry) => html` diff --git a/src/common/entity/attribute_icon_path.ts b/src/common/entity/attribute_icon_path.ts new file mode 100644 index 0000000000..aa42803887 --- /dev/null +++ b/src/common/entity/attribute_icon_path.ts @@ -0,0 +1,35 @@ +/** Return an icon representing a attribute. */ +import { HassEntity } from "home-assistant-js-websocket"; +import { + computeFanModeIcon, + computeHvacModeIcon, + computePresetModeIcon, + computeSwingModeIcon, +} from "../../data/climate"; +import { computeDomain } from "./compute_domain"; + +const iconGenerators: Record string>> = { + climate: { + fan_mode: computeFanModeIcon, + hvac_mode: computeHvacModeIcon, + preset_mode: computePresetModeIcon, + swing_mode: computeSwingModeIcon, + }, +}; + +export const attributeIconPath = ( + state: HassEntity | undefined, + attribute: string, + attributeValue?: string +) => { + if (!state) { + return undefined; + } + const domain = computeDomain(state.entity_id); + if (iconGenerators[domain]?.[attribute]) { + return iconGenerators[domain]?.[attribute]( + attributeValue || state.attributes[attribute] + ); + } + return undefined; +}; diff --git a/src/common/entity/state_icon_path.ts b/src/common/entity/state_icon_path.ts index 24d842caf6..ac8e2c47ad 100644 --- a/src/common/entity/state_icon_path.ts +++ b/src/common/entity/state_icon_path.ts @@ -4,7 +4,7 @@ import { DEFAULT_DOMAIN_ICON } from "../const"; import { computeDomain } from "./compute_domain"; import { domainIcon } from "./domain_icon"; -export const stateIconPath = (state?: HassEntity) => { +export const stateIconPath = (state: HassEntity | undefined) => { if (!state) { return DEFAULT_DOMAIN_ICON; } diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index ac2f1f9a17..f6bad8a965 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -25,16 +25,6 @@ interface HassEntityWithCachedName extends HassEntity, ScorableTextItem { export type HaEntityPickerEntityFilterFunc = (entity: HassEntity) => boolean; -// eslint-disable-next-line lit/prefer-static-styles -const rowRenderer: ComboBoxLitRenderer = (item) => - html` - ${item.state - ? html`` - : ""} - ${item.friendly_name} - ${item.entity_id} - `; - @customElement("ha-entity-picker") export class HaEntityPicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -127,6 +117,21 @@ export class HaEntityPicker extends LitElement { private _states: HassEntityWithCachedName[] = []; + private _rowRenderer: ComboBoxLitRenderer = ( + item + ) => + html` + ${item.state + ? html`` + : ""} + ${item.friendly_name} + ${item.entity_id} + `; + private _getStates = memoizeOne( ( _opened: boolean, @@ -326,7 +331,7 @@ export class HaEntityPicker extends LitElement { .helper=${this.helper} .allowCustomValue=${this.allowCustomEntity} .filteredItems=${this._states} - .renderer=${rowRenderer} + .renderer=${this._rowRenderer} .required=${this.required} .disabled=${this.disabled} @opened-changed=${this._openedChanged} diff --git a/src/components/entity/ha-state-label-badge.ts b/src/components/entity/ha-state-label-badge.ts index 9460c68147..4fe1a4d60c 100644 --- a/src/components/entity/ha-state-label-badge.ts +++ b/src/components/entity/ha-state-label-badge.ts @@ -140,7 +140,8 @@ export class HaStateLabelBadge extends LitElement { ${!image && showIcon ? html`` : ""} ${value && !image && !showIcon diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index f3eabb2b32..a592937d37 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -105,6 +105,7 @@ export class HaStatisticPicker extends LitElement { ? html`` : ""} ${item.name} diff --git a/src/components/entity/state-badge.ts b/src/components/entity/state-badge.ts index ecf012ebca..75d077ed51 100644 --- a/src/components/entity/state-badge.ts +++ b/src/components/entity/state-badge.ts @@ -1,11 +1,11 @@ import { mdiAlert } from "@mdi/js"; import type { HassEntity } from "home-assistant-js-websocket"; import { - css, CSSResultGroup, - html, LitElement, PropertyValues, + css, + html, nothing, } from "lit"; import { property, state } from "lit/decorators"; @@ -14,8 +14,8 @@ import { styleMap } from "lit/directives/style-map"; import { computeDomain } from "../../common/entity/compute_domain"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { - stateColorCss, stateColorBrightness, + stateColorCss, } from "../../common/entity/state_color"; import { iconColorCSS } from "../../common/style/icon_color_css"; import { cameraUrlWithWidthHeight } from "../../data/camera"; @@ -90,11 +90,12 @@ export class StateBadge extends LitElement { const domain = stateObj ? computeStateDomain(stateObj) : undefined; return html``; } diff --git a/src/components/entity/state-info.ts b/src/components/entity/state-info.ts index 5e1564ff4b..db631e4496 100644 --- a/src/components/entity/state-info.ts +++ b/src/components/entity/state-info.ts @@ -29,6 +29,7 @@ class StateInfo extends LitElement { const name = computeStateName(this.stateObj); return html``; + } + + if (!this.stateObj || !this.attribute) { + return nothing; + } + + if (!this.hass) { + return this._renderFallback(); + } + + const icon = attributeIcon( + this.hass, + this.stateObj, + this.attribute, + this.attributeValue + ).then((icn) => { + if (icn) { + return html``; + } + return this._renderFallback(); + }); + + return html`${until(icon)}`; + } + + private _renderFallback() { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-attribute-icon": HaAttributeIcon; + } +} diff --git a/src/components/ha-control-select-menu.ts b/src/components/ha-control-select-menu.ts index d3d00b4688..c26d1cee5b 100644 --- a/src/components/ha-control-select-menu.ts +++ b/src/components/ha-control-select-menu.ts @@ -126,9 +126,9 @@ export class HaControlSelectMenu extends SelectBase { return html`
- ${icon && "path" in icon + ${icon && icon.localName === "ha-svg-icon" && "path" in icon ? html`` - : icon && "icon" in icon + : icon && icon.localName === "ha-icon" && "icon" in icon ? html`` : html``}
diff --git a/src/components/ha-related-items.ts b/src/components/ha-related-items.ts index b843cd2ba9..be59a28b88 100644 --- a/src/components/ha-related-items.ts +++ b/src/components/ha-related-items.ts @@ -246,7 +246,8 @@ export class HaRelatedItems extends LitElement { graphic="icon" > ${entity.attributes.friendly_name || entity.entity_id} @@ -270,7 +271,8 @@ export class HaRelatedItems extends LitElement { graphic="icon" > ${group.attributes.friendly_name || group.entity_id} @@ -294,7 +296,8 @@ export class HaRelatedItems extends LitElement { graphic="icon" > ${scene.attributes.friendly_name || scene.entity_id} @@ -349,7 +352,8 @@ export class HaRelatedItems extends LitElement { graphic="icon" > ${automation.attributes.friendly_name || @@ -403,7 +407,8 @@ export class HaRelatedItems extends LitElement { graphic="icon" > ${script.attributes.friendly_name || script.entity_id} diff --git a/src/components/ha-selector/ha-selector-icon.ts b/src/components/ha-selector/ha-selector-icon.ts index 7f491a93f2..148bd08dfd 100644 --- a/src/components/ha-selector/ha-selector-icon.ts +++ b/src/components/ha-selector/ha-selector-icon.ts @@ -1,8 +1,10 @@ import { html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; +import { until } from "lit/directives/until"; import { fireEvent } from "../../common/dom/fire_event"; import { computeDomain } from "../../common/entity/compute_domain"; import { domainIcon } from "../../common/entity/domain_icon"; +import { entityIcon } from "../../data/icons"; import { IconSelector } from "../../data/selector"; import { HomeAssistant } from "../../types"; import "../ha-icon-picker"; @@ -33,7 +35,10 @@ export class HaIconSelector extends LitElement { const stateObj = iconEntity ? this.hass.states[iconEntity] : undefined; const placeholder = - this.selector.icon?.placeholder || stateObj?.attributes.icon; + this.selector.icon?.placeholder || + stateObj?.attributes.icon || + (stateObj && until(entityIcon(this.hass, stateObj))); + const fallbackPath = !placeholder && stateObj ? domainIcon(computeDomain(iconEntity!), stateObj) diff --git a/src/components/ha-state-icon.ts b/src/components/ha-state-icon.ts index eace7706bc..5ec0a4a95a 100644 --- a/src/components/ha-state-icon.ts +++ b/src/components/ha-state-icon.ts @@ -1,25 +1,49 @@ import { HassEntity } from "home-assistant-js-websocket"; -import { html, LitElement, TemplateResult } from "lit"; +import { html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators"; +import { until } from "lit/directives/until"; import { stateIconPath } from "../common/entity/state_icon_path"; +import { entityIcon } from "../data/icons"; +import { HomeAssistant } from "../types"; import "./ha-icon"; import "./ha-svg-icon"; @customElement("ha-state-icon") export class HaStateIcon extends LitElement { - @property({ attribute: false }) public state?: HassEntity; + @property({ attribute: false }) public hass?: HomeAssistant; + + @property({ attribute: false }) public stateObj?: HassEntity; @property() public icon?: string; - protected render(): TemplateResult { - if (this.icon || this.state?.attributes.icon) { + protected render() { + if (this.icon || this.stateObj?.attributes.icon) { return html``; } - return html``; + if (!this.stateObj) { + return nothing; + } + if (!this.hass) { + return this._renderFallback(); + } + const icon = entityIcon(this.hass, this.stateObj).then((icn) => { + if (icn) { + return html``; + } + return this._renderFallback(); + }); + return html`${until(icon)}`; + } + + private _renderFallback() { + return html``; } } + declare global { interface HTMLElementTagNameMap { "ha-state-icon": HaStateIcon; diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts index 549fa02320..e6a274ed19 100644 --- a/src/components/ha-target-picker.ts +++ b/src/components/ha-target-picker.ts @@ -224,7 +224,8 @@ export class HaTargetPicker extends LitElement { ${entityState ? html`` : ""} diff --git a/src/data/context.ts b/src/data/context.ts index 7fbff9fd06..b5d914522c 100644 --- a/src/data/context.ts +++ b/src/data/context.ts @@ -3,6 +3,8 @@ import { HassConfig } from "home-assistant-js-websocket"; import { HomeAssistant } from "../types"; import { EntityRegistryEntry } from "./entity_registry"; +export const connectionContext = + createContext("connection"); export const statesContext = createContext("states"); export const entitiesContext = createContext("entities"); diff --git a/src/data/icons.ts b/src/data/icons.ts new file mode 100644 index 0000000000..dfa090207e --- /dev/null +++ b/src/data/icons.ts @@ -0,0 +1,133 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import { computeStateDomain } from "../common/entity/compute_state_domain"; +import { HomeAssistant } from "../types"; + +const resources: Record = { + entity: {}, + entity_component: undefined, +}; + +interface IconResources { + resources: Record>; +} + +interface PlatformIcons { + [domain: string]: { + [translation_key: string]: { + state: Record; + state_attributes: Record }>; + default: string; + }; + }; +} + +interface ComponentIcons { + [device_class: string]: { + state: Record; + state_attributes: Record }>; + default: string; + }; +} + +export type IconCategory = "entity" | "entity_component"; + +export const getHassIcons = async ( + hass: HomeAssistant, + category: IconCategory, + integration?: string +): Promise => + hass.callWS<{ resources: Record }>({ + type: "frontend/get_icons", + category, + integration, + }); + +export const getPlatformIcons = async ( + hass: HomeAssistant, + integration: string, + force = false +): Promise => { + if (!force && integration && integration in resources.entity) { + return resources.entity[integration]; + } + const result = getHassIcons(hass, "entity", integration); + resources.entity[integration] = result.then( + (res) => res?.resources[integration] + ); + return resources.entity[integration]; +}; + +export const getComponentIcons = async ( + hass: HomeAssistant, + domain: string, + force = false +): Promise => { + if (!force && resources.entity_component) { + return resources.entity_component.then((res) => res[domain]); + } + resources.entity_component = getHassIcons(hass, "entity_component").then( + (result) => result.resources + ); + return resources.entity_component.then((res) => res[domain]); +}; + +export const entityIcon = async (hass: HomeAssistant, state: HassEntity) => { + let icon: string | undefined; + const domain = computeStateDomain(state); + const entity = hass.entities?.[state.entity_id]; + if (entity?.translation_key && entity.platform) { + const platformIcons = await getPlatformIcons(hass, entity.platform); + if (platformIcons) { + icon = + platformIcons[domain]?.[entity.translation_key]?.state?.[state.state] || + platformIcons[domain]?.[entity.translation_key]?.default; + } + } + if (!icon) { + const entityComponentIcons = await getComponentIcons(hass, domain); + if (entityComponentIcons) { + icon = + entityComponentIcons[state.attributes.device_class || "_"]?.state?.[ + state.state + ] || + entityComponentIcons._?.state?.[state.state] || + entityComponentIcons[state.attributes.device_class || "_"]?.default || + entityComponentIcons._?.default; + } + } + return icon; +}; + +export const attributeIcon = async ( + hass: HomeAssistant, + state: HassEntity, + attribute: string, + attributeValue?: string +) => { + let icon: string | undefined; + const domain = computeStateDomain(state); + const entity = hass.entities?.[state.entity_id]; + if (entity?.translation_key && entity.platform) { + const platformIcons = await getPlatformIcons(hass, entity.platform); + if (platformIcons) { + icon = + platformIcons[domain]?.[entity.translation_key]?.state_attributes?.[ + attribute + ]?.state?.[attributeValue || state.attributes[attribute]]; + } + } + if (!icon) { + const entityComponentIcons = await getComponentIcons(hass, domain); + if (entityComponentIcons) { + icon = + entityComponentIcons[state.attributes.device_class || "_"] + .state_attributes?.[attribute]?.state?.[ + attributeValue || state.attributes[attribute] + ] || + entityComponentIcons._.state_attributes?.[attribute]?.state?.[ + attributeValue || state.attributes[attribute] + ]; + } + } + return icon; +}; diff --git a/src/dialogs/more-info/controls/more-info-climate.ts b/src/dialogs/more-info/controls/more-info-climate.ts index 8daa9ba241..496953f07d 100644 --- a/src/dialogs/more-info/controls/more-info-climate.ts +++ b/src/dialogs/more-info/controls/more-info-climate.ts @@ -17,16 +17,13 @@ import "../../../components/ha-icon-button-toggle"; import "../../../components/ha-list-item"; import "../../../components/ha-select"; import "../../../components/ha-switch"; +import "../../../components/ha-attribute-icon"; import { ClimateEntity, ClimateEntityFeature, compareClimateHvacModes, - computeFanModeIcon, - computeHvacModeIcon, - computePresetModeIcon, - computeSwingModeIcon, } from "../../../data/climate"; -import { UNAVAILABLE } from "../../../data/entity"; +import { UNAVAILABLE, isUnavailableState } from "../../../data/entity"; import "../../../state-control/climate/ha-state-control-climate-humidity"; import "../../../state-control/climate/ha-state-control-climate-temperature"; import { HomeAssistant } from "../../../types"; @@ -164,17 +161,31 @@ class MoreInfoClimate extends LitElement { @selected=${this._handleOperationModeChanged} @closed=${stopPropagation} > - + ${!isUnavailableState(this.stateObj.state) + ? html`` + : html``} ${stateObj.attributes.hvac_modes .concat() .sort(compareClimateHvacModes) .map( (mode) => html` - + .hass=${this.hass} + .stateObj=${stateObj} + attribute="hvac_mode" + .attributeValue=${mode} + > ${this.hass.formatEntityState(stateObj, mode)} ` @@ -194,14 +205,30 @@ class MoreInfoClimate extends LitElement { @selected=${this._handlePresetmodeChanged} @closed=${stopPropagation} > - + ${stateObj.attributes.preset_mode + ? html`` + : html` + + `} ${stateObj.attributes.preset_modes!.map( (mode) => html` - + .hass=${this.hass} + .stateObj=${stateObj} + attribute="preset_mode" + .attributeValue=${mode} + > ${this.hass.formatEntityAttributeValue( stateObj, "preset_mode", @@ -227,14 +254,27 @@ class MoreInfoClimate extends LitElement { @selected=${this._handleFanModeChanged} @closed=${stopPropagation} > - + ${stateObj.attributes.fan_mode + ? html`` + : html` + + `} ${stateObj.attributes.fan_modes!.map( (mode) => html` - + .hass=${this.hass} + .stateObj=${stateObj} + attribute="fan_mode" + .attributeValue=${mode} + > ${this.hass.formatEntityAttributeValue( stateObj, "fan_mode", @@ -260,17 +300,30 @@ class MoreInfoClimate extends LitElement { @selected=${this._handleSwingmodeChanged} @closed=${stopPropagation} > - + ${stateObj.attributes.swing_mode + ? html`` + : html` + + `} ${stateObj.attributes.swing_modes!.map( (mode) => html` - + .hass=${this.hass} + .stateObj=${stateObj} + attribute="swing_mode" + .attributeValue=${mode} + > ${this.hass.formatEntityAttributeValue( stateObj, "swing_mode", diff --git a/src/layouts/home-assistant.ts b/src/layouts/home-assistant.ts index f9781eef5d..6bac52581f 100644 --- a/src/layouts/home-assistant.ts +++ b/src/layouts/home-assistant.ts @@ -3,16 +3,16 @@ import { customElement, state } from "lit/decorators"; import { isNavigationClick } from "../common/dom/is-navigation-click"; import { navigate } from "../common/navigate"; import { getStorageDefaultPanelUrlPath } from "../data/panel"; +import { WindowWithPreloads } from "../data/preloads"; import { getRecorderInfo, RecorderInfo } from "../data/recorder"; import "../resources/custom-card-support"; import { HassElement } from "../state/hass-element"; import QuickBarMixin from "../state/quick-bar-mixin"; import { HomeAssistant, Route } from "../types"; -import { WindowWithPreloads } from "../data/preloads"; import { storeState } from "../util/ha-pref-storage"; import { - renderLaunchScreenInfoBox, removeLaunchScreen, + renderLaunchScreenInfoBox, } from "../util/launch-screen"; import { registerServiceWorker, diff --git a/src/panels/calendar/ha-panel-calendar.ts b/src/panels/calendar/ha-panel-calendar.ts index 1c37d7bedd..2b9dfa8c3d 100644 --- a/src/panels/calendar/ha-panel-calendar.ts +++ b/src/panels/calendar/ha-panel-calendar.ts @@ -112,7 +112,11 @@ class PanelCalendar extends LitElement { .value=${selCal.entity_id} .selected=${!this._deSelectedCalendars.includes(selCal.entity_id)} > - + ${selCal.name} ` diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index 6e5d41f3a0..588c07a109 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -123,7 +123,8 @@ class HaAutomationPicker extends LitElement { type: "icon", template: (automation) => html` - + ${getStatisticLabel( this.hass, diff --git a/src/panels/config/entities/entity-registry-settings-editor.ts b/src/panels/config/entities/entity-registry-settings-editor.ts index 783528c53a..2da5ef250b 100644 --- a/src/panels/config/entities/entity-registry-settings-editor.ts +++ b/src/panels/config/entities/entity-registry-settings-editor.ts @@ -11,6 +11,7 @@ import { PropertyValues, } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { until } from "lit/directives/until"; import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { fireEvent } from "../../../common/dom/fire_event"; @@ -65,6 +66,7 @@ import { subscribeEntityRegistry, updateEntityRegistryEntry, } from "../../../data/entity_registry"; +import { entityIcon } from "../../../data/icons"; import { domainToName } from "../../../data/integration"; import { getNumberDeviceClassConvertibleUnits } from "../../../data/number"; import { @@ -379,7 +381,8 @@ export class EntityRegistrySettingsEditor extends LitElement { "ui.dialogs.entity_registry.editor.icon" )} .placeholder=${this.entry.original_icon || - stateObj?.attributes.icon} + stateObj?.attributes.icon || + (stateObj && until(entityIcon(this.hass, stateObj)))} .fallbackPath=${!this._icon && !stateObj?.attributes.icon && stateObj diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index b5598dbe4e..51c658ffc4 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -212,7 +212,8 @@ export class HaConfigEntities extends LitElement { `, }, diff --git a/src/panels/config/helpers/ha-config-helpers.ts b/src/panels/config/helpers/ha-config-helpers.ts index 8163787d4e..8a0607770a 100644 --- a/src/panels/config/helpers/ha-config-helpers.ts +++ b/src/panels/config/helpers/ha-config-helpers.ts @@ -129,7 +129,10 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) { type: "icon", template: (helper) => helper.entity - ? html`` + ? html`` : html`
diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts index 5f29a08398..27e21501db 100644 --- a/src/panels/config/scene/ha-scene-dashboard.ts +++ b/src/panels/config/scene/ha-scene-dashboard.ts @@ -104,7 +104,10 @@ class HaSceneDashboard extends LitElement { ), type: "icon", template: (scene) => html` - + `, }, name: { diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts index 8af1d5fba5..b8c2ab466e 100644 --- a/src/panels/config/scene/ha-scene-editor.ts +++ b/src/panels/config/scene/ha-scene-editor.ts @@ -349,6 +349,7 @@ export class HaSceneEditor extends SubscribeMixin( @click=${this._showMoreInfo} > @@ -416,6 +417,7 @@ export class HaSceneEditor extends SubscribeMixin( @click=${this._showMoreInfo} > diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts index f4e671eb91..0b51320a8a 100644 --- a/src/panels/config/script/ha-script-picker.ts +++ b/src/panels/config/script/ha-script-picker.ts @@ -119,7 +119,8 @@ class HaScriptPicker extends LitElement { type: "icon", template: (script) => html` ${computeStateName(entityState)} ${entityState.entity_id} diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts index 95dae60241..dbec9e9520 100644 --- a/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts +++ b/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts @@ -137,7 +137,8 @@ export class VoiceAssistantsExpose extends LitElement { template: (entry) => html` `, }, diff --git a/src/panels/lovelace/cards/hui-area-card.ts b/src/panels/lovelace/cards/hui-area-card.ts index eff790b5fe..5a455a9f6c 100644 --- a/src/panels/lovelace/cards/hui-area-card.ts +++ b/src/panels/lovelace/cards/hui-area-card.ts @@ -33,10 +33,8 @@ import { } from "../../../common/number/format_number"; import { subscribeOne } from "../../../common/util/subscribe-one"; import parseAspectRatio from "../../../common/util/parse-aspect-ratio"; -import "../../../components/entity/state-badge"; import "../../../components/ha-card"; import "../../../components/ha-icon-button"; -import "../../../components/ha-state-icon"; import "../../../components/ha-svg-icon"; import { AreaRegistryEntry, diff --git a/src/panels/lovelace/cards/hui-button-card.ts b/src/panels/lovelace/cards/hui-button-card.ts index 9491dd07e3..4337a77b35 100644 --- a/src/panels/lovelace/cards/hui-button-card.ts +++ b/src/panels/lovelace/cards/hui-button-card.ts @@ -214,7 +214,8 @@ export class HuiButtonCard extends LitElement implements LovelaceCard { )} data-state=${ifDefined(stateObj?.state)} .icon=${this._config.icon} - .state=${stateObj} + .hass=${this.hass} + .stateObj=${stateObj} style=${styleMap({ color: colored ? this._computeColor(stateObj) : undefined, filter: colored ? stateColorBrightness(stateObj) : undefined, diff --git a/src/panels/lovelace/cards/hui-entity-card.ts b/src/panels/lovelace/cards/hui-entity-card.ts index 2c8b9bc679..024bb033ce 100644 --- a/src/panels/lovelace/cards/hui-entity-card.ts +++ b/src/panels/lovelace/cards/hui-entity-card.ts @@ -139,7 +139,8 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
diff --git a/src/panels/lovelace/cards/hui-media-control-card.ts b/src/panels/lovelace/cards/hui-media-control-card.ts index 8127e215f4..7d5a1d8cc3 100644 --- a/src/panels/lovelace/cards/hui-media-control-card.ts +++ b/src/panels/lovelace/cards/hui-media-control-card.ts @@ -234,7 +234,11 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { >
- +
${this._config!.name || computeStateName(this.hass!.states[this._config!.entity])} diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.ts b/src/panels/lovelace/cards/hui-picture-entity-card.ts index db2068cb82..efded2eb6d 100644 --- a/src/panels/lovelace/cards/hui-picture-entity-card.ts +++ b/src/panels/lovelace/cards/hui-picture-entity-card.ts @@ -181,6 +181,7 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard { hui-image { cursor: pointer; + height: 100%; } .footer { diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts index e8f6fed98e..b1479a1db3 100644 --- a/src/panels/lovelace/cards/hui-picture-glance-card.ts +++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts @@ -278,7 +278,8 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard { > diff --git a/src/panels/lovelace/cards/hui-statistic-card.ts b/src/panels/lovelace/cards/hui-statistic-card.ts index edbd7c3fe1..7128cf921f 100644 --- a/src/panels/lovelace/cards/hui-statistic-card.ts +++ b/src/panels/lovelace/cards/hui-statistic-card.ts @@ -144,7 +144,8 @@ export class HuiStatisticCard extends LitElement implements LovelaceCard {
diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index fcfc7b6205..781f02bd42 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -256,7 +256,8 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { html` `}
diff --git a/src/panels/lovelace/components/hui-image.ts b/src/panels/lovelace/components/hui-image.ts index b46899a864..cbfe010120 100644 --- a/src/panels/lovelace/components/hui-image.ts +++ b/src/panels/lovelace/components/hui-image.ts @@ -400,12 +400,14 @@ export class HuiImage extends LitElement { .container { transition: filter 0.2s linear; + height: 100%; } img { display: block; - height: auto; + height: 100%; width: 100%; + object-fit: cover; } .progress-container { @@ -428,6 +430,12 @@ export class HuiImage extends LitElement { background-size: contain; background-repeat: no-repeat; } + .fill img { + object-fit: fill; + } + .contain img { + object-fit: contain; + } .ratio img, .ratio div { diff --git a/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts index abcb662114..8e6eb4bbec 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts @@ -19,7 +19,6 @@ import { import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event"; import { customType } from "../../../../common/structs/is-custom-type"; import { computeRTLDirection } from "../../../../common/util/compute_rtl"; -import "../../../../components/entity/state-badge"; import "../../../../components/ha-card"; import "../../../../components/ha-formfield"; import "../../../../components/ha-icon"; diff --git a/src/panels/lovelace/elements/hui-state-icon-element.ts b/src/panels/lovelace/elements/hui-state-icon-element.ts index 0e90e2d4fd..1f21100479 100644 --- a/src/panels/lovelace/elements/hui-state-icon-element.ts +++ b/src/panels/lovelace/elements/hui-state-icon-element.ts @@ -59,6 +59,7 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement { return html` `}
diff --git a/src/panels/lovelace/special-rows/hui-button-row.ts b/src/panels/lovelace/special-rows/hui-button-row.ts index f74d444604..6c92cd0b01 100644 --- a/src/panels/lovelace/special-rows/hui-button-row.ts +++ b/src/panels/lovelace/special-rows/hui-button-row.ts @@ -53,7 +53,11 @@ export class HuiButtonRow extends LitElement implements LovelaceRow { this._config.name ?? (stateObj ? computeStateName(stateObj) : ""); return html` - +
${name}
diff --git a/src/panels/todo/ha-panel-todo.ts b/src/panels/todo/ha-panel-todo.ts index 448798a187..03a3e2b1fd 100644 --- a/src/panels/todo/ha-panel-todo.ts +++ b/src/panels/todo/ha-panel-todo.ts @@ -167,7 +167,11 @@ class PanelTodo extends LitElement { .entityId=${list.entity_id} .activated=${list.entity_id === this._entityId} > - ${list.name} ` ); diff --git a/src/state-summary/state-card-input_select.ts b/src/state-summary/state-card-input_select.ts index c82347b343..5b2cf12370 100644 --- a/src/state-summary/state-card-input_select.ts +++ b/src/state-summary/state-card-input_select.ts @@ -40,7 +40,7 @@ class StateCardInputSelect extends LitElement { protected render(): TemplateResult { return html` - + + + >( string, ContextProvider | undefined > = { + connection: new ContextProvider(this, { + context: connectionContext, + initialValue: this.hass + ? this.hass.connection + : this._pendingHass.connection, + }), states: new ContextProvider(this, { context: statesContext, initialValue: this.hass ? this.hass.states : this._pendingHass.states,