11import { useState , useEffect , useRef } from 'react' ;
22
3- export const useModalDrag = ( sheetRef , scrollRef , headerRef , onClose ) => {
3+ export const useModalDrag = ( sheetRef , scrollRef , onClose ) => {
44 const [ translateY , setTranslateY ] = useState ( 0 ) ;
55 const [ isDragging , setIsDragging ] = useState ( false ) ;
6+
67 const startYRef = useRef ( 0 ) ;
78 const lastYRef = useRef ( 0 ) ;
8- const dragStartedOnHeaderRef = useRef ( false ) ;
99
1010 const onTouchStart = ( e ) => {
11- if ( ! sheetRef . current || ! headerRef . current ) return ;
11+ if ( ! sheetRef . current ) return ;
1212
13- // Check if touch started on the header
1413 const touch = e . touches ? e . touches [ 0 ] : e ;
15- const headerRect = headerRef . current . getBoundingClientRect ( ) ;
16- const touchedHeader = touch . clientY >= headerRect . top && touch . clientY <= headerRect . bottom ;
14+ const scrollEl = scrollRef . current ;
1715
18- if ( ! touchedHeader ) {
19- dragStartedOnHeaderRef . current = false ;
20- return ;
21- }
16+ // Only allow drag when content is fully scrolled to top
17+ const scrollAtTop = ! scrollEl || scrollEl . scrollTop <= 0 ;
18+ if ( ! scrollAtTop ) return ;
2219
23- dragStartedOnHeaderRef . current = true ;
2420 startYRef . current = touch . clientY ;
2521 lastYRef . current = touch . clientY ;
2622 setIsDragging ( true ) ;
2723 } ;
2824
2925 const onTouchMove = ( e ) => {
30- if ( ! isDragging || ! sheetRef . current || ! dragStartedOnHeaderRef . current ) return ;
26+ if ( ! isDragging || ! sheetRef . current ) return ;
3127
3228 const touch = e . touches ? e . touches [ 0 ] : e ;
3329 const deltaY = touch . clientY - startYRef . current ;
34- lastYRef . current = touch . clientY ;
3530
36- const scrollEl = scrollRef . current ;
37- const scrollAtTop = ! scrollEl || scrollEl . scrollTop <= 0 ;
38-
39- if ( deltaY > 0 && scrollAtTop ) {
40- setTranslateY ( deltaY ) ;
41- if ( e . cancelable ) e . preventDefault ( ) ;
42- } else if ( deltaY < 0 && translateY > 0 ) {
43- setTranslateY ( Math . max ( 0 , deltaY ) ) ;
31+ // Only drag downward, and damp movement to reduce jitter
32+ if ( deltaY > 0 ) {
33+ setTranslateY ( deltaY * 0.9 ) ;
4434 if ( e . cancelable ) e . preventDefault ( ) ;
4535 }
4636 } ;
4737
4838 const onTouchEnd = ( ) => {
49- if ( ! isDragging || ! dragStartedOnHeaderRef . current ) return ;
39+ if ( ! isDragging ) return ;
40+
5041 setIsDragging ( false ) ;
51- dragStartedOnHeaderRef . current = false ;
5242
5343 const delta = lastYRef . current - startYRef . current ;
54- const threshold = Math . min ( 140 , window . innerHeight * 0.18 ) ;
44+ const threshold = window . innerHeight * 0.50 ; // must drag half screen to close
45+
5546 if ( delta > threshold ) {
56- // Let the parent handle the close with animation
47+ // Trigger animated close via parent, not instant close
5748 onClose ( ) ;
5849 } else {
5950 setTranslateY ( 0 ) ;
6051 }
6152 } ;
6253
54+ // Use pointer events for stability
6355 useEffect ( ( ) => {
6456 const el = sheetRef . current ;
6557 if ( ! el ) return ;
6658
67- const onPointerDown = ( e ) => {
59+ const handlePointerDown = ( e ) => {
6860 if ( window . innerWidth >= 768 ) return ;
69- el . setPointerCapture ?. ( e . pointerId ) ;
7061 onTouchStart ( e ) ;
7162 } ;
72- const onPointerMove = ( e ) => {
63+ const handlePointerMove = ( e ) => {
7364 if ( ! isDragging ) return ;
65+ lastYRef . current = e . clientY ;
7466 onTouchMove ( e ) ;
7567 } ;
76- const onPointerUp = ( e ) => {
68+ const handlePointerUp = ( ) => {
7769 if ( ! isDragging ) return ;
78- onTouchEnd ( e ) ;
79- el . releasePointerCapture ?. ( e . pointerId ) ;
70+ onTouchEnd ( ) ;
8071 } ;
8172
82- el . addEventListener ( ' pointerdown' , onPointerDown ) ;
83- window . addEventListener ( ' pointermove' , onPointerMove ) ;
84- window . addEventListener ( ' pointerup' , onPointerUp ) ;
73+ el . addEventListener ( " pointerdown" , handlePointerDown ) ;
74+ window . addEventListener ( " pointermove" , handlePointerMove ) ;
75+ window . addEventListener ( " pointerup" , handlePointerUp ) ;
8576
8677 return ( ) => {
87- el . removeEventListener ( ' pointerdown' , onPointerDown ) ;
88- window . removeEventListener ( ' pointermove' , onPointerMove ) ;
89- window . removeEventListener ( ' pointerup' , onPointerUp ) ;
78+ el . removeEventListener ( " pointerdown" , handlePointerDown ) ;
79+ window . removeEventListener ( " pointermove" , handlePointerMove ) ;
80+ window . removeEventListener ( " pointerup" , handlePointerUp ) ;
9081 } ;
9182 } , [ isDragging ] ) ;
9283
@@ -96,4 +87,4 @@ export const useModalDrag = (sheetRef, scrollRef, headerRef, onClose) => {
9687 onTouchMove,
9788 onTouchEnd
9889 } ;
99- } ;
90+ } ;
0 commit comments