diff --git a/src/common/dom/stop_propagation.ts b/src/common/dom/stop_propagation.ts new file mode 100644 index 0000000000..b04b2156c0 --- /dev/null +++ b/src/common/dom/stop_propagation.ts @@ -0,0 +1 @@ +export const stopPropagation = (ev) => ev.stopPropagation(); diff --git a/src/data/input-select.ts b/src/data/input-select.ts index 04a2176fa5..c119cd0290 100644 --- a/src/data/input-select.ts +++ b/src/data/input-select.ts @@ -1,6 +1,6 @@ import { HomeAssistant } from "../types"; -export const setOption = ( +export const setInputSelectOption = ( hass: HomeAssistant, entity: string, option: string diff --git a/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts index c068fe3179..3568196454 100644 --- a/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts @@ -8,7 +8,6 @@ import { customElement, PropertyValues, } from "lit-element"; -import { repeat } from "lit-html/directives/repeat"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; @@ -18,11 +17,12 @@ import "../components/hui-warning"; import computeStateName from "../../../common/entity/compute_state_name"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, InputSelectEntity } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; -import { setOption } from "../../../data/input-select"; +import { setInputSelectOption } from "../../../data/input-select"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import { forwardHaptic } from "../../../util/haptics"; +import { stopPropagation } from "../../../common/dom/stop_propagation"; @customElement("hui-input-select-entity-row") class HuiInputSelectEntityRow extends LitElement implements EntityRow { @@ -47,7 +47,9 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow { return html``; } - const stateObj = this.hass.states[this._config.entity]; + const stateObj = this.hass.states[this._config.entity] as + | InputSelectEntity + | undefined; if (!stateObj) { return html` @@ -64,26 +66,43 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow { return html` - - ${repeat( - stateObj.attributes.options, - (option) => - html` - ${option} - ` + + ${stateObj.attributes.options.map( + (option) => html` + ${option} + ` )} `; } + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + + if (!this.hass || !this._config) { + return; + } + + const stateObj = this.hass.states[this._config.entity] as + | InputSelectEntity + | undefined; + + if (!stateObj) { + return; + } + + // Update selected after rendering the items or else it won't work in Firefox + this.shadowRoot!.querySelector( + "paper-listbox" + )!.selected = stateObj.attributes.options.indexOf(stateObj.state); + } + static get styles(): CSSResult { return css` :host { @@ -94,22 +113,28 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow { margin-left: 16px; flex: 1; } + + paper-item { + cursor: pointer; + min-width: 200px; + } `; } private _selectedChanged(ev): void { - forwardHaptic(this, "light"); - // Selected Option will transition to '' before transitioning to new value const stateObj = this.hass!.states[this._config!.entity]; - if ( - !ev.target.selectedItem || - ev.target.selectedItem.innerText === "" || - ev.target.selectedItem.innerText === stateObj.state - ) { + const option = ev.detail.item.innerText; + if (option === stateObj.state) { return; } - setOption(this.hass!, stateObj.entity_id, ev.target.selectedItem.innerText); + forwardHaptic(this, "light"); + + setInputSelectOption( + this.hass!, + stateObj.entity_id, + ev.target.selectedItem.innerText + ); } } diff --git a/src/polymer-types.ts b/src/polymer-types.ts index 4432149176..4ffbf77df6 100644 --- a/src/polymer-types.ts +++ b/src/polymer-types.ts @@ -18,6 +18,12 @@ export interface PolymerChangedEvent extends Event { }; } +export interface PolymerIronSelectEvent extends Event { + detail: { + item: T; + }; +} + declare global { // for fire event interface HASSDomEvents { diff --git a/src/state-summary/state-card-input_select.js b/src/state-summary/state-card-input_select.js deleted file mode 100644 index 76e4667988..0000000000 --- a/src/state-summary/state-card-input_select.js +++ /dev/null @@ -1,96 +0,0 @@ -import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../components/entity/state-badge"; - -import computeStateName from "../common/entity/compute_state_name"; - -class StateCardInputSelect extends PolymerElement { - static get template() { - return html` - - - ${this.stateBadgeTemplate} - - - - - - `; - } - - static get stateBadgeTemplate() { - return html` - - `; - } - - static get properties() { - return { - hass: Object, - stateObj: Object, - inDialog: { - type: Boolean, - value: false, - }, - selectedOption: { - type: String, - observer: "selectedOptionChanged", - }, - }; - } - - _computeStateName(stateObj) { - return computeStateName(stateObj); - } - - computeSelected(stateObj) { - return stateObj.attributes.options.indexOf(stateObj.state); - } - - selectedOptionChanged(option) { - // Selected Option will transition to '' before transitioning to new value - if (option === "" || option === this.stateObj.state) { - return; - } - this.hass.callService("input_select", "select_option", { - option: option, - entity_id: this.stateObj.entity_id, - }); - } - - stopPropagation(ev) { - ev.stopPropagation(); - } -} -customElements.define("state-card-input_select", StateCardInputSelect); diff --git a/src/state-summary/state-card-input_select.ts b/src/state-summary/state-card-input_select.ts new file mode 100644 index 0000000000..19befdfb29 --- /dev/null +++ b/src/state-summary/state-card-input_select.ts @@ -0,0 +1,96 @@ +import { + LitElement, + customElement, + TemplateResult, + html, + CSSResult, + css, + property, + PropertyValues, +} from "lit-element"; +import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; +import "@polymer/paper-item/paper-item"; +// tslint:disable-next-line: no-duplicate-imports +import { PaperItemElement } from "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; + +import "../components/entity/state-badge"; + +import computeStateName from "../common/entity/compute_state_name"; +import { HomeAssistant, InputSelectEntity } from "../types"; +import { setInputSelectOption } from "../data/input-select"; +import { PolymerIronSelectEvent } from "../polymer-types"; +import { stopPropagation } from "../common/dom/stop_propagation"; + +@customElement("state-card-input_select") +class StateCardInputSelect extends LitElement { + @property() public hass!: HomeAssistant; + @property() public stateObj!: InputSelectEntity; + + protected render(): TemplateResult | void { + return html` + + + + ${this.stateObj.attributes.options.map( + (option) => html` + ${option} + ` + )} + + + `; + } + + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + // Update selected after rendering the items or else it won't work in Firefox + this.shadowRoot!.querySelector( + "paper-listbox" + )!.selected = this.stateObj.attributes.options.indexOf(this.stateObj.state); + } + + private async _selectedOptionChanged( + ev: PolymerIronSelectEvent + ) { + const option = ev.detail.item.innerText; + if (option === this.stateObj.state) { + return; + } + await setInputSelectOption(this.hass, this.stateObj.entity_id, option); + } + + static get styles(): CSSResult { + return css` + :host { + display: block; + } + + state-badge { + float: left; + margin-top: 10px; + } + + paper-dropdown-menu-light { + display: block; + margin-left: 53px; + } + + paper-item { + cursor: pointer; + min-width: 200px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "state-card-input_select": StateCardInputSelect; + } +} diff --git a/src/types.ts b/src/types.ts index e312a1f6b9..9a5a731a3b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -219,6 +219,12 @@ export type CameraEntity = HassEntityBase & { }; }; +export type InputSelectEntity = HassEntityBase & { + attributes: HassEntityAttributeBase & { + options: string[]; + }; +}; + export interface Route { prefix: string; path: string;