mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-14 21:06:34 +00:00
Remove side effects of render and Add types - Button/Glance (#1919)
* Remove side effects of render and Add types * Addressing changes * Updating when to apply theme * Review Updates * Fixing last reviews * Updates from travis
This commit is contained in:
parent
447c06d817
commit
aebd1a1be1
@ -1,5 +1,12 @@
|
|||||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
import {
|
||||||
import { fireEvent } from "../../../common/dom/fire_event.js";
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyDeclarations,
|
||||||
|
PropertyValues,
|
||||||
|
} from "@polymer/lit-element";
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { TemplateResult } from "lit-html";
|
||||||
|
import { styleMap } from "lit-html/directives/styleMap.js";
|
||||||
|
|
||||||
import "../../../components/ha-card.js";
|
import "../../../components/ha-card.js";
|
||||||
|
|
||||||
@ -9,11 +16,11 @@ import stateIcon from "../../../common/entity/state_icon.js";
|
|||||||
import computeStateDomain from "../../../common/entity/compute_state_domain.js";
|
import computeStateDomain from "../../../common/entity/compute_state_domain.js";
|
||||||
import computeStateName from "../../../common/entity/compute_state_name.js";
|
import computeStateName from "../../../common/entity/compute_state_name.js";
|
||||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element.js";
|
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element.js";
|
||||||
import { styleMap } from "lit-html/directives/styleMap.js";
|
import { HomeAssistant, LightEntity } from "../../../types.js";
|
||||||
import { HomeAssistant } from "../../../types.js";
|
|
||||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||||
import { LovelaceCard, LovelaceConfig } from "../types.js";
|
import { LovelaceCard, LovelaceConfig } from "../types.js";
|
||||||
import { longPress } from "../common/directives/long-press-directive";
|
import { longPress } from "../common/directives/long-press-directive";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event.js";
|
||||||
|
|
||||||
interface Config extends LovelaceConfig {
|
interface Config extends LovelaceConfig {
|
||||||
entity: string;
|
entity: string;
|
||||||
@ -29,38 +36,47 @@ interface Config extends LovelaceConfig {
|
|||||||
class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement)
|
class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement)
|
||||||
implements LovelaceCard {
|
implements LovelaceCard {
|
||||||
public hass?: HomeAssistant;
|
public hass?: HomeAssistant;
|
||||||
protected config?: Config;
|
private _config?: Config;
|
||||||
|
|
||||||
static get properties(): PropertyDeclarations {
|
static get properties(): PropertyDeclarations {
|
||||||
return {
|
return {
|
||||||
hass: {},
|
hass: {},
|
||||||
config: {},
|
_config: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCardSize() {
|
public getCardSize(): number {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(config: Config) {
|
public setConfig(config: Config): void {
|
||||||
if (!isValidEntityId(config.entity)) {
|
if (!isValidEntityId(config.entity)) {
|
||||||
throw new Error("Invalid Entity");
|
throw new Error("Invalid Entity");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.config = { theme: "default", ...config };
|
this._config = { theme: "default", ...config };
|
||||||
|
|
||||||
if (this.hass) {
|
|
||||||
this.requestUpdate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
if (!this.config) {
|
if (changedProps.has("_config")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
|
if (oldHass) {
|
||||||
|
return (
|
||||||
|
oldHass.states[this._config!.entity] !==
|
||||||
|
this.hass!.states[this._config!.entity]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
const stateObj = this.hass!.states[this.config.entity];
|
const stateObj = this.hass.states[this._config.entity];
|
||||||
|
|
||||||
applyThemesOnElement(this, this.hass!.themes, this.config.theme);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${this.renderStyle()}
|
${this.renderStyle()}
|
||||||
@ -72,7 +88,7 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
${
|
${
|
||||||
!stateObj
|
!stateObj
|
||||||
? html`<div class="not-found">Entity not available: ${
|
? html`<div class="not-found">Entity not available: ${
|
||||||
this.config.entity
|
this._config.entity
|
||||||
}</div>`
|
}</div>`
|
||||||
: html`
|
: html`
|
||||||
<paper-button>
|
<paper-button>
|
||||||
@ -80,20 +96,14 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
<ha-icon
|
<ha-icon
|
||||||
data-domain="${computeStateDomain(stateObj)}"
|
data-domain="${computeStateDomain(stateObj)}"
|
||||||
data-state="${stateObj.state}"
|
data-state="${stateObj.state}"
|
||||||
.icon="${
|
.icon="${this._config.icon || stateIcon(stateObj)}"
|
||||||
this.config.icon ? this.config.icon : stateIcon(stateObj)
|
|
||||||
}"
|
|
||||||
style="${styleMap({
|
style="${styleMap({
|
||||||
filter: this._computeBrightness(stateObj),
|
filter: this._computeBrightness(stateObj),
|
||||||
color: this._computeColor(stateObj),
|
color: this._computeColor(stateObj),
|
||||||
})}"
|
})}"
|
||||||
></ha-icon>
|
></ha-icon>
|
||||||
<span>
|
<span>
|
||||||
${
|
${this._config.name || computeStateName(stateObj)}
|
||||||
this.config.name
|
|
||||||
? this.config.name
|
|
||||||
: computeStateName(stateObj)
|
|
||||||
}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</paper-button>
|
</paper-button>
|
||||||
@ -103,7 +113,17 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderStyle() {
|
protected updated(changedProps: PropertyValues): void {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
|
if (!oldHass || oldHass.themes !== this.hass.themes) {
|
||||||
|
applyThemesOnElement(this, this.hass.themes, this._config.theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderStyle(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
ha-icon {
|
ha-icon {
|
||||||
@ -143,7 +163,7 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeBrightness(stateObj) {
|
private _computeBrightness(stateObj: HassEntity | LightEntity): string {
|
||||||
if (!stateObj.attributes.brightness) {
|
if (!stateObj.attributes.brightness) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -151,20 +171,19 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
return `brightness(${(brightness + 245) / 5}%)`;
|
return `brightness(${(brightness + 245) / 5}%)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeColor(stateObj) {
|
private _computeColor(stateObj: HassEntity | LightEntity): string {
|
||||||
if (!stateObj.attributes.hs_color) {
|
if (!stateObj.attributes.hs_color) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const hue = stateObj.attributes.hs_color[0];
|
const { hue, sat } = stateObj.attributes.hs_color;
|
||||||
const sat = stateObj.attributes.hs_color[1];
|
|
||||||
if (sat <= 10) {
|
if (sat <= 10) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
|
return `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleClick(hold) {
|
private handleClick(hold: boolean): void {
|
||||||
const config = this.config;
|
const config = this._config;
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { html, LitElement } from "@polymer/lit-element";
|
import {
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
PropertyDeclarations,
|
||||||
|
} from "@polymer/lit-element";
|
||||||
import { classMap } from "lit-html/directives/classMap.js";
|
import { classMap } from "lit-html/directives/classMap.js";
|
||||||
|
|
||||||
import computeStateDisplay from "../../../common/entity/compute_state_display.js";
|
import computeStateDisplay from "../../../common/entity/compute_state_display.js";
|
||||||
@ -17,6 +22,7 @@ import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
|||||||
import { HomeAssistant } from "../../../types.js";
|
import { HomeAssistant } from "../../../types.js";
|
||||||
import { LovelaceCard, LovelaceConfig } from "../types.js";
|
import { LovelaceCard, LovelaceConfig } from "../types.js";
|
||||||
import { longPress } from "../common/directives/long-press-directive";
|
import { longPress } from "../common/directives/long-press-directive";
|
||||||
|
import { TemplateResult } from "lit-html";
|
||||||
|
|
||||||
interface EntityConfig {
|
interface EntityConfig {
|
||||||
name: string;
|
name: string;
|
||||||
@ -40,27 +46,25 @@ interface Config extends LovelaceConfig {
|
|||||||
export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
||||||
implements LovelaceCard {
|
implements LovelaceCard {
|
||||||
public hass?: HomeAssistant;
|
public hass?: HomeAssistant;
|
||||||
protected config?: Config;
|
private _config?: Config;
|
||||||
protected configEntities?: EntityConfig[];
|
private _configEntities?: EntityConfig[];
|
||||||
|
|
||||||
static get properties() {
|
static get properties(): PropertyDeclarations {
|
||||||
return {
|
return {
|
||||||
hass: {},
|
hass: {},
|
||||||
config: {},
|
_config: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCardSize() {
|
public getCardSize(): number {
|
||||||
const columns =
|
|
||||||
this.config!.columns || Math.min(this.config!.entities.length, 5);
|
|
||||||
return (
|
return (
|
||||||
(this.config!.title ? 1 : 0) +
|
(this._config!.title ? 1 : 0) +
|
||||||
2 * Math.ceil(this.configEntities!.length / columns)
|
Math.ceil(this._configEntities!.length / 5)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(config: Config) {
|
public setConfig(config: Config): void {
|
||||||
this.config = { theme: "default", ...config };
|
this._config = { theme: "default", ...config };
|
||||||
const entities = processConfigEntities(config.entities);
|
const entities = processConfigEntities(config.entities);
|
||||||
|
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
@ -78,26 +82,43 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
const columns = config.columns || Math.min(config.entities.length, 5);
|
const columns = config.columns || Math.min(config.entities.length, 5);
|
||||||
this.style.setProperty("--glance-column-width", `${100 / columns}%`);
|
this.style.setProperty("--glance-column-width", `${100 / columns}%`);
|
||||||
|
|
||||||
this.configEntities = entities;
|
this._configEntities = entities;
|
||||||
|
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
if (!this.config || !this.hass) {
|
if (changedProps.has("_config")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
|
if (oldHass && this._configEntities) {
|
||||||
|
for (const entity of this._configEntities) {
|
||||||
|
if (
|
||||||
|
oldHass.states[entity.entity] !== this.hass!.states[entity.entity]
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
const { title } = this.config;
|
const { title } = this._config;
|
||||||
|
|
||||||
applyThemesOnElement(this, this.hass!.themes, this.config.theme);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${this.renderStyle()}
|
${this.renderStyle()}
|
||||||
<ha-card .header="${title}">
|
<ha-card .header="${title}">
|
||||||
<div class="entities ${classMap({ "no-header": !title })}">
|
<div class="entities ${classMap({ "no-header": !title })}">
|
||||||
${this.configEntities!.map((entityConf) =>
|
${this._configEntities!.map((entityConf) =>
|
||||||
this.renderEntity(entityConf)
|
this.renderEntity(entityConf)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -105,7 +126,18 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderStyle() {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldHass = changedProperties.get("hass") as HomeAssistant | undefined;
|
||||||
|
if (!oldHass || oldHass.themes !== this.hass.themes) {
|
||||||
|
applyThemesOnElement(this, this.hass.themes, this._config.theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderStyle(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
.entities {
|
.entities {
|
||||||
@ -147,7 +179,7 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderEntity(entityConf) {
|
private renderEntity(entityConf): TemplateResult {
|
||||||
const stateObj = this.hass!.states[entityConf.entity];
|
const stateObj = this.hass!.states[entityConf.entity];
|
||||||
|
|
||||||
if (!stateObj) {
|
if (!stateObj) {
|
||||||
@ -165,7 +197,7 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
.longPress="${longPress()}"
|
.longPress="${longPress()}"
|
||||||
>
|
>
|
||||||
${
|
${
|
||||||
this.config!.show_name !== false
|
this._config!.show_name !== false
|
||||||
? html`<div class="name">${
|
? html`<div class="name">${
|
||||||
"name" in entityConf
|
"name" in entityConf
|
||||||
? entityConf.name
|
? entityConf.name
|
||||||
@ -178,7 +210,7 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
.overrideIcon="${entityConf.icon}"
|
.overrideIcon="${entityConf.icon}"
|
||||||
></state-badge>
|
></state-badge>
|
||||||
${
|
${
|
||||||
this.config!.show_state !== false
|
this._config!.show_state !== false
|
||||||
? html`<div>${computeStateDisplay(this.localize, stateObj)}</div>`
|
? html`<div>${computeStateDisplay(this.localize, stateObj)}</div>`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
@ -186,7 +218,7 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleClick(ev: MouseEvent, hold) {
|
private handleClick(ev: MouseEvent, hold: boolean): void {
|
||||||
const config = (ev.currentTarget as any).entityConf as EntityConfig;
|
const config = (ev.currentTarget as any).entityConf as EntityConfig;
|
||||||
const entityId = config.entity;
|
const entityId = config.entity;
|
||||||
const action = hold ? config.hold_action : config.tap_action || "more-info";
|
const action = hold ? config.hold_action : config.tap_action || "more-info";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user