Skip to content

Commit

Permalink
TreeView: Add indication for "Loading" for screen readers (#4969)
Browse files Browse the repository at this point in the history
* Add indication for "Loading" for screen readers

* Update test

* Add changeset

* Return early

* Fix test
  • Loading branch information
TylerJDev authored Sep 27, 2024
1 parent c5696b3 commit 0cd6151
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/spotty-melons-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

Add initial loading state to live region announcement in `TreeView`
2 changes: 1 addition & 1 deletion packages/react/src/TreeView/TreeView.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ export const AsyncSuccess: StoryFn = args => {
}

AsyncSuccess.args = {
responseTime: 2000,
responseTime: 4000,
}

export const AsyncWithCount: StoryFn = args => {
Expand Down
21 changes: 15 additions & 6 deletions packages/react/src/TreeView/TreeView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<SubTreeState>('loading')
const [state, setState] = React.useState<SubTreeState>('initial')

const setLoadingState = () => {
setState(state === 'initial' ? 'loading' : 'done')
}

return (
<div>
{/* Mimic the completion of async loading by clicking the button */}
<button type="button" onClick={() => setState('done')}>
Done
<button type="button" onClick={setLoadingState}>
Load
</button>
<TreeView aria-label="Test tree">
<TreeView.Item id="parent" defaultExpanded>
Expand All @@ -1382,12 +1386,17 @@ describe('Asyncronous loading', () => {
}
const {getByRole} = renderWithTheme(<TestTree />)

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)

Expand Down Expand Up @@ -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')

Expand Down
8 changes: 5 additions & 3 deletions packages/react/src/TreeView/TreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -616,10 +616,9 @@ const SubTree: React.FC<TreeViewSubTreeProps> = ({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)

Expand All @@ -646,6 +645,9 @@ const SubTree: React.FC<TreeViewSubTreeProps> = ({count, state, children}) => {

setLoadingFocused(false)
}
} else if (state === 'loading') {
const parentName = getAccessibleName(parentElement)
announceUpdate(`${parentName} content loading`)
}
}, [loadingFocused, previousState, state, itemId, announceUpdate, ref, safeSetTimeout])

Expand Down

0 comments on commit 0cd6151

Please sign in to comment.