lots of new changes

* HACS badge
* hacs.json
* New action handling with double tap support
* Cleanup
This commit is contained in:
Ian Richardson committed 2019-10-30 12:44:59 -05:00
1 parent 3e606bbfd7
commit 078499f029
10 files changed
+695 -1244

No files matched your search

+7 -2
View File
@@ -4,6 +4,7 @@ A community driven boilerplate of best practices for Home Assistant Lovelace cus
[![GitHub Release][releases-shield]][releases]
[![License][license-shield]](LICENSE.md)
[![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge)](https://github.com/custom-components/hacs)
![Project Maintenance][maintenance-shield]
[![GitHub Activity][commits-shield]][commits]
@@ -50,9 +51,13 @@ Install necessary modules
Do a test lint & build on the project. You can see available scripts in the package.json
`npm run build`
### Step 4
## Step 4
Customize to suit your needs and contribute it back to the custom-cards org
Search the repo for all instances of "TODO" and handle the changes/suggestions
### Step 5
Customize to suit your needs and contribute it back to the community
[Troubleshooting](https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins)
+18
View File
@@ -0,0 +1,18 @@
function t(t,e,n,s){var i,r=arguments.length,o=r<3?e:null===s?s=Object.getOwnPropertyDescriptor(e,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(t,e,n,s);else for(var a=t.length-1;a>=0;a--)(i=t[a])&&(o=(r<3?i(o):r>3?i(e,n,o):i(e,n))||o);return r>3&&o&&Object.defineProperty(e,n,o),o}const e=new WeakMap,n=t=>"function"==typeof t&&e.has(t),s=void 0!==window.customElements&&void 0!==window.customElements.polyfillWrapFlushCallback,i=(t,e,n=null)=>{for(;e!==n;){const n=e.nextSibling;t.removeChild(e),e=n}},r={},o={},a=`{{lit-${String(Math.random()).slice(2)}}}`,c=`\x3c!--${a}--\x3e`,l=new RegExp(`${a}|${c}`),d="$lit$";class h{constructor(t,e){this.parts=[],this.element=e;const n=[],s=[],i=document.createTreeWalker(e.content,133,null,!1);let r=0,o=-1,c=0;const{strings:h,values:{length:p}}=t;for(;c<p;){const t=i.nextNode();if(null!==t){if(o++,1===t.nodeType){if(t.hasAttributes()){const e=t.attributes,{length:n}=e;let s=0;for(let t=0;t<n;t++)u(e[t].name,d)&&s++;for(;s-- >0;){const e=h[c],n=f.exec(e)[2],s=n.toLowerCase()+d,i=t.getAttribute(s);t.removeAttribute(s);const r=i.split(l);this.parts.push({type:"attribute",index:o,name:n,strings:r}),c+=r.length-1}}"TEMPLATE"===t.tagName&&(s.push(t),i.currentNode=t.content)}else if(3===t.nodeType){const e=t.data;if(e.indexOf(a)>=0){const s=t.parentNode,i=e.split(l),r=i.length-1;for(let e=0;e<r;e++){let n,r=i[e];if(""===r)n=m();else{const t=f.exec(r);null!==t&&u(t[2],d)&&(r=r.slice(0,t.index)+t[1]+t[2].slice(0,-d.length)+t[3]),n=document.createTextNode(r)}s.insertBefore(n,t),this.parts.push({type:"node",index:++o})}""===i[r]?(s.insertBefore(m(),t),n.push(t)):t.data=i[r],c+=r}}else if(8===t.nodeType)if(t.data===a){const e=t.parentNode;null!==t.previousSibling&&o!==r||(o++,e.insertBefore(m(),t)),r=o,this.parts.push({type:"node",index:o}),null===t.nextSibling?t.data="":(n.push(t),o--),c++}else{let e=-1;for(;-1!==(e=t.data.indexOf(a,e+1));)this.parts.push({type:"node",index:-1}),c++}}else i.currentNode=s.pop()}for(const t of n)t.parentNode.removeChild(t)}}const u=(t,e)=>{const n=t.length-e.length;return n>=0&&t.slice(n)===e},p=t=>-1!==t.index,m=()=>document.createComment(""),f=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=\/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;class _{constructor(t,e,n){this.__parts=[],this.template=t,this.processor=e,this.options=n}update(t){let e=0;for(const n of this.__parts)void 0!==n&&n.setValue(t[e]),e++;for(const t of this.__parts)void 0!==t&&t.commit()}_clone(){const t=s?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),e=[],n=this.template.parts,i=document.createTreeWalker(t,133,null,!1);let r,o=0,a=0,c=i.nextNode();for(;o<n.length;)if(r=n[o],p(r)){for(;a<r.index;)a++,"TEMPLATE"===c.nodeName&&(e.push(c),i.currentNode=c.content),null===(c=i.nextNode())&&(i.currentNode=e.pop(),c=i.nextNode());if("node"===r.type){const t=this.processor.handleTextExpression(this.options);t.insertAfterNode(c.previousSibling),this.__parts.push(t)}else this.__parts.push(...this.processor.handleAttributeExpressions(c,r.name,r.strings,this.options));o++}else this.__parts.push(void 0),o++;return s&&(document.adoptNode(t),customElements.upgrade(t)),t}}const g=` ${a} `;class y{constructor(t,e,n,s){this.strings=t,this.values=e,this.type=n,this.processor=s}getHTML(){const t=this.strings.length-1;let e="",n=!1;for(let s=0;s<t;s++){const t=this.strings[s],i=t.lastIndexOf("\x3c!--");n=(i>-1||n)&&-1===t.indexOf("--\x3e",i+1);const r=f.exec(t);e+=null===r?t+(n?g:c):t.substr(0,r.index)+r[1]+r[2]+d+r[3]+a}return e+=this.strings[t]}getTemplateElement(){const t=document.createElement("template");return t.innerHTML=this.getHTML(),t}}const v=t=>null===t||!("object"==typeof t||"function"==typeof t),S=t=>Array.isArray(t)||!(!t||!t[Symbol.iterator]);class w{constructor(t,e,n){this.dirty=!0,this.element=t,this.name=e,this.strings=n,this.parts=[];for(let t=0;t<n.length-1;t++)this.parts[t]=this._createPart()}_createPart(){return new b(this)}_getValue(){const t=this.strings,e=t.length-1;let n="";for(let s=0;s<e;s++){n+=t[s];const e=this.parts[s];if(void 0!==e){const t=e.value;if(v(t)||!S(t))n+="string"==typeof t?t:String(t);else for(const e of t)n+="string"==typeof e?e:String(e)}}return n+=t[e]}commit(){this.dirty&&(this.dirty=!1,this.element.setAttribute(this.name,this._getValue()))}}class b{constructor(t){this.value=void 0,this.committer=t}setValue(t){t===r||v(t)&&t===this.value||(this.value=t,n(t)||(this.committer.dirty=!0))}commit(){for(;n(this.value);){const t=this.value;this.value=r,t(this)}this.value!==r&&this.committer.commit()}}class x{constructor(t){this.value=void 0,this.__pendingValue=void 0,this.options=t}appendInto(t){this.startNode=t.appendChild(m()),this.endNode=t.appendChild(m())}insertAfterNode(t){this.startNode=t,this.endNode=t.nextSibling}appendIntoPart(t){t.__insert(this.startNode=m()),t.__insert(this.endNode=m())}insertAfterPart(t){t.__iLine truncated
<ha-card>
<div class="warning">Show Warning</div>
</ha-card>
`:O`
<ha-card
.header=${this._config.name}
@action=${this._handleAction}
.actionHandler=${Dt({hasHold:Tt(this._config.hold_action),hasDoubleTap:Tt(this._config.double_tap_action)})}
></ha-card>
`:O``}_handleAction(t){Et(this,this.hass,this._config,t.detail.action)}static get styles(){return ct`
.warning {
display: block;
color: black;
background-color: #fce588;
padding: 8px;
}
`}};t([it()],Vt.prototype,"hass",void 0),t([it()],Vt.prototype,"_config",void 0),Vt=t([(t=>e=>"function"==typeof e?((t,e)=>(window.customElements.define(t,e),e))(t,e):((t,e)=>{const{kind:n,elements:s}=e;return{kind:n,elements:s,finisher(e){window.customElements.define(t,e)}}})(t,e))("boilerplate-card")],Vt);
-19
View File
@@ -1,19 +0,0 @@
function t(t,e,s,n){var i,r=arguments.length,o=r<3?e:null===n?n=Object.getOwnPropertyDescriptor(e,s):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(t,e,s,n);else for(var a=t.length-1;a>=0;a--)(i=t[a])&&(o=(r<3?i(o):r>3?i(e,s,o):i(e,s))||o);return r>3&&o&&Object.defineProperty(e,s,o),o}const e=new WeakMap,s=t=>"function"==typeof t&&e.has(t),n=void 0!==window.customElements&&void 0!==window.customElements.polyfillWrapFlushCallback,i=(t,e,s=null)=>{let n=e;for(;n!==s;){const e=n.nextSibling;t.removeChild(n),n=e}},r={},o={},a=`{{lit-${String(Math.random()).slice(2)}}}`,c=`\x3c!--${a}--\x3e`,l=new RegExp(`${a}|${c}`),h="$lit$";class d{constructor(t,e){this.parts=[],this.element=e;let s=-1,n=0;const i=[],r=e=>{const o=e.content,c=document.createTreeWalker(o,133,null,!1);let d=0;for(;c.nextNode();){s++;const e=c.currentNode;if(1===e.nodeType){if(e.hasAttributes()){const i=e.attributes;let r=0;for(let t=0;t<i.length;t++)i[t].value.indexOf(a)>=0&&r++;for(;r-- >0;){const i=t.strings[n],r=m.exec(i)[2],o=r.toLowerCase()+h,a=e.getAttribute(o).split(l);this.parts.push({type:"attribute",index:s,name:r,strings:a}),e.removeAttribute(o),n+=a.length-1}}"TEMPLATE"===e.tagName&&r(e)}else if(3===e.nodeType){const t=e.data;if(t.indexOf(a)>=0){const r=e.parentNode,o=t.split(l),a=o.length-1;for(let t=0;t<a;t++)r.insertBefore(""===o[t]?u():document.createTextNode(o[t]),e),this.parts.push({type:"node",index:++s});""===o[a]?(r.insertBefore(u(),e),i.push(e)):e.data=o[a],n+=a}}else if(8===e.nodeType)if(e.data===a){const t=e.parentNode;null!==e.previousSibling&&s!==d||(s++,t.insertBefore(u(),e)),d=s,this.parts.push({type:"node",index:s}),null===e.nextSibling?e.data="":(i.push(e),s--),n++}else{let t=-1;for(;-1!==(t=e.data.indexOf(a,t+1));)this.parts.push({type:"node",index:-1})}}};r(e);for(const t of i)t.parentNode.removeChild(t)}}const p=t=>-1!==t.index,u=()=>document.createComment(""),m=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F \x09\x0a\x0c\x0d"'>=\/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;class f{constructor(t,e,s){this._parts=[],this.template=t,this.processor=e,this.options=s}update(t){let e=0;for(const s of this._parts)void 0!==s&&s.setValue(t[e]),e++;for(const t of this._parts)void 0!==t&&t.commit()}_clone(){const t=n?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),e=this.template.parts;let s=0,i=0;const r=t=>{const n=document.createTreeWalker(t,133,null,!1);let o=n.nextNode();for(;s<e.length&&null!==o;){const t=e[s];if(p(t))if(i===t.index){if("node"===t.type){const t=this.processor.handleTextExpression(this.options);t.insertAfterNode(o.previousSibling),this._parts.push(t)}else this._parts.push(...this.processor.handleAttributeExpressions(o,t.name,t.strings,this.options));s++}else i++,"TEMPLATE"===o.nodeName&&r(o.content),o=n.nextNode();else this._parts.push(void 0),s++}};return r(t),n&&(document.adoptNode(t),customElements.upgrade(t)),t}}class y{constructor(t,e,s,n){this.strings=t,this.values=e,this.type=s,this.processor=n}getHTML(){const t=this.strings.length-1;let e="";for(let s=0;s<t;s++){const t=this.strings[s],n=m.exec(t);e+=n?t.substr(0,n.index)+n[1]+n[2]+h+n[3]+a:t+c}return e+this.strings[t]}getTemplateElement(){const t=document.createElement("template");return t.innerHTML=this.getHTML(),t}}const g=t=>null===t||!("object"==typeof t||"function"==typeof t);class _{constructor(t,e,s){this.dirty=!0,this.element=t,this.name=e,this.strings=s,this.parts=[];for(let t=0;t<s.length-1;t++)this.parts[t]=this._createPart()}_createPart(){return new v(this)}_getValue(){const t=this.strings,e=t.length-1;let s="";for(let n=0;n<e;n++){s+=t[n];const e=this.parts[n];if(void 0!==e){const t=e.value;if(null!=t&&(Array.isArray(t)||"string"!=typeof t&&t[Symbol.iterator]))for(const e of t)s+="string"==typeof e?e:String(e);else s+="string"==typeof t?t:String(t)}}return s+=t[e]}commit(){this.dirty&&(this.dirty=!1,this.element.setAttribute(this.name,this._getValue()))}}class v{constructor(t){this.value=void 0,this.committer=t}setValue(t){t===r||g(t)&&t===this.value||(this.value=t,s(t)||(this.committer.dirty=!0))}commit(){for(;s(this.value);){const t=this.value;this.value=r,t(this)}this.value!==r&&this.committer.commit()}}class w{constructor(t){this.value=void 0,this._pendingValue=void 0,this.options=t}appendInto(t){this.startNode=t.appendChild(u()),this.endNode=t.appendChild(u())}insertAfterNode(t){this.startNode=t,this.endNode=t.nextSibling}appendIntoPart(t){t._insert(this.startNode=u()),t._insert(this.endNode=u())}insertAfterPart(t){t._insert(this.startNode=u()),this.endNode=t.endNode,t.endNode=this.startNode}setValue(t){this._pendingValue=t}commit(){for(;s(this._pendingValue);){const t=this._pendingValue;this._pendingValue=r,t(this)}const t=this._pendingValue;t!==r&&(g(t)?t!==this.value&&this._commitText(t):t instanceof y?this._commitTemplateResult(t):t instanceof Node?this._commitNode(t):Array.isArray(t)||t[SLine truncated
<ha-card>
<div class="warning">Show Warning</div>
</ha-card>
`:V`
<ha-card
.header=${this._config.name?this._config.name:"Boilerplate"}
@ha-click="${this._handleTap}"
@ha-hold="${this._handleHold}"
.longpress="${ft()}"
></ha-card>
`:V``}_handleTap(){dt(this,this.hass,this._config,!1)}_handleHold(){dt(this,this.hass,this._config,!0)}static get styles(){return it`
.warning {
display: block;
color: black;
background-color: #fce588;
padding: 8px;
}
`}};t([tt()],yt.prototype,"hass",void 0),t([tt()],yt.prototype,"_config",void 0),yt=t([(t=>e=>"function"==typeof e?((t,e)=>(window.customElements.define(t,e),e))(t,e):((t,e)=>{const{kind:s,elements:n}=e;return{kind:s,elements:n,finisher(e){window.customElements.define(t,e)}}})(t,e))("boilerplate-card")],yt);
+4
View File
@@ -0,0 +1,4 @@
{
"name": "Boilerplate Card",
"render_readme": true
}
+19 -19
View File
@@ -1,6 +1,6 @@
{
"name": "boilerplate-card",
"version": "1.1.0",
"version": "1.1.1",
"description": "Lovelace boilerplate-card",
"keywords": [
"home-assistant",
@@ -12,30 +12,30 @@
],
"module": "boilerplate-card.js",
"repository": "git@github.com:custom_cards/boilerplate-card.git",
"author": "BoilerPlate <boilerplate@email.com>",
"author": "Ian Richardson <iantrich@gmail.com>",
"license": "MIT",
"dependencies": {
"custom-card-helpers": "^1.0.8",
"home-assistant-js-websocket": "^3.4.0",
"lit-element": "^2.0.1"
"custom-card-helpers": "^1.3.5",
"home-assistant-js-websocket": "^4.4.0",
"lit-element": "^2.2.1"
},
"devDependencies": {
"@babel/core": "^7.4.3",
"@babel/plugin-proposal-class-properties": "^7.4.0",
"@babel/core": "^7.5.5",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-decorators": "^7.4.0",
"@typescript-eslint/eslint-plugin": "^1.4.2",
"@typescript-eslint/parser": "^1.4.1",
"eslint": "^5.14.1",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-import": "^2.16.0",
"prettier": "^1.16.4",
"rollup": "^1.2.3",
"rollup-plugin-babel": "^4.3.2",
"rollup-plugin-node-resolve": "^4.0.1",
"rollup-plugin-terser": "^4.0.4",
"rollup-plugin-typescript2": "^0.19.2",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"eslint": "^6.2.2",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-plugin-import": "^2.18.2",
"prettier": "^1.18.2",
"rollup": "^1.20.2",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-terser": "^5.1.1",
"rollup-plugin-typescript2": "^0.23.0",
"rollup-plugin-uglify": "^6.0.2",
"typescript": "^3.3.3333"
"typescript": "^3.5.3"
},
"scripts": {
"start": "rollup -c --watch",
+1 -1
View File
@@ -4,7 +4,7 @@ import babel from 'rollup-plugin-babel';
import { terser } from "rollup-plugin-terser";
export default {
input: ['src/card.ts'],
input: ['src/boilerplate-card.ts'],
output: {
dir: './dist',
format: 'es',
+206
View File
@@ -0,0 +1,206 @@
import { directive, PropertyPart } from "lit-html";
import { fireEvent, ActionHandlerOptions } from "custom-card-helpers";
const isTouch =
"ontouchstart" in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0;
interface ActionHandler extends HTMLElement {
holdTime: number;
bind(element: Element, options): void;
}
interface ActionHandlerElement extends Element {
actionHandler?: boolean;
}
class ActionHandler extends HTMLElement implements ActionHandler {
public holdTime: number;
public ripple: any;
protected timer: number | undefined;
protected held: boolean;
protected cooldownStart: boolean;
protected cooldownEnd: boolean;
private dblClickTimeout: number | undefined;
constructor() {
super();
this.holdTime = 500;
this.ripple = document.createElement("mwc-ripple");
this.timer = undefined;
this.held = false;
this.cooldownStart = false;
this.cooldownEnd = false;
}
public connectedCallback() {
Object.assign(this.style, {
position: "absolute",
width: isTouch ? "100px" : "50px",
height: isTouch ? "100px" : "50px",
transform: "translate(-50%, -50%)",
pointerEvents: "none",
});
this.appendChild(this.ripple);
this.ripple.primary = true;
[
"touchcancel",
"mouseout",
"mouseup",
"touchmove",
"mousewheel",
"wheel",
"scroll",
].forEach((ev) => {
document.addEventListener(
ev,
() => {
clearTimeout(this.timer);
this.stopAnimation();
this.timer = undefined;
},
{ passive: true }
);
});
}
public bind(element: ActionHandlerElement, options) {
if (element.actionHandler) {
return;
}
element.actionHandler = true;
element.addEventListener("contextmenu", (ev: Event) => {
const e = ev || window.event;
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
e.cancelBubble = true;
e.returnValue = false;
return false;
});
const clickStart = (ev: Event) => {
if (this.cooldownStart) {
return;
}
this.held = false;
let x;
let y;
if ((ev as TouchEvent).touches) {
x = (ev as TouchEvent).touches[0].pageX;
y = (ev as TouchEvent).touches[0].pageY;
} else {
x = (ev as MouseEvent).pageX;
y = (ev as MouseEvent).pageY;
}
if (options.hasHold) {
this.timer = window.setTimeout(() => {
this.startAnimation(x, y);
this.held = true;
}, this.holdTime);
}
this.cooldownStart = true;
window.setTimeout(() => (this.cooldownStart = false), 100);
};
const clickEnd = (ev: Event) => {
if (
this.cooldownEnd ||
(["touchend", "touchcancel"].includes(ev.type) &&
this.timer === undefined)
) {
return;
}
clearTimeout(this.timer);
this.stopAnimation();
this.timer = undefined;
if (this.held) {
fireEvent(element as HTMLElement, "action", { action: "hold" });
} else if (options.hasDoubleTap) {
if ((ev as MouseEvent).detail === 1) {
this.dblClickTimeout = window.setTimeout(() => {
fireEvent(element as HTMLElement, "action", { action: "tap" });
}, 250);
} else {
clearTimeout(this.dblClickTimeout);
fireEvent(element as HTMLElement, "action", { action: "double_tap" });
}
} else {
fireEvent(element as HTMLElement, "action", { action: "tap" });
}
this.cooldownEnd = true;
window.setTimeout(() => (this.cooldownEnd = false), 100);
};
element.addEventListener("touchstart", clickStart, { passive: true });
element.addEventListener("touchend", clickEnd);
element.addEventListener("touchcancel", clickEnd);
// iOS 13 sends a complete normal touchstart-touchend series of events followed by a mousedown-click series.
// That might be a bug, but until it's fixed, this should make action-handler work.
// If it's not a bug that is fixed, this might need updating with the next iOS version.
// Note that all events (both touch and mouse) must be listened for in order to work on computers with both mouse and touchscreen.
const isIOS13 = window.navigator.userAgent.match(/iPhone OS 13_/);
if (!isIOS13) {
element.addEventListener("mousedown", clickStart, { passive: true });
element.addEventListener("click", clickEnd);
}
}
private startAnimation(x: number, y: number) {
Object.assign(this.style, {
left: `${x}px`,
top: `${y}px`,
display: null,
});
this.ripple.disabled = false;
this.ripple.active = true;
this.ripple.unbounded = true;
}
private stopAnimation() {
this.ripple.active = false;
this.ripple.disabled = true;
this.style.display = "none";
}
}
// TODO You need to replace all instances of "action-handler-boilerplate" with "action-handler-<your card name>"
customElements.define("action-handler-boilerplate", ActionHandler);
const geActionHandler = (): ActionHandler => {
const body = document.body;
if (body.querySelector("action-handler-boilerplate")) {
return body.querySelector("action-handler-boilerplate") as ActionHandler;
}
const actionhandler = document.createElement("action-handler-boilerplate");
body.appendChild(actionhandler);
return actionhandler as ActionHandler;
};
export const actionHandlerBind = (
element: ActionHandlerElement,
options: ActionHandlerOptions
) => {
const actionhandler: ActionHandler = geActionHandler();
if (!actionhandler) {
return;
}
actionhandler.bind(element, options);
};
export const actionHandler = directive(
(options: ActionHandlerOptions = {}) => (part: PropertyPart) => {
actionHandlerBind(part.committer.element, options);
}
);
+18 -16
View File
@@ -10,19 +10,20 @@ import {
} from "lit-element";
import {
HomeAssistant,
handleClick,
longPress,
hasConfigOrEntityChanged
hasConfigOrEntityChanged,
hasAction,
ActionHandlerEvent,
handleAction
} from "custom-card-helpers";
import { BoilerplateConfig } from "./types";
import { actionHandler } from "./action-handler-directive";
// TODO Name your custom element
@customElement("boilerplate-card")
class BoilerplateCard extends LitElement {
// TODO Add any properities that should cause your element to re-render here
@property() public hass?: HomeAssistant;
@property() private _config?: BoilerplateConfig;
public setConfig(config: BoilerplateConfig): void {
@@ -31,11 +32,14 @@ class BoilerplateCard extends LitElement {
throw new Error("Invalid configuration");
}
this._config = config;
this._config = {
name: "Boilerplate",
...config
};
}
protected shouldUpdate(changedProps: PropertyValues): boolean {
return hasConfigOrEntityChanged(this, changedProps);
return hasConfigOrEntityChanged(this, changedProps, false);
}
protected render(): TemplateResult | void {
@@ -54,20 +58,18 @@ class BoilerplateCard extends LitElement {
return html`
<ha-card
.header=${this._config.name ? this._config.name : "Boilerplate"}
@ha-click="${this._handleTap}"
@ha-hold="${this._handleHold}"
.longpress="${longPress()}"
.header=${this._config.name}
@action=${this._handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(this._config!.hold_action),
hasDoubleTap: hasAction(this._config!.double_tap_action)
})}
></ha-card>
`;
}
private _handleTap(): void {
handleClick(this, this.hass!, this._config!, false);
}
private _handleHold(): void {
handleClick(this, this.hass!, this._config!, true);
private _handleAction(ev: ActionHandlerEvent) {
handleAction(this, this.hass!, this._config!, ev.detail.action!);
}
static get styles(): CSSResult {
+2 -1
View File
@@ -1,4 +1,4 @@
import { ActionConfig } from "custom-card-helpers";
import { ActionConfig, HASSDomEvent } from "custom-card-helpers";
// TODO Add your configuration elements here for type-checking
export interface BoilerplateConfig {
@@ -9,4 +9,5 @@ export interface BoilerplateConfig {
entity?: string;
tap_aciton?: ActionConfig;
hold_action?: ActionConfig;
double_tap_action?: ActionConfig;
}
+420 -1186
View File
File diff suppressed because it is too large. Load diff