pmndrs / use-gesture

👇Bread n butter utility for component-tied mouse/touch gestures in React and Vanilla Javascript.

Home Page:https://use-gesture.netlify.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

useDrag: Setting bounds breaks swipe behavior

steodor opened this issue · comments

Describe the bug
The swipe parameter in the callback is always [0, 0] if bounds are reached. The problem is conceptual (see Details below) and applies everywhere (it's not a technical/cross-platform issue but a logical issue).

Sandbox or Video
Here's a fork of the cards gallery example, only a bit modified: bounds were added (0 all around).
Result: You can no longer swipe to other cards
Expected result: Swipe should still work, just like on the blue square in the docs (on the swipe section).

Information:

  • all browsers/devices, see sandbox for versions (same as examples)

Checklist:

  • I've read the documentation.
  • If this is an issue with drag, I've tried setting touch-action: none to the draggable element.

Details:
The docs for swipe state:

Here are the conditions for a swipe to be detected on the x axis:

The drag gesture is over.
The drag gesture didn't last more than 220ms.
movement[0] is superior to the swipe.distance[0] option.
velocity[0] is superior to the swipe.velocity[0] option.

The problem is, whenever any bounds are being reached, the movement in that direction will be 0 on subsequent swipes in that direction, thus invalidating any swipe logic. Also, since movement is 0 then so is velocity, which is being used in the sandbox example and also breaks down when bounds are used.
My sandbox which breaks the example is a bit pointless, but it was just the fastest i could do to prove the bug. In my use case i'm implementing a swipe-able photo gallery with pinch zoom on every picture. While zoomed in i can drag the picture around but i need to put bounds so that i can't drag the photo off-screen. Problem is once i set bounds, i can't swipe between pictures any more (unless the photo is zoomed in and in the middle somewhere so that no bound is encountered).
I think the movement/velocity (and swipe!) should be computed before bounds, and then reset afterwards to their current behavior if bounds were met (only reset movement/velocity, but keeping the computed swipe). What do you think?

One workaround is to not set bounds option, but compute and enforce bounds in the drag gesture callback (this is what the docs on swipe do basically, as they ignore the drag offset so it's equivalent to bounds set to 0 all around). Problem is if bounds aren't static then computation quickly adds up and performance may get a hit (didn't actually profile it but that's the direction it's headed).

Another workaround is to raise the swipe behavior to the container element (where there are no bounds but also nothing gets moved so it's like on the docs page with that square), but that might complicate other parts of the code - in my case resetting the zoom on the picture that flies off the screen on navigation.

However, i think the ideal case would be if swipe still works even when bounds are reached. What do you think?

Thanks for reporting this and the detailed explanation @steodor, that's much appreciated. I've made a fix attempt here #595. I'm now calculating swipe based on the raw movement. Let me know if it works out for you.

Hi @dbismut , thank you for the quick fix! It works very well, as you can see here: https://codesandbox.io/s/gesture-drag-forked-vycd92?file=/src/App.jsx - btw i like that i could fork the example with code from the branch so i could test it out, really nice touch!
I'll be waiting for the release then :) thanks again, and have a nice day!

Released 10.2.26!