Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
Merge pull request #468 from cds-snc/issue/432/accessiblity
Browse files Browse the repository at this point in the history
Fix accessibility in BottomSheet
  • Loading branch information
henrytao-me authored Jul 6, 2020
2 parents d367780 + c4180d9 commit afd2bdd
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 208 deletions.
139 changes: 54 additions & 85 deletions src/components/BottomSheet/BottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,53 @@
import React, {forwardRef, useState, useCallback, useRef, useEffect, useMemo, useImperativeHandle} from 'react';
import {View, StyleSheet, TouchableOpacity, useWindowDimensions} from 'react-native';
import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
import {StyleSheet, useWindowDimensions, View} from 'react-native';
import Animated from 'react-native-reanimated';
import {useSafeArea} from 'react-native-safe-area-context';
import BottomSheetRaw from 'reanimated-bottom-sheet';
import {useI18n} from '@shopify/react-i18n';

import {Box} from '../Box';
import {Icon} from '../Icon';

import {SheetContentsContainer} from './SheetContentsContainer';

const {abs, sub, pow} = Animated;

export interface BottomSheetProps {
collapsed?: React.ComponentType;
content: React.ComponentType;
extraContent?: boolean;
}

export interface BottomSheetBahavior {
export interface BottomSheetBehavior {
expand(): void;
collapse(): void;
refreshSnapPoints(extraContent: boolean): void;
callbackNode: Animated.Value<number>;
setOnStateChange(onStateChange: (isExpanded: boolean) => void): void;
}

export interface BottomSheetProps {
collapsedComponent: React.ComponentType<BottomSheetBehavior>;
expandedComponent: React.ComponentType<BottomSheetBehavior>;
}

const BottomSheetInternal = (
{content: ContentComponent, collapsed: CollapsedComponent, extraContent}: BottomSheetProps,
ref: React.Ref<BottomSheetBahavior>,
{expandedComponent: ExpandedComponent, collapsedComponent: CollapsedComponent}: BottomSheetProps,
ref: React.Ref<BottomSheetBehavior>,
) => {
const bottomSheetPosition = useRef(new Animated.Value(1));
const bottomSheetRef: React.Ref<BottomSheetRaw> = useRef(null);

const [isExpanded, setIsExpanded] = useState(false);
const [i18n] = useI18n();
const toggleExpanded = useCallback(() => {
setIsExpanded(isExpanded => !isExpanded);
}, []);

useImperativeHandle(ref, () => ({
expand: () => {
setIsExpanded(true);
},
collapse: () => {
setIsExpanded(false);
},
}));
const [extraContent, setExtraContent] = useState(false);
const [onStateChange, setOnStateChange] = useState<(isExpanded: boolean) => void>();

const behavior = useMemo<BottomSheetBehavior>(
() => ({
expand: () => {
setIsExpanded(true);
},
collapse: () => {
setIsExpanded(false);
},
refreshSnapPoints: setExtraContent,
callbackNode: bottomSheetPosition.current,
setOnStateChange: callback => setOnStateChange(() => callback),
}),
[],
);
useImperativeHandle(ref, () => behavior, [behavior]);
useEffect(() => onStateChange?.(isExpanded), [isExpanded, onStateChange]);

const insets = useSafeArea();
const renderHeader = useCallback(() => <Box height={insets.top} />, [insets.top]);
Expand All @@ -58,53 +63,32 @@ const BottomSheetInternal = (
bottomSheetRef.current?.snapTo(isExpanded ? 0 : 1);
}, [width, isExpanded, snapPoints]);

const expandedContentWrapper = useMemo(
() => (
<Animated.View style={{opacity: abs(sub(bottomSheetPosition.current, 1))}}>
<View style={styles.content}>
<ContentComponent />
</View>

<View style={styles.collapseContentHandleBar}>
<TouchableOpacity
onPress={toggleExpanded}
style={styles.collapseButton}
accessibilityLabel={i18n.translate('BottomSheet.Collapse')}
accessibilityRole="button"
>
<Icon name="sheet-handle-bar-close" size={44} />
</TouchableOpacity>
</View>
</Animated.View>
),
[i18n, toggleExpanded],
);
const collapsedContentWrapper = useMemo(
() => (
<Animated.View style={{...styles.collapseContent, opacity: pow(bottomSheetPosition.current, 2)}}>
<View style={styles.collapseContentHandleBar}>
<Icon name="sheet-handle-bar" size={44} />
</View>
{CollapsedComponent ? (
<View style={styles.content}>
<CollapsedComponent />
</View>
) : null}
</Animated.View>
),
[CollapsedComponent],
);
const expandedComponentWrapper = useMemo(() => <ExpandedComponent {...behavior} />, [behavior]);
const collapsedComponentWrapper = useMemo(() => <CollapsedComponent {...behavior} />, [behavior]);

const renderContent = useCallback(() => {
return (
<SheetContentsContainer isExpanded={isExpanded} toggleExpanded={toggleExpanded}>
<SheetContentsContainer>
<>
{collapsedContentWrapper}
{expandedContentWrapper}
<View
style={styles.collapseContent}
accessibilityElementsHidden={isExpanded}
importantForAccessibility={isExpanded ? 'no-hide-descendants' : undefined}
pointerEvents={isExpanded ? 'none' : undefined}
>
{collapsedComponentWrapper}
</View>
<View
pointerEvents={isExpanded ? undefined : 'none'}
accessibilityElementsHidden={!isExpanded}
importantForAccessibility={isExpanded ? undefined : 'no-hide-descendants'}
>
{expandedComponentWrapper}
</View>
</>
</SheetContentsContainer>
);
}, [collapsedContentWrapper, expandedContentWrapper, isExpanded, toggleExpanded]);
}, [collapsedComponentWrapper, expandedComponentWrapper, isExpanded]);

