From e3c0c06b27574a21605507aadcad4932be66e2cf Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Mon, 27 Nov 2023 16:55:26 -0800 Subject: [PATCH] fix(list): Add live region for dynamically changing list items (#8148) **Related Issue:** #5625 ## Summary - Adds aria-live region to show currently enabled and filtered items --- .../list/assets/list/t9n/messages.json | 4 + .../list/assets/list/t9n/messages_en.json | 4 + .../src/components/list/list.e2e.ts | 6 +- .../src/components/list/list.tsx | 112 ++++++++++++++++-- t9nmanifest.txt | 1 + 5 files changed, 114 insertions(+), 13 deletions(-) create mode 100644 packages/calcite-components/src/components/list/assets/list/t9n/messages.json create mode 100644 packages/calcite-components/src/components/list/assets/list/t9n/messages_en.json diff --git a/packages/calcite-components/src/components/list/assets/list/t9n/messages.json b/packages/calcite-components/src/components/list/assets/list/t9n/messages.json new file mode 100644 index 00000000000..76dafae6f23 --- /dev/null +++ b/packages/calcite-components/src/components/list/assets/list/t9n/messages.json @@ -0,0 +1,4 @@ +{ + "filterEnabled": "Filter enabled.", + "total": "Total items: {count}." +} diff --git a/packages/calcite-components/src/components/list/assets/list/t9n/messages_en.json b/packages/calcite-components/src/components/list/assets/list/t9n/messages_en.json new file mode 100644 index 00000000000..76dafae6f23 --- /dev/null +++ b/packages/calcite-components/src/components/list/assets/list/t9n/messages_en.json @@ -0,0 +1,4 @@ +{ + "filterEnabled": "Filter enabled.", + "total": "Total items: {count}." +} diff --git a/packages/calcite-components/src/components/list/list.e2e.ts b/packages/calcite-components/src/components/list/list.e2e.ts index d222d44e0fa..d875c5bd247 100755 --- a/packages/calcite-components/src/components/list/list.e2e.ts +++ b/packages/calcite-components/src/components/list/list.e2e.ts @@ -1,4 +1,4 @@ -import { accessible, hidden, renders, focusable, disabled, defaults } from "../../tests/commonTests"; +import { accessible, hidden, renders, focusable, disabled, defaults, t9n } from "../../tests/commonTests"; import { placeholderImage } from "../../../.storybook/placeholderImage"; import { html } from "../../../support/formatting"; import { E2EPage, newE2EPage } from "@stencil/core/testing"; @@ -88,6 +88,10 @@ describe("calcite-list", () => { hidden("calcite-list"); }); + describe.skip("translation support", () => { + t9n("calcite-list"); + }); + describe("accessible", () => { accessible(html` diff --git a/packages/calcite-components/src/components/list/list.tsx b/packages/calcite-components/src/components/list/list.tsx index c10f1a77b04..84d6770a392 100755 --- a/packages/calcite-components/src/components/list/list.tsx +++ b/packages/calcite-components/src/components/list/list.tsx @@ -45,6 +45,15 @@ import { setUpLoadableComponent, } from "../../utils/loadable"; import { HandleNudge } from "../handle/interfaces"; +import { + connectMessages, + disconnectMessages, + setUpMessages, + T9nComponent, + updateMessages, +} from "../../utils/t9n"; +import { ListMessages } from "./assets/list/t9n"; +import { NumberingSystem, numberStringFormatter } from "../../utils/locale"; import { ListDragDetail } from "./interfaces"; /** @@ -58,8 +67,11 @@ import { ListDragDetail } from "./interfaces"; tag: "calcite-list", styleUrl: "list.scss", shadow: true, + assetsDirs: ["assets"], }) -export class List implements InteractiveComponent, LoadableComponent, SortableComponent { +export class List + implements InteractiveComponent, LoadableComponent, SortableComponent, T9nComponent +{ // -------------------------------------------------------------------------- // // Properties @@ -137,6 +149,30 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo */ @Prop({ reflect: true }) loading = false; + /** + * Use this property to override individual strings used by the component. + */ + // eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module + @Prop({ mutable: true }) messageOverrides: Partial; + + /** + * Made into a prop for testing purposes only + * + * @internal + */ + // eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module + @Prop({ mutable: true }) messages: ListMessages; + + @Watch("messageOverrides") + onMessagesChange(): void { + /* wired up by t9n util */ + } + + /** + * Specifies the Unicode numeral system used by the component for localization. + */ + @Prop() numberingSystem: NumberingSystem; + /** * One of the items within the list can be opened. * @@ -299,6 +335,7 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo return; } + connectMessages(this); this.connectObserver(); this.updateListItems(); this.setUpSorting(); @@ -306,18 +343,9 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo this.setParentList(); } - disconnectedCallback(): void { - if (dragActive(this)) { - return; - } - - this.disconnectObserver(); - disconnectSortableComponent(this); - disconnectInteractive(this); - } - - componentWillLoad(): void { + async componentWillLoad(): Promise { setUpLoadableComponent(this); + await setUpMessages(this); } componentDidRender(): void { @@ -328,12 +356,32 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo setComponentLoaded(this); } + disconnectedCallback(): void { + if (dragActive(this)) { + return; + } + + this.disconnectObserver(); + disconnectSortableComponent(this); + disconnectInteractive(this); + disconnectMessages(this); + } + // -------------------------------------------------------------------------- // // Private Properties // // -------------------------------------------------------------------------- + @State() effectiveLocale = ""; + + @Watch("effectiveLocale") + effectiveLocaleChange(): void { + updateMessages(this, this.effectiveLocale); + } + + @State() defaultMessages: ListMessages; + @Element() el: HTMLCalciteListElement; @State() assistiveText: string; @@ -409,6 +457,7 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo {this.assistiveText} ) : null} + {this.renderItemAriaLive()} {loading ? : null} + {filterEnabled && filterText && filteredData?.length ? ( +
{messages.filterEnabled}
+ ) : null} +
+ {messages.total.replace( + "{count}", + numberStringFormatter.localize(enabledListItems.length.toString()) + )} +
+ {enabledListItems.length ? ( +
    + {enabledListItems.map((item) => ( +
  1. {item.label}
  2. + ))} +
+ ) : null} + + ) : null; + } + private connectObserver(): void { this.mutationObserver?.observe(this.el, { childList: true, subtree: true }); } diff --git a/t9nmanifest.txt b/t9nmanifest.txt index e5f0b9f0f44..9cd9a64fc60 100644 --- a/t9nmanifest.txt +++ b/t9nmanifest.txt @@ -21,6 +21,7 @@ packages\calcite-components\src\components\input-number\assets\input-number\t9n packages\calcite-components\src\components\input-text\assets\input-text\t9n packages\calcite-components\src\components\input-time-picker\assets\input-time-picker\t9n packages\calcite-components\src\components\input-time-zone\assets\input-time-zone\t9n +packages\calcite-components\src\components\list\assets\list\t9n packages\calcite-components\src\components\list-item\assets\list-item\t9n packages\calcite-components\src\components\menu\assets\menu\t9n packages\calcite-components\src\components\menu-item\assets\menu-item\t9n