diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts
index 26c0d4b707..2386fa8d1a 100644
--- a/src/panels/lovelace/components/hui-card-options.ts
+++ b/src/panels/lovelace/components/hui-card-options.ts
@@ -14,9 +14,9 @@ import { swapCard, moveCard } from "../editor/config-util";
export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
public cardConfig?: LovelaceCardConfig;
- protected hass?: HomeAssistant;
- protected lovelace?: Lovelace;
- protected path?: [number, number];
+ public hass?: HomeAssistant;
+ public lovelace?: Lovelace;
+ public path?: [number, number];
static get properties(): PropertyDeclarations {
return { hass: {}, lovelace: {}, path: {} };
diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts
index a18cbb3dfd..f794001823 100644
--- a/src/panels/lovelace/hui-root.ts
+++ b/src/panels/lovelace/hui-root.ts
@@ -38,6 +38,9 @@ import "./components/notifications/hui-notification-drawer";
import "./components/notifications/hui-notifications-button";
import "./hui-unused-entities";
import "./hui-view";
+// Not a duplicate import, this one is for type
+// tslint:disable-next-line
+import { HUIView } from "./hui-view";
import createCardElement from "./common/create-card-element";
import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog";
import { Lovelace } from "./types";
@@ -336,10 +339,10 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
super.updated(changedProperties);
const view = this._view;
- const huiView = view.lastChild as any;
+ const huiView = view.lastChild as HUIView;
if (changedProperties.has("columns") && huiView) {
- (this._view.lastChild as any).columns = this.columns;
+ huiView.columns = this.columns;
}
if (changedProperties.has("hass") && huiView) {
diff --git a/src/panels/lovelace/hui-view.js b/src/panels/lovelace/hui-view.ts
similarity index 54%
rename from src/panels/lovelace/hui-view.js
rename to src/panels/lovelace/hui-view.ts
index e068eee53e..52093225a1 100644
--- a/src/panels/lovelace/hui-view.js
+++ b/src/panels/lovelace/hui-view.ts
@@ -1,20 +1,75 @@
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
+import {
+ html,
+ LitElement,
+ PropertyValues,
+ PropertyDeclarations,
+} from "@polymer/lit-element";
+import { TemplateResult } from "lit-html";
+import { PolymerElement } from "@polymer/polymer";
import "../../components/entity/ha-state-label-badge";
import applyThemesOnElement from "../../common/dom/apply_themes_on_element";
-import EventsMixin from "../../mixins/events-mixin";
-import localizeMixin from "../../mixins/localize-mixin";
+import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin";
+import { LovelaceViewConfig } from "../../data/lovelace";
+import { HomeAssistant } from "../../types";
+
+import { Lovelace, LovelaceCard } from "./types";
import createCardElement from "./common/create-card-element";
import { computeCardSize } from "./common/compute-card-size";
import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog";
let editCodeLoaded = false;
-class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
- static get template() {
+export class HUIView extends hassLocalizeLitMixin(LitElement) {
+ public hass?: HomeAssistant;
+ public lovelace?: Lovelace;
+ public columns?: number;
+ public index?: number;
+ private _cards: LovelaceCard[];
+ private _badges: Array<{ element: PolymerElement; entityId: string }>;
+
+ static get properties(): PropertyDeclarations {
+ return {
+ hass: {},
+ lovelace: {},
+ columns: {},
+ index: {},
+ _cards: {},
+ _badges: {},
+ };
+ }
+
+ constructor() {
+ super();
+ this._cards = [];
+ this._badges = [];
+ }
+
+ protected render(): TemplateResult {
+ return html`
+ ${this.renderStyles()}
+
+
+ ${
+ this.lovelace!.editMode
+ ? html`
+
+ `
+ : ""
+ }
+ `;
+ }
+
+ protected renderStyles(): TemplateResult {
return html`
-
-
-
`;
}
- static get properties() {
- return {
- hass: {
- type: Object,
- observer: "_hassChanged",
- },
- lovelace: {
- type: Object,
- observer: "_lovelaceChanged",
- },
- config: Object,
- columns: Number,
- editMode: Boolean,
- index: Number,
- };
+ protected updated(changedProperties: PropertyValues): void {
+ super.updated(changedProperties);
+
+ const lovelace = this.lovelace!;
+
+ if (lovelace.editMode && !editCodeLoaded) {
+ editCodeLoaded = true;
+ import(/* webpackChunkName: "hui-view-editable" */ "./hui-view-editable");
+ }
+
+ let editModeChanged = false;
+ let configChanged = false;
+
+ if (changedProperties.has("lovelace")) {
+ const oldLovelace = changedProperties.get("lovelace") as Lovelace;
+ editModeChanged =
+ !oldLovelace || lovelace.editMode !== oldLovelace.editMode;
+ configChanged = !oldLovelace || lovelace.config !== oldLovelace.config;
+ }
+
+ if (configChanged) {
+ this._createBadges(lovelace.config.views[this.index!]);
+ } else if (changedProperties.has("hass")) {
+ this._badges.forEach((badge) => {
+ const { element, entityId } = badge;
+ element.setProperties({
+ hass: this.hass,
+ state: this.hass!.states[entityId],
+ });
+ });
+ }
+
+ if (configChanged || editModeChanged || changedProperties.has("columns")) {
+ this._createCards(lovelace.config.views[this.index!]);
+ } else if (changedProperties.has("hass")) {
+ this._cards.forEach((element) => {
+ element.hass = this.hass;
+ });
+ }
}
- static get observers() {
- return [
- // Put all properties in 1 observer so we only call configChanged once
- "_createBadges(config)",
- "_createCards(config, columns, editMode)",
- ];
- }
-
- constructor() {
- super();
- this._cards = [];
- this._badges = [];
- }
-
- _addCard() {
+ private _addCard(): void {
showEditCardDialog(this, {
- lovelace: this.lovelace,
- path: [this.index],
+ lovelace: this.lovelace!,
+ path: [this.index!],
});
}
- _createBadges(config) {
- const root = this.$.badges;
+ private _createBadges(config: LovelaceViewConfig): void {
+ const root = this.shadowRoot!.getElementById("badges")!;
+
while (root.lastChild) {
root.removeChild(root.lastChild);
}
@@ -141,14 +194,18 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
return;
}
- const elements = [];
+ const elements: HUIView["_badges"] = [];
for (const entityId of config.badges) {
- if (!(entityId in this.hass.states)) continue;
+ if (!(entityId in this.hass!.states)) {
+ continue;
+ }
- const element = document.createElement("ha-state-label-badge");
+ const element = document.createElement(
+ "ha-state-label-badge"
+ ) as PolymerElement;
element.setProperties({
hass: this.hass,
- state: this.hass.states[entityId],
+ state: this.hass!.states[entityId],
});
elements.push({ element, entityId });
root.appendChild(element);
@@ -157,8 +214,8 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
root.style.display = elements.length > 0 ? "block" : "none";
}
- _createCards(config) {
- const root = this.$.columns;
+ private _createCards(config: LovelaceViewConfig): void {
+ const root = this.shadowRoot!.getElementById("columns")!;
while (root.lastChild) {
root.removeChild(root.lastChild);
@@ -169,14 +226,14 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
return;
}
- const elements = [];
- const elementsToAppend = [];
+ const elements: LovelaceCard[] = [];
+ const elementsToAppend: HTMLElement[] = [];
config.cards.forEach((cardConfig, cardIndex) => {
- const element = createCardElement(cardConfig);
+ const element = createCardElement(cardConfig) as LovelaceCard;
element.hass = this.hass;
elements.push(element);
- if (!this.lovelace.editMode) {
+ if (!this.lovelace!.editMode) {
elementsToAppend.push(element);
return;
}
@@ -184,14 +241,14 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
const wrapper = document.createElement("hui-card-options");
wrapper.hass = this.hass;
wrapper.lovelace = this.lovelace;
- wrapper.path = [this.index, cardIndex];
+ wrapper.path = [this.index!, cardIndex];
wrapper.appendChild(element);
elementsToAppend.push(wrapper);
});
- let columns = [];
- const columnEntityCount = [];
- for (let i = 0; i < this.columns; i++) {
+ let columns: HTMLElement[][] = [];
+ const columnEntityCount: number[] = [];
+ for (let i = 0; i < this.columns!; i++) {
columns.push([]);
columnEntityCount.push(0);
}
@@ -233,29 +290,15 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
this._cards = elements;
if ("theme" in config) {
- applyThemesOnElement(root, this.hass.themes, config.theme);
- }
- }
-
- _hassChanged(hass) {
- this._badges.forEach((badge) => {
- const { element, entityId } = badge;
- element.setProperties({
- hass,
- state: hass.states[entityId],
- });
- });
- this._cards.forEach((element) => {
- element.hass = hass;
- });
- }
-
- _lovelaceChanged(lovelace) {
- if (lovelace.editMode && !editCodeLoaded) {
- editCodeLoaded = true;
- import(/* webpackChunkName: "hui-view-editable" */ "./hui-view-editable");
+ applyThemesOnElement(root, this.hass!.themes, config.theme);
}
}
}
+declare global {
+ interface HTMLElementTagNameMap {
+ "hui-view": HUIView;
+ }
+}
+
customElements.define("hui-view", HUIView);
diff --git a/test-mocha/panels/lovelace/editor/config-util.spec.ts b/test-mocha/panels/lovelace/editor/config-util.spec.ts
index dac981de04..fc417e2ca1 100644
--- a/test-mocha/panels/lovelace/editor/config-util.spec.ts
+++ b/test-mocha/panels/lovelace/editor/config-util.spec.ts
@@ -119,7 +119,7 @@ describe("moveCard", () => {
],
};
- const result = function() {
+ const result = () => {
moveCard(config, [1, 0], [1]);
};
assert.throws(