Add tabindex to lovelace elements (#4160)

* tabindex

* use action handler

* circular focus test

* address comment

* add focus styling to other elements

* add focus styling to cards

* style glance card entities

* Add back light/thermo changes that were lost in rebase

* Remove unused import

* lint

* lint

* 💄 tweak focus style for glance entities

* 💄 apply styling to focused state-label-badges
This commit is contained in:
Ian Richardson 2020-01-11 04:50:43 -06:00 committed by Bram Kragten
parent 2848e3a63b
commit 0f487ae4bf
22 changed files with 124 additions and 10 deletions

View File

@ -15,6 +15,7 @@ class HaCallServiceButton extends EventsMixin(PolymerElement) {
id="progress"
progress="[[progress]]"
on-click="buttonTapped"
tabindex="0"
><slot></slot
></ha-progress-button>
`;

View File

@ -4,6 +4,8 @@ import {
TemplateResult,
customElement,
property,
CSSResult,
css,
} from "lit-element";
import "../../../components/entity/ha-state-label-badge";
@ -45,6 +47,7 @@ export class HuiStateLabelBadge extends LitElement implements LovelaceBadge {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
></ha-state-label-badge>
`;
}
@ -52,6 +55,21 @@ export class HuiStateLabelBadge extends LitElement implements LovelaceBadge {
private _handleAction(ev: ActionHandlerEvent) {
handleAction(this, this.hass!, this._config!, ev.detail.action!);
}
static get styles(): CSSResult {
return css`
ha-state-label-badge:focus {
outline: none;
background: var(--divider-color);
border-radius: 4px;
}
ha-state-label-badge {
display: inline-block;
padding: 4px;
margin: -4px 0 -4px 0;
}
`;
}
}
declare global {

View File

@ -134,6 +134,7 @@ class HuiEntityButtonCard extends LitElement implements LovelaceCard {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
>
${this._config.show_icon
? html`
@ -195,6 +196,11 @@ class HuiEntityButtonCard extends LitElement implements LovelaceCard {
font-size: 1.2rem;
}
ha-card:focus {
outline: none;
background: var(--divider-color);
}
ha-icon {
width: 40%;
height: auto;

View File

@ -104,6 +104,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
return html`
<ha-card
@click="${this._handleClick}"
tabindex="0"
style=${styleMap({
"--base-unit": this._baseUnit,
})}
@ -228,6 +229,10 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
position: relative;
cursor: pointer;
}
ha-card:focus {
outline: none;
background: var(--divider-color);
}
.container {
width: calc(var(--base-unit) * 4);
height: calc(var(--base-unit) * 2);

View File

@ -167,6 +167,13 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
margin-bottom: 12px;
width: var(--glance-column-width, 20%);
}
.entity:focus {
outline: none;
background: var(--divider-color);
border-radius: 14px;
padding: 4px;
margin: -4px 0;
}
.entity div {
width: 100%;
text-align: center;
@ -207,6 +214,7 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
hasHold: hasAction(entityConf.hold_action),
hasDoubleClick: hasAction(entityConf.double_tap_action),
})}
tabindex="0"
>
${this._config!.show_name !== false
? html`

View File

@ -94,7 +94,8 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
<paper-icon-button
icon="hass:dots-vertical"
class="more-info"
@click="${this._handleMoreInfo}"
@click=${this._handleMoreInfo}
tabindex="0"
></paper-icon-button>
<div id="controls">
@ -121,6 +122,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
color: this._computeColor(stateObj),
})}
@click=${this._handleClick}
tabindex="0"
></paper-icon-button>
</div>
</div>

View File

@ -147,6 +147,7 @@ class HuiMapCard extends LitElement implements LovelaceCard {
></div>
<paper-icon-button
@click=${this._fitMap}
tabindex="0"
icon="hass:image-filter-center-focus"
title="Reset focus"
></paper-icon-button>

View File

@ -86,6 +86,7 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
class="${classMap({
clickable: Boolean(
this._config.tap_action || this._config.hold_action

View File

@ -156,6 +156,7 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
class=${classMap({
clickable: stateObj.state !== UNAVAILABLE,
})}

View File

@ -168,6 +168,7 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
.config=${this._config}
.hass=${this.hass}
.image=${this._config.image}
@ -230,6 +231,7 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
hasHold: hasAction(entityConf.hold_action),
hasDoubleClick: hasAction(entityConf.double_tap_action),
})}
tabindex="0"
.config=${entityConf}
class="${classMap({
"state-on": !STATES_OFF.has(stateObj.state),
@ -318,6 +320,11 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
padding-bottom: 4px;
padding-top: 4px;
}
ha-icon:focus {
outline: none;
background: var(--divider-color);
border-radius: 100%;
}
.state {
display: block;
font-size: 12px;

View File

@ -21,6 +21,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { PlantStatusCardConfig, PlantAttributeTarget } from "./types";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { actionHandler } from "../common/directives/action-handler-directive";
const SENSORS = {
moisture: "hass:water",
@ -119,7 +120,9 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
(item) => html`
<div
class="attributes"
@click="${this._handleMoreInfo}"
@action=${this._handleMoreInfo}
.actionHandler=${actionHandler()}
tabindex="0"
.value="${item}"
>
<div>
@ -206,6 +209,12 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
cursor: pointer;
}
.attributes:focus {
outline: none;
background: var(--divider-color);
border-radius: 100%;
}
.attributes div {
text-align: center;
}

View File

@ -25,6 +25,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
import { fetchRecent } from "../../../data/history";
import { SensorCardConfig } from "./types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { actionHandler } from "../common/directives/action-handler-directive";
const midPoint = (
_Ax: number,
@ -241,7 +242,11 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
graph = "";
}
return html`
<ha-card @click="${this._handleClick}">
<ha-card
@action=${this._handleClick}
.actionHandler=${actionHandler()}
tabindex="0"
>
<div class="flex">
<div class="icon">
<ha-icon
@ -353,6 +358,11 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
cursor: pointer;
}
ha-card:focus {
outline: none;
background: var(--divider-color);
}
.flex {
display: flex;
}

View File

@ -26,6 +26,7 @@ import {
} from "../../../data/shopping-list";
import { ShoppingListCardConfig, SensorCardConfig } from "./types";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { actionHandler } from "../common/directives/action-handler-directive";
@customElement("hui-shopping-list-card")
class HuiShoppingListCard extends LitElement implements LovelaceCard {
@ -165,7 +166,9 @@ class HuiShoppingListCard extends LitElement implements LovelaceCard {
</span>
<ha-icon
class="clearall"
@click="${this._clearItems}"
@action=${this._clearItems}
.actionHandler=${actionHandler()}
tabindex="0"
icon="hass:notification-clear-all"
.title="${this.hass!.localize(
"ui.panel.lovelace.cards.shopping-list.clear_items"

View File

@ -33,6 +33,7 @@ import {
CLIMATE_PRESET_NONE,
} from "../../../data/climate";
import { HassEntity } from "home-assistant-js-websocket";
import { actionHandler } from "../common/directives/action-handler-directive";
const modeIcons: { [mode in HvacMode]: string } = {
auto: "hass:calendar-repeat",
@ -218,6 +219,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
icon="hass:dots-vertical"
class="more-info"
@click=${this._handleMoreInfo}
tabindex="0"
></paper-icon-button>
<div id="controls">
@ -364,9 +366,10 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
class="${classMap({ "selected-icon": currentMode === mode })}"
.mode="${mode}"
.icon="${modeIcons[mode]}"
@click="${this._handleModeClick}"
@action=${this._handleAction}
.actionHandler=${actionHandler()}
tabindex="0"
></paper-icon-button>
></ha-icon>
`;
}
@ -376,7 +379,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
});
}
private _handleModeClick(e: MouseEvent): void {
private _handleAction(e: MouseEvent): void {
this.hass!.callService("climate", "set_hvac_mode", {
entity_id: this._config!.entity,
hvac_mode: (e.currentTarget as any).mode,

View File

@ -23,6 +23,7 @@ import { computeRTL } from "../../../common/util/compute_rtl";
import { fireEvent } from "../../../common/dom/fire_event";
import { toggleAttribute } from "../../../common/dom/toggle_attribute";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { actionHandler } from "../common/directives/action-handler-directive";
const cardinalDirections = [
"N",
@ -141,7 +142,11 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
: undefined;
return html`
<ha-card @click="${this.handleClick}">
<ha-card
@action=${this._handleAction}
.actionHandler=${actionHandler()}
tabindex="0"
>
<div class="header">
${this.hass.localize(`state.weather.${stateObj.state}`) ||
stateObj.state}
@ -274,7 +279,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
return hasConfigOrEntityChanged(this, changedProps);
}
private handleClick(): void {
private _handleAction(): void {
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
}

View File

@ -171,6 +171,11 @@ class HuiGenericEntityRow extends LitElement {
state-badge {
flex: 0 0 40px;
}
state-badge:focus {
outline: none;
background: var(--divider-color);
border-radius: 100%;
}
:host([rtl]) .flex {
margin-left: 0;
margin-right: 16px;

View File

@ -45,6 +45,7 @@ export class HuiIconElement extends LitElement implements LovelaceElement {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
></ha-icon>
`;
}
@ -58,6 +59,11 @@ export class HuiIconElement extends LitElement implements LovelaceElement {
:host {
cursor: pointer;
}
ha-icon:focus {
outline: none;
background: var(--divider-color);
border-radius: 100%;
}
`;
}
}

View File

@ -56,6 +56,7 @@ export class HuiImageElement extends LitElement implements LovelaceElement {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
></hui-image>
`;
}
@ -70,6 +71,11 @@ export class HuiImageElement extends LitElement implements LovelaceElement {
hui-image {
-webkit-user-select: none !important;
}
hui-image:focus {
outline: none;
background: var(--divider-color);
border-radius: 100%;
}
`;
}

View File

@ -70,6 +70,7 @@ export class HuiStateBadgeElement extends LitElement
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
></ha-state-label-badge>
`;
}

View File

@ -66,6 +66,7 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
.overrideIcon=${this._config.icon}
></state-badge>
`;
@ -76,6 +77,11 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement {
:host {
cursor: pointer;
}
state-badge:focus {
outline: none;
background: var(--divider-color);
border-radius: 100%;
}
`;
}

View File

@ -65,6 +65,7 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
tabindex="0"
>
${this._config.prefix}${stateObj
? computeStateDisplay(
@ -90,6 +91,11 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
padding: 8px;
white-space: nowrap;
}
div:focus {
outline: none;
background: var(--divider-color);
border-radius: 100%;
}
`;
}
}

View File

@ -141,7 +141,6 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow {
margin-left: 16px;
flex: 1;
}
paper-item {
cursor: pointer;
min-width: 200px;
@ -149,6 +148,11 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow {
.pointer {
cursor: pointer;
}
state-badge:focus {
outline: none;
background: var(--divider-color);
border-radius: 100%;
}
`;
}