import { useCallback , useContext , useEffect , useRef } from "react" ; import { ModalGestureContext } from "@react-navigation/stack" ; import type { FlatList , NativeScrollEvent , NativeSyntheticEvent , ScrollView , SectionList , VirtualizedList , } from "react-native" ; const scrollToTop = ( scrollableRef ) => { if ( ! scrollableRef . current ) { return ; } if ( "scrollToOffset" in scrollableRef . current ) { ( scrollableRef . current as FlatList ) . scrollToOffset ( { animated : false , offset : 0 , } ) ; return ; } if ( "scrollTo" in scrollableRef . current ) { ( scrollableRef . current as ScrollView ) . scrollTo ( { animated : false , y : 0 , } ) ; return ; } if ( "scrollTo" in scrollableRef . current ) { ( scrollableRef . current as SectionList ) . scrollToLocation ( { animated : false , itemIndex : 0 , sectionIndex : 0 , viewPosition : 0 , viewOffset : 1000 , } ) ; return ; } if ( "scrollTo" in scrollableRef . current ) { ( scrollableRef . current as VirtualizedList < any > ) . scrollToOffset ( { animated : false , offset : 0 , } ) ; return ; } } ; export const useScrollableModalGestureInteraction = ( scrollableRef ) => { const context = useContext ( ModalGestureContext ) ; if ( ! context ) { throw new Error ( "Couldn't find values for modal gesture. Are you inside a screen in Modal Stack?" ) ; } const { modalTranslateY , scrollableGestureRef } = context ; const lockScrolling = useRef ( true ) ; const setLockScrolling = useCallback ( ( value ) => { lockScrolling . current = value > 0 ; } , [ lockScrolling ] ) ; const setOffset = useCallback ( ( value ) => { modalTranslateY . setOffset ( - value ) ; } , [ modalTranslateY ] ) ; const handleOnBeginDrag = useCallback ( ( { nativeEvent : { contentOffset : { y } , } , } ) => { if ( modalTranslateY . _value === 0 ) { setLockScrolling ( 0 ) ; } setOffset ( y ) ; } , [ setLockScrolling , setOffset , modalTranslateY ] ) ; const handleOnScroll = useCallback ( ( { nativeEvent : { contentOffset : { y } , } , } ) => { if ( y <= 0 || lockScrolling . current ) { scrollToTop ( scrollableRef ) ; } } , [ ] ) ; const handleOnEndDrag = useCallback ( ( { nativeEvent : { contentOffset : { y } , } , } ) => { setOffset ( y ) ; } , [ setOffset ] ) ; useEffect ( ( ) => { const listener = modalTranslateY . addListener ( ( { value } ) => setLockScrolling ( value ) ) ; return ( ) => { modalTranslateY . removeListener ( listener ) ; } ; } , [ modalTranslateY , setLockScrolling ] ) ; return { scrollableGestureRef , handleOnScroll , handleOnEndDrag : handleOnEndDrag , handleOnBeginDrag : handleOnBeginDrag , } ; } ;