From 55ea06f6491b1f18bc1c3a17260f7df899b82f16 Mon Sep 17 00:00:00 2001 From: Tim R Date: Wed, 8 Mar 2023 14:45:09 -0600 Subject: [PATCH 1/2] Ready for PR --- .../components/Templates/CategoryLanding.tsx | 5 +- .../FeatureLandingAndChildTemplate.tsx | 7 ++- .../src/components/Templates/HeaderBanner.tsx | 21 +++++--- VAMobile/src/utils/hooks.tsx | 50 +++++++++++++++---- 4 files changed, 58 insertions(+), 25 deletions(-) diff --git a/VAMobile/src/components/Templates/CategoryLanding.tsx b/VAMobile/src/components/Templates/CategoryLanding.tsx index 345509afd3b..7b937675e14 100644 --- a/VAMobile/src/components/Templates/CategoryLanding.tsx +++ b/VAMobile/src/components/Templates/CategoryLanding.tsx @@ -3,7 +3,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context' import React, { FC, useState } from 'react' import { CrisisLineCta, TextView, TextViewProps, VAIconProps } from 'components' -import { useRouteNavigation, useTheme } from 'utils/hooks' +import { useIsScreenReaderEnabled, useRouteNavigation, useTheme } from 'utils/hooks' import HeaderBanner, { HeaderBannerProps } from './HeaderBanner' import VAScrollView, { VAScrollViewProps } from 'components/VAScrollView' @@ -34,6 +34,7 @@ export const CategoryLanding: FC = ({ title, headerButton, const fontScale = useWindowDimensions().fontScale const theme = useTheme() const navigateTo = useRouteNavigation() + const screenReaderEnabled = useIsScreenReaderEnabled(true) const [scrollOffset, setScrollOffset] = useState(0) const [trackScrollOffset, setTrackScrollOffset] = useState(true) @@ -99,7 +100,7 @@ export const CategoryLanding: FC = ({ title, headerButton, - {title ? {title} : null} + {title && !screenReaderEnabled ? {title} : null} {children} diff --git a/VAMobile/src/components/Templates/FeatureLandingAndChildTemplate.tsx b/VAMobile/src/components/Templates/FeatureLandingAndChildTemplate.tsx index f08c2bdefca..6bf963644b7 100644 --- a/VAMobile/src/components/Templates/FeatureLandingAndChildTemplate.tsx +++ b/VAMobile/src/components/Templates/FeatureLandingAndChildTemplate.tsx @@ -3,7 +3,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context' import React, { FC, ReactNode, useState } from 'react' import { TextView, TextViewProps, VAIconProps } from 'components' -import { useTheme } from 'utils/hooks' +import { useIsScreenReaderEnabled, useTheme } from 'utils/hooks' import HeaderBanner, { HeaderBannerProps } from './HeaderBanner' import VAScrollView, { VAScrollViewProps } from 'components/VAScrollView' @@ -46,6 +46,7 @@ export const ChildTemplate: FC = ({ backLabel, backLabelA11y const insets = useSafeAreaInsets() const fontScale = useWindowDimensions().fontScale const theme = useTheme() + const screenReaderEnabled = useIsScreenReaderEnabled(true) const [scrollOffset, setScrollOffset] = useState(0) const [trackScrollOffset, setTrackScrollOffset] = useState(true) @@ -108,9 +109,7 @@ export const ChildTemplate: FC = ({ backLabel, backLabelA11y transitionHeader(event.nativeEvent.contentOffset.y) }} {...scrollViewProps}> - - {title} - + {!screenReaderEnabled ? {title} : null} {children} {footerContent} diff --git a/VAMobile/src/components/Templates/HeaderBanner.tsx b/VAMobile/src/components/Templates/HeaderBanner.tsx index 621ce1d2aac..a01f02d3cc9 100644 --- a/VAMobile/src/components/Templates/HeaderBanner.tsx +++ b/VAMobile/src/components/Templates/HeaderBanner.tsx @@ -4,7 +4,7 @@ import { useFocusEffect } from '@react-navigation/native' import React, { FC, useEffect, useReducer, useState } from 'react' import { Box, BoxProps, DescriptiveBackButton, TextView, TextViewProps, VAIcon, VAIconProps } from 'components' -import { useAccessibilityFocus, useTheme } from 'utils/hooks' +import { useAccessibilityFocus, useIsScreenReaderEnabled, useTheme } from 'utils/hooks' import MenuView, { MenuViewActionsType } from 'components/Menu' export type HeaderLeftButtonProps = { @@ -63,6 +63,7 @@ const HeaderBanner: FC = ({ leftButton, title, rightButton, d const [focusTitle, setFocusTitle] = useAccessibilityFocus() const focus = leftButton ? 'Left' : title ? 'Title' : 'Right' useFocusEffect(focus === 'Title' ? setFocusTitle : setFocus) + const screenReaderEnabled = useIsScreenReaderEnabled(true) const TEXT_CONSTRAINT_THRESHOLD = 30 @@ -79,6 +80,9 @@ const HeaderBanner: FC = ({ leftButton, title, rightButton, d * Reducer to swap between "VA" and title based on scroll */ const titleShowingReducer = (initTitleShowing: boolean) => { + if (screenReaderEnabled) { + return true + } return transition ? title.scrollOffset >= title.transitionHeaderHeight : initTitleShowing } @@ -123,13 +127,14 @@ const HeaderBanner: FC = ({ leftButton, title, rightButton, d zIndex: 1, } - const headerDropShadow: ShadowProps = titleShowing - ? { - startColor: theme.colors.background.headerDropShadow, - distance: 4, - sides: { start: false, top: false, bottom: true, end: false }, - } - : { disabled: true } + const headerDropShadow: ShadowProps = + titleShowing && !screenReaderEnabled + ? { + startColor: theme.colors.background.headerDropShadow, + distance: 4, + sides: { start: false, top: false, bottom: true, end: false }, + } + : { disabled: true } const titleBannerProps: BoxProps = { alignItems: 'center', diff --git a/VAMobile/src/utils/hooks.tsx b/VAMobile/src/utils/hooks.tsx index 014a0d6e2e9..0bd52be0074 100644 --- a/VAMobile/src/utils/hooks.tsx +++ b/VAMobile/src/utils/hooks.tsx @@ -1,4 +1,18 @@ -import { AccessibilityInfo, ActionSheetIOS, Alert, AlertButton, AppState, Dimensions, Linking, PixelRatio, ScrollView, UIManager, View, findNodeHandle } from 'react-native' +import { + AccessibilityInfo, + ActionSheetIOS, + Alert, + AlertButton, + AppState, + Dimensions, + EmitterSubscription, + Linking, + PixelRatio, + ScrollView, + UIManager, + View, + findNodeHandle, +} from 'react-native' import { EventArg, useNavigation } from '@react-navigation/native' import { ImagePickerResponse } from 'react-native-image-picker' import { MutableRefObject, ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react' @@ -147,10 +161,10 @@ export function useAccessibilityFocus(): [MutableRefObject, () => void] { // eslint-disable-next-line @typescript-eslint/no-explicit-any const ref: MutableRefObject = useRef(null) const dispatch = useAppDispatch() - const screanReaderEnabled = useIsScreanReaderEnabled() + const screenReaderEnabled = useIsScreenReaderEnabled() const setFocus = useCallback(() => { - if (ref.current && screanReaderEnabled) { + if (ref.current && screenReaderEnabled) { /** * There is a race condition during transition that causes the accessibility focus * to intermittently fail to be set https://github.com/facebook/react-native/issues/30097 @@ -181,32 +195,46 @@ export function useAccessibilityFocus(): [MutableRefObject, () => void] { return () => clearTimeout(timeOutPageFocus) } - }, [ref, dispatch, screanReaderEnabled]) + }, [ref, dispatch, screenReaderEnabled]) return [ref, setFocus] } /** - * Hook to check if the screan reader is enabled + * Hook to check if the screen reader is enabled * + * withListener - True to add a listener to live update screen reader status, default false * @returns boolean if the screen reader is on */ -export function useIsScreanReaderEnabled(): boolean { - const [screanReaderEnabled, setScreanReaderEnabled] = useState(false) +export function useIsScreenReaderEnabled(withListener = false): boolean { + const [screenReaderEnabled, setScreenReaderEnabled] = useState(false) useEffect(() => { let isMounted = true + let screenReaderChangedSubscription: EmitterSubscription + + if (withListener) { + screenReaderChangedSubscription = AccessibilityInfo.addEventListener('screenReaderChanged', (isScreenReaderEnabled) => { + if (isMounted) { + setScreenReaderEnabled(isScreenReaderEnabled) + } + }) + } AccessibilityInfo.isScreenReaderEnabled().then((isScreenReaderEnabled) => { if (isMounted) { - setScreanReaderEnabled(isScreenReaderEnabled) + setScreenReaderEnabled(isScreenReaderEnabled) } }) + return () => { isMounted = false + if (withListener) { + screenReaderChangedSubscription.remove() + } } - }, [screanReaderEnabled]) + }, [screenReaderEnabled, withListener]) - return screanReaderEnabled + return screenReaderEnabled } /** @@ -301,7 +329,7 @@ export function useAutoScrollToElement(): [MutableRefObject, Mutable const scrollRef = useRef() as MutableRefObject const [viewRef, setFocus] = useAccessibilityFocus() const [shouldFocus, setShouldFocus] = useState(true) - const screenReaderEnabled = useIsScreanReaderEnabled() + const screenReaderEnabled = useIsScreenReaderEnabled() const scrollToElement = useCallback( (offset?: number) => { From 4da6a8c8be00d2224e6d850d60b501bc04a59959 Mon Sep 17 00:00:00 2001 From: Tim R Date: Wed, 8 Mar 2023 15:42:48 -0600 Subject: [PATCH 2/2] Hopeful fix for silly docusaurus failure --- .../FrontEnd/CustomHooks/useIsScreanReaderEnabled.mdx | 8 -------- .../FrontEnd/CustomHooks/useIsScreenReaderEnabled.mdx | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreanReaderEnabled.mdx create mode 100644 VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreenReaderEnabled.mdx diff --git a/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreanReaderEnabled.mdx b/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreanReaderEnabled.mdx deleted file mode 100644 index 726761ae812..00000000000 --- a/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreanReaderEnabled.mdx +++ /dev/null @@ -1,8 +0,0 @@ -import HooksInfo from '../../../../src/components/HooksInfo' - -export const exampleString = `const screanReaderEnabled = useIsScreanReaderEnabled()\n -const setFocus = useCallback(() => { - if (ref.current && screanReaderEnabled) {} -}` - - diff --git a/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreenReaderEnabled.mdx b/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreenReaderEnabled.mdx new file mode 100644 index 00000000000..388fb7bdf94 --- /dev/null +++ b/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreenReaderEnabled.mdx @@ -0,0 +1,8 @@ +import HooksInfo from '../../../../src/components/HooksInfo' + +export const exampleString = `const screenReaderEnabled = useIsScreenReaderEnabled()\n +const setFocus = useCallback(() => { + if (ref.current && screenReaderEnabled) {} +}` + +