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
@ -66,7 +66,7 @@ You can then use your card in your dashboard configuration:
```yaml ```yaml
# Example dashboard configuration # Example dashboard configuration
views: views:
- name: Example - name: Example
cards: cards:
- type: "custom:content-card-example" - type: "custom:content-card-example"
entity: input_boolean.switch_tv entity: input_boolean.switch_tv
@ -85,7 +85,7 @@ Your card can define a `getCardSize` method that returns the size of your card a
Since some elements can be lazy loaded, if you want to get the card size of another element, you should first check it is defined. Since some elements can be lazy loaded, if you want to get the card size of another element, you should first check it is defined.
```js ```js
return customElements return customElements
.whenDefined(element.localName) .whenDefined(element.localName)
.then(() => element.getCardSize()); .then(() => element.getCardSize());
``` ```
@ -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,
}); });
} }
@ -208,7 +206,7 @@ And for your configuration:
```yaml ```yaml
# Example dashboard configuration # Example dashboard configuration
views: views:
- name: Example - name: Example
cards: cards:
- type: "custom:wired-toggle-card" - type: "custom:wired-toggle-card"
entities: entities:
@ -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,9 +253,9 @@ 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