diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 7fb9d34a6..568ae43fd 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -98,6 +98,13 @@ var View = React.createClass({ PropTypes.oneOf(AccessibilityTraits), PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)), ]), + + /** + * When `accessible` is true, the system will invoke this function when the + * user performs the magic tap gesture. + */ + onMagicTap: PropTypes.func, + /** * Used to locate this view in end-to-end tests. */ diff --git a/Libraries/ReactNative/ReactNativeViewAttributes.js b/Libraries/ReactNative/ReactNativeViewAttributes.js index e9e9bbd56..7fca115df 100644 --- a/Libraries/ReactNative/ReactNativeViewAttributes.js +++ b/Libraries/ReactNative/ReactNativeViewAttributes.js @@ -22,6 +22,7 @@ ReactNativeViewAttributes.UIView = { accessibilityTraits: true, testID: true, onLayout: true, + onMagicTap: true, }; ReactNativeViewAttributes.RCTView = merge( diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 7d6925b12..51b37635a 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1309,6 +1309,9 @@ RCT_EXPORT_METHOD(clearJSResponder) @"topLoadingError": @{ @"registrationName": @"onLoadingError" }, + @"topMagicTap": @{ + @"registrationName": @"onMagicTap" + }, } mutableCopy]; [_viewManagers enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTViewManager *manager, BOOL *stop) { diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index b8da37b15..7335605eb 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -15,8 +15,13 @@ @protocol RCTAutoInsetsProtocol; +@class RCTView; +typedef void (^RCTViewMagicTapHandler)(RCTView *view); + @interface RCTView : UIView +@property (nonatomic, copy) RCTViewMagicTapHandler magicTapHandler; + /** * Used to control how touch events are processed. */ diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index c2cd04703..675b3b8be 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -167,6 +167,16 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view) } } +- (BOOL)accessibilityPerformMagicTap +{ + if (self.magicTapHandler) { + self.magicTapHandler(self); + return YES; + } else { + return NO; + } +} + #pragma mark - Statics for dealing with layoutGuides + (void)autoAdjustInsetsForView:(UIView *)parentView diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 3bedccdc8..eff68f05f 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -17,6 +17,7 @@ #import "RCTUIManager.h" #import "RCTUtils.h" #import "RCTView.h" +#import "UIView+React.h" @implementation RCTConvert(UIAccessibilityTraits) @@ -171,6 +172,19 @@ RCT_CUSTOM_VIEW_PROPERTY(borderWidth, CGFloat, RCTView) view.layer.borderWidth = json ? [RCTConvert CGFloat:json] : defaultView.layer.borderWidth; } } +RCT_CUSTOM_VIEW_PROPERTY(onMagicTap, BOOL, RCTView) +{ + RCTViewMagicTapHandler handler = nil; + if ([RCTConvert BOOL:json]) { + __weak RCTViewManager *weakSelf = self; + handler = ^(RCTView *tappedView) { + NSDictionary *body = @{ @"target": tappedView.reactTag }; + [weakSelf.bridge.eventDispatcher sendInputEventWithName:@"topMagicTap" body:body]; + }; + } + + view.magicTapHandler = handler; +} #define RCT_VIEW_BORDER_PROPERTY(SIDE) \ RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Width, CGFloat, RCTView) \