From 6da311078a2abcc7ade5735ba03738d327537928 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Fri, 22 Feb 2019 14:08:18 -0600 Subject: [PATCH] Convert input-number to Lit/TS (#2792) * Convert input-number to Lit/TS Should I worry about width for the state display with slider? * address review comments * clientWidth not currently working * unsure about the typing of _InputElement * remove unused import * get clientwidth * added comment --- src/data/input_text.ts | 2 +- .../hui-input-number-entity-row.js | 188 ------------------ .../hui-input-number-entity-row.ts | 162 +++++++++++++++ 3 files changed, 163 insertions(+), 189 deletions(-) delete mode 100644 src/panels/lovelace/entity-rows/hui-input-number-entity-row.js create mode 100644 src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts diff --git a/src/data/input_text.ts b/src/data/input_text.ts index a8ed653111..04ee6c334c 100644 --- a/src/data/input_text.ts +++ b/src/data/input_text.ts @@ -1,7 +1,7 @@ import { HomeAssistant } from "../types"; export const setValue = (hass: HomeAssistant, entity: string, value: string) => - hass.callService("input_text", "set_value", { + hass.callService(entity.split(".", 1)[0], "set_value", { value, entity_id: entity, }); diff --git a/src/panels/lovelace/entity-rows/hui-input-number-entity-row.js b/src/panels/lovelace/entity-rows/hui-input-number-entity-row.js deleted file mode 100644 index 611d496592..0000000000 --- a/src/panels/lovelace/entity-rows/hui-input-number-entity-row.js +++ /dev/null @@ -1,188 +0,0 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "@polymer/paper-input/paper-input"; -import { IronResizableBehavior } from "@polymer/iron-resizable-behavior/iron-resizable-behavior"; -import { mixinBehaviors } from "@polymer/polymer/lib/legacy/class"; - -import "../components/hui-generic-entity-row"; -import "../../../components/ha-slider"; -import { computeRTL } from "../../../common/util/compute_rtl"; - -class HuiInputNumberEntityRow extends mixinBehaviors( - [IronResizableBehavior], - PolymerElement -) { - static get template() { - return html` - ${this.styleTemplate} - - ${this.inputNumberControlTemplate} - - `; - } - - static get styleTemplate() { - return html` - - `; - } - - static get inputNumberControlTemplate() { - return html` -
- - -
- `; - } - - static get properties() { - return { - hass: Object, - _config: Object, - _stateObj: { - type: Object, - computed: "_computeStateObj(hass.states, _config.entity)", - observer: "_stateObjChanged", - }, - _min: { - type: Number, - value: 0, - }, - _max: { - type: Number, - value: 100, - }, - _step: Number, - _value: Number, - _rtl: { - type: String, - computed: "_computeRTLDirection(hass)", - }, - }; - } - - ready() { - super.ready(); - if (typeof ResizeObserver === "function") { - const ro = new ResizeObserver((entries) => { - entries.forEach(() => { - this._hiddenState(); - }); - }); - ro.observe(this.$.input_number_card); - } else { - this.addEventListener("iron-resize", this._hiddenState); - } - } - - _equals(a, b) { - return a === b; - } - - _computeStateObj(states, entityId) { - return states && entityId in states ? states[entityId] : null; - } - - setConfig(config) { - if (!config || !config.entity) { - throw new Error("Entity not configured."); - } - this._config = config; - } - - _hiddenState() { - if ( - !this.$ || - !this._stateObj || - this._stateObj.attributes.mode !== "slider" - ) - return; - const width = this.$.input_number_card.offsetWidth; - const stateEl = this.shadowRoot.querySelector(".state"); - if (!stateEl) return; - stateEl.hidden = width <= 350; - } - - _stateObjChanged(stateObj, oldStateObj) { - if (!stateObj) return; - - this.setProperties({ - _min: Number(stateObj.attributes.min), - _max: Number(stateObj.attributes.max), - _step: Number(stateObj.attributes.step), - _value: Number(stateObj.state), - }); - if ( - oldStateObj && - stateObj.attributes.mode === "slider" && - oldStateObj.attributes.mode !== "slider" - ) { - this._hiddenState(); - } - } - - _selectedValueChanged() { - if (this._value === Number(this._stateObj.state)) return; - - this.hass.callService("input_number", "set_value", { - value: this._value, - entity_id: this._stateObj.entity_id, - }); - } - - _computeRTLDirection(hass) { - return computeRTL(hass) ? "rtl" : "ltr"; - } -} -customElements.define("hui-input-number-entity-row", HuiInputNumberEntityRow); diff --git a/src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts new file mode 100644 index 0000000000..f3fb9d0709 --- /dev/null +++ b/src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts @@ -0,0 +1,162 @@ +import { + html, + LitElement, + TemplateResult, + property, + customElement, + css, + CSSResult, +} from "lit-element"; + +import "../components/hui-generic-entity-row"; +import "../../../components/ha-slider"; +import "../components/hui-warning"; + +import { computeRTLDirection } from "../../../common/util/compute_rtl"; +import { EntityRow, EntityConfig } from "./types"; +import { HomeAssistant } from "../../../types"; +import { setValue } from "../../../data/input_text"; + +@customElement("hui-input-number-entity-row") +class HuiInputNumberEntityRow extends LitElement implements EntityRow { + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; + private _loaded?: boolean; + private _updated?: boolean; + + public setConfig(config: EntityConfig): void { + if (!config) { + throw new Error("Configuration error"); + } + this._config = config; + } + + public connectedCallback(): void { + super.connectedCallback(); + if (this._updated && !this._loaded) { + this._initialLoad(); + } + } + + protected firstUpdated(): void { + this._updated = true; + if (this.isConnected && !this._loaded) { + this._initialLoad(); + } + } + + protected render(): TemplateResult | void { + if (!this._config || !this.hass) { + return html``; + } + + const stateObj = this.hass.states[this._config.entity]; + + if (!stateObj) { + return html` + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} + `; + } + + return html` + +
+ ${stateObj.attributes.mode === "slider" + ? html` +
+ + + ${Number(stateObj.state)} + ${stateObj.attributes.unit_of_measurement} + +
+ ` + : html` + + `} +
+
+ `; + } + + static get styles(): CSSResult { + return css` + .flex { + display: flex; + align-items: center; + } + .state { + min-width: 45px; + text-align: center; + } + paper-input { + text-align: right; + } + `; + } + + private async _initialLoad(): Promise { + this._loaded = true; + await this.updateComplete; + const element = this.shadowRoot!.querySelector(".state") as HTMLElement; + + if (!element || !this.parentElement) { + return; + } + + element.hidden = this.parentElement.clientWidth <= 350; + } + + private get _inputElement(): { value: string } { + // linter recommended the following syntax + return (this.shadowRoot!.getElementById("input") as unknown) as { + value: string; + }; + } + + private _selectedValueChanged(): void { + const element = this._inputElement; + const stateObj = this.hass!.states[this._config!.entity]; + + if (element.value !== stateObj.state) { + setValue(this.hass!, stateObj.entity_id, element.value!); + } + } + + private _computeRTLDirection(): string { + return computeRTLDirection(this.hass!); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-input-number-entity-row": HuiInputNumberEntityRow; + } +}