mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 01:06:35 +00:00
Convert state badge to TypeScript (#2712)
This commit is contained in:
parent
039bc587cc
commit
f23258eb8c
@ -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);
|
127
src/components/entity/state-badge.ts
Normal file
127
src/components/entity/state-badge.ts
Normal 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);
|
@ -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
36
src/components/ha-icon.ts
Normal 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);
|
Loading…
x
Reference in New Issue
Block a user