diff --git a/dist/chartdeck-card.js b/dist/chartdeck-card.js index dc4193f..e92b546 100644 --- a/dist/chartdeck-card.js +++ b/dist/chartdeck-card.js @@ -3,23 +3,23 @@ * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,n=Symbol(),o=new WeakMap;let i=class{constructor(t,e,o){if(this._$cssResult$=!0,o!==n)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const n=this.t;if(e&&void 0===t){const e=void 0!==n&&1===n.length;e&&(t=o.get(n)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o.set(n,t))}return t}toString(){return this.cssText}};const r=(t,...e)=>{const o=1===t.length?t[0]:e.reduce((e,n,o)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+t[o+1],t[0]);return new i(o,t,n)},a=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const n of t.cssRules)e+=n.cssText;return(t=>new i("string"==typeof t?t:t+"",void 0,n))(e)})(t):t,{is:s,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:d,getOwnPropertySymbols:h,getPrototypeOf:u}=Object,p=globalThis,m=p.trustedTypes,f=m?m.emptyScript:"",g=p.reactiveElementPolyfillSupport,y=(t,e)=>t,_={toAttribute(t,e){switch(e){case Boolean:t=t?f:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let n=t;switch(e){case Boolean:n=null!==t;break;case Number:n=null===t?null:Number(t);break;case Object:case Array:try{n=JSON.parse(t)}catch(t){n=null}}return n}},v=(t,e)=>!s(t,e),b={attribute:!0,type:String,converter:_,reflect:!1,useDefault:!1,hasChanged:v}; +const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,n=Symbol(),o=new WeakMap;let i=class{constructor(t,e,o){if(this._$cssResult$=!0,o!==n)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const n=this.t;if(e&&void 0===t){const e=void 0!==n&&1===n.length;e&&(t=o.get(n)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o.set(n,t))}return t}toString(){return this.cssText}};const r=(t,...e)=>{const o=1===t.length?t[0]:e.reduce((e,n,o)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+t[o+1],t[0]);return new i(o,t,n)},a=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const n of t.cssRules)e+=n.cssText;return(t=>new i("string"==typeof t?t:t+"",void 0,n))(e)})(t):t,{is:s,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:d,getOwnPropertySymbols:h,getPrototypeOf:u}=Object,p=globalThis,m=p.trustedTypes,f=m?m.emptyScript:"",g=p.reactiveElementPolyfillSupport,_=(t,e)=>t,y={toAttribute(t,e){switch(e){case Boolean:t=t?f:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let n=t;switch(e){case Boolean:n=null!==t;break;case Number:n=null===t?null:Number(t);break;case Object:case Array:try{n=JSON.parse(t)}catch(t){n=null}}return n}},v=(t,e)=>!s(t,e),b={attribute:!0,type:String,converter:y,reflect:!1,useDefault:!1,hasChanged:v}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;let $=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=b){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const n=Symbol(),o=this.getPropertyDescriptor(t,n,e);void 0!==o&&l(this.prototype,t,o)}}static getPropertyDescriptor(t,e,n){const{get:o,set:i}=c(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:o,set(e){const r=o?.call(this);i?.call(this,e),this.requestUpdate(t,r,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(y("elementProperties")))return;const t=u(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(y("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(y("properties"))){const t=this.properties,e=[...d(t),...h(t)];for(const n of e)this.createProperty(n,t[n])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,n]of e)this.elementProperties.set(t,n)}this._$Eh=new Map;for(const[e,n]of this.elementProperties){const t=this._$Eu(e,n);void 0!==t&&this._$Eh.set(t,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const n=new Set(t.flat(1/0).reverse());for(const t of n)e.unshift(a(t))}else void 0!==t&&e.push(a(t));return e}static _$Eu(t,e){const n=e.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof t?t.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(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const n of e.keys())this.hasOwnProperty(n)&&(t.set(n,this[n]),delete this[n]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const n=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((n,o)=>{if(e)n.adoptedStyleSheets=o.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of o){const o=document.createElement("style"),i=t.litNonce;void 0!==i&&o.setAttribute("nonce",i),o.textContent=e.cssText,n.appendChild(o)}})(n,this.constructor.elementStyles),n}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,n){this._$AK(t,n)}_$ET(t,e){const n=this.constructor.elementProperties.get(t),o=this.constructor._$Eu(t,n);if(void 0!==o&&!0===n.reflect){const i=(void 0!==n.converter?.toAttribute?n.converter:_).toAttribute(e,n.type);this._$Em=t,null==i?this.removeAttribute(o):this.setAttribute(o,i),this._$Em=null}}_$AK(t,e){const n=this.constructor,o=n._$Eh.get(t);if(void 0!==o&&this._$Em!==o){const t=n.getPropertyOptions(o),i="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:_;this._$Em=o;const r=i.fromAttribute(e,t.type);this[o]=r??this._$Ej?.get(o)??r,this._$Em=null}}requestUpdate(t,e,n,o=!1,i){if(void 0!==t){const r=this.constructor;if(!1===o&&(i=this[t]),n??=r.getPropertyOptions(t),!((n.hasChanged??v)(i,e)||n.useDefault&&n.reflect&&i===this._$Ej?.get(t)&&!this.hasAttribute(r._$Eu(t,n))))return;this.C(t,e,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:n,reflect:o,wrapped:i},r){n&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??e??this[t]),!0!==i||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||n||(e=void 0),this._$AL.set(t,e)),!0===o&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,n]of t){const{wrapped:t}=n,o=this[e];!0!==t||this._$AL.has(e)||void 0===o||this.C(e,void 0,n,o)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}};$.elementStyles=[],$.shadowRootOptions={mode:"open"},$[y("elementProperties")]=new Map,$[y("finalized")]=new Map,g?.({ReactiveElement:$}),(p.reactiveElementVersions??=[]).push("2.1.2"); + */Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;let $=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=b){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const n=Symbol(),o=this.getPropertyDescriptor(t,n,e);void 0!==o&&l(this.prototype,t,o)}}static getPropertyDescriptor(t,e,n){const{get:o,set:i}=c(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:o,set(e){const r=o?.call(this);i?.call(this,e),this.requestUpdate(t,r,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(_("elementProperties")))return;const t=u(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(_("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(_("properties"))){const t=this.properties,e=[...d(t),...h(t)];for(const n of e)this.createProperty(n,t[n])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,n]of e)this.elementProperties.set(t,n)}this._$Eh=new Map;for(const[e,n]of this.elementProperties){const t=this._$Eu(e,n);void 0!==t&&this._$Eh.set(t,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const n=new Set(t.flat(1/0).reverse());for(const t of n)e.unshift(a(t))}else void 0!==t&&e.push(a(t));return e}static _$Eu(t,e){const n=e.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof t?t.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(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const n of e.keys())this.hasOwnProperty(n)&&(t.set(n,this[n]),delete this[n]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const n=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((n,o)=>{if(e)n.adoptedStyleSheets=o.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of o){const o=document.createElement("style"),i=t.litNonce;void 0!==i&&o.setAttribute("nonce",i),o.textContent=e.cssText,n.appendChild(o)}})(n,this.constructor.elementStyles),n}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,n){this._$AK(t,n)}_$ET(t,e){const n=this.constructor.elementProperties.get(t),o=this.constructor._$Eu(t,n);if(void 0!==o&&!0===n.reflect){const i=(void 0!==n.converter?.toAttribute?n.converter:y).toAttribute(e,n.type);this._$Em=t,null==i?this.removeAttribute(o):this.setAttribute(o,i),this._$Em=null}}_$AK(t,e){const n=this.constructor,o=n._$Eh.get(t);if(void 0!==o&&this._$Em!==o){const t=n.getPropertyOptions(o),i="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:y;this._$Em=o;const r=i.fromAttribute(e,t.type);this[o]=r??this._$Ej?.get(o)??r,this._$Em=null}}requestUpdate(t,e,n,o=!1,i){if(void 0!==t){const r=this.constructor;if(!1===o&&(i=this[t]),n??=r.getPropertyOptions(t),!((n.hasChanged??v)(i,e)||n.useDefault&&n.reflect&&i===this._$Ej?.get(t)&&!this.hasAttribute(r._$Eu(t,n))))return;this.C(t,e,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:n,reflect:o,wrapped:i},r){n&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??e??this[t]),!0!==i||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||n||(e=void 0),this._$AL.set(t,e)),!0===o&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,n]of t){const{wrapped:t}=n,o=this[e];!0!==t||this._$AL.has(e)||void 0===o||this.C(e,void 0,n,o)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}};$.elementStyles=[],$.shadowRootOptions={mode:"open"},$[_("elementProperties")]=new Map,$[_("finalized")]=new Map,g?.({ReactiveElement:$}),(p.reactiveElementVersions??=[]).push("2.1.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const x=globalThis,w=t=>t,k=x.trustedTypes,M=k?k.createPolicy("lit-html",{createHTML:t=>t}):void 0,A="$lit$",C=`lit$${Math.random().toFixed(9).slice(2)}$`,S="?"+C,E=`<${S}>`,O=document,T=()=>O.createComment(""),L=t=>null===t||"object"!=typeof t&&"function"!=typeof t,N=Array.isArray,U="[ \t\n\f\r]",j=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,z=/-->/g,P=/>/g,H=RegExp(`>|${U}(?:([^\\s"'>=/]+)(${U}*=${U}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),F=/'/g,D=/"/g,R=/^(?:script|style|textarea|title)$/i,V=t=>(e,...n)=>({_$litType$:t,strings:e,values:n}),B=V(1),I=V(2),W=Symbol.for("lit-noChange"),Z=Symbol.for("lit-nothing"),q=new WeakMap,Y=O.createTreeWalker(O,129);function G(t,e){if(!N(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==M?M.createHTML(e):e}class X{constructor({strings:t,_$litType$:e},n){let o;this.parts=[];let i=0,r=0;const a=t.length-1,s=this.parts,[l,c]=((t,e)=>{const n=t.length-1,o=[];let i,r=2===e?"":3===e?"":"",a=j;for(let s=0;s"===l[0]?(a=i??j,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,n=l[1],a=void 0===l[3]?H:'"'===l[3]?D:F):a===D||a===F?a=H:a===z||a===P?a=j:(a=H,i=void 0);const h=a===H&&t[s+1].startsWith("/>")?" ":"";r+=a===j?e+E:c>=0?(o.push(n),e.slice(0,c)+A+e.slice(c)+C+h):e+C+(-2===c?s:h)}return[G(t,r+(t[n]||"")+(2===e?"":3===e?"":"")),o]})(t,e);if(this.el=X.createElement(l,n),Y.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(o=Y.nextNode())&&s.length0){o.textContent=k?k.emptyScript:"";for(let n=0;nN(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==Z&&L(this._$AH)?this._$AA.nextSibling.data=t:this.T(O.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:n}=t,o="number"==typeof n?this._$AC(t):(void 0===n.el&&(n.el=X.createElement(G(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===o)this._$AH.p(e);else{const t=new K(o,this),n=t.u(this.options);t.p(e),this.T(n),this._$AH=t}}_$AC(t){let e=q.get(t.strings);return void 0===e&&q.set(t.strings,e=new X(t)),e}k(t){N(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let n,o=0;for(const i of t)o===e.length?e.push(n=new Q(this.O(T()),this.O(T()),this,this.options)):n=e[o],n._$AI(i),o++;o2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=Z}_$AI(t,e=this,n,o){const i=this.strings;let r=!1;if(void 0===i)t=J(this,t,e,0),r=!L(t)||t!==this._$AH&&t!==W,r&&(this._$AH=t);else{const o=t;let a,s;for(t=i[0],a=0;at,k=x.trustedTypes,M=k?k.createPolicy("lit-html",{createHTML:t=>t}):void 0,A="$lit$",E=`lit$${Math.random().toFixed(9).slice(2)}$`,C="?"+E,S=`<${C}>`,O=document,L=()=>O.createComment(""),T=t=>null===t||"object"!=typeof t&&"function"!=typeof t,N=Array.isArray,j="[ \t\n\f\r]",U=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,z=/-->/g,P=/>/g,H=RegExp(`>|${j}(?:([^\\s"'>=/]+)(${j}*=${j}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),F=/'/g,D=/"/g,V=/^(?:script|style|textarea|title)$/i,R=t=>(e,...n)=>({_$litType$:t,strings:e,values:n}),B=R(1),I=R(2),Z=Symbol.for("lit-noChange"),W=Symbol.for("lit-nothing"),q=new WeakMap,Y=O.createTreeWalker(O,129);function G(t,e){if(!N(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==M?M.createHTML(e):e}class X{constructor({strings:t,_$litType$:e},n){let o;this.parts=[];let i=0,r=0;const a=t.length-1,s=this.parts,[l,c]=((t,e)=>{const n=t.length-1,o=[];let i,r=2===e?"":3===e?"":"",a=U;for(let s=0;s"===l[0]?(a=i??U,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,n=l[1],a=void 0===l[3]?H:'"'===l[3]?D:F):a===D||a===F?a=H:a===z||a===P?a=U:(a=H,i=void 0);const h=a===H&&t[s+1].startsWith("/>")?" ":"";r+=a===U?e+S:c>=0?(o.push(n),e.slice(0,c)+A+e.slice(c)+E+h):e+E+(-2===c?s:h)}return[G(t,r+(t[n]||"")+(2===e?"":3===e?"":"")),o]})(t,e);if(this.el=X.createElement(l,n),Y.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(o=Y.nextNode())&&s.length0){o.textContent=k?k.emptyScript:"";for(let n=0;nN(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==W&&T(this._$AH)?this._$AA.nextSibling.data=t:this.T(O.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:n}=t,o="number"==typeof n?this._$AC(t):(void 0===n.el&&(n.el=X.createElement(G(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===o)this._$AH.p(e);else{const t=new K(o,this),n=t.u(this.options);t.p(e),this.T(n),this._$AH=t}}_$AC(t){let e=q.get(t.strings);return void 0===e&&q.set(t.strings,e=new X(t)),e}k(t){N(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let n,o=0;for(const i of t)o===e.length?e.push(n=new Q(this.O(L()),this.O(L()),this,this.options)):n=e[o],n._$AI(i),o++;o2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=W}_$AI(t,e=this,n,o){const i=this.strings;let r=!1;if(void 0===i)t=J(this,t,e,0),r=!T(t)||t!==this._$AH&&t!==Z,r&&(this._$AH=t);else{const o=t;let a,s;for(t=i[0],a=0;a{const o=n?.renderBefore??e;let i=o._$litPart$;if(void 0===i){const t=n?.renderBefore??null;o._$litPart$=i=new Q(e.insertBefore(T(),t),t,void 0,n??{})}return i._$AI(t),i})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return W}};lt._$litElement$=!0,lt.finalized=!0,st.litElementHydrateSupport?.({LitElement:lt});const ct=st.litElementPolyfillSupport;ct?.({LitElement:lt}),(st.litElementVersions??=[]).push("4.2.2"); + */let lt=class extends ${constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=((t,e,n)=>{const o=n?.renderBefore??e;let i=o._$litPart$;if(void 0===i){const t=n?.renderBefore??null;o._$litPart$=i=new Q(e.insertBefore(L(),t),t,void 0,n??{})}return i._$AI(t),i})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return Z}};lt._$litElement$=!0,lt.finalized=!0,st.litElementHydrateSupport?.({LitElement:lt});const ct=st.litElementPolyfillSupport;ct?.({LitElement:lt}),(st.litElementVersions??=[]).push("4.2.2"); /** * @license * Copyright 2017 Google LLC @@ -30,41 +30,41 @@ const dt=1,ht=2,ut=3,pt=4,mt=t=>(...e)=>({_$litDirective$:t,values:e});let ft=cl * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */const{I:gt}=rt,yt=t=>t,_t=()=>document.createComment(""),vt=(t,e,n)=>{const o=t._$AA.parentNode,i=void 0===e?t._$AB:e._$AA;if(void 0===n){const e=o.insertBefore(_t(),i),r=o.insertBefore(_t(),i);n=new gt(e,r,t,t.options)}else{const e=n._$AB.nextSibling,r=n._$AM,a=r!==t;if(a){let e;n._$AQ?.(t),n._$AM=t,void 0!==n._$AP&&(e=t._$AU)!==r._$AU&&n._$AP(e)}if(e!==i||a){let t=n._$AA;for(;t!==e;){const e=yt(t).nextSibling;yt(o).insertBefore(t,i),t=e}}}return n},bt=(t,e,n=t)=>(t._$AI(e,n),t),$t={},xt=(t,e=$t)=>t._$AH=e,wt=t=>{t._$AR(),t._$AA.remove()},kt=(t,e,n)=>{const o=new Map;for(let i=e;i<=n;i++)o.set(t[i],i);return o},Mt=mt(class extends ft{constructor(t){if(super(t),t.type!==ht)throw Error("repeat() can only be used in text expressions")}dt(t,e,n){let o;void 0===n?n=e:void 0!==e&&(o=e);const i=[],r=[];let a=0;for(const s of t)i[a]=o?o(s,a):a,r[a]=n(s,a),a++;return{values:r,keys:i}}render(t,e,n){return this.dt(t,e,n).values}update(t,[e,n,o]){const i=(t=>t._$AH)(t),{values:r,keys:a}=this.dt(e,n,o);if(!Array.isArray(i))return this.ut=a,r;const s=this.ut??=[],l=[];let c,d,h=0,u=i.length-1,p=0,m=r.length-1;for(;h<=u&&p<=m;)if(null===i[h])h++;else if(null===i[u])u--;else if(s[h]===a[p])l[p]=bt(i[h],r[p]),h++,p++;else if(s[u]===a[m])l[m]=bt(i[u],r[m]),u--,m--;else if(s[h]===a[m])l[m]=bt(i[h],r[m]),vt(t,l[m+1],i[h]),h++,m--;else if(s[u]===a[p])l[p]=bt(i[u],r[p]),vt(t,i[h],i[u]),u--,p++;else if(void 0===c&&(c=kt(a,p,m),d=kt(s,h,u)),c.has(s[h]))if(c.has(s[u])){const e=d.get(a[p]),n=void 0!==e?i[e]:null;if(null===n){const e=vt(t,i[h]);bt(e,r[p]),l[p]=e}else l[p]=bt(n,r[p]),vt(t,i[h],n),i[e]=null;p++}else wt(i[u]),u--;else wt(i[h]),h++;for(;p<=m;){const e=vt(t,l[m+1]);bt(e,r[p]),l[p++]=e}for(;h<=u;){const t=i[h++];null!==t&&wt(t)}return this.ut=a,xt(t,l),W}}),At=t=>!!t&&"none"!==t.action; + */const{I:gt}=rt,_t=t=>t,yt=()=>document.createComment(""),vt=(t,e,n)=>{const o=t._$AA.parentNode,i=void 0===e?t._$AB:e._$AA;if(void 0===n){const e=o.insertBefore(yt(),i),r=o.insertBefore(yt(),i);n=new gt(e,r,t,t.options)}else{const e=n._$AB.nextSibling,r=n._$AM,a=r!==t;if(a){let e;n._$AQ?.(t),n._$AM=t,void 0!==n._$AP&&(e=t._$AU)!==r._$AU&&n._$AP(e)}if(e!==i||a){let t=n._$AA;for(;t!==e;){const e=_t(t).nextSibling;_t(o).insertBefore(t,i),t=e}}}return n},bt=(t,e,n=t)=>(t._$AI(e,n),t),$t={},xt=(t,e=$t)=>t._$AH=e,wt=t=>{t._$AR(),t._$AA.remove()},kt=(t,e,n)=>{const o=new Map;for(let i=e;i<=n;i++)o.set(t[i],i);return o},Mt=mt(class extends ft{constructor(t){if(super(t),t.type!==ht)throw Error("repeat() can only be used in text expressions")}dt(t,e,n){let o;void 0===n?n=e:void 0!==e&&(o=e);const i=[],r=[];let a=0;for(const s of t)i[a]=o?o(s,a):a,r[a]=n(s,a),a++;return{values:r,keys:i}}render(t,e,n){return this.dt(t,e,n).values}update(t,[e,n,o]){const i=(t=>t._$AH)(t),{values:r,keys:a}=this.dt(e,n,o);if(!Array.isArray(i))return this.ut=a,r;const s=this.ut??=[],l=[];let c,d,h=0,u=i.length-1,p=0,m=r.length-1;for(;h<=u&&p<=m;)if(null===i[h])h++;else if(null===i[u])u--;else if(s[h]===a[p])l[p]=bt(i[h],r[p]),h++,p++;else if(s[u]===a[m])l[m]=bt(i[u],r[m]),u--,m--;else if(s[h]===a[m])l[m]=bt(i[h],r[m]),vt(t,l[m+1],i[h]),h++,m--;else if(s[u]===a[p])l[p]=bt(i[u],r[p]),vt(t,i[h],i[u]),u--,p++;else if(void 0===c&&(c=kt(a,p,m),d=kt(s,h,u)),c.has(s[h]))if(c.has(s[u])){const e=d.get(a[p]),n=void 0!==e?i[e]:null;if(null===n){const e=vt(t,i[h]);bt(e,r[p]),l[p]=e}else l[p]=bt(n,r[p]),vt(t,i[h],n),i[e]=null;p++}else wt(i[u]),u--;else wt(i[h]),h++;for(;p<=m;){const e=vt(t,l[m+1]);bt(e,r[p]),l[p++]=e}for(;h<=u;){const t=i[h++];null!==t&&wt(t)}return this.ut=a,xt(t,l),Z}}),At=t=>!!t&&"none"!==t.action; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function Ct(t,e){let n,o,i=0,r=0,a=!1,s=!1;const l=n=>{const o=e(),i="tap"===n?o.tap_action:"hold"===n?o.hold_action:o.double_tap_action;At(i)&&t.dispatchEvent(new CustomEvent("hass-action",{bubbles:!0,composed:!0,detail:{config:o,action:n}}))},c=()=>{void 0!==n&&clearTimeout(n),n=void 0},d=t=>{const o=t;o.button>0||(a=!0,s=!1,i=o.clientX,r=o.clientY,c(),At(e().hold_action)&&(n=setTimeout(()=>{n=void 0,s=!0,l("hold")},500)))},h=t=>{if(!a)return;const e=t;Math.hypot(e.clientX-i,e.clientY-r)>10&&(c(),a=!1)},u=()=>{c(),a=!1},p=()=>{const t=a;c(),a=!1,t&&!s?At(e().double_tap_action)?void 0!==o?(clearTimeout(o),o=void 0,l("double_tap")):o=setTimeout(()=>{o=void 0,l("tap")},250):l("tap"):s=!1},m=t=>{const e=t;e.repeat||"Enter"!==e.key&&" "!==e.key||(" "===e.key&&e.preventDefault(),l("tap"))},f=t=>{At(e().hold_action)&&t.preventDefault()};return t.addEventListener("pointerdown",d),t.addEventListener("pointermove",h),t.addEventListener("pointerup",p),t.addEventListener("pointercancel",u),t.addEventListener("pointerleave",u),t.addEventListener("keydown",m),t.addEventListener("contextmenu",f),()=>{c(),void 0!==o&&clearTimeout(o),o=void 0,t.removeEventListener("pointerdown",d),t.removeEventListener("pointermove",h),t.removeEventListener("pointerup",p),t.removeEventListener("pointercancel",u),t.removeEventListener("pointerleave",u),t.removeEventListener("keydown",m),t.removeEventListener("contextmenu",f)}}const St={primary:{variable:"--primary-color",fallback:"#2f6fe4"},green:{variable:"--success-color",fallback:"#1fae7a"},amber:{variable:"--warning-color",fallback:"#f59e0b"},red:{variable:"--error-color",fallback:"#ef3b5a"},blue:{variable:"--info-color",fallback:"#2f6fe4"},purple:{variable:"--purple-color",fallback:"#8b6cff"},grey:{variable:"--grey-color",fallback:"#8e919a"}};function Et(t){if(Object.prototype.hasOwnProperty.call(St,t)){const{variable:e,fallback:n}=St[t];return`var(${e}, ${n})`}return t}const Ot=new Set(["amber"]);function Tt(t){if(Object.prototype.hasOwnProperty.call(St,t))return Ot.has(t)?"dark":"light";const e=function(t){const e=t.trim().toLowerCase(),n=/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(e);if(n){const t=n[1].length<=4?[...n[1]].map(t=>t+t).join(""):n[1],[e,o,i]=[0,2,4].map(e=>parseInt(t.slice(e,e+2),16));return[e,o,i,8===t.length?parseInt(t.slice(6,8),16)/255:1]}const o=/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)\s*(?:[,/]\s*([\d.]+)(%?)\s*)?\)$/.exec(e);if(o){const[t,e,n]=[o[1],o[2],o[3]].map(t=>Math.min(255,Number(t))),i=void 0===o[4]?1:Number(o[4])/(o[5]?100:1);return[t,e,n,Math.min(1,i)]}}(t);return e?e[3]<.5?"theme":function([t,e,n]){const o=t=>{const e=t/255;return e<=.03928?e/12.92:((e+.055)/1.055)**2.4};return.2126*o(t)+.7152*o(e)+.0722*o(n)}([e[0],e[1],e[2]])>.4?"dark":"light":"light"}function Lt(t,e){let n=e[0];for(const o of e){if(!(o.from<=t))break;n=o}return n}const Nt={battery:[{from:0,color:"red",label:"Low"},{from:20,color:"amber"},{from:50,color:"green"}],usage:[{from:0,color:"green"},{from:60,color:"amber"},{from:85,color:"red",label:"High"}],temperature:[{from:-50,color:"blue",label:"Cold"},{from:16,color:"green"},{from:24,color:"amber"},{from:28,color:"red",label:"Hot"}],none:void 0},Ut=["label","area","floor","device_class","domain","entity"];function jt(t,e){if(null==t)return;if("object"!=typeof t||Array.isArray(t))throw new Error(`"${e}" must list what to match, such as "area" or "device_class"`);const n="include"===e?Ut.filter(t=>"entity"!==t):Ut,o={};for(const[i,r]of Object.entries(t)){if(!n.includes(i))throw new Error(`"${e}" can't match on "${i}". Use: ${n.join(", ")}`);const t=(Array.isArray(r)?r:[r]).filter(t=>null!=t&&""!==t);if(t.some(t=>"string"!=typeof t))throw new Error(`"${e}.${i}" must be text or a list of text`);t.length&&(o[i]=t)}return Object.keys(o).length?o:void 0}function zt(t){const e=t.state;return"unavailable"===e||"unknown"===e||""!==e.trim()&&Number.isFinite(Number(e))}function Pt(t,e){const n=t.entity_id,o=e.entities?.[n],i=o?.device_id?e.devices?.[o.device_id]:void 0,r=o?.area_id??i?.area_id??void 0,a=t.attributes?.device_class;return{label:[...o?.labels??[],...i?.labels??[]],area:r,floor:r?e.areas?.[r]?.floor_id??void 0:void 0,device_class:"string"==typeof a?a:void 0,domain:n.slice(0,n.indexOf(".")),entity:n}}function Ht(t,e,n){const o=t[e],i=n[e];return Array.isArray(i)?i.some(t=>o.includes(t)):void 0!==i&&o.includes(i)}function Ft(t,e){return Object.keys(t).every(n=>Ht(t,n,e))}function Dt(t,e){return!!t&&Object.keys(t).some(n=>Ht(t,n,e))}const Rt=new WeakMap;const Vt=["bar","thin","segmented","tank","ring","needle","arc","line","column","area"],Bt=[{from:-1/0,color:"primary"}],It=["none","ascending","descending"];function Wt(t){if("number"==typeof t)return Number.isFinite(t)?t:void 0;if("string"==typeof t&&""!==t.trim()){const e=Number(t);return Number.isFinite(e)?e:void 0}}function Zt(t,e){if(null==t||""===t)return;const n=Wt(t);if(void 0!==n)return n;if("string"==typeof t)return t;throw new Error(`"${e}" must be a number or an entity id`)}function qt(t,e,n,o=1/0){if(null==t||""===t)return;const i=Wt(t);if(void 0===i||!Number.isInteger(i)||io){throw new Error(`"${e}" must be a whole number ${o===1/0?`of at least ${n}`:`from ${n} to ${o}`}`)}return i}function Yt(t){if(null==t)return;if(!Array.isArray(t))throw new Error('"severity" must be a list of bands');if(0===t.length)return;const e=t.map((t,e)=>{let n;try{n=Zt(t?.from,"from")}catch{n=void 0}if(void 0===n)throw new Error(`Severity band ${e+1}: "from" must be a number or an entity id`);if("string"!=typeof t.color||!t.color)throw new Error(`Severity band ${e+1}: "color" is required`);return{...t,from:n}});return e.every(t=>"number"==typeof t.from)?e.sort((t,e)=>t.from-e.from):e}function Gt(t,e,n){if(null==t)return{action:e};if("object"!=typeof t||"string"!=typeof t.action)throw new Error(`"${n}" must have an "action"`);return t}function Xt(t,e){return void 0!==t?t:e}function Jt(t,e,n){const o="string"==typeof t?{entity:t}:t;if(!o||"object"!=typeof o||"string"!=typeof o.entity||!o.entity)throw new Error(`Entity ${n+1} needs an "entity" id`);if(void 0!==o.attribute&&null!==o.attribute&&"string"!=typeof o.attribute)throw new Error(`Entity ${n+1}: "attribute" must be an attribute name`);const i=Xt(Zt(o.min,"min"),Zt(e.min,"min"))??0,r=Xt(Zt(o.max,"max"),Zt(e.max,"max"))??100;if("number"==typeof i&&"number"==typeof r&&i>=r)throw new Error(`"max" (${r}) must be greater than "min" (${i})`);const a={...o,entity:o.entity,min:i,max:r,severity:Yt(o.severity)??Yt(e.severity)??Bt,tap_action:Gt(Xt(o.tap_action,e.tap_action),"more-info","tap_action"),hold_action:Gt(Xt(o.hold_action,e.hold_action),"none","hold_action"),double_tap_action:Gt(Xt(o.double_tap_action,e.double_tap_action),"none","double_tap_action")},s=Xt(o.name,e.name),l=Xt(o.icon,e.icon),c=Xt(o.unit,e.unit),d=Xt(Zt(o.target,"target"),Zt(e.target,"target")),h=Xt(qt(o.decimals,"decimals",0,20),qt(e.decimals,"decimals",0,20));return void 0!==s&&(a.name=s),void 0!==l&&(a.icon=l),void 0!==c&&(a.unit=c),void 0!==d&&(a.target=d),void 0!==h&&(a.decimals=h),o.attribute||delete a.attribute,a} + */function Et(t,e){let n,o,i=0,r=0,a=!1,s=!1;const l=n=>{const o=e(),i="tap"===n?o.tap_action:"hold"===n?o.hold_action:o.double_tap_action;At(i)&&t.dispatchEvent(new CustomEvent("hass-action",{bubbles:!0,composed:!0,detail:{config:o,action:n}}))},c=()=>{void 0!==n&&clearTimeout(n),n=void 0},d=t=>{const o=t;o.button>0||(a=!0,s=!1,i=o.clientX,r=o.clientY,c(),At(e().hold_action)&&(n=setTimeout(()=>{n=void 0,s=!0,l("hold")},500)))},h=t=>{if(!a)return;const e=t;Math.hypot(e.clientX-i,e.clientY-r)>10&&(c(),a=!1)},u=()=>{c(),a=!1},p=()=>{const t=a;c(),a=!1,t&&!s?At(e().double_tap_action)?void 0!==o?(clearTimeout(o),o=void 0,l("double_tap")):o=setTimeout(()=>{o=void 0,l("tap")},250):l("tap"):s=!1},m=t=>{const e=t;e.repeat||"Enter"!==e.key&&" "!==e.key||(" "===e.key&&e.preventDefault(),l("tap"))},f=t=>{At(e().hold_action)&&t.preventDefault()};return t.addEventListener("pointerdown",d),t.addEventListener("pointermove",h),t.addEventListener("pointerup",p),t.addEventListener("pointercancel",u),t.addEventListener("pointerleave",u),t.addEventListener("keydown",m),t.addEventListener("contextmenu",f),()=>{c(),void 0!==o&&clearTimeout(o),o=void 0,t.removeEventListener("pointerdown",d),t.removeEventListener("pointermove",h),t.removeEventListener("pointerup",p),t.removeEventListener("pointercancel",u),t.removeEventListener("pointerleave",u),t.removeEventListener("keydown",m),t.removeEventListener("contextmenu",f)}}const Ct={primary:{variable:"--primary-color",fallback:"#2f6fe4"},green:{variable:"--success-color",fallback:"#1fae7a"},amber:{variable:"--warning-color",fallback:"#f59e0b"},red:{variable:"--error-color",fallback:"#ef3b5a"},blue:{variable:"--info-color",fallback:"#2f6fe4"},purple:{variable:"--purple-color",fallback:"#8b6cff"},grey:{variable:"--grey-color",fallback:"#8e919a"}};function St(t){if(Object.prototype.hasOwnProperty.call(Ct,t)){const{variable:e,fallback:n}=Ct[t];return`var(${e}, ${n})`}return t}const Ot=new Set(["amber"]);function Lt(t){if(Object.prototype.hasOwnProperty.call(Ct,t))return Ot.has(t)?"dark":"light";const e=function(t){const e=t.trim().toLowerCase(),n=/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(e);if(n){const t=n[1].length<=4?[...n[1]].map(t=>t+t).join(""):n[1],[e,o,i]=[0,2,4].map(e=>parseInt(t.slice(e,e+2),16));return[e,o,i,8===t.length?parseInt(t.slice(6,8),16)/255:1]}const o=/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)\s*(?:[,/]\s*([\d.]+)(%?)\s*)?\)$/.exec(e);if(o){const[t,e,n]=[o[1],o[2],o[3]].map(t=>Math.min(255,Number(t))),i=void 0===o[4]?1:Number(o[4])/(o[5]?100:1);return[t,e,n,Math.min(1,i)]}}(t);return e?e[3]<.5?"theme":function([t,e,n]){const o=t=>{const e=t/255;return e<=.03928?e/12.92:((e+.055)/1.055)**2.4};return.2126*o(t)+.7152*o(e)+.0722*o(n)}([e[0],e[1],e[2]])>.4?"dark":"light":"light"}function Tt(t,e){let n=e[0];for(const o of e){if(!(o.from<=t))break;n=o}return n}const Nt={battery:[{from:0,color:"red",label:"Low"},{from:20,color:"amber"},{from:50,color:"green"}],usage:[{from:0,color:"green"},{from:60,color:"amber"},{from:85,color:"red",label:"High"}],temperature:[{from:-50,color:"blue",label:"Cold"},{from:16,color:"green"},{from:24,color:"amber"},{from:28,color:"red",label:"Hot"}],none:void 0},jt=["label","area","floor","device_class","domain","entity"];function Ut(t,e){if(null==t)return;if("object"!=typeof t||Array.isArray(t))throw new Error(`"${e}" must list what to match, such as "area" or "device_class"`);const n="include"===e?jt.filter(t=>"entity"!==t):jt,o={};for(const[i,r]of Object.entries(t)){if(!n.includes(i))throw new Error(`"${e}" can't match on "${i}". Use: ${n.join(", ")}`);const t=(Array.isArray(r)?r:[r]).filter(t=>null!=t&&""!==t);if(t.some(t=>"string"!=typeof t))throw new Error(`"${e}.${i}" must be text or a list of text`);t.length&&(o[i]=t)}return Object.keys(o).length?o:void 0}function zt(t){const e=t.state;return"unavailable"===e||"unknown"===e||""!==e.trim()&&Number.isFinite(Number(e))}function Pt(t,e){const n=t.entity_id,o=e.entities?.[n],i=o?.device_id?e.devices?.[o.device_id]:void 0,r=o?.area_id??i?.area_id??void 0,a=t.attributes?.device_class;return{label:[...o?.labels??[],...i?.labels??[]],area:r,floor:r?e.areas?.[r]?.floor_id??void 0:void 0,device_class:"string"==typeof a?a:void 0,domain:n.slice(0,n.indexOf(".")),entity:n}}function Ht(t,e,n){const o=t[e],i=n[e];return Array.isArray(i)?i.some(t=>o.includes(t)):void 0!==i&&o.includes(i)}function Ft(t,e){return Object.keys(t).every(n=>Ht(t,n,e))}function Dt(t,e){return!!t&&Object.keys(t).some(n=>Ht(t,n,e))}const Vt=new WeakMap;const Rt=["bar","thin","segmented","tank","ring","needle","arc","line","column","area","combined"],Bt=[{from:-1/0,color:"primary"}],It=["none","ascending","descending"];function Zt(t){if("number"==typeof t)return Number.isFinite(t)?t:void 0;if("string"==typeof t&&""!==t.trim()){const e=Number(t);return Number.isFinite(e)?e:void 0}}function Wt(t,e){if(null==t||""===t)return;const n=Zt(t);if(void 0!==n)return n;if("string"==typeof t)return t;throw new Error(`"${e}" must be a number or an entity id`)}function qt(t,e,n,o=1/0){if(null==t||""===t)return;const i=Zt(t);if(void 0===i||!Number.isInteger(i)||io){throw new Error(`"${e}" must be a whole number ${o===1/0?`of at least ${n}`:`from ${n} to ${o}`}`)}return i}function Yt(t){if(null==t)return;if(!Array.isArray(t))throw new Error('"severity" must be a list of bands');if(0===t.length)return;const e=t.map((t,e)=>{let n;try{n=Wt(t?.from,"from")}catch{n=void 0}if(void 0===n)throw new Error(`Severity band ${e+1}: "from" must be a number or an entity id`);if("string"!=typeof t.color||!t.color)throw new Error(`Severity band ${e+1}: "color" is required`);return{...t,from:n}});return e.every(t=>"number"==typeof t.from)?e.sort((t,e)=>t.from-e.from):e}function Gt(t,e,n){if(null==t)return{action:e};if("object"!=typeof t||"string"!=typeof t.action)throw new Error(`"${n}" must have an "action"`);return t}function Xt(t,e){return void 0!==t?t:e}function Jt(t,e,n){const o="string"==typeof t?{entity:t}:t;if(!o||"object"!=typeof o||"string"!=typeof o.entity||!o.entity)throw new Error(`Entity ${n+1} needs an "entity" id`);if(void 0!==o.attribute&&null!==o.attribute&&"string"!=typeof o.attribute)throw new Error(`Entity ${n+1}: "attribute" must be an attribute name`);const i=Xt(Wt(o.min,"min"),Wt(e.min,"min"))??0,r=Xt(Wt(o.max,"max"),Wt(e.max,"max"))??100;if("number"==typeof i&&"number"==typeof r&&i>=r)throw new Error(`"max" (${r}) must be greater than "min" (${i})`);const a={...o,entity:o.entity,min:i,max:r,severity:Yt(o.severity)??Yt(e.severity)??Bt,tap_action:Gt(Xt(o.tap_action,e.tap_action),"more-info","tap_action"),hold_action:Gt(Xt(o.hold_action,e.hold_action),"none","hold_action"),double_tap_action:Gt(Xt(o.double_tap_action,e.double_tap_action),"none","double_tap_action")},s=Xt(o.name,e.name),l=Xt(o.icon,e.icon),c=Xt(o.unit,e.unit),d=Xt(Wt(o.target,"target"),Wt(e.target,"target")),h=Xt(qt(o.decimals,"decimals",0,20),qt(e.decimals,"decimals",0,20));return void 0!==s&&(a.name=s),void 0!==l&&(a.icon=l),void 0!==c&&(a.unit=c),void 0!==d&&(a.target=d),void 0!==h&&(a.decimals=h),o.attribute||delete a.attribute,a} /** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt&&t.type!==pt)throw Error("The `live` directive is not allowed on child or event bindings");if(!(t=>void 0===t.strings)(t))throw Error("`live` bindings can only contain a single expression")}render(t){return t}update(t,[e]){if(e===W||e===Z)return e;const n=t.element,o=t.name;if(t.type===ut){if(e===n[o])return W}else if(t.type===pt){if(!!e===n.hasAttribute(o))return W}else if(t.type===dt&&n.getAttribute(o)===e+"")return W;return xt(t),e}}),Qt={en:{entity_not_found:"Entity not found",unavailable:"Unavailable",no_entities:"Add an entity in the editor to get started.",no_matches:"No entities match right now.",none_available:"None of these entities are available.",editor_section_entities:"Entities",editor_section_style:"Style",editor_section_chart:"Chart",editor_group_bars:"Bars",editor_group_gauges:"Gauges",editor_group_history:"History charts",editor_group_totals:"Parts of a total",editor_group_compare:"Comparisons",editor_group_distribution:"Distributions",editor_period_last:"Show the last",editor_period_unit:"Unit",editor_period_unit_hour:"Hours",editor_period_unit_day:"Days",editor_period_unit_week:"Weeks",editor_period_unit_month:"Months",editor_source:"Readings from",editor_source_history:"History (every change)",editor_source_statistics:"Long-term statistics",editor_curve:"Line shape",editor_curve_smooth:"Smooth",editor_curve_straight:"Straight",editor_curve_step:"Steps",editor_color_by:"Colour",editor_color_by_series:"One colour per entity",editor_color_by_bands:"By colour band",editor_labels:"Show values on the points",editor_series_color:"Line colour",editor_dash:"Dashed",editor_section_limits:"Limits",editor_section_colours:"Colours",editor_section_display:"Display",editor_section_actions:"Actions",editor_title:"Title",editor_style_bar:"Bar",editor_style_thin:"Thin",editor_style_segmented:"Segmented",editor_style_tank:"Tank",editor_style_ring:"Ring",editor_style_needle:"Needle",editor_style_arc:"Arc",editor_show_name:"Show name",editor_show_value:"Show value",editor_show_icon:"Show icon",editor_show_target:"Show target",editor_show_legend:"Show legend",editor_columns:"Columns",editor_sort:"Sort",editor_sort_none:"As listed",editor_sort_ascending:"Lowest first",editor_sort_descending:"Highest first",editor_decimals:"Decimals",editor_unit:"Unit",editor_animate:"Animate",editor_hide_unavailable:"Hide unavailable entities",editor_limit:"Show at most",editor_include_heading:"Also show every entity that matches",editor_include_help:"New devices appear without editing the card. Pick several of one kind to match any of them; different kinds must all match.",editor_exclude_heading:"Leave out",editor_exclude_help:"Matched entities are left out if they match any of these.",editor_rule_device_class:"Device class",editor_rule_area:"Areas",editor_rule_floor:"Floors",editor_rule_label:"Labels",editor_rule_domain:"Domains",editor_rule_entity:"Entities",editor_tap_action:"Tap action",editor_hold_action:"Hold action",editor_double_tap_action:"Double tap action",editor_attribute:"Attribute (instead of the state)",editor_name:"Name",editor_icon:"Icon",editor_min:"Minimum",editor_max:"Maximum",editor_target:"Target",editor_none:"None",editor_card_setting:"card setting",editor_limit_default:"Default ({value})",editor_limit_number:"Number",editor_limit_entity:"Entity",editor_preset:"Preset",editor_preset_battery:"Battery (low is bad)",editor_preset_usage:"Usage (high is bad)",editor_preset_temperature:"Temperature",editor_preset_none:"None",editor_preset_custom:"Custom",editor_band_from:"From",editor_band_from_entity:"Start from an entity",editor_band_from_number:"Start from a number",editor_band_from_entity_label:"Starts at this entity",editor_band_color:"Colour",editor_band_custom_color:"CSS colour",editor_band_label:"Label",editor_band_icon:"Icon",editor_color_icon:"Colour icons to match their band",editor_color_primary:"Primary",editor_color_green:"Green",editor_color_amber:"Amber",editor_color_red:"Red",editor_color_blue:"Blue",editor_color_purple:"Purple",editor_color_grey:"Grey",editor_color_custom:"Custom…",editor_add_band:"Add band",editor_remove_band:"Remove band",editor_add_entity:"Add entity",editor_move_up:"Move up",editor_move_down:"Move down",editor_remove_entity:"Remove entity",editor_show_options:"Show options",editor_hide_options:"Hide options",editor_not_found:"{entity} (not found)",editor_severity:"Colours"}};function te(t,e){Qt[t]={...Qt[t],...e}}function ee(t){return(t?.locale?.language??t?.language??"en").split("-")[0]}function ne(t,e,n){const o=ee(t),i=Qt[o]?.[e]??Qt.en[e]??e;return n?i.replace(/\{(\w+)\}/g,(t,e)=>e in n?String(n[e]):t):i}function oe(t){return null==t||""===t}function ie(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function re(t,e,n){const[o,...i]=e,r=function(t,e){return Array.isArray(t)?[...t]:ie(t)?{...t}:"number"==typeof e?[]:{}}(t,o),a=r,s=i.length?re(a[o],i,n):n,l=i.length>0&&ie(s)&&0===Object.keys(s).length;return oe(s)?Array.isArray(r)&&"number"==typeof o?r.splice(o,1):delete a[o]:l&&ie(r)?delete a[o]:a[o]=s,r}function ae(t,e,n){return 0===e.length||oe(n)&&void 0===function(t,e){let n=t;for(const o of e){if("object"!=typeof n||null===n)return;n=n[o]}return n}(t,e)?t:re(t,e,n)}function se(t,e){const n=t;return{width:n.line_width??e.line_width??2.5,dots:n.dots??!0===e.dots,onTop:!0===n.on_top}}function le(t,e){return[...t.filter(t=>!e(t)),...t.filter(e)]}function ce(t){return t.map(([t,e])=>`M${Math.round(100*t)/100},${Math.round(100*e)/100}h0`).join("")}function de(t){return Math.round(10*(t+3.5))/10}function he(t,e){if(void 0!==t&&("number"!=typeof t||!Number.isFinite(t)||t<.5||t>12))throw new Error(`${e} must be a number from 0.5 to 12`)}function ue(t,e){if(void 0!==t&&"boolean"!=typeof t)throw new Error(`${e} must be true or false`)}function pe(t){he(t.line_width,'"line_width"'),ue(t.dots,'"dots"');for(const e of t.entities??[])"object"==typeof e&&(he(e.line_width,`"line_width" of ${e.entity}`),ue(e.dots,`"dots" of ${e.entity}`),ue(e.on_top,`"on_top" of ${e.entity}`))}const me=[{name:"title",path:["title"]}],fe=[{name:"show_name",path:["show","name"],default:!0},{name:"show_value",path:["show","value"],default:!0},{name:"show_icon",path:["show","icon"],default:!0},{name:"show_target",path:["show","target"],default:!0},{name:"show_legend",path:["show","legend"],default:!1},{name:"animate",path:["animate"],default:!0},{name:"hide_unavailable",path:["hide_unavailable"],default:!1}],ge=[{name:"color_icon",path:["color_icon"],default:!1}],ye=[{name:"columns",path:["columns"]},{name:"sort",path:["sort"],default:"none"},{name:"limit",path:["limit"]},{name:"decimals",path:["decimals"]},{name:"unit",path:["unit"]}],_e=[{name:"tap_action",path:["tap_action"],default:{action:"more-info"}},{name:"hold_action",path:["hold_action"],default:{action:"none"}},{name:"double_tap_action",path:["double_tap_action"],default:{action:"none"}}],ve=[{name:"name",path:["name"]},{name:"unit",path:["unit"]},{name:"decimals",path:["decimals"]}],be=[{name:"attribute",path:["attribute"]}],$e=[{name:"series_color",path:["color"]},{name:"curve",path:["curve"]},{name:"line_width",path:["line_width"]},{name:"dash",path:["dash"],default:!1},{name:"on_top",path:["on_top"],default:!1}],xe={number:{min:.5,max:12,step:.5,mode:"box",unit_of_measurement:"px"}},we=new Map;function ke(t){let e=we.get(t);return e||(e=[...$e,{name:"dots",path:["dots"],default:t}],we.set(t,e)),e}const Me=_e.map(({name:t,path:e})=>({name:t,path:e})),Ae=[{name:"title",selector:{text:{}}}],Ce=_e.map(({name:t})=>({name:t,selector:{ui_action:{}}})),Se=[{type:"grid",name:"",schema:[{name:"name",selector:{text:{}}},{name:"unit",selector:{text:{}}},{name:"decimals",selector:{number:{min:0,max:20,mode:"box"}}}]}],Ee=new Map;let Oe;function Te(t){const e=ee(t);if(Oe?.language!==e){const n=e=>ne(t,e);Oe={language:e,schema:[{type:"grid",name:"",schema:[{name:"series_color",selector:{text:{}}},{name:"curve",selector:{select:{mode:"dropdown",options:["smooth","straight","step"].map(t=>({value:t,label:n(`editor_curve_${t}`)}))}}}]},{type:"grid",name:"",schema:[{name:"line_width",selector:xe},{name:"dash",selector:{boolean:{}}},{name:"dots",selector:{boolean:{}}},{name:"on_top",selector:{boolean:{}}}]}]}}return Oe.schema}function Le(t){return[{type:"grid",name:"",schema:[{name:"columns",selector:{number:{min:1,max:6,mode:"box"}}},{name:"sort",selector:{select:{mode:"dropdown",options:["none","ascending","descending"].map(e=>({value:e,label:ne(t,`editor_sort_${e}`)}))}}},{name:"limit",selector:{number:{min:1,mode:"box"}}},{name:"decimals",selector:{number:{min:0,max:20,mode:"box"}}},{name:"unit",selector:{text:{}}}]}]}const Ne={include:["device_class","area","floor","label","domain"],exclude:["entity","device_class","area","floor","label","domain"]};function Ue(t,e){const n=t=>({select:{multiple:!0,custom_value:!0,mode:"dropdown",options:t}});switch(t){case"device_class":return n(e.deviceClasses);case"domain":return n(e.domains);case"entity":return{entity:{multiple:!0}};default:return{[t]:{multiple:!0}}}}const je=new Map;function ze(t,e){const n=function(t){const e=new Set,n=new Set;for(const o of Object.values(t?.states??{})){const t=o.attributes?.device_class;"string"==typeof t&&t&&e.add(t),n.add(o.entity_id.slice(0,o.entity_id.indexOf(".")))}return{deviceClasses:[...e].sort(),domains:[...n].sort()}}(e),o=`${n.deviceClasses.join()}|${n.domains.join()}`,i=je.get(t);if(i?.key===o)return i.schema;const r=Ne[t].map(e=>({name:`${t}_${e}`,selector:Ue(e,n)}));return je.set(t,{key:o,schema:r}),r}let Pe;function He(t,e){let n=t;for(const o of e){if("object"!=typeof n||null===n)return;n=n[o]}return n}function Fe(t,e){if(t===e)return!0;if("object"!=typeof t||"object"!=typeof e||null===t||null===e)return!1;if(Array.isArray(t)!==Array.isArray(e))return!1;const n=Object.keys(t),o=Object.keys(e);return n.length===o.length&&n.every(n=>Fe(t[n],e[n]))}function De(t,e){const n={};for(const o of e){const e=He(t,o.path)??o.default;void 0!==e&&(n[o.name]=e)}return n}function Re(t,e,n){const o=De(t,e);let i=t;for(const r of e){const t=n[r.name];Fe(o[r.name],t)||(i=ae(i,r.path,void 0!==r.default&&Fe(t,r.default)?void 0:t))}return i}const Ve="var(--divider-color, rgba(127, 127, 127, 0.3))",Be="var(--primary-color, #03a9f4)",Ie="var(--secondary-text-color, #727272)";function We(t,e,n,o){const i=(o-90)*Math.PI/180;return[(t+n*Math.cos(i)).toFixed(2),(e+n*Math.sin(i)).toFixed(2)]}function Ze(t,e,n,o){return We(t,e,n,o).join(" ")}function qe(t,e,n,o,i){const r=i-o>180?1:0;return`M ${Ze(t,e,n,o)} A ${n} ${n} 0 ${r} 1 ${Ze(t,e,n,i)}`}function Ye(t){return B`
+ `}function Ge(t){let e=1/0,n=-1/0;for(const o of t)for(const t of o)for(const o of[t.v,t.min,t.max])"number"==typeof o&&(on&&(n=o));return e===1/0?void 0:[e,n]}function Xe(t,e){const[n,o]=t,[i,r]=e,a=o===n?0:(r-i)/(o-n);return t=>i+(t-n)*a}const Je=["outside","inside"],Ke=!0,Qe=!0,tn="outside",en=!0,nn=!1,on=t=>"number"==typeof t&&Number.isFinite(t);function rn(t){const e=t;for(const n of["x_axis","y_axis"])if(void 0!==e[n]&&"boolean"!=typeof e[n])throw new Error(`"${n}" must be true or false`);if(void 0!==e.axis_labels&&!Je.includes(e.axis_labels))throw new Error(`"axis_labels" must be one of: ${Je.join(", ")}`);if(void 0!==e.gridlines){const t=e.gridlines;if("object"!=typeof t||null===t||Array.isArray(t))throw new Error('"gridlines" must have "horizontal" and "vertical" (true or false)');for(const e of["horizontal","vertical"])if(void 0!==t[e]&&"boolean"!=typeof t[e])throw new Error(`"gridlines.${e}" must be true or false`)}for(const n of["y_min","y_max"])if(void 0!==e[n]&&!on(e[n]))throw new Error(`"${n}" must be a number`);if(on(e.y_min)&&on(e.y_max)&&e.y_min>=e.y_max)throw new Error('"y_min" must be below "y_max"')}function an(t){const e=t,n=e.gridlines??{};return{x:e.x_axis??Ke,y:e.y_axis??Qe,labels:e.axis_labels??tn,horizontal:n.horizontal??en,vertical:n.vertical??nn,min:on(e.y_min)?e.y_min:void 0,max:on(e.y_max)?e.y_max:void 0}}function sn(t){return Math.max(0,-Math.floor(Math.log10(t)+1e-9))}const ln=t=>Number(t.toPrecision(12));function cn(t,e,n){let[o,i]=function([t,e],n=.08){if(t===e)return[t-1,e+1];const o=(e-t)*n;return[t-o,e+o]}(t??[0,1]);void 0!==e.min&&(o=e.min),void 0!==e.max&&(i=e.max),i<=o&&(void 0!==e.min?i=o+Math.max(1,.1*Math.abs(o)):o=i-Math.max(1,.1*Math.abs(i)));const r=function(t,e){if(!(t>0&&Number.isFinite(t)))return 1;const n=t/Math.max(1,e),o=10**Math.floor(Math.log10(n));for(const i of[1,2,5])if(i*o>=n*(1-1e-9))return i*o;return 10*o}(i-o,n);void 0===e.min&&(o=ln(Math.floor(o/r+1e-9)*r)),void 0===e.max&&(i=ln(Math.ceil(i/r-1e-9)*r));const a=[];for(let s=Math.ceil(o/r-1e-9);s*r<=i+1e-9*r;s++)a.push(ln(s*r));return{domain:[o,i],ticks:a,decimals:sn(r)}}const dn=6e4,hn=36e5,un=864e5,pn=[...[1,5,10,15,30].map(t=>({unit:"minute",n:t,ms:t*dn})),...[1,2,3,6,12].map(t=>({unit:"hour",n:t,ms:t*hn})),...[1,2,7].map(t=>({unit:"day",n:t,ms:t*un})),...[1,2,3,6].map(t=>({unit:"month",n:t,ms:30.44*t*un})),...[1,2,5,10,20,50,100].map(t=>({unit:"year",n:t,ms:365.25*t*un}))];const mn=t=>-new Date(t).getTimezoneOffset()*dn;function fn(t){if(!t)return mn;let e;try{e=new Intl.DateTimeFormat("en-US",{timeZone:t,hourCycle:"h23",year:"numeric",month:"numeric",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric"})}catch{return mn}return t=>{const n={};for(const o of e.formatToParts(t))n[o.type]=Number(o.value);return Date.UTC(n.year,n.month-1,n.day,n.hour%24,n.minute,n.second)-1e3*Math.floor(t/1e3)}}function gn(t,e){return t-e(t-e(t))}function _n(t,e,n,o){const i=[],r=t.end+e(t.end);for(let a=n,s=0;a<=r&&s<1e3;a=o(a),s++){const n=gn(a,e);n>=t.start&&n<=t.end&&n!==i[i.length-1]&&i.push(n)}return i}function yn(t,e,n=mn){const{unit:o,n:i}=function(t,e){return pn.find(n=>t/n.ms<=Math.max(1,e))??pn[pn.length-1]}(t.end-t.start,e),r=t.start+n(t.start);if("minute"===o||"hour"===o||"day"===o&&7!==i){const e=i*("minute"===o?dn:"hour"===o?hn:un);return{unit:o,ticks:_n(t,n,Math.ceil(r/e)*e,t=>t+e)}}if("day"===o){const e=Math.ceil(r/un);return{unit:o,ticks:_n(t,n,(e+((4-e)%7+7)%7)*un,t=>t+7*un)}}const a=new Date(r);if("month"===o){let e=a.getUTCFullYear(),s=a.getUTCMonth();Date.UTC(e,s){const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth()+i)};return{unit:o,ticks:_n(t,n,Date.UTC(e,s),l)}}let s=a.getUTCFullYear();return Date.UTC(s,0)Date.UTC(new Date(t).getUTCFullYear()+i,0))}}function vn(t){return"server"===t?.locale?.time_zone?t.config?.time_zone:void 0}function bn(t){const e=t?.locale?.time_format;return"12"===e||"24"!==e&&void 0}const $n=new Map;function xn(t,e,n){const o=`${t}|${e}|${JSON.stringify(n)}`;let i=$n.get(o);if(!i){try{i=new Intl.DateTimeFormat(t,{...n,timeZone:e})}catch{i=new Intl.DateTimeFormat(void 0,n)}$n.set(o,i)}return i}function wn(t,e,n=!1){return xn(e?.locale?.language??"en",vn(e),{hour:"numeric",minute:"2-digit",...n?{second:"2-digit"}:{},hour12:bn(e)}).format(t)}function kn(t,e){return xn(e?.locale?.language??"en",vn(e),{weekday:"short",day:"numeric",month:"short",hour:"numeric",minute:"2-digit",hour12:bn(e)}).format(t)}function Mn(t,e,n,o,i){const r=o?.locale?.language??"en",a=vn(o),s=t+(i??fn(a))(t),l=new Date(s),c=s%un===0;switch(e){case"minute":case"hour":return c?xn(r,a,{weekday:"short"}).format(t):wn(t,o);case"day":return n<=7*un?xn(r,a,{weekday:"short"}).format(t):xn(r,a,{day:"numeric",month:"short"}).format(t);case"month":return xn(r,a,0===l.getUTCMonth()?{month:"short",year:"numeric"}:{month:"short"}).format(t);default:return xn(r,a,{year:"numeric"}).format(t)}}function An(t,e){if(t.length<=e)return t;const n=[];let o=[];for(const r of t)null===r.v?(o.length&&n.push(o),n.push([r]),o=[]):o.push(r);o.length&&n.push(o);const i=t.length;return n.flatMap(t=>null===t[0].v?t:function(t,e){if(t.length<=e||e<3)return t;const n=[t[0]],o=(t.length-2)/(e-2);let i=0;for(let r=0;rp&&(p=e,u=n)}n.push(t[u]),i=u}return n.push(t[t.length-1]),n}(t,Math.max(3,Math.round(t.length/i*e))))}const En=36e5,Cn=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],Sn=["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],On=new Map;function Ln(t){let e=On.get(t);return e||(e=new Intl.DateTimeFormat("en-US",{timeZone:t,hourCycle:"h23",year:"numeric",month:"numeric",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",weekday:"short"}),On.set(t,e)),e}function Tn(t,e){const n={};for(const o of Ln(e).formatToParts(new Date(t)))n[o.type]=o.value;return{year:Number(n.year),month:Number(n.month),day:Number(n.day),hour:Number(n.hour)%24,minute:Number(n.minute),second:Number(n.second),weekday:Cn.indexOf(n.weekday)+1}}function Nn(t,e){const n=Tn(t,e);return Date.UTC(n.year,n.month-1,n.day,n.hour,n.minute,n.second)-1e3*Math.floor(t/1e3)}function jn(t,e,n,o=1,i=0,r=0,a=0){const s=Date.UTC(e,n-1,o,i,r,a),l=new Date(s),c=Nn(s-24*En,t),d=Nn(s+24*En,t),h=[s-c,s-d].filter(e=>{const n=Tn(e,t);return n.year===l.getUTCFullYear()&&n.month===l.getUTCMonth()+1&&n.day===l.getUTCDate()&&n.hour===l.getUTCHours()&&n.minute===l.getUTCMinutes()&&n.second===l.getUTCSeconds()});return h.length?Math.min(...h):function(t,e,n,o){for(;e-t>1e3;){const i=1e3*Math.floor((t+e)/2e3);Nn(i,o)===n?t=i:e=i}return e}(s-d,s-c,c,t)}function Un(t,e,n){const o=new Date(Date.UTC(t,e-1,n));return{year:o.getUTCFullYear(),month:o.getUTCMonth()+1,day:o.getUTCDate()}}function zn(t,e,n){const o=Tn(e,n.timeZone);switch(t){case"hour":return e-e%1e3-1e3*(60*o.minute+o.second);case"day":return jn(n.timeZone,o.year,o.month,o.day);case"week":{const t=(o.weekday-n.firstDay+7)%7,e=Un(o.year,o.month,o.day-t);return jn(n.timeZone,e.year,e.month,e.day)}case"month":return jn(n.timeZone,o.year,o.month,1);case"year":return jn(n.timeZone,o.year,1,1)}}function Pn(t,e,n,o){if("hour"===t)return e+n*En;const i=Tn(e,o.timeZone);let{year:r,month:a,day:s}=i;if("day"===t)({year:r,month:a,day:s}=Un(r,a,s+n));else if("week"===t)({year:r,month:a,day:s}=Un(r,a,s+7*n));else{const e=Un(r,a+("year"===t?12*n:n),1),o=Un(e.year,e.month+1,0).day;({year:r,month:a}=e),s=Math.min(s,o)}return jn(o.timeZone,r,a,s,i.hour,i.minute,i.second)}function Hn(t){try{const e=new Intl.Locale(t),n=e.getWeekInfo?.().firstDay??e.weekInfo?.firstDay;return"number"==typeof n&&n>=1&&n<=7?n:1}catch{return 1}}function Fn(t){const e=t?.locale,n=t?.config?.time_zone,o="server"===e?.time_zone&&function(t){if("string"!=typeof t||""===t)return!1;try{return Ln(t),!0}catch{return!1}}(n)?n:(new Intl.DateTimeFormat).resolvedOptions().timeZone||"UTC",i=Sn.indexOf(String(e?.first_weekday??"language"))+1;return{timeZone:o,firstDay:i>0?i:Hn(e?.language??t?.language??"en")}}const Dn=["hour","day","week","month"],Vn=["day","week","month","year"],Rn=["now","end"],Bn={last:24,unit:"hour",offset:0,navigate:!1,until:"now"},In={hour:36e5,day:864e5,week:6048e5};function Zn(t,e,n){const o="string"==typeof t&&""!==t.trim()?Number(t):t;if("number"!=typeof o||!Number.isInteger(o)||o"number"==typeof t&&Number.isFinite(t)?t:null;function no(t,e){return(t??[]).map(t=>{const n="number"==typeof t.start?t.start:Date.parse(t.start);let o;return o="change"===e?eo(t.change):"state"===e?eo(t.state)??eo(t.mean):"min"===e||"max"===e?eo(t[e])??eo(t.mean)??eo(t.state):eo(t.mean)??eo(t.state),{t:n,v:o,min:t.min??null,max:t.max??null}})}function oo(t){const e=(t.end-t.start)/864e5;return e<=2?"5minute":e<=35?"hour":e<=400?"day":"month"}function io(t){return{period:oo(t),types:["mean","min","max","state"],value:"mean"}}function ro(t){return t.attribute?`${t.entity}|${t.attribute}`:t.entity}const ao=["hour","day","week","month"],so=["mean","sum","min","max","first","last","change"];function lo(t){if(void 0!==t.aggregate&&!so.includes(t.aggregate))throw new Error(`"aggregate" must be one of: ${so.join(", ")}`);if(void 0!==t.group_by){if(!ao.includes(t.group_by))throw new Error(`"group_by" must be one of: ${ao.join(", ")}`);return{unit:t.group_by,aggregate:t.aggregate??"mean"}}}function co(t,e,n,o,i=!1){const r="change"===n?function(t){let e=null;return t.map(t=>{if(null===t.v)return null;if(null===e)return e=t.v,0;if(t.v>=e){const n=t.v-e;return e=t.v,n}return e-t.v>.1*Math.abs(e)?(e=t.v,Math.max(0,t.v)):0})}(t):[],a=[];let s=0;for(let l=0;l+1c&&p.push({v:m.v,dt:g-c,reading:!1,carried:!0,up:0});fnull!==t.v);if(0===_.length)continue;const y=_.map(t=>t.v);switch(i&&(u.min=Math.min(...y),u.max=Math.max(...y)),n){case"mean":{const t=_.reduce((t,e)=>t+e.dt,0);u.v=t>0?_.reduce((t,e)=>t+e.v*e.dt,0)/t:y.reduce((t,e)=>t+e,0)/y.length;break}case"min":u.v=Math.min(...y);break;case"max":u.v=Math.max(...y);break;case"first":u.v=y[0];break;case"last":u.v=y[y.length-1];break;case"sum":{const t=_.filter(t=>t.reading&&!t.carried);u.v=t.length?t.reduce((t,e)=>t+e.v,0):null;break}case"change":u.v=_.reduce((t,e)=>t+(e.reading&&!e.carried?e.up??0:0),0)}}return a}const ho={"5minute":3e5,hour:36e5,day:9e7,week:6912e5,month:27648e5},uo={mean:{types:["mean"],value:"mean"},min:{types:["min"],value:"min"},max:{types:["max"],value:"max"},first:{types:["state","mean"],value:"state"},last:{types:["state","mean"],value:"state"},sum:{types:["change"],value:"change"},change:{types:["change"],value:"change"}};const po={"5minute":3e5,hour:36e5,day:864e5,week:864e5,month:864e5};class mo{constructor(t){this.onChange=t,this.shape="",this.loadedFrom=1/0,this.loadedTo=-1/0,this.status="loading",this.data=new Map,this.seen=new Map,this.generation=0}get(t,e,n,o,i={}){const r=i.live??!0,a="statistics"===o?i.statistics??io(n):void 0,s=`${o}|${e.map(ro).join(",")}|${a?JSON.stringify(a):""}`,l=void 0!==this.pausedAt&&Date.now()-this.pausedAt>go,c=void 0!==this.pausedAt&&"statistics"===o&&r;this.pausedAt=void 0;const d=Math.max(6e4,(n.end-n.start)/100),h=n.startthis.loadedTo+d);(s!==this.shape||h||l&&r||c)&&(this.shape=s,this.load(t,e,n,r,a)),"ready"===this.status&&"history"===o&&this.loadedTo===1/0&&this.appendLive(t,e);const u=new Map;for(const[p,m]of this.data)u.set(p,fo(m,n));return{status:this.status,data:u,error:this.error}}pause(){clearTimeout(this.timer),this.timer=void 0,this.pausedAt=Date.now()}dispose(){clearTimeout(this.timer),this.timer=void 0,this.shape="",this.loadedFrom=1/0,this.loadedTo=-1/0,this.generation++}load(t,e,n,o,i){const r=++this.generation;this.status="loading",this.loadedFrom=n.start,this.loadedTo=o?1/0:n.end,clearTimeout(this.timer);const a=i?async function(t,e,n,o=io(n)){const i=new Map;if(!t.callWS||0===e.length)return i;const r=[...new Set(e.map(t=>t.entity))],a=await t.callWS({type:"recorder/statistics_during_period",start_time:new Date(n.start).toISOString(),end_time:new Date(n.end).toISOString(),statistic_ids:r,period:o.period,types:o.types});for(const s of e)i.set(ro(s),no(a?.[s.entity],o.value));return i}(t,e,n,i):async function(t,e,n){const o=new Map;if(!t.callWS||0===e.length)return o;const i={type:"history/history_during_period",start_time:new Date(n.start).toISOString(),end_time:new Date(n.end).toISOString(),significant_changes_only:!1},r=[...new Set(e.filter(t=>!t.attribute).map(t=>t.entity))],a=[...new Set(e.filter(t=>t.attribute).map(t=>t.entity))],s=[];return r.length&&s.push(t.callWS({...i,entity_ids:r,minimal_response:!0,no_attributes:!0}).then(t=>{for(const e of r)o.set(ro({entity:e}),to(t?.[e]))})),a.length&&s.push(t.callWS({...i,entity_ids:a,no_attributes:!1}).then(t=>{for(const n of e.filter(t=>t.attribute))o.set(ro(n),to(t?.[n.entity],n.attribute))})),await Promise.all(s),o}(t,e,n);a.then(n=>{if(r===this.generation){this.data=n,this.status="ready",this.error=void 0,this.seen.clear();for(const n of e)this.seen.set(ro(n),t.states[n.entity]);i&&o&&(this.timer=setTimeout(()=>{this.shape="",this.onChange()},po[i.period])),this.onChange()}},t=>{r===this.generation&&(this.status="error",this.error=t instanceof Error?t.message:String(t?.message??t),this.onChange())})}appendLive(t,e){for(const n of e){const e=ro(n),o=t.states[n.entity];if(!o||this.seen.get(e)===o)continue;this.seen.set(e,o);const i=Date.parse(o.last_updated??o.last_changed??"")||Date.now(),r=this.data.get(e)??[],a=r[r.length-1];a&&i<=a.t||(r.push({t:i,v:Qn(n.attribute?o.attributes?.[n.attribute]:o.state)}),this.data.set(e,r))}}}function fo(t,e){let n=0;for(;nt.t<=e.end),i=t[n-1];return i?[{...i,t:e.start,carried:!0},...o]:o}const go=6e4,_o=new WeakMap;const yo=["smooth","straight","step"],vo=t=>(Math.round(100*t)/100).toString();function bo(t){return t.map(([t,e],n)=>`${n?"L":"M"}${vo(t)},${vo(e)}`).join("")}function $o(t,e){return 0===t.length?"":1===t.length?`M${vo(t[0][0])},${vo(t[0][1])}h0`:"smooth"===e?function(t){const e=t.length;if(e<3)return bo(t);const n=[],o=[];for(let a=0;a9){const r=3/Math.sqrt(n);i[a]=r*t*o[a],i[a+1]=r*e*o[a]}}let r=`M${vo(t[0][0])},${vo(t[0][1])}`;for(let a=0;a"object"==typeof t?t.curve:void 0)];for(const n of e)if(void 0!==n&&!yo.includes(n))throw new Error(`"curve" must be one of: ${yo.join(", ")}`)}function Co(t,e=Date.now(),n={}){const o=qn(t.raw.period),i=t.raw.source??"history",r=Fn(t.hass),a=Gn(o,e,r,o.navigate?Jn(t.host,o):0),s=lo(t.raw),l={start:s?zn(s.unit,a.start,r):a.start,end:a.end},c=t.items.map(t=>({entity:t.entityId,attribute:t.config.attribute})),d=function(t,e){let n=_o.get(t);return n||(n=new mo(e),_o.set(t,n)),n}(t.host,t.requestUpdate),h=s&&"statistics"===i?function(t,e,n,o=!1){const i=e.timeZone===n&&("week"!==t.unit||1===e.firstDay),r="hour"!==t.unit&&i?t.unit:"hour",{types:a,value:s}=uo[t.aggregate];return{period:r,types:o?[...new Set([...a,"min","max"])]:a,value:s}}(s,r,t.hass.config?.time_zone,!0===n.range):void 0,u=h?{start:l.start-ho[h.period],end:l.end}:l,p=d.get(t.hass,c,u,i,{live:a.live,statistics:h}),m=s?function(t,e,n,o,i=1e4){const r=[zn(t,e,o)];let a=1;for(;r[r.length-1]r[r.length-1]?e:r[r.length-1]+En),a++}return 1===r.length&&r.push(Pn(t,r[0],1,o)),r}(s.unit,l.start,l.end,r):[],f=t.raw.curve??"smooth",g=Math.min(l.end,e),_=t.items.map((t,e)=>{const o=t.config;let r=p.data.get(ro(c[e]))??[];const a=r[r.length-1];return s?r="statistics"===i?function(t,e,n,o=1/0,i=!1){const r=[];let a=0;for(let s=0;s+1t+e,0)/h.length;else if("sum"===n||"change"===n)m=h.reduce((t,e)=>t+e,0);else if("min"===n)m=Math.min(...h);else if("max"===n)m=Math.max(...h);else if("last"===n)m=h[h.length-1];else{const e=t.slice(0,a).reverse().find(t=>null!==t.v),n=t.slice(a,d).find(t=>t.carried&&null!==t.v);m=(e??n)?.v??h[0]}const f={t:l,end:c,v:m};i&&null!==m&&(f.min=Math.min(...u),f.max=Math.max(...p)),r.push(f)}return r}(r,m,s.aggregate,g,!0===n.range):co(r,m,n.aggregate?.(t)??s.aggregate,g,!0===n.range):"history"===i&&a&&null!==a.v&&a.t1===t?e:n;function Oo(t,e,n,o,i){const r=(t,e)=>ne(i,t,e);if(t.calendar&&n<2)return r({day:["period_today","period_yesterday"],week:["period_this_week","period_last_week"],month:["period_this_month","period_last_month"],year:["period_this_year","period_last_year"]}[t.calendar][n]);if(!t.calendar&&0===n){const e=t.last;return r({hour:So(e,"period_last_hour","period_last_hours"),day:So(e,"period_last_day","period_last_days"),week:So(e,"period_last_week_rolling","period_last_weeks"),month:So(e,"period_last_month_rolling","period_last_months")}[t.unit],{n:e})}const a={timeZone:o.timeZone},s=Tn(e.start,o.timeZone).year===Tn(Date.now(),o.timeZone).year;let l;"year"===t.calendar?a.year="numeric":"month"===t.calendar?Object.assign(a,{month:"long",year:"numeric"}):(Object.assign(a,{day:"numeric",month:"short"}),s||(a.year="numeric"),"day"===t.calendar&&(a.weekday="short"),t.calendar||"hour"!==t.unit&&"day"!==t.unit||Object.assign(a,{hour:"numeric",minute:"2-digit"}));try{l=new Intl.DateTimeFormat(i?.locale?.language??i?.language??"en",a)}catch{l=new Intl.DateTimeFormat("en",a)}const c=t.calendar?e.end-1:e.end;return"day"===t.calendar||"month"===t.calendar||"year"===t.calendar?l.format(e.start):l.formatRange(e.start,c)}function Lo(t,e,n=Date.now()){const{period:o}=t;if(!o.navigate)return W;const i=Jn(e.host,o),r=t=>n=>{n.stopPropagation(),Kn(e.host,o,t),e.requestUpdate()},a=Oo(o,t.range,t.back,t.zone,e.hass);let s="";if(0!==i){const i=Gn(o,n,t.zone);s=Oo(o,i,i.back,t.zone,e.hass)}const l=t=>B``;return B`
@@ -83,8 +83,8 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt @click=${r(0)} > ${s} - `:Z} -
`}const Lo=r` + `:W} +
`}const To=r` .period-nav { display: flex; align-items: center; @@ -142,16 +142,16 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt border: 1px solid color-mix(in srgb, var(--primary-color) 40%, transparent); white-space: nowrap; } -`;function No(t){!function(t){yo.get(t)?.pause()}(t)}function Uo(t,e){const{show:n}=e.config;return n.name||n.value?B`
+`;function No(t){!function(t){_o.get(t)?.pause()}(t)}function jo(t,e){const{show:n}=e.config;return n.name||n.value?B`
${t.series.map(t=>B`
- ${n.name?B`${t.entity.name}`:Z} - ${n.value?B`${t.entity.display}`:Z} + ${n.name?B`${t.entity.name}`:W} + ${n.value?B`${t.entity.display}`:W}
`)} -
`:Z}function jo(t,e){return"loading"===t.status?B`
${ne(e.hass,"chart_loading")}
`:"error"===t.status?B`
+
`:W}function Uo(t,e){return"loading"===t.status?B`
${ne(e.hass,"chart_loading")}
`:"error"===t.status?B`
${ne(e.hass,"chart_error",{error:t.error??""})}
`:t.series.every(t=>t.points.every(t=>null===t.v))?B`
${ne(e.hass,"chart_no_data")}
`:void 0}const zo=r` - ${Lo} + ${To} .series-header { display: flex; flex-wrap: wrap; @@ -239,14 +239,20 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt background: color-mix(in srgb, var(--card-background-color, #fff) 80%, transparent); white-space: nowrap; } -`;function Po(t,e,n){const{locale:o,grouping:i}=function(t){const e=t?.locale?.language??"en";switch(t?.locale?.number_format){case"system":return{locale:void 0,grouping:!0};case"comma_decimal":return{locale:"en-US",grouping:!0};case"decimal_comma":return{locale:"de",grouping:!0};case"space_comma":return{locale:"fr",grouping:!0};case"none":return{locale:"en-US",grouping:!1};default:return{locale:e,grouping:!0}}}(n),r=new Intl.NumberFormat(o,{minimumFractionDigits:e,maximumFractionDigits:e,useGrouping:i});let a=r.format(0===t?0:t);return 0===Number(t.toFixed(e))&&(a=r.format(0)),a}function Ho(t,e){return e?`${t} ${e}`:t}const Fo=new WeakMap;function Do(t){Fo.get(t)?.observer?.disconnect(),Fo.delete(t)}function Ro(t){const e=an(t.raw);return Math.max(0,function(t){let e=Fo.get(t.host);if(!e){const n={width:t.host.clientWidth||400};e=n,Fo.set(t.host,n),"undefined"!=typeof ResizeObserver&&(n.observer=new ResizeObserver(e=>{const o=Math.round(e[e.length-1].contentRect.width);Math.round(o/70)!==Math.round(n.width/70)&&(n.width=o,t.requestUpdate())}),n.observer.observe(t.host))}return e.width}(t)-32-(e.y&&"outside"===e.labels?40:0))}function Vo(t,e,n){const o=an(t.raw),i=cn(n,o,4),r=Math.max(2,Math.min(8,Math.floor(Ro(t)/70))),{unit:a,ticks:s}=_n(e,r,fn(vn(t.hass)));return{options:o,value:i,times:s,unit:a,range:e,scales:{x:Xe([e.start,e.end],[0,wo]),y:Xe(i.domain,[ko,0]),domain:i.domain}}}const Bo=t=>Math.round(1e4*t)/100+"%";function Io({axes:t,ctx:e,content:n,label:o,defs:i=Z,overlay:r=Z,hover:a}){const{options:s}=t,l="outside"===s.labels,c=s.y&&t.value.ticks.length>0,d=s.x&&t.times.length>0,h=c?function(t,e){const{scales:n,value:o}=t;return o.ticks.map(t=>{const i=n.y(t)/ko;return B`.92?"bottom":""}" style="top:${Bo(i)}" +`;function Po(t,e,n){const{locale:o,grouping:i}=function(t){const e=t?.locale?.language??"en";switch(t?.locale?.number_format){case"system":return{locale:void 0,grouping:!0};case"comma_decimal":return{locale:"en-US",grouping:!0};case"decimal_comma":return{locale:"de",grouping:!0};case"space_comma":return{locale:"fr",grouping:!0};case"none":return{locale:"en-US",grouping:!1};default:return{locale:e,grouping:!0}}}(n),r=new Intl.NumberFormat(o,{minimumFractionDigits:e,maximumFractionDigits:e,useGrouping:i});let a=r.format(0===t?0:t);return 0===Number(t.toFixed(e))&&(a=r.format(0)),a}function Ho(t,e){return e?`${t} ${e}`:t}const Fo=new WeakMap;function Do(t){Fo.get(t)?.observer?.disconnect(),Fo.delete(t)}function Vo(t){const e=an(t.raw);return Math.max(0,function(t){let e=Fo.get(t.host);if(!e){const n={width:t.host.clientWidth||400};e=n,Fo.set(t.host,n),"undefined"!=typeof ResizeObserver&&(n.observer=new ResizeObserver(e=>{const o=Math.round(e[e.length-1].contentRect.width);Math.round(o/70)!==Math.round(n.width/70)&&(n.width=o,t.requestUpdate())}),n.observer.observe(t.host))}return e.width}(t)-32-(e.y&&"outside"===e.labels?40:0))}function Ro(t,e,n){const o=an(t.raw),i=cn(n,o,4),r=Math.max(2,Math.min(8,Math.floor(Vo(t)/70))),{unit:a,ticks:s}=yn(e,r,fn(vn(t.hass)));return{options:o,value:i,times:s,unit:a,range:e,scales:{x:Xe([e.start,e.end],[0,wo]),y:Xe(i.domain,[ko,0]),domain:i.domain}}}const Bo=t=>Math.round(1e4*t)/100+"%";function Io({axes:t,ctx:e,content:n,label:o,defs:i=W,overlay:r=W,hover:a,right:s}){const{options:l}=t,c="outside"===l.labels,d=l.y&&t.value.ticks.length>0,h=l.x&&t.times.length>0,u=d?function(t,e){const{scales:n,value:o}=t;return o.ticks.map(t=>{const i=n.y(t)/ko;return B`.92?"bottom":""}" style="top:${Bo(i)}" >${Po(t,o.decimals,e.hass)}`})}(t,e):[],u=c?B`
${h}
`:Z,p=d?B`
${function(t,e){const{scales:n,range:o}=t,i=fn(vn(e.hass));return t.times.map(r=>{const a=n.x(r)/wo;return B`.95?"end":""}" style="left:${Bo(a)}" + >`})}(t,e):[],p=d?B`
${u}
`:W,m=h?B`
${function(t,e){const{scales:n,range:o}=t,i=fn(vn(e.hass));return t.times.map(r=>{const a=n.x(r)/wo;return B`.95?"end":""}" style="left:${Bo(a)}" >${t.label?t.label(r):Mn(r,t.unit,o.end-o.start,e.hass,i)}`})}(t,e)}
`:Z,m=c?B`
`:W,f=d?B``:Z;return B`
- ${l&&c?B`
${m}${h}
`:Z} + >`:W,g=s&&l.y&&s.value.ticks.length>0?s:void 0,_=g?B``:W,y=g?B`
${c?_:W}${function(t,e){return t.value.ticks.map(n=>{const o=t.y(n)/ko;return B`.92?"bottom":""}" style="top:${Bo(o)}" + >${Po(n,t.value.decimals,e.hass)}`})}(g,e)}
`:W;return B`
+ ${c&&d?B`
${f}${u}
`:W}
- ${function(t,e,n=Z,o=Z){return B`${t} `}(n,o,i,function(t){const{options:e,scales:n}=t;return I` - ${e.horizontal?t.value.ticks.map(t=>I``):Z} - ${e.vertical?t.times.map(t=>I``):Z} - `}(t))} ${l?Z:B`${u}${p}`} ${r} + ${e.horizontal?t.value.ticks.map(t=>I``):W} + ${e.vertical?t.times.map(t=>I``):W} + `}(t))} ${c?W:B`${p}${y}${m}`} + ${r}
- ${l?p:Z} -
`}const Wo=r` + ${c?B`${y}${m}`:W} +
`}const Zo=r` .plot-wrap { display: grid; grid-template-columns: auto minmax(0, 1fr); @@ -342,6 +349,22 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt .x-axis .axis-label.end { transform: translateX(-100%); } + .plot-wrap.has-right { + grid-template-columns: auto minmax(0, 1fr) auto; + } + .axes-outside .y-axis.right { + grid-column: 3; + padding-right: 0; + padding-left: 6px; + } + .axes-outside .y-axis.right .axis-label { + right: auto; + left: 6px; + } + .axes-inside .y-axis.right .axis-label { + left: auto; + right: 2px; + } .axes-inside .y-axis, .axes-inside .x-axis { position: absolute; @@ -369,9 +392,9 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt border-radius: 2px; background: color-mix(in srgb, var(--card-background-color, #fff) 70%, transparent); } -`,Zo=["above","over","hidden"];function qo(t){if(void 0!==t.compact&&"boolean"!=typeof t.compact)throw new Error('"compact" must be true or false');if(void 0!==t.header&&!Zo.includes(t.header))throw new Error(`"header" must be one of: ${Zo.join(", ")}`)}function Yo(t){return{compact:!0===t.compact,header:t.header??"above"}}function Go(t,e,n){return B`
- ${"above"===t.header?e:Z}${n} -
`}function Xo(t){return t===Z?Z:B`
t.stopPropagation()}>${t}
`}const Jo=r` +`,Wo=["above","over","hidden"];function qo(t){if(void 0!==t.compact&&"boolean"!=typeof t.compact)throw new Error('"compact" must be true or false');if(void 0!==t.header&&!Wo.includes(t.header))throw new Error(`"header" must be one of: ${Wo.join(", ")}`)}function Yo(t){return{compact:!0===t.compact,header:t.header??"above"}}function Go(t,e,n){return B`
+ ${"above"===t.header?e:W}${n} +
`}function Xo(t){return t===W?W:B`
t.stopPropagation()}>${t}
`}const Jo=r` .header-over { position: absolute; top: 2px; @@ -428,12 +451,12 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt ${ne(t.hass,"chart_total")} ${null===e?"—":Ho(Po(e,o,t.hass),n)} -
`}function mi(t,e,n,o,i,r={}){if(void 0===o)return Z;const a=n.x(o)/wo;if(!(a>=0&&a<=1))return Z;const s=function(t,e){const n=t*e;return n+190<=e?"right":n>=190?"left":t>.5?"pin-left":"pin-right"}(a,i),l=e.map(t=>{const e=ii(t.points,o);return{s:t,p:e<0?void 0:t.points[e]}});return B``}function mi(t,e,n,o,i,r={}){if(void 0===o)return W;const a=n.x(o)/wo;if(!(a>=0&&a<=1))return W;const s=function(t,e){const n=t*e;return n+190<=e?"right":n>=190?"left":t>.5?"pin-left":"pin-right"}(a,i),l=e.map(t=>{const e=ii(t.points,o);return{s:t,p:e<0?void 0:t.points[e]}});return B``}te("en",{chart_total:"Total"});const fi=r` .plot-area.hoverable { @@ -531,14 +554,14 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt .tooltip-total .swatch { background: none; } -`;function gi(t,e,n){return{select:{mode:"dropdown",options:n.map(n=>({value:n,label:ne(t,`editor_${e}_${n}`)}))}}}te("en",{editor_period_calendar:"Period",editor_period_calendar_rolling:"The last…",editor_period_calendar_day:"Today",editor_period_calendar_week:"This week",editor_period_calendar_month:"This month",editor_period_calendar_year:"This year",editor_period_offset:"Periods back (0 is the current one)",editor_period_until:"Draw up to",editor_period_until_now:"Now",editor_period_until_end:"The end of the period",editor_period_navigate:"Show previous and next buttons",editor_group_by:"Group readings by",editor_group_by_none:"Don't group",editor_group_by_hour:"Hour",editor_group_by_day:"Day",editor_group_by_week:"Week",editor_group_by_month:"Month",editor_aggregate:"Combine with",editor_aggregate_mean:"Average",editor_aggregate_sum:"Sum",editor_aggregate_min:"Lowest",editor_aggregate_max:"Highest",editor_aggregate_first:"First",editor_aggregate_last:"Last",editor_aggregate_change:"Change (meters that count up)"});const yi=[{name:"period_calendar",path:["period","calendar"],default:"rolling"},{name:"period_last",path:["period","last"],default:24},{name:"period_unit",path:["period","unit"],default:"hour"},{name:"period_offset",path:["period","offset"],default:0},{name:"period_until",path:["period","until"],default:"now"},{name:"period_navigate",path:["period","navigate"],default:!1},{name:"source",path:["source"],default:"history"},{name:"group_by",path:["group_by"],default:"none"},{name:"aggregate",path:["aggregate"],default:"mean"}];function _i(t){const e=t?.period;return`${e?.calendar?"calendar":"rolling"}${t?.group_by?"|grouped":""}`}function vi(t,e){const[n,o]=_i(e).split("|"),i="calendar"===n;return[{type:"grid",name:"",schema:[{name:"period_calendar",selector:gi(t,"period_calendar",["rolling",...Rn])},...i?[{name:"period_until",selector:gi(t,"period_until",Vn)}]:[{name:"period_last",selector:{number:{min:1,mode:"box"}}},{name:"period_unit",selector:gi(t,"period_unit",Dn)}],{name:"period_offset",selector:{number:{min:0,mode:"box"}}}]},{name:"period_navigate",selector:{boolean:{}}},{name:"source",selector:gi(t,"source",Ao)},{type:"grid",name:"",schema:[{name:"group_by",selector:gi(t,"group_by",["none",...ao])},...o?[{name:"aggregate",selector:gi(t,"aggregate",so)}]:[]]}]}te("en",{editor_x_axis:"Time labels",editor_y_axis:"Value labels",editor_axis_labels:"Axis labels",editor_axis_labels_outside:"Beside the chart",editor_axis_labels_inside:"Over the chart",editor_grid_horizontal:"Lines across",editor_grid_vertical:"Lines down",editor_y_min:"Lowest value shown",editor_y_max:"Highest value shown",editor_tooltip:"Show values on hover or touch",editor_line_width:"Line width (px)",editor_dots:"Dot at each reading",editor_on_top:"Draw above the other lines",editor_compact:"Compact",editor_header:"Names and values",editor_header_above:"Above the chart",editor_header_over:"Over the chart",editor_header_hidden:"Hidden"});const bi=[{name:"header",path:["header"],default:"above"},{name:"compact",path:["compact"],default:!1}];function $i(t){return[{type:"grid",name:"",schema:[{name:"header",selector:gi(t,"header",Zo)},{name:"compact",selector:{boolean:{}}}]}]}const xi=[{name:"x_axis",path:["x_axis"],default:Ke},{name:"y_axis",path:["y_axis"],default:Qe},{name:"axis_labels",path:["axis_labels"],default:tn},{name:"grid_horizontal",path:["gridlines","horizontal"],default:en},{name:"grid_vertical",path:["gridlines","vertical"],default:nn},{name:"y_min",path:["y_min"]},{name:"y_max",path:["y_max"]},{name:"tooltip",path:["tooltip"],default:!0}];function wi(t){return[{type:"grid",name:"",schema:[{name:"x_axis",selector:{boolean:{}}},{name:"y_axis",selector:{boolean:{}}},{name:"grid_horizontal",selector:{boolean:{}}},{name:"grid_vertical",selector:{boolean:{}}}]},{name:"axis_labels",selector:gi(t,"axis_labels",Je)},{type:"grid",name:"",schema:[{name:"y_min",selector:{number:{mode:"box",step:"any"}}},{name:"y_max",selector:{number:{mode:"box",step:"any"}}}]},{name:"tooltip",selector:{boolean:{}}}]}const ki=new Map;function Mi(t,e,n){const o=`${t}|${ee(e)}`;let i=ki.get(o);return i||(i=n(),ki.set(o,i)),i}function Ai(t,e,n,o){return B`({value:n,label:ne(t,`editor_${e}_${n}`)}))}}}te("en",{editor_period_calendar:"Period",editor_period_calendar_rolling:"The last…",editor_period_calendar_day:"Today",editor_period_calendar_week:"This week",editor_period_calendar_month:"This month",editor_period_calendar_year:"This year",editor_period_offset:"Periods back (0 is the current one)",editor_period_until:"Draw up to",editor_period_until_now:"Now",editor_period_until_end:"The end of the period",editor_period_navigate:"Show previous and next buttons",editor_group_by:"Group readings by",editor_group_by_none:"Don't group",editor_group_by_hour:"Hour",editor_group_by_day:"Day",editor_group_by_week:"Week",editor_group_by_month:"Month",editor_aggregate:"Combine with",editor_aggregate_mean:"Average",editor_aggregate_sum:"Sum",editor_aggregate_min:"Lowest",editor_aggregate_max:"Highest",editor_aggregate_first:"First",editor_aggregate_last:"Last",editor_aggregate_change:"Change (meters that count up)"});const _i=[{name:"period_calendar",path:["period","calendar"],default:"rolling"},{name:"period_last",path:["period","last"],default:24},{name:"period_unit",path:["period","unit"],default:"hour"},{name:"period_offset",path:["period","offset"],default:0},{name:"period_until",path:["period","until"],default:"now"},{name:"period_navigate",path:["period","navigate"],default:!1},{name:"source",path:["source"],default:"history"},{name:"group_by",path:["group_by"],default:"none"},{name:"aggregate",path:["aggregate"],default:"mean"}];function yi(t){const e=t?.period;return`${e?.calendar?"calendar":"rolling"}${t?.group_by?"|grouped":""}`}function vi(t,e){const[n,o]=yi(e).split("|"),i="calendar"===n;return[{type:"grid",name:"",schema:[{name:"period_calendar",selector:gi(t,"period_calendar",["rolling",...Vn])},...i?[{name:"period_until",selector:gi(t,"period_until",Rn)}]:[{name:"period_last",selector:{number:{min:1,mode:"box"}}},{name:"period_unit",selector:gi(t,"period_unit",Dn)}],{name:"period_offset",selector:{number:{min:0,mode:"box"}}}]},{name:"period_navigate",selector:{boolean:{}}},{name:"source",selector:gi(t,"source",Ao)},{type:"grid",name:"",schema:[{name:"group_by",selector:gi(t,"group_by",["none",...ao])},...o?[{name:"aggregate",selector:gi(t,"aggregate",so)}]:[]]}]}te("en",{editor_x_axis:"Time labels",editor_y_axis:"Value labels",editor_axis_labels:"Axis labels",editor_axis_labels_outside:"Beside the chart",editor_axis_labels_inside:"Over the chart",editor_grid_horizontal:"Lines across",editor_grid_vertical:"Lines down",editor_y_min:"Lowest value shown",editor_y_max:"Highest value shown",editor_tooltip:"Show values on hover or touch",editor_line_width:"Line width (px)",editor_dots:"Dot at each reading",editor_on_top:"Draw above the other lines",editor_compact:"Compact",editor_header:"Names and values",editor_header_above:"Above the chart",editor_header_over:"Over the chart",editor_header_hidden:"Hidden"});const bi=[{name:"header",path:["header"],default:"above"},{name:"compact",path:["compact"],default:!1}];function $i(t){return[{type:"grid",name:"",schema:[{name:"header",selector:gi(t,"header",Wo)},{name:"compact",selector:{boolean:{}}}]}]}const xi=[{name:"x_axis",path:["x_axis"],default:Ke},{name:"y_axis",path:["y_axis"],default:Qe},{name:"axis_labels",path:["axis_labels"],default:tn},{name:"grid_horizontal",path:["gridlines","horizontal"],default:en},{name:"grid_vertical",path:["gridlines","vertical"],default:nn},{name:"y_min",path:["y_min"]},{name:"y_max",path:["y_max"]},{name:"tooltip",path:["tooltip"],default:!0}];function wi(t){return[{type:"grid",name:"",schema:[{name:"x_axis",selector:{boolean:{}}},{name:"y_axis",selector:{boolean:{}}},{name:"grid_horizontal",selector:{boolean:{}}},{name:"grid_vertical",selector:{boolean:{}}}]},{name:"axis_labels",selector:gi(t,"axis_labels",Je)},{type:"grid",name:"",schema:[{name:"y_min",selector:{number:{mode:"box",step:"any"}}},{name:"y_max",selector:{number:{mode:"box",step:"any"}}}]},{name:"tooltip",selector:{boolean:{}}}]}const ki=new Map;function Mi(t,e,n){const o=`${t}|${ee(e)}`;let i=ki.get(o);return i||(i=n(),ki.set(o,i)),i}function Ai(t,e,n,o){return B`ne(t.hass,`editor_${e.name}`)} - @value-changed=${e=>{e.stopPropagation();const n=Re(t.config,o,e.detail?.value??{});n!==t.config&&t.commit(n)}} - >`}const Ci=[...yi,{name:"curve",path:["curve"],default:"smooth"},{name:"color_by",path:["color_by"],default:"series"},{name:"labels",path:["labels"],default:!1},{name:"line_width",path:["line_width"],default:2.5},{name:"dots",path:["dots"],default:!1},...xi,...bi];function Si(t,e){if(!t)return e;const[n,o]=t,i={};return void 0===e.y_min&&n>=0&&n<=o/2&&(i.y_min=0),void 0===e.y_max&&o<=0&&o>=n/2&&(i.y_max=0),Object.keys(i).length?{...e,...i}:e}function Ei(t){const e=[];return t.forEach((n,o)=>{o>0&&e.push([n[0],t[o-1][1]]),e.push(n)}),e}function Oi(t,e,n){if(t.length<2)return"";const[o,i,r]="step"===n?[Ei(t),Ei(e),"straight"]:[t,e,n];return`${$o(o,r)}${$o([...i].reverse(),r).replace(/^M/,"L")}Z`}function Ti(t,e){return"step"===e?$o(Ei(t),"straight"):$o(t,e)}function Li(t,e,n,o,i={}){const r=se(t.entity.config,o),a=t.entity.config.line_width??o.line_width,s=n.y(Math.min(Math.max(0,n.domain[0]),n.domain[1])),l=function(t){const e=t.entity.config.negative_color;return"string"==typeof e&&e.trim()?Et(e.trim()):t.color}(t),c=`cd-area-${t.index}`,d=`cd-area-line-${t.index}`,h=l!==t.color,u=I`${function(t,e,n,o,i=.42,r=.05){const a=Math.min(1,Math.max(0,o/ko));return I` + @value-changed=${e=>{e.stopPropagation();const n=Ve(t.config,o,e.detail?.value??{});n!==t.config&&t.commit(n)}} + >`}const Ei=[..._i,{name:"curve",path:["curve"],default:"smooth"},{name:"color_by",path:["color_by"],default:"series"},{name:"labels",path:["labels"],default:!1},{name:"line_width",path:["line_width"],default:2.5},{name:"dots",path:["dots"],default:!1},...xi,...bi];function Ci(t,e){if(!t)return e;const[n,o]=t,i={};return void 0===e.y_min&&n>=0&&n<=o/2&&(i.y_min=0),void 0===e.y_max&&o<=0&&o>=n/2&&(i.y_max=0),Object.keys(i).length?{...e,...i}:e}function Si(t){const e=[];return t.forEach((n,o)=>{o>0&&e.push([n[0],t[o-1][1]]),e.push(n)}),e}function Oi(t,e,n){if(t.length<2)return"";const[o,i,r]="step"===n?[Si(t),Si(e),"straight"]:[t,e,n];return`${$o(o,r)}${$o([...i].reverse(),r).replace(/^M/,"L")}Z`}function Li(t,e){return"step"===e?$o(Si(t),"straight"):$o(t,e)}function Ti(t,e,n,o,i={}){const r=se(t.entity.config,o),a=t.entity.config.line_width??o.line_width,s=n.y(Math.min(Math.max(0,n.domain[0]),n.domain[1])),l=function(t){const e=t.entity.config.negative_color;return"string"==typeof e&&e.trim()?St(e.trim()):t.color}(t),c=`cd-area-${t.index}`,d=`cd-area-line-${t.index}`,h=l!==t.color,u=I`${function(t,e,n,o,i=.42,r=.05){const a=Math.min(1,Math.max(0,o/ko));return I` @@ -547,13 +570,13 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt ${h?function(t,e,n,o){const i=Math.min(1,Math.max(0,o/ko));return I` - `}(d,t.color,l,s):Z}`,p=[],m=[],f=[];if(i.layers){const o=i.layers;let r=[];const a=()=>{if(r.length){const i=r.map(t=>[n.x(e[t].t),n.y(o[t][1])]),a=r.map(t=>[n.x(e[t].t),n.y(o[t][0])]);p.push(Oi(i,a,t.curve)),m.push(Ti(i,t.curve))}r=[]};for(let t=0;t[n.x(t.t),n.y(t.v)]);p.push(Oi(e,e.map(([t])=>[t,s]),t.curve)),m.push(Ti(e,t.curve))}if(r.dots){const t=i.range;e.forEach((e,o)=>{if(null===e.v||t&&(e.t===t.start||e.t===t.end))return;const r=i.layers?i.layers[o]?.[1]:e.v;void 0!==r&&f.push([n.x(e.t),n.y(r)])})}const g=a??2,y=h?`url(#${d})`:t.color;return{defs:u,body:I` + `}(d,t.color,l,s):W}`,p=[],m=[],f=[];if(i.layers){const o=i.layers;let r=[];const a=()=>{if(r.length){const i=r.map(t=>[n.x(e[t].t),n.y(o[t][1])]),a=r.map(t=>[n.x(e[t].t),n.y(o[t][0])]);p.push(Oi(i,a,t.curve)),m.push(Li(i,t.curve))}r=[]};for(let t=0;t[n.x(t.t),n.y(t.v)]);p.push(Oi(e,e.map(([t])=>[t,s]),t.curve)),m.push(Li(e,t.curve))}if(r.dots){const t=i.range;e.forEach((e,o)=>{if(null===e.v||t&&(e.t===t.start||e.t===t.end))return;const r=i.layers?i.layers[o]?.[1]:e.v;void 0!==r&&f.push([n.x(e.t),n.y(r)])})}const g=a??2,_=h?`url(#${d})`:t.color;return{defs:u,body:I` - - ${f.length>0&&f.length<=200?I``:Z} - `}}te("en",{editor_style_area:"Area",editor_stack:"Stack",editor_stack_none:"Don't stack",editor_stack_normal:"On top of each other",editor_stack_percent:"To 100 %",editor_negative_color:"Colour below zero"});const Ni=[...yi,{name:"curve",path:["curve"],default:"smooth"},{name:"stack",path:["stack"],default:"none"},{name:"line_width",path:["line_width"],default:2},{name:"dots",path:["dots"],default:!1},...xi,...bi];const Ui={name:"negative_color",path:["negative_color"]},ji=new Map;const zi=r` + ${f.length>0&&f.length<=200?I``:W} + `}}te("en",{editor_style_area:"Area",editor_stack:"Stack",editor_stack_none:"Don't stack",editor_stack_normal:"On top of each other",editor_stack_percent:"To 100 %",editor_negative_color:"Colour below zero"});const Ni=[..._i,{name:"curve",path:["curve"],default:"smooth"},{name:"stack",path:["stack"],default:"none"},{name:"line_width",path:["line_width"],default:2},{name:"dots",path:["dots"],default:!1},...xi,...bi];const ji={name:"negative_color",path:["negative_color"]},Ui=new Map;const zi=r` .plot .fill { vector-effect: none; } @@ -570,7 +593,7 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt } `,Pi={layout:"chart",group:"history",height:240,styles:r` ${zo} - ${Wo} + ${Zo} ${fi} ${Jo} ${zi} @@ -583,8 +606,8 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt `,validate(t){Co(t),rn(t),ci(t),pe(t),qo(t),Qo(t),function(t){for(const e of t.entities??[]){if("object"!=typeof e)continue;const t=e.negative_color;if(void 0!==t&&"string"!=typeof t)throw new Error(`"negative_color" of ${e.entity} must be a colour`)}}(t)},editor:function(t){const e=Mi(`area|${_i(t.config)}`,t.hass,()=>[...vi(t.hass,t.config),{type:"grid",name:"",schema:[{name:"curve",selector:gi(t.hass,"curve",_o)},{name:"stack",selector:gi(t.hass,"stack",Ko)}]},{type:"grid",name:"",schema:[{name:"line_width",selector:xe},{name:"dots",selector:{boolean:{}}}]},...wi(t.hass),...$i(t.hass)]);return Ai(t,"chart",e,Ni)},entityFields:function(t,e){const n=!0===e.dots;let o=ji.get(n);return o||(o=[...ke(n),Ui],ji.set(n,o)),{schema:Mi("area-entity",t,()=>[...Te(t),{name:"negative_color",selector:{text:{}}}]),fields:o}},disconnect(t){No(t),Do(t),si(t)},render:function(t){const e=So(t),n=To(e,t),o=Uo(e,t),i=n===Z&&o===Z?Z:B`${n}${o}`,r=jo(e,t),a=Yo(t.raw);if(r)return Go("over"===a.header?{...a,header:"above"}:a,i,r);const s=t.raw.stack??"none",l=e.series.map(t=>({...t,points:An(t.points,500)}));let c,d,h=l;const u={};if("none"===s){const n=Ge(l.map(t=>t.points));d=Vo({...t,raw:Si(n,t.raw)},e.range,n);const o=d.scales,i=le(l,e=>se(e.entity.config,t.raw).onTop);c=i.map(n=>Li(n,n.points,o,t.raw,{range:e.range}))}else{const n=function(t){const e=[...new Set(t.flatMap(t=>t.map(t=>t.t)))].sort((t,e)=>t-e);return{times:e,values:t.map(t=>e.map(e=>ti(t,e)))}}(l.map(t=>t.points)),o=ei(n.values,s),i=ni(n.values);h=l.map((t,e)=>({...t,points:n.times.map((t,o)=>({t:t,v:n.values[e][o]}))}));const r=oi(o),a="percent"===s?{y_min:r[0]<0?-100:0,y_max:r[1]>0?100:0}:{};d=Vo({...t,raw:Si(r,{...a,...t.raw})},e.range,r);const p=d.scales;c=h.map((n,i)=>Li(n,n.points,p,t.raw,{layers:o[i],stacked:!0,range:e.range})).reverse();const m=new Map;h.forEach(t=>t.points.forEach((t,e)=>m.set(t,e))),u.dotY=(t,e)=>{const n=o[t.index][m.get(e)??-1];return n?p.y(n[1]):null};const f=ui(h),g=Math.max(...h.map(t=>t.entity.decimals));u.footer=e=>{const n=e.length?m.get(e[0].p):void 0;return pi(t,void 0===n?null:i[n],f,g)},"percent"===s&&(u.text=(e,n)=>{const i=n?o[e.index][m.get(n)??-1]:null;if(!n||null===n.v||!i)return"—";const r=Math.round(Math.abs(i[1]-i[0]));return`${Ho(Po(n.v,e.entity.decimals,t.hass),e.entity.unit)} · ${r} %`})}const p=li(t.raw),m=ne(t.hass,"chart_aria",{style:ne(t.hass,"editor_style_area"),names:e.series.map(t=>t.entity.name).join(", ")});return Go(a,i,Io({axes:d,ctx:t,content:I`${c.map(t=>t.body)}`,defs:I`${c.map(t=>t.defs)}`,label:m,overlay:B`${"over"===a.header?Xo(i):Z} - ${p?mi(t,h,d.scales,ai(t.host),Ro(t),u):Z}`,hover:p?di(t,e.range,h.map(t=>t.points)):void 0}))}};function Hi(t,e,n){return!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(n)||n<=e?0:Math.min(1,Math.max(0,(t-e)/(n-e)))}function Fi(t,e,n){if(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(n)||n<=e)return[0,0];const o=Hi(t,e,n);if(e<0&&n>0){const t=Hi(0,e,n);return o"number"==typeof t.from))return t;const n=[];for(const o of t){const t=e?Ii(o.from,e,"band start"):null;null!==t&&n.push({...o,from:t})}return n.length?n.sort((t,e)=>t.from-e.from):Bt}function Zi(t,e){const n=t.entity,o=e.states[n],i=t.name??o?.attributes?.friendly_name??n,r=t.unit??(t.attribute?"":o?.attributes?.unit_of_measurement??""),a=function(t,e){if(e)return t.attribute?e.attributes?.[t.attribute]:e.state}(t,o),s=function(t){return"number"==typeof t?Number.isFinite(t)?t:null:"string"==typeof t?Bi(t):null}(a),l=null!==s;let c;c=Vi(t.decimals)?t.attribute?l?function(t){const e=String(t),n=e.indexOf(".");return-1===n||/e/i.test(e)?0:Math.min(2,e.length-n-1)}(a):0:function(t,e,n){const o=t?.entities?.[e]?.display_precision;return"number"==typeof o?o:"%"===n?0:1}(e,n,r):t.decimals;const d=Ii(t.min,e)??0,h=Ii(t.max,e)??100,u=Ii(t.target,e),p=Wi(t.severity,e);let m,f="";return l?(f=Po(s,c,e),m=Ho(f,r)):m=o?function(t,e,n,o){const i=t.attribute;return i&&"string"==typeof n&&""!==n.trim()?o.formatEntityAttributeValue?.(e,i)??n:o.formatEntityState?.(e)??ne(o,"unavailable")}(t,o,a,e):ne(e,"entity_not_found"),{entityId:n,config:t,stateObj:o,available:l,value:s,min:d,max:h,target:u,name:i,unit:r,decimals:c,position:l?Hi(s,d,h):0,span:l?Fi(s,d,h):[0,0],targetPosition:null===u?null:Hi(u,d,h),band:Lt(l?s:-1/0,p),bands:p,valueText:f,display:m,label:`${i}, ${m}`}}function qi(t,e){if(!t.include)return[];const n=new Set(t.entities.map(t=>t.entity));return function(t,e,n){const o=Rt.get(t);if(o&&o.exclude===e&&o.states===n.states&&o.entities===n.entities&&o.devices===n.devices&&o.areas===n.areas)return o.ids;const i=[];for(const a of Object.values(n.states)){if(!zt(a)||n.entities?.[a.entity_id]?.hidden)continue;const o=Pt(a,n);if(!Ft(t,o)||Dt(e,o))continue;const r=a.attributes?.friendly_name;i.push({id:a.entity_id,name:"string"==typeof r&&r?r:a.entity_id})}i.sort((t,e)=>t.name.localeCompare(e.name)||(t.idt.id);return Rt.set(t,{exclude:e,states:n.states,entities:n.entities,devices:n.devices,areas:n.areas,ids:r}),r}(t.include,t.exclude,e).filter(t=>!n.has(t))}const Yi={layout:"rows",group:"bars",height:46,minColumnWidth:160,styles:r` + stroke="var(--primary-color, #03a9f4)" stroke-width="2.5" stroke-linecap="round" />`,validate(t){Eo(t),rn(t),ci(t),pe(t),qo(t),Qo(t),function(t){for(const e of t.entities??[]){if("object"!=typeof e)continue;const t=e.negative_color;if(void 0!==t&&"string"!=typeof t)throw new Error(`"negative_color" of ${e.entity} must be a colour`)}}(t)},editor:function(t){const e=Mi(`area|${yi(t.config)}`,t.hass,()=>[...vi(t.hass,t.config),{type:"grid",name:"",schema:[{name:"curve",selector:gi(t.hass,"curve",yo)},{name:"stack",selector:gi(t.hass,"stack",Ko)}]},{type:"grid",name:"",schema:[{name:"line_width",selector:xe},{name:"dots",selector:{boolean:{}}}]},...wi(t.hass),...$i(t.hass)]);return Ai(t,"chart",e,Ni)},entityFields:function(t,e){const n=!0===e.dots;let o=Ui.get(n);return o||(o=[...ke(n),ji],Ui.set(n,o)),{schema:Mi("area-entity",t,()=>[...Le(t),{name:"negative_color",selector:{text:{}}}]),fields:o}},disconnect(t){No(t),Do(t),si(t)},render:function(t){const e=Co(t),n=Lo(e,t),o=jo(e,t),i=n===W&&o===W?W:B`${n}${o}`,r=Uo(e,t),a=Yo(t.raw);if(r)return Go("over"===a.header?{...a,header:"above"}:a,i,r);const s=t.raw.stack??"none",l=e.series.map(t=>({...t,points:An(t.points,500)}));let c,d,h=l;const u={};if("none"===s){const n=Ge(l.map(t=>t.points));d=Ro({...t,raw:Ci(n,t.raw)},e.range,n);const o=d.scales,i=le(l,e=>se(e.entity.config,t.raw).onTop);c=i.map(n=>Ti(n,n.points,o,t.raw,{range:e.range}))}else{const n=function(t){const e=[...new Set(t.flatMap(t=>t.map(t=>t.t)))].sort((t,e)=>t-e);return{times:e,values:t.map(t=>e.map(e=>ti(t,e)))}}(l.map(t=>t.points)),o=ei(n.values,s),i=ni(n.values);h=l.map((t,e)=>({...t,points:n.times.map((t,o)=>({t:t,v:n.values[e][o]}))}));const r=oi(o),a="percent"===s?{y_min:r[0]<0?-100:0,y_max:r[1]>0?100:0}:{};d=Ro({...t,raw:Ci(r,{...a,...t.raw})},e.range,r);const p=d.scales;c=h.map((n,i)=>Ti(n,n.points,p,t.raw,{layers:o[i],stacked:!0,range:e.range})).reverse();const m=new Map;h.forEach(t=>t.points.forEach((t,e)=>m.set(t,e))),u.dotY=(t,e)=>{const n=o[t.index][m.get(e)??-1];return n?p.y(n[1]):null};const f=ui(h),g=Math.max(...h.map(t=>t.entity.decimals));u.footer=e=>{const n=e.length?m.get(e[0].p):void 0;return pi(t,void 0===n?null:i[n],f,g)},"percent"===s&&(u.text=(e,n)=>{const i=n?o[e.index][m.get(n)??-1]:null;if(!n||null===n.v||!i)return"—";const r=Math.round(Math.abs(i[1]-i[0]));return`${Ho(Po(n.v,e.entity.decimals,t.hass),e.entity.unit)} · ${r} %`})}const p=li(t.raw),m=ne(t.hass,"chart_aria",{style:ne(t.hass,"editor_style_area"),names:e.series.map(t=>t.entity.name).join(", ")});return Go(a,i,Io({axes:d,ctx:t,content:I`${c.map(t=>t.body)}`,defs:I`${c.map(t=>t.defs)}`,label:m,overlay:B`${"over"===a.header?Xo(i):W} + ${p?mi(t,h,d.scales,ai(t.host),Vo(t),u):W}`,hover:p?di(t,e.range,h.map(t=>t.points)):void 0}))}};function Hi(t,e,n){return!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(n)||n<=e?0:Math.min(1,Math.max(0,(t-e)/(n-e)))}function Fi(t,e,n){if(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(n)||n<=e)return[0,0];const o=Hi(t,e,n);if(e<0&&n>0){const t=Hi(0,e,n);return o"number"==typeof t.from))return t;const n=[];for(const o of t){const t=e?Ii(o.from,e,"band start"):null;null!==t&&n.push({...o,from:t})}return n.length?n.sort((t,e)=>t.from-e.from):Bt}function Wi(t,e){const n=t.entity,o=e.states[n],i=t.name??o?.attributes?.friendly_name??n,r=t.unit??(t.attribute?"":o?.attributes?.unit_of_measurement??""),a=function(t,e){if(e)return t.attribute?e.attributes?.[t.attribute]:e.state}(t,o),s=function(t){return"number"==typeof t?Number.isFinite(t)?t:null:"string"==typeof t?Bi(t):null}(a),l=null!==s;let c;c=Ri(t.decimals)?t.attribute?l?function(t){const e=String(t),n=e.indexOf(".");return-1===n||/e/i.test(e)?0:Math.min(2,e.length-n-1)}(a):0:function(t,e,n){const o=t?.entities?.[e]?.display_precision;return"number"==typeof o?o:"%"===n?0:1}(e,n,r):t.decimals;const d=Ii(t.min,e)??0,h=Ii(t.max,e)??100,u=Ii(t.target,e),p=Zi(t.severity,e);let m,f="";return l?(f=Po(s,c,e),m=Ho(f,r)):m=o?function(t,e,n,o){const i=t.attribute;return i&&"string"==typeof n&&""!==n.trim()?o.formatEntityAttributeValue?.(e,i)??n:o.formatEntityState?.(e)??ne(o,"unavailable")}(t,o,a,e):ne(e,"entity_not_found"),{entityId:n,config:t,stateObj:o,available:l,value:s,min:d,max:h,target:u,name:i,unit:r,decimals:c,position:l?Hi(s,d,h):0,span:l?Fi(s,d,h):[0,0],targetPosition:null===u?null:Hi(u,d,h),band:Tt(l?s:-1/0,p),bands:p,valueText:f,display:m,label:`${i}, ${m}`}}function qi(t,e){if(!t.include)return[];const n=new Set(t.entities.map(t=>t.entity));return function(t,e,n){const o=Vt.get(t);if(o&&o.exclude===e&&o.states===n.states&&o.entities===n.entities&&o.devices===n.devices&&o.areas===n.areas)return o.ids;const i=[];for(const a of Object.values(n.states)){if(!zt(a)||n.entities?.[a.entity_id]?.hidden)continue;const o=Pt(a,n);if(!Ft(t,o)||Dt(e,o))continue;const r=a.attributes?.friendly_name;i.push({id:a.entity_id,name:"string"==typeof r&&r?r:a.entity_id})}i.sort((t,e)=>t.name.localeCompare(e.name)||(t.idt.id);return Vt.set(t,{exclude:e,states:n.states,entities:n.entities,devices:n.devices,areas:n.areas,ids:r}),r}(t.include,t.exclude,e).filter(t=>!n.has(t))}const Yi={layout:"rows",group:"bars",height:46,minColumnWidth:160,styles:r` .style-bar .entity { display: flex; align-items: center; @@ -666,31 +689,31 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt white-space: nowrap; margin-left: auto; } - `,render(t,{show:e,hass:n}){const o=e.value||!t.available,i=B`${e.name?B`${t.name}`:Z}${o?B`${t.display}`:Z}`;return B` + `,render(t,{show:e,hass:n}){const o=e.value||!t.available,i=B`${e.name?B`${t.name}`:W}${o?B`${t.display}`:W}`;return B` ${e.icon?B``:Z} + .icon=${Vi(t)} + >`:W}
- ${e.target&&null!==t.targetPosition&&t.available?B`
`:Z} + ${e.target&&null!==t.targetPosition&&t.available?B`
`:W}
${i}
- ${t.available?B``:Z} + ${t.available?B``:W}
- `}},Gi=["auto","none","hour","day","week","month"],Xi=["auto","mean","sum","min","max","first","last","change"],Ji={last:7,unit:"day"},Ki={hour:1/24,day:1,week:7,month:30};function Qi(t){if(t.config.attribute)return!1;const e=t.stateObj?.attributes?.state_class;return"total_increasing"===e||"total"===e}function tr(t,e){const n={...t,period:t.period??{...Ji}};return"none"===t.group_by?delete n.group_by:void 0!==t.group_by&&"auto"!==t.group_by||(n.group_by=function(t){if(t.calendar)return{day:"hour",week:"day",month:"day",year:"month"}[t.calendar];const e=t.last*Ki[t.unit];return e<=2?"hour":e<=62?"day":e<=190?"week":"month"}(qn(n.period))),void 0!==t.aggregate&&"auto"!==t.aggregate||(n.aggregate=!0!==t.range&&e.length>0&&e.every(Qi)?"change":"mean"),n}function er(t,e,n,o){const i=e-t,r=.8*i/o,a=o>1?.12*r:0;return[t+.2*i/2+n*r+a/2,r-a]}function nr(t,e=!0){let n=e?0:1/0,o=e?0:-1/0;for(const i of t)null!==i&&Number.isFinite(i)&&(n=Math.min(n,i),o=Math.max(o,i));return n===1/0?void 0:[n,o]}const or={hour:66,day:52,week:52,month:60};te("en",{editor_style_column:"Column",editor_group_by_auto:"Automatic",editor_aggregate_auto:"Automatic (change for meters, else average)",editor_range:"Lowest to highest in each column",editor_rounded:"Rounded tops",editor_column_labels:"Show values on the columns",editor_column_color:"Colour"});const ir={hour:"hour",day:"day",week:"day",month:"month"};const rr=(t,e)=>Math.round(t/e*1e4)/100+"%",ar=t=>Math.min(ko,Math.max(0,t));function sr(t,e,n,o,i,r,a,s){const l=ar(t.y(i)),c=ar(t.y(o));return B`
0&&e.every(tr)?"change":"mean"),n}function nr(t,e){const n=[...new Set(t.flatMap(t=>t.map(t=>t.t)))].sort((t,e)=>t-e),o=t.map(t=>new Map(t.map(t=>[t.t,t]))),i=new Map;for(const a of t)for(const t of a)void 0!==t.end&&i.set(t.t,t.end);const r={times:[],ends:[],values:t.map(()=>[]),lows:t.map(()=>[]),highs:t.map(()=>[])};return n.forEach((a,s)=>{const l=Math.min(i.get(a)??n[s+1]??e,e);l>a&&(r.times.push(a),r.ends.push(l),t.forEach((t,e)=>{const n=o[e].get(a);r.values[e].push(n?n.v:ti(t,a)),r.lows[e].push(n?.min??null),r.highs[e].push(n?.max??null)}))}),r}function or(t,e,n,o){const i=e-t,r=.8*i/o,a=o>1?.12*r:0;return[t+.2*i/2+n*r+a/2,r-a]}function ir(t,e=!0){let n=e?0:1/0,o=e?0:-1/0;for(const i of t)null!==i&&Number.isFinite(i)&&(n=Math.min(n,i),o=Math.max(o,i));return n===1/0?void 0:[n,o]}const rr={hour:66,day:52,week:52,month:60};te("en",{editor_style_column:"Column",editor_group_by_auto:"Automatic",editor_aggregate_auto:"Automatic (change for meters, else average)",editor_range:"Lowest to highest in each column",editor_rounded:"Rounded tops",editor_column_labels:"Show values on the columns",editor_column_color:"Colour"});const ar={hour:"hour",day:"day",week:"day",month:"month"};function sr(t,e,n,o){if("hour"===n)return`${kn(t,o)} – ${wn(e,o)}`;const i="day"===n?{weekday:"short",day:"numeric",month:"short"}:"week"===n?{day:"numeric",month:"short"}:{month:"long",year:"numeric"};let r;try{r=new Intl.DateTimeFormat(o?.locale?.language??"en",{...i,timeZone:vn(o)})}catch{r=new Intl.DateTimeFormat("en",i)}return"week"===n?r.formatRange(t,e-1):r.format(t)}const lr=(t,e)=>Math.round(t/e*1e4)/100+"%",cr=t=>Math.min(ko,Math.max(0,t));function dr(t,e,n,o,i,r,a,s){const l=cr(t.y(i)),c=cr(t.y(o));return B`
`}function lr(t,e,n,o,i,r){return B`
`}function hr(t,e,n,o,i,r){return B`${Po(o,i,t.hass)}`}function cr(t,e,n,o){const i=t.y(o);return i<0||i>ko?B``:B`
`}function ur(t,e,n,o){const i=t.y(o);return i<0||i>ko?B``:B`
`}const dr=yi.map(t=>"period_last"===t.name?{...t,default:Ji.last}:"period_unit"===t.name?{...t,default:Ji.unit}:"group_by"===t.name||"aggregate"===t.name?{...t,default:"auto"}:t),hr=[...dr,{name:"stack",path:["stack"],default:"none"},{name:"color_by",path:["color_by"],default:"series"},{name:"range",path:["range"],default:!1},{name:"column_labels",path:["labels"],default:!1},{name:"rounded",path:["rounded"],default:!0},...xi,...bi];const ur=[{name:"column_color",path:["color"]}],pr=r` + style="left:${lr(e-.1*n,wo)};width:${lr(1.2*n,wo)};top:${lr(i,ko)}" + >
`}const pr=_i.map(t=>"period_last"===t.name?{...t,default:Ji.last}:"period_unit"===t.name?{...t,default:Ji.unit}:"group_by"===t.name||"aggregate"===t.name?{...t,default:"auto"}:t),mr=[...pr,{name:"stack",path:["stack"],default:"none"},{name:"color_by",path:["color_by"],default:"series"},{name:"range",path:["range"],default:!1},{name:"column_labels",path:["labels"],default:!1},{name:"rounded",path:["rounded"],default:!0},...xi,...bi];const fr=[{name:"column_color",path:["color"]}],gr=r` .columns { position: absolute; inset: 0; @@ -750,36 +773,51 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt .axes-inside .x-axis { z-index: 1; } -`,mr={layout:"chart",group:"history",height:240,styles:r` +`,_r={layout:"chart",group:"history",height:240,styles:r` ${zo} - ${Wo} + ${Zo} ${fi} ${Jo} - ${pr} + ${gr} `,thumbnail:()=>I` - `,validate:function(t){if(void 0!==t.group_by&&!(t=>Gi.includes(t))(t.group_by))throw new Error(`"group_by" must be one of: ${Gi.join(", ")}`);if(void 0!==t.aggregate&&!Xi.includes(t.aggregate))throw new Error(`"aggregate" must be one of: ${Xi.join(", ")}`);const e={...t};"auto"!==t.group_by&&"none"!==t.group_by||delete e.group_by,"auto"===t.aggregate&&delete e.aggregate,Co(e),rn(t),ci(t),qo(t),Qo(t);for(const n of["range","rounded","labels"])if(void 0!==t[n]&&"boolean"!=typeof t[n])throw new Error(`"${n}" must be true or false`);if(void 0!==t.color_by&&"series"!==t.color_by&&"bands"!==t.color_by)throw new Error('"color_by" must be one of: series, bands')},editor:function(t){const e="none"===t.config.group_by,n={...t.config,group_by:void 0},o=Mi(`column|${_i(n)}|${e}`,t.hass,()=>[...vi(t.hass,n).slice(0,-1),{type:"grid",name:"",schema:[{name:"group_by",selector:gi(t.hass,"group_by",Gi)},...e?[]:[{name:"aggregate",selector:gi(t.hass,"aggregate",Xi)}]]},{type:"grid",name:"",schema:[{name:"stack",selector:gi(t.hass,"stack",Ko)},{name:"color_by",selector:gi(t.hass,"color_by",["series","bands"])}]},{type:"grid",name:"",schema:[{name:"range",selector:{boolean:{}}},{name:"column_labels",selector:{boolean:{}}},{name:"rounded",selector:{boolean:{}}}]},...wi(t.hass),...$i(t.hass)]);return Ai({...t,commit:e=>t.commit(function(t){const e=t.period;return e&&"object"==typeof e&&void 0===e.calendar?void 0!==e.last&&void 0!==e.unit?t:{...t,period:{last:Ji.last,unit:Ji.unit,...e}}:t}(e))},"chart",o,hr)},entityFields:t=>({schema:Mi("column-entity",t,()=>[{name:"column_color",selector:{text:{}}}]),fields:ur}),disconnect(t){No(t),Do(t),si(t)},render:function(t){const e={...t,raw:tr(t.raw,t.items)},n=e.raw,o=!0===n.range,i=So(e,Date.now(),{range:o}),r=To(i,e),a=Uo(i,e),s=r===Z&&a===Z?Z:B`${r}${a}`,l=jo(i,e),c=Yo(n);if(l)return Go("over"===c.header?{...c,header:"above"}:c,s,l);const d=o?"none":n.stack??"none",h=i.group,u=function(t,e){const n=[...new Set(t.flatMap(t=>t.map(t=>t.t)))].sort((t,e)=>t-e),o=t.map(t=>new Map(t.map(t=>[t.t,t]))),i=new Map;for(const a of t)for(const t of a)void 0!==t.end&&i.set(t.t,t.end);const r={times:[],ends:[],values:t.map(()=>[]),lows:t.map(()=>[]),highs:t.map(()=>[])};return n.forEach((a,s)=>{const l=Math.min(i.get(a)??n[s+1]??e,e);l>a&&(r.times.push(a),r.ends.push(l),t.forEach((t,e)=>{const n=o[e].get(a);r.values[e].push(n?n.v:ti(t,a)),r.lows[e].push(n?.min??null),r.highs[e].push(n?.max??null)}))}),r}(i.series.map(t=>t.points),h?1/0:i.range.end),p=h&&u.ends.length?{...i.range,end:Math.max(i.range.end,...u.ends)}:i.range,m="none"===d?void 0:ei(u.values,d),f=i.series.map(t=>t.entity.target).filter(t=>null!==t);let g;g=m?oi(m):o?nr([...u.lows.flat(),...u.highs.flat(),...u.values.flat(),...f],!1):nr([...u.values.flat(),...e.config.show.target?f:[]]);let y=n;"percent"===d?y={y_min:g[0]<0?-100:0,y_max:g[1]>0?100:0,...n}:!o&&g&&(y=function(t,e){const n={...e};return void 0===e.y_min&&t[0]>=0&&(n.y_min=0),void 0===e.y_max&&t[1]<=0&&(n.y_max=0),n}(g,n));let _=Vo({...e,raw:y},p,g);const{scales:v}=_,b=u.times.map((t,e)=>(t+u.ends[e])/2),$=new Map(b.map((t,e)=>[t,e]));if(h&&b.length){const t=(x=b.length,w=Ro(e)/or[h.unit],Math.max(1,Math.ceil(x/Math.max(1,w)))),n=ir[h.unit],o="day"===h.unit&&b.length<=8?6048e5:i.range.end-i.range.start;_={..._,unit:n,times:b.filter((e,n)=>n%t===0),label:t=>Mn(u.times[$.get(t)],n,o,e.hass)}}var x,w;const k=function(t,e,n,o,i,r){const a=t.raw,s=e.series,l=s.length,c=!0===a.range,d="bands"===a.color_by,h=Ro(t)/wo,u=!0===a.labels&&"percent"!==i&&n.times.length*(r?1:l)<=60,p=t.config.show.target&&"percent"!==i,m=Math.min(Math.max(0,o.domain[0]),o.domain[1]),f=(t,e)=>d?Et(Lt(e,t.entity.bands).color):t.color,g={columns:[],labels:[],targets:[]},y=r?ni(n.values):[];return n.times.forEach((e,i)=>{const a=o.x(e),d=o.x(n.ends[i]);if(r){const[e,l]=er(a,d,0,1);let c=-1,m=-1;r.forEach((t,e)=>{const n=t[i];n&&n[1]>n[0]&&(c=e),n&&n[1]{const a=t[i];if(!a||a[0]===a[1])return;const d=n.values[r][i],h=r===c?"top":r===m?"bottom":"";g.columns.push(sr(o,e,l,Math.min(...a),Math.max(...a),f(s[r],d),h,r))});const _=y[i];if(u&&null!==_&&l*h>=24){const n=_>=0?Math.max(0,...r.map(t=>t[i]?.[1]??0)):Math.min(0,...r.map(t=>t[i]?.[1]??0)),a=Math.max(...s.map(t=>t.entity.decimals));g.labels.push(lr(t,e+l/2,o.y(n),_,a,_<0))}const v=s[0].entity.target;return void(p&&null!==v&&g.targets.push(cr(o,e,l,v)))}s.forEach((e,r)=>{const s=n.values[r][i];if(null===s)return;const[y,_]=er(a,d,r,l);if(c){const t=n.lows[r][i]??s,a=n.highs[r][i]??s;g.columns.push(sr(o,y,_,t,a,f(e,s),"both",r)),g.columns.push(B`
`,validate:function(t){if(void 0!==t.group_by&&!(t=>Gi.includes(t))(t.group_by))throw new Error(`"group_by" must be one of: ${Gi.join(", ")}`);if(void 0!==t.aggregate&&!Xi.includes(t.aggregate))throw new Error(`"aggregate" must be one of: ${Xi.join(", ")}`);const e={...t};"auto"!==t.group_by&&"none"!==t.group_by||delete e.group_by,"auto"===t.aggregate&&delete e.aggregate,Eo(e),rn(t),ci(t),qo(t),Qo(t);for(const n of["range","rounded","labels"])if(void 0!==t[n]&&"boolean"!=typeof t[n])throw new Error(`"${n}" must be true or false`);if(void 0!==t.color_by&&"series"!==t.color_by&&"bands"!==t.color_by)throw new Error('"color_by" must be one of: series, bands')},editor:function(t){const e="none"===t.config.group_by,n={...t.config,group_by:void 0},o=Mi(`column|${yi(n)}|${e}`,t.hass,()=>[...vi(t.hass,n).slice(0,-1),{type:"grid",name:"",schema:[{name:"group_by",selector:gi(t.hass,"group_by",Gi)},...e?[]:[{name:"aggregate",selector:gi(t.hass,"aggregate",Xi)}]]},{type:"grid",name:"",schema:[{name:"stack",selector:gi(t.hass,"stack",Ko)},{name:"color_by",selector:gi(t.hass,"color_by",["series","bands"])}]},{type:"grid",name:"",schema:[{name:"range",selector:{boolean:{}}},{name:"column_labels",selector:{boolean:{}}},{name:"rounded",selector:{boolean:{}}}]},...wi(t.hass),...$i(t.hass)]);return Ai({...t,commit:e=>t.commit(function(t){const e=t.period;return e&&"object"==typeof e&&void 0===e.calendar?void 0!==e.last&&void 0!==e.unit?t:{...t,period:{last:Ji.last,unit:Ji.unit,...e}}:t}(e))},"chart",o,mr)},entityFields:t=>({schema:Mi("column-entity",t,()=>[{name:"column_color",selector:{text:{}}}]),fields:fr}),disconnect(t){No(t),Do(t),si(t)},render:function(t){const e={...t,raw:er(t.raw,t.items)},n=e.raw,o=!0===n.range,i=Co(e,Date.now(),{range:o}),r=Lo(i,e),a=jo(i,e),s=r===W&&a===W?W:B`${r}${a}`,l=Uo(i,e),c=Yo(n);if(l)return Go("over"===c.header?{...c,header:"above"}:c,s,l);const d=o?"none":n.stack??"none",h=i.group,u=nr(i.series.map(t=>t.points),h?1/0:i.range.end),p=h&&u.ends.length?{...i.range,end:Math.max(i.range.end,...u.ends)}:i.range,m="none"===d?void 0:ei(u.values,d),f=i.series.map(t=>t.entity.target).filter(t=>null!==t);let g;g=m?oi(m):o?ir([...u.lows.flat(),...u.highs.flat(),...u.values.flat(),...f],!1):ir([...u.values.flat(),...e.config.show.target?f:[]]);let _=n;"percent"===d?_={y_min:g[0]<0?-100:0,y_max:g[1]>0?100:0,...n}:!o&&g&&(_=function(t,e){const n={...e};return void 0===e.y_min&&t[0]>=0&&(n.y_min=0),void 0===e.y_max&&t[1]<=0&&(n.y_max=0),n}(g,n));let y=Ro({...e,raw:_},p,g);const{scales:v}=y,b=u.times.map((t,e)=>(t+u.ends[e])/2),$=new Map(b.map((t,e)=>[t,e]));if(h&&b.length){const t=(x=b.length,w=Vo(e)/rr[h.unit],Math.max(1,Math.ceil(x/Math.max(1,w)))),n=ar[h.unit],o="day"===h.unit&&b.length<=8?6048e5:i.range.end-i.range.start;y={...y,unit:n,times:b.filter((e,n)=>n%t===0),label:t=>Mn(u.times[$.get(t)],n,o,e.hass)}}var x,w;const k=function(t,e,n,o,i,r){const a=t.raw,s=e.series,l=s.length,c=!0===a.range,d="bands"===a.color_by,h=Vo(t)/wo,u=!0===a.labels&&"percent"!==i&&n.times.length*(r?1:l)<=60,p=t.config.show.target&&"percent"!==i,m=Math.min(Math.max(0,o.domain[0]),o.domain[1]),f=(t,e)=>d?St(Tt(e,t.entity.bands).color):t.color,g={columns:[],labels:[],targets:[]},_=r?ni(n.values):[];return n.times.forEach((e,i)=>{const a=o.x(e),d=o.x(n.ends[i]);if(r){const[e,l]=or(a,d,0,1);let c=-1,m=-1;r.forEach((t,e)=>{const n=t[i];n&&n[1]>n[0]&&(c=e),n&&n[1]{const a=t[i];if(!a||a[0]===a[1])return;const d=n.values[r][i],h=r===c?"top":r===m?"bottom":"";g.columns.push(dr(o,e,l,Math.min(...a),Math.max(...a),f(s[r],d),h,r))});const y=_[i];if(u&&null!==y&&l*h>=24){const n=y>=0?Math.max(0,...r.map(t=>t[i]?.[1]??0)):Math.min(0,...r.map(t=>t[i]?.[1]??0)),a=Math.max(...s.map(t=>t.entity.decimals));g.labels.push(hr(t,e+l/2,o.y(n),y,a,y<0))}const v=s[0].entity.target;return void(p&&null!==v&&g.targets.push(ur(o,e,l,v)))}s.forEach((e,r)=>{const s=n.values[r][i];if(null===s)return;const[_,y]=or(a,d,r,l);if(c){const t=n.lows[r][i]??s,a=n.highs[r][i]??s;g.columns.push(dr(o,_,y,t,a,f(e,s),"both",r)),g.columns.push(B`
`)}else g.columns.push(sr(o,y,_,Math.min(m,s),Math.max(m,s),f(e,s),s>=m?"top":"bottom",r)),u&&_*h>=24&&g.labels.push(lr(t,y+_/2,o.y(s),s,e.entity.decimals,s({...t,points:b.map((t,n)=>({t:t,v:u.values[e][n],min:u.lows[e][n],max:u.highs[e][n]}))})),A={dotY:()=>null,heading:t=>{const n=$.get(t);return void 0===n?kn(t,e.hass):h?function(t,e,n,o){if("hour"===n)return`${kn(t,o)} – ${wn(e,o)}`;const i="day"===n?{weekday:"short",day:"numeric",month:"short"}:"week"===n?{day:"numeric",month:"short"}:{month:"long",year:"numeric"};let r;try{r=new Intl.DateTimeFormat(o?.locale?.language??"en",{...i,timeZone:vn(o)})}catch{r=new Intl.DateTimeFormat("en",i)}return"week"===n?r.formatRange(t,e-1):r.format(t)}(u.times[n],u.ends[n],h.unit,e.hass):kn(u.times[n],e.hass)}},C=(t,n)=>Po(t,n.entity.decimals,e.hass);if(o&&(A.text=(t,e)=>{if(!e||null===e.v)return"—";const n=e.min??e.v,o=e.max??e.v;return Ho(`${C(n,t)} – ${C(o,t)}`,t.entity.unit)}),m){const t=ni(u.values),n=ui(M),o=Math.max(...M.map(t=>t.entity.decimals));A.footer=i=>pi(e,t[$.get(i[0]?.p?.t??NaN)??-1]??null,n,o),"percent"===d&&(A.text=(t,e)=>{const n=e?m[t.index][$.get(e.t)??-1]:null;return e&&null!==e.v&&n?`${Ho(C(e.v,t),t.entity.unit)} · ${Math.round(Math.abs(n[1]-n[0]))} %`:"—"})}const S=li(n),E=S?ai(e.host):void 0,O=void 0===E?void 0:$.get(E),T=void 0===O?Z:B`
`)}else g.columns.push(dr(o,_,y,Math.min(m,s),Math.max(m,s),f(e,s),s>=m?"top":"bottom",r)),u&&y*h>=24&&g.labels.push(hr(t,_+y/2,o.y(s),s,e.entity.decimals,s({...t,points:b.map((t,n)=>({t:t,v:u.values[e][n],min:u.lows[e][n],max:u.highs[e][n]}))})),A={dotY:()=>null,heading:t=>{const n=$.get(t);return void 0===n?kn(t,e.hass):h?sr(u.times[n],u.ends[n],h.unit,e.hass):kn(u.times[n],e.hass)}},E=(t,n)=>Po(t,n.entity.decimals,e.hass);if(o&&(A.text=(t,e)=>{if(!e||null===e.v)return"—";const n=e.min??e.v,o=e.max??e.v;return Ho(`${E(n,t)} – ${E(o,t)}`,t.entity.unit)}),m){const t=ni(u.values),n=ui(M),o=Math.max(...M.map(t=>t.entity.decimals));A.footer=i=>pi(e,t[$.get(i[0]?.p?.t??NaN)??-1]??null,n,o),"percent"===d&&(A.text=(t,e)=>{const n=e?m[t.index][$.get(e.t)??-1]:null;return e&&null!==e.v&&n?`${Ho(E(e.v,t),t.entity.unit)} · ${Math.round(Math.abs(n[1]-n[0]))} %`:"—"})}const C=li(n),S=C?ai(e.host):void 0,O=void 0===S?void 0:$.get(S),L=void 0===O?W:B`
`,L=ne(e.hass,"chart_aria",{style:ne(e.hass,"editor_style_column"),names:i.series.map(t=>t.entity.name).join(", ")}),N=!1===n.rounded?0:4;return Go(c,s,Io({axes:_,ctx:e,content:I``,label:L,overlay:B`
${T}${k.columns}${k.targets}
+ style="left:${lr(v.x(u.times[O]),wo)};width:${lr(v.x(u.ends[O])-v.x(u.times[O]),wo)}" + >
`,T=ne(e.hass,"chart_aria",{style:ne(e.hass,"editor_style_column"),names:i.series.map(t=>t.entity.name).join(", ")}),N=!1===n.rounded?0:4;return Go(c,s,Io({axes:y,ctx:e,content:I``,label:T,overlay:B`
${L}${k.columns}${k.targets}
${k.labels}
- ${"over"===c.header?Xo(s):Z} - ${S?mi(e,M,v,E,Ro(e),A):Z}`,hover:S?di(e,p,M.map(t=>t.points)):void 0}))}},fr=["series","bands"];function gr(t,e,n){return B`
+ ${"over"===c.header?Xo(s):W} + ${C?mi(e,M,v,S,Vo(e),A):W}`,hover:C?di(e,p,M.map(t=>t.points)):void 0}))}},yr=["series","bands"];function vr(t,e,n,o,i){const r=se(t.entity.config,i),a=An(t.points,500),s=xo(a).map(n=>$o(n.map(t=>[e.x(t.t),e.y(t.v)]),t.curve)).join(""),l=r.dots?a.filter(t=>null!==t.v&&t.t!==o.start&&t.t!==o.end):[],c=l.length>0&&l.length<=200?I`[e.x(t.t),e.y(t.v)]))} + fill="none" + stroke=${n} + style="stroke-width:${de(r.width)}px" + >`:W;return I` + + ${c} + `}function br(t,e,n){return B`
${t.series.flatMap(o=>{const i=o.points.filter(e=>null!==e.v&&(void 0!==t.group||e.t!==t.range.start&&e.t!==t.range.end));return i.length>40?[]:i.map(t=>B`${Po(t.v,o.entity.decimals,n.hass)}`)})} -
`}te("en",{editor_style_line:"Line",chart_loading:"Loading history…",chart_error:"Couldn't load history: {error}",chart_no_data:"No readings in this period.",chart_aria:"{style} chart of {names}"});const yr={layout:"chart",group:"history",height:240,styles:r` +
`}te("en",{editor_style_line:"Line",chart_loading:"Loading history…",chart_error:"Couldn't load history: {error}",chart_no_data:"No readings in this period.",chart_aria:"{style} chart of {names}"});const $r={layout:"chart",group:"history",height:240,styles:r` ${zo} - ${Wo} + ${Zo} ${fi} ${Jo} .style-line .line { @@ -796,26 +834,41 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt `,validate(t){if(Co(t),rn(t),ci(t),pe(t),qo(t),void 0!==t.color_by&&!fr.includes(t.color_by))throw new Error(`"color_by" must be one of: ${fr.join(", ")}`)},editor:function(t){const e=Mi(`line|${_i(t.config)}`,t.hass,()=>[...vi(t.hass,t.config),{type:"grid",name:"",schema:[{name:"curve",selector:gi(t.hass,"curve",_o)},{name:"color_by",selector:gi(t.hass,"color_by",["series","bands"])}]},{type:"grid",name:"",schema:[{name:"line_width",selector:xe},{name:"dots",selector:{boolean:{}}}]},{name:"labels",selector:{boolean:{}}},...wi(t.hass),...$i(t.hass)]);return Ai(t,"chart",e,Ci)},entityFields:(t,e)=>({schema:Te(t),fields:ke(!0===e.dots)}),disconnect(t){No(t),Do(t),si(t)},render(t){const e=So(t),n=To(e,t),o=Uo(e,t),i=n===Z&&o===Z?Z:B`${n}${o}`,r=jo(e,t),a=Yo(t.raw);if(r)return Go("over"===a.header?{...a,header:"above"}:a,i,r);const s=Vo(t,e.range,Ge(e.series.map(t=>t.points))),{scales:l}=s,c=li(t.raw),d="bands"===t.raw.color_by,h=d?I`${e.series.map(t=>function(t,e,n){const[o,i]=n.domain,r=t=>Math.min(1,Math.max(0,(t-o)/(i-o))),a=[];return e.forEach((t,n)=>{const o=Number.isFinite(t.from)?r(t.from):0,i=n+1`)}),I` + stroke-width="2.5" stroke-linecap="round" stroke-dasharray="4 3" />`,validate(t){if(Eo(t),rn(t),ci(t),pe(t),qo(t),void 0!==t.color_by&&!yr.includes(t.color_by))throw new Error(`"color_by" must be one of: ${yr.join(", ")}`)},editor:function(t){const e=Mi(`line|${yi(t.config)}`,t.hass,()=>[...vi(t.hass,t.config),{type:"grid",name:"",schema:[{name:"curve",selector:gi(t.hass,"curve",yo)},{name:"color_by",selector:gi(t.hass,"color_by",["series","bands"])}]},{type:"grid",name:"",schema:[{name:"line_width",selector:xe},{name:"dots",selector:{boolean:{}}}]},{name:"labels",selector:{boolean:{}}},...wi(t.hass),...$i(t.hass)]);return Ai(t,"chart",e,Ei)},entityFields:(t,e)=>({schema:Le(t),fields:ke(!0===e.dots)}),disconnect(t){No(t),Do(t),si(t)},render(t){const e=Co(t),n=Lo(e,t),o=jo(e,t),i=n===W&&o===W?W:B`${n}${o}`,r=Uo(e,t),a=Yo(t.raw);if(r)return Go("over"===a.header?{...a,header:"above"}:a,i,r);const s=Ro(t,e.range,Ge(e.series.map(t=>t.points))),{scales:l}=s,c=li(t.raw),d="bands"===t.raw.color_by,h=d?I`${e.series.map(t=>function(t,e,n){const[o,i]=n.domain,r=t=>Math.min(1,Math.max(0,(t-o)/(i-o))),a=[];return e.forEach((t,n)=>{const o=Number.isFinite(t.from)?r(t.from):0,i=n+1`)}),I` ${a} - `}(`cd-bands-${t.index}`,t.entity.bands,l))}`:Z,u=le(e.series,e=>se(e.entity.config,t.raw).onTop),p=I`${u.map(n=>function(t,e,n,o,i){const r=se(t.entity.config,i),a=An(t.points,500),s=xo(a).map(n=>$o(n.map(t=>[e.x(t.t),e.y(t.v)]),t.curve)).join(""),l=r.dots?a.filter(t=>null!==t.v&&t.t!==o.start&&t.t!==o.end):[],c=l.length>0&&l.length<=200?I`[e.x(t.t),e.y(t.v)]))} - fill="none" - stroke=${n} - style="stroke-width:${de(r.width)}px" - >`:Z;return I` - - ${c} - `}(n,l,d?`url(#cd-bands-${n.index})`:n.color,e.range,t.raw))}`,m=ne(t.hass,"chart_aria",{style:ne(t.hass,"editor_style_line"),names:e.series.map(t=>t.entity.name).join(", ")});return Go(a,i,Io({axes:s,ctx:t,content:p,label:m,defs:h,overlay:B`${"over"===a.header?Xo(i):Z} - ${!0===t.raw.labels?gr(e,l,t):Z} - ${c?mi(t,e.series,l,ai(t.host),Ro(t)):Z}`,hover:c?di(t,e.range,e.series.map(t=>t.points)):void 0}))}},_r=t=>(Math.abs(t)<.005?0:t).toFixed(2);function vr(t,e,n,o){const i=o*Math.PI/180;return[t+n*Math.sin(i),e-n*Math.cos(i)]}function br(t,e,n,o,i){const r=String(Number(n.toFixed(2))),a=i-o,[s,l]=vr(t,e,n,o);if(a>=359.99){const[i,a]=vr(t,e,n,o+180);return`M${_r(s)} ${_r(l)} A${r} ${r} 0 1 1 ${_r(i)} ${_r(a)} A${r} ${r} 0 1 1 ${_r(s)} ${_r(l)}`}const[c,d]=vr(t,e,n,i),h=a>180?1:0;return`M${_r(s)} ${_r(l)} A${r} ${r} 0 ${h} 1 ${_r(c)} ${_r(d)}`}function $r(t,e){const n=t/2;return[-n+e[0]*t,-n+e[1]*t]}function xr(t){let e=0;for(const n of t)e+=n.codePointAt(0)>=11904?1/.58:1;return e}function wr(t,e=76,n=12,o=8,i=11){const r=t.trim();let a=[r];if(xr(r)>i){let t=xr(r);for(let e=r.indexOf(" ");e>0;e=r.indexOf(" ",e+1)){const n=Math.max(xr(r.slice(0,e)),xr(r.slice(e+1)));nString(Math.round(1e3*t)/1e3+0);function Cr(t,e,n,o,i,r=11){const{lines:a,size:s}=wr(t,e,n,o,r),l=i-1.2*(a.length-1)*s;return I`${a.map((t,e)=>I`${t}`)}`}const Sr={layout:"tiles",group:"gauges",height:140,minColumnWidth:134,styles:r` + `}(`cd-bands-${t.index}`,t.entity.bands,l))}`:W,u=le(e.series,e=>se(e.entity.config,t.raw).onTop),p=I`${u.map(n=>vr(n,l,d?`url(#cd-bands-${n.index})`:n.color,e.range,t.raw))}`,m=ne(t.hass,"chart_aria",{style:ne(t.hass,"editor_style_line"),names:e.series.map(t=>t.entity.name).join(", ")});return Go(a,i,Io({axes:s,ctx:t,content:p,label:m,defs:h,overlay:B`${"over"===a.header?Xo(i):W} + ${!0===t.raw.labels?br(e,l,t):W} + ${c?mi(t,e.series,l,ai(t.host),Vo(t)):W}`,hover:c?di(t,e.range,e.series.map(t=>t.points)):void 0}))}},xr=["line","column","area"],wr=["auto","left","right"];te("en",{editor_style_combined:"Combined",editor_series_type:"Draw as",editor_series_type_line:"Line",editor_series_type_column:"Columns",editor_series_type_area:"Area",editor_series_axis:"Value axis",editor_series_axis_auto:"Automatic (by unit)",editor_series_axis_left:"Left",editor_series_axis_right:"Right",editor_series_aggregate:"Combine with",editor_series_aggregate_auto:"As the card",editor_series_aggregate_mean:"Average",editor_series_aggregate_sum:"Sum",editor_series_aggregate_min:"Lowest",editor_series_aggregate_max:"Highest",editor_series_aggregate_first:"First",editor_series_aggregate_last:"Last",editor_series_aggregate_change:"Change (meters that count up)"});const kr=t=>t.config,Mr=t=>kr(t).type??"line";function Ar(t,e){const n={...t},o=e.some(t=>"column"===Mr(t));return"none"!==t.group_by&&(void 0!==t.group_by&&"auto"!==t.group_by||o)?void 0!==t.group_by&&"auto"!==t.group_by||(n.group_by=Qi(qn(t.period))):delete n.group_by,"auto"===t.aggregate&&delete n.aggregate,n}function Er(t,e){const n=t.flatMap(t=>t.points.map(t=>t.v));return ir(n,e.includes("column"))}const Cr=[..._i.map(t=>"group_by"===t.name||"aggregate"===t.name?{...t,default:"auto"}:t),{name:"curve",path:["curve"],default:"smooth"},{name:"line_width",path:["line_width"],default:2.5},{name:"dots",path:["dots"],default:!1},{name:"rounded",path:["rounded"],default:!0},...xi,...bi];const Sr=[{name:"series_type",path:["type"],default:"line"},{name:"series_axis",path:["y_axis"],default:"auto"},{name:"series_color",path:["color"]},{name:"series_aggregate",path:["aggregate"],default:"auto"},{name:"curve",path:["curve"]},{name:"line_width",path:["line_width"]},{name:"dash",path:["dash"],default:!1},{name:"negative_color",path:["negative_color"]}],Or={layout:"chart",group:"history",height:240,styles:r` + ${zo} + ${Zo} + ${fi} + ${Jo} + ${zi} + ${gr} + .lines-over { + pointer-events: none; + } + .lines-over .line { + stroke-linecap: round; + stroke-linejoin: round; + } + .lines-over .dots { + stroke-linecap: round; + } + .lines-over .line.dashed { + stroke-dasharray: 6 5; + } + `,thumbnail:()=>I` + + + + `,validate:function(t){if(void 0!==t.group_by&&!Gi.includes(t.group_by))throw new Error(`"group_by" must be one of: ${Gi.join(", ")}`);if(void 0!==t.aggregate&&!Xi.includes(t.aggregate))throw new Error(`"aggregate" must be one of: ${Xi.join(", ")}`);const e={...t};if("auto"!==t.group_by&&"none"!==t.group_by||delete e.group_by,"auto"===t.aggregate&&delete e.aggregate,Eo(e),lo(e),rn(t),ci(t),pe(t),qo(t),void 0!==t.rounded&&"boolean"!=typeof t.rounded)throw new Error('"rounded" must be true or false');for(const n of t.entities??[]){if("object"!=typeof n)continue;const t=n;if(void 0!==t.type&&!xr.includes(t.type))throw new Error(`"type" of ${n.entity} must be one of: ${xr.join(", ")}`);if(void 0!==t.y_axis&&"left"!==t.y_axis&&"right"!==t.y_axis)throw new Error(`"y_axis" of ${n.entity} must be one of: left, right`);if(void 0!==t.aggregate&&!so.includes(t.aggregate))throw new Error(`"aggregate" of ${n.entity} must be one of: ${so.join(", ")}`)}},editor:function(t){const e="none"===t.config.group_by,n={...t.config,group_by:void 0},o=Mi(`combined|${yi(n)}|${e}`,t.hass,()=>[...vi(t.hass,n).slice(0,-1),{type:"grid",name:"",schema:[{name:"group_by",selector:gi(t.hass,"group_by",Gi)},...e?[]:[{name:"aggregate",selector:gi(t.hass,"aggregate",Xi)}]]},{name:"curve",selector:gi(t.hass,"curve",yo)},{type:"grid",name:"",schema:[{name:"line_width",selector:xe},{name:"dots",selector:{boolean:{}}},{name:"rounded",selector:{boolean:{}}}]},...wi(t.hass),...$i(t.hass)]);return Ai(t,"chart",o,Cr)},entityFields:t=>({schema:Mi("combined-entity",t,()=>[{type:"grid",name:"",schema:[{name:"series_type",selector:gi(t,"series_type",xr)},{name:"series_axis",selector:gi(t,"series_axis",wr)},{name:"series_color",selector:{text:{}}},{name:"series_aggregate",selector:gi(t,"series_aggregate",["auto",...so])}]},{type:"grid",name:"",schema:[{name:"curve",selector:gi(t,"curve",yo)},{name:"line_width",selector:xe},{name:"dash",selector:{boolean:{}}},{name:"negative_color",selector:{text:{}}}]}]),fields:Sr}),disconnect(t){No(t),Do(t),si(t)},render:function(t){const e={...t,raw:Ar(t.raw,t.items)},n=e.raw,o=Co(e,Date.now(),{aggregate:e=>function(t,e){const n=e.aggregate;return kr(t).aggregate??(n&&"auto"!==n?n:tr(t)?"change":"mean")}(e,t.raw)}),i=Lo(o,e),r=jo(o,e),a=i===W&&r===W?W:B`${i}${r}`,s=Uo(o,e),l=Yo(n);if(s)return Go("over"===l.header?{...l,header:"above"}:l,a,s);const c=o.series.map(t=>Mr(t.entity)),d=function(t){const e=t[0]?.unit,n=t.map(t=>kr(t).y_axis??(t.unit===e?"left":"right"));return n.includes("left")?n:n.map(()=>"left")}(o.series.map(t=>t.entity)),h=o.group,u=o.series.map(t=>h?{...t,points:t.points.map(t=>({...t,t:void 0!==t.end?(t.t+t.end)/2:t.t}))}:t),p=h?Math.max(o.range.end,...o.series.flatMap(t=>t.points.map(t=>t.end??0))):0,m=h?{...o.range,end:p}:o.range,f=t=>u.filter((e,n)=>d[n]===t),g=t=>c.filter((e,n)=>d[n]===t),_=Er(f("left"),g("left"));let y=n;_&&g("left").includes("column")?y={...n,y_min:n.y_min??(_[0]>=0?0:void 0),y_max:n.y_max??(_[1]<=0?0:void 0)}:g("left").includes("area")&&(y=Ci(_,n));const v=Ro({...e,raw:y},m,_),b=v.scales,$=f("right"),x=Er($,g("right")),w={};x&&(g("right").includes("column")||g("right").includes("area"))&&(x[0]>=0&&x[0]<=x[1]/2&&(w.min=0),x[1]<=0&&x[1]>=x[0]/2&&(w.max=0));const k=$.length?cn(x,w,4):void 0,M=k?{x:b.x,y:Xe(k.domain,[ko,0]),domain:k.domain}:void 0,A=t=>"right"===d[t.index]&&M?M:b,E=u.filter(t=>"area"===c[t.index]).map(t=>Ti(t,t.points,A(t),n,{range:m})),C=u.filter(t=>"line"===c[t.index]).map(t=>vr({...t,points:t.points},A(t),t.color,m,n)),S=u.filter(t=>"column"===c[t.index]),O=nr(o.series.filter(t=>"column"===c[t.index]).map(t=>t.points),h?1/0:o.range.end),L=!1===n.rounded?0:4,T=[];O.times.forEach((t,e)=>{const n=b.x(t),o=b.x(O.ends[e]);S.forEach((t,i)=>{const r=O.values[i][e];if(null===r)return;const a=A(t),s=Math.min(Math.max(0,a.domain[0]),a.domain[1]),[l,c]=or(n,o,i,S.length);T.push(dr(a,l,c,Math.min(s,r),Math.max(s,r),t.color,r>=s?"top":"bottom",t.index))})});const N=O.times.map((t,e)=>(t+O.ends[e])/2),j=u.map(t=>{if("column"!==c[t.index]||h)return t;const e=S.indexOf(t);return{...t,points:N.map((t,n)=>({t:t,v:O.values[e][n]}))}}),U=new Map;for(const H of o.series)for(const t of H.points)void 0!==t.end&&U.set((t.t+t.end)/2,[t.t,t.end]);const z=li(n),P=ne(e.hass,"chart_aria",{style:ne(e.hass,"editor_style_combined"),names:o.series.map(t=>t.entity.name).join(", ")});return Go(l,a,Io({axes:v,ctx:e,right:k&&M?{value:k,y:M.y}:void 0,content:I`${E.map(t=>t.body)}`,defs:I`${E.map(t=>t.defs)}`,label:P,overlay:B`
${T}
+ + ${"over"===l.header?Xo(a):W} + ${z?mi(e,j,b,ai(e.host),Vo(e),{dotY:(t,e)=>"column"===c[t.index]||null===e.v?null:A(t).y(e.v),heading:t=>{const n=U.get(t);return n&&h?sr(n[0],n[1],h.unit,e.hass):kn(t,e.hass)}}):W}`,hover:z?di(e,m,j.map(t=>t.points)):void 0}))}},Lr=t=>(Math.abs(t)<.005?0:t).toFixed(2);function Tr(t,e,n,o){const i=o*Math.PI/180;return[t+n*Math.sin(i),e-n*Math.cos(i)]}function Nr(t,e,n,o,i){const r=String(Number(n.toFixed(2))),a=i-o,[s,l]=Tr(t,e,n,o);if(a>=359.99){const[i,a]=Tr(t,e,n,o+180);return`M${Lr(s)} ${Lr(l)} A${r} ${r} 0 1 1 ${Lr(i)} ${Lr(a)} A${r} ${r} 0 1 1 ${Lr(s)} ${Lr(l)}`}const[c,d]=Tr(t,e,n,i),h=a>180?1:0;return`M${Lr(s)} ${Lr(l)} A${r} ${r} 0 ${h} 1 ${Lr(c)} ${Lr(d)}`}function jr(t,e){const n=t/2;return[-n+e[0]*t,-n+e[1]*t]}function Ur(t){let e=0;for(const n of t)e+=n.codePointAt(0)>=11904?1/.58:1;return e}function zr(t,e=76,n=12,o=8,i=11){const r=t.trim();let a=[r];if(Ur(r)>i){let t=Ur(r);for(let e=r.indexOf(" ");e>0;e=r.indexOf(" ",e+1)){const n=Math.max(Ur(r.slice(0,e)),Ur(r.slice(e+1)));nString(Math.round(1e3*t)/1e3+0);function Dr(t,e,n,o,i,r=11){const{lines:a,size:s}=zr(t,e,n,o,r),l=i-1.2*(a.length-1)*s;return I`${a.map((t,e)=>I`${t}`)}`}const Vr={layout:"tiles",group:"gauges",height:140,minColumnWidth:134,styles:r` /* A definite width that shrinks with a narrow tile (the svg inside is sized in %). */ .needle-gauge { display: flex; @@ -891,24 +944,24 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt text-overflow: ellipsis; white-space: nowrap; } - `,render(t,{show:e,hass:n}){const o=function(t,e,n){const o=n-e,i=[];return o>0?(t.forEach((r,a)=>{const s=0===a?e:Math.max(r.from,e),l=Math.min(a+1s&&i.push({from:(s-e)/o,to:(l-e)/o,color:r.color})}),i):i}(t.bands,t.min,t.max),i=o.map((t,e)=>{const n=180*t.from-90+(e>0?1:0),i=180*t.to-90-(en?I``:Z}),r=Array.from({length:11},(t,e)=>{const[n,o]=vr(kr,Mr,36,18*e-90),[i,r]=vr(kr,Mr,40,18*e-90);return I``});let a=Z;if(e.target&&null!==t.targetPosition&&t.available){const e=180*t.targetPosition-90,[n,o]=vr(kr,Mr,57,e),[i,r]=vr(kr,Mr,64,e-3),[s,l]=vr(kr,Mr,64,e+3);a=I``}const s=!e.value;return B`
+ `,render(t,{show:e,hass:n}){const o=function(t,e,n){const o=n-e,i=[];return o>0?(t.forEach((r,a)=>{const s=0===a?e:Math.max(r.from,e),l=Math.min(a+1s&&i.push({from:(s-e)/o,to:(l-e)/o,color:r.color})}),i):i}(t.bands,t.min,t.max),i=o.map((t,e)=>{const n=180*t.from-90+(e>0?1:0),i=180*t.to-90-(en?I``:W}),r=Array.from({length:11},(t,e)=>{const[n,o]=Tr(Pr,Hr,36,18*e-90),[i,r]=Tr(Pr,Hr,40,18*e-90);return I``});let a=W;if(e.target&&null!==t.targetPosition&&t.available){const e=180*t.targetPosition-90,[n,o]=Tr(Pr,Hr,57,e),[i,r]=Tr(Pr,Hr,64,e-3),[s,l]=Tr(Pr,Hr,64,e+3);a=I``}const s=!e.value;return B`
${e.name||e.icon?B`
${e.icon?B``:Z} - ${e.name?B`${t.name}`:Z} -
`:Z} -
`;var l,c,d,h,u}};let Er=0;const Or=new WeakMap;const Tr=60,Lr=60,Nr=t=>String(Math.round(1e3*t)/1e3+0);function Ur(t){const[e,n]=$r(t,[0,1]),o=br(Tr,Lr,46,e,n),i=t<360;return{layout:"tiles",group:"gauges",height:i?135:155,minColumnWidth:128,styles:r` + .icon=${Vi(t)} + >`:W} + ${e.name?B`${t.name}`:W} +
`:W} + `;var l,c,d,h,u}};let Rr=0;const Br=new WeakMap;const Ir=60,Zr=60,Wr=t=>String(Math.round(1e3*t)/1e3+0);function qr(t){const[e,n]=jr(t,[0,1]),o=Nr(Ir,Zr,46,e,n),i=t<360;return{layout:"tiles",group:"gauges",height:i?135:155,minColumnWidth:128,styles:r` /* A definite width: the dial is a size container and can't size the tile itself. */ .radial { display: flex; @@ -1008,7 +1061,7 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt text-overflow: ellipsis; white-space: nowrap; } - `,render(e,{show:n,hass:r}){const a=function(t){let e=Or.get(t);return e||(e="cd-g-"+ ++Er,Or.set(t,e)),e}(e.config),s=e.span[1]-e.span[0]<=0,l=`stroke-dasharray: ${Nr(100*(e.span[1]-e.span[0]))} 100; stroke-dashoffset: ${Nr(100*-e.span[0])}`,c=(d=e.band.color,Object.prototype.hasOwnProperty.call(St,d)?St[d].fallback:d);var d;const h=function(t){return!t.includes("var(")&&("undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("color",t))}(c)?`url(#${a}) ${c}`:`url(#${a})`,u=n.icon?6:0,p=(m=e.valueText,Math.min(22,Math.floor(124/Math.max(1,m.length))));var m;let f=Z;if(n.target&&null!==e.targetPosition&&e.available){const n=$r(t,[e.targetPosition,e.targetPosition])[0],[o,i]=vr(Tr,Lr,39.5,n),[r,a]=vr(Tr,Lr,52.5,n);f=I``}return B`
+ `,render(e,{show:n,hass:r}){const a=function(t){let e=Br.get(t);return e||(e="cd-g-"+ ++Rr,Br.set(t,e)),e}(e.config),s=e.span[1]-e.span[0]<=0,l=`stroke-dasharray: ${Wr(100*(e.span[1]-e.span[0]))} 100; stroke-dashoffset: ${Wr(100*-e.span[0])}`,c=(d=e.band.color,Object.prototype.hasOwnProperty.call(Ct,d)?Ct[d].fallback:d);var d;const h=function(t){return!t.includes("var(")&&("undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("color",t))}(c)?`url(#${a}) ${c}`:`url(#${a})`,u=n.icon?6:0,p=(m=e.valueText,Math.min(22,Math.floor(124/Math.max(1,m.length))));var m;let f=W;if(n.target&&null!==e.targetPosition&&e.available){const n=jr(t,[e.targetPosition,e.targetPosition])[0],[o,i]=Tr(Ir,Zr,39.5,n),[r,a]=Tr(Ir,Zr,52.5,n);f=I``}return B`
${n.icon&&e.available?B``:Z} + .icon=${Vi(e)} + >`:W}
- ${n.name?B`${e.name}`:Z} -
`}}}const jr=Ur(360),zr=Ur(270);function Pr(t){const[e,n]=t;return Array.from({length:10},(t,o)=>{const i=(o+.5)/10;return i>e&&i<=n})}const Hr={layout:"rows",group:"bars",height:50,minColumnWidth:180,styles:r` + ${n.name?B`${e.name}`:W} +
`}}}const Yr=qr(360),Gr=qr(270);function Xr(t){const[e,n]=t;return Array.from({length:10},(t,o)=>{const i=(o+.5)/10;return i>e&&i<=n})}const Jr={layout:"rows",group:"bars",height:50,minColumnWidth:180,styles:r` /* Each row is measured on its own, so a narrow column (columns: 2 or 3) switches layout even when the card as a whole is wide. A container can't restyle itself, hence .seg. */ .style-segmented .entity { @@ -1160,24 +1213,24 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt padding-bottom: 0; } } - `,render(t,{show:e,hass:n}){const o=t.available?Pr(t.span):Pr([0,0]),i=e.target&&t.available&&null!==t.targetPosition?Math.min(9,Math.max(0,Math.floor(10*t.targetPosition))):-1,r=!t.available;return B`
+ `,render(t,{show:e,hass:n}){const o=t.available?Xr(t.span):Xr([0,0]),i=e.target&&t.available&&null!==t.targetPosition?Math.min(9,Math.max(0,Math.floor(10*t.targetPosition))):-1,r=!t.available;return B`
${e.icon?B``:Z} + .icon=${Vi(t)} + >`:W}
${e.name||r?B`
- ${e.name?B`${t.name}`:Z} - ${r?B`${t.display}`:Z} -
`:Z} + ${e.name?B`${t.name}`:W} + ${r?B`${t.display}`:W} +
`:W}
${o.map((t,e)=>B``)}
- ${e.value?B`${t.available?t.display:""}`:Z} -
`}},Fr={layout:"tiles",group:"bars",height:230,tilesPerRow:4,minColumnWidth:80,styles:r` + ${e.value?B`${t.available?t.display:""}`:W} + `}},Kr={layout:"tiles",group:"bars",height:230,tilesPerRow:4,minColumnWidth:80,styles:r` .style-tank .entity { display: flex; flex-direction: column; @@ -1244,15 +1297,15 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt class="icon" .hass=${n} .stateObj=${t.stateObj} - .icon=${Ri(t)} - >`:Z} - ${e.value||!t.available?B`${t.display}`:Z} + .icon=${Vi(t)} + >`:W} + ${e.value||!t.available?B`${t.display}`:W}
- ${e.target&&null!==t.targetPosition&&t.available?B`
`:Z} + ${e.target&&null!==t.targetPosition&&t.available?B`
`:W}
- ${e.name?B`${t.name}`:Z} - `},Dr={layout:"rows",group:"bars",height:44,minColumnWidth:140,styles:r` + ${e.name?B`${t.name}`:W} + `},Qr={layout:"rows",group:"bars",height:44,minColumnWidth:140,styles:r` .style-thin .entity { display: flex; align-items: center; @@ -1323,25 +1376,25 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt class="icon" .hass=${n} .stateObj=${t.stateObj} - .icon=${Ri(t)} - >`:Z} + .icon=${Vi(t)} + >`:W}
${e.name||o?B`
- ${e.name?B`${t.name}`:Z} - ${o?B`${t.display}`:Z} -
`:Z} + ${e.name?B`${t.name}`:W} + ${o?B`${t.display}`:W} +
`:W}
- ${e.target&&null!==t.targetPosition&&t.available?B`
`:Z} + ${e.target&&null!==t.targetPosition&&t.available?B`
`:W}
- `}},Rr=["bars","gauges","history","totals","compare","distribution"];function Vr(t){return"chart"===t.layout}const Br={bar:Yi,thin:Dr,segmented:Hr,tank:Fr,ring:jr,needle:Sr,arc:zr,line:yr,column:mr,area:Pi},Ir="important",Wr=" !"+Ir,Zr=mt(class extends ft{constructor(t){if(super(t),t.type!==dt||"style"!==t.name||t.strings?.length>2)throw Error("The `styleMap` directive must be used in the `style` attribute and must be the only part in the attribute.")}render(t){return Object.keys(t).reduce((e,n)=>{const o=t[n];return null==o?e:e+`${n=n.includes("-")?n:n.replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g,"-$&").toLowerCase()}:${o};`},"")}update(t,[e]){const{style:n}=t.element;if(void 0===this.ft)return this.ft=new Set(Object.keys(e)),this.render(e);for(const o of this.ft)null==e[o]&&(this.ft.delete(o),o.includes("-")?n.removeProperty(o):n[o]=null);for(const o in e){const t=e[o];if(null!=t){this.ft.add(o);const e="string"==typeof t&&t.endsWith(Wr);o.includes("-")||e?n.setProperty(o,e?t.slice(0,-11):t,e?Ir:""):n[o]=t}}return W}}),qr=Object.keys(Nt),Yr=Object.keys(St),Gr="custom",Xr={text:{}},Jr={entity:{domain:["sensor","input_number","number"]}}; + `}},ta=["bars","gauges","history","totals","compare","distribution"];function ea(t){return"chart"===t.layout}const na={bar:Yi,thin:Qr,segmented:Jr,tank:Kr,ring:Yr,needle:Vr,arc:Gr,line:$r,column:_r,area:Pi,combined:Or},oa="important",ia=" !"+oa,ra=mt(class extends ft{constructor(t){if(super(t),t.type!==dt||"style"!==t.name||t.strings?.length>2)throw Error("The `styleMap` directive must be used in the `style` attribute and must be the only part in the attribute.")}render(t){return Object.keys(t).reduce((e,n)=>{const o=t[n];return null==o?e:e+`${n=n.includes("-")?n:n.replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g,"-$&").toLowerCase()}:${o};`},"")}update(t,[e]){const{style:n}=t.element;if(void 0===this.ft)return this.ft=new Set(Object.keys(e)),this.render(e);for(const o of this.ft)null==e[o]&&(this.ft.delete(o),o.includes("-")?n.removeProperty(o):n[o]=null);for(const o in e){const t=e[o];if(null!=t){this.ft.add(o);const e="string"==typeof t&&t.endsWith(ia);o.includes("-")||e?n.setProperty(o,e?t.slice(0,-11):t,e?oa:""):n[o]=t}}return Z}}),aa=Object.keys(Nt),sa=Object.keys(Ct),la="custom",ca={text:{}},da={entity:{domain:["sensor","input_number","number"]}}; /** * @license * Copyright 2018 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function Kr(t){return"string"==typeof t&&""!==t.trim()&&!Number.isFinite(Number(t))}const Qr={icon:{}};function ta(t){return void 0===t?"none":qr.find(e=>Nt[e]&&Fe(Nt[e],t))??"custom"}function ea(t){return Yr.includes(t)}class na extends lt{constructor(){super(),this._customOpen=new Set,this._entityOpen=new Set}willUpdate(t){t.has("bands")&&(this._customOpen.size&&(this._customOpen=new Set),this._entityOpen.size&&(this._entityOpen=new Set))}_entityValue(t){const e=this.hass?.states[t]?.state,n=void 0===e||""===e.trim()?NaN:Number(e);return Number.isFinite(n)?n:void 0}_t(t){return ne(this.hass,t)}_getSelectors(){const t=`${ee(this.hass)}|${this.unit??""}`;if(this._selectors?.key===t)return this._selectors;const e=qr.map(t=>({value:t,label:this._t(`editor_preset_${t}`)})),n=t=>({select:{mode:"dropdown",options:t}});return this._selectors={key:t,preset:n(e),presetCustom:n([...e,{value:Gr,label:this._t("editor_preset_custom")}]),color:n([...Yr,Gr].map(t=>({value:t,label:this._t(`editor_color_${t}`)}))),from:{number:{mode:"box",step:"any",...this.unit?{unit_of_measurement:this.unit}:{}}}},this._selectors}_emit(t){this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:t&&t.length?t:void 0}}))}_presetChanged(t){t.stopPropagation();const e=t.detail?.value;if(!e||e===Gr||!qr.includes(e))return;if(e===ta(this.bands))return;const n=Nt[e];this._emit(n?structuredClone(n):void 0)}_updateBand(t,e,n){const o=[...this.bands??[]],i={...o[t]};null==n||""===n?delete i[e]:i[e]=n,o[t]=i,this._emit(o)}_fromChanged(t,e){e.stopPropagation();const n=Number(e.detail?.value);""!==e.detail?.value&&null!=e.detail?.value&&Number.isFinite(n)&&this._updateBand(t,"from",n)}_fromEntityChanged(t,e){e.stopPropagation();const n=e.detail?.value;"string"==typeof n&&""!==n&&this._updateBand(t,"from",n)}_toggleFromMode(t){const e=this.bands?.[t]?.from,n=new Set(this._entityOpen);Kr(e)?this._updateBand(t,"from",this._entityValue(e)??0):n.delete(t)||n.add(t),this._entityOpen=n}_colorChanged(t,e){e.stopPropagation();const n=e.detail?.value,o=this.bands?.[t]?.color??"primary";if(!n)return;const i=new Set(this._customOpen);n!==Gr?(i.delete(t),this._customOpen=i,n!==o&&this._updateBand(t,"color",n)):ea(o)&&(this._customOpen=i.add(t))}_customColorChanged(t,e){e.stopPropagation();const n="string"==typeof e.detail?.value?e.detail.value.trim():"";if(!n)return;const o=new Set(this._customOpen);o.delete(t),this._customOpen=o,this._updateBand(t,"color",n)}_iconChanged(t,e){e.stopPropagation(),this._updateBand(t,"icon",e.detail?.value)}_labelChanged(t,e){e.stopPropagation(),this._updateBand(t,"label",e.detail?.value)}_removeBand(t){const e=[...this.bands??[]];e.splice(t,1),this._emit(e)}_addBand(){const t=[...this.bands??[]],e=t[t.length-1]?.from,n="number"==typeof e?e:Kr(e)?this._entityValue(e)??NaN:"string"==typeof e&&""!==e.trim()?Number(e):NaN;t.push({from:Number.isFinite(n)?n+10:0,color:"primary"}),this._emit(t)}_renderBand(t,e,n){const o=!ea(t.color)||this._customOpen.has(e),i=Kr(t.from)?t.from:void 0,r=void 0!==i||this._entityOpen.has(e);return B`
- + */function ha(t){return"string"==typeof t&&""!==t.trim()&&!Number.isFinite(Number(t))}const ua={icon:{}};function pa(t){return void 0===t?"none":aa.find(e=>Nt[e]&&Fe(Nt[e],t))??"custom"}function ma(t){return sa.includes(t)}class fa extends lt{constructor(){super(),this._customOpen=new Set,this._entityOpen=new Set}willUpdate(t){t.has("bands")&&(this._customOpen.size&&(this._customOpen=new Set),this._entityOpen.size&&(this._entityOpen=new Set))}_entityValue(t){const e=this.hass?.states[t]?.state,n=void 0===e||""===e.trim()?NaN:Number(e);return Number.isFinite(n)?n:void 0}_t(t){return ne(this.hass,t)}_getSelectors(){const t=`${ee(this.hass)}|${this.unit??""}`;if(this._selectors?.key===t)return this._selectors;const e=aa.map(t=>({value:t,label:this._t(`editor_preset_${t}`)})),n=t=>({select:{mode:"dropdown",options:t}});return this._selectors={key:t,preset:n(e),presetCustom:n([...e,{value:la,label:this._t("editor_preset_custom")}]),color:n([...sa,la].map(t=>({value:t,label:this._t(`editor_color_${t}`)}))),from:{number:{mode:"box",step:"any",...this.unit?{unit_of_measurement:this.unit}:{}}}},this._selectors}_emit(t){this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:t&&t.length?t:void 0}}))}_presetChanged(t){t.stopPropagation();const e=t.detail?.value;if(!e||e===la||!aa.includes(e))return;if(e===pa(this.bands))return;const n=Nt[e];this._emit(n?structuredClone(n):void 0)}_updateBand(t,e,n){const o=[...this.bands??[]],i={...o[t]};null==n||""===n?delete i[e]:i[e]=n,o[t]=i,this._emit(o)}_fromChanged(t,e){e.stopPropagation();const n=Number(e.detail?.value);""!==e.detail?.value&&null!=e.detail?.value&&Number.isFinite(n)&&this._updateBand(t,"from",n)}_fromEntityChanged(t,e){e.stopPropagation();const n=e.detail?.value;"string"==typeof n&&""!==n&&this._updateBand(t,"from",n)}_toggleFromMode(t){const e=this.bands?.[t]?.from,n=new Set(this._entityOpen);ha(e)?this._updateBand(t,"from",this._entityValue(e)??0):n.delete(t)||n.add(t),this._entityOpen=n}_colorChanged(t,e){e.stopPropagation();const n=e.detail?.value,o=this.bands?.[t]?.color??"primary";if(!n)return;const i=new Set(this._customOpen);n!==la?(i.delete(t),this._customOpen=i,n!==o&&this._updateBand(t,"color",n)):ma(o)&&(this._customOpen=i.add(t))}_customColorChanged(t,e){e.stopPropagation();const n="string"==typeof e.detail?.value?e.detail.value.trim():"";if(!n)return;const o=new Set(this._customOpen);o.delete(t),this._customOpen=o,this._updateBand(t,"color",n)}_iconChanged(t,e){e.stopPropagation(),this._updateBand(t,"icon",e.detail?.value)}_labelChanged(t,e){e.stopPropagation(),this._updateBand(t,"label",e.detail?.value)}_removeBand(t){const e=[...this.bands??[]];e.splice(t,1),this._emit(e)}_addBand(){const t=[...this.bands??[]],e=t[t.length-1]?.from,n="number"==typeof e?e:ha(e)?this._entityValue(e)??NaN:"string"==typeof e&&""!==e.trim()?Number(e):NaN;t.push({from:Number.isFinite(n)?n+10:0,color:"primary"}),this._emit(t)}_renderBand(t,e,n){const o=!ma(t.color)||this._customOpen.has(e),i=ha(t.from)?t.from:void 0,r=void 0!==i||this._entityOpen.has(e);return B`
+ this._colorChanged(e,t)} > this._labelChanged(e,t)} > @@ -1375,7 +1428,7 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt data-role="icon" .hass=${this.hass} .label=${this._t("editor_band_icon")} - .selector=${Qr} + .selector=${ua} .value=${t.icon??""} @value-changed=${t=>this._iconChanged(e,t)} > @@ -1398,31 +1451,31 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt data-role="from-entity" .hass=${this.hass} .label=${this._t("editor_band_from_entity_label")} - .selector=${Jr} + .selector=${da} .value=${i??""} @value-changed=${t=>this._fromEntityChanged(e,t)} - >`:Z} + >`:W} ${o?B`this._customColorChanged(e,t)} - >`:Z} -
`}render(){const t=this._getSelectors(),e=ta(this.bands);return B``:W} +
`}render(){const t=this._getSelectors(),e=pa(this.bands);return B` ${(this.bands??[]).map((e,n)=>this._renderBand(e,n,t))} - `}}na.properties={hass:{attribute:!1},bands:{attribute:!1},unit:{attribute:!1},_customOpen:{state:!0},_entityOpen:{state:!0}},na.styles=r` + `}}fa.properties={hass:{attribute:!1},bands:{attribute:!1},unit:{attribute:!1},_customOpen:{state:!0},_entityOpen:{state:!0}},fa.styles=r` :host { display: block; } @@ -1489,7 +1542,7 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt outline: 2px solid var(--primary-color, #03a9f4); outline-offset: 2px; } - `,customElements.get("cd-bands-editor")||customElements.define("cd-bands-editor",na);const oa={number:{mode:"box",step:"any"}},ia={entity:{domain:["sensor","input_number","number"]}};function ra(t){return null==t||""===t?"default":"number"==typeof t||""!==t.trim()&&Number.isFinite(Number(t))?"number":"entity"}class aa extends lt{willUpdate(t){t.has("value")&&"default"!==ra(this.value)&&(this._mode=void 0)}_modeSelectorFor(){const t=(t,e)=>ne(this.hass,t,e),e=[{value:"default",label:t("editor_limit_default",{value:this.defaultLabel??""})},{value:"number",label:t("editor_limit_number")},{value:"entity",label:t("editor_limit_entity")}],n=e.map(t=>t.label).join("|");return this._modeSelector?.key!==n&&(this._modeSelector={key:n,selector:{select:{mode:"dropdown",options:e}}}),this._modeSelector.selector}get _currentMode(){return this._mode??ra(this.value)}_emit(t){this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:t}}))}_modeChanged(t){t.stopPropagation();const e=t.detail?.value;e&&e!==this._currentMode&&(this._mode=e,void 0!==this.value&&this._emit(void 0))}_numberChanged(t){t.stopPropagation();const e=t.detail?.value,n="number"==typeof e?e:""===e||null==e?NaN:Number(e);this._mode="number",this._emit(Number.isFinite(n)?n:void 0)}_entityChanged(t){t.stopPropagation();const e=t.detail?.value;this._mode="entity",this._emit("string"==typeof e&&""!==e?e:void 0)}render(){const t=t=>ne(this.hass,t),e=this._currentMode;return B`ne(this.hass,t,e),e=[{value:"default",label:t("editor_limit_default",{value:this.defaultLabel??""})},{value:"number",label:t("editor_limit_number")},{value:"entity",label:t("editor_limit_entity")}],n=e.map(t=>t.label).join("|");return this._modeSelector?.key!==n&&(this._modeSelector={key:n,selector:{select:{mode:"dropdown",options:e}}}),this._modeSelector.selector}get _currentMode(){return this._mode??ya(this.value)}_emit(t){this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:t}}))}_modeChanged(t){t.stopPropagation();const e=t.detail?.value;e&&e!==this._currentMode&&(this._mode=e,void 0!==this.value&&this._emit(void 0))}_numberChanged(t){t.stopPropagation();const e=t.detail?.value,n="number"==typeof e?e:""===e||null==e?NaN:Number(e);this._mode="number",this._emit(Number.isFinite(n)?n:void 0)}_entityChanged(t){t.stopPropagation();const e=t.detail?.value;this._mode="entity",this._emit("string"==typeof e&&""!==e?e:void 0)}render(){const t=t=>ne(this.hass,t),e=this._currentMode;return B``:"entity"===e?B``:Z}`}}aa.properties={hass:{attribute:!1},label:{attribute:!1},value:{attribute:!1},defaultLabel:{attribute:!1},_mode:{state:!0}},aa.styles=r` + >`:W}`}}va.properties={hass:{attribute:!1},label:{attribute:!1},value:{attribute:!1},defaultLabel:{attribute:!1},_mode:{state:!0}},va.styles=r` :host { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; align-items: start; } - `,customElements.get("cd-limit-field")||customElements.define("cd-limit-field",aa);const sa=["min","max","target"];function la(t,e,n){const o=e&&!n?t?.states[e]?.attributes?.unit_of_measurement:void 0;return"string"==typeof o&&o?o:void 0}class ca extends lt{constructor(){super(),this._computeLabel=t=>this._t(`editor_${t.name}`),this._expanded=new Set}_t(t,e){return ne(this.hass,t,e)}get _asConfig(){return{type:"",entities:this.entities??[]}}_emit(t){t.entities!==this.entities&&this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:t.entities??[]}}))}_set(t,e,n){this._emit(function(t,e,n,o){if("entity"===n&&(oe(o)||"string"!=typeof o))return t;const i=[...t.entities??[]],r=i[e];if(void 0===r)return t;const a="string"==typeof r?{entity:r}:{...r};oe(o)?delete a[n]:a[n]=o;const s=Object.keys(a);return i[e]=1===s.length&&"entity"===s[0]&&"string"==typeof a.entity?a.entity:a,{...t,entities:i}}(this._asConfig,t,e,n))}_move(t,e){const n=new Set;for(const o of this._expanded)n.add(o===t?e:o===e?t:o);this._expanded=n,this._emit(function(t,e,n){const o=[...t.entities??[]];if(e<0||e>=o.length||e===n)return t;const[i]=o.splice(e,1);return o.splice(Math.max(0,Math.min(n,o.length)),0,i),{...t,entities:o}}(this._asConfig,t,e))}_remove(t){const e=new Set;for(const n of this._expanded)n!==t&&e.add(n>t?n-1:n);this._expanded=e,this._emit(function(t,e){const n=[...t.entities??[]];return e<0||e>=n.length?t:(n.splice(e,1),{...t,entities:n})}(this._asConfig,t))}_toggle(t){const e=new Set(this._expanded);e.delete(t)||e.add(t),this._expanded=e}_add(t){t.stopPropagation();const e=t.detail?.value;"string"==typeof e&&""!==e&&(t.target.value="",this._emit(function(t,e){return{...t,entities:[...t.entities??[],e]}}(this._asConfig,e)))}_formChanged(t,e,n){n.stopPropagation();const o=this.entities?.[t];if(void 0===o)return;const i="string"==typeof o?{entity:o}:o,r=Re(i,e,n.detail?.value??{});if(r===i)return;const a=[...this.entities??[]],s=Object.keys(r);a[t]=1===s.length&&"entity"===s[0]?r.entity:r,this._emit({type:"",entities:a})}_rowLabel(t){const e=this.hass?.states[t];return e?{text:e.attributes.friendly_name||t,missing:!1}:this.hass?{text:this._t("editor_not_found",{entity:t}),missing:!0}:{text:t,missing:!1}}_form(t,e,n,o,i){return B`this._t(`editor_${t.name}`),this._expanded=new Set}_t(t,e){return ne(this.hass,t,e)}get _asConfig(){return{type:"",entities:this.entities??[]}}_emit(t){t.entities!==this.entities&&this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:t.entities??[]}}))}_set(t,e,n){this._emit(function(t,e,n,o){if("entity"===n&&(oe(o)||"string"!=typeof o))return t;const i=[...t.entities??[]],r=i[e];if(void 0===r)return t;const a="string"==typeof r?{entity:r}:{...r};oe(o)?delete a[n]:a[n]=o;const s=Object.keys(a);return i[e]=1===s.length&&"entity"===s[0]&&"string"==typeof a.entity?a.entity:a,{...t,entities:i}}(this._asConfig,t,e,n))}_move(t,e){const n=new Set;for(const o of this._expanded)n.add(o===t?e:o===e?t:o);this._expanded=n,this._emit(function(t,e,n){const o=[...t.entities??[]];if(e<0||e>=o.length||e===n)return t;const[i]=o.splice(e,1);return o.splice(Math.max(0,Math.min(n,o.length)),0,i),{...t,entities:o}}(this._asConfig,t,e))}_remove(t){const e=new Set;for(const n of this._expanded)n!==t&&e.add(n>t?n-1:n);this._expanded=e,this._emit(function(t,e){const n=[...t.entities??[]];return e<0||e>=n.length?t:(n.splice(e,1),{...t,entities:n})}(this._asConfig,t))}_toggle(t){const e=new Set(this._expanded);e.delete(t)||e.add(t),this._expanded=e}_add(t){t.stopPropagation();const e=t.detail?.value;"string"==typeof e&&""!==e&&(t.target.value="",this._emit(function(t,e){return{...t,entities:[...t.entities??[],e]}}(this._asConfig,e)))}_formChanged(t,e,n){n.stopPropagation();const o=this.entities?.[t];if(void 0===o)return;const i="string"==typeof o?{entity:o}:o,r=Ve(i,e,n.detail?.value??{});if(r===i)return;const a=[...this.entities??[]],s=Object.keys(r);a[t]=1===s.length&&"entity"===s[0]?r.entity:r,this._emit({type:"",entities:a})}_rowLabel(t){const e=this.hass?.states[t];return e?{text:e.attributes.friendly_name||t,missing:!1}:this.hass?{text:this._t("editor_not_found",{entity:t}),missing:!0}:{text:t,missing:!1}}_form(t,e,n,o,i){return B`this._formChanged(e,i,t)} >`}_renderOverrides(t,e){const n=t=>e=>{e.stopPropagation(),t(e.detail?.value)};return B`
- ${this._form("entity-attribute",e,t,function(t){let e=Ee.get(t);return e||(e=[{name:"attribute",selector:{attribute:{entity_id:t}}}],Ee.set(t,e)),e}(t.entity),be)} - ${this._form("entity-text",e,t,Se,ve)} - ${this.chartFields?this._form("entity-chart",e,t,this.chartFields.schema,this.chartFields.fields):Z} + ${this._form("entity-attribute",e,t,function(t){let e=Se.get(t);return e||(e=[{name:"attribute",selector:{attribute:{entity_id:t}}}],Se.set(t,e)),e}(t.entity),be)} + ${this._form("entity-text",e,t,Ce,ve)} + ${this.chartFields?this._form("entity-chart",e,t,this.chartFields.schema,this.chartFields.fields):W} this._set(e,"icon",t))} > - ${sa.map(o=>B`B`this._set(e,"severity",t))} > - ${this._form("entity-actions",e,t,Ce,Me)} + ${this._form("entity-actions",e,t,Ee,Me)}
`}_renderRow(t,e,n){const o=function(t){return"string"==typeof t?t:t.entity}(t),i="string"==typeof t?{entity:t}:t,r=this._rowLabel(o),a=this._expanded.has(e);return B`
${r.text}
@@ -1590,7 +1643,7 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt @click=${()=>this._toggle(e)} >
- ${a?this._renderOverrides(i,e):Z} + ${a?this._renderOverrides(i,e):W}
`}render(){const t=this.entities??[];return B`${t.map((e,n)=>this._renderRow(e,n,t.length))} `}}ca.properties={hass:{attribute:!1},entities:{attribute:!1},unit:{attribute:!1},chartFields:{attribute:!1},_expanded:{state:!0}},ca.styles=r` + >`}}xa.properties={hass:{attribute:!1},entities:{attribute:!1},unit:{attribute:!1},chartFields:{attribute:!1},_expanded:{state:!0}},xa.styles=r` :host { display: block; } @@ -1651,7 +1704,7 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt display: block; margin-top: 8px; } - `,customElements.get("cd-entities-editor")||customElements.define("cd-entities-editor",ca);class da extends lt{constructor(){super(...arguments),this._label=t=>ne(this.hass,t),this._computeLabel=t=>ne(this.hass,`editor_${t.name}`),this._computeRuleLabel=t=>ne(this.hass,`editor_rule_${t.name.slice(t.name.indexOf("_")+1)}`)}setConfig(t){this._config=t}connectedCallback(){super.connectedCallback(),async function(){if(!customElements.get("ha-entity-picker")&&"function"==typeof window.loadCardHelpers)try{const t=await window.loadCardHelpers(),e=await t.createCardElement({type:"entities",entities:[]}),n=e?.constructor;await(n?.getConfigElement?.())}catch{}}()}_commit(t){this._config=t,function(t,e){t.dispatchEvent(new CustomEvent("config-changed",{bubbles:!0,composed:!0,detail:{config:e}}))}(this,t)}_formChanged(t,e){if(e.stopPropagation(),!this._config)return;const n=e.detail?.value??{};this._commit(Re(this._config,t,n))}_form(t,e,n){return B`ne(this.hass,t),this._computeLabel=t=>ne(this.hass,`editor_${t.name}`),this._computeRuleLabel=t=>ne(this.hass,`editor_rule_${t.name.slice(t.name.indexOf("_")+1)}`)}setConfig(t){this._config=t}connectedCallback(){super.connectedCallback(),async function(){if(!customElements.get("ha-entity-picker")&&"function"==typeof window.loadCardHelpers)try{const t=await window.loadCardHelpers(),e=await t.createCardElement({type:"entities",entities:[]}),n=e?.constructor;await(n?.getConfigElement?.())}catch{}}()}_commit(t){this._config=t,function(t,e){t.dispatchEvent(new CustomEvent("config-changed",{bubbles:!0,composed:!0,detail:{config:e}}))}(this,t)}_formChanged(t,e){if(e.stopPropagation(),!this._config)return;const n=e.detail?.value??{};this._commit(Ve(this._config,t,n))}_form(t,e,n){return B`this._formChanged(n,t)} >`}_panel(t,e){return B`
${e}
-
`}_subChanged(t,e){e.stopPropagation(),this._config&&this._commit(ae(this._config,t,e.detail?.value))}_chartFields(){const t=Br[this._config?.style??"bar"];return t&&Vr(t)&&this._config?t.entityFields?.(this.hass,this._config):void 0}renderEntities(){return B``}_subChanged(t,e){e.stopPropagation(),this._config&&this._commit(ae(this._config,t,e.detail?.value))}_chartFields(){const t=na[this._config?.style??"bar"];return t&&ea(t)&&this._config?t.entityFields?.(this.hass,this._config):void 0}renderEntities(){return B`this._subChanged(["severity"],t)} - >`}_firstEntityUnit(){const t=this._config?.entities?.[0];return"string"==typeof t?la(this.hass,t):t?.unit??la(this.hass,t?.entity,t?.attribute)}_selectStyle(t){this._config&&this._commit(ae(this._config,["style"],"bar"===t?void 0:t))}renderStyle(){const t=this._config?.style??"bar";return B`${Rr.map(e=>{const n=Vt.filter(t=>Br[t].group===e);return n.length?B`
${this._label(`editor_group_${e}`)}
+ >`}_firstEntityUnit(){const t=this._config?.entities?.[0];return"string"==typeof t?$a(this.hass,t):t?.unit??$a(this.hass,t?.entity,t?.attribute)}_selectStyle(t){this._config&&this._commit(ae(this._config,["style"],"bar"===t?void 0:t))}renderStyle(){const t=this._config?.style??"bar";return B`${ta.map(e=>{const n=Rt.filter(t=>na[t].group===e);return n.length?B`
${this._label(`editor_group_${e}`)}
- ${n.map(e=>{const n=Br[e],o=Vr(n)?B`${this._label(`editor_style_${e}`)} `})} -
`:Z})}`}renderChart(){const t=Br[this._config?.style??"bar"];return t&&Vr(t)&&t.editor&&this._config?this._panel("chart",t.editor({hass:this.hass,config:this._config,commit:t=>this._commit(t)})):Z}renderDisplay(){return B`${this._toggles(fe)} - ${this._form("display",function(t){const e=ee(t);return Pe?.language!==e&&(Pe={language:e,schema:Le(t)}),Pe.schema}(this.hass),ye)}`}_toggles(t){const e=De(this._config,t);return B`
+
`:W})}`}renderChart(){const t=na[this._config?.style??"bar"];return t&&ea(t)&&t.editor&&this._config?this._panel("chart",t.editor({hass:this.hass,config:this._config,commit:t=>this._commit(t)})):W}renderDisplay(){return B`${this._toggles(fe)} + ${this._form("display",function(t){const e=ee(t);return Pe?.language!==e&&(Pe={language:e,schema:Te(t)}),Pe.schema}(this.hass),_e)}`}_toggles(t){const e=De(this._config,t);return B`
${t.map(({name:n})=>{const o=this._label(`editor_${n}`),i=!0===e[n];return B`
this._toggle(t,n,!i)}>${o}this._toggle(t,n,e.target.checked)} >
`})} -
`}_toggle(t,e,n){if(!this._config)return;const o=De(this._config,t);this._commit(Re(this._config,t,{...o,[e]:n}))}renderActions(){return this._form("actions",Ce,_e)}render(){return this._config?B`
${this._form("title",Ae,me)}
+ `}_toggle(t,e,n){if(!this._config)return;const o=De(this._config,t);this._commit(Ve(this._config,t,{...o,[e]:n}))}renderActions(){return this._form("actions",Ee,ye)}render(){return this._config?B`
${this._form("title",Ae,me)}
${this._panel("entities",this.renderEntities())} ${this._panel("style",this.renderStyle())} ${this.renderChart()} ${this._panel("limits",this.renderLimits())} ${this._panel("colours",this.renderColours())} ${this._panel("display",this.renderDisplay())} - ${this._panel("actions",this.renderActions())}`:Z}}da.properties={hass:{attribute:!1},_config:{state:!0}},da.styles=r` + ${this._panel("actions",this.renderActions())}`:W}}wa.properties={hass:{attribute:!1},_config:{state:!0}},wa.styles=r` :host { display: block; } @@ -1796,7 +1849,7 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt outline-offset: -1px; border-color: transparent; } - `,customElements.get("chartdeck-card-editor")||customElements.define("chartdeck-card-editor",da);const ha=r` + `,customElements.get("chartdeck-card-editor")||customElements.define("chartdeck-card-editor",wa);const ka=r` :host { display: block; --cd-duration: 900ms; @@ -1899,29 +1952,29 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt border-radius: 50%; flex: none; } -`;console.info("%c CHARTDECK %c 1.2.0 ","color:#fff;background:#3b8bff;font-weight:700","color:#3b8bff");const ua={rows:16,tiles:8};function pa(t){const e=ua[t.layout];return Math.max(1,Math.floor((368+e)/((t.minColumnWidth??0)+e)))}class ma extends lt{constructor(){super(...arguments),this._watched=new Set,this._matched=[],this._items=[],this._detachers=new Map,this._readyScheduled=!1,this._readyAt=-1/0}static getStubConfig(t){const e=Object.values(t?.states??{}).filter(t=>t.entity_id.startsWith("sensor.")&&""!==t.state.trim()&&Number.isFinite(Number(t.state))),n=t=>"battery"===t.attributes?.device_class;return e.sort((t,e)=>n(t)!==n(e)?n(t)?-1:1:t.entity_ide.entity_id?1:0),{type:"custom:chartdeck-card",style:"bar",entities:e.slice(0,3).map(t=>t.entity_id)}}static getConfigElement(){return document.createElement("chartdeck-card-editor")}setConfig(t){const e=function(t){if(!t||"object"!=typeof t)throw new Error("Invalid configuration");const e=t.style??"bar";if(!Vt.includes(e))throw new Error(`Unknown style "${String(e)}". Use one of: ${Vt.join(", ")}`);const n=t.sort??"none";if(!It.includes(n))throw new Error(`Unknown sort "${String(n)}". Use one of: ${It.join(", ")}`);if(void 0!==t.entities&&!Array.isArray(t.entities))throw new Error('"entities" must be a list');const o=(t.entities??[]).map((e,n)=>Jt(e,t,n)),i={name:!0,value:!0,icon:!0,target:!0,legend:!1,...t.show},r=qt(t.columns,"columns",1),a=qt(t.limit,"limit",1),s=jt(t.include,"include"),l=jt(t.exclude,"exclude");s&&Jt("sensor.chartdeck_check",t,0);const c={style:e,entities:o,hideUnavailable:!0===t.hide_unavailable,cardOptions:t,show:i,sort:n,animate:!1!==t.animate,colorIcon:!0===t.color_icon,legendBands:Yt(t.severity)??Bt};return void 0!==t.title&&(c.title=t.title),void 0!==r&&(c.columns=r),void 0!==a&&(c.limit=a),s&&(c.include=s),l&&(c.exclude=l),c}(t),n=Br[e.style];if(Vr(n)&&n.validate?.(t),this._watched=function(t){const e=new Set;for(const n of t.entities){e.add(n.entity);for(const t of[n.min,n.max,n.target,...n.severity.map(t=>t.from)])"string"==typeof t&&""!==t&&e.add(t)}for(const n of t.legendBands)"string"==typeof n.from&&e.add(n.from);return e}(e),Vr(n))for(const o of n.watch?.(t)??[])this._watched.add(o);this._config&&this._config.style!==e.style&&this._disconnectStyle(),this._config=e}get _styleName(){return this._config?.style??"bar"}get _style(){return Br[this._styleName]}_legend(t){const e=this._config;if(!e?.show.legend||0===this._count())return[];const n=t?.decimals??1;return function(t,e,n){const o=n?` ${n}`:"",i=[];return t.forEach((n,r)=>{const a=t[r+1],s=Et(n.color);n.label?i.push({color:s,text:n.label}):Number.isFinite(n.from)?a?i.push({color:s,text:`${e(n.from)}–${e(a.from)}${o}`}):i.push({color:s,text:`${e(n.from)}${o}+`}):a&&i.push({color:s,text:`< ${e(a.from)}${o}`})}),i}(Wi(e.legendBands,this.hass),t=>Po(t,n,this.hass),t?.unit??"")}_count(){return this.hasUpdated&&this.hass?this._items.length:this._config?.entities.length??0}_contentHeight(){const t=this._config;if(!t)return 0;const e=this._style,n=16+(t.title?73:0)+(this._legend().length>0?32:0);if(Vr(e))return n+e.height;const o=this._count(),i=void 0!==t.columns?Math.min(t.columns,pa(e)):"rows"===e.layout?1:Math.min(o,e.tilesPerRow??3,pa(e));return n+(0===o?0:Math.ceil(o/Math.max(1,i)))*e.height}getCardSize(){return Math.max(1,Math.ceil(this._contentHeight()/50))}getGridOptions(){const t=this._count();if(Vr(this._style))return{columns:12,rows:"auto",min_columns:6,min_rows:2};const e="rows"===this._style.layout;return{columns:e||t<=1?6:12,rows:"auto",min_columns:e?6:3,min_rows:1}}shouldUpdate(t){if(0===t.size)return!0;if([...t.keys()].some(t=>"hass"!==t))return!0;if(!t.has("hass"))return!1;const e=t.get("hass"),n=this.hass;if(!e||!n)return!0;for(const o of this._watched)if(e.states[o]!==n.states[o])return!0;if(this._config?.include){const t=qi(this._config,n);if(t.length!==this._matched.length||t.some((t,e)=>t!==this._matched[e]))return!0;for(const o of t)if(e.states[o]!==n.states[o])return!0}return e.themes?.darkMode!==n.themes?.darkMode||e.themes?.theme!==n.themes?.theme||e.locale!==n.locale}willUpdate(){const t=!1===this._config?.animate||"function"==typeof window.matchMedia&&!!window.matchMedia("(prefers-reduced-motion: reduce)")?.matches;this.toggleAttribute("static",t),(t||this.preview)&&this.setAttribute("ready","")}_scheduleReady(){if(this._readyScheduled||this.hasAttribute("ready")||0===this._items.length)return;this._readyScheduled=!0;const t=()=>{this.shadowRoot?.querySelector(".entity")?.getBoundingClientRect(),this.setAttribute("ready",""),this._readyAt=performance.now()};"function"==typeof requestAnimationFrame?requestAnimationFrame(t):setTimeout(t,16)}updated(){this._scheduleReady(),this._syncActions()}connectedCallback(){if(super.connectedCallback(),!this.hasUpdated)return;const t=this._config?Br[this._config.style]:void 0;t&&Vr(t)&&this.requestUpdate(),this._syncActions(),this.hasAttribute("ready")&&!this.hasAttribute("static")&&performance.now()-this._readyAt<1e3&&(this.removeAttribute("ready"),this._readyScheduled=!1,this._scheduleReady())}_disconnectStyle(){const t=this._config?Br[this._config.style]:void 0;t&&Vr(t)&&t.disconnect?.(this)}disconnectedCallback(){super.disconnectedCallback(),this._disconnectStyle();for(const t of this._detachers.values())t();this._detachers.clear()}_syncActions(){const t=this.shadowRoot;if(!t)return;const e=new Set(t.querySelectorAll(".entity"));for(const[n,o]of this._detachers)e.has(n)||(o(),this._detachers.delete(n));for(const n of e)this._detachers.has(n)||this._detachers.set(n,Ct(n,()=>this._items[Number(n.dataset.index)].config))}_renderEntity(t,e,n,o){const i=this._config,r=(a=t.config,At(a.tap_action)||At(a.hold_action)||At(a.double_tap_action));var a;const s=function(t){const e=Et(t);return{start:e,end:`color-mix(in srgb, ${e} 80%, #fff)`}}(t.band.color),l=`--start:${t.span[0]};--end:${t.span[1]};--pos:${t.position};--target:${t.targetPosition??0};--c-start:${s.start};--c-end:${s.end}`;return B`
t.entity_id.startsWith("sensor.")&&""!==t.state.trim()&&Number.isFinite(Number(t.state))),n=t=>"battery"===t.attributes?.device_class;return e.sort((t,e)=>n(t)!==n(e)?n(t)?-1:1:t.entity_ide.entity_id?1:0),{type:"custom:chartdeck-card",style:"bar",entities:e.slice(0,3).map(t=>t.entity_id)}}static getConfigElement(){return document.createElement("chartdeck-card-editor")}setConfig(t){const e=function(t){if(!t||"object"!=typeof t)throw new Error("Invalid configuration");const e=t.style??"bar";if(!Rt.includes(e))throw new Error(`Unknown style "${String(e)}". Use one of: ${Rt.join(", ")}`);const n=t.sort??"none";if(!It.includes(n))throw new Error(`Unknown sort "${String(n)}". Use one of: ${It.join(", ")}`);if(void 0!==t.entities&&!Array.isArray(t.entities))throw new Error('"entities" must be a list');const o=(t.entities??[]).map((e,n)=>Jt(e,t,n)),i={name:!0,value:!0,icon:!0,target:!0,legend:!1,...t.show},r=qt(t.columns,"columns",1),a=qt(t.limit,"limit",1),s=Ut(t.include,"include"),l=Ut(t.exclude,"exclude");s&&Jt("sensor.chartdeck_check",t,0);const c={style:e,entities:o,hideUnavailable:!0===t.hide_unavailable,cardOptions:t,show:i,sort:n,animate:!1!==t.animate,colorIcon:!0===t.color_icon,legendBands:Yt(t.severity)??Bt};return void 0!==t.title&&(c.title=t.title),void 0!==r&&(c.columns=r),void 0!==a&&(c.limit=a),s&&(c.include=s),l&&(c.exclude=l),c}(t),n=na[e.style];if(ea(n)&&n.validate?.(t),this._watched=function(t){const e=new Set;for(const n of t.entities){e.add(n.entity);for(const t of[n.min,n.max,n.target,...n.severity.map(t=>t.from)])"string"==typeof t&&""!==t&&e.add(t)}for(const n of t.legendBands)"string"==typeof n.from&&e.add(n.from);return e}(e),ea(n))for(const o of n.watch?.(t)??[])this._watched.add(o);this._config&&this._config.style!==e.style&&this._disconnectStyle(),this._config=e}get _styleName(){return this._config?.style??"bar"}get _style(){return na[this._styleName]}_legend(t){const e=this._config;if(!e?.show.legend||0===this._count())return[];const n=t?.decimals??1;return function(t,e,n){const o=n?` ${n}`:"",i=[];return t.forEach((n,r)=>{const a=t[r+1],s=St(n.color);n.label?i.push({color:s,text:n.label}):Number.isFinite(n.from)?a?i.push({color:s,text:`${e(n.from)}–${e(a.from)}${o}`}):i.push({color:s,text:`${e(n.from)}${o}+`}):a&&i.push({color:s,text:`< ${e(a.from)}${o}`})}),i}(Zi(e.legendBands,this.hass),t=>Po(t,n,this.hass),t?.unit??"")}_count(){return this.hasUpdated&&this.hass?this._items.length:this._config?.entities.length??0}_contentHeight(){const t=this._config;if(!t)return 0;const e=this._style,n=16+(t.title?73:0)+(this._legend().length>0?32:0);if(ea(e))return n+e.height;const o=this._count(),i=void 0!==t.columns?Math.min(t.columns,Aa(e)):"rows"===e.layout?1:Math.min(o,e.tilesPerRow??3,Aa(e));return n+(0===o?0:Math.ceil(o/Math.max(1,i)))*e.height}getCardSize(){return Math.max(1,Math.ceil(this._contentHeight()/50))}getGridOptions(){const t=this._count();if(ea(this._style))return{columns:12,rows:"auto",min_columns:6,min_rows:2};const e="rows"===this._style.layout;return{columns:e||t<=1?6:12,rows:"auto",min_columns:e?6:3,min_rows:1}}shouldUpdate(t){if(0===t.size)return!0;if([...t.keys()].some(t=>"hass"!==t))return!0;if(!t.has("hass"))return!1;const e=t.get("hass"),n=this.hass;if(!e||!n)return!0;for(const o of this._watched)if(e.states[o]!==n.states[o])return!0;if(this._config?.include){const t=qi(this._config,n);if(t.length!==this._matched.length||t.some((t,e)=>t!==this._matched[e]))return!0;for(const o of t)if(e.states[o]!==n.states[o])return!0}return e.themes?.darkMode!==n.themes?.darkMode||e.themes?.theme!==n.themes?.theme||e.locale!==n.locale}willUpdate(){const t=!1===this._config?.animate||"function"==typeof window.matchMedia&&!!window.matchMedia("(prefers-reduced-motion: reduce)")?.matches;this.toggleAttribute("static",t),(t||this.preview)&&this.setAttribute("ready","")}_scheduleReady(){if(this._readyScheduled||this.hasAttribute("ready")||0===this._items.length)return;this._readyScheduled=!0;const t=()=>{this.shadowRoot?.querySelector(".entity")?.getBoundingClientRect(),this.setAttribute("ready",""),this._readyAt=performance.now()};"function"==typeof requestAnimationFrame?requestAnimationFrame(t):setTimeout(t,16)}updated(){this._scheduleReady(),this._syncActions()}connectedCallback(){if(super.connectedCallback(),!this.hasUpdated)return;const t=this._config?na[this._config.style]:void 0;t&&ea(t)&&this.requestUpdate(),this._syncActions(),this.hasAttribute("ready")&&!this.hasAttribute("static")&&performance.now()-this._readyAt<1e3&&(this.removeAttribute("ready"),this._readyScheduled=!1,this._scheduleReady())}_disconnectStyle(){const t=this._config?na[this._config.style]:void 0;t&&ea(t)&&t.disconnect?.(this)}disconnectedCallback(){super.disconnectedCallback(),this._disconnectStyle();for(const t of this._detachers.values())t();this._detachers.clear()}_syncActions(){const t=this.shadowRoot;if(!t)return;const e=new Set(t.querySelectorAll(".entity"));for(const[n,o]of this._detachers)e.has(n)||(o(),this._detachers.delete(n));for(const n of e)this._detachers.has(n)||this._detachers.set(n,Et(n,()=>this._items[Number(n.dataset.index)].config))}_renderEntity(t,e,n,o){const i=this._config,r=(a=t.config,At(a.tap_action)||At(a.hold_action)||At(a.double_tap_action));var a;const s=function(t){const e=St(t);return{start:e,end:`color-mix(in srgb, ${e} 80%, #fff)`}}(t.band.color),l=`--start:${t.span[0]};--end:${t.span[1]};--pos:${t.position};--target:${t.targetPosition??0};--c-start:${s.start};--c-end:${s.end}`;return B`
${n.render(t,{show:i.show,hass:o})} -
`}render(){const t=this._config;if(!t)return Z;const e=this.hass,n=this._style;let o,i,r;const a=e?function(t,e){const n=qi(t,e).map((e,n)=>Jt(e,t.cardOptions,n)),o=[...t.entities,...n].map(t=>Zi(t,e));return t.hideUnavailable?o.filter(t=>t.available):o}(t,e):[];if(this._matched=e?qi(t,e):[],0!==t.entities.length||t.include)if(e)if(0===a.length)this._items=[],o=B`
${ne(e,t.include?"no_matches":"none_available")}
`;else{i=a[0];const s=new Map,l=new Set;a.forEach((t,e)=>{s.set(t,l.has(t.entityId)?`${t.entityId}#${e}`:t.entityId),l.add(t.entityId)}),this._items=function(t,e){if("none"===e)return[...t];const n="ascending"===e?1:-1;return t.map((t,e)=>({item:t,index:e})).sort((t,e)=>{if(t.item.available!==e.item.available)return t.item.available?-1:1;if(t.item.available){const o=(t.item.position-e.item.position)*n;if(0!==o)return o}return t.index-e.index}).map(t=>t.item)}(a,t.sort).slice(0,t.limit);const c=this._items.filter(t=>t.available).map(t=>t.display.length);if(r=c.length?Math.max(...c):void 0,Vr(n))o=B`
+
`}render(){const t=this._config;if(!t)return W;const e=this.hass,n=this._style;let o,i,r;const a=e?function(t,e){const n=qi(t,e).map((e,n)=>Jt(e,t.cardOptions,n)),o=[...t.entities,...n].map(t=>Wi(t,e));return t.hideUnavailable?o.filter(t=>t.available):o}(t,e):[];if(this._matched=e?qi(t,e):[],0!==t.entities.length||t.include)if(e)if(0===a.length)this._items=[],o=B`
${ne(e,t.include?"no_matches":"none_available")}
`;else{i=a[0];const s=new Map,l=new Set;a.forEach((t,e)=>{s.set(t,l.has(t.entityId)?`${t.entityId}#${e}`:t.entityId),l.add(t.entityId)}),this._items=function(t,e){if("none"===e)return[...t];const n="ascending"===e?1:-1;return t.map((t,e)=>({item:t,index:e})).sort((t,e)=>{if(t.item.available!==e.item.available)return t.item.available?-1:1;if(t.item.available){const o=(t.item.position-e.item.position)*n;if(0!==o)return o}return t.index-e.index}).map(t=>t.item)}(a,t.sort).slice(0,t.limit);const c=this._items.filter(t=>t.available).map(t=>t.display.length);if(r=c.length?Math.max(...c):void 0,ea(n))o=B`
${n.render({items:this._items,config:t,raw:t.cardOptions,hass:e,requestUpdate:()=>this.requestUpdate(),host:this})} -
`;else{const i="tiles"===n.layout,r=function(t,e){if(void 0===e)return"rows"===t.layout?"grid-template-columns: repeat(1, minmax(0, 1fr))":"";const n=(e-1)*ua[t.layout];return`grid-template-columns: repeat(auto-fill, minmax(max(min(${t.minColumnWidth??0}px, 100%), calc((100% - ${n}px) / ${e} - 0.5px)), 1fr))`}(n,t.columns);o=B`
`;else{const i="tiles"===n.layout,r=function(t,e){if(void 0===e)return"rows"===t.layout?"grid-template-columns: repeat(1, minmax(0, 1fr))":"";const n=(e-1)*Ma[t.layout];return`grid-template-columns: repeat(auto-fill, minmax(max(min(${t.minColumnWidth??0}px, 100%), calc((100% - ${n}px) / ${e} - 0.5px)), 1fr))`}(n,t.columns);o=B`
${Mt(this._items,t=>s.get(t),(t,o)=>this._renderEntity(t,o,n,e))} -
`}}else this._items=[],o=Z;else this._items=[],o=B`
${ne(e,"no_entities")}
`;const s=this._legend(i);return B` +
`}}else this._items=[],o=W;else this._items=[],o=B`
${ne(e,"no_entities")}
`;const s=this._legend(i);return B`
${o}
@@ -1929,5 +1982,5 @@ const Kt=mt(class extends ft{constructor(t){if(super(t),t.type!==ut&&t.type!==dt ${s.map(t=>B`${t.text}`)} -
`:Z} - `}}ma.properties={hass:{attribute:!1},preview:{type:Boolean},_config:{state:!0}},ma.styles=[ha,...Object.values(Br).map(t=>t.styles)],customElements.get("chartdeck-card")||customElements.define("chartdeck-card",ma);const fa=window.customCards??=[];fa.some(t=>"chartdeck-card"===t.type)||fa.push({type:"chartdeck-card",name:"Chartdeck",description:"Bars, gauges and charts, set up entirely from the visual editor.",preview:!0,documentationURL:"https://tempus2016.github.io/chartdeck/"});export{ma as ChartdeckCard}; + `:W} + `}}Ea.properties={hass:{attribute:!1},preview:{type:Boolean},_config:{state:!0}},Ea.styles=[ka,...Object.values(na).map(t=>t.styles)],customElements.get("chartdeck-card")||customElements.define("chartdeck-card",Ea);const Ca=window.customCards??=[];Ca.some(t=>"chartdeck-card"===t.type)||Ca.push({type:"chartdeck-card",name:"Chartdeck",description:"Bars, gauges and charts, set up entirely from the visual editor.",preview:!0,documentationURL:"https://tempus2016.github.io/chartdeck/"});export{Ea as ChartdeckCard}; diff --git a/src/chart/frame.ts b/src/chart/frame.ts index ebca92f..d9976e7 100644 --- a/src/chart/frame.ts +++ b/src/chart/frame.ts @@ -5,7 +5,7 @@ import { parsePeriod, periodRange, setSteps, stepsFor } from '../history/period' import type { Period } from '../history/period'; import { key } from '../history/fetch'; import { PERIOD_MS, groupHistory, groupStatistics, parseGrouping, statisticsQueryFor } from '../history/group'; -import type { Grouping } from '../history/group'; +import type { Aggregate, Grouping } from '../history/group'; import { pauseStore, storeFor } from '../history/store'; import { boundaries, startOf, wallTime, zoneFor } from '../history/timezone'; import type { Zone } from '../history/timezone'; @@ -94,6 +94,12 @@ export function validateHistoryOptions(raw: CardConfig): void { export interface FrameOptions { /** Keep each group's lowest and highest (`min`, `max` on its point), for range charts. */ range?: boolean; + /** + * How to combine one series' grouped history, when it differs from the card's (a meter's change + * beside a temperature's average). Statistics load one column for every series, so they use + * the card's. + */ + aggregate?: (entity: ResolvedEntity) => Aggregate | undefined; } /** Load (or reuse) the card's history and pair it with its entities. */ @@ -126,7 +132,7 @@ export function historyFrame(ctx: ChartContext, now = Date.now(), options: Frame points = source === 'statistics' ? groupStatistics(points, bounds, group.aggregate, until, options.range === true) - : groupHistory(points, bounds, group.aggregate, until, options.range === true); + : groupHistory(points, bounds, options.aggregate?.(entity) ?? group.aggregate, until, options.range === true); } else if (source === 'history' && last && last.v !== null && last.t < until) { // A sensor holds its last reading until it changes, so carry it on to the right edge. points = [...points, { t: until, v: last.v }]; diff --git a/src/chart/grid.ts b/src/chart/grid.ts index a4de65d..d8af4ee 100644 --- a/src/chart/grid.ts +++ b/src/chart/grid.ts @@ -133,6 +133,23 @@ function timeLabels(axes: PlotAxes, ctx: ChartContext) { }); } +/** A second value axis, up the right side, for series in another unit. */ +export interface RightAxis { + value: ValueAxis; + /** Value to plot units, as `PlotScales.y`. */ + y: (v: number) => number; +} + +function rightLabels(right: RightAxis, ctx: ChartContext) { + return right.value.ticks.map((v) => { + const top = right.y(v) / VIEW_H; + const end = top < 0.08 ? 'top' : top > 0.92 ? 'bottom' : ''; + return html`${formatNumber(v, right.value.decimals, ctx.hass)}`; + }); +} + export interface ChartAreaOptions { axes: PlotAxes; ctx: ChartContext; @@ -144,6 +161,8 @@ export interface ChartAreaOptions { overlay?: TemplateResult | typeof nothing; /** Pointer handlers for a hover tooltip; the plot then takes sideways touch drags. */ hover?: Hover; + /** A second value axis on the right. */ + right?: RightAxis; } /** @@ -151,7 +170,16 @@ export interface ChartAreaOptions { * stretched SVG never distorts it. Outside labels get their own column and row; inside ones sit * over the plot's left and bottom edges. */ -export function chartArea({ axes, ctx, content, label, defs = nothing, overlay = nothing, hover }: ChartAreaOptions) { +export function chartArea({ + axes, + ctx, + content, + label, + defs = nothing, + overlay = nothing, + hover, + right, +}: ChartAreaOptions) { const { options } = axes; const outside = options.labels === 'outside'; const y = options.y && axes.value.ticks.length > 0; @@ -166,7 +194,20 @@ export function chartArea({ axes, ctx, content, label, defs = nothing, overlay = .reduce((a, b) => (b.length > a.length ? b : a), '')}` : nothing; - return html`
+ const r = right && options.y && right.value.ticks.length > 0 ? right : undefined; + const rSizer = r + ? html`` + : nothing; + const rLabels = r + ? html`
${outside ? rSizer : nothing}${rightLabels(r, ctx)}
` + : nothing; + return html`
${outside && y ? html`
${sizer}${yTicks}
` : nothing}
- ${plot(content, label, defs, gridLines(axes))} ${outside ? nothing : html`${yLabels}${xLabels}`} ${overlay} + ${plot(content, label, defs, gridLines(axes))} ${outside ? nothing : html`${yLabels}${rLabels}${xLabels}`} + ${overlay}
- ${outside ? xLabels : nothing} + ${outside ? html`${rLabels}${xLabels}` : nothing}
`; } @@ -249,6 +291,22 @@ export const gridStyles = css` .x-axis .axis-label.end { transform: translateX(-100%); } + .plot-wrap.has-right { + grid-template-columns: auto minmax(0, 1fr) auto; + } + .axes-outside .y-axis.right { + grid-column: 3; + padding-right: 0; + padding-left: 6px; + } + .axes-outside .y-axis.right .axis-label { + right: auto; + left: 6px; + } + .axes-inside .y-axis.right .axis-label { + left: auto; + right: 2px; + } .axes-inside .y-axis, .axes-inside .x-axis { position: absolute; diff --git a/src/styles/column.ts b/src/styles/column.ts index 06fdb42..7282b78 100644 --- a/src/styles/column.ts +++ b/src/styles/column.ts @@ -140,7 +140,7 @@ interface Drawn { } /** A column from `lo` to `hi` (values), `left`/`width` in plot units, with its outer end(s) rounded. */ -function column( +export function column( scales: PlotScales, left: number, width: number, diff --git a/src/styles/combined.ts b/src/styles/combined.ts new file mode 100644 index 0000000..82096f7 --- /dev/null +++ b/src/styles/combined.ts @@ -0,0 +1,420 @@ +import { css, html, nothing, svg } from 'lit'; +import type { TemplateResult } from 'lit'; +import { formatDateTime, validateAxisOptions, valueAxis } from '../chart/axes'; +import { + COLUMN_AGGREGATES, + COLUMN_GROUPS, + autoGroupUnit, + columnBox, + columnTable, + isMeter, + spread, +} from '../chart/columns'; +import { + VIEW_H, + VIEW_W, + disconnectHistory, + frameMessage, + frameStyles, + historyFrame, + periodNav, + seriesHeader, + validateHistoryOptions, +} from '../chart/frame'; +import type { ChartSeries } from '../chart/frame'; +import { chartArea, gridStyles, plotAxes, plotWidth, stopChartWidth } from '../chart/grid'; +import type { PlotScales } from '../chart/grid'; +import { chartFrame, chartLayout, headerOver, layoutStyles, validateLayout } from '../chart/layout'; +import { CURVES } from '../chart/paths'; +import { linear } from '../chart/scale'; +import { DEFAULT_LINE_WIDTH, validateSeriesStyle } from '../chart/series-style'; +import { + hoverHandlers, + hoverTime, + stopHover, + tooltipEnabled, + tooltipLayer, + tooltipStyles, + validateTooltipOptions, +} from '../chart/tooltip'; +import { + AXES_FIELDS, + HISTORY_FIELDS, + LAYOUT_FIELDS, + axesSchema, + cachedSchema, + chartForm, + choice, + historySchema, + historyVariant, + layoutSchema, +} from '../editor/chart-editors'; +import { LINE_WIDTH_SELECTOR } from '../editor/schemas'; +import type { FieldBinding } from '../editor/schemas'; +import { AGGREGATES, parseGrouping } from '../history/group'; +import type { Aggregate } from '../history/group'; +import { parsePeriod } from '../history/period'; +import type { Point } from '../history/types'; +import { localize, registerStrings } from '../localize'; +import type { ResolvedEntity } from '../resolve'; +import type { CardConfig } from '../types'; +import { areaStyles, drawArea, zeroFloor } from './area'; +import { column, columnStyles, groupHeading } from './column'; +import { seriesPath } from './line'; +import type { ChartContext, ChartEditorContext, ChartStyleModule } from './index'; + +export const SERIES_TYPES = ['line', 'column', 'area'] as const; +export type SeriesType = (typeof SERIES_TYPES)[number]; +export const Y_AXES = ['auto', 'left', 'right'] as const; +type Side = 'left' | 'right'; + +/** Gaps between value labels on the right axis, as on the left. */ +const VALUE_GAPS = 4; + +registerStrings('en', { + editor_style_combined: 'Combined', + editor_series_type: 'Draw as', + editor_series_type_line: 'Line', + editor_series_type_column: 'Columns', + editor_series_type_area: 'Area', + editor_series_axis: 'Value axis', + editor_series_axis_auto: 'Automatic (by unit)', + editor_series_axis_left: 'Left', + editor_series_axis_right: 'Right', + editor_series_aggregate: 'Combine with', + editor_series_aggregate_auto: 'As the card', + editor_series_aggregate_mean: 'Average', + editor_series_aggregate_sum: 'Sum', + editor_series_aggregate_min: 'Lowest', + editor_series_aggregate_max: 'Highest', + editor_series_aggregate_first: 'First', + editor_series_aggregate_last: 'Last', + editor_series_aggregate_change: 'Change (meters that count up)', +}); + +type Own = { type?: SeriesType; y_axis?: Side; aggregate?: Aggregate }; +const own = (e: ResolvedEntity) => e.config as unknown as Own; + +/** How a series is drawn: its own `type`, else a line. */ +export const seriesType = (e: ResolvedEntity): SeriesType => own(e).type ?? 'line'; + +/** + * Which value axis each series uses: its own `y_axis`, else left for the first series' unit and + * right for any other. When nothing ends up on the left, everything moves there. + */ +export function axisSides(items: readonly ResolvedEntity[]): Side[] { + const first = items[0]?.unit; + const sides = items.map((e) => own(e).y_axis ?? (e.unit === first ? 'left' : 'right')); + return sides.includes('left') ? sides : sides.map(() => 'left'); +} + +/** + * The card config the shared frame reads. With any column series and no `group_by` (or `auto`), + * readings are grouped to fit the span, as on the column chart; without columns, auto means not + * grouped. `none` never groups. + */ +export function combinedRaw(raw: CardConfig, items: readonly ResolvedEntity[]): CardConfig { + const out: Record = { ...raw }; + const columns = items.some((e) => seriesType(e) === 'column'); + if (raw.group_by === 'none' || ((raw.group_by === undefined || raw.group_by === 'auto') && !columns)) { + delete out.group_by; + } else if (raw.group_by === undefined || raw.group_by === 'auto') { + out.group_by = autoGroupUnit(parsePeriod(raw.period as CardConfig['period'])); + } + if (raw.aggregate === 'auto') delete out.aggregate; + return out as CardConfig; +} + +/** + * How one series' groups are combined: its own `aggregate`, else the card's when set, else a + * meter's change (energy per day) and anything else's average (the day's temperature). + */ +export function seriesAggregate(e: ResolvedEntity, raw: CardConfig): Aggregate { + const card = raw.aggregate; + return own(e).aggregate ?? (card && card !== 'auto' ? (card as Aggregate) : isMeter(e) ? 'change' : 'mean'); +} + +function validate(raw: CardConfig): void { + if (raw.group_by !== undefined && !COLUMN_GROUPS.includes(raw.group_by as (typeof COLUMN_GROUPS)[number])) { + throw new Error(`"group_by" must be one of: ${COLUMN_GROUPS.join(', ')}`); + } + if (raw.aggregate !== undefined && !COLUMN_AGGREGATES.includes(raw.aggregate as (typeof COLUMN_AGGREGATES)[number])) { + throw new Error(`"aggregate" must be one of: ${COLUMN_AGGREGATES.join(', ')}`); + } + const shared: Record = { ...raw }; + if (raw.group_by === 'auto' || raw.group_by === 'none') delete shared.group_by; + if (raw.aggregate === 'auto') delete shared.aggregate; + validateHistoryOptions(shared as CardConfig); + parseGrouping(shared as CardConfig); + validateAxisOptions(raw); + validateTooltipOptions(raw); + validateSeriesStyle(raw); + validateLayout(raw); + if (raw.rounded !== undefined && typeof raw.rounded !== 'boolean') throw new Error('"rounded" must be true or false'); + for (const e of raw.entities ?? []) { + if (typeof e !== 'object') continue; + const o = e as unknown as Own; + if (o.type !== undefined && !SERIES_TYPES.includes(o.type)) { + throw new Error(`"type" of ${e.entity} must be one of: ${SERIES_TYPES.join(', ')}`); + } + if (o.y_axis !== undefined && o.y_axis !== 'left' && o.y_axis !== 'right') { + throw new Error(`"y_axis" of ${e.entity} must be one of: left, right`); + } + if (o.aggregate !== undefined && !AGGREGATES.includes(o.aggregate)) { + throw new Error(`"aggregate" of ${e.entity} must be one of: ${AGGREGATES.join(', ')}`); + } + } +} + +/** Lowest and highest of the given series' values, with zero in when columns stand on it. */ +function sideExtent(series: ChartSeries[], types: SeriesType[]): [number, number] | undefined { + const values = series.flatMap((s) => s.points.map((p) => p.v)); + return spread(values, types.includes('column')); +} + +function render(ctx0: ChartContext): TemplateResult { + const ctx = { ...ctx0, raw: combinedRaw(ctx0.raw, ctx0.items) }; + const raw = ctx.raw; + const frame = historyFrame(ctx, Date.now(), { aggregate: (e) => seriesAggregate(e, ctx0.raw) }); + const nav = periodNav(frame, ctx); + const names = seriesHeader(frame, ctx); + const header = nav === nothing && names === nothing ? nothing : html`${nav}${names}`; + const message = frameMessage(frame, ctx); + const layout = chartLayout(raw); + if (message) return chartFrame(layout.header === 'over' ? { ...layout, header: 'above' } : layout, header, message); + const types = frame.series.map((s) => seriesType(s.entity)); + const sides = axisSides(frame.series.map((s) => s.entity)); + const group = frame.group; + // Grouped, each reading is drawn in the middle of its group, so lines pass over the columns. + const series: ChartSeries[] = frame.series.map((s) => + group ? { ...s, points: s.points.map((p) => ({ ...p, t: p.end !== undefined ? (p.t + p.end) / 2 : p.t })) } : s, + ); + const lastEnd = group + ? Math.max(frame.range.end, ...frame.series.flatMap((s) => s.points.map((p) => p.end ?? 0))) + : 0; + const xRange = group ? { ...frame.range, end: lastEnd } : frame.range; + const on = (side: Side) => series.filter((_, i) => sides[i] === side); + const typesOn = (side: Side) => types.filter((_, i) => sides[i] === side); + // Left: the shared axes (options, gridlines, a set lowest/highest). Columns stand on zero, and + // areas reaching down near it do. + const leftData = sideExtent(on('left'), typesOn('left')); + let leftRaw = raw; + if (leftData && typesOn('left').includes('column')) { + leftRaw = { + ...raw, + y_min: raw.y_min ?? (leftData[0] >= 0 ? 0 : undefined), + y_max: raw.y_max ?? (leftData[1] <= 0 ? 0 : undefined), + }; + } else if (typesOn('left').includes('area')) leftRaw = zeroFloor(leftData, raw); + const axes = plotAxes({ ...ctx, raw: leftRaw }, xRange, leftData); + const left = axes.scales; + // Right: its own round steps over its series' readings. + const rightSeries = on('right'); + const rightData = sideExtent(rightSeries, typesOn('right')); + const rightFixed: { min?: number; max?: number } = {}; + if (rightData && (typesOn('right').includes('column') || typesOn('right').includes('area'))) { + if (rightData[0] >= 0 && rightData[0] <= rightData[1] / 2) rightFixed.min = 0; + if (rightData[1] <= 0 && rightData[1] >= rightData[0] / 2) rightFixed.max = 0; + } + const rightAxis = rightSeries.length ? valueAxis(rightData, rightFixed, VALUE_GAPS) : undefined; + const right: PlotScales | undefined = rightAxis + ? { x: left.x, y: linear(rightAxis.domain, [VIEW_H, 0]), domain: rightAxis.domain } + : undefined; + const scalesOf = (s: ChartSeries) => (sides[s.index] === 'right' && right ? right : left); + + // Areas at the back, then columns, then lines on top. + const areas = series + .filter((s) => types[s.index] === 'area') + .map((s) => drawArea(s, s.points, scalesOf(s), raw, { range: xRange })); + const lines = series + .filter((s) => types[s.index] === 'line') + .map((s) => seriesPath({ ...s, points: s.points }, scalesOf(s), s.color, xRange, raw)); + const columnSeries = series.filter((s) => types[s.index] === 'column'); + const table = columnTable( + frame.series.filter((s) => types[s.index] === 'column').map((s) => s.points), + group ? Infinity : frame.range.end, + ); + const radius = raw.rounded === false ? 0 : 4; + const columns: TemplateResult[] = []; + table.times.forEach((t, i) => { + const x0 = left.x(t); + const x1 = left.x(table.ends[i]); + columnSeries.forEach((s, k) => { + const v = table.values[k][i]; + if (v === null) return; + const sc = scalesOf(s); + const base = Math.min(Math.max(0, sc.domain[0]), sc.domain[1]); + const [l, w] = columnBox(x0, x1, k, columnSeries.length); + columns.push( + column(sc, l, w, Math.min(base, v), Math.max(base, v), s.color, v >= base ? 'top' : 'bottom', s.index), + ); + }); + }); + // Column series read their slot (middle) in the tooltip; others their nearest reading. + const centres = table.times.map((t, i) => (t + table.ends[i]) / 2); + const shown = series.map((s) => { + if (types[s.index] !== 'column' || group) return s; + const k = columnSeries.indexOf(s); + return { ...s, points: centres.map((t, i): Point => ({ t, v: table.values[k][i] })) }; + }); + const bounds = new Map(); + for (const s of frame.series) + for (const p of s.points) if (p.end !== undefined) bounds.set((p.t + p.end) / 2, [p.t, p.end]); + const tooltip = tooltipEnabled(raw); + const label = localize(ctx.hass, 'chart_aria', { + style: localize(ctx.hass, 'editor_style_combined'), + names: frame.series.map((s) => s.entity.name).join(', '), + }); + return chartFrame( + layout, + header, + chartArea({ + axes, + ctx, + right: rightAxis && right ? { value: rightAxis, y: right.y } : undefined, + content: svg`${areas.map((a) => a.body)}`, + defs: svg`${areas.map((a) => a.defs)}`, + label, + overlay: html`
${columns}
+ + ${layout.header === 'over' ? headerOver(header) : nothing} + ${ + tooltip + ? tooltipLayer(ctx, shown, left, hoverTime(ctx.host), plotWidth(ctx), { + dotY: (s, p) => (types[s.index] === 'column' || p.v === null ? null : scalesOf(s).y(p.v)), + heading: (t) => { + const b = bounds.get(t); + return b && group ? groupHeading(b[0], b[1], group.unit, ctx.hass) : formatDateTime(t, ctx.hass); + }, + }) + : nothing + }`, + hover: tooltip + ? hoverHandlers( + ctx, + xRange, + shown.map((s) => s.points), + ) + : undefined, + }), + ); +} + +const COMBINED_FIELDS: FieldBinding[] = [ + ...HISTORY_FIELDS.map((f) => (f.name === 'group_by' || f.name === 'aggregate' ? { ...f, default: 'auto' } : f)), + { name: 'curve', path: ['curve'], default: 'smooth' }, + { name: 'line_width', path: ['line_width'], default: DEFAULT_LINE_WIDTH }, + { name: 'dots', path: ['dots'], default: false }, + { name: 'rounded', path: ['rounded'], default: true }, + ...AXES_FIELDS, + ...LAYOUT_FIELDS, +]; + +export function combinedEditor(ctx: ChartEditorContext): TemplateResult { + const ungrouped = ctx.config.group_by === 'none'; + const period = { ...ctx.config, group_by: undefined }; + const schema = cachedSchema(`combined|${historyVariant(period)}|${ungrouped}`, ctx.hass, () => [ + // The shared period fields without their grouping row: this chart has its own choices. + ...historySchema(ctx.hass, period).slice(0, -1), + { + type: 'grid', + name: '', + schema: [ + { name: 'group_by', selector: choice(ctx.hass, 'group_by', COLUMN_GROUPS) }, + ...(ungrouped ? [] : [{ name: 'aggregate', selector: choice(ctx.hass, 'aggregate', COLUMN_AGGREGATES) }]), + ], + }, + { name: 'curve', selector: choice(ctx.hass, 'curve', CURVES) }, + { + type: 'grid', + name: '', + schema: [ + { name: 'line_width', selector: LINE_WIDTH_SELECTOR }, + { name: 'dots', selector: { boolean: {} } }, + { name: 'rounded', selector: { boolean: {} } }, + ], + }, + ...axesSchema(ctx.hass), + ...layoutSchema(ctx.hass), + ]); + return chartForm(ctx, 'chart', schema, COMBINED_FIELDS); +} + +const ENTITY_FIELDS: FieldBinding[] = [ + { name: 'series_type', path: ['type'], default: 'line' }, + { name: 'series_axis', path: ['y_axis'], default: 'auto' }, + { name: 'series_color', path: ['color'] }, + { name: 'series_aggregate', path: ['aggregate'], default: 'auto' }, + { name: 'curve', path: ['curve'] }, + { name: 'line_width', path: ['line_width'] }, + { name: 'dash', path: ['dash'], default: false }, + { name: 'negative_color', path: ['negative_color'] }, +]; + +export const combined: ChartStyleModule = { + layout: 'chart', + group: 'history', + height: 240, + styles: css` + ${frameStyles} + ${gridStyles} + ${tooltipStyles} + ${layoutStyles} + ${areaStyles} + ${columnStyles} + .lines-over { + pointer-events: none; + } + .lines-over .line { + stroke-linecap: round; + stroke-linejoin: round; + } + .lines-over .dots { + stroke-linecap: round; + } + .lines-over .line.dashed { + stroke-dasharray: 6 5; + } + `, + thumbnail: () => svg` + + + + `, + validate, + editor: combinedEditor, + entityFields: (hass) => ({ + schema: cachedSchema('combined-entity', hass, () => [ + { + type: 'grid', + name: '', + schema: [ + { name: 'series_type', selector: choice(hass, 'series_type', SERIES_TYPES) }, + { name: 'series_axis', selector: choice(hass, 'series_axis', Y_AXES) }, + { name: 'series_color', selector: { text: {} } }, + { name: 'series_aggregate', selector: choice(hass, 'series_aggregate', ['auto', ...AGGREGATES]) }, + ], + }, + { + type: 'grid', + name: '', + schema: [ + { name: 'curve', selector: choice(hass, 'curve', CURVES) }, + { name: 'line_width', selector: LINE_WIDTH_SELECTOR }, + { name: 'dash', selector: { boolean: {} } }, + { name: 'negative_color', selector: { text: {} } }, + ], + }, + ]), + fields: ENTITY_FIELDS, + }), + disconnect(host) { + disconnectHistory(host); + stopChartWidth(host); + stopHover(host); + }, + render, +}; diff --git a/src/styles/index.ts b/src/styles/index.ts index f74dbda..2a06cfe 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -5,6 +5,7 @@ import type { CardConfig, HomeAssistant, NormalizedConfig, ShowOptions, StyleNam import { area } from './area'; import { bar } from './bar'; import { columnChart } from './column'; +import { combined } from './combined'; import { line } from './line'; import { needle } from './needle'; import { arc, ring } from './radial'; @@ -110,4 +111,5 @@ export const STYLES: Record = { line, column: columnChart, area, + combined, }; diff --git a/src/styles/line.ts b/src/styles/line.ts index 4db129e..33cfcbe 100644 --- a/src/styles/line.ts +++ b/src/styles/line.ts @@ -72,7 +72,8 @@ function bandGradient(id: string, bands: ResolvedBand[], scales: PlotScales): SV `; } -function seriesPath(s: ChartSeries, scales: PlotScales, stroke: string, range: Range, raw: CardConfig) { +/** One series' line (and dots), for the line chart and the combined chart. */ +export function seriesPath(s: ChartSeries, scales: PlotScales, stroke: string, range: Range, raw: CardConfig) { const style = seriesStyle(s.entity.config, raw); const thinned = downsample(s.points, MAX_POINTS); const d = runs(thinned) diff --git a/src/types.ts b/src/types.ts index 3450938..f72ec6d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,6 @@ import type { Rule } from './fill'; -export type StyleName = 'bar' | 'thin' | 'segmented' | 'tank' | 'ring' | 'needle' | 'arc' | 'line' | 'column' | 'area'; +export type StyleName = + 'bar' | 'thin' | 'segmented' | 'tank' | 'ring' | 'needle' | 'arc' | 'line' | 'column' | 'area' | 'combined'; export const STYLE_NAMES: StyleName[] = [ 'bar', 'thin', @@ -11,6 +12,7 @@ export const STYLE_NAMES: StyleName[] = [ 'line', 'column', 'area', + 'combined', ]; export type SortMode = 'none' | 'ascending' | 'descending'; /** A number, or a string naming an entity whose state supplies the number. */ diff --git a/test/combined.test.ts b/test/combined.test.ts new file mode 100644 index 0000000..e457edb --- /dev/null +++ b/test/combined.test.ts @@ -0,0 +1,161 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import '../src/chartdeck-card'; +import { axisSides, combinedRaw, seriesAggregate, seriesType } from '../src/styles/combined'; +import type { ResolvedEntity } from '../src/resolve'; +import type { CardConfig } from '../src/types'; +import { H, ago, chartHass, mountCard, mountEditor, pointAt, q, qa, tooltipRows } from './helpers/chart'; +import type { Card } from './helpers/chart'; + +const now = Date.now(); +const sec = (ms: number) => ago(now, ms); +const D = 24 * H; + +const states = { + 'sensor.energy': ['1000', { friendly_name: 'Energy', unit_of_measurement: 'kWh', state_class: 'total_increasing' }], + 'sensor.temp': ['20', { friendly_name: 'Temp', unit_of_measurement: '°C', state_class: 'measurement' }], + 'sensor.power': ['300', { friendly_name: 'Power', unit_of_measurement: 'W' }], +} as const; + +const history = { + 'sensor.energy': Array.from({ length: 11 }, (_, i) => ({ s: String(1000 + 10 * i), lu: sec((10 - i) * D + H) })), + 'sensor.temp': [ + { s: '15', lu: sec(8 * D) }, + { s: '25', lu: sec(3 * D) }, + { s: '18', lu: sec(5 * H) }, + ], + 'sensor.power': [ + { s: '400', lu: sec(20 * H) }, + { s: '-600', lu: sec(10 * H) }, + { s: 'unavailable', lu: sec(5 * H) }, + ], +}; + +const mount = (config: Record) => + mountCard({ style: 'combined', ...config } as Partial, chartHass(states, history)); + +const entity = (unit: string, extra: Record = {}, attrs: Record = {}) => + ({ unit, config: { entity: 'sensor.x', ...extra }, stateObj: { attributes: attrs } }) as unknown as ResolvedEntity; + +afterEach(() => { + document.body.innerHTML = ''; +}); + +describe('combined chart maths', () => { + it('puts a second unit on the right axis, unless told', () => { + expect(axisSides([entity('kWh'), entity('°C'), entity('kWh')])).toEqual(['left', 'right', 'left']); + expect(axisSides([entity('kWh'), entity('°C', { y_axis: 'left' })])).toEqual(['left', 'left']); + expect(axisSides([entity('kWh', { y_axis: 'right' })])).toEqual(['left']); + expect(seriesType(entity('W'))).toBe('line'); + expect(seriesType(entity('W', { type: 'area' }))).toBe('area'); + }); + + it('groups to fit only when there are columns, and combines each series its own way', () => { + const raw = { type: 'x', period: { last: 7, unit: 'day' } } as CardConfig; + const col = entity('kWh', { type: 'column' }, { state_class: 'total_increasing' }); + expect(combinedRaw(raw, [col]).group_by).toBe('day'); + expect(combinedRaw(raw, [entity('W')]).group_by).toBeUndefined(); + expect(combinedRaw({ ...raw, group_by: 'none' }, [col]).group_by).toBeUndefined(); + expect(combinedRaw({ ...raw, group_by: 'hour', aggregate: 'auto' }, [col])).toMatchObject({ group_by: 'hour' }); + expect(combinedRaw({ ...raw, aggregate: 'auto' }, [col])).not.toHaveProperty('aggregate'); + expect(seriesAggregate(col, raw)).toBe('change'); + expect(seriesAggregate(entity('°C'), raw)).toBe('mean'); + expect(seriesAggregate(entity('°C'), { ...raw, aggregate: 'max' })).toBe('max'); + expect(seriesAggregate(entity('°C', { aggregate: 'min' }), { ...raw, aggregate: 'max' })).toBe('min'); + }); +}); + +describe('combined chart', () => { + it('draws daily energy columns with the average temperature as a line on a second axis', async () => { + const card = await mount({ + period: { last: 7, unit: 'day' }, + entities: [{ entity: 'sensor.energy', type: 'column' }, 'sensor.temp'], + }); + expect(qa(card, '.col').length).toBeGreaterThanOrEqual(7); + expect(qa(card, '.lines-over path.line')).toHaveLength(1); + expect(q(card, '.plot-wrap')!.classList.contains('has-right')).toBe(true); + expect(qa(card, '.y-axis.right .axis-label').length).toBeGreaterThan(1); + expect(q(card, 'svg.plot')!.getAttribute('aria-label')).toBe('Combined chart of Energy, Temp'); + pointAt(q(card, '.plot-area')!, 'pointermove', 0.5); + await card.updateComplete; + const rows = tooltipRows(card); + expect(rows[0]).toBe('Energy 10.0 kWh'); + expect(rows[1]).toMatch(/^Temp \d+\.\d °C$/); + // A dot on the line only. + expect(qa(card, '.hover-dot')).toHaveLength(1); + }); + + it('draws an area with a line, and all three together', async () => { + const two = await mount({ + entities: [ + { entity: 'sensor.power', type: 'area' }, + { entity: 'sensor.temp', y_axis: 'left' }, + ], + }); + expect(qa(two, 'path.fill')).toHaveLength(1); + expect(qa(two, '.lines-over path.line')).toHaveLength(1); + expect(q(two, '.plot-wrap')!.classList.contains('has-right')).toBe(false); + const three = await mount({ + period: { last: 2, unit: 'day' }, + axis_labels: 'inside', + entities: [ + { entity: 'sensor.power', type: 'area' }, + { entity: 'sensor.energy', type: 'column', y_axis: 'right' }, + 'sensor.temp', + ], + }); + expect(qa(three, 'path.fill')).toHaveLength(1); + expect(qa(three, '.col').length).toBeGreaterThan(0); + expect(qa(three, '.lines-over path.line')).toHaveLength(1); + expect(q(three, '.plot-area .y-axis.right')).not.toBeNull(); + }); + + it('draws one column per reading when not grouped', async () => { + const card = await mount({ + group_by: 'none', + entities: [{ entity: 'sensor.power', type: 'column' }, 'sensor.temp'], + }); + expect(qa(card, '.col')).toHaveLength(2); + pointAt(q(card, '.plot-area')!, 'pointermove', 1 - 15 / 24); + await card.updateComplete; + expect(tooltipRows(card)[0]).toBe('Power 400.0 W'); + }); + + it('checks its options', () => { + const card = document.createElement('chartdeck-card') as Card; + const set = (extra: Record) => () => + card.setConfig({ type: 'x', style: 'combined', entities: ['sensor.temp'], ...extra } as CardConfig); + expect(set({ entities: [{ entity: 'sensor.temp', type: 'pie' }] })).toThrow(/type/); + expect(set({ entities: [{ entity: 'sensor.temp', y_axis: 'middle' }] })).toThrow(/y_axis/); + expect(set({ entities: [{ entity: 'sensor.temp', aggregate: 'median' }] })).toThrow(/aggregate/); + expect(set({ group_by: 'year' })).toThrow(/group_by/); + expect(set({ aggregate: 'median' })).toThrow(/aggregate/); + expect(set({ rounded: 'no' })).toThrow(/rounded/); + expect( + set({ + group_by: 'auto', + aggregate: 'auto', + entities: [{ entity: 'sensor.temp', type: 'area', y_axis: 'right' }], + }), + ).not.toThrow(); + }); +}); + +describe('combined chart editor', () => { + it('edits the chart, and each entity’s type, axis and combining', async () => { + const raw = { type: 'custom:chartdeck-card', style: 'combined', entities: ['sensor.temp'] } as CardConfig; + const { form, change, events, entityFields } = await mountEditor(raw, chartHass(states, {})); + expect(form().data).toMatchObject({ group_by: 'auto', aggregate: 'auto', curve: 'smooth', rounded: true }); + change({ group_by: 'none', rounded: false }); + expect(events.at(-1)).toEqual({ ...raw, group_by: 'none', rounded: false }); + expect(entityFields().fields.map((f) => f.name)).toEqual([ + 'series_type', + 'series_axis', + 'series_color', + 'series_aggregate', + 'curve', + 'line_width', + 'dash', + 'negative_color', + ]); + }); +});