diff --git a/src/panels/lovelace/common/ha-card-condition-editor.ts b/src/panels/lovelace/common/ha-card-condition-editor.ts
index 7209868ed4..301cc6131e 100644
--- a/src/panels/lovelace/common/ha-card-condition-editor.ts
+++ b/src/panels/lovelace/common/ha-card-condition-editor.ts
@@ -8,6 +8,7 @@ import "../../../components/ha-yaml-editor";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import "./types/ha-card-condition-state";
+import "./types/ha-card-condition-responsive";
import { Condition } from "./validate-condition";
@customElement("ha-card-condition-editor")
diff --git a/src/panels/lovelace/common/types/ha-card-condition-responsive.ts b/src/panels/lovelace/common/types/ha-card-condition-responsive.ts
new file mode 100644
index 0000000000..0b753c2b89
--- /dev/null
+++ b/src/panels/lovelace/common/types/ha-card-condition-responsive.ts
@@ -0,0 +1,107 @@
+import { html, LitElement, PropertyValues } from "lit";
+import { customElement, property } from "lit/decorators";
+import { assert, literal, number, object, optional } from "superstruct";
+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 { ResponsiveCondition } from "../validate-condition";
+
+const responsiveConditionStruct = object({
+ condition: literal("responsive"),
+ max_width: optional(number()),
+ min_width: optional(number()),
+});
+
+const SCHEMA = [
+ {
+ name: "",
+ type: "grid",
+ schema: [
+ {
+ name: "min_width",
+ selector: {
+ number: {
+ mode: "box",
+ step: 1,
+ unit_of_measurement: "px",
+ },
+ },
+ },
+ {
+ name: "max_width",
+ selector: {
+ number: {
+ mode: "box",
+ step: 1,
+ unit_of_measurement: "px",
+ },
+ },
+ },
+ ],
+ },
+] as const satisfies readonly HaFormSchema[];
+
+@customElement("ha-card-condition-responsive")
+export class HaCardConditionResponsive extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ attribute: false }) public condition!: ResponsiveCondition;
+
+ @property({ type: Boolean }) public disabled = false;
+
+ public static get defaultConfig(): ResponsiveCondition {
+ return { condition: "responsive" };
+ }
+
+ protected willUpdate(changedProperties: PropertyValues): void {
+ if (!changedProperties.has("condition")) {
+ return;
+ }
+ try {
+ assert(this.condition, responsiveConditionStruct);
+ } catch (err: any) {
+ fireEvent(this, "ui-mode-not-available", err);
+ }
+ }
+
+ protected render() {
+ return html`
+
+ `;
+ }
+
+ private _valueChanged(ev: CustomEvent): void {
+ ev.stopPropagation();
+ const data = ev.detail.value as ResponsiveCondition;
+ fireEvent(this, "value-changed", { value: data });
+ }
+
+ private _computeLabelCallback = (
+ schema: SchemaUnion
+ ): string => {
+ switch (schema.name) {
+ case "min_width":
+ case "max_width":
+ return this.hass.localize(
+ `ui.panel.lovelace.editor.card.conditional.${schema.name}`
+ );
+ default:
+ return "";
+ }
+ };
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-card-condition-responsive": HaCardConditionResponsive;
+ }
+}
diff --git a/src/panels/lovelace/common/types/ha-card-condition-state.ts b/src/panels/lovelace/common/types/ha-card-condition-state.ts
index 436a3b3619..f728a54ff8 100644
--- a/src/panels/lovelace/common/types/ha-card-condition-state.ts
+++ b/src/panels/lovelace/common/types/ha-card-condition-state.ts
@@ -1,13 +1,22 @@
-import type { HassEntity } from "home-assistant-js-websocket";
-import { html, LitElement } from "lit";
+import { html, LitElement, PropertyValues } from "lit";
import { customElement, property } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { assert, literal, object, optional, string } from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
+import { LocalizeFunc } from "../../../../common/translations/localize";
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";
+const stateConditionStruct = object({
+ condition: literal("state"),
+ entity: string(),
+ state: optional(string()),
+ state_not: optional(string()),
+});
+
type StateConditionData = {
condition: "state";
entity: string;
@@ -15,43 +24,6 @@ type StateConditionData = {
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;
@@ -61,9 +33,64 @@ export class HaCardConditionState extends LitElement {
@property({ type: Boolean }) public disabled = false;
public static get defaultConfig(): StateCondition {
- return { condition: "state", entity: "", state: "" };
+ return { condition: "state", entity: "" };
}
+ protected willUpdate(changedProperties: PropertyValues): void {
+ if (!changedProperties.has("condition")) {
+ return;
+ }
+ try {
+ assert(this.condition, stateConditionStruct);
+ } catch (err: any) {
+ fireEvent(this, "ui-mode-not-available", err);
+ }
+ }
+
+ private _schema = memoizeOne(
+ (localize: LocalizeFunc) =>
+ [
+ { name: "entity", selector: { entity: {} } },
+ {
+ name: "",
+ type: "grid",
+ schema: [
+ {
+ name: "invert",
+ selector: {
+ select: {
+ mode: "dropdown",
+ options: [
+ {
+ label: localize(
+ "ui.panel.lovelace.editor.card.conditional.state_equal"
+ ),
+ value: "false",
+ },
+ {
+ label: localize(
+ "ui.panel.lovelace.editor.card.conditional.state_not_equal"
+ ),
+ value: "true",
+ },
+ ],
+ },
+ },
+ },
+ {
+ name: "state",
+ selector: {
+ state: {},
+ },
+ context: {
+ filter_entity: "entity",
+ },
+ },
+ ],
+ },
+ ] as const satisfies readonly HaFormSchema[]
+ );
+
protected render() {
const { state, state_not, ...content } = this.condition;
@@ -77,7 +104,7 @@ export class HaCardConditionState extends LitElement {
+ schema: SchemaUnion>
): string => {
- const entity = this.hass.states[this.condition.entity] as
- | HassEntity
- | undefined;
+ const entity = this.condition.entity
+ ? this.hass.states[this.condition.entity]
+ : undefined;
switch (schema.name) {
case "entity":
return this.hass.localize("ui.components.entity.entity-picker.entity");
diff --git a/src/panels/lovelace/common/validate-condition.ts b/src/panels/lovelace/common/validate-condition.ts
index 6c92dee597..66bb4d9f42 100644
--- a/src/panels/lovelace/common/validate-condition.ts
+++ b/src/panels/lovelace/common/validate-condition.ts
@@ -18,7 +18,7 @@ export type ResponsiveCondition = {
function checkStateCondition(condition: StateCondition, hass: HomeAssistant) {
const state = hass.states[condition.entity]
- ? hass!.states[condition.entity].state
+ ? hass.states[condition.entity].state
: UNAVAILABLE;
return condition.state != null
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 e4e098d323..26a490878c 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,4 +1,3 @@
-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";
@@ -6,23 +5,10 @@ import { mdiCodeBraces, mdiContentCopy, mdiListBoxOutline } from "@mdi/js";
import deepClone from "deep-clone-simple";
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
-import {
- any,
- array,
- assert,
- assign,
- literal,
- number,
- object,
- optional,
- string,
- union,
-} from "superstruct";
+import { any, array, assert, assign, object, optional } from "superstruct";
import { storage } from "../../../../common/decorators/storage";
import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/entity/ha-entity-picker";
-import "../../../../components/ha-select";
-import "../../../../components/ha-textfield";
import type {
LovelaceCardConfig,
LovelaceConfig,
@@ -40,26 +26,11 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import type { GUIModeChangedEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
-const stateConditionStruct = object({
- condition: optional(literal("state")),
- entity: string(),
- state: optional(string()),
- state_not: optional(string()),
-});
-
-const responsiveConditionStruct = object({
- condition: literal("responsive"),
- max_width: optional(number()),
- min_width: optional(number()),
-});
-
const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
card: any(),
- conditions: optional(
- array(union([stateConditionStruct, responsiveConditionStruct]))
- ),
+ conditions: optional(array(any())),
})
);
diff --git a/src/translations/en.json b/src/translations/en.json
index 3c9bfce684..aadbf74386 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -4767,6 +4767,8 @@
"state_equal": "State is equal to",
"state_not_equal": "State is not equal to",
"current_state": "current",
+ "min_width": "Min width",
+ "max_width": "Max width",
"condition_explanation": "The card will be shown when ALL conditions below are fulfilled.",
"change_type": "Change type"
},