|
1 | 1 | /* @flow */ |
2 | 2 |
|
3 | | -import React from 'react' |
4 | | -import PropTypes from 'prop-types' |
| 3 | +import React from 'react'; |
| 4 | +import PropTypes from 'prop-types'; |
5 | 5 | import { |
6 | 6 | Text, |
7 | 7 | TouchableNativeFeedback, |
| 8 | + TouchableHighlight, |
8 | 9 | Platform, |
9 | 10 | StyleSheet, |
10 | | - ScrollView, |
11 | 11 | PixelRatio, |
12 | 12 | View |
13 | | -} from 'react-native' |
14 | | -import Modal from 'react-native-modalbox' |
| 13 | +} from 'react-native'; |
| 14 | +import Modal from 'react-native-modalbox'; |
15 | 15 |
|
16 | 16 | type Props = { |
17 | 17 | styleContainer?: Object, |
18 | 18 | coverScreen?: boolean, |
19 | 19 | backButtonEnabled?: boolean, |
20 | 20 | height?: number, |
21 | 21 | title?: string, |
22 | | - options: Array<Object>, |
| 22 | + options?: Array<Object>, |
23 | 23 | fontFamily?: string, |
24 | 24 | titleFontFamily?: string, |
25 | 25 | isOpen?: boolean, |
26 | 26 | cancelButtonIndex?: number, |
27 | | - itemDivider?: number |
28 | | -} |
| 27 | + itemDivider?: number, |
| 28 | + contentStyle?: any, |
| 29 | + children: any |
| 30 | +}; |
29 | 31 |
|
30 | 32 | class BottomSheet extends React.PureComponent<Props> { |
31 | | - bottomSheet: Modal |
| 33 | + bottomSheet: Modal; |
32 | 34 |
|
33 | 35 | static propTypes = { |
34 | 36 | styleContainer: PropTypes.object, |
35 | 37 | coverScreen: PropTypes.bool, |
36 | 38 | backButtonEnabled: PropTypes.bool, |
37 | 39 | height: PropTypes.number, |
38 | 40 | title: PropTypes.string, |
39 | | - options: PropTypes.arrayOf(PropTypes.object).isRequired, |
| 41 | + options: PropTypes.arrayOf(PropTypes.object), |
40 | 42 | fontFamily: PropTypes.string, |
41 | 43 | titleFontFamily: PropTypes.string, |
42 | 44 | isOpen: PropTypes.bool, |
43 | 45 | cancelButtonIndex: PropTypes.number, |
44 | | - itemDivider: PropTypes.number |
45 | | - } |
46 | | - |
47 | | - renderOption = (options: Array<Object>) => { |
48 | | - return options.map((item, index) => { |
49 | | - return ( |
50 | | - <View style={{ flexDirection: 'column' }} key={index}> |
51 | | - <TouchableNativeFeedback |
52 | | - onPress={item.onPress} |
53 | | - background={TouchableNativeFeedback.SelectableBackground()}> |
54 | | - <View style={styles.item}> |
55 | | - {item.icon} |
56 | | - <Text style={[styles.text, { fontFamily: this.props.fontFamily }]}> |
57 | | - {item.title} |
58 | | - </Text> |
59 | | - </View> |
60 | | - </TouchableNativeFeedback> |
61 | | - {this.props.itemDivider === index + 1 ? ( |
62 | | - <View style={styles.separator} /> |
63 | | - ) : null} |
64 | | - </View> |
65 | | - ) |
66 | | - }) |
67 | | - } |
| 46 | + itemDivider: PropTypes.number, |
| 47 | + contentStyle: PropTypes.object |
| 48 | + }; |
68 | 49 |
|
69 | 50 | /** |
70 | 51 | * Open the BottomSheet |
71 | 52 | */ |
72 | 53 | open() { |
73 | | - this.bottomSheet.open() |
| 54 | + this.bottomSheet.open(); |
74 | 55 | } |
75 | 56 |
|
76 | 57 | /** |
77 | 58 | * Close the BottomSheet |
78 | 59 | */ |
79 | 60 | close() { |
80 | | - this.bottomSheet.close() |
| 61 | + this.bottomSheet.close(); |
81 | 62 | } |
82 | 63 |
|
83 | | - renderTitle = () => { |
84 | | - if (!this.props.title) { |
85 | | - return |
| 64 | + /** |
| 65 | + * Renders content based on the options or children |
| 66 | + * @returns {*} |
| 67 | + */ |
| 68 | + renderContent() { |
| 69 | + const { |
| 70 | + options, |
| 71 | + title, |
| 72 | + children, |
| 73 | + fontFamily, |
| 74 | + itemDivider, |
| 75 | + titleFontFamily |
| 76 | + } = this.props; |
| 77 | + |
| 78 | + if (options && options.length) { |
| 79 | + title && ( |
| 80 | + <Text |
| 81 | + style={[ |
| 82 | + styles.title, |
| 83 | + { |
| 84 | + fontFamily: titleFontFamily |
| 85 | + } |
| 86 | + ]}> |
| 87 | + {title} |
| 88 | + </Text> |
| 89 | + ); |
| 90 | + return options.map( |
| 91 | + ( |
| 92 | + item: { |
| 93 | + onPress: Function, |
| 94 | + icon: any, |
| 95 | + title: string |
| 96 | + }, |
| 97 | + index: number |
| 98 | + ) => { |
| 99 | + return ( |
| 100 | + <View |
| 101 | + style={{ |
| 102 | + flexDirection: 'column' |
| 103 | + }} |
| 104 | + key={index}> |
| 105 | + {Platform.OS === 'android' ? ( |
| 106 | + <TouchableNativeFeedback |
| 107 | + onPress={item.onPress} |
| 108 | + background={TouchableNativeFeedback.SelectableBackground()}> |
| 109 | + <View style={styles.item}> |
| 110 | + {item.icon} |
| 111 | + <Text |
| 112 | + style={[ |
| 113 | + styles.text, |
| 114 | + { |
| 115 | + fontFamily: fontFamily |
| 116 | + } |
| 117 | + ]}> |
| 118 | + {item.title} |
| 119 | + </Text> |
| 120 | + </View> |
| 121 | + </TouchableNativeFeedback> |
| 122 | + ) : ( |
| 123 | + <TouchableHighlight |
| 124 | + onPress={item.onPress} |
| 125 | + underlayColor="#F5F5F5"> |
| 126 | + <View style={styles.item}> |
| 127 | + {item.icon} |
| 128 | + <Text |
| 129 | + style={[ |
| 130 | + styles.text, |
| 131 | + { |
| 132 | + fontFamily: fontFamily |
| 133 | + } |
| 134 | + ]}> |
| 135 | + {item.title} |
| 136 | + </Text> |
| 137 | + </View> |
| 138 | + </TouchableHighlight> |
| 139 | + )} |
| 140 | + {itemDivider === index + 1 && <View style={styles.separator} />} |
| 141 | + </View> |
| 142 | + ); |
| 143 | + } |
| 144 | + ); |
86 | 145 | } |
87 | | - return ( |
88 | | - <Text style={[styles.title, { fontFamily: this.props.titleFontFamily }]}> |
89 | | - {this.props.title} |
90 | | - </Text> |
91 | | - ) |
| 146 | + return children; |
92 | 147 | } |
93 | 148 |
|
94 | 149 | render() { |
95 | | - if (Platform.OS !== 'android') { |
96 | | - console.warn('Bottom Sheet is only available on Android.') |
97 | | - return null |
98 | | - } |
| 150 | + const { |
| 151 | + height, |
| 152 | + backButtonEnabled, |
| 153 | + isOpen, |
| 154 | + coverScreen, |
| 155 | + contentStyle, |
| 156 | + styleContainer |
| 157 | + } = this.props; |
99 | 158 | return ( |
100 | 159 | <Modal |
101 | 160 | ref={(ref: any) => { |
102 | | - this.bottomSheet = ref |
| 161 | + this.bottomSheet = ref; |
103 | 162 | }} |
104 | | - style={[this.props.styleContainer, { height: this.props.height }]} |
105 | | - backButtonClose={this.props.backButtonEnabled} |
| 163 | + style={[ |
| 164 | + styleContainer, |
| 165 | + { |
| 166 | + height: height |
| 167 | + } |
| 168 | + ]} |
| 169 | + backButtonClose={backButtonEnabled} |
106 | 170 | position="bottom" |
107 | | - isOpen={this.props.isOpen} |
108 | | - coverScreen={this.props.coverScreen}> |
109 | | - <ScrollView style={styles.modal}> |
110 | | - {this.renderTitle()} |
111 | | - {this.renderOption(this.props.options)} |
112 | | - </ScrollView> |
| 171 | + isOpen={isOpen} |
| 172 | + coverScreen={coverScreen}> |
| 173 | + <View style={[styles.modal, contentStyle]}>{this.renderContent()}</View> |
113 | 174 | </Modal> |
114 | | - ) |
| 175 | + ); |
115 | 176 | } |
116 | 177 | } |
117 | 178 |
|
@@ -146,6 +207,6 @@ const styles = StyleSheet.create({ |
146 | 207 | marginBottom: 8, |
147 | 208 | width: '100%' |
148 | 209 | } |
149 | | -}) |
| 210 | +}); |
150 | 211 |
|
151 | | -export default BottomSheet |
| 212 | +export default BottomSheet; |
0 commit comments