From 4ec76ebd087de6f385c292c896c052450ffc5f2a Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Thu, 22 Feb 2024 18:15:00 +0530 Subject: [PATCH 01/14] Fix focus tracking for dynamic iframe content --- .../@react-aria/interactions/src/useFocus.ts | 6 +- .../stories/useFocusRing.stories.tsx | 57 ++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/packages/@react-aria/interactions/src/useFocus.ts b/packages/@react-aria/interactions/src/useFocus.ts index 828e565599d..bf877c9988d 100644 --- a/packages/@react-aria/interactions/src/useFocus.ts +++ b/packages/@react-aria/interactions/src/useFocus.ts @@ -17,6 +17,7 @@ import {DOMAttributes, FocusableElement, FocusEvents} from '@react-types/shared'; import {FocusEvent, useCallback} from 'react'; +import {getOwnerDocument} from '@react-aria/utils'; import {useSyntheticBlurEvent} from './utils'; export interface FocusProps extends FocusEvents { @@ -61,7 +62,10 @@ export function useFocus(pro const onFocus: FocusProps['onFocus'] = useCallback((e: FocusEvent) => { // Double check that document.activeElement actually matches e.target in case a previously chained // focus handler already moved focus somewhere else. - if (e.target === e.currentTarget && document.activeElement === e.target) { + + const ownerDocument = getOwnerDocument(e.target); + + if (e.target === e.currentTarget && ownerDocument.activeElement === e.target) { if (onFocusProp) { onFocusProp(e); } diff --git a/packages/@react-aria/interactions/stories/useFocusRing.stories.tsx b/packages/@react-aria/interactions/stories/useFocusRing.stories.tsx index 58420fcfdc9..28340021c94 100644 --- a/packages/@react-aria/interactions/stories/useFocusRing.stories.tsx +++ b/packages/@react-aria/interactions/stories/useFocusRing.stories.tsx @@ -10,10 +10,15 @@ * governing permissions and limitations under the License. */ +import {addWindowFocusTracking} from '../src'; import {Cell, Column, Row, TableBody, TableHeader, TableView} from '@react-spectrum/table'; import {Key} from '@react-types/shared'; -import React, {useState} from 'react'; +import {mergeProps} from '@react-aria/utils'; +import React, {useEffect, useRef, useState} from 'react'; +import ReactDOM from 'react-dom'; import {SearchField} from '@react-spectrum/searchfield'; +import {useButton} from '@react-aria/button'; +import {useFocusRing} from '@react-aria/focus'; interface IColumn { name: string, @@ -59,6 +64,11 @@ export const SearchTableview = { } }; +export const IFrame = { + render: () => , + name: 'focus state in dynamic iframe' +}; + function SearchExample() { const [items, setItems] = useState(manyRows); @@ -89,3 +99,48 @@ function SearchExample() { ); } + +function Button() { + const buttonRef = useRef(null); + + const {buttonProps} = useButton({}, buttonRef); + const {focusProps, isFocusVisible, isFocused} = useFocusRing(); + + return ( + + ); +} + +const IframeWrapper = ({children}) => { + const iframeRef = useRef(null); + + useEffect(() => { + if (iframeRef.current) { + const main = document.createElement('main'); + const iframeDocument = iframeRef.current.contentDocument || iframeRef.current.contentWindow.document; + iframeDocument.body.innerHTML = ''; + iframeDocument.body.appendChild(main); + ReactDOM.render(children, main); + + return addWindowFocusTracking(iframeDocument.body); + } + }, [children]); + + return