Skip to content

Commit

Permalink
Added talkback support for TouchableNativeFeedback accessibility: dis…
Browse files Browse the repository at this point in the history
…abled prop (#31224)

Summary:
Issue #30952
Add talkback support for TouchableNativeFeedback component.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Changed] - TouchableNativeFeedback: sync disabled prop with accessibilityState

Pull Request resolved: #31224

Test Plan:
I have checked that talkback and disabled works properly on the actual device(Pixel4a Android11).

```jsx
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * format
 * flow strict-local
 */

import * as React from 'react';
import {
  Text,
  View,
  StyleSheet,
  TouchableNativeFeedback,
  Alert,
} from 'react-native';

export default function App() {
  const onPress = () => Alert.alert('test');

  return (
    <View style={styles.container}>
      {/*not disabled, voice:double tap to activate*/}
      <TouchableNativeFeedback onPress={onPress}>
        <View style={styles.touchable}>
          <Text style={styles.text}>talkback OK</Text>
        </View>
      </TouchableNativeFeedback>

      {/*disabled, voice:disabled*/}
      <TouchableNativeFeedback disabled={true} onPress={onPress}>
        <View style={styles.touchable}>
          <Text style={styles.text}>
            should be disabled when disabled is true
          </Text>
        </View>
      </TouchableNativeFeedback>

      {/*disabled, voice:disabled*/}
      <TouchableNativeFeedback
        accessibilityState={{disabled: true}}
        onPress={onPress}>
        <View style={styles.touchable}>
          <Text style={styles.text}>
            should be disabled when accessibilityState disabled is true
          </Text>
        </View>
      </TouchableNativeFeedback>

      {/*disabled, voice:disabled*/}
      <TouchableNativeFeedback
        disabled={true}
        accessibilityState={{}}
        onPress={onPress}>
        <View style={styles.touchable}>
          <Text style={styles.text}>
            should be disabled when disabled is true and accessibilityState is
            empty
          </Text>
        </View>
      </TouchableNativeFeedback>

      {/*disabled, voice:disabled*/}
      <TouchableNativeFeedback
        disabled={true}
        accessibilityState={{checked: true}}
        onPress={onPress}>
        <View style={styles.touchable}>
          <Text style={styles.text}>
            should keep accessibilityState when disabled is true
          </Text>
        </View>
      </TouchableNativeFeedback>

      {/*disabled, voice:disabled*/}
      <TouchableNativeFeedback
        disabled={true}
        accessibilityState={{disabled: false}}
        onPress={onPress}>
        <View style={styles.touchable}>
          <Text style={styles.text}>
            should overwrite accessibilityState with value of disabled prop
          </Text>
        </View>
      </TouchableNativeFeedback>

      {/*not disabled, voice:double tap to activate*/}
      <TouchableNativeFeedback
        disabled={false}
        accessibilityState={{disabled: true}}
        onPress={onPress}>
        <View style={styles.touchable}>
          <Text style={styles.text}>
            should overwrite accessibilityState with value of disabled prop
          </Text>
        </View>
      </TouchableNativeFeedback>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 16,
  },
  touchable: {flex: 0.5, borderColor: 'black', borderWidth: 1, marginBottom: 8},
  text: {alignSelf: 'center'},
});

```

Reviewed By: yungsters

Differential Revision: D27479271

Pulled By: kacieb

fbshipit-source-id: 43187839b58dfe8f91afdba91453fb6b98e1a604
  • Loading branch information
