mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-19 19:07:23 +00:00
Move card loading logic into hui-card (#21018)
* Move card rebuild to hui-card * Use hui card in stack card * add once to event * Do not use state * Use hui card in conditional card * Use editMode instead of lovelace in hui card * Fix edit mode * Use hui-card in card dialog and panel todo * Fix edit mode * Fix types * Migrate entity filter card * Update demo card * Fix UI view * Allow edit mode attribute * Remove unused condition * Remove unused section preview code * Remove useless check for config
This commit is contained in:
parent
a497f42f73
commit
433c00b73a
@ -1,8 +1,9 @@
|
||||
import "@material/mwc-button";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { until } from "lit/directives/until";
|
||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||
import "../../../src/components/ha-card";
|
||||
import "../../../src/components/ha-button";
|
||||
import "../../../src/components/ha-circular-progress";
|
||||
import { LovelaceCardConfig } from "../../../src/data/lovelace/config/card";
|
||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
@ -11,7 +12,6 @@ import {
|
||||
demoConfigs,
|
||||
selectedDemoConfig,
|
||||
selectedDemoConfigIndex,
|
||||
setDemoConfig,
|
||||
} from "../configs/demo-configs";
|
||||
|
||||
@customElement("ha-demo-card")
|
||||
@ -64,9 +64,9 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<mwc-button @click=${this._nextConfig} .disabled=${this._switching}>
|
||||
<ha-button @click=${this._nextConfig} .disabled=${this._switching}>
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.next_demo")}
|
||||
</mwc-button>
|
||||
</ha-button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="small-hidden">
|
||||
@ -87,9 +87,9 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
</div>
|
||||
<div class="actions small-hidden">
|
||||
<a href="https://www.home-assistant.io" target="_blank">
|
||||
<mwc-button>
|
||||
<ha-button>
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.learn_more")}
|
||||
</mwc-button>
|
||||
</ha-button>
|
||||
</a>
|
||||
</div>
|
||||
</ha-card>
|
||||
@ -113,13 +113,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
|
||||
private async _updateConfig(index: number) {
|
||||
this._switching = true;
|
||||
try {
|
||||
await setDemoConfig(this.hass, this.lovelace!, index);
|
||||
} catch (err: any) {
|
||||
alert("Failed to switch config :-(");
|
||||
} finally {
|
||||
this._switching = false;
|
||||
}
|
||||
fireEvent(this, "set-demo-config" as any, { index });
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
@ -149,7 +143,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.picker mwc-button {
|
||||
.picker ha-button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
import type { LocalizeFunc } from "../../../src/common/translations/localize";
|
||||
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
import { selectedDemoConfig } from "../configs/demo-configs";
|
||||
import {
|
||||
selectedDemoConfig,
|
||||
selectedDemoConfigIndex,
|
||||
setDemoConfig,
|
||||
} from "../configs/demo-configs";
|
||||
import "../custom-cards/cast-demo-row";
|
||||
import "../custom-cards/ha-demo-card";
|
||||
import type { HADemoCard } from "../custom-cards/ha-demo-card";
|
||||
|
||||
export const mockLovelace = (
|
||||
hass: MockHomeAssistant,
|
||||
@ -19,17 +22,22 @@ export const mockLovelace = (
|
||||
hass.mockWS("lovelace/resources", () => Promise.resolve([]));
|
||||
};
|
||||
|
||||
customElements.whenDefined("hui-card").then(() => {
|
||||
customElements.whenDefined("hui-root").then(() => {
|
||||
// eslint-disable-next-line
|
||||
const HUIView = customElements.get("hui-card");
|
||||
// Patch HUI-VIEW to make the lovelace object available to the demo card
|
||||
const oldCreateCard = HUIView!.prototype.createElement;
|
||||
const HUIRoot = customElements.get("hui-root")!;
|
||||
|
||||
HUIView!.prototype.createElement = function (config) {
|
||||
const el = oldCreateCard.call(this, config);
|
||||
if (config.type === "custom:ha-demo-card") {
|
||||
(el as HADemoCard).lovelace = this.lovelace;
|
||||
}
|
||||
return el;
|
||||
const oldFirstUpdated = HUIRoot.prototype.firstUpdated;
|
||||
|
||||
HUIRoot.prototype.firstUpdated = function (changedProperties) {
|
||||
oldFirstUpdated.call(this, changedProperties);
|
||||
this.addEventListener("set-demo-config", async (ev) => {
|
||||
const index = (ev as CustomEvent).detail.index;
|
||||
try {
|
||||
await setDemoConfig(this.hass, this.lovelace!, index);
|
||||
} catch (err: any) {
|
||||
setDemoConfig(this.hass, this.lovelace!, selectedDemoConfigIndex);
|
||||
alert("Failed to switch config :-(");
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { load } from "js-yaml";
|
||||
import { html, css, LitElement, PropertyValues } from "lit";
|
||||
import { LitElement, PropertyValueMap, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { createCardElement } from "../../../src/panels/lovelace/create-element/create-card-element";
|
||||
import memoizeOne from "memoize-one";
|
||||
import "../../../src/panels/lovelace/cards/hui-card";
|
||||
import type { HuiCard } from "../../../src/panels/lovelace/cards/hui-card";
|
||||
import { HomeAssistant } from "../../../src/types";
|
||||
|
||||
export interface DemoCardConfig {
|
||||
@ -19,7 +21,12 @@ class DemoCard extends LitElement {
|
||||
|
||||
@state() private _size?: number;
|
||||
|
||||
@query("#card") private _card!: HTMLElement;
|
||||
@query("hui-card", false) private _card?: HuiCard;
|
||||
|
||||
private _config = memoizeOne((config: string) => {
|
||||
const c = (load(config) as any)[0];
|
||||
return c;
|
||||
});
|
||||
|
||||
render() {
|
||||
return html`
|
||||
@ -30,63 +37,32 @@ class DemoCard extends LitElement {
|
||||
: ""}
|
||||
</h2>
|
||||
<div class="root">
|
||||
<div id="card"></div>
|
||||
${this.showConfig ? html`<pre>${this.config.config.trim()}</pre>` : ""}
|
||||
<hui-card
|
||||
.config=${this._config(this.config.config)}
|
||||
.hass=${this.hass}
|
||||
@card-updated=${this._cardUpdated}
|
||||
></hui-card>
|
||||
${this.showConfig
|
||||
? html`<pre>${this.config.config.trim()}</pre>`
|
||||
: nothing}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (changedProps.has("config")) {
|
||||
const card = this._card;
|
||||
while (card.lastChild) {
|
||||
card.removeChild(card.lastChild);
|
||||
}
|
||||
|
||||
const el = this._createCardElement((load(this.config.config) as any)[0]);
|
||||
card.appendChild(el);
|
||||
this._getSize(el);
|
||||
}
|
||||
|
||||
if (changedProps.has("hass")) {
|
||||
const card = this._card.lastChild;
|
||||
if (card) {
|
||||
(card as any).hass = this.hass;
|
||||
}
|
||||
}
|
||||
private async _cardUpdated(ev) {
|
||||
ev.stopPropagation();
|
||||
this._updateSize();
|
||||
}
|
||||
|
||||
async _getSize(el) {
|
||||
await customElements.whenDefined(el.localName);
|
||||
|
||||
if (!("getCardSize" in el)) {
|
||||
this._size = undefined;
|
||||
return;
|
||||
}
|
||||
this._size = await el.getCardSize();
|
||||
private async _updateSize() {
|
||||
this._size = await this._card?.getCardSize();
|
||||
}
|
||||
|
||||
_createCardElement(cardConfig) {
|
||||
const element = createCardElement(cardConfig);
|
||||
if (this.hass) {
|
||||
element.hass = this.hass;
|
||||
}
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev) => {
|
||||
ev.stopPropagation();
|
||||
this._rebuildCard(element, cardConfig);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
return element;
|
||||
}
|
||||
|
||||
_rebuildCard(cardElToReplace, config) {
|
||||
const newCardEl = this._createCardElement(config);
|
||||
cardElToReplace.parentElement.replaceChild(newCardEl, cardElToReplace);
|
||||
protected update(
|
||||
_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
||||
): void {
|
||||
super.update(_changedProperties);
|
||||
this._updateSize();
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
@ -101,7 +77,7 @@ class DemoCard extends LitElement {
|
||||
font-size: 0.5em;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
#card {
|
||||
hui-card {
|
||||
max-width: 400px;
|
||||
width: 100vw;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { PropertyValues, ReactiveElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { PropertyValueMap, PropertyValues, ReactiveElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { MediaQueriesListener } from "../../../common/dom/media_query";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
@ -10,23 +11,41 @@ import {
|
||||
checkConditionsMet,
|
||||
} from "../common/validate-condition";
|
||||
import { createCardElement } from "../create-element/create-card-element";
|
||||
import type { Lovelace, LovelaceCard, LovelaceLayoutOptions } from "../types";
|
||||
import { createErrorCardConfig } from "../create-element/create-element-base";
|
||||
import type { LovelaceCard, LovelaceLayoutOptions } from "../types";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
"card-visibility-changed": { value: boolean };
|
||||
"card-updated": undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("hui-card")
|
||||
export class HuiCard extends ReactiveElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public lovelace?: Lovelace;
|
||||
@property({ type: Boolean }) public editMode = false;
|
||||
|
||||
@property({ attribute: false }) public isPanel = false;
|
||||
@property({ type: Boolean }) public isPanel = false;
|
||||
|
||||
@state() public _config?: LovelaceCardConfig;
|
||||
set config(config: LovelaceCardConfig | undefined) {
|
||||
if (!config) return;
|
||||
if (config.type !== this._config?.type) {
|
||||
this._buildElement(config);
|
||||
} else if (config !== this.config) {
|
||||
this._element?.setConfig(config);
|
||||
fireEvent(this, "card-updated");
|
||||
}
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
public get config() {
|
||||
return this._config;
|
||||
}
|
||||
|
||||
private _config?: LovelaceCardConfig;
|
||||
|
||||
private _element?: LovelaceCard;
|
||||
|
||||
@ -44,7 +63,7 @@ export class HuiCard extends ReactiveElement {
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._listenMediaQueries();
|
||||
this._updateElement();
|
||||
this._updateVisibility();
|
||||
}
|
||||
|
||||
public getCardSize(): number | Promise<number> {
|
||||
@ -56,7 +75,7 @@ export class HuiCard extends ReactiveElement {
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
const configOptions = this._config?.layout_options ?? {};
|
||||
const configOptions = this.config?.layout_options ?? {};
|
||||
if (this._element) {
|
||||
const cardOptions = this._element.getLayoutOptions?.() ?? {};
|
||||
return {
|
||||
@ -67,51 +86,76 @@ export class HuiCard extends ReactiveElement {
|
||||
return configOptions;
|
||||
}
|
||||
|
||||
// Public to make demo happy
|
||||
public createElement(config: LovelaceCardConfig) {
|
||||
const element = createCardElement(config) as LovelaceCard;
|
||||
private _createElement(config: LovelaceCardConfig) {
|
||||
const element = createCardElement(config);
|
||||
element.hass = this.hass;
|
||||
element.editMode = this.lovelace?.editMode;
|
||||
element.editMode = this.editMode;
|
||||
// Update element when the visibility of the card changes (e.g. conditional card or filter card)
|
||||
element.addEventListener("card-visibility-changed", (ev) => {
|
||||
element.addEventListener("card-visibility-changed", (ev: Event) => {
|
||||
ev.stopPropagation();
|
||||
this._updateElement();
|
||||
this._updateVisibility();
|
||||
});
|
||||
element.addEventListener(
|
||||
"ll-upgrade",
|
||||
(ev: Event) => {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "card-updated");
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev: Event) => {
|
||||
ev.stopPropagation();
|
||||
this._buildElement(config);
|
||||
fireEvent(this, "card-updated");
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
return element;
|
||||
}
|
||||
|
||||
public setConfig(config: LovelaceCardConfig): void {
|
||||
if (this._config === config) {
|
||||
return;
|
||||
}
|
||||
this._config = config;
|
||||
this._element = this.createElement(config);
|
||||
private _buildElement(config: LovelaceCardConfig) {
|
||||
this._element = this._createElement(config);
|
||||
|
||||
while (this.lastChild) {
|
||||
this.removeChild(this.lastChild);
|
||||
}
|
||||
this.appendChild(this._element!);
|
||||
this._updateVisibility();
|
||||
}
|
||||
|
||||
protected update(changedProperties: PropertyValues<typeof this>) {
|
||||
super.update(changedProperties);
|
||||
protected update(changedProps: PropertyValues<typeof this>) {
|
||||
super.update(changedProps);
|
||||
|
||||
if (this._element) {
|
||||
if (changedProperties.has("hass")) {
|
||||
this._element.hass = this.hass;
|
||||
if (changedProps.has("hass")) {
|
||||
try {
|
||||
this._element.hass = this.hass;
|
||||
} catch (e: any) {
|
||||
this._buildElement(createErrorCardConfig(e.message, null));
|
||||
}
|
||||
}
|
||||
if (changedProperties.has("lovelace")) {
|
||||
this._element.editMode = this.lovelace?.editMode;
|
||||
if (changedProps.has("editMode")) {
|
||||
try {
|
||||
this._element.editMode = this.editMode;
|
||||
} catch (e: any) {
|
||||
this._buildElement(createErrorCardConfig(e.message, null));
|
||||
}
|
||||
}
|
||||
if (changedProperties.has("hass") || changedProperties.has("lovelace")) {
|
||||
this._updateElement();
|
||||
}
|
||||
if (changedProperties.has("isPanel")) {
|
||||
if (changedProps.has("isPanel")) {
|
||||
this._element.isPanel = this.isPanel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected willUpdate(
|
||||
changedProps: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
||||
): void {
|
||||
if (changedProps.has("hass") || changedProps.has("lovelace")) {
|
||||
this._updateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private _clearMediaQueries() {
|
||||
this._listeners.forEach((unsub) => unsub());
|
||||
this._listeners = [];
|
||||
@ -119,42 +163,50 @@ export class HuiCard extends ReactiveElement {
|
||||
|
||||
private _listenMediaQueries() {
|
||||
this._clearMediaQueries();
|
||||
if (!this._config?.visibility) {
|
||||
if (!this.config?.visibility) {
|
||||
return;
|
||||
}
|
||||
const conditions = this._config.visibility;
|
||||
const conditions = this.config.visibility;
|
||||
const hasOnlyMediaQuery =
|
||||
conditions.length === 1 &&
|
||||
conditions[0].condition === "screen" &&
|
||||
!!conditions[0].media_query;
|
||||
|
||||
this._listeners = attachConditionMediaQueriesListeners(
|
||||
this._config.visibility,
|
||||
this.config.visibility,
|
||||
(matches) => {
|
||||
this._updateElement(hasOnlyMediaQuery && matches);
|
||||
this._updateVisibility(hasOnlyMediaQuery && matches);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _updateElement(forceVisible?: boolean) {
|
||||
if (!this._element) {
|
||||
private _updateVisibility(forceVisible?: boolean) {
|
||||
if (!this._element || !this.hass) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._element.hidden) {
|
||||
this.style.setProperty("display", "none");
|
||||
this.toggleAttribute("hidden", true);
|
||||
this._setElementVisibility(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const visible =
|
||||
forceVisible ||
|
||||
this.lovelace?.editMode ||
|
||||
!this._config?.visibility ||
|
||||
checkConditionsMet(this._config.visibility, this.hass);
|
||||
this.editMode ||
|
||||
!this.config?.visibility ||
|
||||
checkConditionsMet(this.config.visibility, this.hass);
|
||||
this._setElementVisibility(visible);
|
||||
}
|
||||
|
||||
private _setElementVisibility(visible: boolean) {
|
||||
if (!this._element) return;
|
||||
|
||||
if (this.hidden !== !visible) {
|
||||
this.style.setProperty("display", visible ? "" : "none");
|
||||
this.toggleAttribute("hidden", !visible);
|
||||
fireEvent(this, "card-visibility-changed", { value: visible });
|
||||
}
|
||||
|
||||
this.style.setProperty("display", visible ? "" : "none");
|
||||
this.toggleAttribute("hidden", !visible);
|
||||
if (!visible && this._element.parentElement) {
|
||||
this.removeChild(this._element);
|
||||
} else if (visible && !this._element.parentElement) {
|
||||
|
@ -3,7 +3,6 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
import { HuiConditionalBase } from "../components/hui-conditional-base";
|
||||
import { createCardElement } from "../create-element/create-card-element";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { ConditionalCardConfig } from "./types";
|
||||
|
||||
@ -38,28 +37,13 @@ class HuiConditionalCard extends HuiConditionalBase implements LovelaceCard {
|
||||
}
|
||||
|
||||
private _createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
const element = createCardElement(cardConfig) as LovelaceCard;
|
||||
if (this.hass) {
|
||||
element.hass = this.hass;
|
||||
}
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev) => {
|
||||
ev.stopPropagation();
|
||||
this._rebuildCard(cardConfig);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
const element = document.createElement("hui-card");
|
||||
element.hass = this.hass;
|
||||
element.editMode = this.editMode;
|
||||
element.config = cardConfig;
|
||||
return element;
|
||||
}
|
||||
|
||||
private _rebuildCard(config: LovelaceCardConfig): void {
|
||||
this._element = this._createCardElement(config);
|
||||
if (this.lastChild) {
|
||||
this.replaceChild(this._element, this.lastChild);
|
||||
}
|
||||
}
|
||||
|
||||
protected setVisibility(conditionMet: boolean): void {
|
||||
const visible = this.editMode || conditionMet;
|
||||
const previouslyHidden = this.hidden;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { PropertyValues, ReactiveElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
@ -11,11 +12,10 @@ import {
|
||||
checkConditionsMet,
|
||||
extractConditionEntityIds,
|
||||
} from "../common/validate-condition";
|
||||
import { createCardElement } from "../create-element/create-card-element";
|
||||
import { EntityFilterEntityConfig } from "../entity-rows/types";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { HuiCard } from "./hui-card";
|
||||
import { EntityFilterCardConfig } from "./types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
|
||||
@customElement("hui-entity-filter-card")
|
||||
export class HuiEntityFilterCard
|
||||
@ -59,7 +59,7 @@ export class HuiEntityFilterCard
|
||||
|
||||
@state() private _config?: EntityFilterCardConfig;
|
||||
|
||||
private _element?: LovelaceCard;
|
||||
private _element?: HuiCard;
|
||||
|
||||
private _configEntities?: EntityFilterEntityConfig[];
|
||||
|
||||
@ -173,12 +173,12 @@ export class HuiEntityFilterCard
|
||||
}
|
||||
|
||||
if (!this.lastChild) {
|
||||
this._element.setConfig({
|
||||
this._element.config = {
|
||||
...this._baseCardConfig!,
|
||||
entities: entitiesList,
|
||||
});
|
||||
};
|
||||
this._oldEntities = entitiesList;
|
||||
} else if (this._element.tagName !== "HUI-ERROR-CARD") {
|
||||
} else {
|
||||
const isSame =
|
||||
this._oldEntities &&
|
||||
entitiesList.length === this._oldEntities.length &&
|
||||
@ -186,10 +186,10 @@ export class HuiEntityFilterCard
|
||||
|
||||
if (!isSame) {
|
||||
this._oldEntities = entitiesList;
|
||||
this._element.setConfig({
|
||||
this._element.config = {
|
||||
...this._baseCardConfig!,
|
||||
entities: entitiesList,
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,33 +245,12 @@ export class HuiEntityFilterCard
|
||||
}
|
||||
|
||||
private _createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
const element = createCardElement(cardConfig) as LovelaceCard;
|
||||
if (this.hass) {
|
||||
element.hass = this.hass;
|
||||
}
|
||||
element.isPanel = this.isPanel;
|
||||
const element = document.createElement("hui-card");
|
||||
element.hass = this.hass;
|
||||
element.editMode = this.editMode;
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev) => {
|
||||
ev.stopPropagation();
|
||||
this._rebuildCard(element, cardConfig);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
element.config = cardConfig;
|
||||
return element;
|
||||
}
|
||||
|
||||
private _rebuildCard(
|
||||
cardElToReplace: LovelaceCard,
|
||||
config: LovelaceCardConfig
|
||||
): void {
|
||||
const newCardEl = this._createCardElement(config);
|
||||
if (cardElToReplace.parentElement) {
|
||||
cardElToReplace.parentElement!.replaceChild(newCardEl, cardElToReplace);
|
||||
}
|
||||
this._element = newCardEl;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { dump } from "js-yaml";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-alert";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCard } from "../types";
|
||||
@ -10,6 +10,8 @@ import { ErrorCardConfig } from "./types";
|
||||
export class HuiErrorCard extends LitElement implements LovelaceCard {
|
||||
public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public editMode = false;
|
||||
|
||||
@state() private _config?: ErrorCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
|
@ -1,19 +1,12 @@
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
nothing,
|
||||
} from "lit";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { createCardElement } from "../create-element/create-card-element";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import "./hui-card";
|
||||
import type { HuiCard } from "./hui-card";
|
||||
import { StackCardConfig } from "./types";
|
||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||
|
||||
export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
extends LitElement
|
||||
@ -32,7 +25,7 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
|
||||
@property({ type: Boolean }) public editMode = false;
|
||||
|
||||
@state() protected _cards?: LovelaceCard[];
|
||||
@state() protected _cards?: HuiCard[];
|
||||
|
||||
@state() protected _config?: T;
|
||||
|
||||
@ -49,30 +42,36 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
}
|
||||
this._config = config;
|
||||
this._cards = config.cards.map((card) => {
|
||||
const element = this._createCardElement(card) as LovelaceCard;
|
||||
const element = this._createCardElement(card);
|
||||
return element;
|
||||
});
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (
|
||||
!this._cards ||
|
||||
(!changedProps.has("hass") && !changedProps.has("editMode"))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
protected update(changedProperties) {
|
||||
super.update(changedProperties);
|
||||
|
||||
for (const element of this._cards) {
|
||||
if (this.hass) {
|
||||
element.hass = this.hass;
|
||||
if (this._cards) {
|
||||
if (changedProperties.has("hass")) {
|
||||
this._cards.forEach((card) => {
|
||||
card.hass = this.hass;
|
||||
});
|
||||
}
|
||||
if (this.editMode !== undefined) {
|
||||
element.editMode = this.editMode;
|
||||
if (changedProperties.has("editMode")) {
|
||||
this._cards.forEach((card) => {
|
||||
card.editMode = this.editMode;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
const element = document.createElement("hui-card");
|
||||
element.hass = this.hass;
|
||||
element.editMode = this.editMode;
|
||||
element.config = cardConfig;
|
||||
return element;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._config || !this._cards) {
|
||||
return nothing;
|
||||
@ -110,34 +109,4 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
private _createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
const element = createCardElement(cardConfig) as LovelaceCard;
|
||||
if (this.hass) {
|
||||
element.hass = this.hass;
|
||||
}
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev) => {
|
||||
ev.stopPropagation();
|
||||
this._rebuildCard(element, cardConfig);
|
||||
fireEvent(this, "ll-rebuild");
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
return element;
|
||||
}
|
||||
|
||||
private _rebuildCard(
|
||||
cardElToReplace: LovelaceCard,
|
||||
config: LovelaceCardConfig
|
||||
): void {
|
||||
const newCardEl = this._createCardElement(config);
|
||||
if (cardElToReplace.parentElement) {
|
||||
cardElToReplace.parentElement.replaceChild(newCardEl, cardElToReplace);
|
||||
}
|
||||
this._cards = this._cards!.map((curCardEl) =>
|
||||
curCardEl === cardElToReplace ? newCardEl : curCardEl
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { MediaQueriesListener } from "../../../common/dom/media_query";
|
||||
import { deepEqual } from "../../../common/util/deep-equal";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { HuiCard } from "../cards/hui-card";
|
||||
import { ConditionalCardConfig } from "../cards/types";
|
||||
import {
|
||||
Condition,
|
||||
@ -12,7 +13,6 @@ import {
|
||||
validateConditionalConfig,
|
||||
} from "../common/validate-condition";
|
||||
import { ConditionalRowConfig, LovelaceRow } from "../entity-rows/types";
|
||||
import { LovelaceCard } from "../types";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@ -28,7 +28,7 @@ export class HuiConditionalBase extends ReactiveElement {
|
||||
|
||||
@state() protected _config?: ConditionalCardConfig | ConditionalRowConfig;
|
||||
|
||||
protected _element?: LovelaceCard | LovelaceRow;
|
||||
protected _element?: HuiCard | LovelaceRow;
|
||||
|
||||
private _listeners: MediaQueriesListener[] = [];
|
||||
|
||||
|
@ -152,6 +152,7 @@ const _lazyCreate = <T extends keyof CreateElementConfigTypes>(
|
||||
customElements.whenDefined(tag).then(() => {
|
||||
try {
|
||||
customElements.upgrade(element);
|
||||
fireEvent(element, "ll-upgrade");
|
||||
// @ts-ignore
|
||||
element.setConfig(config);
|
||||
} catch (err: any) {
|
||||
|
@ -1,106 +0,0 @@
|
||||
import { PropertyValues, ReactiveElement } from "lit";
|
||||
import { property } from "lit/decorators";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { createCardElement } from "../../create-element/create-card-element";
|
||||
import { createErrorCardConfig } from "../../create-element/create-element-base";
|
||||
import { LovelaceCard } from "../../types";
|
||||
|
||||
export class HuiCardPreview extends ReactiveElement {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public config?: LovelaceCardConfig;
|
||||
|
||||
private _element?: LovelaceCard;
|
||||
|
||||
private get _error() {
|
||||
return this._element?.tagName === "HUI-ERROR-CARD";
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.addEventListener("ll-rebuild", () => {
|
||||
this._cleanup();
|
||||
if (this.config) {
|
||||
this._createCard(this.config);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
protected update(changedProperties: PropertyValues) {
|
||||
super.update(changedProperties);
|
||||
|
||||
if (changedProperties.has("config")) {
|
||||
const oldConfig = changedProperties.get("config") as
|
||||
| undefined
|
||||
| LovelaceCardConfig;
|
||||
|
||||
if (!this.config) {
|
||||
this._cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.config.type) {
|
||||
this._createCard(
|
||||
createErrorCardConfig("No card type found", this.config)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._element) {
|
||||
this._createCard(this.config);
|
||||
return;
|
||||
}
|
||||
|
||||
// in case the element was an error element we always want to recreate it
|
||||
if (!this._error && oldConfig && this.config.type === oldConfig.type) {
|
||||
try {
|
||||
this._element.setConfig(this.config);
|
||||
} catch (err: any) {
|
||||
this._createCard(createErrorCardConfig(err.message, this.config));
|
||||
}
|
||||
} else {
|
||||
this._createCard(this.config);
|
||||
}
|
||||
}
|
||||
|
||||
if (changedProperties.has("hass")) {
|
||||
if (this._element) {
|
||||
this._element.hass = this.hass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _createCard(configValue: LovelaceCardConfig): void {
|
||||
this._cleanup();
|
||||
this._element = createCardElement(configValue);
|
||||
|
||||
this._element.editMode = true;
|
||||
|
||||
if (this.hass) {
|
||||
this._element!.hass = this.hass;
|
||||
}
|
||||
|
||||
this.appendChild(this._element!);
|
||||
}
|
||||
|
||||
private _cleanup() {
|
||||
if (!this._element) {
|
||||
return;
|
||||
}
|
||||
this.removeChild(this._element);
|
||||
this._element = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-card-preview": HuiCardPreview;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("hui-card-preview", HuiCardPreview);
|
@ -5,7 +5,7 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import "./hui-card-preview";
|
||||
import "../../cards/hui-card";
|
||||
import type { DeleteCardDialogParams } from "./show-delete-card-dialog";
|
||||
|
||||
@customElement("hui-dialog-delete-card")
|
||||
@ -45,10 +45,11 @@ export class HuiDialogDeleteCard extends LitElement {
|
||||
${this._cardConfig
|
||||
? html`
|
||||
<div class="element-preview">
|
||||
<hui-card-preview
|
||||
<hui-card
|
||||
.hass=${this.hass}
|
||||
.config=${this._cardConfig}
|
||||
></hui-card-preview>
|
||||
editMode
|
||||
></hui-card>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
@ -74,7 +75,7 @@ export class HuiDialogDeleteCard extends LitElement {
|
||||
.element-preview {
|
||||
position: relative;
|
||||
}
|
||||
hui-card-preview {
|
||||
hui-card {
|
||||
margin: 4px auto;
|
||||
max-width: 500px;
|
||||
display: block;
|
||||
|
@ -36,7 +36,7 @@ import { findLovelaceContainer } from "../lovelace-path";
|
||||
import type { GUIModeChangedEvent } from "../types";
|
||||
import "./hui-card-element-editor";
|
||||
import type { HuiCardElementEditor } from "./hui-card-element-editor";
|
||||
import "./hui-card-preview";
|
||||
import "../../cards/hui-card";
|
||||
import type { EditCardDialogParams } from "./show-edit-card-dialog";
|
||||
|
||||
declare global {
|
||||
@ -245,11 +245,12 @@ export class HuiDialogEditCard
|
||||
></hui-card-element-editor>
|
||||
</div>
|
||||
<div class="element-preview">
|
||||
<hui-card-preview
|
||||
<hui-card
|
||||
.hass=${this.hass}
|
||||
.config=${this._cardConfig}
|
||||
editMode
|
||||
class=${this._error ? "blur" : ""}
|
||||
></hui-card-preview>
|
||||
></hui-card>
|
||||
${this._error
|
||||
? html`
|
||||
<ha-circular-progress
|
||||
@ -452,7 +453,7 @@ export class HuiDialogEditCard
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content hui-card-preview {
|
||||
.content hui-card {
|
||||
margin: 4px auto;
|
||||
max-width: 390px;
|
||||
}
|
||||
@ -470,7 +471,7 @@ export class HuiDialogEditCard
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.content hui-card-preview {
|
||||
.content hui-card {
|
||||
padding: 8px 10px;
|
||||
margin: auto 0px;
|
||||
max-width: 500px;
|
||||
@ -498,7 +499,7 @@ export class HuiDialogEditCard
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
hui-card-preview {
|
||||
hui-card {
|
||||
padding-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
display: block;
|
||||
|
@ -18,7 +18,7 @@ import {
|
||||
LovelaceContainerPath,
|
||||
parseLovelaceContainerPath,
|
||||
} from "../lovelace-path";
|
||||
import "./hui-card-preview";
|
||||
import "../../cards/hui-card";
|
||||
import { showCreateCardDialog } from "./show-create-card-dialog";
|
||||
import { SuggestCardDialogParams } from "./show-suggest-card-dialog";
|
||||
|
||||
@ -84,10 +84,7 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
<div class="element-preview">
|
||||
${this._cardConfig.map(
|
||||
(cardConfig) => html`
|
||||
<hui-card-preview
|
||||
.hass=${this.hass}
|
||||
.config=${cardConfig}
|
||||
></hui-card-preview>
|
||||
<hui-card .hass=${this.hass} .config=${cardConfig}></hui-card>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
@ -191,7 +188,7 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
.element-preview {
|
||||
position: relative;
|
||||
}
|
||||
hui-card-preview,
|
||||
hui-card,
|
||||
hui-section {
|
||||
padding-top: 8px;
|
||||
margin: 4px auto;
|
||||
|
@ -1,104 +0,0 @@
|
||||
import { PropertyValues, ReactiveElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { LovelaceSectionElement } from "../../../../data/lovelace";
|
||||
import { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { createSectionElement } from "../../create-element/create-section-element";
|
||||
import { createErrorSectionConfig } from "../../sections/hui-error-section";
|
||||
import { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
|
||||
@customElement("hui-section-preview")
|
||||
export class HuiSectionPreview extends ReactiveElement {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public lovelace?: LovelaceConfig;
|
||||
|
||||
@property({ attribute: false }) public config?: LovelaceSectionConfig;
|
||||
|
||||
private _element?: LovelaceSectionElement;
|
||||
|
||||
private get _error() {
|
||||
return this._element?.tagName === "HUI-ERROR-SECTION";
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.addEventListener("ll-rebuild", () => {
|
||||
this._cleanup();
|
||||
if (this.config) {
|
||||
this._createSection(this.config);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
protected update(changedProperties: PropertyValues) {
|
||||
super.update(changedProperties);
|
||||
|
||||
if (changedProperties.has("config")) {
|
||||
const oldConfig = changedProperties.get("config") as
|
||||
| undefined
|
||||
| LovelaceSectionConfig;
|
||||
|
||||
if (!this.config) {
|
||||
this._cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.config.type) {
|
||||
this._createSection(createErrorSectionConfig("No section type found"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._element) {
|
||||
this._createSection(this.config);
|
||||
return;
|
||||
}
|
||||
|
||||
// in case the element was an error element we always want to recreate it
|
||||
if (!this._error && oldConfig && this.config.type === oldConfig.type) {
|
||||
try {
|
||||
this._element.setConfig(this.config);
|
||||
} catch (err: any) {
|
||||
this._createSection(createErrorSectionConfig(err.message));
|
||||
}
|
||||
} else {
|
||||
this._createSection(this.config);
|
||||
}
|
||||
}
|
||||
|
||||
if (changedProperties.has("hass")) {
|
||||
if (this._element) {
|
||||
this._element.hass = this.hass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _createSection(configValue: LovelaceSectionConfig): void {
|
||||
this._cleanup();
|
||||
this._element = createSectionElement(configValue) as LovelaceSectionElement;
|
||||
|
||||
if (this.hass) {
|
||||
this._element!.hass = this.hass;
|
||||
}
|
||||
|
||||
this.appendChild(this._element!);
|
||||
}
|
||||
|
||||
private _cleanup() {
|
||||
if (!this._element) {
|
||||
return;
|
||||
}
|
||||
this.removeChild(this._element);
|
||||
this._element = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-section-preview": HuiSectionPreview;
|
||||
}
|
||||
}
|
@ -11,10 +11,10 @@ import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { HuiCard } from "../cards/hui-card";
|
||||
import "../components/hui-card-edit-mode";
|
||||
import { moveCard } from "../editor/config-util";
|
||||
import type { Lovelace } from "../types";
|
||||
import { HuiCard } from "../cards/hui-card";
|
||||
|
||||
const CARD_SORTABLE_OPTIONS: HaSortableOptions = {
|
||||
delay: 100,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { PropertyValues, ReactiveElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { MediaQueriesListener } from "../../../common/dom/media_query";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import type { LovelaceSectionElement } from "../../../data/lovelace";
|
||||
@ -16,7 +17,6 @@ import {
|
||||
attachConditionMediaQueriesListeners,
|
||||
checkConditionsMet,
|
||||
} from "../common/validate-condition";
|
||||
import { createErrorCardConfig } from "../create-element/create-element-base";
|
||||
import { createSectionElement } from "../create-element/create-section-element";
|
||||
import { showCreateCardDialog } from "../editor/card-editor/show-create-card-dialog";
|
||||
import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
|
||||
@ -26,7 +26,6 @@ import { parseLovelaceCardPath } from "../editor/lovelace-path";
|
||||
import { generateLovelaceSectionStrategy } from "../strategies/get-strategy";
|
||||
import type { Lovelace } from "../types";
|
||||
import { DEFAULT_SECTION_LAYOUT } from "./const";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@ -54,23 +53,15 @@ export class HuiSection extends ReactiveElement {
|
||||
|
||||
private _listeners: MediaQueriesListener[] = [];
|
||||
|
||||
// Public to make demo happy
|
||||
public createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
private _createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
const element = document.createElement("hui-card");
|
||||
element.hass = this.hass;
|
||||
element.lovelace = this.lovelace;
|
||||
element.setConfig(cardConfig);
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev: Event) => {
|
||||
// In edit mode let it go to hui-root and rebuild whole section.
|
||||
if (!this.lovelace!.editMode) {
|
||||
ev.stopPropagation();
|
||||
this._rebuildCard(element, cardConfig);
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
element.editMode = this.lovelace?.editMode || false;
|
||||
element.config = cardConfig;
|
||||
element.addEventListener("card-updated", (ev: Event) => {
|
||||
ev.stopPropagation();
|
||||
this._cards = [...this._cards];
|
||||
});
|
||||
return element;
|
||||
}
|
||||
|
||||
@ -121,22 +112,14 @@ export class HuiSection extends ReactiveElement {
|
||||
// Config has not changed. Just props
|
||||
if (changedProperties.has("hass")) {
|
||||
this._cards.forEach((element) => {
|
||||
try {
|
||||
element.hass = this.hass;
|
||||
} catch (e: any) {
|
||||
this._rebuildCard(element, createErrorCardConfig(e.message, null));
|
||||
}
|
||||
element.hass = this.hass;
|
||||
});
|
||||
this._layoutElement.hass = this.hass;
|
||||
}
|
||||
if (changedProperties.has("lovelace")) {
|
||||
this._layoutElement.lovelace = this.lovelace;
|
||||
this._cards.forEach((element) => {
|
||||
try {
|
||||
element.lovelace = this.lovelace;
|
||||
} catch (e: any) {
|
||||
this._rebuildCard(element, createErrorCardConfig(e.message, null));
|
||||
}
|
||||
element.editMode = this.lovelace?.editMode || false;
|
||||
});
|
||||
}
|
||||
if (changedProperties.has("_cards")) {
|
||||
@ -283,22 +266,8 @@ export class HuiSection extends ReactiveElement {
|
||||
return;
|
||||
}
|
||||
|
||||
this._cards = config.cards.map((cardConfig) => {
|
||||
const element = this.createCardElement(cardConfig);
|
||||
return element;
|
||||
});
|
||||
}
|
||||
|
||||
private _rebuildCard(
|
||||
cardElToReplace: HuiCard,
|
||||
config: LovelaceCardConfig
|
||||
): void {
|
||||
const newCardEl = this.createCardElement(config);
|
||||
if (cardElToReplace.parentElement) {
|
||||
cardElToReplace.parentElement!.replaceChild(newCardEl, cardElToReplace);
|
||||
}
|
||||
this._cards = this._cards!.map((curCardEl) =>
|
||||
curCardEl === cardElToReplace ? newCardEl : curCardEl
|
||||
this._cards = config.cards.map((cardConfig) =>
|
||||
this._createCardElement(cardConfig)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ declare global {
|
||||
// eslint-disable-next-line
|
||||
interface HASSDomEvents {
|
||||
"ll-rebuild": Record<string, unknown>;
|
||||
"ll-upgrade": Record<string, unknown>;
|
||||
"ll-badge-rebuild": Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { HuiCard } from "../cards/hui-card";
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
import type { Lovelace, LovelaceBadge, LovelaceCard } from "../types";
|
||||
import type { Lovelace, LovelaceBadge } from "../types";
|
||||
|
||||
// Find column with < 5 size, else smallest column
|
||||
const getColumnIndex = (columnSizes: number[], size: number) => {
|
||||
@ -249,7 +249,7 @@ export class MasonryView extends LitElement implements LovelaceViewElement {
|
||||
}
|
||||
|
||||
private _addCardToColumn(columnEl, index, editMode) {
|
||||
const card: LovelaceCard = this.cards[index];
|
||||
const card: HuiCard = this.cards[index];
|
||||
if (!editMode || this.isStrategy) {
|
||||
card.editMode = false;
|
||||
columnEl.appendChild(card);
|
||||
|
@ -17,7 +17,7 @@ import type { HomeAssistant } from "../../../types";
|
||||
import { HuiCard } from "../cards/hui-card";
|
||||
import { HuiCardOptions } from "../components/hui-card-options";
|
||||
import { HuiWarning } from "../components/hui-warning";
|
||||
import type { Lovelace, LovelaceCard } from "../types";
|
||||
import type { Lovelace } from "../types";
|
||||
|
||||
let editCodeLoaded = false;
|
||||
|
||||
@ -32,7 +32,7 @@ export class PanelView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
@property({ attribute: false }) public cards: HuiCard[] = [];
|
||||
|
||||
@state() private _card?: LovelaceCard | HuiWarning | HuiCardOptions;
|
||||
@state() private _card?: HuiCard | HuiWarning | HuiCardOptions;
|
||||
|
||||
public setConfig(_config: LovelaceViewConfig): void {}
|
||||
|
||||
@ -104,7 +104,7 @@ export class PanelView extends LitElement implements LovelaceViewElement {
|
||||
return;
|
||||
}
|
||||
|
||||
const card: LovelaceCard = this.cards[0];
|
||||
const card: HuiCard = this.cards[0];
|
||||
card.isPanel = true;
|
||||
|
||||
if (this.isStrategy || !this.lovelace?.editMode) {
|
||||
|
@ -15,7 +15,7 @@ import type { HomeAssistant } from "../../../types";
|
||||
import { HuiCard } from "../cards/hui-card";
|
||||
import { HuiCardOptions } from "../components/hui-card-options";
|
||||
import { replaceCard } from "../editor/config-util";
|
||||
import type { Lovelace, LovelaceCard } from "../types";
|
||||
import type { Lovelace } from "../types";
|
||||
|
||||
export class SideBarView extends LitElement implements LovelaceViewElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -140,9 +140,9 @@ export class SideBarView extends LitElement implements LovelaceViewElement {
|
||||
});
|
||||
}
|
||||
|
||||
this.cards.forEach((card: LovelaceCard, idx) => {
|
||||
this.cards.forEach((card, idx) => {
|
||||
const cardConfig = this._config?.cards?.[idx];
|
||||
let element: LovelaceCard | HuiCardOptions;
|
||||
let element: HuiCard | HuiCardOptions;
|
||||
if (this.isStrategy || !this.lovelace?.editMode) {
|
||||
card.editMode = false;
|
||||
element = card;
|
||||
|
@ -21,7 +21,6 @@ import "../cards/hui-card";
|
||||
import type { HuiCard } from "../cards/hui-card";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import { createBadgeElement } from "../create-element/create-badge-element";
|
||||
import { createErrorCardConfig } from "../create-element/create-element-base";
|
||||
import { createViewElement } from "../create-element/create-view-element";
|
||||
import { showCreateCardDialog } from "../editor/card-editor/show-create-card-dialog";
|
||||
import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
|
||||
@ -77,19 +76,12 @@ export class HUIView extends ReactiveElement {
|
||||
private _createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
const element = document.createElement("hui-card");
|
||||
element.hass = this.hass;
|
||||
element.lovelace = this.lovelace;
|
||||
element.setConfig(cardConfig);
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev: Event) => {
|
||||
// In edit mode let it go to hui-root and rebuild whole view.
|
||||
if (!this.lovelace!.editMode) {
|
||||
ev.stopPropagation();
|
||||
this._rebuildCard(element, cardConfig);
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
element.editMode = this.lovelace.editMode;
|
||||
element.config = cardConfig;
|
||||
element.addEventListener("card-updated", (ev: Event) => {
|
||||
ev.stopPropagation();
|
||||
this._cards = [...this._cards];
|
||||
});
|
||||
return element;
|
||||
}
|
||||
|
||||
@ -183,11 +175,7 @@ export class HUIView extends ReactiveElement {
|
||||
});
|
||||
|
||||
this._cards.forEach((element) => {
|
||||
try {
|
||||
element.hass = this.hass;
|
||||
} catch (e: any) {
|
||||
this._rebuildCard(element, createErrorCardConfig(e.message, null));
|
||||
}
|
||||
element.hass = this.hass;
|
||||
});
|
||||
|
||||
this._sections.forEach((element) => {
|
||||
@ -226,12 +214,7 @@ export class HUIView extends ReactiveElement {
|
||||
}
|
||||
});
|
||||
this._cards.forEach((element) => {
|
||||
try {
|
||||
element.hass = this.hass;
|
||||
element.lovelace = this.lovelace;
|
||||
} catch (e: any) {
|
||||
this._rebuildCard(element, createErrorCardConfig(e.message, null));
|
||||
}
|
||||
element.editMode = this.lovelace.editMode;
|
||||
});
|
||||
}
|
||||
if (changedProperties.has("_cards")) {
|
||||
@ -388,19 +371,6 @@ export class HUIView extends ReactiveElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _rebuildCard(
|
||||
cardElToReplace: HuiCard,
|
||||
config: LovelaceCardConfig
|
||||
): void {
|
||||
const newCardEl = this._createCardElement(config);
|
||||
if (cardElToReplace.parentElement) {
|
||||
cardElToReplace.parentElement!.replaceChild(newCardEl, cardElToReplace);
|
||||
}
|
||||
this._cards = this._cards!.map((curCardEl) =>
|
||||
curCardEl === cardElToReplace ? newCardEl : curCardEl
|
||||
);
|
||||
}
|
||||
|
||||
private _rebuildBadge(
|
||||
badgeElToReplace: LovelaceBadge,
|
||||
config: LovelaceBadgeConfig
|
||||
|
@ -17,12 +17,13 @@ import {
|
||||
html,
|
||||
nothing,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||
import { storage } from "../../common/decorators/storage";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { supportsFeature } from "../../common/entity/supports-feature";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import { constructUrlCurrentPath } from "../../common/url/construct-url";
|
||||
import {
|
||||
@ -40,6 +41,7 @@ import "../../components/ha-two-pane-top-app-bar-fixed";
|
||||
import { deleteConfigEntry } from "../../data/config_entries";
|
||||
import { getExtendedEntityRegistryEntry } from "../../data/entity_registry";
|
||||
import { fetchIntegrationManifest } from "../../data/integration";
|
||||
import { LovelaceCardConfig } from "../../data/lovelace/config/card";
|
||||
import { TodoListEntityFeature, getTodoLists } from "../../data/todo";
|
||||
import { showConfigFlowDialog } from "../../dialogs/config-flow/show-dialog-config-flow";
|
||||
import {
|
||||
@ -49,11 +51,8 @@ import {
|
||||
import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { HuiErrorCard } from "../lovelace/cards/hui-error-card";
|
||||
import { createCardElement } from "../lovelace/create-element/create-card-element";
|
||||
import { LovelaceCard } from "../lovelace/types";
|
||||
import "../lovelace/cards/hui-card";
|
||||
import { showTodoItemEditDialog } from "./show-dialog-todo-item-editor";
|
||||
import { supportsFeature } from "../../common/entity/supports-feature";
|
||||
|
||||
@customElement("ha-panel-todo")
|
||||
class PanelTodo extends LitElement {
|
||||
@ -63,8 +62,6 @@ class PanelTodo extends LitElement {
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public mobile = false;
|
||||
|
||||
@state() private _card?: LovelaceCard | HuiErrorCard;
|
||||
|
||||
@storage({
|
||||
key: "selectedTodoEntity",
|
||||
state: true,
|
||||
@ -128,15 +125,10 @@ class PanelTodo extends LitElement {
|
||||
if (changedProperties.has("_entityId") || !this.hasUpdated) {
|
||||
this._setupTodoElement();
|
||||
}
|
||||
|
||||
if (changedProperties.has("hass") && this._card) {
|
||||
this._card.hass = this.hass;
|
||||
}
|
||||
}
|
||||
|
||||
private _setupTodoElement(): void {
|
||||
if (!this._entityId) {
|
||||
this._card = undefined;
|
||||
navigate(constructUrlCurrentPath(""), { replace: true });
|
||||
return;
|
||||
}
|
||||
@ -144,13 +136,16 @@ class PanelTodo extends LitElement {
|
||||
constructUrlCurrentPath(createSearchParam({ entity_id: this._entityId })),
|
||||
{ replace: true }
|
||||
);
|
||||
this._card = createCardElement({
|
||||
type: "todo-list",
|
||||
entity: this._entityId,
|
||||
}) as LovelaceCard;
|
||||
this._card.hass = this.hass;
|
||||
}
|
||||
|
||||
private _cardConfig = memoizeOne(
|
||||
(entityId: string) =>
|
||||
({
|
||||
type: "todo-list",
|
||||
entity: entityId,
|
||||
}) as LovelaceCardConfig
|
||||
);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const entityRegistryEntry = this._entityId
|
||||
? this.hass.entities[this._entityId]
|
||||
@ -274,7 +269,16 @@ class PanelTodo extends LitElement {
|
||||
: nothing}
|
||||
</ha-button-menu>
|
||||
<div id="columns">
|
||||
<div class="column">${this._card}</div>
|
||||
<div class="column">
|
||||
${this._entityId
|
||||
? html`
|
||||
<hui-card
|
||||
.hass=${this.hass}
|
||||
.config=${this._cardConfig(this._entityId)}
|
||||
></hui-card>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
</div>
|
||||
${entityState &&
|
||||
supportsFeature(entityState, TodoListEntityFeature.CREATE_TODO_ITEM)
|
||||
|
Loading…
x
Reference in New Issue
Block a user