Skip to content

Commit d86923a

Browse files
committed
Temporary patch for Chrome Android
1 parent d4cdc75 commit d86923a

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

packages/@react-aria/focus/src/FocusScope.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
import {FocusableElement, RefObject} from '@react-types/shared';
1414
import {focusSafely} from './focusSafely';
15-
import {getOwnerDocument, useLayoutEffect} from '@react-aria/utils';
15+
import {getInteractionModality} from '@react-aria/interactions';
16+
import {getOwnerDocument, isAndroid, isChrome, useLayoutEffect} from '@react-aria/utils';
1617
import {isElementVisible} from './isElementVisible';
1718
import React, {ReactNode, useContext, useEffect, useMemo, useRef} from 'react';
1819

@@ -376,12 +377,19 @@ function useFocusContainment(scopeRef: RefObject<Element[] | null>, contain?: bo
376377
};
377378

378379
let onBlur = (e) => {
379-
// Use raf to delay long enough that subdialogs will fully unmount and not move focus away from parent menu's hovered item that triggered the close
380+
// Firefox doesn't shift focus back to the Dialog properly without this
380381
if (raf.current) {
381382
cancelAnimationFrame(raf.current);
382383
}
383384
raf.current = requestAnimationFrame(() => {
384-
if (e.relatedTarget && shouldContainFocus(scopeRef) && !isElementInChildScope(e.relatedTarget, scopeRef)) {
385+
// Patches infinite focus coersion loop for Android Talkback where the user isn't able to move the virtual cursor
386+
// if within a containing focus scope. Bug filed against Chrome: https://issuetracker.google.com/issues/384844019.
387+
// Note that this means focus can leave focus containing modals due to this, but it is isolated to Chrome Talkback.
388+
let modality = getInteractionModality();
389+
let shouldSkipFocusRestore = (modality === 'virtual' || modality === null) && isAndroid() && isChrome();
390+
391+
// Use document.activeElement instead of e.relatedTarget so we can tell if user clicked into iframe
392+
if (!shouldSkipFocusRestore && ownerDocument.activeElement && shouldContainFocus(scopeRef) && !isElementInChildScope(ownerDocument.activeElement, scopeRef)) {
385393
activeScope = scopeRef;
386394
if (ownerDocument.body.contains(e.target)) {
387395
focusedNode.current = e.target;

0 commit comments

Comments
 (0)