-
Notifications
You must be signed in to change notification settings - Fork 169
Expand file tree
/
Copy pathuseScrollDrag.ts
More file actions
86 lines (76 loc) · 2.4 KB
/
useScrollDrag.ts
File metadata and controls
86 lines (76 loc) · 2.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import raf from '@rc-component/util/lib/raf';
import * as React from 'react';
function smoothScrollOffset(offset: number) {
return Math.floor(offset ** 0.5);
}
export function getPageXY(
e: React.MouseEvent | React.TouchEvent | MouseEvent | TouchEvent,
horizontal: boolean,
) {
const obj = 'touches' in e ? e.touches[0] : e;
return obj[horizontal ? 'pageX' : 'pageY'] - window[horizontal ? 'scrollX' : 'scrollY'];
}
export default function useScrollDrag(
inVirtual: boolean,
componentRef: React.RefObject<HTMLElement>,
onScrollOffset: (offset: number) => void,
) {
React.useEffect(() => {
const ele = componentRef.current;
if (inVirtual && ele) {
let mouseDownLock = false;
let rafId: number;
let offset: number;
const stopScroll = () => {
raf.cancel(rafId);
};
const continueScroll = () => {
stopScroll();
rafId = raf(() => {
onScrollOffset(offset);
continueScroll();
});
};
const onMouseDown = (e: MouseEvent) => {
// Skip if nest List has handled this event
const event = e as MouseEvent & {
_virtualHandled?: boolean;
};
if (!event._virtualHandled) {
event._virtualHandled = true;
mouseDownLock = true;
}
};
const onMouseUp = () => {
mouseDownLock = false;
stopScroll();
};
const onMouseMove = (e: MouseEvent) => {
if (mouseDownLock) {
const mouseY = getPageXY(e, false);
const { top, bottom } = ele.getBoundingClientRect();
if (mouseY <= top) {
const diff = top - mouseY;
offset = -smoothScrollOffset(diff);
continueScroll();
} else if (mouseY >= bottom) {
const diff = mouseY - bottom;
offset = smoothScrollOffset(diff);
continueScroll();
} else {
stopScroll();
}
}
};
ele.addEventListener('mousedown', onMouseDown);
ele.ownerDocument.addEventListener('mouseup', onMouseUp);
ele.ownerDocument.addEventListener('mousemove', onMouseMove);
return () => {
ele.removeEventListener('mousedown', onMouseDown);
ele.ownerDocument.removeEventListener('mouseup', onMouseUp);
ele.ownerDocument.removeEventListener('mousemove', onMouseMove);
stopScroll();
};
}
}, [inVirtual]);
}