diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index ecfe8bc408f..97feafc4c10 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -17,6 +17,7 @@ #import #import #import +#import #ifdef RCT_DYNAMIC_FRAMEWORKS #import @@ -722,7 +723,8 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view) } NSMutableArray *valueComponents = [NSMutableArray new]; - NSString *roleString = [NSString stringWithUTF8String:props.accessibilityRole.c_str()]; + NSString *roleString = (props.role != Role::None) ? [NSString stringWithUTF8String:toString(props.role).c_str()] + : [NSString stringWithUTF8String:props.accessibilityRole.c_str()]; // In iOS, checkbox and radio buttons aren't recognized as traits. However, // because our apps use checkbox and radio buttons often, we should announce diff --git a/packages/react-native/React/Views/RCTView.m b/packages/react-native/React/Views/RCTView.m index fc678c2577a..66c6c5978f8 100644 --- a/packages/react-native/React/Views/RCTView.m +++ b/packages/react-native/React/Views/RCTView.m @@ -332,7 +332,11 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused) } } NSMutableArray *valueComponents = [NSMutableArray new]; - NSString *roleDescription = self.accessibilityRole ? rolesAndStatesDescription[self.accessibilityRole] : nil; + + // TODO: This logic makes VoiceOver describe some AccessibilityRole which do not have a backing UIAccessibilityTrait. + // It does not run on Fabric. + NSString *role = self.role ?: self.accessibilityRole; + NSString *roleDescription = role ? rolesAndStatesDescription[role] : nil; if (roleDescription) { [valueComponents addObject:roleDescription]; } diff --git a/packages/react-native/React/Views/RCTViewManager.m b/packages/react-native/React/Views/RCTViewManager.m index 2b8f2c0a33a..9a0af4e74ce 100644 --- a/packages/react-native/React/Views/RCTViewManager.m +++ b/packages/react-native/React/Views/RCTViewManager.m @@ -26,54 +26,97 @@ RCT_MULTI_ENUM_CONVERTER( UIAccessibilityTraits, (@{ - @"none" : @(UIAccessibilityTraitNone), + @"adjustable" : @(UIAccessibilityTraitAdjustable), + @"alert" : @(UIAccessibilityTraitNone), + @"alertdialog" : @(UIAccessibilityTraitNone), + @"allowsDirectInteraction" : @(UIAccessibilityTraitAllowsDirectInteraction), + @"application" : @(UIAccessibilityTraitNone), + @"article" : @(UIAccessibilityTraitNone), + @"banner" : @(UIAccessibilityTraitNone), @"button" : @(UIAccessibilityTraitButton), + @"cell" : @(UIAccessibilityTraitNone), + @"checkbox" : @(UIAccessibilityTraitNone), + @"columnheader" : @(UIAccessibilityTraitNone), + @"combobox" : @(UIAccessibilityTraitNone), + @"complementary" : @(UIAccessibilityTraitNone), + @"contentinfo" : @(UIAccessibilityTraitNone), + @"definition" : @(UIAccessibilityTraitNone), + @"dialog" : @(UIAccessibilityTraitNone), + @"directory" : @(UIAccessibilityTraitNone), + @"disabled" : @(UIAccessibilityTraitNotEnabled), + @"document" : @(UIAccessibilityTraitNone), + @"drawerlayout" : @(UIAccessibilityTraitNone), @"dropdownlist" : @(UIAccessibilityTraitNone), - @"togglebutton" : @(UIAccessibilityTraitButton), - @"link" : @(UIAccessibilityTraitLink), + @"feed" : @(UIAccessibilityTraitNone), + @"figure" : @(UIAccessibilityTraitNone), + @"form" : @(UIAccessibilityTraitNone), + @"frequentUpdates" : @(UIAccessibilityTraitUpdatesFrequently), + @"grid" : @(UIAccessibilityTraitNone), + @"group" : @(UIAccessibilityTraitNone), @"header" : @(UIAccessibilityTraitHeader), - @"search" : @(UIAccessibilityTraitSearchField), + @"heading" : @(UIAccessibilityTraitHeader), + @"horizontalscrollview" : @(UIAccessibilityTraitNone), + @"iconmenu" : @(UIAccessibilityTraitNone), @"image" : @(UIAccessibilityTraitImage), @"imagebutton" : @(UIAccessibilityTraitImage | UIAccessibilityTraitButton), - @"selected" : @(UIAccessibilityTraitSelected), - @"plays" : @(UIAccessibilityTraitPlaysSound), + @"img" : @(UIAccessibilityTraitImage), @"key" : @(UIAccessibilityTraitKeyboardKey), @"keyboardkey" : @(UIAccessibilityTraitKeyboardKey), - @"text" : @(UIAccessibilityTraitStaticText), - @"summary" : @(UIAccessibilityTraitSummaryElement), - @"disabled" : @(UIAccessibilityTraitNotEnabled), - @"frequentUpdates" : @(UIAccessibilityTraitUpdatesFrequently), - @"startsMedia" : @(UIAccessibilityTraitStartsMediaSession), - @"adjustable" : @(UIAccessibilityTraitAdjustable), - @"allowsDirectInteraction" : @(UIAccessibilityTraitAllowsDirectInteraction), - @"pageTurn" : @(UIAccessibilityTraitCausesPageTurn), - @"alert" : @(UIAccessibilityTraitNone), - @"checkbox" : @(UIAccessibilityTraitNone), - @"combobox" : @(UIAccessibilityTraitNone), + @"link" : @(UIAccessibilityTraitLink), + @"list" : @(UIAccessibilityTraitNone), + @"listitem" : @(UIAccessibilityTraitNone), + @"log" : @(UIAccessibilityTraitNone), + @"main" : @(UIAccessibilityTraitNone), + @"marquee" : @(UIAccessibilityTraitNone), + @"math" : @(UIAccessibilityTraitNone), @"menu" : @(UIAccessibilityTraitNone), @"menubar" : @(UIAccessibilityTraitNone), @"menuitem" : @(UIAccessibilityTraitNone), + @"meter" : @(UIAccessibilityTraitNone), + @"navigation" : @(UIAccessibilityTraitNone), + @"none" : @(UIAccessibilityTraitNone), + @"note" : @(UIAccessibilityTraitNone), + @"option" : @(UIAccessibilityTraitNone), + @"pager" : @(UIAccessibilityTraitNone), + @"pageTurn" : @(UIAccessibilityTraitCausesPageTurn), + @"plays" : @(UIAccessibilityTraitPlaysSound), + @"presentation" : @(UIAccessibilityTraitNone), @"progressbar" : @(UIAccessibilityTraitUpdatesFrequently), @"radio" : @(UIAccessibilityTraitNone), @"radiogroup" : @(UIAccessibilityTraitNone), + @"region" : @(UIAccessibilityTraitNone), + @"row" : @(UIAccessibilityTraitNone), + @"rowgroup" : @(UIAccessibilityTraitNone), + @"rowheader" : @(UIAccessibilityTraitNone), @"scrollbar" : @(UIAccessibilityTraitNone), + @"scrollview" : @(UIAccessibilityTraitNone), + @"search" : @(UIAccessibilityTraitSearchField), + @"searchbox" : @(UIAccessibilityTraitNone), + @"selected" : @(UIAccessibilityTraitSelected), + @"separator" : @(UIAccessibilityTraitNone), + @"slider" : @(UIAccessibilityTraitNone), + @"slidingdrawer" : @(UIAccessibilityTraitNone), @"spinbutton" : @(UIAccessibilityTraitNone), + @"startsMedia" : @(UIAccessibilityTraitStartsMediaSession), + @"status" : @(UIAccessibilityTraitNone), + @"summary" : @(UIAccessibilityTraitSummaryElement), @"switch" : @(SwitchAccessibilityTrait), @"tab" : @(UIAccessibilityTraitNone), @"tabbar" : @(UIAccessibilityTraitTabBar), + @"table" : @(UIAccessibilityTraitNone), @"tablist" : @(UIAccessibilityTraitNone), + @"tabpanel" : @(UIAccessibilityTraitNone), + @"term" : @(UIAccessibilityTraitNone), + @"text" : @(UIAccessibilityTraitStaticText), @"timer" : @(UIAccessibilityTraitNone), + @"togglebutton" : @(UIAccessibilityTraitButton), @"toolbar" : @(UIAccessibilityTraitNone), - @"pager" : @(UIAccessibilityTraitNone), - @"scrollview" : @(UIAccessibilityTraitNone), - @"horizontalscrollview" : @(UIAccessibilityTraitNone), + @"tooltip" : @(UIAccessibilityTraitNone), + @"tree" : @(UIAccessibilityTraitNone), + @"treegrid" : @(UIAccessibilityTraitNone), + @"treeitem" : @(UIAccessibilityTraitNone), @"viewgroup" : @(UIAccessibilityTraitNone), @"webview" : @(UIAccessibilityTraitNone), - @"drawerlayout" : @(UIAccessibilityTraitNone), - @"slidingdrawer" : @(UIAccessibilityTraitNone), - @"iconmenu" : @(UIAccessibilityTraitNone), - @"list" : @(UIAccessibilityTraitNone), - @"grid" : @(UIAccessibilityTraitNone), }), UIAccessibilityTraitNone, unsignedLongLongValue) @@ -182,22 +225,41 @@ RCT_CUSTOM_VIEW_PROPERTY(transform, CATransform3D, RCTView) } RCT_CUSTOM_VIEW_PROPERTY(accessibilityRole, UIAccessibilityTraits, RCTView) +{ + UIAccessibilityTraits accessibilityRoleTraits = + json ? [RCTConvert UIAccessibilityTraits:json] : UIAccessibilityTraitNone; + if (view.reactAccessibilityElement.accessibilityRoleTraits != accessibilityRoleTraits) { + view.accessibilityRoleTraits = accessibilityRoleTraits; + view.reactAccessibilityElement.accessibilityRole = json ? [RCTConvert NSString:json] : nil; + [self updateAccessibilityTraitsForRole:view withDefaultView:defaultView]; + } +} + +RCT_CUSTOM_VIEW_PROPERTY(role, UIAccessibilityTraits, RCTView) +{ + UIAccessibilityTraits roleTraits = json ? [RCTConvert UIAccessibilityTraits:json] : UIAccessibilityTraitNone; + if (view.reactAccessibilityElement.roleTraits != roleTraits) { + view.roleTraits = roleTraits; + view.reactAccessibilityElement.role = json ? [RCTConvert NSString:json] : nil; + [self updateAccessibilityTraitsForRole:view withDefaultView:defaultView]; + } +} + +- (void)updateAccessibilityTraitsForRole:(RCTView *)view withDefaultView:(RCTView *)defaultView { const UIAccessibilityTraits AccessibilityRolesMask = UIAccessibilityTraitNone | UIAccessibilityTraitButton | UIAccessibilityTraitLink | UIAccessibilityTraitSearchField | UIAccessibilityTraitImage | UIAccessibilityTraitKeyboardKey | UIAccessibilityTraitStaticText | UIAccessibilityTraitAdjustable | UIAccessibilityTraitHeader | UIAccessibilityTraitSummaryElement | UIAccessibilityTraitTabBar | UIAccessibilityTraitUpdatesFrequently | SwitchAccessibilityTrait; - view.reactAccessibilityElement.accessibilityTraits = - view.reactAccessibilityElement.accessibilityTraits & ~AccessibilityRolesMask; - UIAccessibilityTraits newTraits = json ? [RCTConvert UIAccessibilityTraits:json] : defaultView.accessibilityTraits; - if (newTraits != UIAccessibilityTraitNone) { - UIAccessibilityTraits maskedTraits = newTraits & AccessibilityRolesMask; - view.reactAccessibilityElement.accessibilityTraits |= maskedTraits; - } else { - NSString *role = json ? [RCTConvert NSString:json] : @""; - view.reactAccessibilityElement.accessibilityRole = role; - } + + // Clear any existing traits set for AccessibilityRole + view.reactAccessibilityElement.accessibilityTraits &= ~(AccessibilityRolesMask); + + view.reactAccessibilityElement.accessibilityTraits |= view.reactAccessibilityElement.role + ? view.reactAccessibilityElement.roleTraits + : view.reactAccessibilityElement.accessibilityRole ? view.reactAccessibilityElement.accessibilityRoleTraits + : (defaultView.accessibilityTraits & AccessibilityRolesMask); } RCT_CUSTOM_VIEW_PROPERTY(accessibilityState, NSDictionary, RCTView) diff --git a/packages/react-native/React/Views/UIView+React.h b/packages/react-native/React/Views/UIView+React.h index 21a70337d7a..d378a8320ba 100644 --- a/packages/react-native/React/Views/UIView+React.h +++ b/packages/react-native/React/Views/UIView+React.h @@ -117,10 +117,13 @@ * Accessibility properties */ @property (nonatomic, copy) NSString *accessibilityRole; +@property (nonatomic, copy) NSString *role; @property (nonatomic, copy) NSDictionary *accessibilityState; @property (nonatomic, copy) NSArray *accessibilityActions; @property (nonatomic, copy) NSDictionary *accessibilityValueInternal; @property (nonatomic, copy) NSString *accessibilityLanguage; +@property (nonatomic) UIAccessibilityTraits accessibilityRoleTraits; +@property (nonatomic) UIAccessibilityTraits roleTraits; /** * Used in debugging to get a description of the view hierarchy rooted at diff --git a/packages/react-native/React/Views/UIView+React.m b/packages/react-native/React/Views/UIView+React.m index 94ad951e717..7c6c71829ff 100644 --- a/packages/react-native/React/Views/UIView+React.m +++ b/packages/react-native/React/Views/UIView+React.m @@ -336,6 +336,16 @@ objc_setAssociatedObject(self, @selector(accessibilityRole), accessibilityRole, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } +- (NSString *)role +{ + return objc_getAssociatedObject(self, _cmd); +} + +- (void)setRole:(NSString *)role +{ + objc_setAssociatedObject(self, @selector(role), role, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + - (NSDictionary *)accessibilityState { return objc_getAssociatedObject(self, _cmd); @@ -356,6 +366,33 @@ self, @selector(accessibilityValueInternal), accessibilityValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } +- (UIAccessibilityTraits)accessibilityRoleTraits +{ + NSNumber *traitsAsNumber = objc_getAssociatedObject(self, _cmd); + return traitsAsNumber ? [traitsAsNumber unsignedLongLongValue] : UIAccessibilityTraitNone; +} + +- (void)setAccessibilityRoleTraits:(UIAccessibilityTraits)accessibilityRoleTraits +{ + objc_setAssociatedObject( + self, + @selector(accessibilityRoleTraits), + [NSNumber numberWithUnsignedLongLong:accessibilityRoleTraits], + OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIAccessibilityTraits)roleTraits +{ + NSNumber *traitsAsNumber = objc_getAssociatedObject(self, _cmd); + return traitsAsNumber ? [traitsAsNumber unsignedLongLongValue] : UIAccessibilityTraitNone; +} + +- (void)setRoleTraits:(UIAccessibilityTraits)roleTraits +{ + objc_setAssociatedObject( + self, @selector(roleTraits), [NSNumber numberWithUnsignedLongLong:roleTraits], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + #pragma mark - Debug - (void)react_addRecursiveDescriptionToString:(NSMutableString *)string atLevel:(NSUInteger)level { diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp index ad6cf1ce83d..d9ebf62e9b5 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp @@ -171,14 +171,6 @@ AccessibilityProps::AccessibilityProps( "importantForAccessibility", sourceProps.importantForAccessibility, ImportantForAccessibility::Auto)), - role( - CoreFeatures::enablePropIteratorSetter ? sourceProps.role - : convertRawProp( - context, - rawProps, - "role", - sourceProps.role, - {})), testId( CoreFeatures::enablePropIteratorSetter ? sourceProps.testId : convertRawProp( @@ -195,19 +187,31 @@ AccessibilityProps::AccessibilityProps( // to work around here, and (2) would require very careful work to address // this case and not regress the more common cases. if (!CoreFeatures::enablePropIteratorSetter) { - const auto *rawPropValue = + auto *accessibilityRoleValue = rawProps.at("accessibilityRole", nullptr, nullptr); - AccessibilityTraits traits; - std::string roleString; - if (rawPropValue == nullptr || !rawPropValue->hasValue()) { - traits = sourceProps.accessibilityTraits; - roleString = sourceProps.accessibilityRole; + auto *roleValue = rawProps.at("role", nullptr, nullptr); + + auto *precedentRoleValue = + roleValue != nullptr ? roleValue : accessibilityRoleValue; + + if (accessibilityRoleValue == nullptr || + !accessibilityRoleValue->hasValue()) { + accessibilityRole = sourceProps.accessibilityRole; } else { - fromRawValue(context, *rawPropValue, traits); - fromRawValue(context, *rawPropValue, roleString); + fromRawValue(context, *accessibilityRoleValue, accessibilityRole); + } + + if (roleValue == nullptr || !roleValue->hasValue()) { + role = sourceProps.role; + } else { + fromRawValue(context, *roleValue, role); + } + + if (precedentRoleValue == nullptr || !precedentRoleValue->hasValue()) { + accessibilityTraits = sourceProps.accessibilityTraits; + } else { + fromRawValue(context, *precedentRoleValue, accessibilityTraits); } - accessibilityTraits = traits; - accessibilityRole = roleString; } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/accessibilityPropsConversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/accessibilityPropsConversions.h index 9ee16674181..1690113e239 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/accessibilityPropsConversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/accessibilityPropsConversions.h @@ -30,7 +30,7 @@ inline void fromString(const std::string &string, AccessibilityTraits &result) { result = AccessibilityTraits::Link; return; } - if (string == "image") { + if (string == "image" || string == "img") { result = AccessibilityTraits::Image; return; } @@ -78,7 +78,7 @@ inline void fromString(const std::string &string, AccessibilityTraits &result) { result = AccessibilityTraits::CausesPageTurn; return; } - if (string == "header") { + if (string == "header" || string == "heading") { result = AccessibilityTraits::Header; return; } diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h index b09fd7115eb..fe0adae88f4 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h @@ -15,6 +15,8 @@ NS_ASSUME_NONNULL_BEGIN NSString *const RCTAttributedStringIsHighlightedAttributeName = @"IsHighlighted"; NSString *const RCTAttributedStringEventEmitterKey = @"EventEmitter"; + +// String representation of either `role` or `accessibilityRole` NSString *const RCTTextAttributesAccessibilityRoleAttributeName = @"AccessibilityRole"; /* diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm index 68388d1c839..7db4677a329 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm @@ -7,6 +7,7 @@ #import "RCTAttributedTextUtils.h" +#include #include #include #include @@ -288,130 +289,12 @@ NSDictionary *RCTNSTextAttributesFromTextAttributes(T attributes[RCTAttributedStringIsHighlightedAttributeName] = @YES; } - if (textAttributes.accessibilityRole.has_value()) { - auto accessibilityRole = textAttributes.accessibilityRole.value(); - switch (accessibilityRole) { - case AccessibilityRole::None: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("none"); - break; - case AccessibilityRole::Button: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("button"); - break; - case AccessibilityRole::Dropdownlist: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("dropdownlist"); - break; - case AccessibilityRole::Togglebutton: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("togglebutton"); - break; - case AccessibilityRole::Link: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("link"); - break; - case AccessibilityRole::Search: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("search"); - break; - case AccessibilityRole::Image: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("image"); - break; - case AccessibilityRole::Keyboardkey: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("keyboardkey"); - break; - case AccessibilityRole::Text: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("text"); - break; - case AccessibilityRole::Adjustable: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("adjustable"); - break; - case AccessibilityRole::Imagebutton: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("imagebutton"); - break; - case AccessibilityRole::Header: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("header"); - break; - case AccessibilityRole::Summary: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("summary"); - break; - case AccessibilityRole::Alert: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("alert"); - break; - case AccessibilityRole::Checkbox: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("checkbox"); - break; - case AccessibilityRole::Combobox: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("combobox"); - break; - case AccessibilityRole::Menu: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("menu"); - break; - case AccessibilityRole::Menubar: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("menubar"); - break; - case AccessibilityRole::Menuitem: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("menuitem"); - break; - case AccessibilityRole::Progressbar: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("progressbar"); - break; - case AccessibilityRole::Radio: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("radio"); - break; - case AccessibilityRole::Radiogroup: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("radiogroup"); - break; - case AccessibilityRole::Scrollbar: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("scrollbar"); - break; - case AccessibilityRole::Spinbutton: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("spinbutton"); - break; - case AccessibilityRole::Switch: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("switch"); - break; - case AccessibilityRole::Tab: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("tab"); - break; - case AccessibilityRole::Tabbar: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("tabbar"); - break; - case AccessibilityRole::Tablist: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("tablist"); - break; - case AccessibilityRole::Timer: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("timer"); - break; - case AccessibilityRole::List: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("list"); - break; - case AccessibilityRole::Toolbar: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("toolbar"); - break; - case AccessibilityRole::Grid: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("grid"); - break; - case AccessibilityRole::Pager: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("pager"); - break; - case AccessibilityRole::Scrollview: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("scrollview"); - break; - case AccessibilityRole::Horizontalscrollview: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("horizontalscrollview"); - break; - case AccessibilityRole::Viewgroup: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("viewgroup"); - break; - case AccessibilityRole::Webview: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("webview"); - break; - case AccessibilityRole::Drawerlayout: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("drawerlayout"); - break; - case AccessibilityRole::Slidingdrawer: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("slidingdrawer"); - break; - case AccessibilityRole::Iconmenu: - attributes[RCTTextAttributesAccessibilityRoleAttributeName] = @("iconmenu"); - break; - }; + if (textAttributes.role.has_value()) { + std::string roleStr = toString(textAttributes.role.value()); + attributes[RCTTextAttributesAccessibilityRoleAttributeName] = [NSString stringWithCString:roleStr.c_str()]; + } else if (textAttributes.accessibilityRole.has_value()) { + std::string roleStr = toString(textAttributes.accessibilityRole.value()); + attributes[RCTTextAttributesAccessibilityRoleAttributeName] = [NSString stringWithCString:roleStr.c_str()]; } return [attributes copy];