Skip to content

Commit

Permalink
feat: added custom accessibility support (#571)(by @nmuranovas)
Browse files Browse the repository at this point in the history
* feat: add custom accessibility support (#1)

* feat: add accessibility support to BottomSheet
* feat: add accessibility support to BottomSheetBackdrop
* feat: add custom accessibility to BottomSheetHandle
* feat: add BottomSheetHandle export to index.ts

* Feature/custom accessibility (#2)

* fix: rename announceChangeForAccessibility to enableAccessibilityChangeAnnouncement

* fix: add 'import type' where needed

* fix: type import
  • Loading branch information
nmuranovas committed Sep 21, 2021
1 parent 7f5e8d2 commit 7b1bcd8
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 18 deletions.
32 changes: 27 additions & 5 deletions src/components/bottomSheet/BottomSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ import {
DEFAULT_HANDLE_HEIGHT,
DEFAULT_ENABLE_CONTENT_PANNING_GESTURE,
DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,
DEFAULT_ACCESSIBLE,
DEFAULT_ACCESSIBILITY_LABEL,
DEFAULT_ACCESSIBILITY_ROLE,
DEFAULT_ENABLE_ACCESSIBILITY_CHANGE_ANNOUNCEMENT,
DEFAULT_ACCESSIBILITY_POSITION_CHANGE_ANNOUNCEMENT,
} from './constants';
import type { ScrollableRef, BottomSheetMethods } from '../../types';
import type { BottomSheetProps } from './types';
Expand Down Expand Up @@ -113,6 +118,14 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
backdropComponent,
backgroundComponent,
children,

// accessibility
accessible: _providedAccessible = DEFAULT_ACCESSIBLE,
accessibilityLabel: _providedAccessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,
accessibilityRole: _providedAccessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,
enableAccessibilityChangeAnnouncement: _providedEnableAccessibilityChangeAnnouncement = DEFAULT_ENABLE_ACCESSIBILITY_CHANGE_ANNOUNCEMENT,
accessibilityPositionChangeAnnouncement: _providedAccessibilityPositionChangeAnnouncement = DEFAULT_ACCESSIBILITY_POSITION_CHANGE_ANNOUNCEMENT,
...rest
} = props;
//#endregion

Expand Down Expand Up @@ -555,7 +568,10 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
* for accessibility service.
*/
AccessibilityInfo.isScreenReaderEnabled().then(isEnabled => {
if (!isEnabled) {
if (
!isEnabled ||
!_providedEnableAccessibilityChangeAnnouncement
) {
return;
}
const positionInScreen = Math.max(
Expand All @@ -567,7 +583,12 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
0
).toFixed(0);
AccessibilityInfo.announceForAccessibility(
`Bottom sheet snapped to ${positionInScreen}% of the screen`
typeof _providedAccessibilityPositionChangeAnnouncement ===
'function'
? _providedAccessibilityPositionChangeAnnouncement(
positionInScreen
)
: _providedAccessibilityPositionChangeAnnouncement
);
});

Expand Down Expand Up @@ -631,10 +652,11 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
{...containerTapGestureHandler}
>
<Animated.View
accessible={true}
accessibilityRole="adjustable"
accessibilityLabel="Bottom Sheet"
accessible={_providedAccessible ?? undefined}
accessibilityRole={_providedAccessibilityRole ?? undefined}
accessibilityLabel={_providedAccessibilityLabel ?? undefined}
style={containerStyle}
{...rest}
>
<BottomSheetInternalProvider value={internalContextVariables}>
<BottomSheetBackgroundContainer
Expand Down
13 changes: 13 additions & 0 deletions src/components/bottomSheet/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ const NORMAL_DECELERATION_RATE = Platform.select({
android: 0.985,
});

const DEFAULT_ACCESSIBLE = true;
const DEFAULT_ACCESSIBILITY_LABEL = 'Bottom Sheet';
const DEFAULT_ACCESSIBILITY_ROLE = 'adjustable';
const DEFAULT_ENABLE_ACCESSIBILITY_CHANGE_ANNOUNCEMENT = true;
const DEFAULT_ACCESSIBILITY_POSITION_CHANGE_ANNOUNCEMENT = (
positionInScreen: string
) => `Bottom sheet snapped to ${positionInScreen}% of the screen`;

export {
DEFAULT_ANIMATION_EASING,
DEFAULT_ANIMATION_DURATION,
Expand All @@ -30,4 +38,9 @@ export {
DEFAULT_ENABLE_CONTENT_PANNING_GESTURE,
DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,
NORMAL_DECELERATION_RATE,
DEFAULT_ACCESSIBLE,
DEFAULT_ACCESSIBILITY_LABEL,
DEFAULT_ACCESSIBILITY_ROLE,
DEFAULT_ENABLE_ACCESSIBILITY_CHANGE_ANNOUNCEMENT,
DEFAULT_ACCESSIBILITY_POSITION_CHANGE_ANNOUNCEMENT,
};
19 changes: 18 additions & 1 deletion src/components/bottomSheet/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { State } from 'react-native-gesture-handler';
import type { BottomSheetHandleProps } from '../bottomSheetHandle';
import type { BottomSheetBackgroundProps } from '../bottomSheetBackground';
import type { BottomSheetBackdropProps } from '../bottomSheetBackdrop';
import type { NullableAccessibilityProps } from '../../types';

export type BottomSheetProps = {
// configuration
Expand Down Expand Up @@ -140,7 +141,23 @@ export type BottomSheetProps = {
* @type React.ReactNode[] | React.ReactNode
*/
children: (() => React.ReactNode) | React.ReactNode[] | React.ReactNode;
} & BottomSheetAnimationConfigs;

// accessibility
/**
* Enables announcement of the snap position change on screen readers.
* @type boolean
* @default true
*/
enableAccessibilityChangeAnnouncement?: boolean;
/**
* Callback on snap position change that announces the returned string on screen readers.
* @type string | ((positionInScreen: string) => string)
*/
accessibilityPositionChangeAnnouncement?:
| string
| ((positionInScreen: string) => string);
} & BottomSheetAnimationConfigs &
Omit<NullableAccessibilityProps, 'accessibilityHint'>;

export interface BottomSheetAnimationConfigs {
/**
Expand Down
18 changes: 14 additions & 4 deletions src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import {
DEFAULT_APPEARS_ON_INDEX,
DEFAULT_DISAPPEARS_ON_INDEX,
DEFAULT_ENABLE_TOUCH_THROUGH,
DEFAULT_ACCESSIBLE,
DEFAULT_ACCESSIBILITY_ROLE,
DEFAULT_ACCESSIBILITY_LABEL,
DEFAULT_ACCESSIBILITY_HINT,
} from './constants';
import { WINDOW_HEIGHT } from '../../constants';
import { usePressBehavior } from './usePressBehavior';
Expand All @@ -44,6 +48,11 @@ const BottomSheetBackdropComponent = ({
pressBehavior,
closeOnPress,
style,
accessible: _providedAccessible = DEFAULT_ACCESSIBLE,
accessibilityRole: _providedAccessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,
accessibilityLabel: _providedAccessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,
accessibilityHint: _providedAccessiblityHint = DEFAULT_ACCESSIBILITY_HINT,
...rest
}: BottomSheetDefaultBackdropProps) => {
//#region hooks
const { handleOnPress, syntheticPressBehavior } = usePressBehavior({
Expand Down Expand Up @@ -137,12 +146,13 @@ const BottomSheetBackdropComponent = ({

return syntheticPressBehavior !== 'none' ? (
<AnimatedTouchableWithoutFeedback
accessible={true}
accessibilityRole="button"
accessibilityLabel="Bottom Sheet backdrop"
accessibilityHint="Tap to close the Bottom Sheet"
accessible={_providedAccessible ?? undefined}
accessibilityRole={_providedAccessibilityRole ?? undefined}
accessibilityLabel={_providedAccessibilityLabel ?? undefined}
accessibilityHint={_providedAccessiblityHint ?? undefined}
onPress={handleOnPress}
style={buttonStyle}
{...rest}
>
<Animated.View key="backdrop" ref={containerRef} style={containerStyle} />
</AnimatedTouchableWithoutFeedback>
Expand Down
9 changes: 9 additions & 0 deletions src/components/bottomSheetBackdrop/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ const DEFAULT_DISAPPEARS_ON_INDEX = 0;
const DEFAULT_ENABLE_TOUCH_THROUGH = false;
const DEFAULT_PRESS_BEHAVIOR = 'close' as const;

const DEFAULT_ACCESSIBLE = true;
const DEFAULT_ACCESSIBILITY_ROLE = 'button';
const DEFAULT_ACCESSIBILITY_LABEL = 'Bottom Sheet backdrop';
const DEFAULT_ACCESSIBILITY_HINT = 'Tap to close the Bottom Sheet';

export {
DEFAULT_OPACITY,
DEFAULT_APPEARS_ON_INDEX,
DEFAULT_DISAPPEARS_ON_INDEX,
DEFAULT_ENABLE_TOUCH_THROUGH,
DEFAULT_PRESS_BEHAVIOR,
DEFAULT_ACCESSIBLE,
DEFAULT_ACCESSIBILITY_ROLE,
DEFAULT_ACCESSIBILITY_LABEL,
DEFAULT_ACCESSIBILITY_HINT,
};
4 changes: 3 additions & 1 deletion src/components/bottomSheetBackdrop/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ViewProps } from 'react-native';
import type Animated from 'react-native-reanimated';
import type { NullableAccessibilityProps } from '../../types';

export interface BottomSheetBackdropProps extends Pick<ViewProps, 'style'> {
/**
Expand All @@ -17,7 +18,8 @@ export interface BottomSheetBackdropProps extends Pick<ViewProps, 'style'> {
export type BackdropPressBehavior = 'none' | 'close' | 'collapse' | number;

export interface BottomSheetDefaultBackdropProps
extends BottomSheetBackdropProps {
extends BottomSheetBackdropProps,
NullableAccessibilityProps {
/**
* Backdrop opacity.
* @type number
Expand Down
26 changes: 24 additions & 2 deletions src/components/bottomSheetHandle/BottomSheetHandle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,32 @@ import React, { memo } from 'react';
import { View } from 'react-native';
import isEqual from 'lodash.isequal';
import { styles } from './styles';
import type { BottomSheetDefaultHandleProps } from './types';
import {
DEFAULT_ACCESSIBLE,
DEFAULT_ACCESSIBILITY_ROLE,
DEFAULT_ACCESSIBILITY_LABEL,
DEFAULT_ACCESSIBILITY_HINT,
} from './constants';

const BottomSheetHandleComponent = (props: BottomSheetDefaultHandleProps) => {
const {
accessible = DEFAULT_ACCESSIBLE,
accessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,
accessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,
accessibilityHint = DEFAULT_ACCESSIBILITY_HINT,
...rest
} = props;

const BottomSheetHandleComponent = () => {
return (
<View style={styles.container}>
<View
style={styles.container}
accessible={accessible ?? undefined}
accessibilityRole={accessibilityRole ?? undefined}
accessibilityLabel={accessibilityLabel ?? undefined}
accessibilityHint={accessibilityHint ?? undefined}
{...rest}
>
<View style={styles.indicator} />
</View>
);
Expand Down
12 changes: 12 additions & 0 deletions src/components/bottomSheetHandle/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const DEFAULT_ACCESSIBLE = true;
const DEFAULT_ACCESSIBILITY_ROLE = 'adjustable';
const DEFAULT_ACCESSIBILITY_LABEL = 'Bottom Sheet handle';
const DEFAULT_ACCESSIBILITY_HINT =
'Drag up or down to extend or minimize the Bottom Sheet';

export {
DEFAULT_ACCESSIBLE,
DEFAULT_ACCESSIBILITY_ROLE,
DEFAULT_ACCESSIBILITY_LABEL,
DEFAULT_ACCESSIBILITY_HINT,
};
5 changes: 5 additions & 0 deletions src/components/bottomSheetHandle/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type Animated from 'react-native-reanimated';
import type { NullableAccessibilityProps } from '../../types';

export interface BottomSheetHandleProps {
/**
Expand All @@ -12,3 +13,7 @@ export interface BottomSheetHandleProps {
*/
animatedPosition: Animated.Node<number>;
}

export interface BottomSheetDefaultHandleProps
extends Omit<BottomSheetHandleProps, 'animatedIndex' | 'animatedPosition'>,
NullableAccessibilityProps {}
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ const BottomSheetHandleContainerComponent = ({
onHandlerStateChange={onHandlerStateChange}
>
<Animated.View
accessible={true}
accessibilityRole="adjustable"
accessibilityLabel="Bottom Sheet handle"
accessibilityHint="Drag up or down to extend or minimize the Bottom Sheet"
onLayout={shouldMeasureHeight ? handleOnLayout : undefined}
>
{renderHandle()}
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export const {
// backdrop
export { default as BottomSheetBackdrop } from './components/bottomSheetBackdrop';

// handle
export { default as BottomSheetHandle } from './components/bottomSheetHandle';

// modal
export { default as BottomSheetModal } from './components/bottomSheetModal';
export { default as BottomSheetModalProvider } from './components/bottomSheetModalProvider';
Expand Down
14 changes: 13 additions & 1 deletion src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { FlatList, ScrollView, SectionList } from 'react-native';
import type {
AccessibilityProps,
FlatList,
ScrollView,
SectionList,
} from 'react-native';

//#region Methods
export interface BottomSheetMethods {
Expand Down Expand Up @@ -49,3 +54,10 @@ export type ScrollableRef = {
type: ScrollableType;
};
//#endregion

export interface NullableAccessibilityProps extends AccessibilityProps {
accessible?: AccessibilityProps['accessible'] | null;
accessibilityLabel?: AccessibilityProps['accessibilityLabel'] | null;
accessibilityHint?: AccessibilityProps['accessibilityHint'] | null;
accessibilityRole?: AccessibilityProps['accessibilityRole'] | null;
}

0 comments on commit 7b1bcd8

Please sign in to comment.