kyamashiro authored and facebook-github-bot committed Apr 3, 2021
1 parent cb028ee commit 88f2356
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 5 deletions.
15 changes: 13 additions & 2 deletions Libraries/Components/Touchable/TouchableNativeFeedback.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,10 @@ class TouchableNativeFeedback extends React.Component<Props, State> {
_createPressabilityConfig(): PressabilityConfig {
return {
cancelable: !this.props.rejectResponderTermination,
disabled: this.props.disabled,
disabled:
this.props.disabled != null
? this.props.disabled
: this.props.accessibilityState?.disabled,
hitSlop: this.props.hitSlop,
delayLongPress: this.props.delayLongPress,
delayPressIn: this.props.delayPressIn,
Expand Down Expand Up @@ -255,6 +258,14 @@ class TouchableNativeFeedback extends React.Component<Props, State> {
...eventHandlersWithoutBlurAndFocus
} = this.state.pressability.getEventHandlers();

const accessibilityState =
this.props.disabled != null
? {
...this.props.accessibilityState,
disabled: this.props.disabled,
}
: this.props.accessibilityState;

return React.cloneElement(
element,
{
Expand All @@ -269,7 +280,7 @@ class TouchableNativeFeedback extends React.Component<Props, State> {
accessibilityHint: this.props.accessibilityHint,
accessibilityLabel: this.props.accessibilityLabel,
accessibilityRole: this.props.accessibilityRole,
accessibilityState: this.props.accessibilityState,
accessibilityState: accessibilityState,
accessibilityActions: this.props.accessibilityActions,
onAccessibilityAction: this.props.onAccessibilityAction,
accessibilityValue: this.props.accessibilityValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@

'use strict';

const React = require('react');
const Text = require('../../../Text/Text');
const TouchableNativeFeedback = require('../TouchableNativeFeedback');
import * as React from 'react';
import ReactTestRenderer from 'react-test-renderer';
import Text from '../../../Text/Text';
import TouchableNativeFeedback from '../TouchableNativeFeedback';
import View from '../../View/View';

const render = require('../../../../jest/renderer');

Expand All @@ -33,3 +35,81 @@ describe('TouchableWithoutFeedback', () => {
);
});
});

describe('<TouchableNativeFeedback />', () => {
it('should render as expected', () => {
const instance = ReactTestRenderer.create(
<TouchableNativeFeedback>
<View />
</TouchableNativeFeedback>,
);

expect(instance.toJSON()).toMatchSnapshot();
});
});

describe('<TouchableNativeFeedback disabled={true}>', () => {
it('should be disabled when disabled is true', () => {
expect(
ReactTestRenderer.create(
<TouchableNativeFeedback disabled={true}>
<View />
</TouchableNativeFeedback>,
),
).toMatchSnapshot();
});
});

describe('<TouchableNativeFeedback disabled={true} accessibilityState={{}}>', () => {
it('should be disabled when disabled is true and accessibilityState is empty', () => {
expect(
ReactTestRenderer.create(
<TouchableNativeFeedback disabled={true} accessibilityState={{}}>
<View />
</TouchableNativeFeedback>,
),
).toMatchSnapshot();
});
});

describe('<TouchableNativeFeedback disabled={true} accessibilityState={{checked: true}}>', () => {
it('should keep accessibilityState when disabled is true', () => {
expect(
ReactTestRenderer.create(
<TouchableNativeFeedback
disabled={true}
accessibilityState={{checked: true}}>
<View />
</TouchableNativeFeedback>,
),
).toMatchSnapshot();
});
});

describe('<TouchableNativeFeedback disabled={true} accessibilityState={{disabled:false}}>', () => {
it('should overwrite accessibilityState with value of disabled prop', () => {
expect(
ReactTestRenderer.create(
<TouchableNativeFeedback
disabled={true}
accessibilityState={{disabled: false}}>
<View />
</TouchableNativeFeedback>,
),
).toMatchSnapshot();
});
});

describe('<TouchableNativeFeedback disabled={false} accessibilityState={{disabled:true}}>', () => {
it('should overwrite accessibilityState with value of disabled prop', () => {
expect(
ReactTestRenderer.create(
<TouchableNativeFeedback
disabled={false}
accessibilityState={{disabled: true}}>
<View />
</TouchableNativeFeedback>,
),
).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,113 @@ exports[`TouchableWithoutFeedback renders correctly 1`] = `
Touchable
</Text>
`;

exports[`<TouchableNativeFeedback /> should render as expected 1`] = `
<View
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
/>
`;

exports[`<TouchableNativeFeedback disabled={true}> should be disabled when disabled is true 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
/>
`;
exports[`<TouchableNativeFeedback disabled={true} accessibilityState={{}}> should be disabled when disabled is true and accessibilityState is empty 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
/>
`;
exports[`<TouchableNativeFeedback disabled={true} accessibilityState={{checked: true}}> should keep accessibilityState when disabled is true 1`] = `
<View
accessibilityState={
Object {
"checked": true,
"disabled": true,
}
}
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
/>
`;
exports[`<TouchableNativeFeedback disabled={true} accessibilityState={{disabled:false}}> should overwrite accessibilityState with value of disabled prop 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
/>
`;
exports[`<TouchableNativeFeedback disabled={false} accessibilityState={{disabled:true}}> should overwrite accessibilityState with value of disabled prop 1`] = `
<View
accessibilityState={
Object {
"disabled": false,
}
}
accessible={true}
focusable={false}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
/>
`;

0 comments on commit 88f2356

Please sign in to comment.