diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h index 507c09056..d43973049 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h @@ -51,6 +51,16 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, strong, nullable) UIColor *foregroundColor; +/** + * Returns the object - usually (sub)view - which represents this + * component view in terms of accessibility. + * All accessibility properties will be applied to this object. + * May be overridden in subclass which needs to be accessiblitywise + * transparent in favour of some subview. + * Defaults to `self`. + */ +@property (nonatomic, strong, nullable, readonly) NSObject *accessibilityElement; + /** * Insets used when hit testing inside this view. */ diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index dad8a5f49..52876c87b 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -131,6 +131,10 @@ using namespace facebook::react; if (oldViewProps.nativeId != newViewProps.nativeId) { self.nativeId = RCTNSStringFromString(newViewProps.nativeId); } + + // `accessible` + if (oldViewProps.accessible != newViewProps.accessible) { + self.accessibilityElement.isAccessibilityElement = newViewProps.accessible; } } @@ -146,11 +150,65 @@ using namespace facebook::react; _layoutMetrics = layoutMetrics; [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; +} +- (void)invalidateBorder +{ + const auto &props = *std::dynamic_pointer_cast(_props); + + bool useCoreAnimationBorderRendering = + props.borderStyle == BorderStyle::Solid && + props.borderWidth.isUniformed() && + props.borderRadius.isUniformed(); + + CALayer *layer = self.layer; + if (_isCoreAnimationBorderRenderingEnabled != useCoreAnimationBorderRendering) { + _isCoreAnimationBorderRenderingEnabled = useCoreAnimationBorderRendering; + if (!useCoreAnimationBorderRendering) { + layer.borderWidth = 0; + layer.borderColor = nil; + layer.cornerRadius = 0; + } + } + + if (useCoreAnimationBorderRendering) { + layer.borderWidth = (CGFloat)props.borderWidth.left; + layer.borderColor = RCTCGColorRefFromSharedColor(props.borderColor); + layer.cornerRadius = (CGFloat)props.borderRadius.topLeft; + _contentView.layer.cornerRadius = (CGFloat)props.borderRadius.topLeft; + _contentView.layer.masksToBounds = YES; + } else { + // Not supported yet. + } +} + +#pragma mark - Accessibility + +- (NSObject *)accessibilityElement +{ + return self; } #pragma mark - Accessibility Events +- (NSArray *)accessibilityCustomActions +{ + const auto &accessibilityProps = *std::dynamic_pointer_cast(_props); + + if (accessibilityProps.accessibilityActions.size() == 0) { + return nil; + } + + NSMutableArray *customActions = [NSMutableArray array]; + for (const auto &accessibilityAction : accessibilityProps.accessibilityActions) { + [customActions addObject:[[UIAccessibilityCustomAction alloc] initWithName:RCTNSStringFromString(accessibilityAction) + target:self + selector:@selector(didActivateAccessibilityCustomAction:)]]; + } + + return [customActions copy]; +} + - (BOOL)accessibilityActivate { _eventEmitter->onAccessibilityTap(); diff --git a/ReactCommon/fabric/view/accessibility/AccessibilityProps.h b/ReactCommon/fabric/view/accessibility/AccessibilityProps.h index c19881dfb..931edc8d3 100644 --- a/ReactCommon/fabric/view/accessibility/AccessibilityProps.h +++ b/ReactCommon/fabric/view/accessibility/AccessibilityProps.h @@ -30,7 +30,7 @@ public: #pragma mark - Props const bool accessible {true}; - const std::string accessibilityActions {""}; + const std::vector accessibilityActions {}; const std::string accessibilityLabel {""}; const AccessibilityTraits accessibilityTraits {AccessibilityTraits::None}; const bool accessibilityViewIsModal {false};