Convert state badge to TypeScript (#2712)

This commit is contained in:
Paulus Schoutsen 2019-02-09 11:55:46 -08:00 committed by GitHub
parent 039bc587cc
commit f23258eb8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 163 additions and 128 deletions

View File

@ -1,110 +0,0 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../ha-icon";
import computeStateDomain from "../../common/entity/compute_state_domain";
import stateIcon from "../../common/entity/state_icon";
class StateBadge extends PolymerElement {
static get template() {
return html`
<style>
:host {
position: relative;
display: inline-block;
width: 40px;
color: var(--paper-item-icon-color, #44739e);
border-radius: 50%;
height: 40px;
text-align: center;
background-size: cover;
line-height: 40px;
}
ha-icon {
transition: color 0.3s ease-in-out, filter 0.3s ease-in-out;
}
/* Color the icon if light or sun is on */
ha-icon[data-domain="light"][data-state="on"],
ha-icon[data-domain="switch"][data-state="on"],
ha-icon[data-domain="binary_sensor"][data-state="on"],
ha-icon[data-domain="fan"][data-state="on"],
ha-icon[data-domain="sun"][data-state="above_horizon"] {
color: var(--paper-item-icon-active-color, #fdd835);
}
/* Color the icon if unavailable */
ha-icon[data-state="unavailable"] {
color: var(--state-icon-unavailable-color);
}
</style>
<ha-icon
id="icon"
data-domain$="[[_computeDomain(stateObj)]]"
data-state$="[[stateObj.state]]"
icon="[[_computeIcon(stateObj, overrideIcon)]]"
></ha-icon>
`;
}
static get properties() {
return {
stateObj: {
type: Object,
observer: "_updateIconAppearance",
},
overrideIcon: String,
};
}
_computeDomain(stateObj) {
return computeStateDomain(stateObj);
}
_computeIcon(stateObj, overrideIcon) {
return overrideIcon || stateIcon(stateObj);
}
_updateIconAppearance(newVal) {
var errorMessage = null;
const iconStyle = {
color: "",
filter: "",
};
const hostStyle = {
backgroundImage: "",
};
// hide icon if we have entity picture
if (newVal.attributes.entity_picture) {
hostStyle.backgroundImage =
"url(" + newVal.attributes.entity_picture + ")";
iconStyle.display = "none";
} else {
if (newVal.attributes.hs_color) {
const hue = newVal.attributes.hs_color[0];
const sat = newVal.attributes.hs_color[1];
if (sat > 10) iconStyle.color = `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
}
if (newVal.attributes.brightness) {
const brightness = newVal.attributes.brightness;
if (typeof brightness !== "number") {
errorMessage = `Type error: state-badge expected number, but type of ${
newVal.entity_id
}.attributes.brightness is ${typeof brightness} (${brightness})`;
// eslint-disable-next-line
console.warn(errorMessage);
}
// lowest brighntess will be around 50% (that's pretty dark)
iconStyle.filter = `brightness(${(brightness + 245) / 5}%)`;
}
}
Object.assign(this.$.icon.style, iconStyle);
Object.assign(this.style, hostStyle);
if (errorMessage) {
throw new Error(`Frontend error: ${errorMessage}`);
}
}
}
customElements.define("state-badge", StateBadge);

View File

@ -0,0 +1,127 @@
import {
LitElement,
TemplateResult,
css,
CSSResult,
html,
property,
PropertyValues,
query,
} from "lit-element";
import "../ha-icon";
import computeStateDomain from "../../common/entity/compute_state_domain";
import stateIcon from "../../common/entity/state_icon";
import { HassEntity } from "home-assistant-js-websocket";
// Not duplicate, this is for typing.
// tslint:disable-next-line
import { HaIcon } from "../ha-icon";
class StateBadge extends LitElement {
@property() public stateObj?: HassEntity;
@property() public overrideIcon?: string;
@query("ha-icon") private _icon!: HaIcon;
protected render(): TemplateResult | void {
const stateObj = this.stateObj;
if (!stateObj) {
return html``;
}
return html`
<ha-icon
id="icon"
data-domain=${computeStateDomain(stateObj)}
data-state=${stateObj.state}
.icon=${this.overrideIcon || stateIcon(stateObj)}
></ha-icon>
`;
}
protected updated(changedProps: PropertyValues) {
if (!changedProps.has("stateObj")) {
return;
}
const stateObj = this.stateObj;
const iconStyle: Partial<CSSStyleDeclaration> = {
color: "",
filter: "",
};
const hostStyle: Partial<CSSStyleDeclaration> = {
backgroundImage: "",
};
if (stateObj) {
// hide icon if we have entity picture
if (stateObj.attributes.entity_picture) {
hostStyle.backgroundImage =
"url(" + stateObj.attributes.entity_picture + ")";
iconStyle.display = "none";
} else {
if (stateObj.attributes.hs_color) {
const hue = stateObj.attributes.hs_color[0];
const sat = stateObj.attributes.hs_color[1];
if (sat > 10) {
iconStyle.color = `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
}
}
if (stateObj.attributes.brightness) {
const brightness = stateObj.attributes.brightness;
if (typeof brightness !== "number") {
const errorMessage = `Type error: state-badge expected number, but type of ${
stateObj.entity_id
}.attributes.brightness is ${typeof brightness} (${brightness})`;
// tslint:disable-next-line
console.warn(errorMessage);
}
// lowest brighntess will be around 50% (that's pretty dark)
iconStyle.filter = `brightness(${(brightness + 245) / 5}%)`;
}
}
}
Object.assign(this._icon.style, iconStyle);
Object.assign(this.style, hostStyle);
}
static get styles(): CSSResult {
return css`
:host {
position: relative;
display: inline-block;
width: 40px;
color: var(--paper-item-icon-color, #44739e);
border-radius: 50%;
height: 40px;
text-align: center;
background-size: cover;
line-height: 40px;
}
ha-icon {
transition: color 0.3s ease-in-out, filter 0.3s ease-in-out;
}
/* Color the icon if light or sun is on */
ha-icon[data-domain="light"][data-state="on"],
ha-icon[data-domain="switch"][data-state="on"],
ha-icon[data-domain="binary_sensor"][data-state="on"],
ha-icon[data-domain="fan"][data-state="on"],
ha-icon[data-domain="sun"][data-state="above_horizon"] {
color: var(--paper-item-icon-active-color, #fdd835);
}
/* Color the icon if unavailable */
ha-icon[data-state="unavailable"] {
color: var(--state-icon-unavailable-color);
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"state-badge": StateBadge;
}
}
customElements.define("state-badge", StateBadge);

View File

@ -1,18 +0,0 @@
import "@polymer/iron-icon/iron-icon";
const IronIconClass = customElements.get("iron-icon");
let loaded = false;
class HaIcon extends IronIconClass {
listen(...args) {
super.listen(...args);
if (!loaded && this._iconsetName === "mdi") {
loaded = true;
import(/* webpackChunkName: "mdi-icons" */ "../resources/mdi-icons");
}
}
}
customElements.define("ha-icon", HaIcon);

36
src/components/ha-icon.ts Normal file
View File

@ -0,0 +1,36 @@
import { Constructor } from "lit-element";
import "@polymer/iron-icon/iron-icon";
// Not duplicate, this is for typing.
// tslint:disable-next-line
import { IronIconElement } from "@polymer/iron-icon/iron-icon";
const ironIconClass = customElements.get("iron-icon") as Constructor<
IronIconElement
>;
let loaded = false;
export class HaIcon extends ironIconClass {
private _iconsetName?: string;
public listen(
node: EventTarget | null,
eventName: string,
methodName: string
): void {
super.listen(node, eventName, methodName);
if (!loaded && this._iconsetName === "mdi") {
loaded = true;
import(/* webpackChunkName: "mdi-icons" */ "../resources/mdi-icons");
}
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-icon": HaIcon;
}
}
customElements.define("ha-icon", HaIcon);