Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Releasing a Manual Gesture over a RN Pressable causes onPress to be fired. (WEB) #2388

Open
Jackman3005 opened this issue Jan 27, 2023 · 6 comments
Labels
Can repro It is confirmed we can reproduce the issue Close when stale The issue will be closed automatically if it remains inactive Platform: Web Repro provided A reproduction with a snack or repo is provided

Comments

@Jackman3005
Copy link

Jackman3005 commented Jan 27, 2023

Description

Hi all, thanks for all that you've put into RNGH so far. It's pretty incredible!

Preface

We have created a "canvas" type component that is wrapped in a <GestureDetector>. The gesture is used to let the user draw lines.

Note: I don't want to cancel the gesture if they drag out of the canvas, because they might do it just for a moment and it is awkward when the line stops if you barely clip the edge. I have other code that removes points off the canvas.

Issue

If the user is "drawing" -- press down inside the canvas and drag around -- if they release over a react-native <Pressable> the Pressable's onPress is fired. This is unexpected behavior, because they did not press down on this button. It happens for all Pressable and TouchableHighlight components we have on that screen regardless of how far away from the canvas (even happens for a couple editor buttons we have absolute positioned over the canvas).

This only happens on web (UPDATE: See comment below). We have tested this on Android and iOS and there is no issue (the onPress is correctly not fired)

Note: we have tried the latest versions of react-native-gesture-handler as well as react-native-web and it does not resolve the issue.

I am not 100% sure if this is a react-native-gesture-handler bug or a react-native-web bug, so apologies if I need to take this issue to react-native-web instead.

Code Snippet

For those wanting an at-a-glance view of likely the most relevant code (See the Snack for more).

const gesture = useMemo(
    () =>
      Gesture.Manual()
        .hitSlop(0)
        .onTouchesDown((event, stateManager) => {
          const locationX = event.changedTouches[0].x;
          const locationY = event.changedTouches[0].y;

          stateManager.begin();
          stateManager.activate();
          runOnJS(addNewPoint)(Math.round(locationX), Math.round(locationY));
        })
        .onTouchesMove((event) => {
          const currentX = event.changedTouches[0]?.x;
          const currentY = event.changedTouches[0]?.y;
          if (currentX === undefined || currentY === undefined) {
            return;
          }

          runOnJS(addNewPoint)(currentX, currentY);
        })
        .onTouchesUp((event, stateManager) => {
          stateManager.end();
          runOnJS(clearPoints)();
        }),
    [clearPoints, addNewPoint]
  );
  return (
    <GestureDetector gesture={gesture} userSelect={'none'}>
      <View style={{ width: '100%', height: 300, backgroundColor: 'white' }}>
        <Svg width={'100%'} height={300}>
          <Path
            d={pointsToSvgPathCommands(points)}
            stroke={'#000'}
            strokeWidth={3}
            fill="none"
          />
        </Svg>
      </View>
    </GestureDetector>
  );

Steps to reproduce

I have supplied a Snack exhibiting the bug in the form that we are experiencing it.

  1. Open Snack
  2. Play with the white canvas by clicking and dragging your mouse around it.
  3. While drawing on the canvas, drag the mouse off the canvas to the button and release the mouse
  4. Observe that the onPress counter has incremented. <---- BUG: This should not increment in this situation!

Snack or a link to a repository

https://snack.expo.dev/@jcoy/brave-french-fries

Gesture Handler version

2.8.0

React Native version

0.70.5

Platforms

Android, iOS, Web

JavaScript runtime

Hermes

Workflow

Expo bare workflow

Architecture

Paper (Old Architecture)

Build type

None

Device

None

Device model

No response

Acknowledgements

Yes

@github-actions github-actions bot added Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Platform: Web Missing info Repro provided A reproduction with a snack or repo is provided and removed Missing info labels Jan 27, 2023
@Jackman3005
Copy link
Author

UPDATE: This does not appear to happen on all browsers. In fact, I have so far only got it to happen on Firefox on Mac (which exhibits the issue 100% of the time). Chrome & Safari on Mac do not exhibit the bug.

Despite having more information, I feel the question of why this is happening is even harder to answer now 🤯.

Note: Firefox does not exhibit more generalized bugs of the same nature. e.g. It does not happen if either: I drag from anywhere on the screen to a button and release; or if I click one button, drag to another and release.

I use Firefox regularly for development and rarely run into exceptional behavior like this, I think the issue is likely still somewhere in the libraries used in the Snack that is causing the bug.

@j-piasecki j-piasecki added the Can repro It is confirmed we can reproduce the issue label Feb 6, 2023
@lightrow
Copy link

lightrow commented Jun 20, 2023

not sure if it's the same, but it happens in Android and iOS apps as well, if gesture detector wraps Pressable, the Pressable will sometimes (not always) fire after the gesture is ended. The workaround is to track the move distance on Pressable (with onTouchMove) and check if it exceeded a threshold (e.g. 10dp) inside onPress handler and do nothing in that case.

In my case it's a custom Swipeable card component implemented through PanGestureHandler, which wraps a Pressable card component.

@m-bert
Copy link
Contributor

m-bert commented Jul 18, 2023

Hi @Jackman3005! From what we've found i would say that the problem is caused by setPointerCapture method, which we use to handle pointer events. The behavior of captured pointer events depends on used browser. Chrome/firefox/safari all give different results while testing events behavior, especially when it comes to handling click event after moving out of element that has started capturing pointer. Given that, it may be difficult to find a workaround.

You can read more about it in this issue.

@itsmepetrov
Copy link

Having the same problem now, was there ever a solution?

@m-bert
Copy link
Contributor

m-bert commented Nov 13, 2023

Unfortunately not. As far as I can tell this is browser-specific behavior and we don't have good solution at the moment. However, we left this issue opened - this way we know that it is still a problem and maybe we will be able to find a workaround in the future.

@coado
Copy link
Contributor

coado commented Aug 1, 2024

Hey, @itsmepetrov and @Jackman3005 I think this issue can be solved by using Pressable from react-native-gesture-handler. Please let me know if it works for you.

@m-bert m-bert removed Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS labels Aug 1, 2024
@j-piasecki j-piasecki added the Close when stale The issue will be closed automatically if it remains inactive label Oct 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Can repro It is confirmed we can reproduce the issue Close when stale The issue will be closed automatically if it remains inactive Platform: Web Repro provided A reproduction with a snack or repo is provided
Projects
None yet
Development

No branches or pull requests

6 participants