Skip to content

Commit

Permalink
fix(list): Add live region for dynamically changing list items (#8148)
Browse files Browse the repository at this point in the history
**Related Issue:** #5625

## Summary

- Adds aria-live region to show currently enabled and filtered items
  • Loading branch information
driskull authored Nov 28, 2023
1 parent fd9c44a commit e3c0c06
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"filterEnabled": "Filter enabled.",
"total": "Total items: {count}."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"filterEnabled": "Filter enabled.",
"total": "Total items: {count}."
}
6 changes: 5 additions & 1 deletion packages/calcite-components/src/components/list/list.e2e.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -88,6 +88,10 @@ describe("calcite-list", () => {
hidden("calcite-list");
});

describe.skip("translation support", () => {
t9n("calcite-list");
});

describe("accessible", () => {
accessible(html`<calcite-list>
<calcite-list-item label="candy" description="kingdom">
Expand Down
112 changes: 100 additions & 12 deletions packages/calcite-components/src/components/list/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

/**
Expand All @@ -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
Expand Down Expand Up @@ -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<ListMessages>;

/**
* 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.
*
Expand Down Expand Up @@ -299,25 +335,17 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo
return;
}

connectMessages(this);
this.connectObserver();
this.updateListItems();
this.setUpSorting();
connectInteractive(this);
this.setParentList();
}

disconnectedCallback(): void {
if (dragActive(this)) {
return;
}

this.disconnectObserver();
disconnectSortableComponent(this);
disconnectInteractive(this);
}

componentWillLoad(): void {
async componentWillLoad(): Promise<void> {
setUpLoadableComponent(this);
await setUpMessages(this);
}

componentDidRender(): void {
Expand All @@ -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;
Expand Down Expand Up @@ -409,6 +457,7 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo
{this.assistiveText}
</span>
) : null}
{this.renderItemAriaLive()}
{loading ? <calcite-scrim class={CSS.scrim} loading={loading} /> : null}
<table
aria-busy={toAriaBoolean(loading)}
Expand Down Expand Up @@ -461,6 +510,45 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo
//
// --------------------------------------------------------------------------

private renderItemAriaLive(): VNode {
const {
messages,
enabledListItems,
parentListEl,
effectiveLocale,
numberingSystem,
filterEnabled,
filterText,
filteredData,
} = this;

numberStringFormatter.numberFormatOptions = {
locale: effectiveLocale,
numberingSystem,
};

return !parentListEl ? (
<div aria-live="polite" class={CSS.assistiveText}>
{filterEnabled && filterText && filteredData?.length ? (
<div key="aria-filter-enabled">{messages.filterEnabled}</div>
) : null}
<div key="aria-item-count">
{messages.total.replace(
"{count}",
numberStringFormatter.localize(enabledListItems.length.toString())
)}
</div>
{enabledListItems.length ? (
<ol key="aria-item-list">
{enabledListItems.map((item) => (
<li>{item.label}</li>
))}
</ol>
) : null}
</div>
) : null;
}

private connectObserver(): void {
this.mutationObserver?.observe(this.el, { childList: true, subtree: true });
}
Expand Down
1 change: 1 addition & 0 deletions t9nmanifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit e3c0c06

Please sign in to comment.