feat: add accessibility role and state to bottom bar (#90)

### Motivation

Exposing `accessibilityRole` and `accessibilityStates` through props in the same way as `accessibilityLabel`. This allows screen readers to announce things like: `Selected. Banana. Button.`

Reasonable defaults were provided, however, consumers can provide custom overrides in the cases where the role might be `imagebutton` or the state might be `disabled`.

### Test plan

Select a button with VoiceOver (iOS) or Talkback (Android) enabled. The screen reader should read something like `Selected. <AccessibilityLabel>. Button.` or something slightly different depending on which platform you are on. Buttons that are not focused should not have `Selected` announced.
This commit is contained in:
Kevin Fawcett
2019-03-30 12:55:25 -04:00
parent 4b096e9641
commit 7c77f60398
2 changed files with 29 additions and 0 deletions

View File

@@ -13,6 +13,8 @@ import BottomTabBar, { type TabBarOptions } from '../views/BottomTabBar';
import ResourceSavingScene from '../views/ResourceSavingScene';
type Props = InjectedProps & {
getAccessibilityRole: (props: { route: any }) => string,
getAccessibilityStates: (props: { route: any }) => Array<string>,
lazy?: boolean,
tabBarComponent?: React.ComponentType<*>,
tabBarOptions?: TabBarOptions,
@@ -62,6 +64,8 @@ class TabNavigationView extends React.PureComponent<Props, State> {
screenProps,
getLabelText,
getAccessibilityLabel,
getAccessibilityRole,
getAccessibilityStates,
getTestID,
renderIcon,
onTabPress,
@@ -89,6 +93,8 @@ class TabNavigationView extends React.PureComponent<Props, State> {
getLabelText={getLabelText}
getButtonComponent={this._getButtonComponent}
getAccessibilityLabel={getAccessibilityLabel}
getAccessibilityRole={getAccessibilityRole}
getAccessibilityStates={getAccessibilityStates}
getTestID={getTestID}
renderIcon={renderIcon}
/>

View File

@@ -34,6 +34,8 @@ type Props = TabBarOptions & {
onTabPress: any,
onTabLongPress: any,
getAccessibilityLabel: (props: { route: any }) => string,
getAccessibilityRole: (props: { route: any }) => string,
getAccessibilityStates: (props: { route: any }) => Array<string>,
getButtonComponent: ({ route: any }) => any,
getLabelText: ({ route: any }) => any,
getTestID: (props: { route: any }) => string,
@@ -56,6 +58,8 @@ class TouchableWithoutFeedbackWrapper extends React.Component<*> {
onLongPress,
testID,
accessibilityLabel,
accessibilityRole,
accessibilityStates,
...props
} = this.props;
@@ -66,6 +70,8 @@ class TouchableWithoutFeedbackWrapper extends React.Component<*> {
testID={testID}
hitSlop={{ left: 15, right: 15, top: 0, bottom: 5 }}
accessibilityLabel={accessibilityLabel}
accessibilityRole={accessibilityRole}
accessibilityStates={accessibilityStates}
>
<View {...props} />
</TouchableWithoutFeedback>
@@ -220,9 +226,24 @@ class TabBarBottom extends React.Component<Props> {
{routes.map((route, index) => {
const focused = index === navigation.state.index;
const scene = { route, focused };
const accessibilityLabel = this.props.getAccessibilityLabel({
route,
});
const accessibilityRole =
this.props.getAccessibilityRole({
route,
}) || 'button';
let accessibilityStates = this.props.getAccessibilityStates({
route,
});
if (!accessibilityStates) {
accessibilityStates = focused ? ['selected'] : [];
}
const testID = this.props.getTestID({ route });
const backgroundColor = focused
@@ -240,6 +261,8 @@ class TabBarBottom extends React.Component<Props> {
onLongPress={() => onTabLongPress({ route })}
testID={testID}
accessibilityLabel={accessibilityLabel}
accessibilityRole={accessibilityRole}
accessibilityStates={accessibilityStates}
style={[
styles.tab,
{ backgroundColor },