diff --git a/src/dialogs/more-info/controls/more-info-light.js b/src/dialogs/more-info/controls/more-info-light.js deleted file mode 100644 index 0362e44822..0000000000 --- a/src/dialogs/more-info/controls/more-info-light.js +++ /dev/null @@ -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` - - - -
-
- -
- -
- -
- -
- -
-
- - - -
- -
- - - - - -
- - -
- `; - } - - 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); diff --git a/src/dialogs/more-info/controls/more-info-light.ts b/src/dialogs/more-info/controls/more-info-light.ts new file mode 100644 index 0000000000..3abab21a99 --- /dev/null +++ b/src/dialogs/more-info/controls/more-info-light.ts @@ -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` +
+ ${this.stateObj.state === "on" + ? html` + ${supportsFeature(this.stateObj!, SUPPORT_BRIGHTNESS) + ? html` + + ` + : ""} + ${supportsFeature(this.stateObj, SUPPORT_COLOR_TEMP) + ? html` + + ` + : ""} + ${supportsFeature(this.stateObj, SUPPORT_WHITE_VALUE) + ? html` + + ` + : ""} + ${supportsFeature(this.stateObj, SUPPORT_COLOR) + ? html` +
+ + + +
+ ` + : ""} + ${supportsFeature(this.stateObj, SUPPORT_EFFECT) && + this.stateObj!.attributes.effect_list?.length + ? html` + + ${this.stateObj.attributes.effect_list.map( + (effect: string) => html` + ${effect} + ` + )} + + + ` + : ""} + ` + : ""} + +
+ `; + } + + 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; + } +} diff --git a/src/types.ts b/src/types.ts index 57a945a993..4b0af2a890 100644 --- a/src/types.ts +++ b/src/types.ts @@ -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; }; };