mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Added talkback support for TouchableNativeFeedback accessibility: disabled prop (#31224)
Summary: Issue https://github.com/facebook/react-native/issues/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: https://github.com/facebook/react-native/pull/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
This commit is contained in:
1 parent
cb028ee69c
commit
88f2356eed
3 files changed
+206
-5
No files matched your search
@@ -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,
|
||||
@@ -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,
|
||||
{
|
||||
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
+110
@@ -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]}
|
||||
/>
|
||||
`;
|
||||
Reference in new issue
Block a user