Skip to content

Commit 148c5ae

Browse files
authored
Fix focus timing issues (#2911)
1 parent ffa557c commit 148c5ae

File tree

2 files changed

+12
-11
lines changed

2 files changed

+12
-11
lines changed

src/TreeView/TreeView.test.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,11 +1230,6 @@ describe('Asyncronous loading', () => {
12301230
})
12311231

12321232
it('moves focus from loading item to first child', async () => {
1233-
// We get a focus zone warning in this test that doesn't
1234-
// happen in the browser. We're not sure why, so we're
1235-
// suppressing it for now.
1236-
jest.spyOn(console, 'warn').mockImplementation()
1237-
12381233
function TestTree() {
12391234
const [state, setState] = React.useState<SubTreeState>('loading')
12401235

@@ -1272,13 +1267,13 @@ describe('Asyncronous loading', () => {
12721267
// Loading item should be focused
12731268
expect(loadingItem).toHaveFocus()
12741269

1270+
// Wait for async loading to complete
1271+
const firstChild = await findByRole('treeitem', {name: 'Child 1'})
1272+
12751273
act(() => {
12761274
jest.runAllTimers()
12771275
})
12781276

1279-
// Wait for async loading to complete
1280-
const firstChild = await findByRole('treeitem', {name: 'Child 1'})
1281-
12821277
// First child should be focused
12831278
expect(firstChild).toHaveFocus()
12841279
})

src/TreeView/TreeView.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {get} from '../constants'
1111
import {ConfirmationDialog} from '../Dialog/ConfirmationDialog'
1212
import {useControllableState} from '../hooks/useControllableState'
1313
import {useId} from '../hooks/useId'
14+
import useSafeTimeout from '../hooks/useSafeTimeout'
1415
import Spinner from '../Spinner'
1516
import sx, {SxProp} from '../sx'
1617
import Text from '../Text'
@@ -513,6 +514,7 @@ const SubTree: React.FC<TreeViewSubTreeProps> = ({count, state, children}) => {
513514
const ref = React.useRef<HTMLElement>(null)
514515
const [loadingFocused, setLoadingFocused] = React.useState(false)
515516
const previousState = usePreviousValue(state)
517+
const {safeSetTimeout} = useSafeTimeout()
516518

517519
React.useEffect(() => {
518520
// If `state` is undefined, we're working in a synchronous context and need
@@ -549,15 +551,19 @@ const SubTree: React.FC<TreeViewSubTreeProps> = ({count, state, children}) => {
549551
const firstChild = getFirstChildElement(parentElement)
550552

551553
if (firstChild) {
552-
firstChild.focus()
554+
safeSetTimeout(() => {
555+
firstChild.focus()
556+
})
553557
} else {
554-
parentElement.focus()
558+
safeSetTimeout(() => {
559+
parentElement.focus()
560+
})
555561
}
556562

557563
setLoadingFocused(false)
558564
}
559565
}
560-
}, [loadingFocused, previousState, state, itemId, announceUpdate, ref])
566+
}, [loadingFocused, previousState, state, itemId, announceUpdate, ref, safeSetTimeout])
561567

562568
// Track focus on the loading indicator
563569
React.useEffect(() => {

0 commit comments

Comments
 (0)