mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 10:16:46 +00:00
parent
8ca70ace4c
commit
1e72ffc0c2
1
src/common/dom/stop_propagation.ts
Normal file
1
src/common/dom/stop_propagation.ts
Normal file
@ -0,0 +1 @@
|
||||
export const stopPropagation = (ev) => ev.stopPropagation();
|
@ -1,6 +1,6 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
export const setOption = (
|
||||
export const setInputSelectOption = (
|
||||
hass: HomeAssistant,
|
||||
entity: string,
|
||||
option: string
|
||||
|
@ -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`
|
||||
<state-badge .stateObj="${stateObj}"></state-badge>
|
||||
<ha-paper-dropdown-menu
|
||||
selected-item-label="${stateObj.state}"
|
||||
@selected-item-label-changed="${this._selectedChanged}"
|
||||
label="${this._config.name || computeStateName(stateObj)}"
|
||||
.label=${this._config.name || computeStateName(stateObj)}
|
||||
.value=${stateObj.state}
|
||||
@iron-select=${this._selectedChanged}
|
||||
@click=${stopPropagation}
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
selected="${stateObj.attributes.options.indexOf(stateObj.state)}"
|
||||
>
|
||||
${repeat(
|
||||
stateObj.attributes.options,
|
||||
(option) =>
|
||||
html`
|
||||
<paper-item>${option}</paper-item>
|
||||
`
|
||||
<paper-listbox slot="dropdown-content">
|
||||
${stateObj.attributes.options.map(
|
||||
(option) => html`
|
||||
<paper-item>${option}</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</ha-paper-dropdown-menu>
|
||||
`;
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,12 @@ export interface PolymerChangedEvent<T> extends Event {
|
||||
};
|
||||
}
|
||||
|
||||
export interface PolymerIronSelectEvent<T> extends Event {
|
||||
detail: {
|
||||
item: T;
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
|
@ -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`
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
state-badge {
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
paper-dropdown-menu {
|
||||
display: block;
|
||||
margin-left: 53px;
|
||||
}
|
||||
|
||||
paper-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
${this.stateBadgeTemplate}
|
||||
<paper-dropdown-menu
|
||||
on-click="stopPropagation"
|
||||
selected-item-label="{{selectedOption}}"
|
||||
label="[[_computeStateName(stateObj)]]"
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
selected="[[computeSelected(stateObj)]]"
|
||||
>
|
||||
<template is="dom-repeat" items="[[stateObj.attributes.options]]">
|
||||
<paper-item>[[item]]</paper-item>
|
||||
</template>
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
`;
|
||||
}
|
||||
|
||||
static get stateBadgeTemplate() {
|
||||
return html`
|
||||
<state-badge state-obj="[[stateObj]]"></state-badge>
|
||||
`;
|
||||
}
|
||||
|
||||
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);
|
96
src/state-summary/state-card-input_select.ts
Normal file
96
src/state-summary/state-card-input_select.ts
Normal file
@ -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`
|
||||
<state-badge .stateObj=${this.stateObj}></state-badge>
|
||||
<paper-dropdown-menu-light
|
||||
.label=${computeStateName(this.stateObj)}
|
||||
.value="${this.stateObj.state}"
|
||||
@iron-select=${this._selectedOptionChanged}
|
||||
@click=${stopPropagation}
|
||||
>
|
||||
<paper-listbox slot="dropdown-content">
|
||||
${this.stateObj.attributes.options.map(
|
||||
(option) => html`
|
||||
<paper-item>${option}</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu-light>
|
||||
`;
|
||||
}
|
||||
|
||||
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<PaperItemElement>
|
||||
) {
|
||||
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;
|
||||
}
|
||||
}
|
@ -219,6 +219,12 @@ export type CameraEntity = HassEntityBase & {
|
||||
};
|
||||
};
|
||||
|
||||
export type InputSelectEntity = HassEntityBase & {
|
||||
attributes: HassEntityAttributeBase & {
|
||||
options: string[];
|
||||
};
|
||||
};
|
||||
|
||||
export interface Route {
|
||||
prefix: string;
|
||||
path: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user