return (
<>
Expand All @@ -127,28 +111,13 @@ const BottomSheetInternal = (
};

const styles = StyleSheet.create({
content: {
marginTop: 10,
spacer: {
marginBottom: -18,
},
collapseContent: {
position: 'absolute',
width: '100%',
},
collapseContentHandleBar: {
position: 'absolute',
width: '100%',
alignItems: 'center',
top: -24,
},
collapseButton: {
height: 50,
width: '100%',
alignItems: 'center',
justifyContent: 'flex-start',
},
spacer: {
marginBottom: -18,
},
});

export const BottomSheet = forwardRef(BottomSheetInternal);
26 changes: 2 additions & 24 deletions src/components/BottomSheet/SheetContentsContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,15 @@
import React from 'react';
import {useI18n} from '@shopify/react-i18n';
import {TouchableHighlight} from 'react-native';

import {Box} from '../Box';
import {SystemStatus, useSystemStatus} from '../../services/ExposureNotificationService';

interface ContentProps {
isExpanded: boolean;
toggleExpanded: () => void;
children?: React.ReactElement;
}

export const SheetContentsContainer = ({children, isExpanded, toggleExpanded}: ContentProps) => {
const [i18n] = useI18n();
const [systemStatus] = useSystemStatus();
const content = (
export const SheetContentsContainer = ({children}: ContentProps) => {
return (
<Box backgroundColor="overlayBackground" minHeight="100%">
<Box marginTop="l">{children}</Box>
</Box>
);

return (
<TouchableHighlight
disabled={isExpanded}
onPress={toggleExpanded}
accessibilityRole="button"
accessibilityLabel={
systemStatus === SystemStatus.Active
? i18n.translate('BottomSheet.OnStatus')
: i18n.translate('BottomSheet.OffStatus')
}
>
{content}
</TouchableHighlight>
);
};
56 changes: 27 additions & 29 deletions src/screens/home/HomeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useCallback, useEffect, useState, useRef, useLayoutEffect} from 'react';
import {useNetInfo} from '@react-native-community/netinfo';
import {DrawerActions, useNavigation} from '@react-navigation/native';
import {BottomSheet, BottomSheetBahavior, Box} from 'components';
import {BottomSheet, BottomSheetBehavior, Box} from 'components';
import {DevSettings, Linking} from 'react-native';
import {
SystemStatus,
Expand Down Expand Up @@ -105,7 +105,7 @@ const Content = ({setBackgroundColor}: ContentProps) => {
}
};

const CollapsedContent = () => {
const CollapsedContent = (bottomSheetBehavior: BottomSheetBehavior) => {
const [systemStatus] = useSystemStatus();
const [notificationStatus, turnNotificationsOn] = useNotificationPermissionStatus();
const showNotificationWarning = notificationStatus !== 'granted';
Expand All @@ -119,11 +119,12 @@ const CollapsedContent = () => {
status={systemStatus}
notificationWarning={showNotificationWarning}
turnNotificationsOn={turnNotificationsOn}
bottomSheetBehavior={bottomSheetBehavior}
/>
);
};

const BottomSheetContent = () => {
const ExpandedContent = (bottomSheetBehavior: BottomSheetBehavior) => {
const [systemStatus] = useSystemStatus();
const [notificationStatus, turnNotificationsOn] = useNotificationPermissionStatus();
const showNotificationWarning = notificationStatus !== 'granted';
Expand All @@ -142,30 +143,7 @@ const BottomSheetContent = () => {
notificationWarning={showNotificationWarning}
turnNotificationsOn={turnNotificationsOnFn}
maxWidth={maxWidth}
/>
);
};

const BottomSheetWrapper = () => {
const bottomSheetRef = useRef<BottomSheetBahavior>(null);
const [notificationStatus] = useNotificationPermissionStatus();
const showNotificationWarning = notificationStatus !== 'granted';

const currentStatus = useExposureStatus()[0].type;
const previousStatus = usePrevious(currentStatus);

useLayoutEffect(() => {
if (previousStatus === 'monitoring' && currentStatus === 'diagnosed') {
bottomSheetRef.current?.collapse();
}
}, [currentStatus, previousStatus]);

return (
<BottomSheet
ref={bottomSheetRef}
content={BottomSheetContent}
collapsed={CollapsedContent}
extraContent={showNotificationWarning}
bottomSheetBehavior={bottomSheetBehavior}
/>
);
};
Expand Down Expand Up @@ -195,13 +173,33 @@ export const HomeScreen = () => {
const maxWidth = useMaxContentWidth();
const [backgroundColor, setBackgroundColor] = useState<string>('mainBackground');

const bottomSheetRef = useRef<BottomSheetBehavior>(null);
const [isBottomSheetExpanded, setIsBottomSheetExpanded] = useState(false);
const currentStatus = useExposureStatus()[0].type;
const previousStatus = usePrevious(currentStatus);
useLayoutEffect(() => {
if (previousStatus === 'monitoring' && currentStatus === 'diagnosed') {
bottomSheetRef.current?.collapse();
}
}, [currentStatus, previousStatus]);
useLayoutEffect(() => {
bottomSheetRef.current?.setOnStateChange(setIsBottomSheetExpanded);
}, []);

return (
<NotificationPermissionStatusProvider>
<Box flex={1} alignItems="center" backgroundColor={strToBackgroundColor(backgroundColor)}>
<Box flex={1} maxWidth={maxWidth} paddingTop="m" alignSelf="stretch">
<Box
flex={1}
maxWidth={maxWidth}
paddingTop="m"
alignSelf="stretch"
accessibilityElementsHidden={isBottomSheetExpanded}
importantForAccessibility={isBottomSheetExpanded ? 'no-hide-descendants' : undefined}
>
<Content setBackgroundColor={setBackgroundColor} />
</Box>
<BottomSheetWrapper />
<BottomSheet ref={bottomSheetRef} expandedComponent={ExpandedContent} collapsedComponent={CollapsedContent} />
</Box>
</NotificationPermissionStatusProvider>
);
Expand Down
Loading

0 comments on commit afd2bdd

Please sign in to comment.