1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
import React, {Fragment, ReactText, useEffect, useRef, useState} from 'react';
import {
Modal,
StyleSheet,
TouchableWithoutFeedback,
View,
ViewProps,
} from 'react-native';
import Animated from 'react-native-reanimated';
import BottomSheet from 'reanimated-bottom-sheet';
import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
interface BottomDrawerProps extends ViewProps {
initialSnapPosition?: ReactText;
isOpen: boolean;
setIsOpen: (open: boolean) => void;
showHeader: boolean;
}
// More examples here:
// https://github.com/osdnk/react-native-reanimated-bottom-sheet/tree/master/Example
const BottomDrawer: React.FC<BottomDrawerProps> = (props) => {
const {isOpen, setIsOpen, showHeader, initialSnapPosition} = props;
const drawerRef = useRef<BottomSheet>(null);
const [modalVisible, setModalVisible] = useState(isOpen);
const bgAlpha = new Animated.Value(isOpen ? 1 : 0);
useEffect(() => {
if (isOpen) {
setModalVisible(true);
} else {
bgAlpha.setValue(0);
drawerRef.current && drawerRef.current.snapTo(1);
}
}, [isOpen]);
const renderContent = () => {
return <View>{props.children}</View>;
};
const renderHeader = () => {
return showHeader ? (
<View style={styles.header}>
<View style={styles.panelHeader}>
<View style={styles.panelHandle} />
</View>
</View>
) : (
<Fragment />
);
};
return (
<Modal
transparent
visible={modalVisible}
onShow={() => {
drawerRef.current && drawerRef.current.snapTo(0);
}}>
<BottomSheet
ref={drawerRef}
snapPoints={[initialSnapPosition ?? '30%', 0]}
initialSnap={1}
renderContent={renderContent}
renderHeader={renderHeader}
enabledContentGestureInteraction={false}
callbackNode={bgAlpha}
onCloseEnd={() => {
setModalVisible(false);
setIsOpen(false);
}}
/>
<TouchableWithoutFeedback
onPress={() => {
setIsOpen(false);
}}>
<Animated.View
style={[
styles.backgroundView,
{
backgroundColor: Animated.interpolateColors(bgAlpha, {
inputRange: [0, 1],
outputColorRange: ['rgba(0,0,0,0.3)', 'rgba(0,0,0,0)'],
}),
},
]}
/>
</TouchableWithoutFeedback>
</Modal>
);
};
const styles = StyleSheet.create({
header: {
backgroundColor: '#f7f5eee8',
shadowColor: '#000000',
paddingTop: 20,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
},
panelHeader: {
alignItems: 'center',
},
panelHandle: {
width: 40,
height: 8,
borderRadius: 4,
backgroundColor: '#00000040',
marginBottom: 10,
},
backgroundView: {
height: SCREEN_HEIGHT,
width: SCREEN_WIDTH,
},
});
export default BottomDrawer;
|