From 0cd6151c2b620f10a06921a88edf6d64e0a1bc1a Mon Sep 17 00:00:00 2001 From: Tyler Jones Date: Fri, 27 Sep 2024 10:58:16 -0400 Subject: [PATCH] TreeView: Add indication for "Loading" for screen readers (#4969) * Add indication for "Loading" for screen readers * Update test * Add changeset * Return early * Fix test --- .changeset/spotty-melons-sit.md | 5 +++++ .../TreeView/TreeView.features.stories.tsx | 2 +- packages/react/src/TreeView/TreeView.test.tsx | 21 +++++++++++++------ packages/react/src/TreeView/TreeView.tsx | 8 ++++--- 4 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 .changeset/spotty-melons-sit.md diff --git a/.changeset/spotty-melons-sit.md b/.changeset/spotty-melons-sit.md new file mode 100644 index 00000000000..8b3043deae2 --- /dev/null +++ b/.changeset/spotty-melons-sit.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +Add initial loading state to live region announcement in `TreeView` diff --git a/packages/react/src/TreeView/TreeView.features.stories.tsx b/packages/react/src/TreeView/TreeView.features.stories.tsx index 14a88a43a93..b4d9a8181b4 100644 --- a/packages/react/src/TreeView/TreeView.features.stories.tsx +++ b/packages/react/src/TreeView/TreeView.features.stories.tsx @@ -407,7 +407,7 @@ export const AsyncSuccess: StoryFn = args => { } AsyncSuccess.args = { - responseTime: 2000, + responseTime: 4000, } export const AsyncWithCount: StoryFn = args => { diff --git a/packages/react/src/TreeView/TreeView.test.tsx b/packages/react/src/TreeView/TreeView.test.tsx index 74fd658ed85..056b6714acb 100644 --- a/packages/react/src/TreeView/TreeView.test.tsx +++ b/packages/react/src/TreeView/TreeView.test.tsx @@ -1354,13 +1354,17 @@ describe('State', () => { describe('Asyncronous loading', () => { it('updates aria live region when loading is done', () => { function TestTree() { - const [state, setState] = React.useState('loading') + const [state, setState] = React.useState('initial') + + const setLoadingState = () => { + setState(state === 'initial' ? 'loading' : 'done') + } return (
{/* Mimic the completion of async loading by clicking the button */} - @@ -1382,12 +1386,17 @@ describe('Asyncronous loading', () => { } const {getByRole} = renderWithTheme() - const doneButton = getByRole('button', {name: 'Done'}) + const doneButton = getByRole('button', {name: 'Load'}) const liveRegion = getByRole('status') // Live region should be empty expect(liveRegion).toHaveTextContent('') + // Click load button to mimic async loading + fireEvent.click(doneButton) + + expect(liveRegion).toHaveTextContent('Parent content loading') + // Click done button to mimic the completion of async loading fireEvent.click(doneButton) @@ -1565,9 +1574,9 @@ describe('Asyncronous loading', () => { advanceTimers: jest.advanceTimersByTime, }) - const treeitem = getByLabelText(/Item 1/) + const treeitem = getByLabelText('Item 1') expect(treeitem).toHaveAttribute('aria-expanded', 'false') - await user.click(getByText(/Item 1/)) + await user.click(getByText('Item 1')) expect(treeitem).toHaveAttribute('aria-expanded', 'true') diff --git a/packages/react/src/TreeView/TreeView.tsx b/packages/react/src/TreeView/TreeView.tsx index d76acce3c24..b891aa97a74 100644 --- a/packages/react/src/TreeView/TreeView.tsx +++ b/packages/react/src/TreeView/TreeView.tsx @@ -616,10 +616,9 @@ const SubTree: React.FC = ({count, state, children}) => { // Handle transition from loading to done state React.useEffect(() => { + const parentElement = document.getElementById(itemId) + if (!parentElement) return if (previousState === 'loading' && state === 'done') { - const parentElement = document.getElementById(itemId) - if (!parentElement) return - // Announce update to screen readers const parentName = getAccessibleName(parentElement) @@ -646,6 +645,9 @@ const SubTree: React.FC = ({count, state, children}) => { setLoadingFocused(false) } + } else if (state === 'loading') { + const parentName = getAccessibleName(parentElement) + announceUpdate(`${parentName} content loading`) } }, [loadingFocused, previousState, state, itemId, announceUpdate, ref, safeSetTimeout])