Files
HomeAssistantVS/www/community/ha-treemap-card/treemap-card.js
T

3306 lines
117 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const se = globalThis, $e = se.ShadowRoot && (se.ShadyCSS === void 0 || se.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, xe = Symbol(), ze = /* @__PURE__ */ new WeakMap();
let Qe = class {
constructor(e, i, n) {
if (this._$cssResult$ = !0, n !== xe) 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 ($e && e === void 0) {
const n = i !== void 0 && i.length === 1;
n && (e = ze.get(i)), e === void 0 && ((this.o = e = new CSSStyleSheet()).replaceSync(this.cssText), n && ze.set(i, e));
}
return e;
}
toString() {
return this.cssText;
}
};
const pt = (t) => new Qe(typeof t == "string" ? t : t + "", void 0, xe), Xe = (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 Qe(i, t, xe);
}, gt = (t, e) => {
if ($e) t.adoptedStyleSheets = e.map(((i) => i instanceof CSSStyleSheet ? i : i.styleSheet));
else for (const i of e) {
const n = document.createElement("style"), s = se.litNonce;
s !== void 0 && n.setAttribute("nonce", s), n.textContent = i.cssText, t.appendChild(n);
}
}, Ve = $e ? (t) => t : (t) => t instanceof CSSStyleSheet ? ((e) => {
let i = "";
for (const n of e.cssRules) i += n.cssText;
return pt(i);
})(t) : t;
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const { is: _t, defineProperty: mt, getOwnPropertyDescriptor: bt, getOwnPropertyNames: vt, getOwnPropertySymbols: yt, getPrototypeOf: $t } = Object, T = globalThis, Ee = T.trustedTypes, xt = Ee ? Ee.emptyScript : "", wt = T.reactiveElementPolyfillSupport, Z = (t, e) => t, le = { toAttribute(t, e) {
switch (e) {
case Boolean:
t = t ? xt : 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;
} }, we = (t, e) => !_t(t, e), Te = { attribute: !0, type: String, converter: le, reflect: !1, useDefault: !1, hasChanged: we };
Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), T.litPropertyMetadata ?? (T.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 = Te) {
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 && mt(this.prototype, e, s);
}
}
static getPropertyDescriptor(e, i, n) {
const { get: s, set: o } = bt(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) ?? Te;
}
static _$Ei() {
if (this.hasOwnProperty(Z("elementProperties"))) return;
const e = $t(this);
e.finalize(), e.l !== void 0 && (this.l = [...e.l]), this.elementProperties = new Map(e.elementProperties);
}
static finalize() {
if (this.hasOwnProperty(Z("finalized"))) return;
if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(Z("properties"))) {
const i = this.properties, n = [...vt(i), ...yt(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(Ve(s));
} else e !== void 0 && i.push(Ve(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 gt(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 : le).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 : le;
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 ?? we)(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[Z("elementProperties")] = /* @__PURE__ */ new Map(), U[Z("finalized")] = /* @__PURE__ */ new Map(), wt?.({ ReactiveElement: U }), (T.reactiveElementVersions ?? (T.reactiveElementVersions = [])).push("2.1.1");
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const Q = globalThis, ce = Q.trustedTypes, Pe = ce ? ce.createPolicy("lit-html", { createHTML: (t) => t }) : void 0, Ke = "$lit$", E = `lit$${Math.random().toFixed(9).slice(2)}$`, et = "?" + E, kt = `<${et}>`, I = document, ee = () => I.createComment(""), te = (t) => t === null || typeof t != "object" && typeof t != "function", ke = Array.isArray, At = (t) => ke(t) || typeof t?.[Symbol.iterator] == "function", ge = `[
\f\r]`, G = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, Ne = /-->/g, Oe = />/g, N = RegExp(`>|${ge}(?:([^\\s"'>=/]+)(${ge}*=${ge}*(?:[^
\f\r"'\`<>=]|("|')|))|$)`, "g"), De = /'/g, Ie = /"/g, tt = /^(?:script|style|textarea|title)$/i, it = (t) => (e, ...i) => ({ _$litType$: t, strings: e, values: i }), $ = it(1), O = it(2), q = Symbol.for("lit-noChange"), _ = Symbol.for("lit-nothing"), He = /* @__PURE__ */ new WeakMap(), D = I.createTreeWalker(I, 129);
function nt(t, e) {
if (!ke(t) || !t.hasOwnProperty("raw")) throw Error("invalid template strings array");
return Pe !== void 0 ? Pe.createHTML(e) : e;
}
const Ct = (t, e) => {
const i = t.length - 1, n = [];
let s, o = e === 2 ? "<svg>" : e === 3 ? "<math>" : "", r = G;
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 === G ? c[1] === "!--" ? r = Ne : c[1] !== void 0 ? r = Oe : c[2] !== void 0 ? (tt.test(c[2]) && (s = RegExp("</" + c[2], "g")), r = N) : c[3] !== void 0 && (r = N) : r === N ? c[0] === ">" ? (r = s ?? G, u = -1) : c[1] === void 0 ? u = -2 : (u = r.lastIndex - c[2].length, h = c[1], r = c[3] === void 0 ? N : c[3] === '"' ? Ie : De) : r === Ie || r === De ? r = N : r === Ne || r === Oe ? r = G : (r = N, s = void 0);
const d = r === N && t[a + 1].startsWith("/>") ? " " : "";
o += r === G ? l + kt : u >= 0 ? (n.push(h), l.slice(0, u) + Ke + l.slice(u) + E + d) : l + E + (u === -2 ? a : d);
}
return [nt(t, o + (t[i] || "<?>") + (e === 2 ? "</svg>" : e === 3 ? "</math>" : "")), n];
};
class ie {
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] = Ct(e, i);
if (this.el = ie.createElement(h, n), D.currentNode = this.el.content, i === 2 || i === 3) {
const u = this.el.content.firstChild;
u.replaceWith(...u.childNodes);
}
for (; (s = D.nextNode()) !== null && l.length < a; ) {
if (s.nodeType === 1) {
if (s.hasAttributes()) for (const u of s.getAttributeNames()) if (u.endsWith(Ke)) {
const f = c[r++], d = s.getAttribute(u).split(E), g = /([.?@])?(.*)/.exec(f);
l.push({ type: 1, index: o, name: g[2], strings: d, ctor: g[1] === "." ? Mt : g[1] === "?" ? zt : g[1] === "@" ? Vt : ue }), s.removeAttribute(u);
} else u.startsWith(E) && (l.push({ type: 6, index: o }), s.removeAttribute(u));
if (tt.test(s.tagName)) {
const u = s.textContent.split(E), f = u.length - 1;
if (f > 0) {
s.textContent = ce ? ce.emptyScript : "";
for (let d = 0; d < f; d++) s.append(u[d], ee()), D.nextNode(), l.push({ type: 2, index: ++o });
s.append(u[f], ee());
}
}
} else if (s.nodeType === 8) if (s.data === et) l.push({ type: 2, index: o });
else {
let u = -1;
for (; (u = s.data.indexOf(E, u + 1)) !== -1; ) l.push({ type: 7, index: o }), u += E.length - 1;
}
o++;
}
}
static createElement(e, i) {
const n = I.createElement("template");
return n.innerHTML = e, n;
}
}
function W(t, e, i = t, n) {
if (e === q) return e;
let s = n !== void 0 ? i._$Co?.[n] : i._$Cl;
const o = te(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 = W(t, s._$AS(t, e.values), s, n)), e;
}
class St {
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);
D.currentNode = s;
let o = D.nextNode(), r = 0, a = 0, l = n[0];
for (; l !== void 0; ) {
if (r === l.index) {
let h;
l.type === 2 ? h = new ne(o, o.nextSibling, this, e) : l.type === 1 ? h = new l.ctor(o, l.name, l.strings, this, e) : l.type === 6 && (h = new Et(o, this, e)), this._$AV.push(h), l = n[++a];
}
r !== l?.index && (o = D.nextNode(), r++);
}
return D.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 ne {
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 = W(this, e, i), te(e) ? e === _ || e == null || e === "" ? (this._$AH !== _ && this._$AR(), this._$AH = _) : e !== this._$AH && e !== q && this._(e) : e._$litType$ !== void 0 ? this.$(e) : e.nodeType !== void 0 ? this.T(e) : At(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 !== _ && te(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 = ie.createElement(nt(n.h, n.h[0]), this.options)), n);
if (this._$AH?._$AD === s) this._$AH.p(i);
else {
const o = new St(s, this), r = o.u(this.options);
o.p(i), this.T(r), this._$AH = o;
}
}
_$AC(e) {
let i = He.get(e.strings);
return i === void 0 && He.set(e.strings, i = new ie(e)), i;
}
k(e) {
ke(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 ne(this.O(ee()), this.O(ee()), 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 ue {
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 = W(this, e, i, 0), r = !te(e) || e !== this._$AH && e !== q, r && (this._$AH = e);
else {
const a = e;
let l, h;
for (e = o[0], l = 0; l < o.length - 1; l++) h = W(this, a[n + l], i, l), h === q && (h = this._$AH[l]), r || (r = !te(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 Mt extends ue {
constructor() {
super(...arguments), this.type = 3;
}
j(e) {
this.element[this.name] = e === _ ? void 0 : e;
}
}
class zt extends ue {
constructor() {
super(...arguments), this.type = 4;
}
j(e) {
this.element.toggleAttribute(this.name, !!e && e !== _);
}
}
class Vt extends ue {
constructor(e, i, n, s, o) {
super(e, i, n, s, o), this.type = 5;
}
_$AI(e, i = this) {
if ((e = W(this, e, i, 0) ?? _) === q) 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 Et {
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) {
W(this, e);
}
}
const Tt = Q.litHtmlPolyfillSupport;
Tt?.(ie, ne), (Q.litHtmlVersions ?? (Q.litHtmlVersions = [])).push("3.3.1");
const Pt = (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 ne(e.insertBefore(ee(), 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 = Pt(i, this.renderRoot, this.renderOptions);
}
connectedCallback() {
super.connectedCallback(), this._$Do?.setConnected(!0);
}
disconnectedCallback() {
super.disconnectedCallback(), this._$Do?.setConnected(!1);
}
render() {
return q;
}
}
B._$litElement$ = !0, B.finalized = !0, X.litElementHydrateSupport?.({ LitElement: B });
const Nt = X.litElementPolyfillSupport;
Nt?.({ LitElement: B });
(X.litElementVersions ?? (X.litElementVersions = [])).push("4.2.1");
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const ot = (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 Ot = { attribute: !0, type: String, converter: le, reflect: !1, hasChanged: we }, Dt = (t = Ot, 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 de(t) {
return (e, i) => typeof i == "object" ? Dt(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 Ae(t) {
return de({ ...t, state: !0, attribute: !1 });
}
var Re, Le;
(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";
})(Re || (Re = {})), (function(t) {
t.language = "language", t.system = "system", t.am_pm = "12", t.twenty_four = "24";
})(Le || (Le = {}));
var be = 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;
}, It = 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);
};
}, Ht = function(t, e, i) {
i === void 0 && (i = !1), i ? history.replaceState(null, "", e) : history.pushState(null, "", e), be(window, "location-changed", { replace: i });
};
function re(t) {
return typeof t == "object" && t !== null && "entity" in t && typeof t.entity == "string";
}
function Rt(t) {
return Array.isArray(t) && t.every((e) => typeof e == "string");
}
function Lt(t) {
return Array.isArray(t) && t.length === 3 && t.every((e) => typeof e == "number");
}
function Ft(t) {
return Array.isArray(t) && t.length === 2 && t.every((e) => typeof e == "number");
}
function Ut(t) {
return typeof t == "string" && (t === "heating" || t === "cooling" || t === "idle" || t === "off");
}
function Bt(t) {
return Ut(t) ? t : void 0;
}
function j(t) {
if (typeof t == "number" && !Number.isNaN(t))
return t;
}
function L(t) {
if (typeof t == "string")
return t;
}
function jt(t) {
return Rt(t) ? t : [];
}
function qt(t) {
if (Lt(t))
return t;
}
function Wt(t) {
if (Ft(t))
return t;
}
function Y(t, e) {
return e.includes("*") ? new RegExp(`^${e.replaceAll("*", ".*")}$`).test(t) : t === e;
}
const Gt = /* @__PURE__ */ new Set(["unavailable", "unknown", "none"]);
function Yt(t) {
return Gt.has(t.toLowerCase());
}
function Jt(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 Ce(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 Zt(t, e, i) {
return (0.299 * t + 0.587 * e + 0.114 * i) / 255;
}
function Qt(t) {
const e = Ce(t);
return (e ? Zt(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), g = Math.round(l + (u - l) * i);
return n !== void 0 ? `rgba(${f}, ${d}, ${g}, ${n})` : `rgb(${f}, ${d}, ${g})`;
}
function Xt(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 Kt(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 ei(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 Xt({
clampedValue: u,
minValue: l,
maxValue: h,
midPoint: f,
colorLow: o,
colorMid: r,
colorHigh: s,
opacity: a
});
if (c !== void 0)
return Kt({
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 J(t, e) {
const i = Ce(t);
return i ? `rgba(${i[0]}, ${i[1]}, ${i[2]}, ${e})` : t;
}
function ti(t) {
return t.startsWith("light.");
}
function ii({ attributes: t, state: e }) {
const i = e === "on", n = j(t.brightness), s = i ? Math.round((n ?? 255) / 255 * 100) : 0, r = jt(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 = qt(t.rgb_color), h = Wt(t.hs_color);
l ? a.rgb = l : h && (a.hs = h);
}
return a;
}
function ni(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] = Jt(o, r);
return `rgba(${a}, ${l}, ${h}, ${n})`;
}
const s = Ce(i);
return s ? `rgba(${s[0]}, ${s[1]}, ${s[2]}, ${n})` : i;
}
const oi = ["switch", "input_boolean", "binary_sensor"];
function si(t) {
const e = t.split(".")[0];
return oi.includes(e ?? "");
}
function ri({ state: t }) {
return { isOn: t === "on" };
}
function ai(t, e, i) {
return t ? i : e;
}
function li(t) {
return t.startsWith("climate.");
}
function ci({ attributes: t, state: e }) {
const i = j(t.current_temperature), n = j(t.temperature), s = Bt(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 _e(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 hi(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 g = d / (t.length - 1) * n, x = r - o - (f - a) / h * (r - o * 2);
return `${g.toFixed(1)},${x.toFixed(1)}`;
}).join(" "), u = `0,${r} ${c} ${n},${r}`;
return { linePoints: c, fillPoints: u };
}
function ui(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 di = 0;
function fi(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 pi(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 gi(t) {
const { segments: e, data: i, width: n, height: s, colors: o, periodHours: r } = t;
if (i.length < 2) return O``;
const a = pi(e, r), l = a.length, h = t.min ?? Math.min(...i), u = (t.max ?? Math.max(...i)) - h || 1, f = 1, d = (b) => s - f - (b - h) / u * (s - f * 2), g = (b) => {
const p = b * (i.length - 1), m = Math.floor(p), w = Math.min(Math.ceil(p), i.length - 1), k = p - m;
return (i[m] ?? 0) * (1 - k) + (i[w] ?? 0) * k;
}, x = [];
let v = null;
for (let b = 0; b < l; b++) {
const p = a[b];
p ? v !== null && v.action === p ? v.end = (b + 1) / l : (v && x.push(v), v = { start: b / l, end: (b + 1) / l, action: p }) : v && (x.push(v), v = null);
}
return v && x.push(v), O`
${x.map((b) => {
const p = b.action === "heating" ? o.heating : o.cooling, m = 10, w = (b.end - b.start) / m;
let k = `${(b.start * n).toFixed(1)},${s}`;
for (let A = 0; A <= m; A++) {
const C = b.start + A * w, y = C * n, M = d(g(C));
k += ` ${y.toFixed(1)},${M.toFixed(1)}`;
}
return k += ` ${(b.end * n).toFixed(1)},${s}`, O`<polygon points="${k}" fill="${p}" />`;
})}
`;
}
function Fe(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 ? hi(t, e, 0) : { linePoints: "", fillPoints: "" }, g = ui(o), x = fi(o), v = a?.show !== !1 && c, b = r?.show !== !1 && c, p = `sparkline-gradient-${di++}`, m = !!a?.style, w = a?.style || `fill: url(#${p});`, k = `stroke: ${g.line}; stroke-width: 1.5;`, A = r?.style ? `${k} ${r.style}` : k;
return O`
<svg viewBox="0 0 ${n} ${s}" preserveAspectRatio="none">
${v && !m ? O`
<defs>
<linearGradient id="${p}" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color: ${g.fillTop};" />
<stop offset="100%" style="stop-color: ${g.fillBottom};" />
</linearGradient>
</defs>
` : _}
${u && c ? gi({ segments: i, data: t, width: n, height: s, colors: x, periodHours: h, min: e.min, max: e.max }) : _}
${v && !i ? O`<polygon points="${d}" style="${w}" />` : _}
${b ? O`<polyline points="${f}" style="fill: none; stroke-linecap: round; stroke-linejoin: round; ${A}" />` : _}
</svg>
`;
}
function _i(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 ? Fe(
n ? i.temperature : [],
e,
i.hvacActions
) : _;
}
return Array.isArray(t) && t.length > 1 ? Fe(t, e) : _;
}
function mi(t) {
return t === "heating" || t === "cooling" || t === "idle" || t === "off";
}
function ae(t) {
return t.startsWith("climate.");
}
const st = {
"12h": { hours: 12, statsPeriod: "5minute" },
"24h": { hours: 24, statsPeriod: "hour" },
"7d": { hours: 168, statsPeriod: "hour" },
"30d": { hours: 720, statsPeriod: "day" }
}, rt = 300 * 1e3, Ue = /* @__PURE__ */ new Map(), Be = /* @__PURE__ */ new Map();
function ve({ entityId: t, period: e, statistic: i }) {
return `${t}:${e}:${i}`;
}
function K(t, e) {
return `${t}|${e}`;
}
async function bi(t, e) {
const i = /* @__PURE__ */ new Map();
if (e.size === 0) return i;
const n = Date.now(), s = /* @__PURE__ */ new Map();
for (const [a, l] of e)
ae(a) && s.set(K(a, l.period), {
entityId: a,
period: l.period
}), ae(l.entityId) && s.set(K(l.entityId, l.period), {
entityId: l.entityId,
period: l.period
});
const o = await yi(t, s, n), r = await vi(t, e, o, n);
for (const [a, l] of e) {
const h = r.get(ve(l)) ?? [], c = ae(a) ? o.get(K(a, l.period))?.hvacActions : void 0;
i.set(a, c ? { temperature: h, hvacActions: c } : { temperature: h });
}
return i;
}
async function vi(t, e, i, n) {
const s = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
for (const r of e.values()) {
const a = ve(r);
if (s.has(a)) continue;
const l = Ue.get(a);
if (l && n - l.fetchedAt < rt) {
s.set(a, l.data);
continue;
}
const h = `${r.period}|${r.statistic}`, c = o.get(h);
c ? c.entityIds.add(r.entityId) : o.set(h, { spec: r, entityIds: /* @__PURE__ */ new Set([r.entityId]) });
}
return await Promise.all(
[...o.values()].map(async ({ spec: r, entityIds: a }) => {
const l = [...a], h = await ki(t, l, r.period, r.statistic);
for (const c of l) {
let u = h.get(c) ?? [];
u.length === 0 && ae(c) && (u = i.get(K(c, r.period))?.temperature ?? []);
const f = ve({ ...r, entityId: c });
Ue.set(f, { data: u, fetchedAt: n }), s.set(f, u);
}
})
), s;
}
async function yi(t, e, i) {
const n = /* @__PURE__ */ new Map();
if (e.size === 0) return n;
const s = /* @__PURE__ */ new Map();
for (const [o, { entityId: r, period: a }] of e) {
const l = Be.get(o);
if (l && i - l.fetchedAt < rt) {
n.set(o, l.data);
continue;
}
const h = s.get(a);
h ? h.push(r) : s.set(a, [r]);
}
return await Promise.all(
[...s].map(async ([o, r]) => {
const a = await $i(t, r, o, i);
for (const l of r) {
const h = a.get(l) ?? { temperature: [], hvacActions: [] }, c = K(l, o);
Be.set(c, { data: h, fetchedAt: i }), n.set(c, h);
}
})
), n;
}
async function $i(t, e, i, n) {
const s = /* @__PURE__ */ new Map();
if (e.length === 0) return s;
const r = st[i].hours * 60 * 60 * 1e3, a = new Date(n - r);
try {
const l = await t.callWS({
type: "history/history_during_period",
start_time: a.toISOString(),
entity_ids: e,
no_attributes: !1,
significant_changes_only: !1
// Get all changes for better temperature resolution
});
if (l)
for (const h of e) {
const c = l[h];
c && c.length > 0 && s.set(h, {
temperature: xi(c),
hvacActions: wi(c, a.getTime(), n, r)
});
}
} catch (l) {
console.warn("[treemap] Failed to fetch climate history:", l);
}
return s;
}
function xi(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 wi(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 (!mi(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), g = Math.min(1, (f - e) / n);
d < 1 && g > 0 && s.push({ start: d, end: g, action: c });
}
return s;
}
async function ki(t, e, i, n) {
const s = /* @__PURE__ */ new Map();
if (e.length === 0)
return s;
const o = st[i], r = new Date(Date.now() - o.hours * 60 * 60 * 1e3).toISOString();
try {
const a = await t.callWS({
type: "recorder/statistics_during_period",
start_time: r,
statistic_ids: e,
period: o.statsPeriod,
types: [n]
});
if (a)
for (const [l, h] of Object.entries(a)) {
const c = h.map((u) => u[n]).filter((u) => typeof u == "number" && !Number.isNaN(u));
s.set(l, c);
}
} catch (a) {
console.warn("[treemap] Failed to fetch statistics:", a);
for (const l of e)
s.has(l) || s.set(l, []);
}
return s;
}
const Se = ["mean", "min", "max", "sum", "state", "change"];
function Ai(t) {
return typeof t == "string" && Se.some((e) => e === t);
}
function me(t, e) {
return t ? e ? { ...t, ...e } : t : e;
}
function je(t) {
const e = {};
if (!t) return e;
for (const i of Object.keys(t)) {
const n = Reflect.get(t, i);
n !== void 0 && Object.assign(e, { [i]: n });
}
return e;
}
function he(t, e) {
const i = { ...je(t), ...je(e) }, n = me(t?.line, e?.line), s = me(t?.fill, e?.fill), o = me(t?.hvac, e?.hvac);
return {
...i,
show: i.show !== !1,
period: i.period ?? "24h",
function: i.function ?? "mean",
mode: i.mode ?? "dark",
...n ? { line: n } : {},
...s ? { fill: s } : {},
...o ? { hvac: o } : {}
};
}
function Ci(t, e) {
return t.entity ?? e;
}
function qe(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 Si(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 Mi(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 We(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: Mi(t, s, n).map((d, g) => ({
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: g % a * h,
y: Math.floor(g / a) * c,
width: h,
height: c
})), rows: l };
}
function zi(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 Vi(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 = qe(n, e), l = qe(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 Ei(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 Ti(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 We(t, e, i, r, a);
const l = t.map((p) => Math.abs(p.value)), h = Math.max(...l);
if (h === 0) return { rects: [], rows: 0 };
const c = l.filter((p) => p > 0);
if (c.length > 1) {
const p = Math.min(...c);
if ((h - p) / h < 0.01)
return We(t, e, i, r, a);
}
const u = e * i, f = zi(t, s, u, a), d = [];
let g = { x: 0, y: 0, width: e, height: i }, x = [...f];
for (; x.length > 0; ) {
const p = g.width < g.height, m = p ? g.height : g.width, { row: w, newRemaining: k } = Vi(x, m);
x = k;
const { rects: A, remaining: C } = Si(w, g, p);
if (d.push(...A), g = C, g.width <= 0 || g.height <= 0) break;
}
r && d.length > 0 && Ei(d, e, i);
const b = new Set(d.map((p) => Math.round(p.y * 100) / 100)).size;
return { rects: d, rows: b };
}
function Pi(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 Ni(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 Ge(t, e, i) {
const n = e ? !i : i;
return [...t].sort(
(s, o) => n ? s.sizeValue - o.sizeValue : o.sizeValue - s.sizeValue
);
}
function Oi(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 Di(t, e, i) {
const n = e ?? i * 0.15;
for (const s of t)
s.sizeValue < n && (s.sizeValue = n);
}
function Ii(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 = Pi(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 && Ni(t, l.sizeMin, l.sizeMax);
const h = !a || a === "value";
let c;
if (h) {
const f = Ge(t, i, n);
c = s !== void 0 && s > 0 ? f.slice(0, s) : f;
} else if (s !== void 0 && s > 0) {
const f = Ge(t, i, n), d = new Set(f.slice(0, s).map((g) => g.entity_id ?? g.label));
c = t.filter((g) => d.has(g.entity_id ?? g.label));
} else
c = [...t];
const u = Oi(c, r);
return Di(c, o, u), { items: c, colorMin: l.colorMin, colorMax: l.colorMax };
}
const Hi = [
{ threshold: 1e12, suffix: "T" },
{ threshold: 1e9, suffix: "B" },
{ threshold: 1e6, suffix: "M" },
{ threshold: 1e3, suffix: "k" }
];
function Ri(t, e = 1, i = !1) {
let n = t, s = "";
if (i) {
for (const o of Hi)
if (Math.abs(t) >= o.threshold) {
n = t / o.threshold, s = o.suffix;
break;
}
}
return n.toFixed(e) + s;
}
function Li(t, e) {
return t !== void 0 ? t : e !== void 0 ? e : 1;
}
const Fi = Xe`
: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 Ui = Object.defineProperty, Bi = Object.getOwnPropertyDescriptor, fe = (t, e, i, n) => {
for (var s = n > 1 ? void 0 : n ? Bi(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 && Ui(e, i, s), s;
};
const ji = "0.16.0";
console.info(
`%c TREEMAP-CARD %c v${ji}`,
"color: white; background: #3498db; font-weight: bold;",
"color: #3498db; background: white; font-weight: bold;"
);
function qi(t, e) {
return t.length !== e.length ? !1 : t.every((i, n) => i === e[n]);
}
let P = class extends B {
constructor() {
super(...arguments), this._sparklineData = /* @__PURE__ */ new Map(), this._fetchingSparklines = !1, this._debouncedFetchSparklines = It(() => void this._fetchSparklineData(), 100), this._entityConfigMap = /* @__PURE__ */ new Map(), this._sparklineConfigMap = /* @__PURE__ */ new Map(), this._sparklineConfigCache = /* @__PURE__ */ new Map(), this._holdTimer = null, this._holdFired = !1;
}
/**
* Return the editor element for visual configuration
*/
static getConfigElement() {
return Promise.resolve().then(() => yn), 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)
Y(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._validateSparklineFunction(t.sparkline), this._config = {
gap: 4,
// smaller gap
...t
}, this._entityConfigMap = /* @__PURE__ */ new Map(), this._sparklineConfigMap = /* @__PURE__ */ new Map(), this._sparklineConfigCache = /* @__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), i.sparkline && (this._validateSparklineFunction(i.sparkline, i.entity), this._sparklineConfigMap.set(i.entity, i.sparkline));
}
}
/**
* Reject an unknown sparkline function up front.
*
* Home Assistant validates the `types` parameter server side and rejects the
* whole websocket call, which would blank every sparkline sharing that request
* rather than just the misconfigured one.
*/
_validateSparklineFunction(t, e) {
const i = t?.function;
if (i === void 0 || Ai(i)) return;
const n = e ? ` for "${e}"` : "";
throw new Error(
`Invalid sparkline function "${String(i)}"${n}. Must be one of: ${Se.join(", ")}`
);
}
/**
* Effective sparkline config for a tile: card-level defaults with the
* per-entity override applied. Matches an exact entity id first, then
* wildcard patterns, mirroring how per-entity actions resolve.
*/
_getSparklineConfig(t) {
const e = this._config?.sparkline;
if (!t) return he(e);
const i = this._sparklineConfigCache.get(t);
if (i) return i;
let n = this._sparklineConfigMap.get(t);
if (!n) {
for (const [o, r] of this._sparklineConfigMap)
if (Y(t, o)) {
n = r;
break;
}
}
const s = he(e, n);
return this._sparklineConfigCache.set(t, s), s;
}
/**
* 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 } : re(t) ? t : { entity: String(t) };
}
getCardSize() {
return 4;
}
updated() {
this._debouncedFetchSparklines();
}
async _fetchSparklineData() {
if (!this.hass || this._fetchingSparklines) return;
const t = /* @__PURE__ */ new Map();
for (const { entity_id: e } of this._resolveData()) {
if (!e) continue;
const i = this._getSparklineConfig(e);
i.show && t.set(e, {
entityId: Ci(i, e),
period: i.period,
statistic: i.function
});
}
if (t.size !== 0) {
this._fetchingSparklines = !0;
try {
const e = await bi(this.hass, t);
e.size > 0 && !this._sparklineDataEquals(e) && (this._sparklineData = e);
} finally {
this._fetchingSparklines = !1;
}
}
}
/**
* Compare sparkline data maps to avoid unnecessary re-renders.
*
* Compares values rather than just lengths: pointing a tile at a different
* source entity usually yields the same number of buckets, and a length-only
* check would discard the new series. If the values really are identical the
* render is identical too, so skipping the update stays safe.
*/
_sparklineDataEquals(t) {
if (this._sparklineData.size !== t.size) return !1;
for (const [e, i] of t) {
const n = this._sparklineData.get(e);
if (!n || !qi(n.temperature, i.temperature)) return !1;
const s = n.hvacActions ?? [], o = i.hvacActions ?? [];
if (s.length !== o.length) return !1;
for (const [r, a] of s.entries()) {
const l = o[r];
if (a.action !== l?.action || a.start !== l.start || a.end !== l.end)
return !1;
}
}
return !0;
}
/**
* Get period hours for HVAC quantization.
*/
_getPeriodHours(t) {
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 (Y(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) => Y(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, g = r ?? L(c.attributes.icon);
if (ti(h)) {
const p = ii(c), { brightness: m } = p;
let w;
p.isOn ? w = 40 + m / 100 * 60 : w = 10, e.push({
label: d,
value: m,
// Display brightness as percentage
sizeValue: w,
sortValue: m,
colorValue: m,
entity_id: h,
icon: g ?? "mdi:lightbulb",
unit: "%",
light: p,
color: a
});
continue;
}
if (li(h)) {
const p = ci(c), m = this._config?.value?.attribute || "current_temperature", w = this._config?.size?.attribute || m, k = this._config?.color?.attribute || m;
let A = _e(p, m), C = _e(p, w), y = _e(p, k);
A === null && (A = j(c.attributes[m]) ?? 0), C === null && (C = j(c.attributes[w]) ?? 0), y === null && (y = j(c.attributes[k]) ?? 0);
const M = typeof A == "number" ? A : 0, z = typeof C == "number" ? Math.max(0.1, Math.abs(C)) : 0.1, ft = typeof y == "number" ? y : 0;
let R;
if (g)
R = g;
else
switch (p.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: M,
sizeValue: z,
sortValue: M,
colorValue: ft,
entity_id: h,
icon: R,
unit: L(c.attributes.unit_of_measurement),
climate: p,
color: a
});
continue;
}
if (si(h)) {
const p = ri(c), { isOn: m } = p;
e.push({
label: d,
value: m ? 1 : 0,
sizeValue: 1,
// Equal size for all binary entities
sortValue: m ? 1 : 0,
colorValue: m ? 1 : 0,
entity_id: h,
icon: g,
binary: p,
color: a
});
continue;
}
const x = this._config?.value?.attribute || "state";
let v;
if (x === "state")
v = Number.parseFloat(c.state);
else {
const p = c.attributes[x];
v = Number.parseFloat(String(p ?? 0));
}
if (Number.isNaN(v)) {
if (!Yt(c.state) || !this._config?.filter?.unavailable)
continue;
const m = 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: g,
unit: m,
unavailable: !0,
rawState: c.state,
color: a
});
continue;
}
const b = L(c.attributes.unit_of_measurement);
e.push({
label: d,
value: v,
sizeValue: v,
sortValue: v,
colorValue: v,
entity_id: h,
icon: g,
unit: b,
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((g) => typeof g == "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 ei(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 ni(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 $`<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 $`
<ha-card header="${a || _}" style="${r}">
${s && n ? $`<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
} = Ii(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 M = y.entity_id ?? y.label;
f.set(M, {
value: y.value,
sortValue: y.sortValue,
colorValue: y.colorValue,
sizeValue: y.sizeValue,
unit: y.unit
});
}
const d = l.map((y) => ({ ...y, value: y.sizeValue })), g = this._config?.order === "asc", v = this._config?.size?.inverse === !0 ? !g : g, b = this._config?.sort_by ?? "value", { rects: p, rows: m } = Ti(d, 100, 100, {
compressRange: !0,
equalSize: u,
ascending: v,
sortBy: b
});
for (const y of p) {
const M = y.entity_id ?? y.label, z = f.get(M);
z && (y.value = z.value, y.sortValue = z.sortValue, y.colorValue = z.colorValue, y.sizeValue = z.sizeValue, y.unit = z.unit);
}
const w = Math.max(1, m), k = Math.max(100, w * 100), A = this._config.height ?? k, C = this._config.gap ?? 6;
return $`
<ha-card header="${a || _}" style="${r}">
${s && n ? $`<div class="treemap-header" style="${o}">${n}</div>` : _}
<div class="card-content">
<div class="treemap-container" style="height: ${A}px">
${p.map((y) => this._renderRect(y, h, c, A, 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 : J(t.color, n);
if (t.unavailable) {
const s = this._config?.color?.unavailable ?? "#868e96";
return n === void 0 ? s : J(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 : J(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 : J(s.heating, n);
if (t.climate.hvacAction === "cooling" && s.cooling)
return n === void 0 ? s.cooling : J(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 ai(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 = Li(this._config?.value?.precision, n), o = this._config?.value?.abbreviate ?? !1, r = Ri(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 } : Qt(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: g, labelStyle: x, valueStyle: v } = this._calculateStyles(o), b = s / 2;
return $`
<div
class="treemap-item ${r}"
style="
left: calc(${t.x}% + ${b}px);
top: calc(${t.y}% + ${b}px);
width: calc(${t.width}% - ${s}px);
height: calc(${t.height}% - ${s}px);
background-color: ${d};
"
@pointerdown="${(p) => this._onPointerDown(p, t)}"
@pointerup="${(p) => this._onPointerUp(p, t)}"
@pointercancel="${() => this._clearHoldTimer()}"
title="${t.label}: ${t.value}"
>
${l && (t.icon || this._config?.icon?.icon) ? $`<ha-icon
class="treemap-icon ${a ? "hvac-active" : ""}"
style="${g}"
icon="${t.icon || this._config?.icon?.icon}"
></ha-icon>` : _}
${h ? $`<span class="treemap-label" style="${x}">${u}</span>` : _}
${c ? $`<span class="treemap-value" style="${v}">${f}</span>` : _}
${(() => {
const p = this._getSparklineConfig(t.entity_id);
if (!p.show) return _;
const m = t.sparklineData ?? (t.entity_id ? this._sparklineData.get(t.entity_id) : void 0);
return $`<div class="treemap-sparkline">
${_i(m, {
mode: p.mode,
line: p.line,
fill: p.fill,
hvac: p.hvac,
periodHours: this._getPeriodHours(p.period),
min: p.min,
max: p.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] && Y(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 && be(this, "hass-more-info", { entityId: e });
break;
case "navigate":
"navigation_path" in t && t.navigation_path && Ht(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":
be(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);
}, P._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);
}
};
P.styles = Fi;
P._HOLD_THRESHOLD_MS = 500;
fe([
de({ attribute: !1 })
], P.prototype, "hass", 2);
fe([
Ae()
], P.prototype, "_config", 2);
fe([
Ae()
], P.prototype, "_sparklineData", 2);
P = fe([
ot("treemap-card")
], P);
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 Wi(t, e) {
return t === e || Number.isNaN(t) && Number.isNaN(e);
}
function Gi(t) {
return t == null ? "" : at(t);
}
function at(t) {
if (typeof t == "string") return t;
if (Array.isArray(t)) return t.map(at).join(",");
const e = String(t);
return e === "0" && Object.is(Number(t), -0) ? "-0" : e;
}
function Me(t) {
return typeof t == "string" || typeof t == "symbol" ? t : Object.is(t?.valueOf?.(), -0) ? "-0" : String(t);
}
function lt(t) {
if (Array.isArray(t)) return t.map(Me);
if (typeof t == "symbol") return [t];
t = Gi(t);
const e = [], i = t.length;
if (i === 0) return e;
let n = 0, s = "", o = "", r = !1, a = !1;
const l = /^-?\d+(?:\.\d+)?$/;
for (t.charCodeAt(0) === 46 && e.push(""); n < i; ) {
const h = t[n];
if (o) h === "\\" && n + 1 < i ? (n++, s += t[n]) : h === o ? o = "" : s += h;
else if (r) if (h === '"' || h === "'")
o = h, a = !0;
else if (h === "]") {
if (r = !1, !a && s.includes(".") && !l.test(s)) {
const c = s.split(".");
for (let u = 0; u < c.length; u++) c[u] !== "" && e.push(c[u]);
} else e.push(s);
s = "";
} else s += h;
else if (h === "[")
r = !0, a = !1, s && (e.push(s), s = "");
else if (h === ".") {
s && (e.push(s), s = "");
const c = t[n + 1];
(c === void 0 || c === ".") && e.push("");
} else s += h;
n++;
}
return s && e.push(s), e;
}
function ye(t) {
return t === "__proto__";
}
const Yi = /\.|(\[(?:[^[\]]*|(["'])(?:(?!\2)[^\\]|\\.)*?\2)\])/;
function Ji(t) {
switch (typeof t) {
case "number":
case "symbol":
return !1;
case "string":
return t === "" || t.startsWith(".") || t.endsWith(".") ? !1 : Yi.test(t);
default:
return !1;
}
}
function ct(t, e, i) {
if (t == null) return i;
switch (typeof e) {
case "string": {
if (ye(e)) return i;
const n = t[e];
return n === void 0 ? Ji(e) && !Object.hasOwn(t, e) ? ct(t, lt(e), i) : i : n;
}
case "number":
case "symbol": {
typeof e == "number" && (e = Me(e));
const n = t[e];
return n === void 0 ? i : n;
}
default: {
if (Array.isArray(e)) return Zi(t, e, i);
if (Object.is(e?.valueOf(), -0) ? e = "-0" : e = String(e), ye(e)) return i;
const n = t[e];
return n === void 0 ? i : n;
}
}
}
function Zi(t, e, i) {
if (e.length === 0) return i;
let n = t;
for (let s = 0; s < e.length; s++) {
if (n == null || ye(e[s])) return i;
n = n[e[s]];
}
return n === void 0 ? i : n;
}
function Ye(t) {
return t !== null && (typeof t == "object" || typeof t == "function");
}
const Qi = /^(?:0|[1-9]\d*)$/;
function Xi(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 Qi.test(t);
}
}
function Ki(t) {
return typeof t == "symbol" || t instanceof Symbol;
}
const en = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, tn = /^\w*$/;
function nn(t, e) {
return Array.isArray(t) ? !1 : typeof t == "number" || typeof t == "boolean" || t == null || Ki(t) ? !0 : typeof t == "string" && (tn.test(t) || !en.test(t)) || e != null && Object.hasOwn(e, t);
}
const on = (t, e, i) => {
const n = t[e];
(!(Object.hasOwn(t, e) && Wi(n, i)) || i === void 0 && !(e in t)) && (t[e] = i);
};
function sn(t) {
return t === "__proto__" || t === "constructor" || t === "prototype";
}
function rn(t, e, i, n) {
if (t == null && !Ye(t)) return t;
let s;
nn(e, t) ? s = [e] : Array.isArray(e) ? s = e : s = lt(e);
const o = i(ct(t, s));
let r = t;
for (let a = 0; a < s.length && r != null; a++) {
const l = Me(s[a]);
if (sn(l)) return t;
let h;
if (a === s.length - 1) h = o;
else {
const c = r[l], u = n?.(c, l, t);
h = u !== void 0 ? u : Ye(c) ? c : Xi(s[a + 1]) ? [] : {};
}
on(r, l, h), r = r[l];
}
return t;
}
function V(t, e, i) {
return rn(t, e, () => i, () => {
});
}
const an = Xe`
: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;
}
`, ht = { 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", function: "Statistik", function_mean: "Mittelwert", function_min: "Minimum", function_max: "Maximum", function_sum: "Summe (laufend)", function_state: "Zustand (letzter Wert)", function_change: "Änderung (Differenz je Intervall)", entity: "Quell-Entität", entity_helper: "Leer lassen, um die eigene Entität der Kachel zu zeichnen. Alle Statistiken stammen aus den Langzeitstatistiken, Sensoren ohne state_class bleiben daher leer." }, 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" } }, ln = {
editor: ht
}, cn = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: ln,
editor: ht
}, Symbol.toStringTag, { value: "Module" })), ut = { 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", function: "Statistic", function_mean: "Mean (average)", function_min: "Min", function_max: "Max", function_sum: "Sum (running total)", function_state: "State (last value)", function_change: "Change (difference per bucket)", entity: "Source entity", entity_helper: "Leave empty to plot each tile's own entity. All statistics come from long-term statistics, so sensors without a state_class stay blank." }, 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" } }, hn = {
editor: ut
}, un = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: hn,
editor: ut
}, Symbol.toStringTag, { value: "Module" })), dt = { 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", function: "Statistique", function_mean: "Moyenne", function_min: "Minimum", function_max: "Maximum", function_sum: "Somme (cumulée)", function_state: "État (dernière valeur)", function_change: "Variation (différence par intervalle)", entity: "Entité source", entity_helper: "Laisser vide pour tracer l’entité de la tuile. Toutes les statistiques proviennent des statistiques long terme : les capteurs sans state_class restent vides." }, 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" } }, dn = {
editor: dt
}, fn = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: dn,
editor: dt
}, Symbol.toStringTag, { value: "Module" })), Je = {
de: cn,
en: un,
fr: fn
};
function pn(t) {
return typeof t == "object" && t !== null;
}
function Ze(t, e) {
const i = e.split(".");
let n = t;
for (const s of i)
if (n && pn(n) && s in n)
n = n[s];
else
return;
return typeof n == "string" ? n : void 0;
}
function gn(t) {
return (t?.language ?? "en").split("-")[0] ?? "en";
}
function _n(t, e) {
const i = gn(t), n = Je[i];
if (n) {
const s = Ze(n, e);
if (s) return s;
}
if (i !== "en") {
const s = Je.en;
if (s) {
const o = Ze(s, e);
if (o) return o;
}
}
return e;
}
var mn = Object.defineProperty, bn = Object.getOwnPropertyDescriptor, pe = (t, e, i, n) => {
for (var s = n > 1 ? void 0 : n ? bn(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 && mn(e, i, s), s;
};
const oe = "https://github.com/omachala/ha-treemap-card";
function F(t) {
const e = t.target;
if (e && typeof e == "object" && "value" in e) {
const i = e.value;
return String(i ?? "");
}
return "";
}
function vn(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 _n(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 = F(e) || void 0;
this._config = V({ ...this._config }, t, i), this._fireConfigChanged();
}
/**
* Generic handler for checkbox changes
*/
_handleBoolChange(t, e) {
if (!this._config) return;
const i = vn(e);
this._config = V({ ...this._config }, t, i), this._fireConfigChanged();
}
/**
* Generic handler for number input changes
*/
_handleNumberChange(t, e) {
if (!this._config) return;
const i = F(e), n = i ? Number.parseFloat(i) : void 0;
this._config = V({ ...this._config }, t, n), this._fireConfigChanged();
}
/**
* Handler for entities textarea (splits lines into array).
*
* Any entity that survives the edit keeps its object config, so per-entity
* settings the textarea cannot show - name, color, actions, sparkline
* overrides - are not destroyed by typing in it.
*/
_handleEntitiesChange(t) {
if (!this._config) return;
const e = /* @__PURE__ */ new Map();
for (const n of this._config.entities ?? [])
re(n) && e.set(n.entity, n);
const i = F(t).split(`
`).map((n) => n.trim()).filter((n) => n.length > 0).map((n) => e.get(n) ?? n);
this._config = V({ ...this._config }, "entities", i), this._fireConfigChanged();
}
/**
* The value to display for a card-level sparkline field.
*
* The editor presents one setting for the whole card, but YAML may override a
* key per entity. When the tiles do not all resolve to the same value there is
* no honest value to show, so the control is left unselected rather than
* claiming a value that only some tiles use.
*/
_sparklineFieldValue(t) {
const e = this._config?.sparkline, i = this._config?.entities ?? [], n = he(e)[t];
if (i.length === 0) return n ?? "";
let s, o = !0;
for (const r of i) {
const a = re(r) ? r.sparkline : void 0, l = he(e, a)[t];
if (o)
s = l, o = !1;
else if (s !== l)
return "";
}
return s ?? "";
}
/**
* Write a card-level sparkline setting.
*
* Per-entity overrides are left alone, exactly as a card-level colour change
* leaves per-entity `color` alone. A tile that overrides this key keeps its
* own value; the control renders blank in that case, which is the signal that
* the tiles do not all agree.
*/
_handleSparklineFieldChange(t, e) {
if (!this._config) return;
const i = F(e).trim() || void 0;
this._config = V({ ...this._config }, `sparkline.${t}`, 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 = V({ ...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 = F(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 = V({ ...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 = F(t).split(`
`).map((n) => n.trim()).filter((n) => n.length > 0);
this._config = V({ ...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 `${oe}?tab=readme-ov-file#${t}`;
}
_renderDocsLink(t) {
return $`
<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 $`
<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 $`<div class="editor">${this._t("editor.no_config")}</div>`;
if (this._config.entity)
return $`
<div class="editor">
<ha-alert alert-type="info">${this._t("editor.yaml_only")}</ha-alert>
</div>
`;
const t = this._config.entities?.map((o) => re(o) ? o.entity : o).join(`
`) ?? "", e = this._config.exclude?.join(`
`) ?? "", i = this._config.label ?? {}, n = this._config.value ?? {}, s = this._config.icon ?? {};
return $`
<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: $`
<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: $`
<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: $`
<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
data-testid="sparkline-period"
label=${this._t("editor.sparkline.period")}
.value=${this._sparklineFieldValue("period")}
@selected=${(o) => this._handleSparklineFieldChange("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
data-testid="sparkline-function"
label=${this._t("editor.sparkline.function")}
.value=${this._sparklineFieldValue("function")}
@selected=${(o) => this._handleSparklineFieldChange("function", o)}
@closed=${(o) => o.stopPropagation()}
>
${Se.map(
(o) => $`<ha-list-item value=${o}
>${this._t(`editor.sparkline.function_${o}`)}</ha-list-item
>`
)}
</ha-select>
<ha-textfield
data-testid="sparkline-entity"
label=${this._t("editor.sparkline.entity")}
.value=${this._sparklineFieldValue("entity")}
@input=${(o) => this._handleSparklineFieldChange("entity", o)}
placeholder="sensor.outdoor_humidity"
></ha-textfield>
<span class="field-helper">${this._t("editor.sparkline.entity_helper")}</span>
<ha-select
data-testid="sparkline-mode"
label=${this._t("editor.sparkline.mode")}
.value=${this._sparklineFieldValue("mode")}
@selected=${(o) => this._handleSparklineFieldChange("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=${oe} 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="${oe}/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=${oe} target="_blank" rel="noopener">
<ha-icon icon="mdi:star-outline"></ha-icon>
${this._t("editor.footer.star")}
</a>
</div>
</div>
`;
}
};
H.styles = an;
pe([
de({ attribute: !1 })
], H.prototype, "hass", 2);
pe([
de({ attribute: !1 })
], H.prototype, "lovelace", 2);
pe([
Ae()
], H.prototype, "_config", 2);
H = pe([
ot("treemap-card-editor")
], H);
const yn = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
get TreemapCardEditor() {
return H;
}
}, Symbol.toStringTag, { value: "Module" }));
export {
P as TreemapCard
};