mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-29 12:16:39 +00:00
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
This commit is contained in:
parent
7d1991ac78
commit
6da311078a
@ -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,
|
||||
});
|
||||
|
@ -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}
|
||||
<hui-generic-entity-row
|
||||
hass="[[hass]]"
|
||||
config="[[_config]]"
|
||||
id="input_number_card"
|
||||
>
|
||||
${this.inputNumberControlTemplate}
|
||||
</hui-generic-entity-row>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styleTemplate() {
|
||||
return html`
|
||||
<style>
|
||||
.flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.state {
|
||||
min-width: 45px;
|
||||
text-align: center;
|
||||
}
|
||||
paper-input {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
|
||||
static get inputNumberControlTemplate() {
|
||||
return html`
|
||||
<div>
|
||||
<template
|
||||
is="dom-if"
|
||||
if="[[_equals(_stateObj.attributes.mode, 'slider')]]"
|
||||
>
|
||||
<div class="flex">
|
||||
<ha-slider
|
||||
dir="[[_rtl]]"
|
||||
min="[[_min]]"
|
||||
max="[[_max]]"
|
||||
value="{{_value}}"
|
||||
step="[[_step]]"
|
||||
pin
|
||||
on-change="_selectedValueChanged"
|
||||
ignore-bar-touch
|
||||
></ha-slider>
|
||||
<span class="state"
|
||||
>[[_value]] [[_stateObj.attributes.unit_of_measurement]]</span
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<template
|
||||
is="dom-if"
|
||||
if="[[_equals(_stateObj.attributes.mode, 'box')]]"
|
||||
>
|
||||
<paper-input
|
||||
no-label-float
|
||||
auto-validate
|
||||
pattern="[0-9]+([\\.][0-9]+)?"
|
||||
step="[[_step]]"
|
||||
min="[[_min]]"
|
||||
max="[[_max]]"
|
||||
value="{{_value}}"
|
||||
type="number"
|
||||
on-change="_selectedValueChanged"
|
||||
></paper-input>
|
||||
</template>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
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);
|
162
src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts
Normal file
162
src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts
Normal file
@ -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`
|
||||
<hui-warning
|
||||
>${this.hass.localize(
|
||||
"ui.panel.lovelace.warning.entity_not_found",
|
||||
"entity",
|
||||
this._config.entity
|
||||
)}</hui-warning
|
||||
>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row .hass="${this.hass}" .config="${this._config}">
|
||||
<div>
|
||||
${stateObj.attributes.mode === "slider"
|
||||
? html`
|
||||
<div class="flex">
|
||||
<ha-slider
|
||||
.dir="${this._computeRTLDirection}"
|
||||
.step="${Number(stateObj.attributes.step)}"
|
||||
.min="${Number(stateObj.attributes.min)}"
|
||||
.max="${Number(stateObj.attributes.max)}"
|
||||
.value="${Number(stateObj.state)}"
|
||||
pin
|
||||
@change="${this._selectedValueChanged}"
|
||||
ignore-bar-touch
|
||||
id="input"
|
||||
></ha-slider>
|
||||
<span class="state">
|
||||
${Number(stateObj.state)}
|
||||
${stateObj.attributes.unit_of_measurement}
|
||||
</span>
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<paper-input
|
||||
no-label-float
|
||||
auto-validate
|
||||
.pattern="[0-9]+([\\.][0-9]+)?"
|
||||
.step="${Number(stateObj.attributes.step)}"
|
||||
.min="${Number(stateObj.attributes.min)}"
|
||||
.max="${Number(stateObj.attributes.max)}"
|
||||
.value="${Number(stateObj.state)}"
|
||||
type="number"
|
||||
@change="${this._selectedValueChanged}"
|
||||
id="input"
|
||||
></paper-input>
|
||||
`}
|
||||
</div>
|
||||
</hui-generic-entity-row>
|
||||
`;
|
||||
}
|
||||
|
||||
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<void> {
|
||||
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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user