-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDragScroll.jsx
More file actions
124 lines (112 loc) · 3.34 KB
/
DragScroll.jsx
File metadata and controls
124 lines (112 loc) · 3.34 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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { useRef, useState, useEffect } from "react";
import "./dragScroll.css";
export default function DragScroll({
children,
gap = "20px",
height = "auto",
sensitivity = 1.3,
disableDragAbove = 2000,
scrollAmount = 300, // buttons scroll by 300px
showButtons = true,
showProgress = true,
className = "",
}) {
const container = useRef(null);
const [dragging, setDragging] = useState(false);
const [startX, setStartX] = useState(0);
const [scrollLeft, setScrollLeft] = useState(0);
const [progress, setProgress] = useState(0);
// Update progress bar
const updateProgress = () => {
const el = container.current;
const pct = el.scrollLeft / (el.scrollWidth - el.clientWidth);
setProgress(pct * 100);
};
useEffect(() => {
const el = container.current;
el.addEventListener("scroll", updateProgress);
return () => el.removeEventListener("scroll", updateProgress);
}, []);
const startDrag = (x) => {
setDragging(true);
setStartX(x);
setScrollLeft(container.current.scrollLeft);
container.current.classList.add("dragging");
};
const stopDrag = () => {
setDragging(false);
container.current.classList.remove("dragging");
};
const onMouseDown = (e) => {
if (window.innerWidth >= disableDragAbove) return;
startDrag(e.pageX);
};
const onMouseMove = (e) => {
if (!dragging) return;
container.current.scrollLeft =
scrollLeft - (e.pageX - startX) * sensitivity;
};
const onTouchStart = (e) => {
if (window.innerWidth >= disableDragAbove) return;
startDrag(e.touches[0].pageX);
};
const onTouchMove = (e) => {
if (!dragging) return;
container.current.scrollLeft =
scrollLeft - (e.touches[0].pageX - startX) * sensitivity;
};
// Scroll button actions
const scrollRight = () => {
container.current.scrollBy({ left: scrollAmount, behavior: "smooth" });
};
const scrollLeftFn = () => {
container.current.scrollBy({ left: -scrollAmount, behavior: "smooth" });
};
return (
<div className="container" style={{ position: "relative", width: "100%" }}>
{/* SCROLL PROGRESS BAR */}
{showProgress && (
<div className="scroll-progress">
<div
className="scroll-progress-inner"
style={{ width: `${progress}%` }}
></div>
</div>
)}
{/* LEFT BUTTON */}
{showButtons && (
<button className="scroll-btn left" onClick={scrollLeftFn}>
⟨
</button>
)}
{/* RIGHT BUTTON */}
{showButtons && (
<button className="scroll-btn right" onClick={scrollRight}>
⟩
</button>
)}
{/* MAIN DRAG-SCROLL AREA */}
<div
ref={container}
className={`drag-scroll ${className}`}
onMouseDown={onMouseDown}
onMouseMove={onMouseMove}
onMouseUp={stopDrag}
onMouseLeave={stopDrag}
onTouchStart={onTouchStart}
onTouchMove={onTouchMove}
onTouchEnd={stopDrag}
style={{
display: "flex",
overflowX: "auto",
gap,
height,
cursor: dragging ? "grabbing" : "grab",
scrollBehavior: "smooth",
}}
>
{children}
</div>
</div>
);
}