react-native-popup-dialog-hendra
Version:
React Native Popup Dialog for IOS & Android.
207 lines (180 loc) • 5.64 kB
JavaScript
// @flow
import React, { Component } from 'react';
import {
View,
StyleSheet,
Animated,
Dimensions,
BackAndroid as RNBackAndroid,
BackHandler as RNBackHandler,
} from 'react-native';
import Overlay from './Overlay';
import FadeAnimation from '../animations/FadeAnimation';
import type { DialogType } from '../type';
const BackHandler = RNBackHandler || RNBackAndroid;
// dialog states
const DIALOG_OPENING: string = 'opening';
const DIALOG_OPENED: string = 'opened';
const DIALOG_CLOSING: string = 'closing';
const DIALOG_CLOSED: string = 'closed';
// default dialog config
const DEFAULT_ANIMATION_DURATION: number = 150;
const DEFAULT_WIDTH: number = Dimensions.get('window').width;
const DEFAULT_HEIGHT: number = 300;
const DISMISS_ON_TOUCH_OUTSIDE: boolean = true;
const DISMISS_ON_HARDWARE_BACK_PRESS: boolean = true;
const HAVE_OVERLAY: boolean = true;
// event types
const HARDWARE_BACK_PRESS_EVENT: string = 'hardwareBackPress';
const styles = StyleSheet.create({
container: {
flex: 1,
position: 'absolute',
top: 0,
left: 0,
justifyContent: 'center',
alignItems: 'center',
zIndex: 1000,
},
dialog: {
borderRadius: 8,
backgroundColor: '#ffffff',
},
hidden: {
top: -10000,
left: 0,
height: 0,
width: 0,
},
});
class Dialog extends Component {
static defaultProps = {
containerStyle: null,
animationDuration: DEFAULT_ANIMATION_DURATION,
dialogAnimation: new FadeAnimation({ animationDuration: DEFAULT_ANIMATION_DURATION }),
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
dismissOnTouchOutside: DISMISS_ON_TOUCH_OUTSIDE,
dismissOnHardwareBackPress: DISMISS_ON_HARDWARE_BACK_PRESS,
haveOverlay: HAVE_OVERLAY,
onShown: () => {},
onDismissed: () => {},
show: false,
}
state = {
dialogState: DIALOG_CLOSED,
};
componentDidMount() {
const { show } = this.props;
if (show) {
this.show();
}
BackHandler.addEventListener(HARDWARE_BACK_PRESS_EVENT, this.hardwareBackEventHandler);
}
componentWillReceiveProps(nextProps: DialogType) {
if (this.props.show !== nextProps.show) {
if (nextProps.show) {
this.show();
return;
}
this.dismiss();
}
}
componentWillUnmount() {
BackHandler.removeEventListener(HARDWARE_BACK_PRESS_EVENT, this.hardwareBackEventHandler);
}
onOverlayPress = () => {
const { dismissOnTouchOutside } = this.props;
if (dismissOnTouchOutside) {
this.dismiss();
}
}
get pointerEvents(): string {
if (this.props.overlayPointerEvents) {
return this.props.overlayPointerEvents;
}
return this.state.dialogState === DIALOG_OPENED ? 'auto' : 'none';
}
get dialogSize(): Object {
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
let { width, height } = this.props;
if (width && width > 0.0 && width <= 1.0) {
width *= screenWidth;
}
if (height && height > 0.0 && height <= 1.0) {
height *= screenHeight;
}
return { width, height };
}
setDialogState(toValue: number, callback?: Function = () => {}) {
const { animationDuration, dialogAnimation } = this.props;
let dialogState = toValue ? DIALOG_OPENING : DIALOG_CLOSING;
// to make sure has passed the dialogAnimation prop and the dialogAnimation has toValue method
if (dialogAnimation && dialogAnimation.toValue) {
dialogAnimation.toValue(toValue);
}
this.setState({ dialogState });
setTimeout(() => {
dialogState = dialogState === DIALOG_CLOSING ? DIALOG_CLOSED : DIALOG_OPENED;
this.setState({ dialogState }, () => { callback(); });
}, animationDuration);
}
show = (callback?: Function = () => {}) => {
const { onShown } = this.props;
callback();
if (![DIALOG_OPENING, DIALOG_OPENED].includes(this.state.dialogState)) {
this.setDialogState(1, onShown);
}
}
dismiss = (callback?: Function = () => {}) => {
const { onDismissed } = this.props;
callback();
if (![DIALOG_CLOSING, DIALOG_CLOSED].includes(this.state.dialogState)) {
this.setDialogState(0, onDismissed);
}
}
hardwareBackEventHandler = (): boolean => {
const { dismissOnHardwareBackPress } = this.props;
const { dialogState } = this.state;
if (dismissOnHardwareBackPress && dialogState === DIALOG_OPENED) {
this.dismiss();
return true;
}
return false;
}
props: DialogType
render() {
const { dialogState } = this.state;
const hidden = dialogState === DIALOG_CLOSED && styles.hidden;
const isShowOverlay = (
[DIALOG_OPENING, DIALOG_OPENED].includes(dialogState) && this.props.haveOverlay
);
const { width, height } = Dimensions.get('window');
const containerSize = { width, height };
return (
<View style={[styles.container, hidden, containerSize, this.props.containerStyle]}>
<Overlay
pointerEvents={this.pointerEvents}
showOverlay={isShowOverlay}
onPress={this.onOverlayPress}
backgroundColor={this.props.overlayBackgroundColor}
opacity={this.props.overlayOpacity}
animationDuration={this.props.animationDuration}
useNativeDriver={this.props.useNativeDriver}
/>
<Animated.View
style={[
styles.dialog,
this.dialogSize,
this.props.dialogStyle,
this.props.dialogAnimation.animations,
]}
>
{this.props.children}
{this.props.actions}
</Animated.View>
</View>
);
}
}
export default Dialog;