mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-23 14:57:13 +00:00
[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:
-4
@@ -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"
|
||||
|
||||
@@ -30,6 +30,7 @@ const Button = React.forwardRef<ButtonProps, *>((props, forwardedRef) => {
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
accessibilityRole="button"
|
||||
disabled={disabled}
|
||||
focusable={!disabled}
|
||||
onPress={onPress}
|
||||
ref={forwardedRef}
|
||||
style={[
|
||||
|
||||
-6
@@ -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
@@ -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>
|
||||
|
||||
-19
@@ -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"
|
||||
/>
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
+38
-82
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user