mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-02 00:27:49 +01:00
167 lines
4.5 KiB
TypeScript
167 lines
4.5 KiB
TypeScript
import type { HassEntity } from "home-assistant-js-websocket";
|
|
import type { TemplateResult } from "lit";
|
|
import { css, html, LitElement, nothing } from "lit";
|
|
import { customElement, property } from "lit/decorators";
|
|
import { debounce } from "../common/util/debounce";
|
|
import "../components/entity/state-info";
|
|
import "../components/ha-slider";
|
|
import "../components/input/ha-input";
|
|
import { isUnavailableState } from "../data/entity/entity";
|
|
import { setValue } from "../data/input_text";
|
|
import type { HomeAssistant } from "../types";
|
|
|
|
@customElement("state-card-input_number")
|
|
class StateCardInputNumber extends LitElement {
|
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
|
|
@property({ attribute: false }) public stateObj!: HassEntity;
|
|
|
|
@property({ attribute: "in-dialog", 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 {
|
|
super.disconnectedCallback();
|
|
this._resizeObserver?.disconnect();
|
|
}
|
|
|
|
protected firstUpdated(): void {
|
|
this._updated = true;
|
|
if (this.isConnected && !this._loaded) {
|
|
this._initialLoad();
|
|
}
|
|
this._attachObserver();
|
|
}
|
|
|
|
protected render(): TemplateResult {
|
|
return html`
|
|
<state-info
|
|
.hass=${this.hass}
|
|
.stateObj=${this.stateObj}
|
|
.inDialog=${this.inDialog}
|
|
></state-info>
|
|
${this.stateObj.attributes.mode === "slider"
|
|
? html`
|
|
<div class="flex">
|
|
<ha-slider
|
|
labeled
|
|
.disabled=${isUnavailableState(this.stateObj.state)}
|
|
.step=${Number(this.stateObj.attributes.step)}
|
|
.min=${Number(this.stateObj.attributes.min)}
|
|
.max=${Number(this.stateObj.attributes.max)}
|
|
.value=${this.stateObj.state}
|
|
@change=${this._selectedValueChanged}
|
|
></ha-slider>
|
|
<span class="state">
|
|
${this.hass.formatEntityState(this.stateObj)}
|
|
</span>
|
|
</div>
|
|
`
|
|
: html`
|
|
<div class="flex state">
|
|
<ha-input
|
|
.disabled=${isUnavailableState(this.stateObj.state)}
|
|
pattern="[0-9]+([\\.][0-9]+)?"
|
|
.step=${Number(this.stateObj.attributes.step)}
|
|
.min=${Number(this.stateObj.attributes.min)}
|
|
.max=${Number(this.stateObj.attributes.max)}
|
|
.value=${Number(this.stateObj.state).toString()}
|
|
type="number"
|
|
@change=${this._selectedValueChanged}
|
|
>
|
|
${this.stateObj.attributes.unit_of_measurement
|
|
? html`<span slot="end"
|
|
>${this.stateObj.attributes.unit_of_measurement}</span
|
|
>`
|
|
: nothing}
|
|
</ha-input>
|
|
</div>
|
|
`}
|
|
`;
|
|
}
|
|
|
|
static styles = 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-input::part(wa-input) {
|
|
text-align: end;
|
|
}
|
|
ha-slider {
|
|
width: 100%;
|
|
max-width: 200px;
|
|
}
|
|
@media (max-width: 450px) {
|
|
state-info {
|
|
flex-basis: 60%;
|
|
}
|
|
}
|
|
`;
|
|
|
|
private async _initialLoad(): Promise<void> {
|
|
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<void> {
|
|
if (!this._resizeObserver) {
|
|
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;
|
|
}
|
|
}
|