Skip to content

Commit 91007ce

Browse files
committed
fix(accessibility): Derive accessibilityTraits from role and state (#57515)
1 parent 9160010 commit 91007ce

2 files changed

Lines changed: 41 additions & 33 deletions

File tree

packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -472,18 +472,6 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
472472
RCTUIAccessibilityTraitsFromAccessibilityTraits(newViewProps.accessibilityTraits);
473473
}
474474

475-
// `accessibilityState`
476-
if (oldViewProps.accessibilityState != newViewProps.accessibilityState) {
477-
self.accessibilityTraits &= ~(UIAccessibilityTraitNotEnabled | UIAccessibilityTraitSelected);
478-
const auto accessibilityState = newViewProps.accessibilityState.value_or(AccessibilityState{});
479-
if (accessibilityState.selected) {
480-
self.accessibilityTraits |= UIAccessibilityTraitSelected;
481-
}
482-
if (accessibilityState.disabled) {
483-
self.accessibilityTraits |= UIAccessibilityTraitNotEnabled;
484-
}
485-
}
486-
487475
// `accessibilityIgnoresInvertColors`
488476
if (oldViewProps.accessibilityIgnoresInvertColors != newViewProps.accessibilityIgnoresInvertColors) {
489477
self.accessibilityIgnoresInvertColors = newViewProps.accessibilityIgnoresInvertColors;

packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,31 @@
1414

1515
namespace facebook::react {
1616

17+
// Derive accessibilityTraits from the resolved role and accessibilityState
18+
// members. This makes accessibilityTraits the single source of truth.
19+
// See: github.com/facebook/react-native/issues/57515
20+
static AccessibilityTraits deriveAccessibilityTraits(
21+
Role role,
22+
const std::string& accessibilityRole,
23+
const std::optional<AccessibilityState>& accessibilityState) {
24+
AccessibilityTraits traits = AccessibilityTraits::None;
25+
if (role != Role::None) {
26+
fromString(toString(role), traits);
27+
} else if (!accessibilityRole.empty()) {
28+
fromString(accessibilityRole, traits);
29+
}
30+
31+
const auto state = accessibilityState.value_or(AccessibilityState{});
32+
if (state.selected) {
33+
traits = traits | AccessibilityTraits::Selected;
34+
}
35+
if (state.disabled) {
36+
traits = traits | AccessibilityTraits::NotEnabled;
37+
}
38+
39+
return traits;
40+
}
41+
1742
AccessibilityProps::AccessibilityProps(
1843
const PropsParserContext& context,
1944
const AccessibilityProps& sourceProps,
@@ -146,19 +171,9 @@ AccessibilityProps::AccessibilityProps(
146171
ImportantForAccessibility::Auto)),
147172
testId(
148173
convertRawProp(context, rawProps, "testID", sourceProps.testId, "")) {
149-
// It is a (severe!) perf deoptimization to request props out-of-order.
150-
// Thus, since we need to request the same prop twice here
151-
// (accessibilityRole) we "must" do them subsequently here to prevent
152-
// a regression. It is reasonable to ask if the `at` function can be improved;
153-
// it probably can, but this is a fairly rare edge-case that (1) is easy-ish
154-
// to work around here, and (2) would require very careful work to address
155-
// this case and not regress the more common cases.
156174
auto* accessibilityRoleValue = rawProps.at("accessibilityRole");
157175
auto* roleValue = rawProps.at("role");
158176

159-
auto* precedentRoleValue =
160-
roleValue != nullptr ? roleValue : accessibilityRoleValue;
161-
162177
if (accessibilityRoleValue == nullptr ||
163178
!accessibilityRoleValue->hasValue()) {
164179
accessibilityRole = sourceProps.accessibilityRole;
@@ -172,11 +187,8 @@ AccessibilityProps::AccessibilityProps(
172187
fromRawValue(context, *roleValue, role);
173188
}
174189

175-
if (precedentRoleValue == nullptr || !precedentRoleValue->hasValue()) {
176-
accessibilityTraits = sourceProps.accessibilityTraits;
177-
} else {
178-
fromRawValue(context, *precedentRoleValue, accessibilityTraits);
179-
}
190+
accessibilityTraits =
191+
deriveAccessibilityTraits(role, accessibilityRole, accessibilityState);
180192
}
181193

182194
void AccessibilityProps::setProp(
@@ -188,7 +200,12 @@ void AccessibilityProps::setProp(
188200

189201
switch (hash) {
190202
RAW_SET_PROP_SWITCH_CASE_BASIC(accessible);
191-
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityState);
203+
case CONSTEXPR_RAW_PROPS_KEY_HASH("accessibilityState"): {
204+
fromRawValue(context, value, accessibilityState, defaults.accessibilityState);
205+
accessibilityTraits =
206+
deriveAccessibilityTraits(role, accessibilityRole, accessibilityState);
207+
return;
208+
}
192209
RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLabel);
193210
RAW_SET_PROP_SWITCH_CASE(
194211
accessibilityOrder, "experimental_accessibilityOrder");
@@ -209,18 +226,21 @@ void AccessibilityProps::setProp(
209226
RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityEscape);
210227
RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityAction);
211228
RAW_SET_PROP_SWITCH_CASE_BASIC(importantForAccessibility);
212-
RAW_SET_PROP_SWITCH_CASE_BASIC(role);
229+
case CONSTEXPR_RAW_PROPS_KEY_HASH("role"): {
230+
fromRawValue(context, value, role, defaults.role);
231+
accessibilityTraits =
232+
deriveAccessibilityTraits(role, accessibilityRole, accessibilityState);
233+
return;
234+
}
213235
RAW_SET_PROP_SWITCH_CASE(testId, "testID");
214236
case CONSTEXPR_RAW_PROPS_KEY_HASH("accessibilityRole"): {
215-
AccessibilityTraits traits = AccessibilityTraits::None;
216237
std::string roleString;
217238
if (value.hasValue()) {
218-
fromRawValue(context, value, traits);
219239
fromRawValue(context, value, roleString);
220240
}
221-
222-
accessibilityTraits = traits;
223241
accessibilityRole = roleString;
242+
accessibilityTraits =
243+
deriveAccessibilityTraits(role, accessibilityRole, accessibilityState);
224244
return;
225245
}
226246
}

0 commit comments

Comments
 (0)