mirror of
https://github.com/status-im/react-native.git
synced 2025-02-21 13:48:13 +00:00
Summary: Because we're now separating accessibilityTraits into accessibilityRole and accessibilityState, we're going to only allow one role to be set, and allow on preset combinations of roles that make sense. This change adds iOS functionality to the role image button because a popular accessibilityTrait combination is image and button. Reviewed By: ikenwoo Differential Revision: D8847012 fbshipit-source-id: da386dbf82cb3854d14c228a1116da9f4067fe93
333 lines
13 KiB
Objective-C
333 lines
13 KiB
Objective-C
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import "RCTViewManager.h"
|
|
|
|
#import "RCTBorderStyle.h"
|
|
#import "RCTBridge.h"
|
|
#import "RCTConvert.h"
|
|
#import "RCTEventDispatcher.h"
|
|
#import "RCTLog.h"
|
|
#import "RCTShadowView.h"
|
|
#import "RCTUIManager.h"
|
|
#import "RCTUIManagerUtils.h"
|
|
#import "RCTUtils.h"
|
|
#import "RCTView.h"
|
|
#import "UIView+React.h"
|
|
#import "RCTConvert+Transform.h"
|
|
|
|
#if TARGET_OS_TV
|
|
#import "RCTTVView.h"
|
|
#endif
|
|
|
|
@implementation RCTConvert(UIAccessibilityTraits)
|
|
|
|
RCT_MULTI_ENUM_CONVERTER(UIAccessibilityTraits, (@{
|
|
@"none": @(UIAccessibilityTraitNone),
|
|
@"button": @(UIAccessibilityTraitButton),
|
|
@"link": @(UIAccessibilityTraitLink),
|
|
@"header": @(UIAccessibilityTraitHeader),
|
|
@"search": @(UIAccessibilityTraitSearchField),
|
|
@"image": @(UIAccessibilityTraitImage),
|
|
@"imagebutton": @(UIAccessibilityTraitImage | UIAccessibilityTraitButton),
|
|
@"selected": @(UIAccessibilityTraitSelected),
|
|
@"plays": @(UIAccessibilityTraitPlaysSound),
|
|
@"key": @(UIAccessibilityTraitKeyboardKey),
|
|
@"keyboardkey": @(UIAccessibilityTraitKeyboardKey),
|
|
@"text": @(UIAccessibilityTraitStaticText),
|
|
@"summary": @(UIAccessibilityTraitSummaryElement),
|
|
@"disabled": @(UIAccessibilityTraitNotEnabled),
|
|
@"frequentUpdates": @(UIAccessibilityTraitUpdatesFrequently),
|
|
@"startsMedia": @(UIAccessibilityTraitStartsMediaSession),
|
|
@"adjustable": @(UIAccessibilityTraitAdjustable),
|
|
@"allowsDirectInteraction": @(UIAccessibilityTraitAllowsDirectInteraction),
|
|
@"pageTurn": @(UIAccessibilityTraitCausesPageTurn),
|
|
}), UIAccessibilityTraitNone, unsignedLongLongValue)
|
|
|
|
@end
|
|
|
|
@implementation RCTViewManager
|
|
|
|
@synthesize bridge = _bridge;
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
- (dispatch_queue_t)methodQueue
|
|
{
|
|
return RCTGetUIManagerQueue();
|
|
}
|
|
|
|
- (UIView *)view
|
|
{
|
|
#if TARGET_OS_TV
|
|
return [RCTTVView new];
|
|
#else
|
|
return [RCTView new];
|
|
#endif
|
|
}
|
|
|
|
- (RCTShadowView *)shadowView
|
|
{
|
|
return [RCTShadowView new];
|
|
}
|
|
|
|
- (NSArray<NSString *> *)customBubblingEventTypes
|
|
{
|
|
return @[
|
|
|
|
// Generic events
|
|
@"press",
|
|
@"change",
|
|
@"focus",
|
|
@"blur",
|
|
@"submitEditing",
|
|
@"endEditing",
|
|
@"keyPress",
|
|
|
|
// Touch events
|
|
@"touchStart",
|
|
@"touchMove",
|
|
@"touchCancel",
|
|
@"touchEnd",
|
|
];
|
|
}
|
|
|
|
#pragma mark - View properties
|
|
|
|
#if TARGET_OS_TV
|
|
// Apple TV properties
|
|
RCT_EXPORT_VIEW_PROPERTY(isTVSelectable, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(hasTVPreferredFocus, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(tvParallaxProperties, NSDictionary)
|
|
#endif
|
|
|
|
RCT_EXPORT_VIEW_PROPERTY(nativeID, NSString)
|
|
|
|
// Acessibility related properties
|
|
RCT_REMAP_VIEW_PROPERTY(accessible, reactAccessibilityElement.isAccessibilityElement, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(accessibilityActions, reactAccessibilityElement.accessibilityActions, NSString)
|
|
RCT_REMAP_VIEW_PROPERTY(accessibilityLabel, reactAccessibilityElement.accessibilityLabel, NSString)
|
|
RCT_REMAP_VIEW_PROPERTY(accessibilityTraits, reactAccessibilityElement.accessibilityTraits, UIAccessibilityTraits)
|
|
RCT_REMAP_VIEW_PROPERTY(accessibilityRole, reactAccessibilityElement.accessibilityTraits, UIAccessibilityTraits)
|
|
RCT_REMAP_VIEW_PROPERTY(accessibilityViewIsModal, reactAccessibilityElement.accessibilityViewIsModal, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(accessibilityElementsHidden, reactAccessibilityElement.accessibilityElementsHidden, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(accessibilityIgnoresInvertColors, reactAccessibilityElement.shouldAccessibilityIgnoresInvertColors, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(onAccessibilityAction, reactAccessibilityElement.onAccessibilityAction, RCTDirectEventBlock)
|
|
RCT_REMAP_VIEW_PROPERTY(onAccessibilityTap, reactAccessibilityElement.onAccessibilityTap, RCTDirectEventBlock)
|
|
RCT_REMAP_VIEW_PROPERTY(onMagicTap, reactAccessibilityElement.onMagicTap, RCTDirectEventBlock)
|
|
RCT_REMAP_VIEW_PROPERTY(testID, reactAccessibilityElement.accessibilityIdentifier, NSString)
|
|
|
|
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
|
|
RCT_REMAP_VIEW_PROPERTY(backfaceVisibility, layer.doubleSided, css_backface_visibility_t)
|
|
RCT_REMAP_VIEW_PROPERTY(opacity, alpha, CGFloat)
|
|
RCT_REMAP_VIEW_PROPERTY(shadowColor, layer.shadowColor, CGColor)
|
|
RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset, CGSize)
|
|
RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, float)
|
|
RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius, CGFloat)
|
|
RCT_CUSTOM_VIEW_PROPERTY(overflow, YGOverflow, RCTView)
|
|
{
|
|
if (json) {
|
|
view.clipsToBounds = [RCTConvert YGOverflow:json] != YGOverflowVisible;
|
|
} else {
|
|
view.clipsToBounds = defaultView.clipsToBounds;
|
|
}
|
|
}
|
|
RCT_CUSTOM_VIEW_PROPERTY(shouldRasterizeIOS, BOOL, RCTView)
|
|
{
|
|
view.layer.shouldRasterize = json ? [RCTConvert BOOL:json] : defaultView.layer.shouldRasterize;
|
|
view.layer.rasterizationScale = view.layer.shouldRasterize ? [UIScreen mainScreen].scale : defaultView.layer.rasterizationScale;
|
|
}
|
|
|
|
RCT_CUSTOM_VIEW_PROPERTY(transform, CATransform3D, RCTView)
|
|
{
|
|
view.layer.transform = json ? [RCTConvert CATransform3D:json] : defaultView.layer.transform;
|
|
// TODO: Improve this by enabling edge antialiasing only for transforms with rotation or skewing
|
|
view.layer.allowsEdgeAntialiasing = !CATransform3DIsIdentity(view.layer.transform);
|
|
}
|
|
|
|
RCT_CUSTOM_VIEW_PROPERTY(pointerEvents, RCTPointerEvents, RCTView)
|
|
{
|
|
if ([view respondsToSelector:@selector(setPointerEvents:)]) {
|
|
view.pointerEvents = json ? [RCTConvert RCTPointerEvents:json] : defaultView.pointerEvents;
|
|
return;
|
|
}
|
|
|
|
if (!json) {
|
|
view.userInteractionEnabled = defaultView.userInteractionEnabled;
|
|
return;
|
|
}
|
|
|
|
switch ([RCTConvert RCTPointerEvents:json]) {
|
|
case RCTPointerEventsUnspecified:
|
|
// Pointer events "unspecified" acts as if a stylesheet had not specified,
|
|
// which is different than "auto" in CSS (which cannot and will not be
|
|
// supported in `React`. "auto" may override a parent's "none".
|
|
// Unspecified values do not.
|
|
// This wouldn't override a container view's `userInteractionEnabled = NO`
|
|
view.userInteractionEnabled = YES;
|
|
case RCTPointerEventsNone:
|
|
view.userInteractionEnabled = NO;
|
|
break;
|
|
default:
|
|
RCTLogError(@"UIView base class does not support pointerEvent value: %@", json);
|
|
}
|
|
}
|
|
RCT_CUSTOM_VIEW_PROPERTY(removeClippedSubviews, BOOL, RCTView)
|
|
{
|
|
if ([view respondsToSelector:@selector(setRemoveClippedSubviews:)]) {
|
|
view.removeClippedSubviews = json ? [RCTConvert BOOL:json] : defaultView.removeClippedSubviews;
|
|
}
|
|
}
|
|
RCT_CUSTOM_VIEW_PROPERTY(borderRadius, CGFloat, RCTView) {
|
|
if ([view respondsToSelector:@selector(setBorderRadius:)]) {
|
|
view.borderRadius = json ? [RCTConvert CGFloat:json] : defaultView.borderRadius;
|
|
} else {
|
|
view.layer.cornerRadius = json ? [RCTConvert CGFloat:json] : defaultView.layer.cornerRadius;
|
|
}
|
|
}
|
|
RCT_CUSTOM_VIEW_PROPERTY(borderColor, CGColor, RCTView)
|
|
{
|
|
if ([view respondsToSelector:@selector(setBorderColor:)]) {
|
|
view.borderColor = json ? [RCTConvert CGColor:json] : defaultView.borderColor;
|
|
} else {
|
|
view.layer.borderColor = json ? [RCTConvert CGColor:json] : defaultView.layer.borderColor;
|
|
}
|
|
}
|
|
RCT_CUSTOM_VIEW_PROPERTY(borderWidth, float, RCTView)
|
|
{
|
|
if ([view respondsToSelector:@selector(setBorderWidth:)]) {
|
|
view.borderWidth = json ? [RCTConvert CGFloat:json] : defaultView.borderWidth;
|
|
} else {
|
|
view.layer.borderWidth = json ? [RCTConvert CGFloat:json] : defaultView.layer.borderWidth;
|
|
}
|
|
}
|
|
RCT_CUSTOM_VIEW_PROPERTY(borderStyle, RCTBorderStyle, RCTView)
|
|
{
|
|
if ([view respondsToSelector:@selector(setBorderStyle:)]) {
|
|
view.borderStyle = json ? [RCTConvert RCTBorderStyle:json] : defaultView.borderStyle;
|
|
}
|
|
}
|
|
RCT_CUSTOM_VIEW_PROPERTY(hitSlop, UIEdgeInsets, RCTView)
|
|
{
|
|
if ([view respondsToSelector:@selector(setHitTestEdgeInsets:)]) {
|
|
if (json) {
|
|
UIEdgeInsets hitSlopInsets = [RCTConvert UIEdgeInsets:json];
|
|
view.hitTestEdgeInsets = UIEdgeInsetsMake(-hitSlopInsets.top, -hitSlopInsets.left, -hitSlopInsets.bottom, -hitSlopInsets.right);
|
|
} else {
|
|
view.hitTestEdgeInsets = defaultView.hitTestEdgeInsets;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define RCT_VIEW_BORDER_PROPERTY(SIDE) \
|
|
RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Width, float, RCTView) \
|
|
{ \
|
|
if ([view respondsToSelector:@selector(setBorder##SIDE##Width:)]) { \
|
|
view.border##SIDE##Width = json ? [RCTConvert CGFloat:json] : defaultView.border##SIDE##Width; \
|
|
} \
|
|
} \
|
|
RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Color, UIColor, RCTView) \
|
|
{ \
|
|
if ([view respondsToSelector:@selector(setBorder##SIDE##Color:)]) { \
|
|
view.border##SIDE##Color = json ? [RCTConvert CGColor:json] : defaultView.border##SIDE##Color; \
|
|
} \
|
|
}
|
|
|
|
RCT_VIEW_BORDER_PROPERTY(Top)
|
|
RCT_VIEW_BORDER_PROPERTY(Right)
|
|
RCT_VIEW_BORDER_PROPERTY(Bottom)
|
|
RCT_VIEW_BORDER_PROPERTY(Left)
|
|
RCT_VIEW_BORDER_PROPERTY(Start)
|
|
RCT_VIEW_BORDER_PROPERTY(End)
|
|
|
|
#define RCT_VIEW_BORDER_RADIUS_PROPERTY(SIDE) \
|
|
RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Radius, CGFloat, RCTView) \
|
|
{ \
|
|
if ([view respondsToSelector:@selector(setBorder##SIDE##Radius:)]) { \
|
|
view.border##SIDE##Radius = json ? [RCTConvert CGFloat:json] : defaultView.border##SIDE##Radius; \
|
|
} \
|
|
} \
|
|
|
|
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopLeft)
|
|
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopRight)
|
|
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopStart)
|
|
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopEnd)
|
|
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomLeft)
|
|
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomRight)
|
|
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomStart)
|
|
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomEnd)
|
|
|
|
RCT_REMAP_VIEW_PROPERTY(display, reactDisplay, YGDisplay)
|
|
RCT_REMAP_VIEW_PROPERTY(zIndex, reactZIndex, NSInteger)
|
|
|
|
#pragma mark - ShadowView properties
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(top, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(right, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(start, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(end, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(bottom, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(left, YGValue)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(width, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(height, YGValue)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(minWidth, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(maxWidth, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(minHeight, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(maxHeight, YGValue)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(borderTopWidth, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(borderRightWidth, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(borderBottomWidth, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(borderLeftWidth, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(borderStartWidth, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(borderEndWidth, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(borderWidth, float)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(marginTop, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(marginRight, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(marginBottom, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(marginLeft, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(marginStart, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(marginEnd, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(marginVertical, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(marginHorizontal, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(margin, YGValue)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(paddingTop, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(paddingRight, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(paddingBottom, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(paddingLeft, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(paddingStart, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(paddingEnd, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(paddingVertical, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(paddingHorizontal, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(padding, YGValue)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(flex, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(flexGrow, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(flexShrink, float)
|
|
RCT_EXPORT_SHADOW_PROPERTY(flexBasis, YGValue)
|
|
RCT_EXPORT_SHADOW_PROPERTY(flexDirection, YGFlexDirection)
|
|
RCT_EXPORT_SHADOW_PROPERTY(flexWrap, YGWrap)
|
|
RCT_EXPORT_SHADOW_PROPERTY(justifyContent, YGJustify)
|
|
RCT_EXPORT_SHADOW_PROPERTY(alignItems, YGAlign)
|
|
RCT_EXPORT_SHADOW_PROPERTY(alignSelf, YGAlign)
|
|
RCT_EXPORT_SHADOW_PROPERTY(alignContent, YGAlign)
|
|
RCT_EXPORT_SHADOW_PROPERTY(position, YGPositionType)
|
|
RCT_EXPORT_SHADOW_PROPERTY(aspectRatio, float)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(overflow, YGOverflow)
|
|
RCT_EXPORT_SHADOW_PROPERTY(display, YGDisplay)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(onLayout, RCTDirectEventBlock)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(direction, YGDirection)
|
|
|
|
@end
|