use-gesture icon indicating copy to clipboard operation
use-gesture copied to clipboard

useDrag is stuck on iOS when navigating between pages

Open WartClaes opened this issue 4 years ago • 8 comments

Describe the bug When using the swipe gestures to go backwards/forwards in your browser history it is possible to break the useDrag functionality. This occurs when you initiate the gesture on an element which is bound to useDrag.

  • open https://trbo.be/bugs/use-gesture/ on an iOS device
  • navigate to other webpage
  • go back
  • swipe to go forward with your finger on the blue block.
  • when you come back to the demo again, the dragging is stuck.

It happens because iOS doesn't refresh the page when going back, but rather uses a cached version.

The workaround I use in our codebase now is to listen on the visibilitychange event and call the cancel function provided by the gesture state.

Sandbox or Video

  • demo: https://trbo.be/bugs/use-gesture/
  • github: https://github.com/WartClaes/use-gesture-drag-issue

(I used the demo from the website to reproduce the issue, but it is unrelated to the usage of @react-spring/web)

Information:

  • React Use Gesture version: 9.1.3 (but also on older versions)
  • Device: tested on iPhone Xs and iPhone 12
  • OS: iOS 14, iOS 15
  • Browser: Safari

Checklist:

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

WartClaes avatar Sep 13 '21 07:09 WartClaes

It seems this package is not handling the lostpointercapture events? Might this be the reason?

https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/lostpointercapture_event

ziriax avatar Sep 13 '21 13:09 ziriax

Can you try upgrading to @use-gesture/react which is in fact v10?

dbismut avatar Sep 13 '21 13:09 dbismut

I updated to @use-gesture/react and the issue is still there.

Both repo and demo are updated

WartClaes avatar Sep 14 '21 06:09 WartClaes

Hi, indeed I can reproduce the issue on the docs website. Thanks for bringing that up.

I'm not exactly sure how to fix this yet: the issue is not so much about pointercancel (which is handled by the lib) or lostpointercapture, as those events don't seem to fire when starting the swipe forward or swipe back (which IMO is what we need).

I believe there might be a workaround with using touch events and preventing default ({ pointer: { touch: true }, preventDefault: true }) that should completely disable the swipe gesture in Safari.

If you have any hints at how I could solve this that would be great!

dbismut avatar Sep 14 '21 10:09 dbismut

I had an issue on Android where pointercancel was being fired when I didn't expect it to, and seemed to resolve it by just using { pointer: { touch: true }.

jzombie avatar Oct 31 '21 15:10 jzombie

@jzombie very likely you didn't properly set touch-action on your draggable element as mentioned in the docs.

dbismut avatar Oct 31 '21 17:10 dbismut

I did, actually. Noticed it on my Android device, then used BrowserStack to do some testing with as well, and noticed it happening on some devices, but not others, using the same Chrome version. It might be related to some other specifics of my implementation, though, but all I know is using the touch events resolved it, and it is consistent on iOS as well.

Just very happy the touch events worked out.

jzombie avatar Oct 31 '21 17:10 jzombie

I came across this reddit thread: https://www.reddit.com/r/learnjavascript/comments/wyzit6/detect_ios_safari_backforward_gesture_with/

And the Redditor u/FabianDR makes an interesting observation that ontouchend doesn't fire when navigating forwards - possibly leaving the gesture in a broken state.

Edit: Really odd iOS behavior but if you fully navigate away on a drag forwards:

  • pointerup and touchend never fire

If you backout of a forward navigation halfway through

  • pointerup and touchend are skipped
  • But on next pointerdown just a touchend is fired beforehand (missing the pointerup)

shalanah avatar Apr 03 '24 22:04 shalanah