|
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