[change] Introduce focusable prop and remove deprecated props

* Adds "focusable" as a replacement for "accessible". This is aligned with RN for Windows.
* Remove "data-focusable" DOM attribute.
* Remove "importantForAccessibility" as this was previously deprecated.
* Remove undocumented "disabled" prop; replaced with "accessibilityDisabled"

Fix #1886
This commit is contained in:
Nicolas Gallagher
2021-02-05 11:51:10 -08:00
parent 956b4a3d74
commit abf00ef9b3
14 changed files with 83 additions and 169 deletions
@@ -4,7 +4,6 @@ exports[`components/Button prop "accessibilityLabel" 1`] = `
<div
aria-label="accessibility label"
class="css-cursor-18t94o4 css-view-1dbjc4n r-backgroundColor-14sbq61 r-borderRadius-1jkafct r-cursor-1loqt21 r-touchAction-1otgn73 r-transitionProperty-1i6wzkk r-userSelect-lrvibr"
data-focusable="true"
role="button"
style="transition-duration: 0s;"
tabindex="0"
@@ -19,7 +18,6 @@ exports[`components/Button prop "accessibilityLabel" 1`] = `
exports[`components/Button prop "color" 1`] = `
<div
class="css-cursor-18t94o4 css-view-1dbjc4n r-borderRadius-1jkafct r-cursor-1loqt21 r-touchAction-1otgn73 r-transitionProperty-1i6wzkk r-userSelect-lrvibr"
data-focusable="true"
role="button"
style="background-color: rgb(0, 0, 255); transition-duration: 0s;"
tabindex="0"
@@ -49,7 +47,6 @@ exports[`components/Button prop "disabled" 1`] = `
exports[`components/Button prop "testID" 1`] = `
<div
class="css-cursor-18t94o4 css-view-1dbjc4n r-backgroundColor-14sbq61 r-borderRadius-1jkafct r-cursor-1loqt21 r-touchAction-1otgn73 r-transitionProperty-1i6wzkk r-userSelect-lrvibr"
data-focusable="true"
data-testid="123"
role="button"
style="transition-duration: 0s;"
@@ -65,7 +62,6 @@ exports[`components/Button prop "testID" 1`] = `
exports[`components/Button prop "title" 1`] = `
<div
class="css-cursor-18t94o4 css-view-1dbjc4n r-backgroundColor-14sbq61 r-borderRadius-1jkafct r-cursor-1loqt21 r-touchAction-1otgn73 r-transitionProperty-1i6wzkk r-userSelect-lrvibr"
data-focusable="true"
role="button"
style="transition-duration: 0s;"
tabindex="0"
+1
View File
@@ -30,6 +30,7 @@ const Button = React.forwardRef<ButtonProps, *>((props, forwardedRef) => {
accessibilityLabel={accessibilityLabel}
accessibilityRole="button"
disabled={disabled}
focusable={!disabled}
onPress={onPress}
ref={forwardedRef}
style={[
@@ -10,7 +10,6 @@ exports[`CheckBox prop "accessibilityLabel" value is set 1`] = `
/>
<input
class="r-bottom-1p0dtai r-cursor-1ei5mc7 r-height-1pi2tsx r-left-1d2f490 r-margin-crgep1 r-opacity-orgf3d r-padding-t60dpp r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu"
data-focusable="true"
type="checkbox"
/>
</div>
@@ -27,7 +26,6 @@ exports[`CheckBox prop "color" value is set 1`] = `
<input
checked=""
class="r-bottom-1p0dtai r-cursor-1ei5mc7 r-height-1pi2tsx r-left-1d2f490 r-margin-crgep1 r-opacity-orgf3d r-padding-t60dpp r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu"
data-focusable="true"
type="checkbox"
/>
</div>
@@ -44,7 +42,6 @@ exports[`CheckBox prop "dataSet" value is set 1`] = `
/>
<input
class="r-bottom-1p0dtai r-cursor-1ei5mc7 r-height-1pi2tsx r-left-1d2f490 r-margin-crgep1 r-opacity-orgf3d r-padding-t60dpp r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu"
data-focusable="true"
type="checkbox"
/>
</div>
@@ -60,7 +57,6 @@ exports[`CheckBox prop "nativeID" value is set 1`] = `
/>
<input
class="r-bottom-1p0dtai r-cursor-1ei5mc7 r-height-1pi2tsx r-left-1d2f490 r-margin-crgep1 r-opacity-orgf3d r-padding-t60dpp r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu"
data-focusable="true"
type="checkbox"
/>
</div>
@@ -76,7 +72,6 @@ exports[`CheckBox prop "style" value is set 1`] = `
/>
<input
class="r-bottom-1p0dtai r-cursor-1ei5mc7 r-height-1pi2tsx r-left-1d2f490 r-margin-crgep1 r-opacity-orgf3d r-padding-t60dpp r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu"
data-focusable="true"
type="checkbox"
/>
</div>
@@ -92,7 +87,6 @@ exports[`CheckBox prop "testID" value is set 1`] = `
/>
<input
class="r-bottom-1p0dtai r-cursor-1ei5mc7 r-height-1pi2tsx r-left-1d2f490 r-margin-crgep1 r-opacity-orgf3d r-padding-t60dpp r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu"
data-focusable="true"
type="checkbox"
/>
</div>
+5 -1
View File
@@ -59,7 +59,11 @@ const CheckBox = forwardRef<CheckBoxProps, *>((props, forwardedRef) => {
});
return (
<View {...other} style={[styles.root, style, disabled && styles.cursorDefault]}>
<View
{...other}
accessibilityDisabled={disabled}
style={[styles.root, style, disabled && styles.cursorDefault]}
>
{fakeControl}
{nativeControl}
</View>
@@ -3,7 +3,6 @@
exports[`components/Pressable default 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
tabindex="0"
/>
`;
@@ -11,7 +10,6 @@ exports[`components/Pressable default 1`] = `
exports[`components/Pressable focus interaction 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
tabindex="0"
/>
`;
@@ -19,7 +17,6 @@ exports[`components/Pressable focus interaction 1`] = `
exports[`components/Pressable focus interaction 2`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
data-focusvisible-polyfill="true"
style="outline: focus-ring;"
tabindex="0"
@@ -33,7 +30,6 @@ exports[`components/Pressable focus interaction 2`] = `
exports[`components/Pressable focus interaction 3`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
style=""
tabindex="0"
/>
@@ -42,7 +38,6 @@ exports[`components/Pressable focus interaction 3`] = `
exports[`components/Pressable hover interaction 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
tabindex="0"
/>
`;
@@ -50,7 +45,6 @@ exports[`components/Pressable hover interaction 1`] = `
exports[`components/Pressable hover interaction 2`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
style="outline: hover-ring;"
tabindex="0"
>
@@ -63,7 +57,6 @@ exports[`components/Pressable hover interaction 2`] = `
exports[`components/Pressable hover interaction 3`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
style=""
tabindex="0"
/>
@@ -72,7 +65,6 @@ exports[`components/Pressable hover interaction 3`] = `
exports[`components/Pressable press interaction 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
tabindex="0"
/>
`;
@@ -80,7 +72,6 @@ exports[`components/Pressable press interaction 1`] = `
exports[`components/Pressable press interaction 2`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
style="outline: press-ring;"
tabindex="0"
>
@@ -93,7 +84,6 @@ exports[`components/Pressable press interaction 2`] = `
exports[`components/Pressable press interaction 3`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
style=""
tabindex="0"
/>
@@ -103,7 +93,6 @@ exports[`components/Pressable prop "accessibilityLabel" value is set 1`] = `
<div
aria-label="label"
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
tabindex="0"
/>
`;
@@ -112,7 +101,6 @@ exports[`components/Pressable prop "accessibilityLiveRegion" value is set 1`] =
<div
aria-live="polite"
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
tabindex="0"
/>
`;
@@ -120,7 +108,6 @@ exports[`components/Pressable prop "accessibilityLiveRegion" value is set 1`] =
exports[`components/Pressable prop "accessibilityRole" value alters HTML element 1`] = `
<a
class="css-reset-4rbku5 css-cursor-18t94o4 css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
role="link"
/>
`;
@@ -128,7 +115,6 @@ exports[`components/Pressable prop "accessibilityRole" value alters HTML element
exports[`components/Pressable prop "accessibilityRole" value is "button" 1`] = `
<div
class="css-cursor-18t94o4 css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
role="button"
tabindex="0"
/>
@@ -137,7 +123,6 @@ exports[`components/Pressable prop "accessibilityRole" value is "button" 1`] = `
exports[`components/Pressable prop "accessibilityRole" value is set 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
role="presentation"
tabindex="0"
/>
@@ -154,7 +139,6 @@ exports[`components/Pressable prop "disabled" 1`] = `
exports[`components/Pressable prop "nativeID" value is set 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
id="nativeID"
tabindex="0"
/>
@@ -163,7 +147,6 @@ exports[`components/Pressable prop "nativeID" value is set 1`] = `
exports[`components/Pressable prop "pointerEvents" 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-pointerEvents-ah5dr5 r-touchAction-1otgn73"
data-focusable="true"
tabindex="0"
/>
`;
@@ -171,7 +154,6 @@ exports[`components/Pressable prop "pointerEvents" 1`] = `
exports[`components/Pressable prop "style" value is set 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
style="border-top-width: 5px; border-right-width: 5px; border-bottom-width: 5px; border-left-width: 5px;"
tabindex="0"
/>
@@ -180,7 +162,6 @@ exports[`components/Pressable prop "style" value is set 1`] = `
exports[`components/Pressable prop "testID" value is set 1`] = `
<div
class="css-view-1dbjc4n r-cursor-1loqt21 r-touchAction-1otgn73"
data-focusable="true"
data-testid="123"
tabindex="0"
/>
+2 -5
View File
@@ -77,7 +77,6 @@ type Props = $ReadOnly<{|
*/
function Pressable(props: Props, forwardedRef): React.Node {
const {
accessible,
children,
delayLongPress,
delayPressIn,
@@ -134,7 +133,6 @@ function Pressable(props: Props, forwardedRef): React.Node {
useHover(hostRef, { contain: true, disabled, onHoverChange: setHovered });
const accessibilityState = { disabled, ...props.accessibilityState };
const interactionState = { hovered, focused, pressed };
function createFocusHandler(callback, value) {
@@ -152,9 +150,8 @@ function Pressable(props: Props, forwardedRef): React.Node {
<View
{...rest}
{...pressEventHandlers}
accessibilityState={accessibilityState}
accessible={accessible !== false}
focusable={focusable !== false}
accessibilityDisabled={disabled}
focusable={!disabled && focusable !== false}
onBlur={createFocusHandler(onBlur, false)}
onFocus={createFocusHandler(onFocus, true)}
ref={setRef}
@@ -45,7 +45,6 @@ exports[`components/Text prop "accessibilityLiveRegion" value is set 1`] = `
exports[`components/Text prop "accessibilityRole" value alters HTML element 1`] = `
<a
class="css-reset-4rbku5 css-cursor-18t94o4 css-text-901oao"
data-focusable="true"
dir="auto"
role="link"
/>
@@ -54,7 +53,6 @@ exports[`components/Text prop "accessibilityRole" value alters HTML element 1`]
exports[`components/Text prop "accessibilityRole" value is "button" 1`] = `
<div
class="css-cursor-18t94o4 css-text-901oao"
data-focusable="true"
dir="auto"
role="button"
tabindex="0"
@@ -71,7 +71,6 @@ function hasPressHandler(props): boolean {
*/
function TouchableHighlight(props: Props, forwardedRef): React.Node {
const {
accessible,
activeOpacity,
children,
delayPressIn,
@@ -166,12 +165,8 @@ function TouchableHighlight(props: Props, forwardedRef): React.Node {
<View
{...rest}
{...pressEventHandlers}
accessibilityState={{
disabled,
...props.accessibilityState
}}
accessible={accessible !== false}
focusable={focusable !== false && onPress !== undefined}
accessibilityDisabled={disabled}
focusable={!disabled && focusable !== false}
ref={setRef}
style={[
styles.root,
@@ -34,7 +34,6 @@ type Props = $ReadOnly<{|
*/
function TouchableOpacity(props: Props, forwardedRef): React.Node {
const {
accessible,
activeOpacity,
delayPressIn,
delayPressOut,
@@ -125,12 +124,8 @@ function TouchableOpacity(props: Props, forwardedRef): React.Node {
<View
{...rest}
{...pressEventHandlers}
accessibilityState={{
disabled,
...props.accessibilityState
}}
accessible={accessible !== false}
focusable={focusable !== false && onPress !== undefined}
accessibilityDisabled={disabled}
focusable={!disabled && focusable !== false}
ref={setRef}
style={[
styles.root,
@@ -46,16 +46,15 @@ export type Props = $ReadOnly<{|
|}>;
const forwardPropsList = {
accessibilityDisabled: true,
accessibilityLabel: true,
accessibilityLiveRegion: true,
accessibilityRole: true,
accessibilityState: true,
accessibilityValue: true,
accessible: true,
children: true,
disabled: true,
focusable: true,
importantForAccessibility: true,
nativeID: true,
onBlur: true,
onFocus: true,
@@ -67,7 +66,6 @@ const pickProps = props => pick(props, forwardPropsList);
function TouchableWithoutFeedback(props: Props, forwardedRef): React.Node {
const {
accessible,
delayPressIn,
delayPressOut,
delayLongPress,
@@ -112,9 +110,8 @@ function TouchableWithoutFeedback(props: Props, forwardedRef): React.Node {
const element = React.Children.only(props.children);
const children = [element.props.children];
const supportedProps = pickProps(props);
supportedProps.accessible = accessible !== false;
supportedProps.accessibilityState = { disabled, ...props.accessibilityState };
supportedProps.focusable = focusable !== false && onPress !== undefined;
supportedProps.accessibilityDisabled = disabled;
supportedProps.focusable = !disabled && focusable !== false;
supportedProps.ref = useMergeRefs(forwardedRef, hostRef, element.ref);
const elementProps = Object.assign(supportedProps, pressEventHandlers);
@@ -40,7 +40,6 @@ exports[`components/View prop "accessibilityLiveRegion" value is set 1`] = `
exports[`components/View prop "accessibilityRole" value alters HTML element 1`] = `
<a
class="css-reset-4rbku5 css-cursor-18t94o4 css-view-1dbjc4n"
data-focusable="true"
role="link"
/>
`;
@@ -48,7 +47,6 @@ exports[`components/View prop "accessibilityRole" value alters HTML element 1`]
exports[`components/View prop "accessibilityRole" value is "button" 1`] = `
<div
class="css-cursor-18t94o4 css-view-1dbjc4n"
data-focusable="true"
role="button"
tabindex="0"
/>
+2 -3
View File
@@ -23,16 +23,15 @@ import StyleSheet from '../StyleSheet';
import TextAncestorContext from '../Text/TextAncestorContext';
const forwardPropsList = {
accessibilityDisabled: true,
accessibilityLabel: true,
accessibilityLiveRegion: true,
accessibilityRole: true,
accessibilityState: true,
accessibilityValue: true,
accessible: true,
children: true,
classList: true,
disabled: true,
importantForAccessibility: true,
focusable: true,
nativeID: true,
onBlur: true,
onClick: true,
@@ -15,95 +15,65 @@ describe('modules/createDOMProps', () => {
test('default case', () => {
expect(createProps({ accessibilityRole })).toEqual(
expect.objectContaining({ 'data-focusable': true })
expect.not.objectContaining({ tabIndex: '-1' })
);
});
test('when "accessible" is true', () => {
expect(createProps({ accessibilityRole, accessible: true })).toEqual(
expect.objectContaining({ 'data-focusable': true })
test('when "focusable" is true', () => {
expect(createProps({ accessibilityRole, focusable: true })).toEqual(
expect.not.objectContaining({ tabIndex: '-1' })
);
});
test('when "accessible" is false', () => {
expect(createProps({ accessibilityRole, accessible: false })).toEqual(
expect.objectContaining({ tabIndex: '-1' })
test('when "focusable" is false', () => {
expect(createProps({ accessibilityRole, focusable: false })).toEqual(
expect.not.objectContaining({ tabIndex: '-1' })
);
});
test('when "disabled" is true', () => {
expect(createProps({ accessibilityRole, disabled: true })).toEqual(
expect.objectContaining({ 'aria-disabled': true, disabled: true, tabIndex: '-1' })
test('when "accessibilityDisabled" is true', () => {
expect(createProps({ accessibilityRole, accessibilityDisabled: true })).toEqual(
expect.objectContaining({ 'aria-disabled': true })
);
});
test('when "disabled" is false', () => {
expect(createProps({ accessibilityRole, disabled: false })).toEqual(
expect.objectContaining({ 'data-focusable': true })
expect(createProps({ accessibilityRole, accessibilityDisabled: false })).toEqual(
expect.not.objectContaining({ tabIndex: '-1' })
);
});
test('when "importantForAccessibility" is "no"', () => {
expect(createProps({ accessibilityRole, importantForAccessibility: 'no' })).toEqual(
expect.objectContaining({ tabIndex: '-1' })
);
});
test('when "importantForAccessibility" is "no-hide-descendants"', () => {
expect(
createProps({
accessibilityRole,
importantForAccessibility: 'no-hide-descendants'
})
).toEqual(expect.objectContaining({ tabIndex: '-1' }));
});
});
const testFocusableRole = accessibilityRole => {
test('default case', () => {
expect(createProps({ accessibilityRole })).toEqual(
expect.objectContaining({ 'data-focusable': true, tabIndex: '0' })
expect.objectContaining({ tabIndex: '0' })
);
});
test('when "accessible" is true', () => {
expect(createProps({ accessibilityRole, accessible: true })).toEqual(
expect.objectContaining({ 'data-focusable': true, tabIndex: '0' })
test('when "focusable" is true', () => {
expect(createProps({ accessibilityRole, focusable: true })).toEqual(
expect.objectContaining({ tabIndex: '0' })
);
});
test('when "accessible" is false', () => {
expect(createProps({ accessibilityRole, accessible: false })).not.toEqual(
expect.objectContaining({ 'data-focusable': true, tabIndex: '0' })
test('when "focusable" is false', () => {
expect(createProps({ accessibilityRole, focusable: false })).not.toEqual(
expect.objectContaining({ tabIndex: '0' })
);
});
test('when "disabled" is true', () => {
expect(createProps({ accessibilityRole, disabled: true })).toEqual(
test('when "accessibilityDisabled" is true', () => {
expect(createProps({ accessibilityRole, accessibilityDisabled: true })).toEqual(
expect.objectContaining({ 'aria-disabled': true, disabled: true })
);
});
test('when "disabled" is false', () => {
expect(createProps({ accessibilityRole, disabled: false })).toEqual(
expect.objectContaining({ 'data-focusable': true, tabIndex: '0' })
test('when "accessibilityDisabled" is false', () => {
expect(createProps({ accessibilityRole, accessibilityDisabled: false })).toEqual(
expect.objectContaining({ tabIndex: '0' })
);
});
test('when "importantForAccessibility" is "no"', () => {
expect(createProps({ accessibilityRole, importantForAccessibility: 'no' })).not.toEqual(
expect.objectContaining({ 'data-focusable': true, tabIndex: '0' })
);
});
test('when "importantForAccessibility" is "no-hide-descendants"', () => {
expect(
createProps({
accessibilityRole,
importantForAccessibility: 'no-hide-descendants'
})
).not.toEqual(expect.objectContaining({ 'data-focusable': true, tabIndex: '0' }));
});
};
describe('"accessibilityRole" of "button"', () => {
@@ -115,36 +85,27 @@ describe('modules/createDOMProps', () => {
});
describe('with unfocusable accessibilityRole', () => {
test('when "accessible" is true', () => {
expect(createProps({ accessible: true })).toEqual(
expect.objectContaining({ 'data-focusable': true, tabIndex: '0' })
test('when "focusable" is true', () => {
expect(createProps({ focusable: true })).toEqual(
expect.objectContaining({ tabIndex: '0' })
);
});
test('when "accessible" is false', () => {
expect(createProps({ accessible: false })).toEqual({});
});
test('when "importantForAccessibility" is "no"', () => {
expect(createProps({ importantForAccessibility: 'no' })).toEqual({});
expect(createProps({ accessible: true, importantForAccessibility: 'no' })).not.toEqual(
expect.objectContaining({ 'data-focusable': true, tabIndex: '0' })
);
});
test('when "importantForAccessibility" is "no-hide-descendants"', () => {
expect(
createProps({ accessible: true, importantForAccessibility: 'no-hide-descendants' })
).not.toEqual(expect.objectContaining({ 'data-focusable': true, tabIndex: '0' }));
test('when "focusable" is false', () => {
expect(createProps({ focusable: false })).toEqual({});
});
});
});
describe('prop "onClick"', () => {
const callsOnClick = (component, accessibilityRole, disabled = false) => {
const callsOnClick = (component, accessibilityRole, accessibilityDisabled = false) => {
const onClick = jest.fn();
const event = { stopPropagation: jest.fn() };
const finalProps = createDOMProps(component, { accessibilityRole, disabled, onClick });
const finalProps = createDOMProps(component, {
accessibilityRole,
accessibilityDisabled,
onClick
});
finalProps.onClick(event);
return onClick.mock.calls.length === 1;
};
@@ -180,13 +141,13 @@ describe('modules/createDOMProps', () => {
});
describe('prop "onKeyDown"', () => {
const callsOnClick = key => (component, accessibilityRole, disabled = false) => {
const callsOnClick = key => (component, accessibilityRole, accessibilityDisabled = false) => {
const onClick = jest.fn();
const onKeyDown = jest.fn();
const event = { key, preventDefault: jest.fn() };
const finalProps = createDOMProps(component, {
accessibilityRole,
disabled,
accessibilityDisabled,
onClick,
onKeyDown
});
@@ -236,8 +197,8 @@ describe('modules/createDOMProps', () => {
const onClick = jest.fn();
const event = { key: 'Enter', preventDefault: jest.fn() };
const finalProps = createDOMProps('div', {
accessible: true,
accessibilityRole: 'article',
focusable: true,
onClick
});
finalProps.onKeyDown(event);
@@ -313,11 +274,6 @@ describe('modules/createDOMProps', () => {
expect(props.className).toEqual(className);
});
test('prop "importantForAccessibility" becomes "aria-hidden"', () => {
const props = createProps({ importantForAccessibility: 'no-hide-descendants' });
expect(props['aria-hidden']).toEqual(true);
});
test('prop "nativeID" becomes "id"', () => {
const nativeID = 'Example.nativeID';
const props = createProps({ nativeID });
+28 -25
View File
@@ -56,15 +56,14 @@ const createDOMProps = (component, props) => {
}
const {
accessibilityDisabled,
accessibilityLabel,
accessibilityLiveRegion,
accessibilityState,
accessibilityValue,
accessible,
classList,
dataSet,
disabled: providedDisabled,
importantForAccessibility,
focusable,
nativeID,
pointerEvents,
style: providedStyle,
@@ -76,7 +75,7 @@ const createDOMProps = (component, props) => {
} = props;
const disabled =
(accessibilityState != null && accessibilityState.disabled === true) || providedDisabled;
(accessibilityState != null && accessibilityState.disabled === true) || accessibilityDisabled;
const role = AccessibilityUtil.propsToAriaRole(props);
const isNativeInteractiveElement =
role === 'link' ||
@@ -142,36 +141,40 @@ const createDOMProps = (component, props) => {
}
}
// legacy fallbacks
if (importantForAccessibility === 'no-hide-descendants') {
domProps['aria-hidden'] = true;
}
if (disabled === true) {
domProps['aria-disabled'] = true;
domProps.disabled = true;
}
// FOCUS
// Assume that 'link' is focusable by default (uses <a>).
// Assume that 'button' is not (uses <div role='button'>) but must be treated as such.
const focusable =
!disabled &&
importantForAccessibility !== 'no' &&
importantForAccessibility !== 'no-hide-descendants';
if (isNativeInteractiveElement) {
if (accessible === false || !focusable) {
// "focusable" indicates that an element may be a keyboard tab-stop.
if (
// These native elements are focusable by default
component === 'a' ||
component === 'button' ||
component === 'input' ||
component === 'select' ||
component === 'textarea'
) {
if (focusable === false || accessibilityDisabled === true) {
domProps.tabIndex = '-1';
} else {
domProps['data-focusable'] = true;
}
} else if (role === 'button' || role === 'menuitem' || role === 'textbox') {
if (accessible !== false && focusable) {
domProps['data-focusable'] = true;
} else if (
// These roles are made focusable by default
role === 'button' ||
role === 'checkbox' ||
role === 'link' ||
role === 'menuitem' ||
role === 'radio' ||
role === 'textbox' ||
role === 'switch'
) {
if (focusable !== false) {
domProps.tabIndex = '0';
}
} else {
if (accessible === true && focusable) {
domProps['data-focusable'] = true;
// Everything else must explicitly set the prop
if (focusable === true) {
domProps.tabIndex = '0';
}
}
@@ -222,11 +225,11 @@ const createDOMProps = (component, props) => {
isNativeInteractiveElement ||
role === 'button' ||
role === 'menuitem' ||
(accessible === true && focusable)
(focusable === true && !accessibilityDisabled)
) {
const onClick = domProps.onClick;
if (onClick != null) {
if (disabled) {
if (accessibilityDisabled) {
// Prevent click propagating if the element is disabled. See #1757
domProps.onClick = function(e) {
e.stopPropagation();