useDragToClose.tsx48 lines · main
1import React, { useCallback } from 'react'
2
3/**
4 * Custom hook to enable closing bottom drawers by dragging down.
5 */
6const useDragToClose = ({
7 onClose,
8 threshold = 100,
9}: {
10 onClose: Function
11 threshold?: number
12}) => {
13 const [startY, setStartY] = React.useState(0)
14 const [currentY, setCurrentY] = React.useState(0)
15 const ref = React.useRef<HTMLDivElement>(null)
16
17 const handleTouchStart = useCallback(
18 (e: React.TouchEvent<HTMLDivElement>) => {
19 setStartY(e.touches[0].clientY)
20 },
21 [setStartY]
22 )
23
24 const handleTouchMove = useCallback(
25 (e: React.TouchEvent<HTMLDivElement>) => {
26 setCurrentY(e.touches[0].clientY)
27 const translateY = currentY - startY
28 if (translateY > 0 && ref.current) {
29 ref.current.style.transform = `translateY(${translateY}px)`
30 }
31 },
32 [setCurrentY, startY, currentY]
33 )
34
35 const handleTouchEnd = useCallback(() => {
36 if (currentY - startY > threshold) {
37 onClose()
38 } else if (ref.current) {
39 ref.current.style.transform = 'translateY(0)'
40 }
41 setStartY(0)
42 setCurrentY(0)
43 }, [setStartY, setCurrentY, startY, currentY])
44
45 return { ref, handleTouchStart, handleTouchMove, handleTouchEnd }
46}
47
48export default useDragToClose