import { forwardRef } from 'react'; import Animated, { type WithSpringConfig, type WithTimingConfig, withSpring, withTiming, Easing, } from 'react-native-reanimated'; import { Platform } from 'react-native'; import { TrueSheet } from '../TrueSheet'; import type { TrueSheetProps, PositionChangeEvent } from '../TrueSheet.types'; import { useReanimatedTrueSheet } from './ReanimatedTrueSheetProvider'; import { useReanimatedPositionChangeHandler } from './useReanimatedPositionChangeHandler'; const SPRING_CONFIG: WithSpringConfig = { damping: 500, stiffness: 1000, mass: 3, overshootClamping: true, }; const TIMING_CONFIG: WithTimingConfig = { duration: 300, easing: Easing.bezier(0.25, 0.1, 0.25, 1), }; interface ReanimatedTrueSheetProps extends TrueSheetProps { /** * Worklet version of `onPositionChange` * * @see {@link TrueSheetProps.onPositionChange} */ onPositionChange?: TrueSheetProps['onPositionChange']; } // Create animated version of TrueSheet const AnimatedTrueSheet = Animated.createAnimatedComponent(TrueSheet); /** * Reanimated-enabled version of TrueSheet that automatically syncs position with the provider's shared value. * Must be used within a ReanimatedTrueSheetProvider. * * NOTE: `onPositionChange` is now under UI thread. * Make sure you add `worklet` if you want to override this. * * @example * ```tsx * import { ReanimatedTrueSheet, ReanimatedTrueSheetProvider } from '@lodev09/react-native-true-sheet' * * function MyScreen() { * const sheetRef = useRef(null) * * return ( * * * * Sheet Content * * * * ) * } * ``` */ export const ReanimatedTrueSheet = forwardRef((props, ref) => { const { onPositionChange, ...rest } = props; const { animatedPosition, animatedIndex, animatedDetent } = useReanimatedTrueSheet(); const positionChangeHandler = useReanimatedPositionChangeHandler((payload) => { 'worklet'; if (payload.realtime) { // Update directly when we have real-time values (during drag or animation tracking) animatedPosition.value = payload.position; animatedIndex.value = payload.index; animatedDetent.value = payload.detent; } else { // Animate position, index, and detent when not real-time if (Platform.OS === 'android') { animatedPosition.value = withTiming(payload.position, TIMING_CONFIG); animatedIndex.value = withTiming(payload.index, TIMING_CONFIG); animatedDetent.value = withTiming(payload.detent, TIMING_CONFIG); } else { animatedPosition.value = withSpring(payload.position, SPRING_CONFIG); animatedIndex.value = withSpring(payload.index, SPRING_CONFIG); animatedDetent.value = withSpring(payload.detent, SPRING_CONFIG); } } onPositionChange?.({ nativeEvent: payload } as PositionChangeEvent); }); return ; });