Skip to content

Commit

Permalink
Fix disabled prop not disabling onPress for voice assistant
Browse files Browse the repository at this point in the history
Summary:
It is currently possible to activate a disabled Pressable with VoiceOver/TalkBack. This fixes this.

Changelog:
[General][Fixed] Fix disabled prop not disabling onPress for voice assistant

Reviewed By: blavalla

Differential Revision: D26225448

fbshipit-source-id: 67fa10f9e5c50143d986dc709a2fb639fdc3e718
  • Loading branch information
kacieb authored and facebook-github-bot committed Feb 8, 2021
1 parent 35b6d2e commit 1c7d9c8
Show file tree
Hide file tree
Showing 4 changed files with 352 additions and 2 deletions.
6 changes: 6 additions & 0 deletions Libraries/Components/Pressable/Pressable.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,16 @@ function Pressable(props: Props, forwardedRef): React.Node {

const hitSlop = normalizeRect(props.hitSlop);

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

const restPropsWithDefaults: React.ElementConfig<typeof View> = {
...restProps,
...android_rippleConfig?.viewProps,
accessible: accessible !== false,
accessibilityState,
focusable: focusable !== false,
hitSlop,
};
Expand Down
64 changes: 64 additions & 0 deletions Libraries/Components/Pressable/__tests__/Pressable-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,67 @@ describe('<Pressable />', () => {
);
});
});

describe('<Pressable disabled={true} />', () => {
it('should be disabled when disabled is true', () => {
expectRendersMatchingSnapshot(
'Pressable',
() => (
<Pressable disabled={true}>
<View />
</Pressable>
),
() => {
jest.dontMock('../Pressable');
},
);
});
});

describe('<Pressable disabled={true} accessibilityState={{}} />', () => {
it('should be disabled when disabled is true and accessibilityState is empty', () => {
expectRendersMatchingSnapshot(
'Pressable',
() => (
<Pressable disabled={true} accessibilityState={{}}>
<View />
</Pressable>
),
() => {
jest.dontMock('../Pressable');
},
);
});
});

describe('<Pressable disabled={true} accessibilityState={{checked: true}} />', () => {
it('should keep accessibilityState when disabled is true', () => {
expectRendersMatchingSnapshot(
'Pressable',
() => (
<Pressable disabled={true} accessibilityState={{checked: true}}>
<View />
</Pressable>
),
() => {
jest.dontMock('../Pressable');
},
);
});
});

describe('<Pressable disabled={true} accessibilityState={{disabled: false}} />', () => {
it('should overwrite accessibilityState with value of disabled prop', () => {
expectRendersMatchingSnapshot(
'Pressable',
() => (
<Pressable disabled={true} accessibilityState={{disabled: false}}>
<View />
</Pressable>
),
() => {
jest.dontMock('../Pressable');
},
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,283 @@ exports[`<Pressable /> should render as expected: should shallow render as <Pres
<View />
</Memo(Pressable)>
`;

exports[`<Pressable disabled={true} /> should be disabled when disabled is true: should deep render when mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
collapsable={false}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View />
</View>
`;

exports[`<Pressable disabled={true} /> should be disabled when disabled is true: should deep render when not mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
collapsable={false}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View />
</View>
`;

exports[`<Pressable disabled={true} /> should be disabled when disabled is true: should shallow render as <Pressable /> when mocked 1`] = `
<Memo(Pressable)
disabled={true}
>
<View />
</Memo(Pressable)>
`;

exports[`<Pressable disabled={true} /> should be disabled when disabled is true: should shallow render as <Pressable /> when not mocked 1`] = `
<Memo(Pressable)
disabled={true}
>
<View />
</Memo(Pressable)>
`;

exports[`<Pressable disabled={true} accessibilityState={{}} /> should be disabled when disabled is true and accessibilityState is empty: should deep render when mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
collapsable={false}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View />
</View>
`;

exports[`<Pressable disabled={true} accessibilityState={{}} /> should be disabled when disabled is true and accessibilityState is empty: should deep render when not mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
collapsable={false}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View />
</View>
`;

exports[`<Pressable disabled={true} accessibilityState={{}} /> should be disabled when disabled is true and accessibilityState is empty: should shallow render as <Pressable /> when mocked 1`] = `
<Memo(Pressable)
accessibilityState={Object {}}
disabled={true}
>
<View />
</Memo(Pressable)>
`;

exports[`<Pressable disabled={true} accessibilityState={{}} /> should be disabled when disabled is true and accessibilityState is empty: should shallow render as <Pressable /> when not mocked 1`] = `
<Memo(Pressable)
accessibilityState={Object {}}
disabled={true}
>
<View />
</Memo(Pressable)>
`;

exports[`<Pressable disabled={true} accessibilityState={{checked: true}} /> should keep accessibilityState when disabled is true: should deep render when mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"checked": true,
"disabled": true,
}
}
accessible={true}
collapsable={false}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View />
</View>
`;

exports[`<Pressable disabled={true} accessibilityState={{checked: true}} /> should keep accessibilityState when disabled is true: should deep render when not mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"checked": true,
"disabled": true,
}
}
accessible={true}
collapsable={false}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View />
</View>
`;

exports[`<Pressable disabled={true} accessibilityState={{checked: true}} /> should keep accessibilityState when disabled is true: should shallow render as <Pressable /> when mocked 1`] = `
<Memo(Pressable)
accessibilityState={
Object {
"checked": true,
}
}
disabled={true}
>
<View />
</Memo(Pressable)>
`;

exports[`<Pressable disabled={true} accessibilityState={{checked: true}} /> should keep accessibilityState when disabled is true: should shallow render as <Pressable /> when not mocked 1`] = `
<Memo(Pressable)
accessibilityState={
Object {
"checked": true,
}
}
disabled={true}
>
<View />
</Memo(Pressable)>
`;

exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> should overwrite accessibilityState with value of disabled prop: should deep render when mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
collapsable={false}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View />
</View>
`;

exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> should overwrite accessibilityState with value of disabled prop: should deep render when not mocked (please verify output manually) 1`] = `
<View
accessibilityState={
Object {
"disabled": true,
}
}
accessible={true}
collapsable={false}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
<View />
</View>
`;

exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> should overwrite accessibilityState with value of disabled prop: should shallow render as <Pressable /> when mocked 1`] = `
<Memo(Pressable)
accessibilityState={
Object {
"disabled": false,
}
}
disabled={true}
>
<View />
</Memo(Pressable)>
`;

exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> should overwrite accessibilityState with value of disabled prop: should shallow render as <Pressable /> when not mocked 1`] = `
<Memo(Pressable)
accessibilityState={
Object {
"disabled": false,
}
}
disabled={true}
>
<View />
</Memo(Pressable)>
`;
4 changes: 2 additions & 2 deletions Libraries/Pressability/Pressability.js
Original file line number Diff line number Diff line change
Expand Up @@ -543,8 +543,8 @@ export default class Pressability {
},

onClick: (event: PressEvent): void => {
const {onPress} = this._config;
if (onPress != null) {
const {onPress, disabled} = this._config;
if (onPress != null && disabled !== true) {
onPress(event);
}
},
Expand Down

0 comments on commit 1c7d9c8

Please sign in to comment.