UNPKG

react-native-reanimated-bottomsheet

Version:

A configurable and performant BottomSheet widget for React Native apps built using Reanimated v2 API.

123 lines (110 loc) 3.65 kB
/* eslint-disable react-hooks/rules-of-hooks */ import React, { useEffect, useImperativeHandle } from 'react'; import Animated, { useSharedValue, withSpring, useAnimatedStyle, useAnimatedGestureHandler } from 'react-native-reanimated'; import { StyleSheet } from 'react-native'; import { PanGestureHandler } from 'react-native-gesture-handler'; var GESTURE; (function (GESTURE) { GESTURE[GESTURE["DRAGGING_UP"] = 0] = "DRAGGING_UP"; GESTURE[GESTURE["DRAGGING_DOWN"] = 1] = "DRAGGING_DOWN"; })(GESTURE || (GESTURE = {})); const defaultSpringConfig = { damping: 50, mass: 0.5, stiffness: 121.6, restSpeedThreshold: 0.3 }; export default /*#__PURE__*/React.forwardRef(({ initialSnap = 0, snapPoints, renderContent, renderHeader, enabledGestureInteraction = true, hasFixedHeight = false, springConfig = defaultSpringConfig }, ref) => { const maxHeight = snapPoints[snapPoints.length - 1]; const defaultHeight = initialSnap ? snapPoints[initialSnap] : snapPoints[0]; const sheetHeight = hasFixedHeight ? useSharedValue(0) : useSharedValue(defaultHeight); const gestureDirection = useSharedValue(GESTURE.DRAGGING_UP); useImperativeHandle(ref, () => ({ close: () => { sheetHeight.value = withSpring(0, defaultSpringConfig); }, snapTo: index => { if (index < snapPoints.length - 1) { sheetHeight.value = withSpring(snapPoints[index], defaultSpringConfig); } } })); useEffect(() => { if (hasFixedHeight) { sheetHeight.value = withSpring(snapPoints[0], defaultSpringConfig); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const getNearestSnap = () => { 'worklet'; let neearestSnapPoint = maxHeight; for (let snapIndex in snapPoints) { const numberedSnapIndex = Number(snapIndex); if (sheetHeight.value - snapPoints[snapIndex] < 0) { if (gestureDirection.value === GESTURE.DRAGGING_UP) { neearestSnapPoint = snapPoints[snapIndex]; } else { const nearestSnapIndex = numberedSnapIndex - 1 >= 0 ? numberedSnapIndex - 1 : numberedSnapIndex; neearestSnapPoint = snapPoints[nearestSnapIndex]; } break; } } return neearestSnapPoint; }; const adjustSnap = _ => { 'worklet'; const nearestSnapPoint = getNearestSnap(); sheetHeight.value = withSpring(nearestSnapPoint, springConfig); }; const gestureHandler = useAnimatedGestureHandler({ onStart: (_, ctx) => { ctx.startY = sheetHeight.value; }, onActive: (event, ctx) => { if (event.velocityY > 0) { gestureDirection.value = GESTURE.DRAGGING_DOWN; } else if (event.velocityY < 0) { gestureDirection.value = GESTURE.DRAGGING_UP; } sheetHeight.value = ctx.startY + event.translationY * -1; }, onEnd: adjustSnap }); const animatedStyle = useAnimatedStyle(() => ({ height: sheetHeight.value })); return /*#__PURE__*/React.createElement(PanGestureHandler, { enabled: enabledGestureInteraction, onGestureEvent: gestureHandler }, /*#__PURE__*/React.createElement(Animated.View, { style: [styles.sheetContainer, animatedStyle] }, /*#__PURE__*/React.createElement(Animated.View, { style: styles.sheetInnerContainer }, renderHeader(), renderContent()))); }); const styles = StyleSheet.create({ sheetContainer: { width: '100%', position: 'absolute', bottom: 0, height: 20, borderRadius: 4 }, sheetInnerContainer: { flex: 1, shadowOpacity: 0.5, shadowOffset: { height: -1, width: 0 } } }); //# sourceMappingURL=index.js.map