mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-18 23:06:40 +00:00
support actions on rows (#4023)
* support actions on rows * address comments * add type * pointer events * move action area to row name to avoid handler competition * add action to state-badge as well * correct type * address comments * handle 'enter' in long-press and make entities state-badge selecatable
This commit is contained in:
parent
e435b9153b
commit
39d052273d
@ -12,16 +12,12 @@ import {
|
|||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../components/hui-entities-toggle";
|
import "../components/hui-entities-toggle";
|
||||||
|
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
|
||||||
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const";
|
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { EntityRow } from "../entity-rows/types";
|
import { EntityRow } from "../entity-rows/types";
|
||||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { processConfigEntities } from "../common/process-config-entities";
|
import { processConfigEntities } from "../common/process-config-entities";
|
||||||
import { createRowElement } from "../common/create-row-element";
|
import { createRowElement } from "../common/create-row-element";
|
||||||
import { EntitiesCardConfig, EntitiesCardEntityConfig } from "./types";
|
import { EntitiesCardConfig, EntitiesCardEntityConfig } from "./types";
|
||||||
|
|
||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
|
|
||||||
@customElement("hui-entities-card")
|
@customElement("hui-entities-card")
|
||||||
@ -161,10 +157,6 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.state-card-dialog {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
padding: 0px 18px 0px 8px;
|
padding: 0px 18px 0px 8px;
|
||||||
}
|
}
|
||||||
@ -176,23 +168,11 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
|||||||
if (this._hass) {
|
if (this._hass) {
|
||||||
element.hass = this._hass;
|
element.hass = this._hass;
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
entityConf.entity &&
|
|
||||||
!DOMAINS_HIDE_MORE_INFO.includes(computeDomain(entityConf.entity))
|
|
||||||
) {
|
|
||||||
element.classList.add("state-card-dialog");
|
|
||||||
element.addEventListener("click", () => this._handleClick(entityConf));
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div>${element}</div>
|
<div>${element}</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleClick(entityConf: EntitiesCardEntityConfig): void {
|
|
||||||
const entityId = entityConf.entity;
|
|
||||||
fireEvent(this, "hass-more-info", { entityId });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -28,6 +28,9 @@ export interface EntitiesCardEntityConfig extends EntityConfig {
|
|||||||
service?: string;
|
service?: string;
|
||||||
service_data?: object;
|
service_data?: object;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
tap_action?: ActionConfig;
|
||||||
|
hold_action?: ActionConfig;
|
||||||
|
double_tap_action?: ActionConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EntitiesCardConfig extends LovelaceCardConfig {
|
export interface EntitiesCardConfig extends LovelaceCardConfig {
|
||||||
|
@ -138,9 +138,16 @@ class LongPress extends HTMLElement implements LongPress {
|
|||||||
window.setTimeout(() => (this.cooldownEnd = false), 100);
|
window.setTimeout(() => (this.cooldownEnd = false), 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEnter = (ev: Event) => {
|
||||||
|
if ((ev as KeyboardEvent).keyCode === 13) {
|
||||||
|
return clickEnd(ev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
element.addEventListener("touchstart", clickStart, { passive: true });
|
element.addEventListener("touchstart", clickStart, { passive: true });
|
||||||
element.addEventListener("touchend", clickEnd);
|
element.addEventListener("touchend", clickEnd);
|
||||||
element.addEventListener("touchcancel", clickEnd);
|
element.addEventListener("touchcancel", clickEnd);
|
||||||
|
element.addEventListener("keyup", handleEnter);
|
||||||
|
|
||||||
// iOS 13 sends a complete normal touchstart-touchend series of events followed by a mousedown-click series.
|
// 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 long-press work.
|
// That might be a bug, but until it's fixed, this should make long-press work.
|
||||||
|
@ -16,8 +16,14 @@ import "../components/hui-warning";
|
|||||||
|
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
import { EntitiesCardEntityConfig } from "../cards/types";
|
|
||||||
import { toggleAttribute } from "../../../common/dom/toggle_attribute";
|
import { toggleAttribute } from "../../../common/dom/toggle_attribute";
|
||||||
|
import { longPress } from "../common/directives/long-press-directive";
|
||||||
|
import { hasDoubleClick } from "../common/has-double-click";
|
||||||
|
import { handleClick } from "../common/handle-click";
|
||||||
|
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const";
|
||||||
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
|
import { EntitiesCardEntityConfig } from "../cards/types";
|
||||||
|
|
||||||
class HuiGenericEntityRow extends LitElement {
|
class HuiGenericEntityRow extends LitElement {
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
@ -46,15 +52,45 @@ class HuiGenericEntityRow extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pointer =
|
||||||
|
(this.config.tap_action && this.config.tap_action.action !== "none") ||
|
||||||
|
(this.config.entity &&
|
||||||
|
!DOMAINS_HIDE_MORE_INFO.includes(computeDomain(this.config.entity)));
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<state-badge
|
<state-badge
|
||||||
|
class=${classMap({
|
||||||
|
pointer,
|
||||||
|
})}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.stateObj=${stateObj}
|
.stateObj=${stateObj}
|
||||||
.overrideIcon=${this.config.icon}
|
.overrideIcon=${this.config.icon}
|
||||||
.overrideImage=${this.config.image}
|
.overrideImage=${this.config.image}
|
||||||
|
@ha-click=${this._handleClick}
|
||||||
|
@ha-hold=${this._handleHold}
|
||||||
|
@ha-dblclick=${this._handleDblClick}
|
||||||
|
.longPress=${longPress({
|
||||||
|
hasDoubleClick: hasDoubleClick(this.config.double_tap_action),
|
||||||
|
})}
|
||||||
|
tabindex="0"
|
||||||
></state-badge>
|
></state-badge>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="info">
|
<div
|
||||||
|
class=${classMap({
|
||||||
|
info: true,
|
||||||
|
pointer,
|
||||||
|
padName: this.showSecondary && !this.config.secondary_info,
|
||||||
|
padSecondary: Boolean(
|
||||||
|
!this.showSecondary || this.config.secondary_info
|
||||||
|
),
|
||||||
|
})}
|
||||||
|
@ha-click=${this._handleClick}
|
||||||
|
@ha-hold=${this._handleHold}
|
||||||
|
@ha-dblclick=${this._handleDblClick}
|
||||||
|
.longPress=${longPress({
|
||||||
|
hasDoubleClick: hasDoubleClick(this.config.double_tap_action),
|
||||||
|
})}
|
||||||
|
>
|
||||||
${this.config.name || computeStateName(stateObj)}
|
${this.config.name || computeStateName(stateObj)}
|
||||||
<div class="secondary">
|
<div class="secondary">
|
||||||
${!this.showSecondary
|
${!this.showSecondary
|
||||||
@ -86,6 +122,18 @@ class HuiGenericEntityRow extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleClick(): void {
|
||||||
|
handleClick(this, this.hass!, this.config!, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleHold(): void {
|
||||||
|
handleClick(this, this.hass!, this.config!, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleDblClick(): void {
|
||||||
|
handleClick(this, this.hass!, this.config!, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
@ -132,6 +180,15 @@ class HuiGenericEntityRow extends LitElement {
|
|||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.padName {
|
||||||
|
padding: 12px 0px;
|
||||||
|
}
|
||||||
|
.padSecondary {
|
||||||
|
padding: 4px 0px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,19 +18,26 @@ import "../components/hui-warning";
|
|||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
|
|
||||||
import { HomeAssistant, InputSelectEntity } from "../../../types";
|
import { HomeAssistant, InputSelectEntity } from "../../../types";
|
||||||
import { EntityRow, EntityConfig } from "./types";
|
import { EntityRow } from "./types";
|
||||||
import { setInputSelectOption } from "../../../data/input-select";
|
import { setInputSelectOption } from "../../../data/input-select";
|
||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
import { forwardHaptic } from "../../../data/haptics";
|
import { forwardHaptic } from "../../../data/haptics";
|
||||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||||
|
import { longPress } from "../common/directives/long-press-directive";
|
||||||
|
import { hasDoubleClick } from "../common/has-double-click";
|
||||||
|
import { handleClick } from "../common/handle-click";
|
||||||
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
|
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const";
|
||||||
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
|
import { EntitiesCardEntityConfig } from "../cards/types";
|
||||||
|
|
||||||
@customElement("hui-input-select-entity-row")
|
@customElement("hui-input-select-entity-row")
|
||||||
class HuiInputSelectEntityRow extends LitElement implements EntityRow {
|
class HuiInputSelectEntityRow extends LitElement implements EntityRow {
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() private _config?: EntityConfig;
|
@property() private _config?: EntitiesCardEntityConfig;
|
||||||
|
|
||||||
public setConfig(config: EntityConfig): void {
|
public setConfig(config: EntitiesCardEntityConfig): void {
|
||||||
if (!config || !config.entity) {
|
if (!config || !config.entity) {
|
||||||
throw new Error("Invalid Configuration: 'entity' required");
|
throw new Error("Invalid Configuration: 'entity' required");
|
||||||
}
|
}
|
||||||
@ -63,8 +70,25 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pointer =
|
||||||
|
(this._config.tap_action && this._config.tap_action.action !== "none") ||
|
||||||
|
(this._config.entity &&
|
||||||
|
!DOMAINS_HIDE_MORE_INFO.includes(computeDomain(this._config.entity)));
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<state-badge .stateObj="${stateObj}"></state-badge>
|
<state-badge
|
||||||
|
.stateObj=${stateObj}
|
||||||
|
class=${classMap({
|
||||||
|
pointer,
|
||||||
|
})}
|
||||||
|
@ha-click=${this._handleClick}
|
||||||
|
@ha-hold=${this._handleHold}
|
||||||
|
@ha-dblclick=${this._handleDblClick}
|
||||||
|
.longPress=${longPress({
|
||||||
|
hasDoubleClick: hasDoubleClick(this._config.double_tap_action),
|
||||||
|
})}
|
||||||
|
tabindex="0"
|
||||||
|
></state-badge>
|
||||||
<ha-paper-dropdown-menu
|
<ha-paper-dropdown-menu
|
||||||
.label=${this._config.name || computeStateName(stateObj)}
|
.label=${this._config.name || computeStateName(stateObj)}
|
||||||
.value=${stateObj.state}
|
.value=${stateObj.state}
|
||||||
@ -103,6 +127,18 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow {
|
|||||||
)!.selected = stateObj.attributes.options.indexOf(stateObj.state);
|
)!.selected = stateObj.attributes.options.indexOf(stateObj.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleClick(): void {
|
||||||
|
handleClick(this, this.hass!, this._config!, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleHold(): void {
|
||||||
|
handleClick(this, this.hass!, this._config!, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleDblClick(): void {
|
||||||
|
handleClick(this, this.hass!, this._config!, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
@ -118,6 +154,9 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user