diff --git a/src/state-summary/state-card-input_number.js b/src/state-summary/state-card-input_number.js deleted file mode 100644 index ced62e2984..0000000000 --- a/src/state-summary/state-card-input_number.js +++ /dev/null @@ -1,200 +0,0 @@ -import "@polymer/iron-flex-layout/iron-flex-layout-classes"; -import { IronResizableBehavior } from "@polymer/iron-resizable-behavior/iron-resizable-behavior"; -import { mixinBehaviors } from "@polymer/polymer/lib/legacy/class"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { computeStateDisplay } from "../common/entity/compute_state_display"; -import "../components/entity/state-info"; -import "../components/ha-slider"; -import "../components/ha-textfield"; - -class StateCardInputNumber extends mixinBehaviors( - [IronResizableBehavior], - PolymerElement -) { - static get template() { - return html` - - - -
- ${this.stateInfoTemplate} - - - -
- `; - } - - static get stateInfoTemplate() { - return html` - - `; - } - - 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); - } - } - - static get properties() { - return { - hass: Object, - hiddenbox: { - type: Boolean, - value: true, - }, - hiddenslider: { - type: Boolean, - value: true, - }, - inDialog: { - type: Boolean, - value: false, - }, - stateObj: { - type: Object, - observer: "stateObjectChanged", - }, - min: { - type: Number, - value: 0, - }, - max: { - type: Number, - value: 100, - }, - maxlength: { - type: Number, - value: 3, - }, - step: Number, - value: Number, - formattedState: String, - mode: String, - }; - } - - hiddenState() { - if (this.mode !== "slider") return; - const sliderwidth = this.$.slider.offsetWidth; - if (sliderwidth < 100) { - this.$.sliderstate.hidden = true; - } else if (sliderwidth >= 145) { - this.$.sliderstate.hidden = false; - } - } - - stateObjectChanged(newVal) { - const prevMode = this.mode; - this.setProperties({ - min: Number(newVal.attributes.min), - max: Number(newVal.attributes.max), - step: Number(newVal.attributes.step), - value: Number(newVal.state), - formattedState: computeStateDisplay( - this.hass.localize, - newVal, - this.hass.locale, - this.hass.entities, - newVal.state - ), - mode: String(newVal.attributes.mode), - maxlength: String(newVal.attributes.max).length, - hiddenbox: newVal.attributes.mode !== "box", - hiddenslider: newVal.attributes.mode !== "slider", - }); - if (this.mode === "slider" && prevMode !== "slider") { - this.hiddenState(); - } - } - - onInput(ev) { - this.value = ev.target.value; - } - - 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, - }); - } - - stopPropagation(ev) { - ev.stopPropagation(); - } -} - -customElements.define("state-card-input_number", StateCardInputNumber); diff --git a/src/state-summary/state-card-input_number.ts b/src/state-summary/state-card-input_number.ts new file mode 100644 index 0000000000..02829dd96a --- /dev/null +++ b/src/state-summary/state-card-input_number.ts @@ -0,0 +1,169 @@ +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { HassEntity } from "home-assistant-js-websocket"; +import { customElement, property } from "lit/decorators"; +import { computeStateDisplay } from "../common/entity/compute_state_display"; +import { computeRTLDirection } from "../common/util/compute_rtl"; +import { debounce } from "../common/util/debounce"; +import "../components/ha-slider"; +import "../components/ha-textfield"; +import "../components/entity/state-info"; +import { isUnavailableState } from "../data/entity"; +import { setValue } from "../data/input_text"; +import { HomeAssistant } from "../types"; +import { installResizeObserver } from "../panels/lovelace/common/install-resize-observer"; + +@customElement("state-card-input_number") +class StateCardInputNumber extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public stateObj!: HassEntity; + + @property({ type: Boolean }) public inDialog = false; + + private _loaded?: boolean; + + private _updated?: boolean; + + private _resizeObserver?: ResizeObserver; + + public connectedCallback(): void { + super.connectedCallback(); + if (this._updated && !this._loaded) { + this._initialLoad(); + } + this._attachObserver(); + } + + public disconnectedCallback(): void { + this._resizeObserver?.disconnect(); + } + + protected firstUpdated(): void { + this._updated = true; + if (this.isConnected && !this._loaded) { + this._initialLoad(); + } + this._attachObserver(); + } + + protected render(): TemplateResult { + return html` + + ${this.stateObj.attributes.mode === "slider" + ? html` +
+ + + ${computeStateDisplay( + this.hass.localize, + this.stateObj, + this.hass.locale, + this.hass.entities, + this.stateObj.state + )} + +
+ ` + : html` +
+ + +
+ `} + `; + } + + static get styles(): CSSResultGroup { + return css` + :host { + display: flex; + } + .flex { + display: flex; + align-items: center; + justify-content: flex-end; + flex-grow: 2; + } + .state { + min-width: 45px; + text-align: end; + } + ha-textfield { + text-align: end; + } + ha-slider { + width: 100%; + max-width: 200px; + } + `; + } + + private async _initialLoad(): Promise { + this._loaded = true; + await this.updateComplete; + this._measureCard(); + } + + private _measureCard() { + if (!this.isConnected) { + return; + } + const element = this.shadowRoot!.querySelector(".state") as HTMLElement; + if (!element) { + return; + } + element.hidden = this.clientWidth <= 300; + } + + private async _attachObserver(): Promise { + if (!this._resizeObserver) { + await installResizeObserver(); + this._resizeObserver = new ResizeObserver( + debounce(() => this._measureCard(), 250, false) + ); + } + if (this.isConnected) { + this._resizeObserver.observe(this); + } + } + + private _selectedValueChanged(ev: Event): void { + if ((ev.target as HTMLInputElement).value !== this.stateObj.state) { + setValue( + this.hass!, + this.stateObj.entity_id, + (ev.target as HTMLInputElement).value + ); + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "state-card-input_number": StateCardInputNumber; + } +}