Add custom tile features documentation (#1680)

* Add custom tile features documentation

* Feedbacks
This commit is contained in:
Paul Bottein 2023-02-15 18:58:22 +01:00 committed by GitHub
parent 59ab7df279
commit 838db3fad4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 142 additions and 30 deletions

View File

@ -22,12 +22,12 @@ class ContentCardExample extends HTMLElement {
<div class="card-content"></div> <div class="card-content"></div>
</ha-card> </ha-card>
`; `;
this.content = this.querySelector('div'); this.content = this.querySelector("div");
} }
const entityId = this.config.entity; const entityId = this.config.entity;
const state = hass.states[entityId]; const state = hass.states[entityId];
const stateStr = state ? state.state : 'unavailable'; const stateStr = state ? state.state : "unavailable";
this.content.innerHTML = ` this.content.innerHTML = `
The state of ${entityId} is ${stateStr}! The state of ${entityId} is ${stateStr}!
@ -40,7 +40,7 @@ class ContentCardExample extends HTMLElement {
// will render an error card. // will render an error card.
setConfig(config) { setConfig(config) {
if (!config.entity) { if (!config.entity) {
throw new Error('You need to define an entity'); throw new Error("You need to define an entity");
} }
this.config = config; this.config = config;
} }
@ -52,7 +52,7 @@ class ContentCardExample extends HTMLElement {
} }
} }
customElements.define('content-card-example', ContentCardExample); customElements.define("content-card-example", ContentCardExample);
``` ```
## Referencing your new card ## Referencing your new card
@ -106,7 +106,7 @@ import "https://unpkg.com/wired-toggle@0.8.0/wired-toggle.js?module";
import { import {
LitElement, LitElement,
html, html,
css css,
} from "https://unpkg.com/lit-element@2.0.1/lit-element.js?module"; } from "https://unpkg.com/lit-element@2.0.1/lit-element.js?module";
function loadCSS(url) { function loadCSS(url) {
@ -123,14 +123,14 @@ class WiredToggleCard extends LitElement {
static get properties() { static get properties() {
return { return {
hass: {}, hass: {},
config: {} config: {},
}; };
} }
render() { render() {
return html` return html`
<wired-card elevation="2"> <wired-card elevation="2">
${this.config.entities.map(ent => { ${this.config.entities.map((ent) => {
const stateObj = this.hass.states[ent]; const stateObj = this.hass.states[ent];
return stateObj return stateObj
? html` ? html`
@ -138,13 +138,11 @@ class WiredToggleCard extends LitElement {
${stateObj.attributes.friendly_name} ${stateObj.attributes.friendly_name}
<wired-toggle <wired-toggle
.checked="${stateObj.state === "on"}" .checked="${stateObj.state === "on"}"
@change="${ev => this._toggle(stateObj)}" @change="${(ev) => this._toggle(stateObj)}"
></wired-toggle> ></wired-toggle>
</div> </div>
` `
: html` : html` <div class="not-found">Entity ${ent} not found.</div> `;
<div class="not-found">Entity ${ent} not found.</div>
`;
})} })}
</wired-card> </wired-card>
`; `;
@ -165,7 +163,7 @@ class WiredToggleCard extends LitElement {
_toggle(state) { _toggle(state) {
this.hass.callService("homeassistant", "toggle", { this.hass.callService("homeassistant", "toggle", {
entity_id: state.entity_id entity_id: state.entity_id,
}); });
} }
@ -248,7 +246,6 @@ customElements.define('content-card-example', ContentCardExample);
```js ```js
class ContentCardEditor extends LitElement { class ContentCardEditor extends LitElement {
setConfig(config) { setConfig(config) {
this._config = config; this._config = config;
} }
@ -256,7 +253,7 @@ class ContentCardEditor extends LitElement {
configChanged(newConfig) { configChanged(newConfig) {
const event = new Event("config-changed", { const event = new Event("config-changed", {
bubbles: true, bubbles: true,
composed: true composed: true,
}); });
event.detail = { config: newConfig }; event.detail = { config: newConfig };
this.dispatchEvent(event); this.dispatchEvent(event);
@ -269,10 +266,125 @@ window.customCards.push({
type: "content-card-example", type: "content-card-example",
name: "Content Card", name: "Content Card",
preview: false, // Optional - defaults to false preview: false, // Optional - defaults to false
description: "A custom card made by me!" // Optional description: "A custom card made by me!", // Optional
}); });
``` ```
## Tile features
The tile card has support for "features" to add quick actions to control the entity. We offer some built-in features, but you can build and use your own using similar way than defining custom cards.
Below is an example of a custom tile feature for [button entity](/docs/core/entity/button/).
![Screenshot of the custom tile feature example](/img/en/frontend/dashboard-custom-tile-feature-screenshot.png)
```js
import {
LitElement,
html,
css,
} from "https://unpkg.com/lit-element@2.0.1/lit-element.js?module";
const supportsButtonPressTileFeature = (stateObj) => {
const domain = stateObj.entity_id.split(".")[0];
return domain === "button";
};
class ButtonPressTileFeature extends LitElement {
static get properties() {
return {
hass: undefined,
config: undefined,
stateObj: undefined,
};
}
static getStubConfig() {
return {
type: "custom:button-press-tile-feature",
label: "Press",
};
}
setConfig(config) {
if (!config) {
throw new Error("Invalid configuration");
}
this.config = config;
}
_press(ev) {
ev.stopPropagation();
this.hass.callService("button", "press", {
entity_id: this.stateObj.entity_id,
});
}
render() {
if (
!this.config ||
!this.hass ||
!this.stateObj ||
!supportsButtonPressTileFeature(this.stateObj)
) {
return null;
}
return html`
<div class="container">
<button class="button" @click=${this._press}>
${this.config.label || "Press"}
</button>
</div>
`;
}
static get styles() {
return css`
.container {
display: flex;
flex-direction: row;
padding: 0 12px 12px 12px;
width: auto;
}
.button {
display: block;
width: 100%;
height: 40px;
border-radius: 6px;
border: none;
background-color: #eeeeee;
cursor: pointer;
transition: background-color 180ms ease-in-out;
}
.button:hover {
background-color: #dddddd;
}
.button:focus {
background-color: #cdcdcd;
}
`;
}
}
customElements.define("button-press-tile-feature", ButtonPressTileFeature);
window.customTileFeatures = window.customTileFeatures || [];
window.customTileFeatures.push({
type: "button-press-tile-feature",
name: "Button press",
supported: supportsButtonPressTileFeature, // Optional
configurable: true, // Optional - defaults to false
});
```
The only difference with custom cards is the graphical configuration option.
To have it displayed in the tile card editor, you must add an object describing it to the array `window.customTileFeatures`.
Required properties of the object are `type` and `name`. It is recommended to define the `supported` option with a function so the editor can only propose the feature if it is compatible with the selected entity in the tile card. Set `configurable` to `true` if your entity has additional configuration (e.g. `label` option in the example above) so the editor.
Also, the static functions `getConfigElement` and `getStubConfig` work the same as with normal custom maps.
## Advanced Resources ## Advanced Resources
Community Maintained Boilerplate Card - Advanced Template (Typescript, Rollup, Linting, etc.) Community Maintained Boilerplate Card - Advanced Template (Typescript, Rollup, Linting, etc.)

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB