123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- /*
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * 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+Transform.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"
- #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),
- @"alert" : @(UIAccessibilityTraitNone),
- @"checkbox" : @(UIAccessibilityTraitNone),
- @"combobox" : @(UIAccessibilityTraitNone),
- @"menu" : @(UIAccessibilityTraitNone),
- @"menubar" : @(UIAccessibilityTraitNone),
- @"menuitem" : @(UIAccessibilityTraitNone),
- @"progressbar" : @(UIAccessibilityTraitNone),
- @"radio" : @(UIAccessibilityTraitNone),
- @"radiogroup" : @(UIAccessibilityTraitNone),
- @"scrollbar" : @(UIAccessibilityTraitNone),
- @"spinbutton" : @(UIAccessibilityTraitNone),
- @"switch" : @(SwitchAccessibilityTrait),
- @"tab" : @(UIAccessibilityTraitNone),
- @"tablist" : @(UIAccessibilityTraitNone),
- @"timer" : @(UIAccessibilityTraitNone),
- @"toolbar" : @(UIAccessibilityTraitNone),
- }),
- 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
- // TODO: Delete props for Apple TV.
- RCT_EXPORT_VIEW_PROPERTY(isTVSelectable, BOOL)
- RCT_EXPORT_VIEW_PROPERTY(hasTVPreferredFocus, BOOL)
- RCT_EXPORT_VIEW_PROPERTY(tvParallaxProperties, NSDictionary)
- #endif
- // Accessibility related properties
- RCT_REMAP_VIEW_PROPERTY(accessible, reactAccessibilityElement.isAccessibilityElement, BOOL)
- RCT_REMAP_VIEW_PROPERTY(accessibilityActions, reactAccessibilityElement.accessibilityActions, NSDictionaryArray)
- RCT_REMAP_VIEW_PROPERTY(accessibilityLabel, reactAccessibilityElement.accessibilityLabel, NSString)
- RCT_REMAP_VIEW_PROPERTY(accessibilityHint, reactAccessibilityElement.accessibilityHint, NSString)
- RCT_REMAP_VIEW_PROPERTY(accessibilityValue, reactAccessibilityElement.accessibilityValueInternal, NSDictionary)
- 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(onAccessibilityEscape, reactAccessibilityElement.onAccessibilityEscape, 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_REMAP_VIEW_PROPERTY(needsOffscreenAlphaCompositing, layer.allowsGroupOpacity, BOOL)
- 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;
- // Enable edge antialiasing in perspective transforms
- view.layer.allowsEdgeAntialiasing = !(view.layer.transform.m34 == 0.0f);
- }
- RCT_CUSTOM_VIEW_PROPERTY(accessibilityRole, UIAccessibilityTraits, RCTView)
- {
- const UIAccessibilityTraits AccessibilityRolesMask = UIAccessibilityTraitNone | UIAccessibilityTraitButton |
- UIAccessibilityTraitLink | UIAccessibilityTraitSearchField | UIAccessibilityTraitImage |
- UIAccessibilityTraitKeyboardKey | UIAccessibilityTraitStaticText | UIAccessibilityTraitAdjustable |
- UIAccessibilityTraitHeader | UIAccessibilityTraitSummaryElement | 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;
- }
- }
- RCT_CUSTOM_VIEW_PROPERTY(accessibilityState, NSDictionary, RCTView)
- {
- NSDictionary<NSString *, id> *state = json ? [RCTConvert NSDictionary:json] : nil;
- NSMutableDictionary<NSString *, id> *newState = [[NSMutableDictionary<NSString *, id> alloc] init];
- if (!state) {
- return;
- }
- const UIAccessibilityTraits AccessibilityStatesMask = UIAccessibilityTraitNotEnabled | UIAccessibilityTraitSelected;
- view.reactAccessibilityElement.accessibilityTraits =
- view.reactAccessibilityElement.accessibilityTraits & ~AccessibilityStatesMask;
- for (NSString *s in state) {
- id val = [state objectForKey:s];
- if (!val) {
- continue;
- }
- if ([s isEqualToString:@"selected"] && [val isKindOfClass:[NSNumber class]] && [val boolValue]) {
- view.reactAccessibilityElement.accessibilityTraits |= UIAccessibilityTraitSelected;
- } else if ([s isEqualToString:@"disabled"] && [val isKindOfClass:[NSNumber class]] && [val boolValue]) {
- view.reactAccessibilityElement.accessibilityTraits |= UIAccessibilityTraitNotEnabled;
- } else {
- newState[s] = val;
- }
- }
- if (newState.count > 0) {
- view.reactAccessibilityElement.accessibilityState = newState;
- // Post a layout change notification to make sure VoiceOver get notified for the state
- // changes that don't happen upon users' click.
- UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
- } else {
- view.reactAccessibilityElement.accessibilityState = nil;
- }
- }
- RCT_CUSTOM_VIEW_PROPERTY(nativeID, NSString *, RCTView)
- {
- view.nativeID = json ? [RCTConvert NSString:json] : defaultView.nativeID;
- [_bridge.uiManager setNativeID:view.nativeID forView:view];
- }
- 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
|