react-native-js-bottom-sheet
Version:
Modal bottom sheet component for Android and iOS that follows the guidelines of Material Design.
213 lines (201 loc) • 4.68 kB
JavaScript
/* @flow */
import React from 'react';
import PropTypes from 'prop-types';
import {
Text,
TouchableNativeFeedback,
TouchableHighlight,
Platform,
StyleSheet,
PixelRatio,
View
} from 'react-native';
import Modal from 'react-native-modalbox';
type Props = {
styleContainer?: Object,
coverScreen?: boolean,
backButtonEnabled?: boolean,
height?: number,
title?: string,
options?: Array<Object>,
fontFamily?: string,
titleFontFamily?: string,
isOpen?: boolean,
cancelButtonIndex?: number,
itemDivider?: number,
contentStyle?: any,
children: any
};
class BottomSheet extends React.PureComponent<Props> {
bottomSheet: Modal;
static propTypes = {
styleContainer: PropTypes.object,
coverScreen: PropTypes.bool,
backButtonEnabled: PropTypes.bool,
height: PropTypes.number,
title: PropTypes.string,
options: PropTypes.arrayOf(PropTypes.object),
fontFamily: PropTypes.string,
titleFontFamily: PropTypes.string,
isOpen: PropTypes.bool,
cancelButtonIndex: PropTypes.number,
itemDivider: PropTypes.number,
contentStyle: PropTypes.object
};
/**
* Open the BottomSheet
*/
open() {
this.bottomSheet.open();
}
/**
* Close the BottomSheet
*/
close() {
this.bottomSheet.close();
}
/**
* Renders content based on the options or children
* @returns {*}
*/
renderContent() {
const {
options,
title,
children,
fontFamily,
itemDivider,
titleFontFamily
} = this.props;
if (options && options.length) {
title && (
<Text
style={[
styles.title,
{
fontFamily: titleFontFamily
}
]}>
{title}
</Text>
);
return options.map(
(
item: {
onPress: Function,
icon: any,
title: string
},
index: number
) => {
return (
<View
style={{
flexDirection: 'column'
}}
key={index}>
{Platform.OS === 'android' ? (
<TouchableNativeFeedback
onPress={item.onPress}
background={TouchableNativeFeedback.SelectableBackground()}>
<View style={styles.item}>
{item.icon}
<Text
style={[
styles.text,
{
fontFamily: fontFamily
}
]}>
{item.title}
</Text>
</View>
</TouchableNativeFeedback>
) : (
<TouchableHighlight
onPress={item.onPress}
underlayColor="#F5F5F5">
<View style={styles.item}>
{item.icon}
<Text
style={[
styles.text,
{
fontFamily: fontFamily
}
]}>
{item.title}
</Text>
</View>
</TouchableHighlight>
)}
{itemDivider === index + 1 && <View style={styles.separator} />}
</View>
);
}
);
}
return children;
}
render() {
const {
height,
backButtonEnabled,
isOpen,
coverScreen,
contentStyle,
styleContainer
} = this.props;
return (
<Modal
ref={(ref: any) => {
this.bottomSheet = ref;
}}
style={[
styleContainer,
{
height: height
}
]}
backButtonClose={backButtonEnabled}
position="bottom"
isOpen={isOpen}
coverScreen={coverScreen}>
<View style={[styles.modal, contentStyle]}>{this.renderContent()}</View>
</Modal>
);
}
}
const styles = StyleSheet.create({
text: {
paddingHorizontal: 32,
fontFamily: 'Roboto',
textAlignVertical: 'center',
color: '#000',
opacity: 0.87
},
item: {
flexDirection: 'row',
height: 48,
alignItems: 'center',
paddingLeft: 16,
paddingRight: 16
},
title: {
height: 42,
color: '#000',
opacity: 0.54,
marginLeft: 16
},
modal: {
marginTop: 16
},
separator: {
height: 1 / PixelRatio.get(),
backgroundColor: '#CCCCCC',
marginTop: 7,
marginBottom: 8,
width: '100%'
}
});
export default BottomSheet;