Files
HomeAssistantVS/www/community/ha-treemap-card/treemap-card.js
T
2026-07-08 10:43:39 -04:00

3117 lines
109 KiB
JavaScript

/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const oe = globalThis, ge = oe.ShadowRoot && (oe.ShadyCSS === void 0 || oe.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, _e = Symbol(), xe = /* @__PURE__ */ new WeakMap();
let Be = class {
constructor(e, i, n) {
if (this._$cssResult$ = !0, n !== _e) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
this.cssText = e, this.t = i;
}
get styleSheet() {
let e = this.o;
const i = this.t;
if (ge && e === void 0) {
const n = i !== void 0 && i.length === 1;
n && (e = xe.get(i)), e === void 0 && ((this.o = e = new CSSStyleSheet()).replaceSync(this.cssText), n && xe.set(i, e));
}
return e;
}
toString() {
return this.cssText;
}
};
const rt = (t) => new Be(typeof t == "string" ? t : t + "", void 0, _e), Fe = (t, ...e) => {
const i = t.length === 1 ? t[0] : e.reduce(((n, s, o) => n + ((r) => {
if (r._$cssResult$ === !0) return r.cssText;
if (typeof r == "number") return r;
throw Error("Value passed to 'css' function must be a 'css' function result: " + r + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.");
})(s) + t[o + 1]), t[0]);
return new Be(i, t, _e);
}, at = (t, e) => {
if (ge) t.adoptedStyleSheets = e.map(((i) => i instanceof CSSStyleSheet ? i : i.styleSheet));
else for (const i of e) {
const n = document.createElement("style"), s = oe.litNonce;
s !== void 0 && n.setAttribute("nonce", s), n.textContent = i.cssText, t.appendChild(n);
}
}, we = ge ? (t) => t : (t) => t instanceof CSSStyleSheet ? ((e) => {
let i = "";
for (const n of e.cssRules) i += n.cssText;
return rt(i);
})(t) : t;
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const { is: lt, defineProperty: ct, getOwnPropertyDescriptor: ht, getOwnPropertyNames: ut, getOwnPropertySymbols: dt, getPrototypeOf: ft } = Object, E = globalThis, Ae = E.trustedTypes, pt = Ae ? Ae.emptyScript : "", gt = E.reactiveElementPolyfillSupport, J = (t, e) => t, se = { toAttribute(t, e) {
switch (e) {
case Boolean:
t = t ? pt : null;
break;
case Object:
case Array:
t = t == null ? t : JSON.stringify(t);
}
return t;
}, fromAttribute(t, e) {
let i = t;
switch (e) {
case Boolean:
i = t !== null;
break;
case Number:
i = t === null ? null : Number(t);
break;
case Object:
case Array:
try {
i = JSON.parse(t);
} catch {
i = null;
}
}
return i;
} }, me = (t, e) => !lt(t, e), ke = { attribute: !0, type: String, converter: se, reflect: !1, useDefault: !1, hasChanged: me };
Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), E.litPropertyMetadata ?? (E.litPropertyMetadata = /* @__PURE__ */ new WeakMap());
let U = class extends HTMLElement {
static addInitializer(e) {
this._$Ei(), (this.l ?? (this.l = [])).push(e);
}
static get observedAttributes() {
return this.finalize(), this._$Eh && [...this._$Eh.keys()];
}
static createProperty(e, i = ke) {
if (i.state && (i.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(e) && ((i = Object.create(i)).wrapped = !0), this.elementProperties.set(e, i), !i.noAccessor) {
const n = Symbol(), s = this.getPropertyDescriptor(e, n, i);
s !== void 0 && ct(this.prototype, e, s);
}
}
static getPropertyDescriptor(e, i, n) {
const { get: s, set: o } = ht(this.prototype, e) ?? { get() {
return this[i];
}, set(r) {
this[i] = r;
} };
return { get: s, set(r) {
const a = s?.call(this);
o?.call(this, r), this.requestUpdate(e, a, n);
}, configurable: !0, enumerable: !0 };
}
static getPropertyOptions(e) {
return this.elementProperties.get(e) ?? ke;
}
static _$Ei() {
if (this.hasOwnProperty(J("elementProperties"))) return;
const e = ft(this);
e.finalize(), e.l !== void 0 && (this.l = [...e.l]), this.elementProperties = new Map(e.elementProperties);
}
static finalize() {
if (this.hasOwnProperty(J("finalized"))) return;
if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(J("properties"))) {
const i = this.properties, n = [...ut(i), ...dt(i)];
for (const s of n) this.createProperty(s, i[s]);
}
const e = this[Symbol.metadata];
if (e !== null) {
const i = litPropertyMetadata.get(e);
if (i !== void 0) for (const [n, s] of i) this.elementProperties.set(n, s);
}
this._$Eh = /* @__PURE__ */ new Map();
for (const [i, n] of this.elementProperties) {
const s = this._$Eu(i, n);
s !== void 0 && this._$Eh.set(s, i);
}
this.elementStyles = this.finalizeStyles(this.styles);
}
static finalizeStyles(e) {
const i = [];
if (Array.isArray(e)) {
const n = new Set(e.flat(1 / 0).reverse());
for (const s of n) i.unshift(we(s));
} else e !== void 0 && i.push(we(e));
return i;
}
static _$Eu(e, i) {
const n = i.attribute;
return n === !1 ? void 0 : typeof n == "string" ? n : typeof e == "string" ? e.toLowerCase() : void 0;
}
constructor() {
super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev();
}
_$Ev() {
this._$ES = new Promise(((e) => this.enableUpdating = e)), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), this.constructor.l?.forEach(((e) => e(this)));
}
addController(e) {
(this._$EO ?? (this._$EO = /* @__PURE__ */ new Set())).add(e), this.renderRoot !== void 0 && this.isConnected && e.hostConnected?.();
}
removeController(e) {
this._$EO?.delete(e);
}
_$E_() {
const e = /* @__PURE__ */ new Map(), i = this.constructor.elementProperties;
for (const n of i.keys()) this.hasOwnProperty(n) && (e.set(n, this[n]), delete this[n]);
e.size > 0 && (this._$Ep = e);
}
createRenderRoot() {
const e = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
return at(e, this.constructor.elementStyles), e;
}
connectedCallback() {
this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(!0), this._$EO?.forEach(((e) => e.hostConnected?.()));
}
enableUpdating(e) {
}
disconnectedCallback() {
this._$EO?.forEach(((e) => e.hostDisconnected?.()));
}
attributeChangedCallback(e, i, n) {
this._$AK(e, n);
}
_$ET(e, i) {
const n = this.constructor.elementProperties.get(e), s = this.constructor._$Eu(e, n);
if (s !== void 0 && n.reflect === !0) {
const o = (n.converter?.toAttribute !== void 0 ? n.converter : se).toAttribute(i, n.type);
this._$Em = e, o == null ? this.removeAttribute(s) : this.setAttribute(s, o), this._$Em = null;
}
}
_$AK(e, i) {
const n = this.constructor, s = n._$Eh.get(e);
if (s !== void 0 && this._$Em !== s) {
const o = n.getPropertyOptions(s), r = typeof o.converter == "function" ? { fromAttribute: o.converter } : o.converter?.fromAttribute !== void 0 ? o.converter : se;
this._$Em = s;
const a = r.fromAttribute(i, o.type);
this[s] = a ?? this._$Ej?.get(s) ?? a, this._$Em = null;
}
}
requestUpdate(e, i, n) {
if (e !== void 0) {
const s = this.constructor, o = this[e];
if (n ?? (n = s.getPropertyOptions(e)), !((n.hasChanged ?? me)(o, i) || n.useDefault && n.reflect && o === this._$Ej?.get(e) && !this.hasAttribute(s._$Eu(e, n)))) return;
this.C(e, i, n);
}
this.isUpdatePending === !1 && (this._$ES = this._$EP());
}
C(e, i, { useDefault: n, reflect: s, wrapped: o }, r) {
n && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(e) && (this._$Ej.set(e, r ?? i ?? this[e]), o !== !0 || r !== void 0) || (this._$AL.has(e) || (this.hasUpdated || n || (i = void 0), this._$AL.set(e, i)), s === !0 && this._$Em !== e && (this._$Eq ?? (this._$Eq = /* @__PURE__ */ new Set())).add(e));
}
async _$EP() {
this.isUpdatePending = !0;
try {
await this._$ES;
} catch (i) {
Promise.reject(i);
}
const e = this.scheduleUpdate();
return e != null && await e, !this.isUpdatePending;
}
scheduleUpdate() {
return this.performUpdate();
}
performUpdate() {
if (!this.isUpdatePending) return;
if (!this.hasUpdated) {
if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) {
for (const [s, o] of this._$Ep) this[s] = o;
this._$Ep = void 0;
}
const n = this.constructor.elementProperties;
if (n.size > 0) for (const [s, o] of n) {
const { wrapped: r } = o, a = this[s];
r !== !0 || this._$AL.has(s) || a === void 0 || this.C(s, void 0, o, a);
}
}
let e = !1;
const i = this._$AL;
try {
e = this.shouldUpdate(i), e ? (this.willUpdate(i), this._$EO?.forEach(((n) => n.hostUpdate?.())), this.update(i)) : this._$EM();
} catch (n) {
throw e = !1, this._$EM(), n;
}
e && this._$AE(i);
}
willUpdate(e) {
}
_$AE(e) {
this._$EO?.forEach(((i) => i.hostUpdated?.())), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(e)), this.updated(e);
}
_$EM() {
this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = !1;
}
get updateComplete() {
return this.getUpdateComplete();
}
getUpdateComplete() {
return this._$ES;
}
shouldUpdate(e) {
return !0;
}
update(e) {
this._$Eq && (this._$Eq = this._$Eq.forEach(((i) => this._$ET(i, this[i])))), this._$EM();
}
updated(e) {
}
firstUpdated(e) {
}
};
U.elementStyles = [], U.shadowRootOptions = { mode: "open" }, U[J("elementProperties")] = /* @__PURE__ */ new Map(), U[J("finalized")] = /* @__PURE__ */ new Map(), gt?.({ ReactiveElement: U }), (E.reactiveElementVersions ?? (E.reactiveElementVersions = [])).push("2.1.1");
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const Z = globalThis, re = Z.trustedTypes, Ce = re ? re.createPolicy("lit-html", { createHTML: (t) => t }) : void 0, je = "$lit$", V = `lit$${Math.random().toFixed(9).slice(2)}$`, qe = "?" + V, _t = `<${qe}>`, I = document, Q = () => I.createComment(""), K = (t) => t === null || typeof t != "object" && typeof t != "function", be = Array.isArray, mt = (t) => be(t) || typeof t?.[Symbol.iterator] == "function", de = `[
\f\r]`, W = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, Se = /-->/g, ze = />/g, P = RegExp(`>|${de}(?:([^\\s"'>=/]+)(${de}*=${de}*(?:[^
\f\r"'\`<>=]|("|')|))|$)`, "g"), Me = /'/g, Ve = /"/g, We = /^(?:script|style|textarea|title)$/i, Ge = (t) => (e, ...i) => ({ _$litType$: t, strings: e, values: i }), x = Ge(1), D = Ge(2), j = Symbol.for("lit-noChange"), _ = Symbol.for("lit-nothing"), Ee = /* @__PURE__ */ new WeakMap(), O = I.createTreeWalker(I, 129);
function Ye(t, e) {
if (!be(t) || !t.hasOwnProperty("raw")) throw Error("invalid template strings array");
return Ce !== void 0 ? Ce.createHTML(e) : e;
}
const bt = (t, e) => {
const i = t.length - 1, n = [];
let s, o = e === 2 ? "<svg>" : e === 3 ? "<math>" : "", r = W;
for (let a = 0; a < i; a++) {
const l = t[a];
let h, c, u = -1, f = 0;
for (; f < l.length && (r.lastIndex = f, c = r.exec(l), c !== null); ) f = r.lastIndex, r === W ? c[1] === "!--" ? r = Se : c[1] !== void 0 ? r = ze : c[2] !== void 0 ? (We.test(c[2]) && (s = RegExp("</" + c[2], "g")), r = P) : c[3] !== void 0 && (r = P) : r === P ? c[0] === ">" ? (r = s ?? W, u = -1) : c[1] === void 0 ? u = -2 : (u = r.lastIndex - c[2].length, h = c[1], r = c[3] === void 0 ? P : c[3] === '"' ? Ve : Me) : r === Ve || r === Me ? r = P : r === Se || r === ze ? r = W : (r = P, s = void 0);
const d = r === P && t[a + 1].startsWith("/>") ? " " : "";
o += r === W ? l + _t : u >= 0 ? (n.push(h), l.slice(0, u) + je + l.slice(u) + V + d) : l + V + (u === -2 ? a : d);
}
return [Ye(t, o + (t[i] || "<?>") + (e === 2 ? "</svg>" : e === 3 ? "</math>" : "")), n];
};
class ee {
constructor({ strings: e, _$litType$: i }, n) {
let s;
this.parts = [];
let o = 0, r = 0;
const a = e.length - 1, l = this.parts, [h, c] = bt(e, i);
if (this.el = ee.createElement(h, n), O.currentNode = this.el.content, i === 2 || i === 3) {
const u = this.el.content.firstChild;
u.replaceWith(...u.childNodes);
}
for (; (s = O.nextNode()) !== null && l.length < a; ) {
if (s.nodeType === 1) {
if (s.hasAttributes()) for (const u of s.getAttributeNames()) if (u.endsWith(je)) {
const f = c[r++], d = s.getAttribute(u).split(V), p = /([.?@])?(.*)/.exec(f);
l.push({ type: 1, index: o, name: p[2], strings: d, ctor: p[1] === "." ? yt : p[1] === "?" ? $t : p[1] === "@" ? xt : le }), s.removeAttribute(u);
} else u.startsWith(V) && (l.push({ type: 6, index: o }), s.removeAttribute(u));
if (We.test(s.tagName)) {
const u = s.textContent.split(V), f = u.length - 1;
if (f > 0) {
s.textContent = re ? re.emptyScript : "";
for (let d = 0; d < f; d++) s.append(u[d], Q()), O.nextNode(), l.push({ type: 2, index: ++o });
s.append(u[f], Q());
}
}
} else if (s.nodeType === 8) if (s.data === qe) l.push({ type: 2, index: o });
else {
let u = -1;
for (; (u = s.data.indexOf(V, u + 1)) !== -1; ) l.push({ type: 7, index: o }), u += V.length - 1;
}
o++;
}
}
static createElement(e, i) {
const n = I.createElement("template");
return n.innerHTML = e, n;
}
}
function q(t, e, i = t, n) {
if (e === j) return e;
let s = n !== void 0 ? i._$Co?.[n] : i._$Cl;
const o = K(e) ? void 0 : e._$litDirective$;
return s?.constructor !== o && (s?._$AO?.(!1), o === void 0 ? s = void 0 : (s = new o(t), s._$AT(t, i, n)), n !== void 0 ? (i._$Co ?? (i._$Co = []))[n] = s : i._$Cl = s), s !== void 0 && (e = q(t, s._$AS(t, e.values), s, n)), e;
}
class vt {
constructor(e, i) {
this._$AV = [], this._$AN = void 0, this._$AD = e, this._$AM = i;
}
get parentNode() {
return this._$AM.parentNode;
}
get _$AU() {
return this._$AM._$AU;
}
u(e) {
const { el: { content: i }, parts: n } = this._$AD, s = (e?.creationScope ?? I).importNode(i, !0);
O.currentNode = s;
let o = O.nextNode(), r = 0, a = 0, l = n[0];
for (; l !== void 0; ) {
if (r === l.index) {
let h;
l.type === 2 ? h = new te(o, o.nextSibling, this, e) : l.type === 1 ? h = new l.ctor(o, l.name, l.strings, this, e) : l.type === 6 && (h = new wt(o, this, e)), this._$AV.push(h), l = n[++a];
}
r !== l?.index && (o = O.nextNode(), r++);
}
return O.currentNode = I, s;
}
p(e) {
let i = 0;
for (const n of this._$AV) n !== void 0 && (n.strings !== void 0 ? (n._$AI(e, n, i), i += n.strings.length - 2) : n._$AI(e[i])), i++;
}
}
class te {
get _$AU() {
return this._$AM?._$AU ?? this._$Cv;
}
constructor(e, i, n, s) {
this.type = 2, this._$AH = _, this._$AN = void 0, this._$AA = e, this._$AB = i, this._$AM = n, this.options = s, this._$Cv = s?.isConnected ?? !0;
}
get parentNode() {
let e = this._$AA.parentNode;
const i = this._$AM;
return i !== void 0 && e?.nodeType === 11 && (e = i.parentNode), e;
}
get startNode() {
return this._$AA;
}
get endNode() {
return this._$AB;
}
_$AI(e, i = this) {
e = q(this, e, i), K(e) ? e === _ || e == null || e === "" ? (this._$AH !== _ && this._$AR(), this._$AH = _) : e !== this._$AH && e !== j && this._(e) : e._$litType$ !== void 0 ? this.$(e) : e.nodeType !== void 0 ? this.T(e) : mt(e) ? this.k(e) : this._(e);
}
O(e) {
return this._$AA.parentNode.insertBefore(e, this._$AB);
}
T(e) {
this._$AH !== e && (this._$AR(), this._$AH = this.O(e));
}
_(e) {
this._$AH !== _ && K(this._$AH) ? this._$AA.nextSibling.data = e : this.T(I.createTextNode(e)), this._$AH = e;
}
$(e) {
const { values: i, _$litType$: n } = e, s = typeof n == "number" ? this._$AC(e) : (n.el === void 0 && (n.el = ee.createElement(Ye(n.h, n.h[0]), this.options)), n);
if (this._$AH?._$AD === s) this._$AH.p(i);
else {
const o = new vt(s, this), r = o.u(this.options);
o.p(i), this.T(r), this._$AH = o;
}
}
_$AC(e) {
let i = Ee.get(e.strings);
return i === void 0 && Ee.set(e.strings, i = new ee(e)), i;
}
k(e) {
be(this._$AH) || (this._$AH = [], this._$AR());
const i = this._$AH;
let n, s = 0;
for (const o of e) s === i.length ? i.push(n = new te(this.O(Q()), this.O(Q()), this, this.options)) : n = i[s], n._$AI(o), s++;
s < i.length && (this._$AR(n && n._$AB.nextSibling, s), i.length = s);
}
_$AR(e = this._$AA.nextSibling, i) {
for (this._$AP?.(!1, !0, i); e !== this._$AB; ) {
const n = e.nextSibling;
e.remove(), e = n;
}
}
setConnected(e) {
this._$AM === void 0 && (this._$Cv = e, this._$AP?.(e));
}
}
class le {
get tagName() {
return this.element.tagName;
}
get _$AU() {
return this._$AM._$AU;
}
constructor(e, i, n, s, o) {
this.type = 1, this._$AH = _, this._$AN = void 0, this.element = e, this.name = i, this._$AM = s, this.options = o, n.length > 2 || n[0] !== "" || n[1] !== "" ? (this._$AH = Array(n.length - 1).fill(new String()), this.strings = n) : this._$AH = _;
}
_$AI(e, i = this, n, s) {
const o = this.strings;
let r = !1;
if (o === void 0) e = q(this, e, i, 0), r = !K(e) || e !== this._$AH && e !== j, r && (this._$AH = e);
else {
const a = e;
let l, h;
for (e = o[0], l = 0; l < o.length - 1; l++) h = q(this, a[n + l], i, l), h === j && (h = this._$AH[l]), r || (r = !K(h) || h !== this._$AH[l]), h === _ ? e = _ : e !== _ && (e += (h ?? "") + o[l + 1]), this._$AH[l] = h;
}
r && !s && this.j(e);
}
j(e) {
e === _ ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, e ?? "");
}
}
class yt extends le {
constructor() {
super(...arguments), this.type = 3;
}
j(e) {
this.element[this.name] = e === _ ? void 0 : e;
}
}
class $t extends le {
constructor() {
super(...arguments), this.type = 4;
}
j(e) {
this.element.toggleAttribute(this.name, !!e && e !== _);
}
}
class xt extends le {
constructor(e, i, n, s, o) {
super(e, i, n, s, o), this.type = 5;
}
_$AI(e, i = this) {
if ((e = q(this, e, i, 0) ?? _) === j) return;
const n = this._$AH, s = e === _ && n !== _ || e.capture !== n.capture || e.once !== n.once || e.passive !== n.passive, o = e !== _ && (n === _ || s);
s && this.element.removeEventListener(this.name, this, n), o && this.element.addEventListener(this.name, this, e), this._$AH = e;
}
handleEvent(e) {
typeof this._$AH == "function" ? this._$AH.call(this.options?.host ?? this.element, e) : this._$AH.handleEvent(e);
}
}
class wt {
constructor(e, i, n) {
this.element = e, this.type = 6, this._$AN = void 0, this._$AM = i, this.options = n;
}
get _$AU() {
return this._$AM._$AU;
}
_$AI(e) {
q(this, e);
}
}
const At = Z.litHtmlPolyfillSupport;
At?.(ee, te), (Z.litHtmlVersions ?? (Z.litHtmlVersions = [])).push("3.3.1");
const kt = (t, e, i) => {
const n = i?.renderBefore ?? e;
let s = n._$litPart$;
if (s === void 0) {
const o = i?.renderBefore ?? null;
n._$litPart$ = s = new te(e.insertBefore(Q(), o), o, void 0, i ?? {});
}
return s._$AI(t), s;
};
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const X = globalThis;
class B extends U {
constructor() {
super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0;
}
createRenderRoot() {
var i;
const e = super.createRenderRoot();
return (i = this.renderOptions).renderBefore ?? (i.renderBefore = e.firstChild), e;
}
update(e) {
const i = this.render();
this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(e), this._$Do = kt(i, this.renderRoot, this.renderOptions);
}
connectedCallback() {
super.connectedCallback(), this._$Do?.setConnected(!0);
}
disconnectedCallback() {
super.disconnectedCallback(), this._$Do?.setConnected(!1);
}
render() {
return j;
}
}
B._$litElement$ = !0, B.finalized = !0, X.litElementHydrateSupport?.({ LitElement: B });
const Ct = X.litElementPolyfillSupport;
Ct?.({ LitElement: B });
(X.litElementVersions ?? (X.litElementVersions = [])).push("4.2.1");
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const Je = (t) => (e, i) => {
i !== void 0 ? i.addInitializer((() => {
customElements.define(t, e);
})) : customElements.define(t, e);
};
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const St = { attribute: !0, type: String, converter: se, reflect: !1, hasChanged: me }, zt = (t = St, e, i) => {
const { kind: n, metadata: s } = i;
let o = globalThis.litPropertyMetadata.get(s);
if (o === void 0 && globalThis.litPropertyMetadata.set(s, o = /* @__PURE__ */ new Map()), n === "setter" && ((t = Object.create(t)).wrapped = !0), o.set(i.name, t), n === "accessor") {
const { name: r } = i;
return { set(a) {
const l = e.get.call(this);
e.set.call(this, a), this.requestUpdate(r, l, t);
}, init(a) {
return a !== void 0 && this.C(r, void 0, t, a), a;
} };
}
if (n === "setter") {
const { name: r } = i;
return function(a) {
const l = this[r];
e.call(this, a), this.requestUpdate(r, l, t);
};
}
throw Error("Unsupported decorator location: " + n);
};
function ce(t) {
return (e, i) => typeof i == "object" ? zt(t, e, i) : ((n, s, o) => {
const r = s.hasOwnProperty(o);
return s.constructor.createProperty(o, n), r ? Object.getOwnPropertyDescriptor(s, o) : void 0;
})(t, e, i);
}
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
function ve(t) {
return ce({ ...t, state: !0, attribute: !1 });
}
var Te, Pe;
(function(t) {
t.language = "language", t.system = "system", t.comma_decimal = "comma_decimal", t.decimal_comma = "decimal_comma", t.space_comma = "space_comma", t.none = "none";
})(Te || (Te = {})), (function(t) {
t.language = "language", t.system = "system", t.am_pm = "12", t.twenty_four = "24";
})(Pe || (Pe = {}));
var pe = function(t, e, i, n) {
n = n || {}, i = i ?? {};
var s = new Event(e, { bubbles: n.bubbles === void 0 || n.bubbles, cancelable: !!n.cancelable, composed: n.composed === void 0 || n.composed });
return s.detail = i, t.dispatchEvent(s), s;
}, Mt = function(t, e, i) {
var n;
return i === void 0 && (i = !1), function() {
var s = [].slice.call(arguments), o = this, r = function() {
n = null, i || t.apply(o, s);
}, a = i && !n;
clearTimeout(n), n = setTimeout(r, e), a && t.apply(o, s);
};
}, Vt = function(t, e, i) {
i === void 0 && (i = !1), i ? history.replaceState(null, "", e) : history.pushState(null, "", e), pe(window, "location-changed", { replace: i });
};
function Ze(t) {
return typeof t == "object" && t !== null && "entity" in t && typeof t.entity == "string";
}
function Et(t) {
return Array.isArray(t) && t.every((e) => typeof e == "string");
}
function Tt(t) {
return Array.isArray(t) && t.length === 3 && t.every((e) => typeof e == "number");
}
function Pt(t) {
return Array.isArray(t) && t.length === 2 && t.every((e) => typeof e == "number");
}
function Nt(t) {
return typeof t == "string" && (t === "heating" || t === "cooling" || t === "idle" || t === "off");
}
function Dt(t) {
return Nt(t) ? t : void 0;
}
function F(t) {
if (typeof t == "number" && !Number.isNaN(t))
return t;
}
function L(t) {
if (typeof t == "string")
return t;
}
function Ot(t) {
return Et(t) ? t : [];
}
function It(t) {
if (Tt(t))
return t;
}
function Ht(t) {
if (Pt(t))
return t;
}
function ie(t, e) {
return e.includes("*") ? new RegExp(`^${e.replaceAll("*", ".*")}$`).test(t) : t === e;
}
const Rt = /* @__PURE__ */ new Set(["unavailable", "unknown", "none"]);
function Lt(t) {
return Rt.has(t.toLowerCase());
}
function Ut(t, e) {
const i = t / 360, n = e / 100, s = 0.5;
let o, r, a;
if (n === 0)
o = r = a = s;
else {
const l = (u, f, d) => (d < 0 && (d += 1), d > 1 && (d -= 1), d < 0.16666666666666666 ? u + (f - u) * 6 * d : d < 0.5 ? f : d < 0.6666666666666666 ? u + (f - u) * (0.6666666666666666 - d) * 6 : u), h = s + n - s * n, c = 2 * s - h;
o = l(c, h, i + 1 / 3), r = l(c, h, i), a = l(c, h, i - 1 / 3);
}
return [Math.round(o * 255), Math.round(r * 255), Math.round(a * 255)];
}
function ye(t) {
if (t.startsWith("#")) {
const i = t.replaceAll("#", "");
return [
Number.parseInt(i.slice(0, 2), 16),
Number.parseInt(i.slice(2, 4), 16),
Number.parseInt(i.slice(4, 6), 16)
];
}
const e = /rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(t);
return e ? [
Number.parseInt(e[1] ?? "0", 10),
Number.parseInt(e[2] ?? "0", 10),
Number.parseInt(e[3] ?? "0", 10)
] : null;
}
function Bt(t, e, i) {
return (0.299 * t + 0.587 * e + 0.114 * i) / 255;
}
function Ft(t) {
const e = ye(t);
return (e ? Bt(e[0], e[1], e[2]) > 0.5 : !1) ? {
icon: "rgba(0, 0, 0, 0.7)",
label: "rgba(0, 0, 0, 0.9)",
value: "rgba(0, 0, 0, 0.7)"
} : {
icon: "rgba(255, 255, 255, 0.85)",
label: "rgba(255, 255, 255, 0.95)",
value: "rgba(255, 255, 255, 0.85)"
};
}
function S(t, e, i, n) {
const s = t.replaceAll("#", ""), o = e.replaceAll("#", ""), r = Number.parseInt(s.slice(0, 2), 16), a = Number.parseInt(s.slice(2, 4), 16), l = Number.parseInt(s.slice(4, 6), 16), h = Number.parseInt(o.slice(0, 2), 16), c = Number.parseInt(o.slice(2, 4), 16), u = Number.parseInt(o.slice(4, 6), 16), f = Math.round(r + (h - r) * i), d = Math.round(a + (c - a) * i), p = Math.round(l + (u - l) * i);
return n !== void 0 ? `rgba(${f}, ${d}, ${p}, ${n})` : `rgb(${f}, ${d}, ${p})`;
}
function jt(t) {
const { clampedValue: e, minValue: i, maxValue: n, midPoint: s, colorLow: o, colorMid: r, colorHigh: a, opacity: l } = t;
if (e <= s) {
if (i >= s)
return S(r, r, 1, l);
const h = (e - i) / (s - i);
return S(o, r, h, l);
} else {
if (n <= s)
return S(r, r, 1, l);
const h = (e - s) / (n - s);
return S(r, a, h, l);
}
}
function qt(t) {
const { clampedValue: e, minValue: i, maxValue: n, neutral: s, colorLow: o, colorHigh: r, opacity: a } = t;
if (e <= s) {
if (i >= s) return S(o, r, 0.5, a);
const l = (e - i) / (s - i);
return S(o, r, l * 0.5, a);
} else {
if (n <= s) return S(o, r, 0.5, a);
const l = (e - s) / (n - s);
return S(o, r, 0.5 + l * 0.5, a);
}
}
function Wt(t, e, i, n) {
const { colorHigh: s, colorLow: o, colorMid: r, opacity: a } = n, l = n.scaleMin ?? e, h = n.scaleMax ?? i, c = n.neutral, u = Math.max(l, Math.min(h, t)), f = c ?? (l + h) / 2;
if (r)
return jt({
clampedValue: u,
minValue: l,
maxValue: h,
midPoint: f,
colorLow: o,
colorMid: r,
colorHigh: s,
opacity: a
});
if (c !== void 0)
return qt({
clampedValue: u,
minValue: l,
maxValue: h,
neutral: c,
colorLow: o,
colorHigh: s,
opacity: a
});
if (h === l)
return S(s, s, 1, a);
const d = (u - l) / (h - l);
return S(o, s, d, a);
}
function G(t, e) {
const i = ye(t);
return i ? `rgba(${i[0]}, ${i[1]}, ${i[2]}, ${e})` : t;
}
function Gt(t) {
return t.startsWith("light.");
}
function Yt({ attributes: t, state: e }) {
const i = e === "on", n = F(t.brightness), s = i ? Math.round((n ?? 255) / 255 * 100) : 0, r = Ot(t.supported_color_modes).some(
(l) => ["rgb", "rgbw", "rgbww", "hs", "xy"].includes(l)
), a = {
brightness: s,
isOn: i,
supportsColor: r
};
if (i && r) {
const l = It(t.rgb_color), h = Ht(t.hs_color);
l ? a.rgb = l : h && (a.hs = h);
}
return a;
}
function Jt(t, e, i) {
if (!t || !t.isOn)
return e;
const n = 0.3 + t.brightness / 100 * 0.7;
if (t.supportsColor && t.rgb) {
const [o, r, a] = t.rgb;
return `rgba(${o}, ${r}, ${a}, ${n})`;
}
if (t.supportsColor && t.hs) {
const [o, r] = t.hs, [a, l, h] = Ut(o, r);
return `rgba(${a}, ${l}, ${h}, ${n})`;
}
const s = ye(i);
return s ? `rgba(${s[0]}, ${s[1]}, ${s[2]}, ${n})` : i;
}
const Zt = ["switch", "input_boolean", "binary_sensor"];
function Xt(t) {
const e = t.split(".")[0];
return Zt.includes(e ?? "");
}
function Qt({ state: t }) {
return { isOn: t === "on" };
}
function Kt(t, e, i) {
return t ? i : e;
}
function ei(t) {
return t.startsWith("climate.");
}
function ti({ attributes: t, state: e }) {
const i = F(t.current_temperature), n = F(t.temperature), s = Dt(t.hvac_action), o = e, r = i ?? null, a = n ?? null;
let l = 0, h = 0;
if (r !== null && a !== null) {
const c = r - a;
o === "heat" ? h = Math.min(c, 0) : o === "cool" ? h = Math.max(c, 0) : h = c, l = Math.abs(h);
}
return {
currentTemperature: r,
targetTemperature: a,
tempDifference: l,
tempOffset: h,
hvacAction: s ?? null,
hvacMode: o ?? null
};
}
function fe(t, e) {
return e === "temp_difference" ? t.tempDifference : e === "temp_offset" ? t.tempOffset : e === "current_temperature" ? t.currentTemperature : e === "temperature" ? t.targetTemperature : e === "hvac_action" ? t.hvacAction : e === "hvac_mode" ? t.hvacMode : null;
}
function ii(t, e = {}, i = 0) {
const { width: n = 100, height: s = 20 } = e, o = 1, r = s - i, a = e.min ?? Math.min(...t), h = (e.max ?? Math.max(...t)) - a || 1, c = t.map((f, d) => {
const p = d / (t.length - 1) * n, $ = r - o - (f - a) / h * (r - o * 2);
return `${p.toFixed(1)},${$.toFixed(1)}`;
}).join(" "), u = `0,${r} ${c} ${n},${r}`;
return { linePoints: c, fillPoints: u };
}
function ni(t) {
return t === "light" ? {
line: "rgba(255, 255, 255, 0.25)",
fillTop: "rgba(255, 255, 255, 0.25)",
fillBottom: "rgba(255, 255, 255, 0.12)"
} : {
line: "rgba(0, 0, 0, 0.15)",
fillTop: "rgba(0, 0, 0, 0.2)",
fillBottom: "rgba(0, 0, 0, 0.1)"
};
}
let oi = 0;
function si(t) {
return t === "light" ? {
heating: "rgba(255, 255, 255, 0.4)",
cooling: "rgba(255, 255, 255, 0.4)"
} : {
heating: "rgba(0, 0, 0, 0.35)",
cooling: "rgba(0, 0, 0, 0.35)"
};
}
function ri(t, e) {
const n = e * 4, s = Array.from({ length: n }, () => null);
for (const o of t) {
if (o.action !== "heating" && o.action !== "cooling") continue;
const r = Math.floor(o.start * n), a = Math.ceil(o.end * n);
for (let l = r; l < a && l < n; l++)
l >= 0 && (o.action === "heating" || s[l] !== "heating") && (s[l] = o.action);
}
return s;
}
function ai(t) {
const { segments: e, data: i, width: n, height: s, colors: o, periodHours: r } = t;
if (i.length < 2) return D``;
const a = ri(e, r), l = a.length, h = t.min ?? Math.min(...i), u = (t.max ?? Math.max(...i)) - h || 1, f = 1, d = (m) => s - f - (m - h) / u * (s - f * 2), p = (m) => {
const g = m * (i.length - 1), b = Math.floor(g), w = Math.min(Math.ceil(g), i.length - 1), A = g - b;
return (i[b] ?? 0) * (1 - A) + (i[w] ?? 0) * A;
}, $ = [];
let v = null;
for (let m = 0; m < l; m++) {
const g = a[m];
g ? v !== null && v.action === g ? v.end = (m + 1) / l : (v && $.push(v), v = { start: m / l, end: (m + 1) / l, action: g }) : v && ($.push(v), v = null);
}
return v && $.push(v), D`
${$.map((m) => {
const g = m.action === "heating" ? o.heating : o.cooling, b = 10, w = (m.end - m.start) / b;
let A = `${(m.start * n).toFixed(1)},${s}`;
for (let k = 0; k <= b; k++) {
const C = m.start + k * w, y = C * n, z = d(p(C));
A += ` ${y.toFixed(1)},${z.toFixed(1)}`;
}
return A += ` ${(m.end * n).toFixed(1)},${s}`, D`<polygon points="${A}" fill="${g}" />`;
})}
`;
}
function Ne(t, e = {}, i) {
const { width: n = 100, height: s = 20, mode: o = "dark", line: r, fill: a, hvac: l, periodHours: h = 24 } = e, c = t.length > 1, u = l?.show !== !1 && i && i.length > 0, { linePoints: f, fillPoints: d } = c ? ii(t, e, 0) : { linePoints: "", fillPoints: "" }, p = ni(o), $ = si(o), v = a?.show !== !1 && c, m = r?.show !== !1 && c, g = `sparkline-gradient-${oi++}`, b = !!a?.style, w = a?.style || `fill: url(#${g});`, A = `stroke: ${p.line}; stroke-width: 1.5;`, k = r?.style ? `${A} ${r.style}` : A;
return D`
<svg viewBox="0 0 ${n} ${s}" preserveAspectRatio="none">
${v && !b ? D`
<defs>
<linearGradient id="${g}" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color: ${p.fillTop};" />
<stop offset="100%" style="stop-color: ${p.fillBottom};" />
</linearGradient>
</defs>
` : _}
${u && c ? ai({ segments: i, data: t, width: n, height: s, colors: $, periodHours: h, min: e.min, max: e.max }) : _}
${v && !i ? D`<polygon points="${d}" style="${w}" />` : _}
${m ? D`<polyline points="${f}" style="fill: none; stroke-linecap: round; stroke-linejoin: round; ${k}" />` : _}
</svg>
`;
}
function li(t, e = {}) {
if (t && typeof t == "object" && "temperature" in t) {
const i = t, n = i.temperature && i.temperature.length > 1, s = i.hvacActions && i.hvacActions.length > 0;
return n || s ? Ne(
n ? i.temperature : [],
e,
i.hvacActions
) : _;
}
return Array.isArray(t) && t.length > 1 ? Ne(t, e) : _;
}
function ci(t) {
return t === "heating" || t === "cooling" || t === "idle" || t === "off";
}
const Xe = {
"12h": { hours: 12, statsPeriod: "5minute" },
"24h": { hours: 24, statsPeriod: "hour" },
"7d": { hours: 168, statsPeriod: "hour" },
"30d": { hours: 720, statsPeriod: "day" }
}, De = /* @__PURE__ */ new Map(), hi = 300 * 1e3;
async function ui(t, e, i = "24h") {
const n = /* @__PURE__ */ new Map(), s = Date.now(), o = [];
for (const r of e) {
const a = `${r}:${i}`, l = De.get(a);
l && s - l.fetchedAt < hi ? n.set(r, l.data) : o.push(r);
}
if (o.length > 0) {
const r = await di(t, o, i);
for (const [a, l] of r) {
const h = `${a}:${i}`;
De.set(h, { data: l, fetchedAt: s }), n.set(a, l);
}
}
return n;
}
async function di(t, e, i) {
const n = /* @__PURE__ */ new Map();
if (e.length === 0)
return n;
const s = e.filter((r) => r.startsWith("climate.")), o = e.filter((r) => !r.startsWith("climate."));
if (o.length > 0) {
const r = await Qe(t, o, i);
for (const [a, l] of r)
n.set(a, { temperature: l });
}
if (s.length > 0) {
const r = await fi(t, s, i);
for (const [a, l] of r)
n.set(a, l);
}
return n;
}
async function fi(t, e, i) {
const n = /* @__PURE__ */ new Map(), s = Xe[i], o = new Date(Date.now() - s.hours * 60 * 60 * 1e3), r = await Qe(t, e, i), a = [];
for (const h of e) {
const c = r.get(h);
!c || c.length === 0 ? a.push(h) : n.set(h, { temperature: c });
}
const l = await pi(t, e, o, s);
for (const h of a) {
const c = l.get(h);
c && c.temperature.length > 0 && n.set(h, { temperature: c.temperature });
}
for (const [h, c] of l) {
const u = n.get(h);
u ? u.hvacActions = c.hvacActions : n.set(h, { temperature: [], hvacActions: c.hvacActions });
}
return n;
}
async function pi(t, e, i, n) {
const s = /* @__PURE__ */ new Map();
if (e.length === 0)
return s;
try {
const o = await t.callWS({
type: "history/history_during_period",
start_time: i.toISOString(),
entity_ids: e,
no_attributes: !1,
significant_changes_only: !1
// Get all changes for better temperature resolution
});
if (o) {
const r = n.hours * 60 * 60 * 1e3, a = Date.now();
for (const l of e) {
const h = o[l];
if (h && h.length > 0) {
const c = gi(h), u = _i(h, i.getTime(), a, r);
s.set(l, {
temperature: c,
hvacActions: u
});
}
}
}
} catch (o) {
console.warn("[treemap] Failed to fetch climate history:", o);
}
return s;
}
function gi(t) {
const e = [], n = Math.max(1, Math.floor(t.length / 60));
for (let s = 0; s < t.length; s += n) {
const o = t[s];
if (!o) continue;
const a = (o.attributes || o.a)?.current_temperature;
typeof a == "number" && !Number.isNaN(a) && e.push(a);
}
return e;
}
function _i(t, e, i, n) {
const s = [];
for (let o = 0; o < t.length; o++) {
const r = t[o];
if (!r) continue;
const a = t[o + 1], h = (r.attributes || r.a)?.hvac_action;
if (!ci(h) || h === "idle" || h === "off") continue;
const c = h, u = r.last_updated ? new Date(r.last_updated).getTime() : new Date((r.lu ?? 0) * 1e3).getTime();
let f;
a ? f = a.last_updated ? new Date(a.last_updated).getTime() : new Date((a.lu ?? 0) * 1e3).getTime() : f = i;
const d = Math.max(0, (u - e) / n), p = Math.min(1, (f - e) / n);
d < 1 && p > 0 && s.push({ start: d, end: p, action: c });
}
return s;
}
async function Qe(t, e, i) {
const n = /* @__PURE__ */ new Map();
if (e.length === 0)
return n;
const s = Xe[i], o = new Date(Date.now() - s.hours * 60 * 60 * 1e3).toISOString();
try {
const r = await t.callWS({
type: "recorder/statistics_during_period",
start_time: o,
statistic_ids: e,
period: s.statsPeriod
});
if (r)
for (const [a, l] of Object.entries(r)) {
const h = l.map(({ mean: c }) => c).filter((c) => c != null);
n.set(a, h);
}
} catch (r) {
console.warn("[treemap] Failed to fetch statistics:", r);
for (const a of e)
n.has(a) || n.set(a, []);
}
return n;
}
function Oe(t, e) {
if (t.length === 0) return 1 / 0;
const i = t.reduce((a, l) => a + l, 0), n = Math.max(...t), s = Math.min(...t), o = e * e, r = i * i;
return Math.max(o * n / r, r / (o * s));
}
function mi(t, e, i) {
const n = t.reduce((r, a) => r + a.normalizedValue, 0), s = [];
let o = 0;
if (i) {
const r = n / e.height;
for (const a of t) {
const l = a.normalizedValue / r;
s.push({
label: a.item.label,
value: a.item.value,
sizeValue: a.item.sizeValue,
sortValue: a.item.sortValue,
colorValue: a.item.colorValue,
entity_id: a.item.entity_id,
icon: a.item.icon,
light: a.item.light,
climate: a.item.climate,
binary: a.item.binary,
color: a.item.color,
sparklineData: a.item.sparklineData,
unavailable: a.item.unavailable,
rawState: a.item.rawState,
x: e.x,
y: e.y + o,
width: r,
height: l
}), o += l;
}
return {
rects: s,
remaining: {
x: e.x + r,
y: e.y,
width: e.width - r,
height: e.height
}
};
} else {
const r = n / e.width;
for (const a of t) {
const l = a.normalizedValue / r;
s.push({
label: a.item.label,
value: a.item.value,
sizeValue: a.item.sizeValue,
sortValue: a.item.sortValue,
colorValue: a.item.colorValue,
entity_id: a.item.entity_id,
icon: a.item.icon,
light: a.item.light,
climate: a.item.climate,
binary: a.item.binary,
color: a.item.color,
sparklineData: a.item.sparklineData,
unavailable: a.item.unavailable,
rawState: a.item.rawState,
x: e.x + o,
y: e.y,
width: l,
height: r
}), o += l;
}
return {
rects: s,
remaining: {
x: e.x,
y: e.y + r,
width: e.width,
height: e.height - r
}
};
}
}
function bi(t, e, i) {
return e === "default" ? [...t] : [...t].sort((n, s) => {
let o;
if (e === "entity_id") {
const r = n.entity_id ?? "", a = s.entity_id ?? "";
o = r.localeCompare(a);
} else e === "label" ? o = n.label.localeCompare(s.label) : o = n.sortValue - s.sortValue;
return i ? o : -o;
});
}
function Ie(t, e, i, n = !1, s = "value") {
const o = t.length;
if (o === 0) return { rects: [], rows: 0 };
const r = e / i;
let a = Math.ceil(Math.sqrt(o * r)), l = Math.ceil(o / a);
for (; a * (l - 1) >= o && l > 1; ) l--;
for (; (a - 1) * l >= o && a > 1; ) a--;
const h = e / a, c = i / l;
return { rects: bi(t, s, n).map((d, p) => ({
label: d.label,
value: d.value,
sizeValue: d.sizeValue,
sortValue: d.sortValue,
colorValue: d.colorValue,
entity_id: d.entity_id,
icon: d.icon,
light: d.light,
climate: d.climate,
binary: d.binary,
color: d.color,
sparklineData: d.sparklineData,
unavailable: d.unavailable,
rawState: d.rawState,
x: p % a * h,
y: Math.floor(p / a) * c,
width: h,
height: c
})), rows: l };
}
function vi(t, e, i, n) {
const s = t.map((c) => Math.abs(c.value)), o = Math.max(...s), r = e ? s.map((c) => Math.sqrt(c / o) * o) : s, a = r.reduce((c, u) => c + u, 0), l = [];
for (const [c, u] of t.entries()) {
const f = s[c], d = r[c];
f !== void 0 && d !== void 0 && d > 0 && u && l.push({ item: u, absValue: f, sizeValue: d });
}
const h = l.map(({ item: c, sizeValue: u }) => ({
item: c,
normalizedValue: u / a * i
}));
return n === "default" || (n === "entity_id" ? h.sort((c, u) => {
const f = c.item.entity_id ?? "", d = u.item.entity_id ?? "";
return f.localeCompare(d);
}) : n === "label" ? h.sort((c, u) => c.item.label.localeCompare(u.item.label)) : h.sort((c, u) => u.normalizedValue - c.normalizedValue)), h;
}
function yi(t, e) {
const i = [];
let n = [], s = [...t];
for (; s.length > 0; ) {
const o = s[0];
if (!o) break;
const r = [...n, o.normalizedValue], a = Oe(n, e), l = Oe(r, e), h = s.length <= 3 && n.length > 0;
if (n.length > 0 && l > a && !h)
break;
i.push(o), n = r, s = s.slice(1);
}
return { row: i, rowValues: n, newRemaining: s };
}
function $i(t, e, i) {
for (const o of t)
o.x = e - o.x - o.width, o.y = i - o.y - o.height;
const n = Math.min(...t.map((o) => o.x)), s = Math.min(...t.map((o) => o.y));
if (n !== 0 || s !== 0)
for (const o of t)
o.x -= n, o.y -= s;
}
function xi(t, e, i, n = {}) {
const { compressRange: s = !0, equalSize: o = !1, ascending: r = !1, sortBy: a = "value" } = n;
if (t.length === 0) return { rects: [], rows: 0 };
if (o)
return Ie(t, e, i, r, a);
const l = t.map((g) => Math.abs(g.value)), h = Math.max(...l);
if (h === 0) return { rects: [], rows: 0 };
const c = l.filter((g) => g > 0);
if (c.length > 1) {
const g = Math.min(...c);
if ((h - g) / h < 0.01)
return Ie(t, e, i, r, a);
}
const u = e * i, f = vi(t, s, u, a), d = [];
let p = { x: 0, y: 0, width: e, height: i }, $ = [...f];
for (; $.length > 0; ) {
const g = p.width < p.height, b = g ? p.height : p.width, { row: w, newRemaining: A } = yi($, b);
$ = A;
const { rects: k, remaining: C } = mi(w, p, g);
if (d.push(...k), p = C, p.width <= 0 || p.height <= 0) break;
}
r && d.length > 0 && $i(d, e, i);
const m = new Set(d.map((g) => Math.round(g.y * 100) / 100)).size;
return { rects: d, rows: m };
}
function wi(t) {
let e = Number.POSITIVE_INFINITY, i = Number.NEGATIVE_INFINITY, n = Number.POSITIVE_INFINITY, s = Number.NEGATIVE_INFINITY;
for (const o of t)
o.colorValue < e && (e = o.colorValue), o.colorValue > i && (i = o.colorValue), o.sizeValue < n && (n = o.sizeValue), o.sizeValue > s && (s = o.sizeValue);
return { colorMin: e, colorMax: i, sizeMin: n, sizeMax: s };
}
function Ai(t, e, i) {
const n = i + e;
for (const r of t)
r.sizeValue = n - r.sizeValue, r.sortValue = -r.sortValue;
const s = n - e, o = s * 0.1;
for (const r of t)
r.sizeValue < o && (r.sizeValue = o);
return s;
}
function He(t, e, i) {
const n = e ? !i : i;
return [...t].sort(
(s, o) => n ? s.sizeValue - o.sizeValue : o.sizeValue - s.sizeValue
);
}
function ki(t, e) {
let i = 1;
for (const n of t)
e !== void 0 && n.sizeValue > e && (n.sizeValue = e), n.sizeValue > i && (i = n.sizeValue);
return i;
}
function Ci(t, e, i) {
const n = e ?? i * 0.15;
for (const s of t)
s.sizeValue < n && (s.sizeValue = n);
}
function Si(t, e = {}) {
const { inverse: i = !1, ascending: n = !1, limit: s, sizeMin: o, sizeMax: r, sortBy: a } = e;
if (t.length === 0)
return { items: [], colorMin: 0, colorMax: 0 };
const l = wi(t);
if (l.sizeMin < 0) {
const f = Math.abs(l.sizeMin);
for (const d of t)
d.sizeValue = d.sizeValue + f;
l.sizeMin = 0, l.sizeMax = l.sizeMax + f;
}
i && Ai(t, l.sizeMin, l.sizeMax);
const h = !a || a === "value";
let c;
if (h) {
const f = He(t, i, n);
c = s !== void 0 && s > 0 ? f.slice(0, s) : f;
} else if (s !== void 0 && s > 0) {
const f = He(t, i, n), d = new Set(f.slice(0, s).map((p) => p.entity_id ?? p.label));
c = t.filter((p) => d.has(p.entity_id ?? p.label));
} else
c = [...t];
const u = ki(c, r);
return Ci(c, o, u), { items: c, colorMin: l.colorMin, colorMax: l.colorMax };
}
const zi = [
{ threshold: 1e12, suffix: "T" },
{ threshold: 1e9, suffix: "B" },
{ threshold: 1e6, suffix: "M" },
{ threshold: 1e3, suffix: "k" }
];
function Mi(t, e = 1, i = !1) {
let n = t, s = "";
if (i) {
for (const o of zi)
if (Math.abs(t) >= o.threshold) {
n = t / o.threshold, s = o.suffix;
break;
}
}
return n.toFixed(e) + s;
}
function Vi(t, e) {
return t !== void 0 ? t : e !== void 0 ? e : 1;
}
const Ei = Fe`
:host {
display: block;
}
ha-card {
height: 100%;
display: flex;
flex-direction: column;
}
.treemap-header {
padding: 8px 16px 0px;
font-size: 16px;
font-weight: 500;
color: var(--primary-text-color);
}
.card-content {
flex: 1;
padding: 16px;
}
.treemap-container {
position: relative;
width: 100%;
border-radius: 8px;
overflow: hidden;
}
.treemap-item {
position: absolute;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 8px;
overflow: hidden;
cursor: pointer;
transition: filter 0.2s ease;
border-radius: 8px;
}
.treemap-item:hover {
filter: brightness(1.1);
}
.treemap-icon {
--mdc-icon-size: 28px;
opacity: 0.85;
}
/* Pulsing animation for active HVAC states (heating/cooling) */
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.treemap-icon.hvac-active {
animation: pulse 2s ease-in-out infinite;
}
.treemap-label {
font-size: 14px;
font-weight: 600;
color: white;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
opacity: 0.9;
}
.treemap-value {
font-size: 14px;
font-weight: 500;
color: rgba(255, 255, 255, 0.85);
opacity: 0.85;
}
.treemap-item.small .treemap-icon {
--mdc-icon-size: 20px;
}
.treemap-item.small .treemap-label {
font-size: 9px;
}
.treemap-item.small .treemap-value {
font-size: 12px;
}
.treemap-item.tiny .treemap-icon {
--mdc-icon-size: 16px;
}
.treemap-item.tiny .treemap-label {
font-size: 8px;
}
.treemap-item.tiny .treemap-value {
display: none;
}
.error {
color: var(--error-color, #db4437);
padding: 16px;
}
.empty {
color: var(--secondary-text-color, #727272);
padding: 16px;
text-align: center;
}
/* Sparkline styles */
.treemap-sparkline {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 20px;
pointer-events: none;
}
.treemap-sparkline svg {
width: 100%;
height: 100%;
}
.treemap-item.small .treemap-sparkline {
height: 14px;
}
.treemap-item.tiny .treemap-sparkline {
display: none;
}
`;
var Ti = Object.defineProperty, Pi = Object.getOwnPropertyDescriptor, he = (t, e, i, n) => {
for (var s = n > 1 ? void 0 : n ? Pi(e, i) : e, o = t.length - 1, r; o >= 0; o--)
(r = t[o]) && (s = (n ? r(e, i, s) : r(s)) || s);
return n && s && Ti(e, i, s), s;
};
const Ni = "0.15.2";
console.info(
`%c TREEMAP-CARD %c v${Ni}`,
"color: white; background: #3498db; font-weight: bold;",
"color: #3498db; background: white; font-weight: bold;"
);
let T = class extends B {
constructor() {
super(...arguments), this._sparklineData = /* @__PURE__ */ new Map(), this._fetchingSparklines = !1, this._debouncedFetchSparklines = Mt(() => void this._fetchSparklineData(), 100), this._entityConfigMap = /* @__PURE__ */ new Map(), this._holdTimer = null, this._holdFired = !1;
}
/**
* Return the editor element for visual configuration
*/
static getConfigElement() {
return Promise.resolve().then(() => rn), document.createElement("treemap-card-editor");
}
/**
* Return stub config for card picker (finds temperature sensors for preview)
*/
static getStubConfig(t) {
const e = Object.keys(t.states).filter((i) => i.startsWith("sensor.") ? t.states[i]?.attributes?.device_class === "temperature" : !1).slice(0, 3);
return {
type: "custom:treemap-card",
entities: e.length > 0 ? e : ["sensor.*"]
};
}
/**
* Optimize re-renders: only update when relevant entity states change
*/
shouldUpdate(t) {
if (t.has("_config") || t.has("_sparklineData"))
return !0;
if (t.has("hass") && this.hass && this._config) {
const e = this._getRelevantStatesHash();
return e !== this._lastRelevantStates ? (this._lastRelevantStates = e, !0) : !1;
}
return !0;
}
/**
* Get a hash of relevant entity states for change detection
*/
_getRelevantStatesHash() {
if (!this.hass) return "";
const t = this._getConfiguredEntityIds(), e = [];
for (const i of t) {
const n = this.hass.states[i];
n && e.push(`${i}:${n.state}:${n.last_updated}`);
}
return e.join("|");
}
/**
* Get entity IDs from config (supports wildcards)
*/
_getConfiguredEntityIds() {
if (!this.hass || !this._config) return [];
if (this._config.entity)
return [this._config.entity];
if (this._config.entities) {
const t = Object.keys(this.hass.states), e = [];
for (const i of this._config.entities) {
const { entity: n } = this._normalizeEntity(i);
if (n.includes("*"))
for (const s of t)
ie(s, n) && e.push(s);
else
e.push(n);
}
return e;
}
return [];
}
setConfig(t) {
if (!t.entities && !t.entity)
throw new Error('Please define "entities" (list) or "entity" (single with JSON array)');
if (this._config = {
gap: 4,
// smaller gap
...t
}, this._entityConfigMap = /* @__PURE__ */ new Map(), t.entities)
for (const e of t.entities) {
const i = this._normalizeEntity(e);
(i.tap_action || i.hold_action || i.double_tap_action) && this._entityConfigMap.set(i.entity, i);
}
}
/**
* Normalize EntityInput to object format
* Converts "sensor.foo" to { entity: "sensor.foo" }
* Preserves existing { entity, name, icon } objects as-is
*/
_normalizeEntity(t) {
return typeof t == "string" ? { entity: t } : Ze(t) ? t : { entity: String(t) };
}
getCardSize() {
return 4;
}
updated() {
this._debouncedFetchSparklines();
}
async _fetchSparklineData() {
if (!this.hass || this._fetchingSparklines || this._config?.sparkline?.show === !1) return;
const e = this._resolveData().map(({ entity_id: i }) => i).filter((i) => !!i);
if (e.length !== 0) {
this._fetchingSparklines = !0;
try {
const i = this._config?.sparkline?.period || "24h", n = await ui(this.hass, e, i);
n.size > 0 && !this._sparklineDataEquals(n) && (this._sparklineData = n);
} finally {
this._fetchingSparklines = !1;
}
}
}
/**
* Compare sparkline data maps to avoid unnecessary re-renders.
*/
_sparklineDataEquals(t) {
if (this._sparklineData.size !== t.size) return !1;
for (const [e, i] of t) {
const n = this._sparklineData.get(e);
if (!n || n.temperature.length !== i.temperature.length) return !1;
const s = n.hvacActions?.length ?? 0, o = i.hvacActions?.length ?? 0;
if (s !== o) return !1;
}
return !0;
}
/**
* Get period hours from config for HVAC quantization.
*/
_getPeriodHours() {
const t = this._config?.sparkline?.period || "24h";
return {
"12h": 12,
"24h": 24,
"7d": 168,
"30d": 720
}[t] ?? 24;
}
_resolveData() {
if (!this.hass || !this._config) return [];
const t = this._lastRelevantStates;
if (this._cachedData && this._cachedDataHash === t)
return this._cachedData;
let e;
return this._config.entities ? e = this._resolveEntities(this._config.entities) : this._config.entity ? e = this._resolveJsonEntity(this._config.entity) : e = [], this._cachedData = e, this._cachedDataHash = t, e;
}
_isExcluded(t) {
const e = this._config?.exclude;
if (!e || e.length === 0) return !1;
for (const i of e)
if (ie(t, i))
return !0;
return !1;
}
_resolveEntities(t) {
if (!this.hass) return [];
const e = [], i = Object.keys(this.hass.states);
for (const n of t) {
const {
entity: s,
name: o,
icon: r,
color: a
} = this._normalizeEntity(n), l = i.filter(
(h) => ie(h, s) && !this._isExcluded(h)
);
for (const h of l) {
const c = this.hass.states[h];
if (!c) continue;
const u = this._config?.label?.attribute || "friendly_name", f = u === "entity_id" ? h : String(c.attributes[u] ?? h.split(".").pop() ?? h), d = o ?? f, p = r ?? L(c.attributes.icon);
if (Gt(h)) {
const g = Yt(c), { brightness: b } = g;
let w;
g.isOn ? w = 40 + b / 100 * 60 : w = 10, e.push({
label: d,
value: b,
// Display brightness as percentage
sizeValue: w,
sortValue: b,
colorValue: b,
entity_id: h,
icon: p ?? "mdi:lightbulb",
unit: "%",
light: g,
color: a
});
continue;
}
if (ei(h)) {
const g = ti(c), b = this._config?.value?.attribute || "current_temperature", w = this._config?.size?.attribute || b, A = this._config?.color?.attribute || b;
let k = fe(g, b), C = fe(g, w), y = fe(g, A);
k === null && (k = F(c.attributes[b]) ?? 0), C === null && (C = F(c.attributes[w]) ?? 0), y === null && (y = F(c.attributes[A]) ?? 0);
const z = typeof k == "number" ? k : 0, M = typeof C == "number" ? Math.max(0.1, Math.abs(C)) : 0.1, st = typeof y == "number" ? y : 0;
let R;
if (p)
R = p;
else
switch (g.hvacAction) {
case "heating": {
R = "mdi:fire";
break;
}
case "cooling": {
R = "mdi:snowflake";
break;
}
case "off": {
R = "mdi:thermostat-off";
break;
}
default:
R = "mdi:thermostat";
}
e.push({
label: d,
value: z,
sizeValue: M,
sortValue: z,
colorValue: st,
entity_id: h,
icon: R,
unit: L(c.attributes.unit_of_measurement),
climate: g,
color: a
});
continue;
}
if (Xt(h)) {
const g = Qt(c), { isOn: b } = g;
e.push({
label: d,
value: b ? 1 : 0,
sizeValue: 1,
// Equal size for all binary entities
sortValue: b ? 1 : 0,
colorValue: b ? 1 : 0,
entity_id: h,
icon: p,
binary: g,
color: a
});
continue;
}
const $ = this._config?.value?.attribute || "state";
let v;
if ($ === "state")
v = Number.parseFloat(c.state);
else {
const g = c.attributes[$];
v = Number.parseFloat(String(g ?? 0));
}
if (Number.isNaN(v)) {
if (!Lt(c.state) || !this._config?.filter?.unavailable)
continue;
const b = L(c.attributes.unit_of_measurement);
e.push({
label: d,
value: 0,
// Placeholder value for sizing
sizeValue: 1,
// Minimal size
sortValue: 0,
colorValue: 0,
entity_id: h,
icon: p,
unit: b,
unavailable: !0,
rawState: c.state,
color: a
});
continue;
}
const m = L(c.attributes.unit_of_measurement);
e.push({
label: d,
value: v,
sizeValue: v,
sortValue: v,
colorValue: v,
entity_id: h,
icon: p,
unit: m,
color: a
});
}
}
return e;
}
_resolveJsonEntity(t) {
if (!this.hass) return [];
const e = this.hass.states[t];
if (!e) return [];
const i = this._config?.data_attribute || "items", n = e.attributes[i];
if (!Array.isArray(n)) return [];
const s = this._config?.label?.attribute ?? this._config?.label?.param ?? "label", o = this._config?.value?.attribute ?? this._config?.value?.param ?? "value", r = this._config?.size?.attribute ?? this._config?.size?.param ?? o, a = this._config?.color?.attribute ?? this._config?.color?.param ?? o, l = this._config?.icon?.attribute ?? this._config?.icon?.param ?? "icon", h = this._config?.sparkline?.attribute;
return n.filter((c) => typeof c == "object" && c !== null).map((c) => {
let u;
if (h) {
const d = c[h];
Array.isArray(d) && (u = d.filter((p) => typeof p == "number"));
}
const f = Number(c[o] ?? 0);
return {
label: String(c[s] ?? c.label ?? ""),
value: f,
sizeValue: Number(c[r] ?? c[o] ?? 0),
sortValue: f,
colorValue: Number(c[a] ?? c[o] ?? 0),
icon: L(c[l]),
entity_id: L(c.entity_id),
sparklineData: u
};
}).filter((c) => c.label && !Number.isNaN(c.value));
}
_getGradientColorOptions() {
return {
colorHigh: this._config?.color?.high || "#16a34a",
colorLow: this._config?.color?.low || "#b91c1c",
colorMid: this._config?.color?.mid,
scaleMin: this._config?.color?.scale?.min,
scaleMax: this._config?.color?.scale?.max,
neutral: this._config?.color?.scale?.neutral,
opacity: this._config?.color?.opacity
};
}
_getColor(t, e, i) {
return Wt(t, e, i, this._getGradientColorOptions());
}
_getSizeClass(t) {
const e = t.width * t.height;
return e < 50 ? "tiny" : e < 150 ? "small" : "";
}
_getLightColor(t) {
const e = this._config?.color?.low ?? "#333333", i = this._config?.color?.high ?? "#fbbf24";
return Jt(t.light, e, i);
}
_filterData(t) {
if (!this._config) return t;
const e = this._config.filter?.above, i = this._config.filter?.below;
return t.filter((n) => n.unavailable ? !0 : !(e !== void 0 && n.value <= e || i !== void 0 && n.value >= i));
}
render() {
if (!this._config)
return x`<ha-card><div class="error">No configuration</div></ha-card>`;
const t = this._resolveData(), e = this._filterData(t), i = !!this._config.header?.title, n = this._config.header?.title, s = this._config.header?.show ?? !!n, o = this._config.header?.style || "", r = this._config.card_style || "", a = i ? void 0 : this._config.title;
if (e.length === 0)
return x`
<ha-card header="${a || _}" style="${r}">
${s && n ? x`<div class="treemap-header" style="${o}">${n}</div>` : _}
<div class="card-content">
<div class="empty">No data available</div>
</div>
</ha-card>
`;
const {
items: l,
colorMin: h,
colorMax: c
} = Si(e, {
inverse: this._config?.size?.inverse,
ascending: this._config?.order === "asc",
limit: this._config?.limit,
sizeMin: this._config?.size?.min,
sizeMax: this._config?.size?.max,
sortBy: this._config?.sort_by ?? "value"
}), u = this._config?.size?.equal === !0, f = /* @__PURE__ */ new Map();
for (const y of l) {
const z = y.entity_id ?? y.label;
f.set(z, {
value: y.value,
sortValue: y.sortValue,
colorValue: y.colorValue,
sizeValue: y.sizeValue,
unit: y.unit
});
}
const d = l.map((y) => ({ ...y, value: y.sizeValue })), p = this._config?.order === "asc", v = this._config?.size?.inverse === !0 ? !p : p, m = this._config?.sort_by ?? "value", { rects: g, rows: b } = xi(d, 100, 100, {
compressRange: !0,
equalSize: u,
ascending: v,
sortBy: m
});
for (const y of g) {
const z = y.entity_id ?? y.label, M = f.get(z);
M && (y.value = M.value, y.sortValue = M.sortValue, y.colorValue = M.colorValue, y.sizeValue = M.sizeValue, y.unit = M.unit);
}
const w = Math.max(1, b), A = Math.max(100, w * 100), k = this._config.height ?? A, C = this._config.gap ?? 6;
return x`
<ha-card header="${a || _}" style="${r}">
${s && n ? x`<div class="treemap-header" style="${o}">${n}</div>` : _}
<div class="card-content">
<div class="treemap-container" style="height: ${k}px">
${g.map((y) => this._renderRect(y, h, c, k, C))}
</div>
</div>
</ha-card>
`;
}
/**
* Determine color for a treemap rect based on entity type and state.
* Priority: unavailable > climate off > climate HVAC active > light > gradient
*/
_getRectColor(t, e, i) {
const n = this._config?.color?.opacity;
if (t.color)
return n === void 0 ? t.color : G(t.color, n);
if (t.unavailable) {
const s = this._config?.color?.unavailable ?? "#868e96";
return n === void 0 ? s : G(s, n);
}
if (t.climate && (t.climate.hvacMode === "off" || t.climate.hvacMode === "unavailable")) {
const s = this._config?.color?.hvac?.off ?? "#868e96";
return n === void 0 ? s : G(s, n);
}
if (t.climate && this._config?.color?.hvac) {
const s = this._config.color.hvac;
if (t.climate.hvacAction === "heating" && s.heating)
return n === void 0 ? s.heating : G(s.heating, n);
if (t.climate.hvacAction === "cooling" && s.cooling)
return n === void 0 ? s.cooling : G(s.cooling, n);
}
if (t.light)
return this._getLightColor(t);
if (t.binary) {
const s = this._config?.color?.low ?? "#333333", o = this._config?.color?.high ?? "#22c55e";
return Kt(t.binary.isOn, s, o);
}
return this._getColor(t.colorValue, e, i);
}
/**
* Format label with replace regex and prefix/suffix.
*/
_formatLabel(t) {
let e = t.label;
const i = this._config?.label?.replace;
if (i) {
const o = i.split("/"), r = o[0], a = o[1];
if (o.length >= 2 && r !== void 0 && a !== void 0)
try {
const l = new RegExp(r, o[2] ?? "");
e = t.label.replace(l, a);
} catch {
}
}
const n = this._config?.label?.prefix || "", s = this._config?.label?.suffix || "";
return `${n}${e}${s}`;
}
/**
* Format value with precision, abbreviation, prefix/suffix, and unit.
*/
_formatValue(t) {
const e = this._config?.value?.prefix, i = this._config?.value?.suffix;
if (t.unavailable && t.rawState)
return t.rawState.charAt(0).toUpperCase() + t.rawState.slice(1);
if (t.binary)
return t.binary.isOn ? "On" : "Off";
const n = t.entity_id ? this.hass?.entities?.[t.entity_id]?.display_precision : void 0, s = Vi(this._config?.value?.precision, n), o = this._config?.value?.abbreviate ?? !1, r = Mi(t.value, s, o), l = this._config?.value?.attribute === "temp_offset" && t.value > 0 ? "+" : "", h = e !== void 0 || i !== void 0, c = t.unit ? " " + t.unit : "";
return h ? `${e ?? ""}${l}${r}${i ?? ""}` : `${l}${r}${c}`;
}
/**
* Calculate styles for icon, label, and value based on color target mode.
*/
_calculateStyles(t) {
const i = (this._config?.color?.target ?? "background") === "foreground", n = i ? "rgba(0, 0, 0, 0.1)" : t, s = i ? { icon: t, label: t, value: t } : Ft(t), o = this._config?.icon?.style || `color: ${s.icon};`, r = this._config?.label?.style || `color: ${s.label};`, a = this._config?.value?.style || `color: ${s.value};`;
return { backgroundColor: n, iconStyle: o, labelStyle: r, valueStyle: a };
}
_renderRect(t, e, i, n, s) {
const o = this._getRectColor(t, e, i), r = this._getSizeClass(t), a = t.climate?.hvacAction === "heating" || t.climate?.hvacAction === "cooling", l = this._config?.icon?.show ?? !0, h = this._config?.label?.show ?? !0, c = this._config?.value?.show ?? !0, u = this._formatLabel(t), f = this._formatValue(t), { backgroundColor: d, iconStyle: p, labelStyle: $, valueStyle: v } = this._calculateStyles(o), m = s / 2;
return x`
<div
class="treemap-item ${r}"
style="
left: calc(${t.x}% + ${m}px);
top: calc(${t.y}% + ${m}px);
width: calc(${t.width}% - ${s}px);
height: calc(${t.height}% - ${s}px);
background-color: ${d};
"
@pointerdown="${(g) => this._onPointerDown(g, t)}"
@pointerup="${(g) => this._onPointerUp(g, t)}"
@pointercancel="${() => this._clearHoldTimer()}"
title="${t.label}: ${t.value}"
>
${l && (t.icon || this._config?.icon?.icon) ? x`<ha-icon
class="treemap-icon ${a ? "hvac-active" : ""}"
style="${p}"
icon="${t.icon || this._config?.icon?.icon}"
></ha-icon>` : _}
${h ? x`<span class="treemap-label" style="${$}">${u}</span>` : _}
${c ? x`<span class="treemap-value" style="${v}">${f}</span>` : _}
${this._config?.sparkline?.show !== !1 ? (() => {
const g = t.sparklineData ?? (t.entity_id ? this._sparklineData.get(t.entity_id) : void 0);
return x`<div class="treemap-sparkline">
${li(g, {
mode: this._config?.sparkline?.mode || "dark",
line: this._config?.sparkline?.line,
fill: this._config?.sparkline?.fill,
hvac: this._config?.sparkline?.hvac,
periodHours: this._getPeriodHours(),
min: this._config?.sparkline?.min,
max: this._config?.sparkline?.max
})}
</div>`;
})() : _}
</div>
`;
}
/**
* Get the effective action config for a rect, with per-entity override support.
*/
_getActionConfig(t, e) {
if (this._entityConfigMap.size > 0 && t.entity_id) {
const n = this._entityConfigMap.get(t.entity_id);
if (n?.[e]) return n[e];
for (const [s, o] of this._entityConfigMap)
if (o[e] && ie(t.entity_id, s))
return o[e];
}
const i = this._config?.[e];
return i || { action: e === "tap_action" ? "more-info" : "none" };
}
_executeAction(t, e) {
switch (t.action) {
case "more-info":
e && pe(this, "hass-more-info", { entityId: e });
break;
case "navigate":
"navigation_path" in t && t.navigation_path && Vt(this, t.navigation_path);
break;
case "url":
"url_path" in t && t.url_path && window.open(t.url_path);
break;
case "toggle":
if (e && this.hass) {
const i = e.split(".")[0] ?? "homeassistant";
this.hass.callService(i, "toggle", { entity_id: e });
}
break;
case "call-service":
if ("service" in t && t.service && this.hass) {
const i = t.service.split("."), n = i[0] ?? "", s = i[1] ?? "";
this.hass.callService(n, s, t.service_data);
}
break;
case "assist":
pe(this, "hass-launch-voice-assistant", {});
break;
}
}
_onPointerDown(t, e) {
if (t.button !== 0 && t.pointerType === "mouse") return;
this._holdFired = !1, this._clearHoldTimer();
const i = this._getActionConfig(e, "hold_action");
i.action !== "none" && (this._holdTimer = setTimeout(() => {
this._holdFired = !0, this._clearHoldTimer(), this._executeAction(i, e.entity_id);
}, T._HOLD_THRESHOLD_MS));
}
_onPointerUp(t, e) {
if (t.button !== 0 && t.pointerType === "mouse" || (this._clearHoldTimer(), this._holdFired)) return;
const i = this._getActionConfig(e, "tap_action");
i.action !== "none" && this._executeAction(i, e.entity_id);
}
_clearHoldTimer() {
this._holdTimer !== null && (clearTimeout(this._holdTimer), this._holdTimer = null);
}
};
T.styles = Ei;
T._HOLD_THRESHOLD_MS = 500;
he([
ce({ attribute: !1 })
], T.prototype, "hass", 2);
he([
ve()
], T.prototype, "_config", 2);
he([
ve()
], T.prototype, "_sparklineData", 2);
T = he([
Je("treemap-card")
], T);
window.customCards = window.customCards || [];
window.customCards.push({
type: "treemap-card",
name: "Treemap Card",
description: "Visualize entities as a treemap with size and color based on values",
preview: !0
});
function ae(t) {
return t === "__proto__";
}
function Di(t) {
switch (typeof t) {
case "number":
case "symbol":
return !1;
case "string":
return t.includes(".") || t.includes("[") || t.includes("]");
}
}
function $e(t) {
return typeof t == "string" || typeof t == "symbol" ? t : Object.is(t?.valueOf?.(), -0) ? "-0" : String(t);
}
function Ke(t) {
if (t == null)
return "";
if (typeof t == "string")
return t;
if (Array.isArray(t))
return t.map(Ke).join(",");
const e = String(t);
return e === "0" && Object.is(Number(t), -0) ? "-0" : e;
}
function et(t) {
if (Array.isArray(t))
return t.map($e);
if (typeof t == "symbol")
return [t];
t = Ke(t);
const e = [], i = t.length;
if (i === 0)
return e;
let n = 0, s = "", o = "", r = !1;
for (t.charCodeAt(0) === 46 && (e.push(""), n++); n < i; ) {
const a = t[n];
o ? a === "\\" && n + 1 < i ? (n++, s += t[n]) : a === o ? o = "" : s += a : r ? a === '"' || a === "'" ? o = a : a === "]" ? (r = !1, e.push(s), s = "") : s += a : a === "[" ? (r = !0, s && (e.push(s), s = "")) : a === "." ? s && (e.push(s), s = "") : s += a, n++;
}
return s && e.push(s), e;
}
function tt(t, e, i) {
if (t == null)
return i;
switch (typeof e) {
case "string": {
if (ae(e))
return i;
const n = t[e];
return n === void 0 ? Di(e) ? tt(t, et(e), i) : i : n;
}
case "number":
case "symbol": {
typeof e == "number" && (e = $e(e));
const n = t[e];
return n === void 0 ? i : n;
}
default: {
if (Array.isArray(e))
return Oi(t, e, i);
if (Object.is(e?.valueOf(), -0) ? e = "-0" : e = String(e), ae(e))
return i;
const n = t[e];
return n === void 0 ? i : n;
}
}
}
function Oi(t, e, i) {
if (e.length === 0)
return i;
let n = t;
for (let s = 0; s < e.length; s++) {
if (n == null || ae(e[s]))
return i;
n = n[e[s]];
}
return n === void 0 ? i : n;
}
function Re(t) {
return t !== null && (typeof t == "object" || typeof t == "function");
}
function Ii(t, e) {
return t === e || Number.isNaN(t) && Number.isNaN(e);
}
const Hi = /^(?:0|[1-9]\d*)$/;
function Ri(t, e = Number.MAX_SAFE_INTEGER) {
switch (typeof t) {
case "number":
return Number.isInteger(t) && t >= 0 && t < e;
case "symbol":
return !1;
case "string":
return Hi.test(t);
}
}
function Li(t) {
return typeof t == "symbol" || t instanceof Symbol;
}
const Ui = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, Bi = /^\w*$/;
function Fi(t, e) {
return Array.isArray(t) ? !1 : typeof t == "number" || typeof t == "boolean" || t == null || Li(t) ? !0 : typeof t == "string" && (Bi.test(t) || !Ui.test(t)) || e != null && Object.hasOwn(e, t);
}
const ji = (t, e, i) => {
const n = t[e];
(!(Object.hasOwn(t, e) && Ii(n, i)) || i === void 0 && !(e in t)) && (t[e] = i);
};
function qi(t, e, i, n) {
if (t == null && !Re(t))
return t;
let s;
Fi(e, t) ? s = [e] : Array.isArray(e) ? s = e : s = et(e);
const o = i(tt(t, s));
let r = t;
for (let a = 0; a < s.length && r != null; a++) {
const l = $e(s[a]);
if (ae(l))
continue;
let h;
if (a === s.length - 1)
h = o;
else {
const c = r[l], u = n?.(c, l, t);
h = u !== void 0 ? u : Re(c) ? c : Ri(s[a + 1]) ? [] : {};
}
ji(r, l, h), r = r[l];
}
return t;
}
function N(t, e, i) {
return qi(t, e, () => i, () => {
});
}
const Wi = Fe`
:host {
display: block;
}
.editor {
display: flex;
flex-direction: column;
gap: 12px;
}
/* Info message for YAML-only features */
.info-message {
padding: 12px 16px;
background: var(--secondary-background-color, #f5f5f5);
border-radius: 8px;
font-size: 14px;
color: var(--secondary-text-color, #666);
}
/* Field styling */
.field {
display: flex;
flex-direction: column;
gap: 4px;
}
.field-label {
font-size: 12px;
font-weight: 500;
color: var(--secondary-text-color, #666);
}
.field-helper {
font-size: 11px;
color: var(--secondary-text-color, #888);
}
/* Inputs */
.input {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--divider-color, #e0e0e0);
border-radius: 4px;
font-size: 14px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color, #333);
box-sizing: border-box;
}
.input:focus {
outline: none;
border-color: var(--primary-color, #03a9f4);
}
.textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--divider-color, #e0e0e0);
border-radius: 4px;
font-family: monospace;
font-size: 13px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color, #333);
box-sizing: border-box;
resize: vertical;
}
.textarea:focus {
outline: none;
border-color: var(--primary-color, #03a9f4);
}
/* ha-expansion-panel */
ha-expansion-panel input[type='checkbox'] {
width: 16px;
height: 16px;
margin: 0 8px 0 0;
cursor: pointer;
accent-color: var(--primary-color, #03a9f4);
}
ha-expansion-panel .content {
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
}
/* Docs link at end of section */
.docs-link {
align-self: flex-end;
color: var(--secondary-text-color, #888);
opacity: 0.6;
transition: opacity 0.2s;
padding: 4px 8px;
margin: -4px -8px;
min-width: 40px;
min-height: 28px;
display: flex;
align-items: center;
justify-content: center;
}
.docs-link:hover {
opacity: 1;
}
.docs-link ha-icon {
--mdc-icon-size: 20px;
}
/* Color picker row */
.color-row {
display: flex;
gap: 16px;
}
.color-field {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
cursor: pointer;
}
.color-field input[type='color'] {
width: 48px;
height: 32px;
padding: 0;
border: 1px solid var(--divider-color, #e0e0e0);
border-radius: 4px;
cursor: pointer;
background: none;
}
.color-field input[type='color']::-webkit-color-swatch-wrapper {
padding: 2px;
}
.color-field input[type='color']::-webkit-color-swatch {
border: none;
border-radius: 2px;
}
.color-field span {
font-size: 11px;
color: var(--secondary-text-color, #666);
}
/* Inline input field */
.inline-field {
display: flex;
flex-direction: column;
gap: 4px;
}
/* Side-by-side fields */
.field-row {
display: flex;
gap: 8px;
}
.field-row ha-textfield,
.field-row ha-select {
flex: 1;
}
/* Checkbox with label */
.checkbox-field {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
font-size: 14px;
color: var(--primary-text-color, #333);
}
.checkbox-field input[type='checkbox'] {
width: 16px;
height: 16px;
margin: 0;
cursor: pointer;
accent-color: var(--primary-color, #03a9f4);
}
.checkbox-field input[type='checkbox']:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.checkbox-field input[type='checkbox']:disabled + span {
opacity: 0.5;
}
/* Color + scale value row */
.color-scale-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
}
.color-scale-row .color-field {
margin: 0;
}
.color-scale-row ha-textfield {
flex: 1;
}
.color-label {
font-size: 14px;
color: var(--primary-text-color, #333);
align-self: center;
}
/* Footer banner */
.footer-banner {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
padding: 8px;
font-size: 13px;
color: var(--secondary-text-color, #888);
}
.footer-banner a {
display: flex;
align-items: center;
gap: 6px;
color: var(--secondary-text-color, #888);
text-decoration: none;
transition: color 0.2s;
padding: 10px 12px;
min-height: 44px;
box-sizing: border-box;
border-radius: 8px;
}
.footer-banner a:hover {
color: var(--primary-text-color, #333);
background: var(--secondary-background-color, rgba(0, 0, 0, 0.05));
}
.footer-banner ha-icon {
--mdc-icon-size: 18px;
}
.footer-banner .separator {
opacity: 0.3;
}
`, it = { no_config: "Keine Konfiguration", yaml_only: "JSON-Attributmodus wird nur über YAML konfiguriert.", entities: { label: "Entitätsmuster (eines pro Zeile)", helper: "Wildcards (*) werden unterstützt", placeholder: `sensor.temperature_*
climate.*
light.living_*` }, exclude: { label: "Ausschlussmuster", placeholder: `*_battery
*_unavailable
light.*` }, label: { title: "Bezeichnung", prefix: "Präfix", suffix: "Suffix", find: "Suchen", replace: "Ersetzen mit", find_placeholder: "Temperatur", replace_placeholder: "Temp" }, value: { title: "Wert", prefix: "Präfix", suffix: "Suffix", suffix_placeholder: "%", precision: "Dezimalstellen", abbreviate: "Große Zahlen abkürzen (k, M, B)" }, icon: { title: "Symbol", override: "Symbol ersetzen" }, sparkline: { title: "Sparkline", period: "Zeitraum", period_12h: "12 Stunden", period_24h: "24 Stunden", period_7d: "7 Tage", period_30d: "30 Tage", mode: "Modus", mode_dark: "Dunkel", mode_light: "Hell", show_line: "Linie anzeigen", show_fill: "Füllung anzeigen", show_hvac: "HVAC-Balken anzeigen (Klimaentitäten)", min: "Y-Achse Min", max: "Y-Achse Max" }, colors: { title: "Farben", target: "Farbe anwenden auf", target_background: "Hintergrund", target_foreground: "Vordergrund (Text)", gradient: "Farbverlauf (niedrig → mittel → hoch)", low: "Niedrig ≤", mid: "Mittel =", high: "Hoch ≥", auto: "auto", middle: "mitte", hvac_colors: "HVAC-Farben (Klimaentitäten)", heating: "Heizen", cooling: "Kühlen", off: "Aus", unavailable: "Nicht verfügbar" }, size: { title: "Größe", equal: "Gleich große Rechtecke", inverse: "Invertiert (niedrige Werte = größer)", min: "Min", max: "Max" }, layout: { title: "Layout", height: "Höhe (px)", gap: "Abstand (px)" }, footer: { docs: "Doku", issues: "Bug oder Idee?", star: "Gefällt es? Stern geben!" }, actions: { title: "Aktionen", tap_action: "Tipp-Aktion", hold_action: "Halten-Aktion" }, data: { title: "Daten", order: "Sortierung", desc: "Absteigend (hoch zuerst)", asc: "Aufsteigend (niedrig zuerst)", limit: "Limit", all: "alle", above: "Filter oberhalb", below: "Filter unterhalb", unavailable: "Nicht verfügbare Entitäten einschließen", sort_by: "Sortieren nach", sort_by_value: "Wert (optimales Layout)", sort_by_entity_id: "Entitäts-ID", sort_by_label: "Bezeichnung", sort_by_default: "Konfigurationsreihenfolge" } }, Gi = {
editor: it
}, Yi = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: Gi,
editor: it
}, Symbol.toStringTag, { value: "Module" })), nt = { no_config: "No configuration", yaml_only: "JSON attribute mode is configured via YAML only.", entities: { label: "Entity patterns (one per line)", helper: "Wildcards (*) are supported", placeholder: `sensor.temperature_*
climate.*
light.living_*` }, exclude: { label: "Exclude patterns", placeholder: `*_battery
*_unavailable
light.*` }, label: { title: "Label", prefix: "Prefix", suffix: "Suffix", find: "Find", replace: "Replace with", find_placeholder: "Temperature", replace_placeholder: "Temp" }, value: { title: "Value", prefix: "Prefix", suffix: "Suffix", suffix_placeholder: "%", precision: "Decimal places", abbreviate: "Abbreviate large numbers (k, M, B)" }, icon: { title: "Icon", override: "Override icon" }, sparkline: { title: "Sparkline", period: "Period", period_12h: "12 hours", period_24h: "24 hours", period_7d: "7 days", period_30d: "30 days", mode: "Mode", mode_dark: "Dark", mode_light: "Light", show_line: "Show line", show_fill: "Show fill", show_hvac: "Show HVAC bars (climate entities)", min: "Y-axis min", max: "Y-axis max" }, colors: { title: "Colors", target: "Apply color to", target_background: "Background", target_foreground: "Foreground (text)", gradient: "Color gradient (low → mid → high)", low: "Low ≤", mid: "Mid =", high: "High ≥", auto: "auto", middle: "middle", hvac_colors: "HVAC colors (climate entities)", heating: "Heating", cooling: "Cooling", off: "Off", unavailable: "Unavailable" }, size: { title: "Size", equal: "Equal size rectangles", inverse: "Inverse (low values = bigger)", min: "Min", max: "Max" }, layout: { title: "Layout", height: "Height (px)", gap: "Gap (px)" }, footer: { docs: "Docs", issues: "Bug or idea?", star: "Like it? Star it!" }, actions: { title: "Actions", tap_action: "Tap action", hold_action: "Hold action" }, data: { title: "Data", order: "Order", desc: "Descending (high first)", asc: "Ascending (low first)", sort_by: "Sort by", sort_by_value: "Value (optimal layout)", sort_by_entity_id: "Entity ID", sort_by_label: "Label", sort_by_default: "Config order", limit: "Limit", all: "all", above: "Filter above", below: "Filter below", unavailable: "Include unavailable entities" } }, Ji = {
editor: nt
}, Zi = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: Ji,
editor: nt
}, Symbol.toStringTag, { value: "Module" })), ot = { no_config: "Aucune configuration", yaml_only: "Le mode attribut JSON est configurable uniquement via YAML.", entities: { label: "Motifs d'entités (un par ligne)", helper: "Wildcards (*) supportés", placeholder: `sensor.temperature_*
climate.*
light.living_*` }, exclude: { label: "Motifs à exclure", placeholder: `*_battery
*_unavailable
light.*` }, label: { title: "Libellé", prefix: "Préfixe", suffix: "Suffixe", find: "Rechercher", replace: "Remplacer par", find_placeholder: "Température", replace_placeholder: "Temp" }, value: { title: "Valeur", prefix: "Préfixe", suffix: "Suffixe", suffix_placeholder: "%", precision: "Décimales", abbreviate: "Abréger les grands nombres (k, M, B)" }, icon: { title: "Icône", override: "Remplacer l'icône" }, sparkline: { title: "Sparkline", period: "Période", period_12h: "12 heures", period_24h: "24 heures", period_7d: "7 jours", period_30d: "30 jours", mode: "Mode", mode_dark: "Sombre", mode_light: "Clair", show_line: "Afficher la ligne", show_fill: "Afficher le remplissage", show_hvac: "Afficher les barres HVAC (entités climatiques)", min: "Min axe Y", max: "Max axe Y" }, colors: { title: "Couleurs", target: "Appliquer la couleur à", target_background: "Arrière-plan", target_foreground: "Premier plan (texte)", gradient: "Dégradé de couleur (bas → milieu → haut)", low: "Bas ≤", mid: "Milieu =", high: "Haut ≥", auto: "auto", middle: "milieu", hvac_colors: "Couleurs HVAC (entités climatiques)", heating: "Chauffage", cooling: "Climatisation", off: "Éteint", unavailable: "Indisponible" }, size: { title: "Taille", equal: "Rectangles de taille égale", inverse: "Inverse (valeurs basses = plus grand)", min: "Min", max: "Max" }, layout: { title: "Disposition", height: "Hauteur (px)", gap: "Espacement (px)" }, footer: { docs: "Docs", issues: "Bug ou idée?", star: "Vous aimez? Étoile!" }, actions: { title: "Actions", tap_action: "Action au tap", hold_action: "Action au maintien" }, data: { title: "Données", order: "Ordre", desc: "Décroissant (haut en premier)", asc: "Croissant (bas en premier)", limit: "Limite", all: "tous", above: "Filtrer au-dessus", below: "Filtrer en-dessous", unavailable: "Inclure les entités indisponibles", sort_by: "Trier par", sort_by_value: "Valeur (disposition optimale)", sort_by_entity_id: "ID d'entité", sort_by_label: "Étiquette", sort_by_default: "Ordre de configuration" } }, Xi = {
editor: ot
}, Qi = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: Xi,
editor: ot
}, Symbol.toStringTag, { value: "Module" })), Le = {
de: Yi,
en: Zi,
fr: Qi
};
function Ki(t) {
return typeof t == "object" && t !== null;
}
function Ue(t, e) {
const i = e.split(".");
let n = t;
for (const s of i)
if (n && Ki(n) && s in n)
n = n[s];
else
return;
return typeof n == "string" ? n : void 0;
}
function en(t) {
return (t?.language ?? "en").split("-")[0] ?? "en";
}
function tn(t, e) {
const i = en(t), n = Le[i];
if (n) {
const s = Ue(n, e);
if (s) return s;
}
if (i !== "en") {
const s = Le.en;
if (s) {
const o = Ue(s, e);
if (o) return o;
}
}
return e;
}
var nn = Object.defineProperty, on = Object.getOwnPropertyDescriptor, ue = (t, e, i, n) => {
for (var s = n > 1 ? void 0 : n ? on(e, i) : e, o = t.length - 1, r; o >= 0; o--)
(r = t[o]) && (s = (n ? r(e, i, s) : r(s)) || s);
return n && s && nn(e, i, s), s;
};
const ne = "https://github.com/omachala/ha-treemap-card";
function Y(t) {
const e = t.target;
if (e && typeof e == "object" && "value" in e) {
const i = e.value;
return String(i ?? "");
}
return "";
}
function sn(t) {
const e = t.target;
return e instanceof HTMLInputElement ? e.checked : !1;
}
let H = class extends B {
constructor() {
super(...arguments), this._actionsSchema = [
{ name: "tap_action", selector: { ui_action: { default_action: "more-info" } } },
{ name: "hold_action", selector: { ui_action: { default_action: "none" } } }
];
}
setConfig(t) {
this._config = { ...t };
}
/**
* Shorthand for localize with current hass context
*/
_t(t) {
return tn(this.hass, t);
}
_fireConfigChanged() {
this._config && this.dispatchEvent(
new CustomEvent("config-changed", {
detail: { config: this._config },
bubbles: !0,
composed: !0
})
);
}
/**
* Generic handler for text input changes
*/
_handleTextChange(t, e) {
if (!this._config) return;
const i = Y(e) || void 0;
this._config = N({ ...this._config }, t, i), this._fireConfigChanged();
}
/**
* Generic handler for checkbox changes
*/
_handleBoolChange(t, e) {
if (!this._config) return;
const i = sn(e);
this._config = N({ ...this._config }, t, i), this._fireConfigChanged();
}
/**
* Generic handler for number input changes
*/
_handleNumberChange(t, e) {
if (!this._config) return;
const i = Y(e), n = i ? Number.parseFloat(i) : void 0;
this._config = N({ ...this._config }, t, n), this._fireConfigChanged();
}
/**
* Handler for entities textarea (splits lines into array)
*/
_handleEntitiesChange(t) {
if (!this._config) return;
const i = Y(t).split(`
`).map((n) => n.trim()).filter((n) => n.length > 0);
this._config = N({ ...this._config }, "entities", i), this._fireConfigChanged();
}
/**
* Handler for ha-icon-picker value-changed event
*/
_handleIconChange(t) {
if (!this._config) return;
const e = t.detail?.value || void 0;
this._config = N({ ...this._config }, "icon.icon", e), this._fireConfigChanged();
}
/**
* Handler for find/replace inputs (combines into 'find/replace' format)
*/
_handleReplaceChange(t, e) {
if (!this._config) return;
const i = Y(e), s = (this._config.label?.replace ?? "/").split("/"), o = t === "find" ? i : s[0] ?? "", r = t === "replace" ? i : s[1] ?? "", a = o || r ? `${o}/${r}` : void 0;
this._config = N({ ...this._config }, "label.replace", a), this._fireConfigChanged();
}
/**
* Handler for exclude textarea (splits lines into array, removes if empty)
*/
_handleExcludeChange(t) {
if (!this._config) return;
const i = Y(t).split(`
`).map((n) => n.trim()).filter((n) => n.length > 0);
this._config = N({ ...this._config }, "exclude", i.length > 0 ? i : void 0), this._fireConfigChanged();
}
_handleActionsChanged(t) {
if (!this._config) return;
const e = t.detail?.value?.tap_action, i = t.detail?.value?.hold_action;
this._config = {
...this._config,
...e !== void 0 && { tap_action: e },
...i !== void 0 && { hold_action: i }
}, this._fireConfigChanged();
}
_docsUrl(t) {
return `${ne}?tab=readme-ov-file#${t}`;
}
_renderDocsLink(t) {
return x`
<a class="docs-link" href=${this._docsUrl(t)} target="_blank" rel="noopener">
<ha-icon icon="mdi:help-circle-outline"></ha-icon>
</a>
`;
}
_renderToggleSection(t) {
return x`
<ha-expansion-panel outlined data-testid="${t.id}-section">
<input
slot="leading-icon"
type="checkbox"
.checked=${t.checked}
@change=${t.onToggle}
@click=${(e) => e.stopPropagation()}
/>
<span slot="header">${t.title}</span>
<div class="content">
${t.content} ${t.docsAnchor ? this._renderDocsLink(t.docsAnchor) : ""}
</div>
</ha-expansion-panel>
`;
}
render() {
if (!this._config)
return x`<div class="editor">${this._t("editor.no_config")}</div>`;
if (this._config.entity)
return x`
<div class="editor">
<ha-alert alert-type="info">${this._t("editor.yaml_only")}</ha-alert>
</div>
`;
const t = this._config.entities?.map((o) => Ze(o) ? o.entity : o).join(`
`) ?? "", e = this._config.exclude?.join(`
`) ?? "", i = this._config.label ?? {}, n = this._config.value ?? {}, s = this._config.icon ?? {};
return x`
<div class="editor">
<!-- Entities -->
<div class="field" data-testid="entities-field">
<label class="field-label">${this._t("editor.entities.label")}</label>
<textarea
class="textarea"
.value=${t}
@input=${this._handleEntitiesChange}
placeholder="sensor.temperature_*&#10;climate.*&#10;light.living_*"
rows="3"
></textarea>
<span class="field-helper">${this._t("editor.entities.helper")}</span>
</div>
<!-- Exclude -->
<div class="field" data-testid="exclude-field">
<label class="field-label">${this._t("editor.exclude.label")}</label>
<textarea
class="textarea"
.value=${e}
@input=${this._handleExcludeChange}
rows="2"
></textarea>
</div>
<!-- Label section -->
${this._renderToggleSection({
id: "label",
title: this._t("editor.label.title"),
checked: i.show !== !1,
onToggle: (o) => this._handleBoolChange("label.show", o),
docsAnchor: "label",
content: x`
<div class="field-row">
<ha-textfield
label=${this._t("editor.label.prefix")}
.value=${i.prefix ?? ""}
@input=${(o) => this._handleTextChange("label.prefix", o)}
></ha-textfield>
<ha-textfield
label=${this._t("editor.label.suffix")}
.value=${i.suffix ?? ""}
@input=${(o) => this._handleTextChange("label.suffix", o)}
></ha-textfield>
</div>
<div class="field-row">
<ha-textfield
label=${this._t("editor.label.find")}
.value=${i.replace?.split("/")[0] ?? ""}
@input=${(o) => this._handleReplaceChange("find", o)}
placeholder=${this._t("editor.label.find_placeholder")}
></ha-textfield>
<ha-textfield
label=${this._t("editor.label.replace")}
.value=${i.replace?.split("/")[1] ?? ""}
@input=${(o) => this._handleReplaceChange("replace", o)}
placeholder=${this._t("editor.label.replace_placeholder")}
></ha-textfield>
</div>
`
})}
<!-- Value section -->
${this._renderToggleSection({
id: "value",
title: this._t("editor.value.title"),
checked: n.show !== !1,
onToggle: (o) => this._handleBoolChange("value.show", o),
docsAnchor: "value",
content: x`
<div class="field-row">
<ha-textfield
label=${this._t("editor.value.prefix")}
.value=${n.prefix ?? ""}
@input=${(o) => this._handleTextChange("value.prefix", o)}
></ha-textfield>
<ha-textfield
label=${this._t("editor.value.suffix")}
.value=${n.suffix ?? ""}
@input=${(o) => this._handleTextChange("value.suffix", o)}
placeholder=${this._t("editor.value.suffix_placeholder")}
></ha-textfield>
</div>
<div class="field-row">
<ha-textfield
type="number"
label=${this._t("editor.value.precision")}
.value=${n.precision ?? ""}
@input=${(o) => this._handleNumberChange("value.precision", o)}
placeholder="1"
></ha-textfield>
</div>
<label class="checkbox-field">
<input
type="checkbox"
.checked=${n.abbreviate ?? !1}
@change=${(o) => this._handleBoolChange("value.abbreviate", o)}
/>
<span>${this._t("editor.value.abbreviate")}</span>
</label>
`
})}
<!-- Icon section -->
${this._renderToggleSection({
id: "icon",
title: this._t("editor.icon.title"),
checked: s.show !== !1,
onToggle: (o) => this._handleBoolChange("icon.show", o),
docsAnchor: "icon",
content: x`
<ha-icon-picker
label=${this._t("editor.icon.override")}
.hass=${this.hass}
.value=${s.icon ?? ""}
@value-changed=${this._handleIconChange}
></ha-icon-picker>
`
})}
<!-- Sparkline section -->
<ha-expansion-panel outlined data-testid="sparkline-section">
<input
slot="leading-icon"
type="checkbox"
.checked=${this._config.sparkline?.show !== !1}
@change=${(o) => this._handleBoolChange("sparkline.show", o)}
@click=${(o) => o.stopPropagation()}
/>
<span slot="header">${this._t("editor.sparkline.title")}</span>
<div class="content">
<ha-select
label=${this._t("editor.sparkline.period")}
.value=${this._config.sparkline?.period ?? "24h"}
@selected=${(o) => this._handleTextChange("sparkline.period", o)}
@closed=${(o) => o.stopPropagation()}
>
<ha-list-item value="12h">${this._t("editor.sparkline.period_12h")}</ha-list-item>
<ha-list-item value="24h">${this._t("editor.sparkline.period_24h")}</ha-list-item>
<ha-list-item value="7d">${this._t("editor.sparkline.period_7d")}</ha-list-item>
<ha-list-item value="30d">${this._t("editor.sparkline.period_30d")}</ha-list-item>
</ha-select>
<ha-select
label=${this._t("editor.sparkline.mode")}
.value=${this._config.sparkline?.mode ?? "dark"}
@selected=${(o) => this._handleTextChange("sparkline.mode", o)}
@closed=${(o) => o.stopPropagation()}
>
<ha-list-item value="dark">${this._t("editor.sparkline.mode_dark")}</ha-list-item>
<ha-list-item value="light">${this._t("editor.sparkline.mode_light")}</ha-list-item>
</ha-select>
<label class="checkbox-field">
<input
type="checkbox"
.checked=${this._config.sparkline?.line?.show !== !1}
@change=${(o) => this._handleBoolChange("sparkline.line.show", o)}
/>
<span>${this._t("editor.sparkline.show_line")}</span>
</label>
<label class="checkbox-field">
<input
type="checkbox"
.checked=${this._config.sparkline?.fill?.show !== !1}
@change=${(o) => this._handleBoolChange("sparkline.fill.show", o)}
/>
<span>${this._t("editor.sparkline.show_fill")}</span>
</label>
<label class="checkbox-field">
<input
type="checkbox"
.checked=${this._config.sparkline?.hvac?.show !== !1}
@change=${(o) => this._handleBoolChange("sparkline.hvac.show", o)}
/>
<span>${this._t("editor.sparkline.show_hvac")}</span>
</label>
<div class="field-row">
<ha-textfield
type="number"
label=${this._t("editor.sparkline.min")}
.value=${this._config.sparkline?.min ?? ""}
@input=${(o) => this._handleNumberChange("sparkline.min", o)}
placeholder=${this._t("editor.colors.auto")}
></ha-textfield>
<ha-textfield
type="number"
label=${this._t("editor.sparkline.max")}
.value=${this._config.sparkline?.max ?? ""}
@input=${(o) => this._handleNumberChange("sparkline.max", o)}
placeholder=${this._t("editor.colors.auto")}
></ha-textfield>
</div>
${this._renderDocsLink("sparkline")}
</div>
</ha-expansion-panel>
<!-- Colors section -->
<ha-expansion-panel outlined data-testid="colors-section">
<span slot="header">${this._t("editor.colors.title")}</span>
<div class="content">
<ha-select
label=${this._t("editor.colors.target")}
.value=${this._config.color?.target ?? "background"}
@selected=${(o) => this._handleTextChange("color.target", o)}
@closed=${(o) => o.stopPropagation()}
>
<ha-list-item value="background"
>${this._t("editor.colors.target_background")}</ha-list-item
>
<ha-list-item value="foreground"
>${this._t("editor.colors.target_foreground")}</ha-list-item
>
</ha-select>
<span class="field-label">${this._t("editor.colors.gradient")}</span>
<div class="color-scale-row">
<label class="color-field">
<input
type="color"
.value=${this._config.color?.low ?? "#b91c1c"}
@input=${(o) => this._handleTextChange("color.low", o)}
/>
</label>
<ha-textfield
type="number"
label=${this._t("editor.colors.low")}
.value=${this._config.color?.scale?.min ?? ""}
@input=${(o) => this._handleNumberChange("color.scale.min", o)}
placeholder=${this._t("editor.colors.auto")}
></ha-textfield>
</div>
<div class="color-scale-row">
<label class="color-field">
<input
type="color"
.value=${this._config.color?.mid ?? "#888888"}
@input=${(o) => this._handleTextChange("color.mid", o)}
/>
</label>
<ha-textfield
type="number"
label=${this._t("editor.colors.mid")}
.value=${this._config.color?.scale?.neutral ?? ""}
@input=${(o) => this._handleNumberChange("color.scale.neutral", o)}
placeholder=${this._t("editor.colors.middle")}
></ha-textfield>
</div>
<div class="color-scale-row">
<label class="color-field">
<input
type="color"
.value=${this._config.color?.high ?? "#16a34a"}
@input=${(o) => this._handleTextChange("color.high", o)}
/>
</label>
<ha-textfield
type="number"
label=${this._t("editor.colors.high")}
.value=${this._config.color?.scale?.max ?? ""}
@input=${(o) => this._handleNumberChange("color.scale.max", o)}
placeholder=${this._t("editor.colors.auto")}
></ha-textfield>
</div>
<div class="color-scale-row">
<label class="color-field">
<input
type="color"
.value=${this._config.color?.unavailable ?? "#868e96"}
@input=${(o) => this._handleTextChange("color.unavailable", o)}
/>
</label>
<span class="color-label">${this._t("editor.colors.unavailable")}</span>
</div>
<span class="field-label">${this._t("editor.colors.hvac_colors")}</span>
<div class="color-row">
<label class="color-field">
<input
type="color"
.value=${this._config.color?.hvac?.heating ?? "#ff6b35"}
@input=${(o) => this._handleTextChange("color.hvac.heating", o)}
/>
<span>${this._t("editor.colors.heating")}</span>
</label>
<label class="color-field">
<input
type="color"
.value=${this._config.color?.hvac?.cooling ?? "#4dabf7"}
@input=${(o) => this._handleTextChange("color.hvac.cooling", o)}
/>
<span>${this._t("editor.colors.cooling")}</span>
</label>
<label class="color-field">
<input
type="color"
.value=${this._config.color?.hvac?.off ?? "#868e96"}
@input=${(o) => this._handleTextChange("color.hvac.off", o)}
/>
<span>${this._t("editor.colors.off")}</span>
</label>
</div>
${this._renderDocsLink("color")}
</div>
</ha-expansion-panel>
<!-- Size section -->
<ha-expansion-panel outlined data-testid="size-section">
<span slot="header">${this._t("editor.size.title")}</span>
<div class="content">
<label class="checkbox-field">
<input
type="checkbox"
.checked=${this._config.size?.equal ?? !1}
@change=${(o) => this._handleBoolChange("size.equal", o)}
/>
<span>${this._t("editor.size.equal")}</span>
</label>
<label class="checkbox-field">
<input
type="checkbox"
.checked=${this._config.size?.inverse ?? !1}
.disabled=${this._config.size?.equal ?? !1}
@change=${(o) => this._handleBoolChange("size.inverse", o)}
/>
<span>${this._t("editor.size.inverse")}</span>
</label>
<div class="field-row">
<ha-textfield
type="number"
label=${this._t("editor.size.min")}
.value=${this._config.size?.min ?? ""}
.disabled=${this._config.size?.equal ?? !1}
@input=${(o) => this._handleNumberChange("size.min", o)}
placeholder=${this._t("editor.colors.auto")}
></ha-textfield>
<ha-textfield
type="number"
label=${this._t("editor.size.max")}
.value=${this._config.size?.max ?? ""}
.disabled=${this._config.size?.equal ?? !1}
@input=${(o) => this._handleNumberChange("size.max", o)}
placeholder=${this._t("editor.colors.auto")}
></ha-textfield>
</div>
${this._renderDocsLink("size")}
</div>
</ha-expansion-panel>
<!-- Data section (order, filter, limit) -->
<ha-expansion-panel outlined data-testid="data-section">
<span slot="header">${this._t("editor.data.title")}</span>
<div class="content">
<ha-select
label=${this._t("editor.data.sort_by")}
.value=${this._config.sort_by ?? "value"}
@selected=${(o) => this._handleTextChange("sort_by", o)}
@closed=${(o) => o.stopPropagation()}
>
<ha-list-item value="value">${this._t("editor.data.sort_by_value")}</ha-list-item>
<ha-list-item value="entity_id"
>${this._t("editor.data.sort_by_entity_id")}</ha-list-item
>
<ha-list-item value="label">${this._t("editor.data.sort_by_label")}</ha-list-item>
<ha-list-item value="default">${this._t("editor.data.sort_by_default")}</ha-list-item>
</ha-select>
<ha-select
label=${this._t("editor.data.order")}
.value=${this._config.order ?? "desc"}
@selected=${(o) => this._handleTextChange("order", o)}
@closed=${(o) => o.stopPropagation()}
>
<ha-list-item value="desc">${this._t("editor.data.desc")}</ha-list-item>
<ha-list-item value="asc">${this._t("editor.data.asc")}</ha-list-item>
</ha-select>
<ha-textfield
type="number"
label=${this._t("editor.data.limit")}
.value=${this._config.limit ?? ""}
@input=${(o) => this._handleNumberChange("limit", o)}
placeholder=${this._t("editor.data.all")}
></ha-textfield>
<div class="field-row">
<ha-textfield
type="number"
label=${this._t("editor.data.above")}
.value=${this._config.filter?.above ?? ""}
@input=${(o) => this._handleNumberChange("filter.above", o)}
></ha-textfield>
<ha-textfield
type="number"
label=${this._t("editor.data.below")}
.value=${this._config.filter?.below ?? ""}
@input=${(o) => this._handleNumberChange("filter.below", o)}
></ha-textfield>
</div>
<label class="checkbox-field">
<input
type="checkbox"
.checked=${this._config.filter?.unavailable ?? !1}
@change=${(o) => this._handleBoolChange("filter.unavailable", o)}
/>
<span>${this._t("editor.data.unavailable")}</span>
</label>
${this._renderDocsLink("order--filter")}
</div>
</ha-expansion-panel>
<!-- Layout section -->
<ha-expansion-panel outlined data-testid="layout-section">
<span slot="header">${this._t("editor.layout.title")}</span>
<div class="content">
<div class="field-row">
<ha-textfield
type="number"
label=${this._t("editor.layout.height")}
.value=${this._config.height ?? ""}
@input=${(o) => this._handleNumberChange("height", o)}
placeholder=${this._t("editor.colors.auto")}
></ha-textfield>
<ha-textfield
type="number"
label=${this._t("editor.layout.gap")}
.value=${this._config.gap ?? ""}
@input=${(o) => this._handleNumberChange("gap", o)}
placeholder="6"
></ha-textfield>
</div>
${this._renderDocsLink("layout")}
</div>
</ha-expansion-panel>
<!-- Actions section -->
<ha-expansion-panel outlined data-testid="actions-section">
<span slot="header">${this._t("editor.actions.title")}</span>
<div class="content">
<ha-form
.hass=${this.hass}
.data=${{
tap_action: this._config.tap_action,
hold_action: this._config.hold_action
}}
.schema=${this._actionsSchema}
.computeLabel=${(o) => this._t(`editor.actions.${o.name}`)}
@value-changed=${this._handleActionsChanged}
data-testid="actions-form"
></ha-form>
${this._renderDocsLink("tap--hold-actions")}
</div>
</ha-expansion-panel>
<!-- Footer banner -->
<div class="footer-banner">
<a href=${ne} target="_blank" rel="noopener">
<ha-icon icon="mdi:book-open-variant"></ha-icon>
${this._t("editor.footer.docs")}
</a>
<span class="separator">|</span>
<a href="${ne}/issues" target="_blank" rel="noopener">
<ha-icon icon="mdi:bug-outline"></ha-icon>
${this._t("editor.footer.issues")}
</a>
<span class="separator">|</span>
<a href=${ne} target="_blank" rel="noopener">
<ha-icon icon="mdi:star-outline"></ha-icon>
${this._t("editor.footer.star")}
</a>
</div>
</div>
`;
}
};
H.styles = Wi;
ue([
ce({ attribute: !1 })
], H.prototype, "hass", 2);
ue([
ce({ attribute: !1 })
], H.prototype, "lovelace", 2);
ue([
ve()
], H.prototype, "_config", 2);
H = ue([
Je("treemap-card-editor")
], H);
const rn = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
get TreemapCardEditor() {
return H;
}
}, Symbol.toStringTag, { value: "Module" }));
export {
T as TreemapCard
};