From 628fc66eccf5657c285403da8161f5d21a28c988 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sun, 14 Jan 2024 10:19:01 +0530 Subject: [PATCH 1/4] fixed focus behavior and optimize active element role implementation --- src/App.js | 2 + .../index.native.tsx | 20 ++++++++++ .../ActiveElementRoleProvider/index.tsx | 40 +++++++++++++++++++ .../ActiveElementRoleProvider/types.ts | 9 +++++ src/components/Button/index.tsx | 18 +++++---- .../useActiveElementRole/index.native.ts | 8 ---- src/hooks/useActiveElementRole/index.ts | 25 ++---------- src/hooks/useActiveElementRole/types.ts | 2 +- 8 files changed, 86 insertions(+), 38 deletions(-) create mode 100644 src/components/ActiveElementRoleProvider/index.native.tsx create mode 100644 src/components/ActiveElementRoleProvider/index.tsx create mode 100644 src/components/ActiveElementRoleProvider/types.ts delete mode 100644 src/hooks/useActiveElementRole/index.native.ts diff --git a/src/App.js b/src/App.js index 3553900bbc7f..58339d22dc86 100644 --- a/src/App.js +++ b/src/App.js @@ -6,6 +6,7 @@ import Onyx from 'react-native-onyx'; import {PickerStateProvider} from 'react-native-picker-select'; import {SafeAreaProvider} from 'react-native-safe-area-context'; import '../wdyr'; +import ActiveElementRoleProvider from './components/ActiveElementRoleProvider'; import ColorSchemeWrapper from './components/ColorSchemeWrapper'; import ComposeProviders from './components/ComposeProviders'; import CustomStatusBarAndBackground from './components/CustomStatusBarAndBackground'; @@ -69,6 +70,7 @@ function App() { PickerStateProvider, EnvironmentProvider, CustomStatusBarAndBackgroundContextProvider, + ActiveElementRoleProvider, ]} > diff --git a/src/components/ActiveElementRoleProvider/index.native.tsx b/src/components/ActiveElementRoleProvider/index.native.tsx new file mode 100644 index 000000000000..4a9f2290b2b0 --- /dev/null +++ b/src/components/ActiveElementRoleProvider/index.native.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import type {ActiveElementRoleContextValue, ActiveElementRoleProps} from './types'; + +const ActiveElementRoleContext = React.createContext({ + role: null, +}); + +function ActiveElementRoleProvider({children}: ActiveElementRoleProps) { + const value = React.useMemo( + () => ({ + role: null, + }), + [], + ); + + return {children}; +} + +export default ActiveElementRoleProvider; +export {ActiveElementRoleContext}; diff --git a/src/components/ActiveElementRoleProvider/index.tsx b/src/components/ActiveElementRoleProvider/index.tsx new file mode 100644 index 000000000000..260fbbad668d --- /dev/null +++ b/src/components/ActiveElementRoleProvider/index.tsx @@ -0,0 +1,40 @@ +import React, {useEffect, useState} from 'react'; +import type {ActiveElementRoleContextValue, ActiveElementRoleProps} from './types'; + +const ActiveElementRoleContext = React.createContext({ + role: null, +}); + +function ActiveElementRoleProvider({children}: ActiveElementRoleProps) { + const [activeRoleRef, setRole] = useState(null); + + const handleFocusIn = () => { + setRole(document?.activeElement?.role ?? null); + }; + + const handleFocusOut = () => { + setRole(null); + }; + + useEffect(() => { + document.addEventListener('focusin', handleFocusIn); + document.addEventListener('focusout', handleFocusOut); + + return () => { + document.removeEventListener('focusin', handleFocusIn); + document.removeEventListener('focusout', handleFocusOut); + }; + }, []); + + const value = React.useMemo( + () => ({ + role: activeRoleRef, + }), + [activeRoleRef], + ); + + return {children}; +} + +export default ActiveElementRoleProvider; +export {ActiveElementRoleContext}; diff --git a/src/components/ActiveElementRoleProvider/types.ts b/src/components/ActiveElementRoleProvider/types.ts new file mode 100644 index 000000000000..f22343b12550 --- /dev/null +++ b/src/components/ActiveElementRoleProvider/types.ts @@ -0,0 +1,9 @@ +type ActiveElementRoleContextValue = { + role: string | null; +}; + +type ActiveElementRoleProps = { + children: React.ReactNode; +}; + +export type {ActiveElementRoleContextValue, ActiveElementRoleProps}; diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 5fb134648134..5fdda0b1a80e 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -265,14 +265,16 @@ function Button( return ( <> - + {pressOnEnter && ( + + )} { diff --git a/src/hooks/useActiveElementRole/index.native.ts b/src/hooks/useActiveElementRole/index.native.ts deleted file mode 100644 index 4278014f02a8..000000000000 --- a/src/hooks/useActiveElementRole/index.native.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type UseActiveElementRole from './types'; - -/** - * Native doesn't have the DOM, so we just return null. - */ -const useActiveElementRole: UseActiveElementRole = () => null; - -export default useActiveElementRole; diff --git a/src/hooks/useActiveElementRole/index.ts b/src/hooks/useActiveElementRole/index.ts index a98999105ac8..98ae285f92b0 100644 --- a/src/hooks/useActiveElementRole/index.ts +++ b/src/hooks/useActiveElementRole/index.ts @@ -1,4 +1,5 @@ -import {useEffect, useRef} from 'react'; +import {useContext} from 'react'; +import {ActiveElementRoleContext} from '@components/ActiveElementRoleProvider'; import type UseActiveElementRole from './types'; /** @@ -6,27 +7,9 @@ import type UseActiveElementRole from './types'; * On native, we just return null. */ const useActiveElementRole: UseActiveElementRole = () => { - const activeRoleRef = useRef(document?.activeElement?.role); + const {role} = useContext(ActiveElementRoleContext); - const handleFocusIn = () => { - activeRoleRef.current = document?.activeElement?.role; - }; - - const handleFocusOut = () => { - activeRoleRef.current = null; - }; - - useEffect(() => { - document.addEventListener('focusin', handleFocusIn); - document.addEventListener('focusout', handleFocusOut); - - return () => { - document.removeEventListener('focusin', handleFocusIn); - document.removeEventListener('focusout', handleFocusOut); - }; - }, []); - - return activeRoleRef.current; + return role; }; export default useActiveElementRole; diff --git a/src/hooks/useActiveElementRole/types.ts b/src/hooks/useActiveElementRole/types.ts index c31b8ab7ddbf..f6884548785f 100644 --- a/src/hooks/useActiveElementRole/types.ts +++ b/src/hooks/useActiveElementRole/types.ts @@ -1,3 +1,3 @@ -type UseActiveElementRole = () => string | null | undefined; +type UseActiveElementRole = () => string | null; export default UseActiveElementRole; From f999a856f5545213cdbc7c1db0debc311624d793 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sun, 14 Jan 2024 12:18:26 +0530 Subject: [PATCH 2/4] minor fix with initial state --- src/components/ActiveElementRoleProvider/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ActiveElementRoleProvider/index.tsx b/src/components/ActiveElementRoleProvider/index.tsx index 260fbbad668d..630af8618c08 100644 --- a/src/components/ActiveElementRoleProvider/index.tsx +++ b/src/components/ActiveElementRoleProvider/index.tsx @@ -6,7 +6,7 @@ const ActiveElementRoleContext = React.createContext(null); + const [activeRoleRef, setRole] = useState(document?.activeElement?.role ?? null); const handleFocusIn = () => { setRole(document?.activeElement?.role ?? null); From 3e628be1f8e15b690147e82f68355aabda8b52f5 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 13 Feb 2024 16:40:41 +0530 Subject: [PATCH 3/4] fixed translation to trackDistanceChooseUnit --- src/languages/es.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index b02aef189545..2959024746d1 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1646,7 +1646,7 @@ export default { trackDistanceCopy: 'Configura la tarifa y unidad usadas para medir distancias.', trackDistanceRate: 'Tarifa', trackDistanceUnit: 'Unidad', - trackDistanceChooseUnit: 'Elija una unidad predeterminada para rastrear.', + trackDistanceChooseUnit: 'Elige una unidad predeterminada de medida.', kilometers: 'Kilómetros', miles: 'Millas', unlockNextDayReimbursements: 'Desbloquea reembolsos diarios', From ea97c12d21a342d1dbf614740807f86ce13ce5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Tue, 13 Feb 2024 17:29:54 +0100 Subject: [PATCH 4/4] typecheck fixes --- src/pages/ShareCodePage.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index 138aa729fcc2..e4e2a90c4157 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -12,8 +12,7 @@ import QRShareWithDownload from '@components/QRShare/QRShareWithDownload'; import type QRShareWithDownloadHandle from '@components/QRShare/QRShareWithDownload/types'; import ScreenWrapper from '@components/ScreenWrapper'; import Section from '@components/Section'; -import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; -import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -28,9 +27,9 @@ import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Report, Session} from '@src/types/onyx'; -type ShareCodePageOnyxProps = WithCurrentUserPersonalDetailsProps & { +type ShareCodePageOnyxProps = { /** Session info for the currently logged in user. */ - session: OnyxEntry; + session?: OnyxEntry; /** The report currently being looked at */ report?: OnyxEntry; @@ -38,12 +37,13 @@ type ShareCodePageOnyxProps = WithCurrentUserPersonalDetailsProps & { type ShareCodePageProps = ShareCodePageOnyxProps; -function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodePageProps) { +function ShareCodePage({report, session}: ShareCodePageProps) { const themeStyles = useThemeStyles(); const {translate} = useLocalize(); const {environmentURL} = useEnvironment(); const qrCodeRef = useRef(null); const {isSmallScreenWidth} = useWindowDimensions(); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const isReport = !!report?.reportID; @@ -145,4 +145,4 @@ function ShareCodePage({report, session, currentUserPersonalDetails}: ShareCodeP ShareCodePage.displayName = 'ShareCodePage'; -export default withCurrentUserPersonalDetails(ShareCodePage); +export default ShareCodePage;