Skip to content

touch.pageX/pageY coordinates are being computed incorrectly which can interfere with onPress events #1618

@tom-un

Description

@tom-un

Environment

react-native -v: 0.68.57-microsoft.0
npm ls react-native-macos: 0.68.57
node -v: v16.17.1
npm -v: 8.15.0
yarn --version: 1.22.19
xcodebuild -version: Xcode 14.1 Build version 14B47b

Steps to reproduce the bug

This issue only manifests if the RCTRootView is not at the origin of the NSWindow. To repro this bug, I modified packages/rn-tester/RNTester-macOS/ViewController.m adding [rootView setFrameOrigin:(NSPoint){0,-100}]; at the end of viewDidLoad.

Then in RNTester go to the "Pressable" page. When you click on "Pressable" in the ListView you have to be very careful to not move the mouse in between mouse down and mouse up (the bug manifests in the ListView as well)

In the "Pressable" page, click on the first "Press Me" button and notice that it flickers from "Pressed!" back to "Press Me".

If you press and drag up, once you get about 100 points above the "Press Me" button it will change to "Pressed!".

Expected Behavior

onPress events should work properly regardless of where the RCTRootView is positioned on the window.

Here is the correct behavior with a potential fix applied:

After-fix

Actual Behavior

In the "Pressable" page, click on the first "Press Me" button and notice that it flickers from "Pressed!" back to "Press Me".

If you press and drag up, once you get about 100 points above the "Press Me" button it will change to "Pressed!".

Before-fix

Reproducible Demo

No response

Additional context

If the RCTRootView is not positioned at the origin of the NSWindow, then touch.pageX/pageY events will not have the correct coordinates. This can make it difficult for a user to click on Touchable and Pressable components unless there are no mouse moves between the mouse down and the mouse up events. The touch down and up events use the touch.locationX/locationY which are computed correctly, but after a touch down if the user move the mouse the touch.pageX/pageY coordinates are used and if the RCTRootView is not at the window origin, these coordinates will be offset. The result is the user will see touch feedback for a moment and then it disappears.

A potential fix is to change React/Base/RCTTouchHandler.m, modifying the line 231:

-  CGPoint rootViewLocation = CGPointMake(location.x, CGRectGetHeight(self.view.window.frame) - location.y);
+  RCTAssert(_cachedRootView, @"We were unable to find a root view for the touch");
+  CGPoint rootViewLocation = [_cachedRootView.window.contentView convertPoint:location toView:_cachedRootView];

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions