Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RNMobile] Accessibility updates for StepperCell and RangeCell #29741

Merged
merged 23 commits into from
Mar 18, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c52fafc
Add unit label to stepper cell
AmandaRiu Mar 10, 2021
ad43397
Pass unitLabel and unitPicker
AmandaRiu Mar 10, 2021
6e6a070
Update access. label and add new access. action to open picker
AmandaRiu Mar 10, 2021
a466390
Make more access. by using access. actions instead of forcing focus
AmandaRiu Mar 10, 2021
5e4e473
Change step value to match current implementation
AmandaRiu Mar 10, 2021
3942b9f
Add some code comments to clarify when methods are used
AmandaRiu Mar 10, 2021
6b6cc42
Update accessibility labels and hints for android support as well
AmandaRiu Mar 11, 2021
54a45c7
Prevent stepper buttons from getting TalkBack focus
AmandaRiu Mar 11, 2021
0a07e2a
Found a better way to control this and didn’t want to negatively effe…
AmandaRiu Mar 11, 2021
ef5d043
This change make it possible for TalkBack to treat the `StepperCell` …
AmandaRiu Mar 11, 2021
d35e818
Fix step to match incremenent value
AmandaRiu Mar 11, 2021
60f6993
Remove unused code
AmandaRiu Mar 12, 2021
f038db4
Ensure changes made are properly saved
AmandaRiu Mar 12, 2021
ee2e18c
Rename methods to make accessibility-only use clear
AmandaRiu Mar 12, 2021
c4d3a7c
Clean up code
AmandaRiu Mar 12, 2021
9bb29de
Replace hard-coded a11y labels with dynamic logic
AmandaRiu Mar 12, 2021
2793ca7
Add optional settingLabel property
AmandaRiu Mar 12, 2021
ef76f0d
Add changelog notes
AmandaRiu Mar 12, 2021
7046b53
Merge branch 'trunk' into rnmobile/29359-ios-bottome-cell-accessibility
AmandaRiu Mar 12, 2021
0b4ff3f
Update event handler names for clarity
AmandaRiu Mar 18, 2021
a492565
Simplify accessibility hint
AmandaRiu Mar 18, 2021
32a3b5d
Remove unused accessibility roles
AmandaRiu Mar 18, 2021
4727add
Apply i18n on size labels
AmandaRiu Mar 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
246 changes: 159 additions & 87 deletions packages/components/src/mobile/bottom-sheet/range-cell.native.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
/**
* External dependencies
*/
import {
Platform,
AccessibilityInfo,
findNodeHandle,
View,
} from 'react-native';
import { Platform, AccessibilityInfo, View } from 'react-native';
import Slider from '@react-native-community/slider';

/**
Expand All @@ -31,7 +26,8 @@ class BottomSheetRangeCell extends Component {
super( props );
this.onChangeValue = this.onChangeValue.bind( this );
this.onChange = this.onChange.bind( this );
this.onCellPress = this.onCellPress.bind( this );
this.onIncrementValue = this.onIncrementValue.bind( this );
this.onDecrementValue = this.onDecrementValue.bind( this );

const { value, defaultValue, minimumValue } = props;
const initialValue = Number( value || defaultValue || minimumValue );
Expand All @@ -43,28 +39,17 @@ class BottomSheetRangeCell extends Component {
};
}

componentWillUnmount() {
clearTimeout( this.timeoutAnnounceValue );
}

onChangeValue( initialValue ) {
const { decimalNum, onChange } = this.props;
initialValue = toFixed( initialValue, decimalNum );
this.setState( { inputValue: initialValue } );
this.announceCurrentValue( `${ initialValue }` );
onChange( initialValue );
}

onCellPress() {
this.setState( { accessible: false } );
if ( this.sliderRef ) {
const reactTag = findNodeHandle( this.sliderRef );
AccessibilityInfo.setAccessibilityFocus( reactTag );
}
}

announceCurrentValue( value ) {
/* translators: %s: current cell value. */
const announcement = sprintf( __( 'Current value is %s' ), value );
AccessibilityInfo.announceForAccessibility( announcement );
}

