Skip to content

Commit 88b273c

Browse files
committed
[IMPL] useSwipe hook
1 parent 8ad256a commit 88b273c

4 files changed

Lines changed: 43 additions & 26 deletions

File tree

apps/react-tools-demo/src/markdown/useSwipe.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,23 @@ Hook to handle swipe gesture.
55

66
```tsx
77
export const UseSwipe = () => {
8-
return <div style={{ position: "relative", width: 400, height: 100, border: "1px solid lightgray" }}>
9-
<div style={{position: "absolute", backgroundColor: "lightgray", width: 400, height: 100}}></div>
8+
const divRef = useRef<HTMLDivElement>(null);
9+
useSwipe({
10+
target: divRef,
11+
onSwipe(e, direction, delta) {
12+
console.log(direction)
13+
delta.x >=0 && (divRef.current!.style.left = delta.x + "px");
14+
},
15+
onSwipeEnd(e, direction, delta) {
16+
divRef.current!.style.left = `${delta.x>330 ? "400" : "0"}px`
17+
},
18+
});
19+
const reset = () => {
20+
divRef.current!.style.left = "0";
21+
}
22+
return <div style={{ position: "relative", display: "flex", alignItems: "center", justifyContent: "center", width: 400, height: 100, border: "1px solid lightgray", overflow: "hidden", margin: "0 auto" }}>
23+
<button onClick={reset}>RESET</button>
24+
<div ref={divRef} style={{ position: "absolute", backgroundColor: "rgb(73 84 104)", zIndex: 100, inset: 0 }}><p>SWIPE</p></div>
1025
</div>
1126
}
1227
```
@@ -26,11 +41,11 @@ useSwipe({ target, onSwipeStart, onSwipe, onSwipeEnd, options }: UseSwipeProps):
2641
object
2742
> - __param.target__: _RefObject<Element>|Element_
2843
element on which attach swipe event.
29-
> - __param.onSwipeStart?__: _(e: PointerEvent) => void_
44+
> - __param.onSwipeStart?__: _(e: PointerEvent|TouchEvent) => void_
3045
callback that will be executed when swipe starts.
31-
> - __param.onSwipe?__: _(e: PointerEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void_
46+
> - __param.onSwipe?__: _(e: PointerEvent|TouchEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void_
3247
callback that will be executed when swipe moves.
33-
> - __param.onSwipeEnd?__: _(e: PointerEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void_
48+
> - __param.onSwipeEnd?__: _(e: PointerEvent|TouchEvent, direction: SwipeDirection, delta: { x: number, y: number }) => void_
3449
callback that will be executed when swipe ends.
3550
> - __param.options?__: _Object_
3651
object to set option for listener.

packages/react-tools/src/hooks/useSwipe.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import { useCallback, useRef } from "react";
22
import { SwipeDirection, UseSwipeProps, UseSwipeResult } from "../models";
33
import { useEventListener } from ".";
4+
import { isTouchEvent } from "..";
45

56
/**
67
* **`useSwipe`**: hook to handle swipe gesture.
78
* @param {UseSwipeProps} param - object
89
* @param {RefObject<Element>|Element} param.target - element on which attach swipe event.
9-
* @param {(e: PointerEvent) => void} [param.onSwipeStart] - callback that will be executed when swipe starts.
10-
* @param {(e: PointerEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void} [param.onSwipe] - callback that will be executed when swipe moves.
11-
* @param {(e: PointerEvent, direction: SwipeDirection, delta: { x: number, y: number }) => void} [param.onSwipeEnd] - callback that will be executed when swipe ends.
10+
* @param {(e: MouseEvent|TouchEvent) => void} [param.onSwipeStart] - callback that will be executed when swipe starts.
11+
* @param {(e: MouseEvent|TouchEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void} [param.onSwipe] - callback that will be executed when swipe moves.
12+
* @param {(e: MouseEvent|TouchEvent, direction: SwipeDirection, delta: { x: number, y: number }) => void} [param.onSwipeEnd] - callback that will be executed when swipe ends.
1213
* @param {Object} [param.options] - object to set option for listener.
1314
* @param {boolean} [param.options.passive=true] - if true, handler callback never calls _preventDefault_ method.
1415
* @param {threshold} [param.options.threshold=0] - a threshold value for swipe event.
1516
* @returns {UseSwipeResult} - callback that stops listener.
1617
*/
1718
export const useSwipe = ({ target, onSwipeStart, onSwipe, onSwipeEnd, options }: UseSwipeProps): UseSwipeResult => {
1819
const isThresholdExceeded = useRef<(diffX:number, diffY:number)=>boolean>((diffX, diffY) => Math.max(Math.abs(diffX), Math.abs(diffY)) >= (options?.threshold ?? 0));
19-
2020
const targetRef = useRef<EventTarget|null>();
2121
const getDirection = useRef<(diffX: number, diffY: number) => SwipeDirection>((diffX, diffY) => {
2222
if (!isThresholdExceeded.current(diffX, diffY)) {
@@ -49,28 +49,29 @@ export const useSwipe = ({ target, onSwipeStart, onSwipe, onSwipeEnd, options }:
4949
});
5050

5151
const stopPointerDown = useEventListener({
52-
type: "pointerdown",
52+
type: ["mousedown", "touchstart"],
5353
element: target,
54-
listener: useCallback((e: PointerEvent) => {
54+
listener: useCallback((e: TouchEvent|MouseEvent) => {
5555
isSwiping.current = true;
5656
targetRef.current = e.target;
5757
e.target && (e.target as HTMLElement).style.setProperty('touch-action', 'none')
5858
e.target && (e.target as HTMLElement).style.setProperty('-webkit-user-select', 'none')
5959
e.target && (e.target as HTMLElement).style.setProperty('-ms-user-select', 'none')
6060
e.target && (e.target as HTMLElement).style.setProperty('user-select', 'none')
61-
const { x, y } = (e.target as Element)?.getBoundingClientRect() ?? {x:0, y:0};
61+
const { x, y } = (e.target as Element)?.getBoundingClientRect() ?? { x: 0, y: 0 };
62+
const {clientX, clientY} = isTouchEvent(e) ? (e as TouchEvent).touches[0] : e as MouseEvent;
6263
coords.current = {
6364
target: {
6465
x,
6566
y
6667
},
6768
start: {
68-
x: e.clientX,
69-
y: e.clientY
69+
x: clientX,
70+
y: clientY
7071
},
7172
end: {
72-
x: e.clientX,
73-
y: e.clientY
73+
x: clientX,
74+
y: clientY
7475
}
7576
}
7677
!!onSwipeStart && onSwipeStart(e);
@@ -82,12 +83,13 @@ export const useSwipe = ({ target, onSwipeStart, onSwipe, onSwipeEnd, options }:
8283
});
8384

8485
const stopPointerMove = useEventListener({
85-
type: "pointermove",
86+
type: ["mousemove", "touchmove"],
8687
element: window,
87-
listener: useCallback((e: PointerEvent) => {
88+
listener: useCallback((e: MouseEvent|TouchEvent) => {
89+
const { clientX, clientY } = isTouchEvent(e) ? (e as TouchEvent).touches[0] : e as MouseEvent;
8890
coords.current.end = {
89-
x: e.clientX,
90-
y: e.clientY
91+
x: clientX,
92+
y: clientY
9193
}
9294
const diffX = coords.current.end.x - coords.current.start.x,
9395
diffY = coords.current.end.y - coords.current.start.y;
@@ -100,9 +102,9 @@ export const useSwipe = ({ target, onSwipeStart, onSwipe, onSwipeEnd, options }:
100102
});
101103

102104
const stopPointerUpCancel = useEventListener({
103-
type: ["pointerup", "pointercancel"],
105+
type: ["mouseup", "mouseleave", "touchend", "touchcancel"],
104106
element: window,
105-
listener: useCallback((e: PointerEvent) => {
107+
listener: useCallback((e: MouseEvent|TouchEvent) => {
106108
const diffX = coords.current.end.x - coords.current.start.x,
107109
diffY = coords.current.end.y - coords.current.start.y;
108110
isSwiping.current && !!onSwipeEnd && onSwipeEnd(e, getDirection.current(diffX, diffY), {x: diffX, y: diffY});

packages/react-tools/src/models/useSwipe.model.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ export interface UseSwipeProps {
66
/**Element swipable*/
77
target: RefObject<Element> | Element;
88
/**Callback that will be executed on swipe starts*/
9-
onSwipeStart?: (e: PointerEvent) => void;
9+
onSwipeStart?: (e: MouseEvent|TouchEvent) => void;
1010
/**Callback that will be executed on swipe moves*/
11-
onSwipe?: (e: PointerEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void;
11+
onSwipe?: (e: MouseEvent|TouchEvent, direction: SwipeDirection, delta: {x: number, y: number}) => void;
1212
/**Callback that will be executed on swipe ends*/
13-
onSwipeEnd?: (e: PointerEvent, direction: SwipeDirection, delta: { x: number, y: number }) => void;
13+
onSwipeEnd?: (e: MouseEvent|TouchEvent, direction: SwipeDirection, delta: { x: number, y: number }) => void;
1414
/**Options configurable for swipe listeners*/
1515
options?: {
1616
/**If true, listener never invokes _preventDefault_ method.*/

packages/react-tools/src/utils/isTouchEvent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ export const isTouchEvent = (event: SyntheticEvent | Event): boolean => {
1010
? window.TouchEvent
1111
? (event as SyntheticEvent).nativeEvent instanceof TouchEvent
1212
: "touches" in (event as SyntheticEvent).nativeEvent
13-
: event instanceof TouchEvent || event instanceof PointerEvent;
13+
: event instanceof TouchEvent;
1414
}

0 commit comments

Comments
 (0)