mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-29 20:26: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";
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
export const setValue = (hass: HomeAssistant, entity: string, value: string) =>
|
export const setValue = (hass: HomeAssistant, entity: string, value: string) =>
|
||||||
hass.callService("input_text", "set_value", {
|
hass.callService(entity.split(".", 1)[0], "set_value", {
|
||||||
value,
|
value,
|
||||||
entity_id: entity,
|
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