Skip to content

Commit 134fc2b

Browse files
ArnonZethanshar
authored andcommitted
Feat/accessibility phase 1 (#531)
* Adding accessibility to Avatar * Updated Avatar and Badge accessibility * Accessibility fixes * Small fixes to Avatar accessibility * Added accessibility support * Added accessibility to Switch * Checkbox accessibility * Checkbox accessibility * Switch accessibility * Small lint fix * Stepper accessibility support * Cosmetics * Avatar accessibility * Refactor * remove unnecessary prop type
1 parent 33d26ca commit 134fc2b

File tree

5 files changed

+86
-19
lines changed

5 files changed

+86
-19
lines changed

demo/src/screens/componentScreens/CheckboxScreen.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class CheckboxScreen extends Component {
88
value2: false,
99
value3: true,
1010
value4: true,
11-
value5: false,
11+
value5: false
1212
};
1313

1414
render() {

src/components/avatar/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,9 @@ export default class Avatar extends PureBaseComponent {
314314
style={[this.getContainerStyle(), containerStyle]}
315315
testID={testID}
316316
onPress={onPress}
317+
accessible
317318
accessibilityLabel={'Avatar'}
319+
accessibilityRole={onPress ? 'button' : 'image'}
318320
{...this.extractAccessibilityProps()}
319321
>
320322
<View

src/components/checkbox/index.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,24 @@ class Checkbox extends BaseComponent {
7373
}
7474

7575
componentDidUpdate(prevProps) {
76-
if (prevProps.value !== this.props.value) {
77-
this.animateCheckbox(this.props.value);
76+
const {value} = this.getThemeProps();
77+
if (prevProps.value !== value) {
78+
this.animateCheckbox(value);
7879
}
7980
}
8081

82+
getAccessibilityProps() {
83+
const {accessibilityLabel, disabled, value} = this.getThemeProps();
84+
const checkedState = value ? 'checked' : 'unchecked';
85+
86+
return {
87+
accessible: true,
88+
accessibilityLabel: accessibilityLabel ? `${accessibilityLabel} ${checkedState}` : `checkbox ${checkedState}`, //TODO: RN60 fix - label and role and convert to accessibilityActions
89+
accessibilityRole: 'button',
90+
accessibilityStates: disabled ? ['disabled'] : undefined
91+
};
92+
}
93+
8194
generateStyles() {
8295
this.styles = createStyles(this.getThemeProps());
8396
}
@@ -95,6 +108,7 @@ class Checkbox extends BaseComponent {
95108

96109
onPress = () => {
97110
const {disabled} = this.getThemeProps();
111+
98112
if (!disabled) {
99113
_.invoke(this.props, 'onValueChange', !this.props.value);
100114
}
@@ -114,12 +128,10 @@ class Checkbox extends BaseComponent {
114128
}
115129

116130
render() {
117-
const {value, selectedIcon, color, iconColor, disabled, testID, ...others} = this.getThemeProps();
118-
const accessibilityLabel = value ? 'checked' : 'unchecked';
119-
131+
const {selectedIcon, color, iconColor, disabled, testID, ...others} = this.getThemeProps();
120132
return (
121133
<TouchableOpacity
122-
accessibilityLabel={accessibilityLabel}
134+
{...this.getAccessibilityProps()}
123135
activeOpacity={1}
124136
testID={testID}
125137
{...others}

src/components/stepper/index.js

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1+
import _ from 'lodash';
12
import React from 'react';
2-
import {Text, View} from 'react-native';
3+
import {AccessibilityInfo, Text, View} from 'react-native';
34
import PropTypes from 'prop-types';
4-
import _ from 'lodash';
5-
import createStyles from './style';
6-
import {BaseComponent} from '../../commons';
75
import StepperButton from './StepperButton';
6+
import createStyles from './style';
7+
import {PureBaseComponent} from '../../commons';
88

99
/**
1010
* @description: Stepper component with increase and decrease buttons
1111
* @gif: https://media.giphy.com/media/3oFzm47bk0v4WV15O8/giphy.gif
1212
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/FormScreen.js
1313
*/
14-
export default class Stepper extends BaseComponent {
14+
export default class Stepper extends PureBaseComponent {
1515
static displayName = 'Stepper';
1616
static propTypes = {
1717
/**
@@ -48,6 +48,47 @@ export default class Stepper extends BaseComponent {
4848
};
4949
}
5050

51+
getAccessibilityProps() {
52+
const {value} = this.state;
53+
const {accessibilityLabel} = this.props;
54+
const labelSuffix = `value = ${value}`;
55+
return {
56+
accessibilityLabel: accessibilityLabel ? `${accessibilityLabel}, ${labelSuffix}` : `Stepper, ${labelSuffix}`,
57+
accessible: true,
58+
accessibilityRole: 'adjustable',
59+
accessibilityActions: ['decrement', 'increment'],
60+
onAccessibilityAction: this.onAccessibilityAction
61+
};
62+
}
63+
64+
onAccessibilityAction = event => {
65+
const {value} = this.state;
66+
const {min, max} = this.props;
67+
const eventMsgContext = event.nativeEvent.action === 'decrement' ? 'Minimum' : 'Maximum';
68+
const stepperLimitMsg = `${eventMsgContext} stepper value, ${value}, reached`;
69+
70+
switch (event.nativeEvent.action) {
71+
case 'decrement':
72+
if (value <= min) {
73+
AccessibilityInfo.announceForAccessibility(`${stepperLimitMsg}`);
74+
} else {
75+
this.updateValue(value - 1);
76+
AccessibilityInfo.announceForAccessibility(value - 1);
77+
}
78+
break;
79+
case 'increment':
80+
if (value >= max) {
81+
AccessibilityInfo.announceForAccessibility(`${stepperLimitMsg}`);
82+
} else {
83+
this.updateValue(value + 1);
84+
AccessibilityInfo.announceForAccessibility(value + 1);
85+
}
86+
break;
87+
default:
88+
break;
89+
}
90+
};
91+
5192
generateStyles() {
5293
this.styles = createStyles(this.props.size);
5394
}
@@ -80,7 +121,7 @@ export default class Stepper extends BaseComponent {
80121
render() {
81122
const {minusDisabled, plusDisabled, testID} = this.getDisabledState();
82123
return (
83-
<View style={[this.styles.container, this.props.containerStyle]}>
124+
<View {...this.getAccessibilityProps()} style={[this.styles.container, this.props.containerStyle]}>
84125
<View style={this.styles.title}>
85126
<Text testID={`${testID}.label`} style={this.styles.titleText}>
86127
{this.getLabel()}

src/components/switch/index.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,25 @@ class Switch extends BaseComponent {
7373
this.styles = createStyles(this.getThemeProps());
7474
}
7575

76-
UNSAFE_componentWillReceiveProps(nextProps) {
77-
if (this.props.value !== nextProps.value) {
78-
this.toggle(nextProps.value);
76+
componentDidUpdate(prevProps) {
77+
const {value} = this.getThemeProps();
78+
if (prevProps.value !== value) {
79+
this.toggle(value);
7980
}
8081
}
8182

83+
getAccessibilityProps() {
84+
const {accessibilityLabel, disabled, value} = this.getThemeProps();
85+
const switchState = value ? 'on' : 'off';
86+
87+
return {
88+
accessible: true,
89+
accessibilityLabel: accessibilityLabel ? `${accessibilityLabel} ${switchState}` : `switch ${switchState}`, //TODO: RN60 fix label and role and convert to accessibilityActions
90+
accessibilityRole: 'button',
91+
accessibilityStates: disabled ? ['disabled'] : undefined
92+
};
93+
}
94+
8295
toggle(value) {
8396
const {thumbPosition} = this.state;
8497

@@ -140,12 +153,11 @@ class Switch extends BaseComponent {
140153
}
141154

142155
render() {
143-
const {value, ...others} = this.getThemeProps();
144-
const accessibilityLabel = value ? 'switchOn' : 'switchOff';
156+
const {...others} = this.getThemeProps();
145157

146158
return (
147159
<TouchableOpacity
148-
accessibilityLabel={accessibilityLabel}
160+
{...this.getAccessibilityProps()}
149161
activeOpacity={1}
150162
{...others}
151163
style={this.getSwitchStyle()}

0 commit comments

Comments
 (0)