From 30461567184f5017d1c0fe3e17941e30498d30be Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Mon, 13 Jan 2025 17:15:39 -0800 Subject: [PATCH 1/3] fix(combobox): fix accessibility when an item's heading or label changes --- .../src/components/combobox-item/combobox-item.tsx | 4 +++- .../calcite-components/src/components/combobox/combobox.tsx | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox-item/combobox-item.tsx b/packages/calcite-components/src/components/combobox-item/combobox-item.tsx index 7d1aaaf93fc..4c44e0ff5ad 100644 --- a/packages/calcite-components/src/components/combobox-item/combobox-item.tsx +++ b/packages/calcite-components/src/components/combobox-item/combobox-item.tsx @@ -168,7 +168,9 @@ export class ComboboxItem extends LitElement implements InteractiveComponent { if ( (changes.has("disabled") && this.hasUpdated) || (changes.has("selected") && this.hasUpdated) || - (changes.has("textLabel") && this.hasUpdated) + (changes.has("textLabel") && this.hasUpdated) || + (changes.has("heading") && this.hasUpdated) || + (changes.has("label") && this.hasUpdated) ) { this.calciteInternalComboboxItemChange.emit(); } diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index a4607ea935e..cb09774c20c 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1679,6 +1679,7 @@ export class Combobox private renderListBoxOptions(): JsxNode { return this.filteredItems.map((item) => (
  • Date: Tue, 14 Jan 2025 11:37:24 -0800 Subject: [PATCH 2/3] add test --- .../combobox-item/combobox-item.e2e.ts | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox-item/combobox-item.e2e.ts b/packages/calcite-components/src/components/combobox-item/combobox-item.e2e.ts index 93ab1a303be..c601131b6f1 100644 --- a/packages/calcite-components/src/components/combobox-item/combobox-item.e2e.ts +++ b/packages/calcite-components/src/components/combobox-item/combobox-item.e2e.ts @@ -1,4 +1,5 @@ -import { describe } from "vitest"; +import { describe, it, expect } from "vitest"; +import { newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; import { defaults, disabled, hidden, reflects, renders, slots } from "../../tests/commonTests"; import { SLOTS } from "./resources"; @@ -46,4 +47,43 @@ describe("calcite-combobox-item", () => { describe("disabled", () => { disabled("calcite-combobox-item", { focusTarget: "none" }); }); + + it("should emit calciteInternalComboboxItemChange", async () => { + const page = await newE2EPage(); + + await page.setContent(""); + + const element = await page.find("calcite-combobox-item"); + + const eventSpy = await element.spyOnEvent("calciteInternalComboboxItemChange"); + + await page.waitForChanges(); + + expect(eventSpy).not.toHaveReceivedEvent(); + + element.setProperty("selected", true); + await page.waitForChanges(); + + expect(eventSpy).toHaveReceivedEventTimes(1); + + element.setProperty("textLabel", "hello"); + await page.waitForChanges(); + + expect(eventSpy).toHaveReceivedEventTimes(2); + + element.setProperty("heading", "hello"); + await page.waitForChanges(); + + expect(eventSpy).toHaveReceivedEventTimes(3); + + element.setProperty("label", "hello"); + await page.waitForChanges(); + + expect(eventSpy).toHaveReceivedEventTimes(4); + + element.setProperty("disabled", true); + await page.waitForChanges(); + + expect(eventSpy).toHaveReceivedEventTimes(5); + }); }); From 5cbe6810f41bb4f95e9897ac6ed5bac77cd92a98 Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Tue, 14 Jan 2025 13:42:52 -0800 Subject: [PATCH 3/3] review fixes --- .../combobox-item/combobox-item.e2e.ts | 42 +------------- .../src/components/combobox/combobox.e2e.ts | 56 +++++++++++++++++++ .../src/components/combobox/combobox.tsx | 4 +- .../src/components/combobox/resources.ts | 1 + 4 files changed, 60 insertions(+), 43 deletions(-) diff --git a/packages/calcite-components/src/components/combobox-item/combobox-item.e2e.ts b/packages/calcite-components/src/components/combobox-item/combobox-item.e2e.ts index c601131b6f1..93ab1a303be 100644 --- a/packages/calcite-components/src/components/combobox-item/combobox-item.e2e.ts +++ b/packages/calcite-components/src/components/combobox-item/combobox-item.e2e.ts @@ -1,5 +1,4 @@ -import { describe, it, expect } from "vitest"; -import { newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; +import { describe } from "vitest"; import { defaults, disabled, hidden, reflects, renders, slots } from "../../tests/commonTests"; import { SLOTS } from "./resources"; @@ -47,43 +46,4 @@ describe("calcite-combobox-item", () => { describe("disabled", () => { disabled("calcite-combobox-item", { focusTarget: "none" }); }); - - it("should emit calciteInternalComboboxItemChange", async () => { - const page = await newE2EPage(); - - await page.setContent(""); - - const element = await page.find("calcite-combobox-item"); - - const eventSpy = await element.spyOnEvent("calciteInternalComboboxItemChange"); - - await page.waitForChanges(); - - expect(eventSpy).not.toHaveReceivedEvent(); - - element.setProperty("selected", true); - await page.waitForChanges(); - - expect(eventSpy).toHaveReceivedEventTimes(1); - - element.setProperty("textLabel", "hello"); - await page.waitForChanges(); - - expect(eventSpy).toHaveReceivedEventTimes(2); - - element.setProperty("heading", "hello"); - await page.waitForChanges(); - - expect(eventSpy).toHaveReceivedEventTimes(3); - - element.setProperty("label", "hello"); - await page.waitForChanges(); - - expect(eventSpy).toHaveReceivedEventTimes(4); - - element.setProperty("disabled", true); - await page.waitForChanges(); - - expect(eventSpy).toHaveReceivedEventTimes(5); - }); }); diff --git a/packages/calcite-components/src/components/combobox/combobox.e2e.ts b/packages/calcite-components/src/components/combobox/combobox.e2e.ts index 87e0957d53c..d1c7495cc06 100644 --- a/packages/calcite-components/src/components/combobox/combobox.e2e.ts +++ b/packages/calcite-components/src/components/combobox/combobox.e2e.ts @@ -731,6 +731,62 @@ describe("calcite-combobox", () => { }); }); + it("should update screen reader list items", async () => { + const page = await newE2EPage(); + + await page.setContent( + html` + + `, + ); + + const item = await page.find("calcite-combobox-item"); + let a11yItem = await page.find(`calcite-combobox >>> ul.${CSS.screenReadersOnly} li`); + + expect(a11yItem).not.toBeNull(); + expect(await a11yItem.getProperty("ariaSelected")).toBe("false"); + expect(await a11yItem.getProperty("ariaLabel")).toBe(null); + expect(await a11yItem.getProperty("textContent")).toBe(""); + + item.setProperty("selected", true); + await page.waitForChanges(); + await page.waitForTimeout(DEBOUNCE.nextTick); + a11yItem = await page.find(`calcite-combobox >>> ul.${CSS.screenReadersOnly} li`); + + expect(await a11yItem.getProperty("ariaSelected")).toBe("true"); + + const label = "label"; + item.setProperty("label", label); + await page.waitForChanges(); + await page.waitForTimeout(DEBOUNCE.nextTick); + a11yItem = await page.find(`calcite-combobox >>> ul.${CSS.screenReadersOnly} li`); + + expect(await a11yItem.getProperty("ariaLabel")).toBe(label); + + const textLabel = "textLabel"; + item.setProperty("textLabel", textLabel); + await page.waitForChanges(); + await page.waitForTimeout(DEBOUNCE.nextTick); + a11yItem = await page.find(`calcite-combobox >>> ul.${CSS.screenReadersOnly} li`); + + expect(await a11yItem.getProperty("textContent")).toBe(textLabel); + + const heading = "heading"; + item.setProperty("heading", heading); + await page.waitForChanges(); + await page.waitForTimeout(DEBOUNCE.nextTick); + a11yItem = await page.find(`calcite-combobox >>> ul.${CSS.screenReadersOnly} li`); + + expect(await a11yItem.getProperty("textContent")).toBe(heading); + + item.setProperty("disabled", true); + await page.waitForChanges(); + await page.waitForTimeout(DEBOUNCE.nextTick); + a11yItem = await page.find(`calcite-combobox >>> ul.${CSS.screenReadersOnly} li`); + + expect(a11yItem).toBeNull(); + }); + it("should control max items displayed", async () => { const maxItems = 7; const page = await newE2EPage(); diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index cb09774c20c..c4abe0d66de 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1785,7 +1785,7 @@ export class Combobox this.renderAllSelectedIndicatorChipCompact(), ]}