import React, { forwardRef, useImperativeHandle, useMemo, useRef } from 'react'; import { Platform } from 'react-native'; import { useAnimatedProps, useAnimatedStyle } from 'react-native-reanimated'; import { NativeViewGestureHandler } from 'react-native-gesture-handler'; import BottomSheetDraggableView from '../bottomSheetDraggableView'; import BottomSheetRefreshControl from '../bottomSheetRefreshControl'; import { useScrollHandler, useScrollableSetter, useBottomSheetInternal, useStableCallback, } from '../../hooks'; import { GESTURE_SOURCE, SCROLLABLE_DECELERATION_RATE_MAPPER, SCROLLABLE_STATE, SCROLLABLE_TYPE, } from '../../constants'; import { styles } from './styles'; export function createBottomSheetScrollableComponent( type: SCROLLABLE_TYPE, ScrollableComponent: any ) { return forwardRef((props, ref) => { // props const { // hooks focusHook, scrollEventsHandlersHook, // props customContentHeight, enableFooterMarginAdjustment = false, overScrollMode = 'never', keyboardDismissMode = 'interactive', showsVerticalScrollIndicator = true, style, refreshing, onRefresh, progressViewOffset, refreshControl, // events onScroll, onScrollBeginDrag, onScrollEndDrag, onContentSizeChange, ...rest }: any = props; //#region refs const nativeGestureRef = useRef(null); const refreshControlGestureRef = useRef(null); //#endregion //#region hooks const { scrollableRef, scrollableContentOffsetY, scrollHandler } = useScrollHandler( scrollEventsHandlersHook, onScroll, onScrollBeginDrag, onScrollEndDrag ); const { enableContentPanningGesture, animatedFooterHeight, animatedScrollableState, animatedContentHeight, enableDynamicSizing, } = useBottomSheetInternal(); //#endregion //#region variables const scrollableAnimatedProps = useAnimatedProps( () => ({ decelerationRate: SCROLLABLE_DECELERATION_RATE_MAPPER[animatedScrollableState.value], showsVerticalScrollIndicator: showsVerticalScrollIndicator ? animatedScrollableState.value === SCROLLABLE_STATE.UNLOCKED : showsVerticalScrollIndicator, }), [showsVerticalScrollIndicator] ); //#endregion //#region callbacks const handleContentSizeChange = useStableCallback( (contentWidth: number, contentHeight: number) => { if (enableDynamicSizing) { animatedContentHeight.value = (customContentHeight ? customContentHeight : contentHeight) + (enableFooterMarginAdjustment ? animatedFooterHeight.value : 0); } if (onContentSizeChange) { onContentSizeChange(contentWidth, contentHeight); } } ); //#endregion //#region styles const containerAnimatedStyle = useAnimatedStyle( () => ({ marginBottom: enableFooterMarginAdjustment ? animatedFooterHeight.value : 0, }), [enableFooterMarginAdjustment] ); const containerStyle = useMemo(() => { return enableFooterMarginAdjustment ? [ ...(style ? ('length' in style ? style : [style]) : []), containerAnimatedStyle, ] : style; }, [enableFooterMarginAdjustment, style, containerAnimatedStyle]); //#endregion //#region effects // @ts-ignore useImperativeHandle(ref, () => scrollableRef.current); useScrollableSetter( scrollableRef, type, scrollableContentOffsetY, onRefresh !== undefined, focusHook ); //#endregion //#region render if (Platform.OS === 'android') { const scrollableContent = ( ); return ( {onRefresh ? ( {scrollableContent} ) : ( scrollableContent )} ); } return ( ); //#endregion }); }