3306 lines
117 KiB
JavaScript
3306 lines
117 KiB
JavaScript
/**
|
||
* @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_* climate.* 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
|
||
};
|