Skip to content

Commit

Permalink
🐛 (@hzcore/gesture-catcher) fix mobile safari touch hijacking
Browse files Browse the repository at this point in the history
Webkit does not allow event.preventDefault() in dynamically added
handlers (i.e., a handler added to 'touchmove' after handling
a 'touchstart'), so we add a permanent 'touchmove' handler to get
around this.

webkit bug: https://bugs.webkit.org/show_bug.cgi?id=184250
based on: atlassian/react-beautiful-dnd#416
  • Loading branch information
lettertwo committed Aug 31, 2018
1 parent 9b45eb6 commit edd7714
Showing 1 changed file with 46 additions and 0 deletions.
46 changes: 46 additions & 0 deletions packages/behaviors/hzcore-gesture-catcher/src/TouchSensor.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ export default class TouchSensor {
)
: fromEvent(document, TOUCH_MOVE),
);
this.webkitHack = config.preventDefault ? new WebkitHack() : null;
}

touchStart: Callbag;
touchMove: Callbag;
touchEnd: Callbag;
webkitHack: ?WebkitHack = null;
gesturing: boolean = false;

state = (source: Callbag) => (start: 0, sink: Callbag) => {
Expand All @@ -40,6 +42,7 @@ export default class TouchSensor {
case TOUCH_START: {
if (this.gesturing) return talkback(1);
this.gesturing = true;
if (this.webkitHack) this.webkitHack.preventTouchMove();
return sink(1, data);
}
case TOUCH_MOVE: {
Expand All @@ -49,6 +52,7 @@ export default class TouchSensor {
case TOUCH_END: {
if (!this.gesturing) return talkback(1);
this.gesturing = false;
if (this.webkitHack) this.webkitHack.allowTouchMove();
return sink(1, data);
}
}
Expand All @@ -75,3 +79,45 @@ export default class TouchSensor {
};
}
}

// Webkit does not allow event.preventDefault() in dynamically added handlers
// (i.e., a handler added to 'touchmove' after handling a 'touchstart'),
// so we add a permanent 'touchmove' handler to get around this.
// webkit bug: https://bugs.webkit.org/show_bug.cgi?id=184250
// Original implementation: https://github.com/atlassian/react-beautiful-dnd/pull/416
class WebkitHack {
constructor() {
// Do nothing when server side rendering or no touch support.
if (typeof window !== 'undefined' && 'ontouchstart' in window) {
// Adding a persistent event handler.
// It can't be passive, otherwise we wouldn't
// be able to preventDefault().
window.addEventListener('touchmove', this.handleTouchMove, {
passive: false,
});
}
}

shouldPreventDefault: boolean = false;

destroy() {
if (typeof window === 'undefined') return;
window.removeEventListener('touchmove', this.handleTouchMove, {
passive: false,
});
}

handleTouchMove = (event: TouchEvent) => {
if (this.shouldPreventDefault && !event.defaultPrevented) {
event.preventDefault();
}
};

preventTouchMove() {
this.shouldPreventDefault = true;
}

allowTouchMove() {
this.shouldPreventDefault = false;
}
}

0 comments on commit edd7714

Please sign in to comment.