1- import React , { useState , useRef , ReactNode , useEffect , FC , useCallback } from 'react' ;
1+ import React , { FC , ReactNode , useEffect , useRef , useState } from 'react' ;
22import styles from './BottomSheet.module.css'
3- import { useMediaQuery } from "react-responsive" ;
4- import { set } from "ol/transform" ;
53
64interface BottomSheetProps {
75 children ?: ReactNode ;
86}
97
10- const BottomSheet : FC < BottomSheetProps > = ( { children } ) => {
8+ const BottomSheet : FC < BottomSheetProps > = ( { children} ) => {
9+ const [ isMouseDownOnBottomSheet , setMouseDownOnBottomSheet ] = useState ( false )
1110 const [ isDragging , setIsDragging ] = useState ( false )
1211 const [ childrenHeight , setChildrenHeight ] = useState ( - 1 )
1312 const offsetYRef = useRef ( 0 )
@@ -17,30 +16,40 @@ const BottomSheet: FC<BottomSheetProps> = ({ children }) => {
1716 const defaultHeight = useRef ( 0 ) ;
1817
1918 const setHeight = ( y : number ) => {
20- if ( bottomSheetRef . current )
19+ if ( bottomSheetRef . current )
2120 bottomSheetRef . current . style . top = `${ y } px`
2221 }
2322
2423 const handleMouseDown = ( e : MouseEvent | TouchEvent ) => {
25- if ( ! bottomSheetRef . current ) return
24+ if ( ! bottomSheetRef . current ) return
2625
27- const clickInside = e . target instanceof Node && bottomSheetRef . current . contains ( e . target )
26+ const clientY = 'touches' in e ? e . touches [ 0 ] . clientY : e . clientY
27+ // negative value means above the edge
28+ offsetYRef . current = clientY - ( bottomSheetRef . current . getBoundingClientRect ( ) . top || 0 )
29+ const clickInside = offsetYRef . current >= 0 // e.target instanceof Node && bottomSheetRef.current.contains(e.target)
2830 if ( ! clickInside ) {
31+ // TODO: why hiding bottom sheet does not work with mouse?
2932 setHeight ( window . innerHeight - minHeight )
3033 return
3134 }
3235
33- const clientY = 'touches' in e ? e . touches [ 0 ] . clientY : e . clientY
34- setIsDragging ( true )
35- offsetYRef . current = clientY - ( bottomSheetRef . current . getBoundingClientRect ( ) . top || 0 )
36+ setMouseDownOnBottomSheet ( true )
3637 }
3738
3839 const handleMouseMove = ( e : MouseEvent | TouchEvent ) => {
39- if ( bottomSheetRef . current && isDragging ) {
40+ const clickInsideChildren = e . target instanceof Node && childrenRef . current ?. contains ( e . target )
41+ if ( clickInsideChildren && childrenHeight > defaultHeight . current ) {
42+ // if scrolling avoid dragging
43+ return
44+ }
45+
46+ if ( bottomSheetRef . current && isMouseDownOnBottomSheet ) {
47+ setIsDragging ( true )
48+
4049 const clientY = 'touches' in e ? e . touches [ 0 ] . clientY : e . clientY
4150 let y = clientY - offsetYRef . current
42- if ( y < 0 ) y = 0 // top border
43- else if ( y > ( window . innerHeight - minHeight ) ) y = window . innerHeight - minHeight
51+ if ( y < 0 ) y = 0 // top border
52+ else if ( y > ( window . innerHeight - minHeight ) ) y = window . innerHeight - minHeight
4453
4554 setHeight ( y )
4655
@@ -50,13 +59,37 @@ const BottomSheet: FC<BottomSheetProps> = ({ children }) => {
5059 }
5160 const handleTouchStart = ( e : MouseEvent | TouchEvent ) => handleMouseDown ( e )
5261 const handleTouchMove = ( e : MouseEvent | TouchEvent ) => handleMouseMove ( e )
53- const handleMouseUp = ( ) => setIsDragging ( false )
62+ const handleMouseUp = ( e : MouseEvent | TouchEvent ) => {
63+ const clickInsideChildren = e . target instanceof Node && childrenRef . current ?. contains ( e . target )
64+ if ( clickInsideChildren ) return
65+ if ( ! isMouseDownOnBottomSheet ) return
66+
67+ if ( bottomSheetRef . current && ! isDragging ) {
68+ // use changedTouches as e.touches[0] is empty on iOS (does it make sense as the 'touch gesture' was already finished?)
69+ const clientY = 'changedTouches' in e ? e . changedTouches [ 0 ] ?. clientY : e . clientY
70+ let y = clientY - offsetYRef . current
71+
72+ // alert('mouseUp, y=' + clientY + '-' + offsetYRef.current + ', ' + (window.innerHeight - defaultHeight.current))
73+ // if clicked
74+ if ( y > ( window . innerHeight - defaultHeight . current ) || y <= 0 ) {
75+ // ... and closed (or max) then medium size
76+ setHeight ( window . innerHeight - defaultHeight . current )
77+ } else {
78+ // ... and medium then maximum size
79+ setHeight ( 0 )
80+ }
81+ }
82+ setIsDragging ( false )
83+ setMouseDownOnBottomSheet ( false )
84+
85+ // prevent us from clicking on elements in the bottom pane directly after we e.g. maximized it (happened only on Android)
86+ e . preventDefault ( )
87+ }
5488
5589 useEffect ( ( ) => {
5690 if ( childrenRef . current ) {
57- if ( defaultHeight . current <= 0 )
58- defaultHeight . current = childrenRef . current . offsetHeight + 80 /* +80 for one routing result */
59- console . log ( "height:" + defaultHeight . current )
91+ if ( defaultHeight . current <= 0 )
92+ defaultHeight . current = childrenRef . current . offsetHeight + 80 // TODO use dynamic value instead of 80 for one routing result
6093 setHeight ( window . innerHeight - defaultHeight . current )
6194 }
6295 } , [ ] ) ;
@@ -75,7 +108,7 @@ const BottomSheet: FC<BottomSheetProps> = ({ children }) => {
75108 document . removeEventListener ( 'mousemove' , handleMouseMove )
76109 document . removeEventListener ( 'mouseup' , handleMouseUp )
77110 } ;
78- } , [ isDragging ] )
111+ } , [ isMouseDownOnBottomSheet , isDragging ] )
79112
80113 return (
81114 < div ref = { bottomSheetRef } className = { styles . bottomSheet } >
@@ -84,12 +117,25 @@ const BottomSheet: FC<BottomSheetProps> = ({ children }) => {
84117 onMouseDown = { ( e : React . MouseEvent ) => handleMouseDown ( e as any ) }
85118 onTouchStart = { ( e : React . TouchEvent ) => handleTouchStart ( e as any ) }
86119 >
87- < span style = { { width : '18px' , height : '4px' , borderRadius : '99px' , backgroundColor : 'rgb(221, 221, 221)' , transform : 'translateX(2px) rotate(0deg)' } } > </ span >
88- < span style = { { width : '18px' , height : '4px' , borderRadius : '99px' , backgroundColor : 'rgb(221, 221, 221)' , transform : 'translateX(-2px) rotate(0deg)' } } > </ span >
89-
90- { /*<span style={{}} onClick={() => setHeight(window.innerHeight - minHeight)}>X</span>*/ }
120+ < span style = { {
121+ width : '18px' ,
122+ height : '4px' ,
123+ borderRadius : '99px' ,
124+ backgroundColor : 'rgb(221, 221, 221)' ,
125+ transform : 'translateX(2px) rotate(0deg)'
126+ } } > </ span >
127+ < span style = { {
128+ width : '18px' ,
129+ height : '4px' ,
130+ borderRadius : '99px' ,
131+ backgroundColor : 'rgb(221, 221, 221)' ,
132+ transform : 'translateX(-2px) rotate(0deg)'
133+ } } > </ span >
91134 </ div >
92- < div ref = { childrenRef } style = { childrenHeight > defaultHeight . current ? { overflowY : 'scroll' , height : childrenHeight + 'px' } : { } } >
135+ < div ref = { childrenRef } style = { childrenHeight > defaultHeight . current ? {
136+ overflowY : 'scroll' ,
137+ height : childrenHeight + 'px'
138+ } : { } } >
93139 { children }
94140 </ div >
95141 </ div >
0 commit comments