rn-modal-picker-awesome
Version:
Cross Platform [ ios, android ] , Modal Picker Awesome , React Native Component , Full Control for Headers & Options & all Sections
342 lines (336 loc) • 11.6 kB
JavaScript
/**
* React Native Modal Picker Component ,
* Advantages => [ single-select, multi-selecte, full-customize-component, auto-close-for-both-single-multi ]
* this work created by @skirmustafa <mustafaskir@gmail.com> in 14,july 2018
* usage :
* <Modal
visible={this.state.visible}
onSelectOption={(option) => console.log('@printSelectOptionFromParent ',option)}
autoClose={false} // close auto after one selection in single selection , in multiselcetio close auto in one case after all selection checked
modalOptions={[{ name:'Option 2', value:'200' },{ name:'Option 3', value:'300' },{ name:'Option 4', value:'400' }]}
selectedOptions={[{ name:'Option 3', value:'300' },]} // only in multiple selection
selectedOption={{ value:'200' }} only in single selection
multiple={false} // if true , enabled multi selection
animateType={'slide'} // [ 'fade', 'slide' ]
modalBackground='#fff'
modalHeaderBackground='#ccc'
closeIconName='md-close' // find list if icons from here https://ionicframework.com/docs/ionicons/
closeIconText='CLOSE'
closeIconStyle={{ color:'#000' }}
closeIconTextStyle={{ color:'#000' }}
doneIconStyle={{ color:'#000' }}
doneIconTextStyle={{ color:'#000', }}
doneIconName='md-close'
doneIconText='DONE'
titleStyle={ {color:'#000',} }
titleText='Title ...'
optionContainerStyle={{ }}
optionTextContainerStyle={{ }}
optionTextStyle={{ }}
optionCircleColor='yellow'
optionCircleInnerColor='green'
/>
*/
import React, { Component } from "react";
import {
View,
Text,
TouchableOpacity,
Modal,
Dimensions,
SafeAreaView
} from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
import _ from "lodash";
let { width, height } = Dimensions.get("window");
export default class ModalComponent extends Component {
constructor() {
super();
this.state = {
visible: false,
selectedOptions: [],
};
}
componentWillReceiveProps(newProps) {
if (newProps.visible) {
this.setState({ visible: newProps.visible });
}
}
componentWillMount() {
if (this.props.selectedOptions && this.props.multiple) {
let values = _.map(this.props.selectedOptions, option => {
return option.value;
});
this.setState({
selectedOptions: [...this.state.selectedOptions, ...values]
});
} else if (this.props.selectedOption && !this.props.multiple) {
this.setState({ selectedOptions: this.props.selectedOption.value });
}
this.setState({ visible: this.props.visible });
}
_onSelecteOptionEvent(option) {
value = option.value;
let singleOrMulti = undefined;
if (this.props.multiple) {
singleOrMulti = true; // multi
} else {
singleOrMulti = false; // single
}
let isInsideArray = _.find(
this.state.selectedOptions,
val => val === value
);
if (isInsideArray) {
let newSelectedOptions = _.filter(
this.state.selectedOptions,
val => val !== value
);
this.setState({ selectedOptions: newSelectedOptions });
this.props.onSelectOption(newSelectedOptions);
if (
this.props.autoClose &&
this.props.multiple &&
newSelectedOptions.length === this.props.modalOptions.length
) {
this.setState({ visible: false });
}
} else {
let newOptions = singleOrMulti
? [...this.state.selectedOptions, value]
: value;
this.setState({ selectedOptions: newOptions });
this.props.onSelectOption(newOptions);
if (
this.props.autoClose &&
this.props.multiple &&
newOptions.length === this.props.modalOptions.length
) {
this.setState({ visible: false });
}
}
if (this.props.autoClose && !this.props.multiple) {
this.setState({ visible: false });
}
}
render() {
return (
<SafeAreaView>
<Modal
animationType={this.props.animateType || "slide"}
transparent={false}
visible={this.state.visible}
>
<View
style={{
backgroundColor: this.props.modalBackground || "#fff",
width,
height,
padding: 0,
margin: 0
}}
>
<View
style={{
height: "10%",
width: "100%",
backgroundColor: this.props.modalHeaderBackground
? this.props.modalHeaderBackground
: this.props.modalBackground
? this.props.modalBackground
: "#fff",
marginTop: "5%",
flexDirection: "row",
alignItems: "center"
}}
>
<View
style={{
flex: 1,
alignItems: "flex-start",
marginHorizontal: "5%"
}}
>
<TouchableOpacity
onPress={() => this.setState({ visible: false })}
style={{ flexDirection: "row", alignItems: "center" }}
>
<Icon
name={
this.props.closeIconName || "ios-close-circle-outline"
}
style={[
{
color: "#bb1b3d",
paddingHorizontal: "3%",
fontSize: 21
},
this.props.closeIconStyle
]}
/>
<Text
style={[
{
fontSize: 16,
paddingHorizontal: "3%",
color: "#bb1b3d"
},
this.props.closeIconTextStyle
]}
>
{this.props.closeIconText || "Close"}
</Text>
</TouchableOpacity>
</View>
<View style={{ flex: 1, alignItems: "center" }}>
<Text
style={[
{ color: "#000", fontSize: 14, fontWeight: "700" },
this.props.titleStyle
]}
>
{this.props.titleText || "Title Of Modal"}
</Text>
</View>
<View
style={{
flex: 1,
alignItems: "flex-end",
marginHorizontal: "5%"
}}
>
<TouchableOpacity
onPress={() => {
this.setState({ visible: false });
}}
style={{ flexDirection: "row", alignItems: "center" }}
>
<Icon
name={
this.props.doneIconName || "ios-checkmark-circle-outline"
}
style={[
{
color: "#4caf50",
paddingHorizontal: "3%",
fontSize: 21
},
this.props.doneIconStyle
]}
/>
<Text
style={[
{
fontSize: 16,
paddingHorizontal: "3%",
color: "#4caf50"
},
this.props.doneIconTextStyle
]}
>
{this.props.doneIconText || "done"}
</Text>
</TouchableOpacity>
</View>
</View>
<View
style={{
flex: 0,
height: 1,
backgroundColor: "#ccc",
shadowColor: "grey",
shadowOffset: { width: 0.5, height: 0.5 },
shadowOpacity: 0.6
}}
/>
<View style={{ flex: 1 }}>
{_.map(this.props.modalOptions, (option, i) => {
let selected = this.props.multiple
? _.filter(
this.state.selectedOptions,
op => op === option.value
)
: undefined;
if (selected) {
selected = selected[0];
}
return (
<TouchableOpacity
onPress={this._onSelecteOptionEvent.bind(this, option)}
key={i}
>
<View
style={[
{
height: 25,
width: "100%",
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-start",
marginTop: "3%"
},
this.props.optionContainer
]}
>
<View
style={[
{
flex: 2,
marginHorizontal: "7%",
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-start",
marginHorizontal: "11%"
},
this.props.optionTextStyle
]}
>
<Text style={[this.props.optionTextStyle]}>
{option.name}
</Text>
</View>
<View
style={[
{
height: 17,
width: 17,
borderRadius: 17 / 2,
borderColor:
this.props.optionCircleColor || "#4caf50",
flex: 0,
borderWidth: 1,
justifyContent: "center",
alignItems: "center",
marginHorizontal: "11%"
}
]}
>
{selected ||
this.state.selectedOptions === option.value ? (
<View
style={{
height: 7,
width: 7,
borderRadius: 7 / 2,
backgroundColor: this.props.optionCircleInnerColor
? this.props.optionCircleInnerColor
: this.props.optionCircleColor
? this.props.optionCircleColor
: "#4caf50"
}}
/>
) : (
<View />
)}
</View>
</View>
</TouchableOpacity>
);
})}
</View>
</View>
</Modal>
</SafeAreaView>
)
}
}