Light More Info: Convert to Lit Element (#6592)

* Update more info

* Remove is unavailable

* Remove divs

* updates

* Update src/dialogs/more-info/controls/more-info-light.ts

* Update src/dialogs/more-info/controls/more-info-light.ts

Co-authored-by: Bram Kragten <mail@bramkragten.nl>

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
Zack Arnett 2020-08-17 09:07:29 -05:00 committed by GitHub
parent 613470b44d
commit 21644ec889
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 311 additions and 361 deletions

View File

@ -1,361 +0,0 @@
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { featureClassNames } from "../../../common/entity/feature_class_names";
import "../../../components/ha-attributes";
import "../../../components/ha-color-picker";
import "../../../components/ha-labeled-slider";
import "../../../components/ha-paper-dropdown-menu";
import { EventsMixin } from "../../../mixins/events-mixin";
import LocalizeMixin from "../../../mixins/localize-mixin";
import "../../../components/ha-icon-button";
const FEATURE_CLASS_NAMES = {
1: "has-brightness",
2: "has-color_temp",
4: "has-effect_list",
16: "has-color",
128: "has-white_value",
};
/*
* @appliesMixin EventsMixin
*/
class MoreInfoLight extends LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<style include="iron-flex"></style>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
}
.effect_list,
.brightness,
.color_temp,
.white_value {
max-height: 0px;
overflow: hidden;
transition: max-height 0.5s ease-in;
}
.color_temp {
--ha-slider-background: -webkit-linear-gradient(
right,
rgb(255, 160, 0) 0%,
white 50%,
rgb(166, 209, 255) 100%
);
/* The color temp minimum value shouldn't be rendered differently. It's not "off". */
--paper-slider-knob-start-border-color: var(--primary-color);
}
.segmentationContainer {
position: relative;
}
ha-color-picker {
display: block;
width: 100%;
max-height: 0px;
overflow: hidden;
transition: max-height 0.5s ease-in;
}
.segmentationButton {
display: none;
position: absolute;
top: 5%;
transform: translate(0%, 0%);
color: var(--secondary-text-color);
}
.has-color.is-on .segmentationButton {
display: inline-block;
}
.has-effect_list.is-on .effect_list,
.has-brightness .brightness,
.has-color_temp.is-on .color_temp,
.has-white_value.is-on .white_value {
max-height: 84px;
}
.has-brightness .has-color_temp.is-on,
.has-white_value.is-on {
margin-top: -16px;
}
.has-brightness .brightness,
.has-color_temp.is-on .color_temp,
.has-white_value.is-on .white_value {
padding-top: 16px;
}
.has-color.is-on ha-color-picker {
max-height: 500px;
overflow: visible;
--ha-color-picker-wheel-borderwidth: 5;
--ha-color-picker-wheel-bordercolor: white;
--ha-color-picker-wheel-shadow: none;
--ha-color-picker-marker-borderwidth: 2;
--ha-color-picker-marker-bordercolor: white;
}
.control {
width: 100%;
}
.is-unavailable .control {
max-height: 0px;
}
ha-attributes {
width: 100%;
}
ha-paper-dropdown-menu {
width: 100%;
}
paper-item {
cursor: pointer;
}
</style>
<div class$="[[computeClassNames(stateObj)]]">
<div class="control brightness">
<ha-labeled-slider
caption="[[localize('ui.card.light.brightness')]]"
icon="hass:brightness-5"
min="1"
max="255"
value="{{brightnessSliderValue}}"
on-change="brightnessSliderChanged"
></ha-labeled-slider>
</div>
<div class="control color_temp">
<ha-labeled-slider
caption="[[localize('ui.card.light.color_temperature')]]"
icon="hass:thermometer"
min="[[stateObj.attributes.min_mireds]]"
max="[[stateObj.attributes.max_mireds]]"
value="{{ctSliderValue}}"
on-change="ctSliderChanged"
></ha-labeled-slider>
</div>
<div class="control white_value">
<ha-labeled-slider
caption="[[localize('ui.card.light.white_value')]]"
icon="hass:file-word-box"
max="255"
value="{{wvSliderValue}}"
on-change="wvSliderChanged"
></ha-labeled-slider>
</div>
<div class="segmentationContainer">
<ha-color-picker
class="control color"
on-colorselected="colorPicked"
desired-hs-color="{{colorPickerColor}}"
throttle="500"
hue-segments="{{hueSegments}}"
saturation-segments="{{saturationSegments}}"
>
</ha-color-picker>
<ha-icon-button
icon="mdi:palette"
on-click="segmentClick"
class="segmentationButton"
></ha-icon-button>
</div>
<div class="control effect_list">
<ha-paper-dropdown-menu
label-float=""
dynamic-align=""
label="[[localize('ui.card.light.effect')]]"
>
<paper-listbox
slot="dropdown-content"
selected="[[stateObj.attributes.effect]]"
on-selected-changed="effectChanged"
attr-for-selected="item-name"
>
<template
is="dom-repeat"
items="[[stateObj.attributes.effect_list]]"
>
<paper-item item-name$="[[item]]">[[item]]</paper-item>
</template>
</paper-listbox>
</ha-paper-dropdown-menu>
</div>
<ha-attributes
state-obj="[[stateObj]]"
extra-filters="brightness,color_temp,white_value,effect_list,effect,hs_color,rgb_color,xy_color,min_mireds,max_mireds,entity_id"
></ha-attributes>
</div>
`;
}
static get properties() {
return {
hass: {
type: Object,
},
stateObj: {
type: Object,
observer: "stateObjChanged",
},
brightnessSliderValue: {
type: Number,
value: 0,
},
ctSliderValue: {
type: Number,
value: 0,
},
wvSliderValue: {
type: Number,
value: 0,
},
hueSegments: {
type: Number,
value: 24,
},
saturationSegments: {
type: Number,
value: 8,
},
colorPickerColor: {
type: Object,
},
};
}
stateObjChanged(newVal, oldVal) {
const props = {
brightnessSliderValue: 0,
};
if (newVal && newVal.state === "on") {
props.brightnessSliderValue = newVal.attributes.brightness;
props.ctSliderValue = newVal.attributes.color_temp;
props.wvSliderValue = newVal.attributes.white_value;
if (newVal.attributes.hs_color) {
props.colorPickerColor = {
h: newVal.attributes.hs_color[0],
s: newVal.attributes.hs_color[1] / 100,
};
}
}
this.setProperties(props);
if (oldVal) {
setTimeout(() => {
this.fire("iron-resize");
}, 500);
}
}
computeClassNames(stateObj) {
const classes = [
"content",
featureClassNames(stateObj, FEATURE_CLASS_NAMES),
];
if (stateObj && stateObj.state === "on") {
classes.push("is-on");
}
if (stateObj && stateObj.state === "unavailable") {
classes.push("is-unavailable");
}
return classes.join(" ");
}
effectChanged(ev) {
const oldVal = this.stateObj.attributes.effect;
const newVal = ev.detail.value;
if (!newVal || oldVal === newVal) return;
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj.entity_id,
effect: newVal,
});
}
brightnessSliderChanged(ev) {
const bri = parseInt(ev.target.value, 10);
if (isNaN(bri)) return;
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj.entity_id,
brightness: bri,
});
}
ctSliderChanged(ev) {
const ct = parseInt(ev.target.value, 10);
if (isNaN(ct)) return;
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj.entity_id,
color_temp: ct,
});
}
wvSliderChanged(ev) {
const wv = parseInt(ev.target.value, 10);
if (isNaN(wv)) return;
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj.entity_id,
white_value: wv,
});
}
segmentClick() {
if (this.hueSegments === 24 && this.saturationSegments === 8) {
this.setProperties({ hueSegments: 0, saturationSegments: 0 });
} else {
this.setProperties({ hueSegments: 24, saturationSegments: 8 });
}
}
serviceChangeColor(hass, entityId, color) {
hass.callService("light", "turn_on", {
entity_id: entityId,
hs_color: [color.h, color.s * 100],
});
}
/**
* Called when a new color has been picked.
* should be throttled with the 'throttle=' attribute of the color picker
*/
colorPicked(ev) {
this.serviceChangeColor(this.hass, this.stateObj.entity_id, ev.detail.hs);
}
}
customElements.define("more-info-light", MoreInfoLight);

View File

@ -0,0 +1,307 @@
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
internalProperty,
PropertyValues,
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import {
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR_TEMP,
SUPPORT_WHITE_VALUE,
SUPPORT_COLOR,
SUPPORT_EFFECT,
} from "../../../data/light";
import { supportsFeature } from "../../../common/entity/supports-feature";
import type { HomeAssistant, LightEntity } from "../../../types";
import "../../../components/ha-attributes";
import "../../../components/ha-color-picker";
import "../../../components/ha-labeled-slider";
import "../../../components/ha-icon-button";
import "../../../components/ha-paper-dropdown-menu";
interface HueSatColor {
h: number;
s: number;
}
@customElement("more-info-light")
class MoreInfoLight extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public stateObj?: LightEntity;
@internalProperty() private _brightnessSliderValue = 0;
@internalProperty() private _ctSliderValue = 0;
@internalProperty() private _wvSliderValue = 0;
@internalProperty() private _hueSegments = 24;
@internalProperty() private _saturationSegments = 8;
@internalProperty() private _colorPickerColor?: HueSatColor;
protected render(): TemplateResult {
if (!this.hass || !this.stateObj) {
return html``;
}
return html`
<div
class="content ${classMap({
"is-on": this.stateObj.state === "on",
})}"
>
${this.stateObj.state === "on"
? html`
${supportsFeature(this.stateObj!, SUPPORT_BRIGHTNESS)
? html`
<ha-labeled-slider
caption=${this.hass.localize("ui.card.light.brightness")}
icon="hass:brightness-5"
min="1"
max="255"
value=${this._brightnessSliderValue}
@change=${this._brightnessSliderChanged}
></ha-labeled-slider>
`
: ""}
${supportsFeature(this.stateObj, SUPPORT_COLOR_TEMP)
? html`
<ha-labeled-slider
class="color_temp"
caption=${this.hass.localize(
"ui.card.light.color_temperature"
)}
icon="hass:thermometer"
.min=${this.stateObj.attributes.min_mireds}
.max=${this.stateObj.attributes.max_mireds}
.value=${this._ctSliderValue}
@change=${this._ctSliderChanged}
></ha-labeled-slider>
`
: ""}
${supportsFeature(this.stateObj, SUPPORT_WHITE_VALUE)
? html`
<ha-labeled-slider
caption=${this.hass.localize("ui.card.light.white_value")}
icon="hass:file-word-box"
max="255"
.value=${this._wvSliderValue}
@change=${this._wvSliderChanged}
></ha-labeled-slider>
`
: ""}
${supportsFeature(this.stateObj, SUPPORT_COLOR)
? html`
<div class="segmentationContainer">
<ha-color-picker
class="color"
@colorselected=${this._colorPicked}
.desiredHsColor=${this._colorPickerColor}
throttle="500"
.hueSegments=${this._hueSegments}
.saturationSegments=${this._saturationSegments}
>
</ha-color-picker>
<ha-icon-button
icon="hass:palette"
@click=${this._segmentClick}
class="segmentationButton"
></ha-icon-button>
</div>
`
: ""}
${supportsFeature(this.stateObj, SUPPORT_EFFECT) &&
this.stateObj!.attributes.effect_list?.length
? html`
<ha-paper-dropdown-menu
.label=${this.hass.localize("ui.card.light.effect")}
>
<paper-listbox
slot="dropdown-content"
.selected=${this.stateObj.attributes.effect || ""}
@iron-select=${this._effectChanged}
attr-for-selected="item-name"
>${this.stateObj.attributes.effect_list.map(
(effect: string) => html`
<paper-item itemName=${effect}
>${effect}</paper-item
>
`
)}
</paper-listbox>
</ha-paper-dropdown-menu>
`
: ""}
`
: ""}
<ha-attributes
.stateObj=${this.stateObj}
extraFilters="brightness,color_temp,white_value,effect_list,effect,hs_color,rgb_color,xy_color,min_mireds,max_mireds,entity_id"
></ha-attributes>
</div>
`;
}
protected updated(changedProps: PropertyValues): void {
const stateObj = this.stateObj! as LightEntity;
if (changedProps.has("stateObj") && stateObj.state === "on") {
this._brightnessSliderValue = stateObj.attributes.brightness;
this._ctSliderValue = stateObj.attributes.color_temp;
this._wvSliderValue = stateObj.attributes.white_value;
if (stateObj.attributes.hs_color) {
this._colorPickerColor = {
h: stateObj.attributes.hs_color[0],
s: stateObj.attributes.hs_color[1] / 100,
};
}
}
}
private _effectChanged(ev: CustomEvent) {
const newVal = ev.detail.value;
if (!newVal || this.stateObj!.attributes.effect === newVal) {
return;
}
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
effect: newVal,
});
}
private _brightnessSliderChanged(ev: CustomEvent) {
const bri = parseInt((ev.target as any).value, 10);
if (isNaN(bri)) {
return;
}
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
brightness: bri,
});
}
private _ctSliderChanged(ev: CustomEvent) {
const ct = parseInt((ev.target as any).value, 10);
if (isNaN(ct)) {
return;
}
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
color_temp: ct,
});
}
private _wvSliderChanged(ev: CustomEvent) {
const wv = parseInt((ev.target as any).value, 10);
if (isNaN(wv)) {
return;
}
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
white_value: wv,
});
}
private _segmentClick() {
if (this._hueSegments === 24 && this._saturationSegments === 8) {
this._hueSegments = 0;
this._saturationSegments = 0;
} else {
this._hueSegments = 24;
this._saturationSegments = 8;
}
}
/**
* Called when a new color has been picked.
* should be throttled with the 'throttle=' attribute of the color picker
*/
private _colorPicked(ev: CustomEvent) {
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
hs_color: [ev.detail.hs.h, ev.detail.hs.s * 100],
});
}
static get styles(): CSSResult {
return css`
.content {
display: flex;
flex-direction: column;
align-items: center;
}
.content.is-on {
margin-top: -16px;
}
.content > * {
width: 100%;
max-height: 84px;
overflow: hidden;
padding-top: 16px;
}
.color_temp {
--ha-slider-background: -webkit-linear-gradient(
right,
rgb(255, 160, 0) 0%,
white 50%,
rgb(166, 209, 255) 100%
);
/* The color temp minimum value shouldn't be rendered differently. It's not "off". */
--paper-slider-knob-start-border-color: var(--primary-color);
}
.segmentationContainer {
position: relative;
max-height: 500px;
}
ha-color-picker {
--ha-color-picker-wheel-borderwidth: 5;
--ha-color-picker-wheel-bordercolor: white;
--ha-color-picker-wheel-shadow: none;
--ha-color-picker-marker-borderwidth: 2;
--ha-color-picker-marker-bordercolor: white;
}
.segmentationButton {
position: absolute;
top: 5%;
color: var(--secondary-text-color);
}
paper-item {
cursor: pointer;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"more-info-light": MoreInfoLight;
}
}

View File

@ -254,6 +254,10 @@ export type LightEntity = HassEntityBase & {
friendly_name: string;
brightness: number;
hs_color: number[];
color_temp: number;
white_value: number;
effect?: string;
effect_list: string[] | null;
};
};