diff --git a/packages/react-native/React/Base/RCTTouchHandler.m b/packages/react-native/React/Base/RCTTouchHandler.m index 3f45d2f7a6bcd8..da95ebd4ae7e77 100644 --- a/packages/react-native/React/Base/RCTTouchHandler.m +++ b/packages/react-native/React/Base/RCTTouchHandler.m @@ -128,8 +128,9 @@ - (void)_recordNewTouches:(NSSet *)touches #else // [macOS // -[NSView hitTest:] takes coordinates in a view's superview coordinate system. // The assumption here is that a RCTUIView/RCTSurfaceView will always have a superview. - CGPoint touchLocation = [self.view.superview convertPoint:touch.locationInWindow fromView:nil]; - NSView *targetView = [self.view hitTest:touchLocation]; + NSView *superview = [[self view] superview]; + const CGPoint touchLocationInSuperview = [superview convertPoint:touch.locationInWindow fromView:nil]; + NSView *targetView = [self.view hitTest:touchLocationInSuperview]; // Don't record clicks on scrollbars. if ([targetView isKindOfClass:[NSScroller class]]) { continue; @@ -148,8 +149,7 @@ - (void)_recordNewTouches:(NSSet *)touches } else { _shouldSendMouseUpOnSystemBehalf = NO; } - touchLocation = [targetView convertPoint:touchLocation fromView:self.view.superview]; - + while (targetView) { BOOL isUserInteractionEnabled = NO; if ([((RCTUIView*)targetView) respondsToSelector:@selector(isUserInteractionEnabled)]) { // [macOS] @@ -161,7 +161,8 @@ - (void)_recordNewTouches:(NSSet *)touches targetView = targetView.superview; } - NSNumber *reactTag = [targetView reactTagAtPoint:touchLocation]; + const CGPoint touchLocationInSelf = [targetView convertPoint:touchLocationInSuperview fromView:self.view.superview]; + NSNumber *reactTag = [targetView reactTagAtPoint:touchLocationInSelf]; BOOL isUserInteractionEnabled = NO; if ([((RCTUIView*)targetView) respondsToSelector:@selector(isUserInteractionEnabled)]) { // [macOS] isUserInteractionEnabled = ((RCTUIView*)targetView).isUserInteractionEnabled; // [macOS] diff --git a/packages/react-native/React/Base/RCTUIKit.h b/packages/react-native/React/Base/RCTUIKit.h index 8cd17e29b3ca41..bea0282f7bf05f 100644 --- a/packages/react-native/React/Base/RCTUIKit.h +++ b/packages/react-native/React/Base/RCTUIKit.h @@ -486,7 +486,10 @@ CGPathRef UIBezierPathCreateCGPathRef(UIBezierPath *path); NS_INLINE RCTPlatformView *RCTUIViewHitTestWithEvent(RCTPlatformView *view, CGPoint point, __unused UIEvent *__nullable event) { - return [view hitTest:point]; + // [macOS IMPORTANT -- point is in local coordinate space, but OSX expects super coordinate space for hitTest: + NSView *superview = [view superview]; + NSPoint pointInSuperview = superview != nil ? [view convertPoint:point toView:superview] : point; + return [view hitTest:pointInSuperview]; } BOOL RCTUIViewSetClipsToBounds(RCTPlatformView *view); diff --git a/packages/react-native/React/Base/macOS/RCTUIKit.m b/packages/react-native/React/Base/macOS/RCTUIKit.m index 48f2ec5f8eff5c..61401fbde00fb9 100644 --- a/packages/react-native/React/Base/macOS/RCTUIKit.m +++ b/packages/react-native/React/Base/macOS/RCTUIKit.m @@ -454,7 +454,10 @@ - (void)setTransform:(CGAffineTransform)transform - (NSView *)hitTest:(NSPoint)point { - return [self hitTest:NSPointToCGPoint(point) withEvent:nil]; + // IMPORTANT point is passed in super coordinates by OSX, but expected to be passed in local coordinates + NSView *superview = [self superview]; + NSPoint pointInSelf = superview != nil ? [self convertPoint:point fromView:superview] : point; + return [self hitTest:pointInSelf withEvent:nil]; } - (BOOL)wantsUpdateLayer @@ -505,7 +508,11 @@ - (BOOL)becomeFirstResponder - (NSView *)hitTest:(CGPoint)point withEvent:(__unused UIEvent *)event { - return self.userInteractionEnabled ? [super hitTest:NSPointFromCGPoint(point)] : nil; +// [macOS + // IMPORTANT point is expected to be passed in local coordinates, but OSX expects point to be super + NSView *superview = [self superview]; + NSPoint pointInSuperview = superview != nil ? [self convertPoint:point toView:superview] : point; + return self.userInteractionEnabled ? [super hitTest:pointInSuperview] : nil; } - (BOOL)pointInside:(CGPoint)point withEvent:(__unused UIEvent *)event diff --git a/packages/react-native/React/Views/RCTView.m b/packages/react-native/React/Views/RCTView.m index deff71bc2c1bba..0238d80cd0ee88 100644 --- a/packages/react-native/React/Views/RCTView.m +++ b/packages/react-native/React/Views/RCTView.m @@ -252,17 +252,8 @@ - (RCTPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event // [macOS // of the hit view will return YES from -pointInside:withEvent:). See: // - https://developer.apple.com/library/ios/qa/qa2013/qa1812.html for (RCTUIView *subview in [sortedSubviews reverseObjectEnumerator]) { // [macOS] - CGPoint pointForHitTest = CGPointZero; // [macOS -#if !TARGET_OS_OSX // [macOS] - pointForHitTest = [subview convertPoint:point fromView:self]; -#else // [macOS - if ([subview isKindOfClass:[RCTView class]]) { - pointForHitTest = [subview convertPoint:point fromView:self]; - } else { - pointForHitTest = point; - } -#endif // macOS] - hitSubview = RCTUIViewHitTestWithEvent(subview, pointForHitTest, event); // macOS] + CGPoint pointForHitTest = [subview convertPoint:point fromView:self]; + hitSubview = RCTUIViewHitTestWithEvent(subview, pointForHitTest, event); // [macOS] if (hitSubview != nil) { break; } diff --git a/packages/react-native/React/Views/UIView+React.m b/packages/react-native/React/Views/UIView+React.m index a3bc056e921a40..1a26e0aa2200ad 100644 --- a/packages/react-native/React/Views/UIView+React.m +++ b/packages/react-native/React/Views/UIView+React.m @@ -573,10 +573,13 @@ - (NSString *)react_recursiveDescription // [macOS #pragma mark - Hit testing -#if TARGET_OS_OSX +#if TARGET_OS_OSX +// IMPORTANT -- point is in local coordinate space, unlike the hitTest: version from OSX which is in super's coordinate space - (RCTPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { - return [self hitTest:point]; + NSView *superview = [self superview]; + NSPoint pointInSuper = superview != nil ? [self convertPoint:point toView:superview] : point; + return [self hitTest:pointInSuper]; } #endif // macOS]