Skip to content

Commit f9819c7

Browse files
javachemeta-codesync[bot]
authored andcommitted
Delegate TouchableNativeFeedback accessibility to its child (#59391)
Summary: Pull Request resolved: #59391 Forward unconsumed view props to the native-feedback child and let `View` normalise accessibility aliases. Preserve child styling and retain legacy alias resolution for non-View children without synthesising empty state or value props. Changelog: [General][Fixed] - Forward accessibility props consistently in TouchableNativeFeedback while preserving child styles. Differential Revision: D126907218
1 parent 7c9668e commit f9819c7

2 files changed

Lines changed: 308 additions & 65 deletions

File tree

‎packages/react-native/Libraries/Components/Touchable/TouchableNativeFeedback.js‎

Lines changed: 99 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -275,81 +275,115 @@ class TouchableNativeFeedback extends React.Component<
275275
const {onBlur, onFocus, ...eventHandlersWithoutBlurAndFocus} =
276276
this.state.pressability.getEventHandlers();
277277

278-
let _accessibilityState = {
279-
busy: this.props['aria-busy'] ?? this.props.accessibilityState?.busy,
280-
checked:
281-
this.props['aria-checked'] ?? this.props.accessibilityState?.checked,
282-
disabled:
283-
this.props['aria-disabled'] ?? this.props.accessibilityState?.disabled,
284-
expanded:
285-
this.props['aria-expanded'] ?? this.props.accessibilityState?.expanded,
286-
selected:
287-
this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
288-
};
278+
const {
279+
accessible,
280+
background,
281+
children: childrenProp,
282+
delayLongPress,
283+
delayPressIn,
284+
delayPressOut,
285+
disabled,
286+
focusable,
287+
onBlur: _onBlur,
288+
onFocus: _onFocus,
289+
onLongPress,
290+
onPress,
291+
onPressIn,
292+
onPressOut,
293+
pressRetentionOffset,
294+
rejectResponderTermination,
295+
style: _style,
296+
touchSoundDisabled,
297+
useForeground,
298+
...restProps
299+
} = this.props;
289300

290-
_accessibilityState =
291-
this.props.disabled != null
292-
? {
293-
..._accessibilityState,
294-
disabled: this.props.disabled,
295-
}
296-
: _accessibilityState;
297-
298-
const accessibilityValue = {
299-
max: this.props['aria-valuemax'] ?? this.props.accessibilityValue?.max,
300-
min: this.props['aria-valuemin'] ?? this.props.accessibilityValue?.min,
301-
now: this.props['aria-valuenow'] ?? this.props.accessibilityValue?.now,
302-
text: this.props['aria-valuetext'] ?? this.props.accessibilityValue?.text,
303-
};
301+
const pressabilityConfig = this._createPressabilityConfig();
302+
if (pressabilityConfig.disabled != null) {
303+
// Expose Pressability's resolved disabled state to accessibility through View.
304+
restProps['aria-disabled'] = pressabilityConfig.disabled;
305+
}
304306

305-
const accessibilityLiveRegion =
306-
this.props['aria-live'] === 'off'
307-
? 'none'
308-
: (this.props['aria-live'] ?? this.props.accessibilityLiveRegion);
307+
if (element.type !== View) {
308+
const accessibilityLabel =
309+
this.props['aria-label'] ?? this.props.accessibilityLabel;
310+
if (accessibilityLabel != null) {
311+
restProps.accessibilityLabel = accessibilityLabel;
312+
}
313+
const nativeID = this.props.id ?? this.props.nativeID;
314+
if (nativeID != null) {
315+
restProps.nativeID = nativeID;
316+
}
317+
const ariaHidden = this.props['aria-hidden'];
318+
if (ariaHidden != null) {
319+
restProps.accessibilityElementsHidden = ariaHidden;
320+
if (ariaHidden === true) {
321+
restProps.importantForAccessibility = 'no-hide-descendants';
322+
}
323+
}
324+
325+
const state = this.props.accessibilityState;
326+
const busy = this.props['aria-busy'] ?? state?.busy;
327+
const checked = this.props['aria-checked'] ?? state?.checked;
328+
const disabledState = restProps['aria-disabled'] ?? state?.disabled;
329+
const expanded = this.props['aria-expanded'] ?? state?.expanded;
330+
const selected = this.props['aria-selected'] ?? state?.selected;
331+
if (
332+
busy != null ||
333+
checked != null ||
334+
disabledState != null ||
335+
expanded != null ||
336+
selected != null
337+
) {
338+
restProps.accessibilityState = {
339+
busy,
340+
checked,
341+
disabled: disabledState,
342+
expanded,
343+
selected,
344+
};
345+
}
346+
347+
const ariaLive = this.props['aria-live'];
348+
if (ariaLive !== undefined) {
349+
restProps.accessibilityLiveRegion =
350+
ariaLive === 'off' ? 'none' : ariaLive;
351+
}
352+
if (this.props['aria-modal'] !== undefined) {
353+
restProps.accessibilityViewIsModal = this.props['aria-modal'];
354+
}
355+
if (
356+
this.props['aria-valuemax'] != null ||
357+
this.props['aria-valuemin'] != null ||
358+
this.props['aria-valuenow'] != null ||
359+
this.props['aria-valuetext'] != null
360+
) {
361+
restProps.accessibilityValue = {
362+
max:
363+
this.props['aria-valuemax'] ?? this.props.accessibilityValue?.max,
364+
min:
365+
this.props['aria-valuemin'] ?? this.props.accessibilityValue?.min,
366+
now:
367+
this.props['aria-valuenow'] ?? this.props.accessibilityValue?.now,
368+
text:
369+
this.props['aria-valuetext'] ?? this.props.accessibilityValue?.text,
370+
};
371+
}
372+
}
309373

310-
const accessibilityLabel =
311-
this.props['aria-label'] ?? this.props.accessibilityLabel;
312374
return cloneElement(
313375
element,
314376
{
377+
...restProps,
315378
...eventHandlersWithoutBlurAndFocus,
316379
...getBackgroundProp(
317-
this.props.background === undefined
380+
background === undefined
318381
? TouchableNativeFeedback.SelectableBackground()
319-
: this.props.background,
320-
this.props.useForeground === true,
382+
: background,
383+
useForeground === true,
321384
),
322-
accessible: this.props.accessible !== false,
323-
accessibilityHint: this.props.accessibilityHint,
324-
accessibilityLanguage: this.props.accessibilityLanguage,
325-
accessibilityLabel: accessibilityLabel,
326-
accessibilityRole: this.props.accessibilityRole,
327-
accessibilityState: _accessibilityState,
328-
accessibilityActions: this.props.accessibilityActions,
329-
onAccessibilityAction: this.props.onAccessibilityAction,
330-
accessibilityValue: accessibilityValue,
331-
importantForAccessibility:
332-
this.props['aria-hidden'] === true
333-
? 'no-hide-descendants'
334-
: this.props.importantForAccessibility,
335-
accessibilityViewIsModal:
336-
this.props['aria-modal'] ?? this.props.accessibilityViewIsModal,
337-
accessibilityLiveRegion: accessibilityLiveRegion,
338-
accessibilityElementsHidden:
339-
this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden,
340-
hitSlop: this.props.hitSlop,
341-
focusable:
342-
this.props.focusable !== false &&
343-
this.props.onPress !== undefined &&
344-
!this.props.disabled,
345-
nativeID: this.props.id ?? this.props.nativeID,
346-
nextFocusDown: this.props.nextFocusDown,
347-
nextFocusForward: this.props.nextFocusForward,
348-
nextFocusLeft: this.props.nextFocusLeft,
349-
nextFocusRight: this.props.nextFocusRight,
350-
nextFocusUp: this.props.nextFocusUp,
351-
onLayout: this.props.onLayout,
352-
testID: this.props.testID,
385+
accessible: accessible !== false,
386+
focusable: focusable !== false && onPress !== undefined && !disabled,
353387
},
354388
...children,
355389
);

0 commit comments

Comments
 (0)