onChange( nextValue ) {
dcalhoun marked this conversation as resolved.
Show resolved Hide resolved
const { onChange, onComplete } = this.props;
this.setState( {
Expand All @@ -76,6 +61,62 @@ class BottomSheetRangeCell extends Component {
}
}

/*
* Only used with screenreaders like VoiceOver and TalkBack. Increments the
* value of this setting programmatically.
*/
onIncrementValue() {
const { step = 10, maximumValue, decimalNum } = this.props;
const { sliderValue } = this.state;

const newValue = toFixed( sliderValue + step, decimalNum );

if ( newValue <= maximumValue || maximumValue === undefined ) {
this.onChangeValue( newValue );
this.setState( {
sliderValue: newValue,
} );
this.announceValue( newValue );
}
}

/*
* Only used with screenreaders like VoiceOver and TalkBack. Decrements the
* value of this setting programmatically.
*/
onDecrementValue() {
const { step = 10, minimumValue, decimalNum } = this.props;
const { sliderValue } = this.state;

const newValue = toFixed( sliderValue - step, decimalNum );

if ( newValue >= minimumValue ) {
this.onChangeValue( newValue );
this.setState( {
sliderValue: newValue,
} );
this.announceValue( newValue );
}
}

/*
* Only used with screenreaders like VoiceOver and TalkBack.
*/
announceValue( value ) {
const { label, unitLabel = '' } = this.props;

if ( Platform.OS === 'ios' ) {
// On Android it triggers the accessibilityLabel with the value change, but
// on iOS we need to do this manually.
clearTimeout( this.timeoutAnnounceValue );
this.timeoutAnnounceValue = setTimeout( () => {
AccessibilityInfo.announceForAccessibility(
`${ value } ${ unitLabel }, ${ label }`
);
}, 300 );
}
}

render() {
const {
value,
Expand All @@ -94,87 +135,118 @@ class BottomSheetRangeCell extends Component {
cellContainerStyle,
onComplete,
shouldDisplayTextInput = true,
unitLabel = '',
openUnitPicker,
children,
decimalNum,
...cellProps
} = this.props;

const { accessible, inputValue, sliderValue } = this.state;

const accessibilityLabel = sprintf(
/* translators: accessibility text. Inform about current value. %1$s: Control label %2$s: Current value. */
_x(
'%1$s. Current value is %2$s',
'Slider for picking a number inside a range'
),
cellProps.label,
value
);
const { inputValue, sliderValue } = this.state;

const accessibilityLabel = openUnitPicker
? sprintf(
/* translators: accessibility text. Inform about current value. %1$s: Control label %2$s: Current value. %3$s: value measurement unit (example: pixels) */
_x(
'%1$s. Current value is %2$s %3$s. Swipe up or down to adjust, double-tap to change unit',
'Slider for picking a number inside a range'
),
cellProps.label,
value,
unitLabel
)
: sprintf(
/* translators: accessibility text. Inform about current value. %1$s: Control label %2$s: Current value. %3$s: value measurement unit (example: pixels) */
_x(
'%1$s. Current value is %2$s %3$s. Swipe up or down to adjust',
'Slider for picking a number inside a range'
),
cellProps.label,
value,
unitLabel
);

const containerStyle = [
styles.container,
isIOS ? styles.containerIOS : styles.containerAndroid,
];

return (
<Cell
{ ...cellProps }
cellContainerStyle={ [
styles.cellContainerStyles,
cellContainerStyle,
<View
accessible={ true }
accessibilityRole="adjustable"
accessibilityActions={ [
{ name: 'increment' },
{ name: 'decrement' },
{ name: 'activate' },
] }
cellRowContainerStyle={ containerStyle }
accessibilityRole={ 'none' }
leftAlign
editable={ false }
activeOpacity={ 1 }
accessible={ accessible }
onPress={ this.onCellPress }
valueStyle={ styles.valueStyle }
onAccessibilityAction={ ( event ) => {
switch ( event.nativeEvent.actionName ) {
case 'increment':
this.onIncrementValue();
break;
case 'decrement':
this.onDecrementValue();
break;
case 'activate':
openUnitPicker();
break;
}
} }
accessibilityLabel={ accessibilityLabel }
accessibilityHint={
/* translators: accessibility text (hint for focusing a slider) */
__( 'Double tap to change the value using slider' )
}
>
<View style={ containerStyle }>
{ preview }
<Slider
value={ sliderValue }
defaultValue={ defaultValue }
disabled={ disabled }
step={ step }
minimumValue={ minimumValue }
maximumValue={ maximumValue }
minimumTrackTintColor={ minimumTrackTintColor }
maximumTrackTintColor={ maximumTrackTintColor }
thumbTintColor={ thumbTintColor }
onValueChange={ this.onChangeValue }
onSlidingComplete={ onComplete }
ref={ ( slider ) => {
this.sliderRef = slider;
} }
style={
isIOS ? styles.sliderIOS : styles.sliderAndroid
}
accessibilityRole={ 'adjustable' }
/>
{ shouldDisplayTextInput && (
<RangeTextInput
label={ cellProps.label }
onChange={ this.onChange }
defaultValue={ `${ inputValue }` }
value={ inputValue }
min={ minimumValue }
max={ maximumValue }
<Cell
{ ...cellProps }
cellContainerStyle={ [
styles.cellContainerStyles,
cellContainerStyle,
] }
cellRowContainerStyle={ containerStyle }
accessibilityRole={ 'adjustable' }
leftAlign
editable={ false }
activeOpacity={ 1 }
accessible={ false }
valueStyle={ styles.valueStyle }
>
<View style={ containerStyle }>
{ preview }
<Slider
value={ sliderValue }
defaultValue={ defaultValue }
disabled={ disabled }
step={ step }
decimalNum={ decimalNum }
>
{ children }
</RangeTextInput>
) }
</View>
</Cell>
minimumValue={ minimumValue }
maximumValue={ maximumValue }
minimumTrackTintColor={ minimumTrackTintColor }
maximumTrackTintColor={ maximumTrackTintColor }
thumbTintColor={ thumbTintColor }
onValueChange={ this.onChangeValue }
onSlidingComplete={ onComplete }
ref={ ( slider ) => {
this.sliderRef = slider;
} }
style={
isIOS ? styles.sliderIOS : styles.sliderAndroid
}
/>
{ shouldDisplayTextInput && (
<RangeTextInput
label={ cellProps.label }
onChange={ this.onChange }
defaultValue={ `${ inputValue }` }
value={ inputValue }
min={ minimumValue }
max={ maximumValue }
step={ step }
decimalNum={ decimalNum }
>
{ children }
</RangeTextInput>
) }
</View>
</Cell>
</View>
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ class BottomSheetStepperCell extends Component {
}

announceValue( value ) {
const { label } = this.props;
const { label, unitLabel = '' } = this.props;

if ( Platform.OS === 'ios' ) {
// On Android it triggers the accessibilityLabel with the value change
clearTimeout( this.timeoutAnnounceValue );
this.timeoutAnnounceValue = setTimeout( () => {
AccessibilityInfo.announceForAccessibility(
`${ value } ${ label }`
`${ value } ${ unitLabel } ${ label }`
);
}, 300 );
}
Expand All @@ -130,6 +130,7 @@ class BottomSheetStepperCell extends Component {
render() {
const {
label,
unitLabel = '',
icon,
min,
max,
Expand All @@ -139,6 +140,7 @@ class BottomSheetStepperCell extends Component {
shouldDisplayTextInput = false,
preview,
onChange,
openUnitPicker,
decimalNum,
cellContainerStyle,
} = this.props;
Expand All @@ -149,12 +151,26 @@ class BottomSheetStepperCell extends Component {
styles.cellLabel,
! icon ? styles.cellLabelNoIcon : {},
];
const accessibilityLabel = sprintf(
/* translators: accessibility text. Inform about current value. %1$s: Control label %2$s: Current value. */
__( '%1$s. Current value is %2$s' ),
label,
value
);
const accessibilityLabel = openUnitPicker
? sprintf(
/* translators: accessibility text. Inform about current value. %1$s: Control label %2$s: Current value. %3$s: value measurement unit (example: pixels) */
__(
'%1$s. Current value is %2$s %3$s. Swipe up or down to adjust, double-tap to change unit'
),
label,
value,
unitLabel
)
: sprintf(
/* translators: accessibility text. Inform about current value. %1$s: Control label %2$s: Current value. %3$s: value measurement unit (example: pixels) */
__(
'%1$s. Current value is %2$s %3$s. Swipe up or down to adjust'
),
label,
value,
unitLabel
);

const containerStyle = [
styles.rowContainer,
isIOS ? styles.containerIOS : styles.containerAndroid,
Expand All @@ -168,6 +184,7 @@ class BottomSheetStepperCell extends Component {
accessibilityActions={ [
{ name: 'increment' },
{ name: 'decrement' },
{ name: 'activate' },
] }
onAccessibilityAction={ ( event ) => {
switch ( event.nativeEvent.actionName ) {
Expand All @@ -177,6 +194,11 @@ class BottomSheetStepperCell extends Component {
case 'decrement':
this.onDecrementValue();
break;
case 'activate':
if ( openUnitPicker ) {
openUnitPicker();
}
break;
}
} }
>
Expand Down