diff --git a/src/panels/lovelace/common/ha-card-condition-editor.ts b/src/panels/lovelace/common/ha-card-condition-editor.ts
new file mode 100644
index 0000000000..7209868ed4
--- /dev/null
+++ b/src/panels/lovelace/common/ha-card-condition-editor.ts
@@ -0,0 +1,102 @@
+import { mdiCodeBraces, mdiDelete, mdiListBoxOutline } from "@mdi/js";
+import { LitElement, css, html } from "lit";
+import { customElement, property, state } from "lit/decorators";
+import { dynamicElement } from "../../../common/dom/dynamic-element-directive";
+import { fireEvent } from "../../../common/dom/fire_event";
+import "../../../components/ha-icon-button";
+import "../../../components/ha-yaml-editor";
+import { haStyle } from "../../../resources/styles";
+import type { HomeAssistant } from "../../../types";
+import "./types/ha-card-condition-state";
+import { Condition } from "./validate-condition";
+
+@customElement("ha-card-condition-editor")
+export default class HaCardConditionEditor extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ attribute: false }) condition!: Condition;
+
+ @state() public _yamlMode = false;
+
+ protected render() {
+ const condition = this.condition;
+ const supported =
+ customElements.get(`ha-card-condition-${condition.condition}`) !==
+ undefined;
+ const yamlMode = this._yamlMode || !supported;
+
+ return html`
+
+
+ ${yamlMode
+ ? html`
+
+ `
+ : html`
+ ${dynamicElement(`ha-card-condition-${condition.condition}`, {
+ hass: this.hass,
+ condition: condition,
+ })}
+ `}
+
+ `;
+ }
+
+ private _toggleMode() {
+ this._yamlMode = !this._yamlMode;
+ }
+
+ private _delete() {
+ fireEvent(this, "value-changed", { value: null });
+ }
+
+ private _onYamlChange(ev: CustomEvent) {
+ ev.stopPropagation();
+ if (!ev.detail.isValid) {
+ return;
+ }
+ // @ts-ignore
+ fireEvent(this, "value-changed", { value: ev.detail.value });
+ }
+
+ static styles = [
+ haStyle,
+ css`
+ .header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ }
+ .content {
+ padding: 12px;
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-card-condition-editor": HaCardConditionEditor;
+ }
+}
diff --git a/src/panels/lovelace/common/types/ha-card-condition-state.ts b/src/panels/lovelace/common/types/ha-card-condition-state.ts
new file mode 100644
index 0000000000..436a3b3619
--- /dev/null
+++ b/src/panels/lovelace/common/types/ha-card-condition-state.ts
@@ -0,0 +1,134 @@
+import type { HassEntity } from "home-assistant-js-websocket";
+import { html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { fireEvent } from "../../../../common/dom/fire_event";
+import "../../../../components/ha-form/ha-form";
+import type { SchemaUnion } from "../../../../components/ha-form/types";
+import { HaFormSchema } from "../../../../components/ha-form/types";
+import type { HomeAssistant } from "../../../../types";
+import { StateCondition } from "../validate-condition";
+
+type StateConditionData = {
+ condition: "state";
+ entity: string;
+ invert: "true" | "false";
+ state?: string;
+};
+
+const SCHEMA = [
+ { name: "entity", selector: { entity: {} } },
+ {
+ name: "",
+ type: "grid",
+ schema: [
+ {
+ name: "invert",
+ selector: {
+ select: {
+ mode: "dropdown",
+ options: [
+ {
+ label: "State equal",
+ value: "false",
+ },
+ {
+ label: "State not equal",
+ value: "true",
+ },
+ ],
+ },
+ },
+ },
+ {
+ name: "state",
+ selector: {
+ state: {},
+ },
+ context: {
+ filter_entity: "entity",
+ },
+ },
+ ],
+ },
+] as const satisfies readonly HaFormSchema[];
+
+@customElement("ha-card-condition-state")
+export class HaCardConditionState extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ attribute: false }) public condition!: StateCondition;
+
+ @property({ type: Boolean }) public disabled = false;
+
+ public static get defaultConfig(): StateCondition {
+ return { condition: "state", entity: "", state: "" };
+ }
+
+ protected render() {
+ const { state, state_not, ...content } = this.condition;
+
+ const data: StateConditionData = {
+ ...content,
+ invert: this.condition.state_not ? "true" : "false",
+ state: this.condition.state_not ?? this.condition.state ?? "",
+ };
+
+ return html`
+
+ `;
+ }
+
+ private _valueChanged(ev: CustomEvent): void {
+ ev.stopPropagation();
+ const data = ev.detail.value as StateConditionData;
+
+ const { invert, state, entity, condition: _, ...content } = data;
+
+ const condition: StateCondition = {
+ condition: "state",
+ ...content,
+ entity: entity ?? "",
+ state: invert === "false" ? state ?? "" : undefined,
+ state_not: invert === "true" ? state ?? "" : undefined,
+ };
+
+ fireEvent(this, "value-changed", { value: condition });
+ }
+
+ private _computeLabelCallback = (
+ schema: SchemaUnion
+ ): string => {
+ const entity = this.hass.states[this.condition.entity] as
+ | HassEntity
+ | undefined;
+ switch (schema.name) {
+ case "entity":
+ return this.hass.localize("ui.components.entity.entity-picker.entity");
+ case "state":
+ if (entity) {
+ return `${this.hass.localize(
+ "ui.components.entity.entity-state-picker.state"
+ )} (${this.hass.formatEntityState(entity)})`;
+ }
+ return `${this.hass.localize(
+ "ui.components.entity.entity-state-picker.state"
+ )}`;
+
+ default:
+ return "";
+ }
+ };
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-card-condition-state": HaCardConditionState;
+ }
+}
diff --git a/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts
index 92e98453d6..e4e098d323 100644
--- a/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts
@@ -1,10 +1,10 @@
import "@material/mwc-list/mwc-list-item";
import "@material/mwc-tab-bar/mwc-tab-bar";
import "@material/mwc-tab/mwc-tab";
+import type { MDCTabBarActivatedEvent } from "@material/tab-bar";
import { mdiCodeBraces, mdiContentCopy, mdiListBoxOutline } from "@mdi/js";
import deepClone from "deep-clone-simple";
-import type { MDCTabBarActivatedEvent } from "@material/tab-bar";
-import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import {
any,
@@ -19,8 +19,7 @@ import {
union,
} from "superstruct";
import { storage } from "../../../../common/decorators/storage";
-import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event";
-import { stopPropagation } from "../../../../common/dom/stop_propagation";
+import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/entity/ha-entity-picker";
import "../../../../components/ha-select";
import "../../../../components/ha-textfield";
@@ -30,6 +29,7 @@ import type {
} from "../../../../data/lovelace";
import type { HomeAssistant } from "../../../../types";
import type { ConditionalCardConfig } from "../../cards/types";
+import "../../common/ha-card-condition-editor";
import type { LovelaceCardEditor } from "../../types";
import "../card-editor/hui-card-element-editor";
import type { HuiCardElementEditor } from "../card-editor/hui-card-element-editor";
@@ -39,7 +39,6 @@ import type { ConfigChangedEvent } from "../hui-element-editor";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import type { GUIModeChangedEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
-import { StateCondition } from "../../common/validate-condition";
const stateConditionStruct = object({
condition: optional(literal("state")),
@@ -177,66 +176,25 @@ export class HuiConditionalCardEditor
${this.hass!.localize(
"ui.panel.lovelace.editor.card.conditional.condition_explanation"
)}
- ${this._config.conditions.map((cond, idx) => {
- if (cond.condition && cond.condition !== "state")
- return nothing;
- return html`
+ ${this._config.conditions.map(
+ (cond, idx) => html`
-
-
-
-
-
-
- ${this.hass!.localize(
- "ui.panel.lovelace.editor.card.conditional.state_equal"
- )}
-
-
- ${this.hass!.localize(
- "ui.panel.lovelace.editor.card.conditional.state_not_equal"
- )}
-
-
-
-
+
- `;
- })}
+ `
+ )}
`}
@@ -321,39 +279,19 @@ export class HuiConditionalCardEditor
fireEvent(this, "config-changed", { config: this._config });
}
- private _changeCondition(ev: Event): void {
- const target = ev.target as any;
- if (!this._config || !target) {
- return;
- }
- const conditions = [...this._config.conditions];
- if (target.configValue === "entity" && target.value === "") {
- conditions.splice(target.idx, 1);
+ private _conditionChanged(ev: CustomEvent) {
+ ev.stopPropagation();
+ const conditions = [...this._config!.conditions];
+ const newValue = ev.detail.value;
+ const index = (ev.target as any).index;
+
+ if (newValue === null) {
+ conditions.splice(index, 1);
} else {
- // Only state condition are supported by the editor
- const condition = { ...conditions[target.idx] } as StateCondition;
- if (target.configValue === "entity") {
- condition.entity = target.value;
- } else if (target.configValue === "state") {
- if (condition.state_not !== undefined) {
- condition.state_not = target.value;
- } else {
- condition.state = target.value;
- }
- } else if (target.configValue === "invert") {
- if (target.value === "true") {
- if (condition.state) {
- condition.state_not = condition.state;
- delete condition.state;
- }
- } else if (condition.state_not) {
- condition.state = condition.state_not;
- delete condition.state_not;
- }
- }
- conditions[target.idx] = condition;
+ conditions[index] = newValue;
}
- this._config = { ...this._config, conditions };
+
+ this._config = { ...this._config!, conditions };
fireEvent(this, "config-changed", { config: this._config });
}
@@ -370,22 +308,10 @@ export class HuiConditionalCardEditor
.condition {
margin-top: 8px;
border: 1px solid var(--divider-color);
+ }
+ .condition .content {
padding: 12px;
}
- .condition .state {
- display: flex;
- align-items: flex-end;
- }
- .condition .state ha-select {
- margin-right: 16px;
- margin-inline-end: 16px;
- margin-inline-start: initial;
- direction: var(--direction);
- }
- .condition .state ha-textfield {
- flex-grow: 1;
- }
-
.card {
margin-top: 8px;
border: 1px solid var(--divider-color);