Repository navigation
fix(View): do not flatten a view whose accessibility props a container uses - #59817
faciledictu wants to merge 2 commits into
Conversation
…r uses Keep the view when iOS or Android reads one of its accessibility props from a container: label, role, state, actions, escape, magic tap, Large Content Viewer and ignoresInvertColors, as react#59335 did for accessibilityLiveRegion.
| const auto& state = viewProps.accessibilityState; | ||
| bool hasState = state.has_value() && | ||
| (state->disabled || state->selected.has_value() || | ||
| state->expanded.has_value() || | ||
| state->checked == AccessibilityState::Checked || | ||
| state->checked == AccessibilityState::Unchecked); |
There was a problem hiding this comment.
Can you add a helper on AccessibilityState instead? eg isMeaningful?
There was a problem hiding this comment.
Done, added AccessibilityState::isMeaningful(). It leaves out busy and mixed on purpose: on Android they go into the content description and replace the children's text (#59856).
| viewProps.isolation == Isolation::Isolate || | ||
| HostPlatformViewTraitsInitializer::formsStackingContext(viewProps) || | ||
| !viewProps.accessibilityOrder.empty(); | ||
| !viewProps.accessibilityOrder.empty() || hasContainerAccessibilityProps(); |
There was a problem hiding this comment.
Do these require a stacking context (parent-child structure is retained, or would formsView be sufficient`?
There was a problem hiding this comment.
They need the children inside. With formsView alone (I checked with a backgroundColor on the same views) the view is kept but its children are mounted next to it, and each case behaves as if it were flattened: the label inside a Pressable reads "Close dialog, ×", the tabbar and the parent's actions don't reach the tabs and the child, and on Android the labelled view is an empty node next to the text. Section 14 in https://github.com/faciledictu/rn-a11y-flattening-repro.
Summary:
Fixes #59816.
ViewShadowNode::initializekeeps a host view for only a few accessibility props (accessible,accessibilityViewIsModal,accessibilityLiveRegionand three more). iOS and Android also read several others from a view that is not an accessibility element, and they are lost when the view is flattened:accessibilityLabel: TalkBack reads it from the container; an accessible ancestor builds its label from its subviews.accessibilityRole/roleandaccessibilityState: the TabBar trait on iOS; heading, checkable and the state on Android.accessibilityActions,onAccessibilityEscape,onAccessibilityMagicTap: iOS passes them to the elements inside or sends them up the hierarchy.accessibilityShowsLargeContentViewer,accessibilityIgnoresInvertColors: they apply to the subviews on iOS.This change keeps the view when any of them is set, as #59335 did for
accessibilityLiveRegion. The old architecture kept these views too.Left out on purpose:
accessibilityHint,accessibilityLanguageandaccessibilityValue, which are not read from a container, andaria-busy/aria-checked="mixed": on Android they go intocontentDescriptionand replace the children's text (a separate bug), so a kept view would be read as "busy".Changelog:
[GENERAL] [FIXED] - A
ViewwithaccessibilityLabel,role,accessibilityState,accessibilityActions,onAccessibilityEscapeor another accessibility prop read from a container is no longer flattenedTest Plan:
View-itest.js): thedoes not unflatten viewtests foraccessibilityLabel,accessibilityRoleandaccessibilityActionsasserted the bug and are nowunflattens view(theaccessibilityActionsone also checked the wrong prop). Added:roleandaria-checkedunflatten,aria-busyandaria-checked="mixed"do not. The iOS-only props are not in the view config Fantom uses. The rest of the suite passes, except 9LogBoxInspector*snapshot tests that fail the same way onmain(93019c4).collapsable={false}control (the results without the change are in Fabric flattens a View whose accessibility props iOS and Android read from a container: label, role, state, actions, escape #59816):