From 147098f0fd3751b5fa432a3679551ab1e49530c1 Mon Sep 17 00:00:00 2001
From: karwosts <32912880+karwosts@users.noreply.github.com>
Date: Mon, 23 Dec 2024 00:21:27 -0800
Subject: [PATCH] ha-form-multi_select accessibility improvements (#21023)
---
.../ha-form/ha-form-multi_select.ts | 85 +++++++++++--------
src/components/ha-md-button-menu.ts | 18 ++++
2 files changed, 69 insertions(+), 34 deletions(-)
diff --git a/src/components/ha-form/ha-form-multi_select.ts b/src/components/ha-form/ha-form-multi_select.ts
index 067840fc5c..f09bad520d 100644
--- a/src/components/ha-form/ha-form-multi_select.ts
+++ b/src/components/ha-form/ha-form-multi_select.ts
@@ -5,12 +5,14 @@ import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import "../ha-button-menu";
import "../ha-check-list-item";
-import type { HaCheckListItem } from "../ha-check-list-item";
import "../ha-checkbox";
import type { HaCheckbox } from "../ha-checkbox";
import "../ha-formfield";
-import "../ha-svg-icon";
+import "../ha-icon-button";
import "../ha-textfield";
+import "../ha-md-button-menu";
+import "../ha-md-menu-item";
+
import type {
HaFormElement,
HaFormMultiSelectData,
@@ -73,13 +75,10 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement {
}
return html`
-
-
+ >
${options.map((item: string | [string, string]) => {
const value = optionValue(item);
const selected = data.includes(value);
- return html`
+
${optionLabel(item)}
- `;
+ `;
})}
-
+
`;
}
+ protected _keydown(ev) {
+ if (ev.code === "Space" || ev.code === "Enter") {
+ ev.preventDefault();
+ this._toggleItem(ev);
+ }
+ }
+
+ protected _toggleItem(ev) {
+ const oldData = this.data || [];
+ let newData: string[];
+ if (ev.currentTarget.action === "add") {
+ newData = [...oldData, ev.currentTarget.value];
+ } else {
+ newData = oldData.filter((d) => d !== ev.currentTarget.value);
+ }
+ fireEvent(this, "value-changed", {
+ value: newData,
+ });
+ }
+
protected firstUpdated() {
this.updateComplete.then(() => {
const { formElement, mdcRoot } =
@@ -139,17 +166,6 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement {
}
}
- private _selectedChanged(ev: CustomEvent): void {
- ev.stopPropagation();
- if (ev.detail.source === "property") {
- return;
- }
- this._handleValueChanged(
- (ev.target as HaCheckListItem).value,
- ev.detail.selected
- );
- }
-
private _valueChanged(ev: CustomEvent): void {
const { value, checked } = ev.target as HaCheckbox;
this._handleValueChanged(value, checked);
@@ -195,7 +211,7 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement {
:host([own-margin]) {
margin-bottom: 5px;
}
- ha-button-menu {
+ ha-md-button-menu {
display: block;
cursor: pointer;
}
@@ -208,22 +224,23 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement {
}
ha-textfield {
display: block;
+ width: 100%;
pointer-events: none;
}
- ha-svg-icon {
+ ha-icon-button {
color: var(--input-dropdown-icon-color);
position: absolute;
right: 1em;
- top: 1em;
+ top: 4px;
cursor: pointer;
inset-inline-end: 1em;
inset-inline-start: initial;
direction: var(--direction);
}
- :host([opened]) ha-svg-icon {
+ :host([opened]) ha-icon-button {
color: var(--primary-color);
}
- :host([opened]) ha-button-menu {
+ :host([opened]) ha-md-button-menu {
--mdc-text-field-idle-line-color: var(--input-hover-line-color);
--mdc-text-field-label-ink-color: var(--primary-color);
}
diff --git a/src/components/ha-md-button-menu.ts b/src/components/ha-md-button-menu.ts
index 09a0a7fd9b..3d4012397f 100644
--- a/src/components/ha-md-button-menu.ts
+++ b/src/components/ha-md-button-menu.ts
@@ -3,6 +3,7 @@ import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, query } from "lit/decorators";
import { FOCUS_TARGET } from "../dialogs/make-dialog-manager";
+import { fireEvent } from "../common/dom/fire_event";
import type { HaIconButton } from "./ha-icon-button";
import "./ha-menu";
import type { HaMenu } from "./ha-menu";
@@ -40,12 +41,22 @@ export class HaMdButtonMenu extends LitElement {
`;
}
+ private _handleOpening(): void {
+ fireEvent(this, "opening", undefined, { composed: false });
+ }
+
+ private _handleClosing(): void {
+ fireEvent(this, "closing", undefined, { composed: false });
+ }
+
private _handleClick(): void {
if (this.disabled) {
return;
@@ -88,3 +99,10 @@ declare global {
"ha-md-button-menu": HaMdButtonMenu;
}
}
+
+declare global {
+ interface HASSDomEvents {
+ opening: undefined;
+ closing: undefined;
+ }
+}