1
1
import _ from 'lodash' ;
2
2
import PropTypes from 'prop-types' ;
3
3
import React from 'react' ;
4
- import { StyleSheet , TouchableWithoutFeedback , SafeAreaView } from 'react-native' ;
4
+ import { StyleSheet , TouchableWithoutFeedback , SafeAreaView , Animated , Easing } from 'react-native' ;
5
5
import * as Animatable from 'react-native-animatable' ;
6
- import GestureRecognizer , { swipeDirections } from 'react-native-swipe-gestures' ;
7
6
import { Constants } from '../../helpers' ;
8
- import { Colors , AnimatableManager } from '../../style' ;
7
+ import { AnimatableManager , Colors } from '../../style' ;
9
8
import { BaseComponent } from '../../commons' ;
10
9
import Modal from '../../screensComponents/modal' ;
11
10
import View from '../view' ;
11
+ import PanGestureView from '../panGestureView' ;
12
+
12
13
13
14
/*eslint-disable*/
14
15
/**
@@ -22,8 +23,8 @@ import View from '../view';
22
23
23
24
const SWIPE_DIRECTIONS = {
24
25
UP : 'up' ,
25
- DOWN : 'down' ,
26
- } ;
26
+ DOWN : 'down'
27
+ } ; // DEFRECATED
27
28
28
29
class Dialog extends BaseComponent {
29
30
static displayName = 'Dialog'
@@ -33,13 +34,13 @@ class Dialog extends BaseComponent {
33
34
*/
34
35
visible : PropTypes . bool ,
35
36
/**
36
- * dismiss callback for when clicking on the background
37
+ * Dismiss callback for when clicking on the background
37
38
*/
38
39
onDismiss : PropTypes . func ,
39
40
/**
40
- * the direction of the swipe to dismiss the dialog (default is 'down')
41
+ * The direction of the swipe to dismiss the dialog (default is 'down')
41
42
*/
42
- dismissSwipeDirection : PropTypes . oneOf ( Object . values ( SWIPE_DIRECTIONS ) ) ,
43
+ dismissSwipeDirection : PropTypes . oneOf ( Object . values ( SWIPE_DIRECTIONS ) ) , // DEFRECATED
43
44
/**
44
45
* The color of the overlay background
45
46
*/
@@ -53,85 +54,137 @@ class Dialog extends BaseComponent {
53
54
*/
54
55
height : PropTypes . oneOfType ( [ PropTypes . number , PropTypes . string ] ) ,
55
56
/**
56
- * the animation configuration to pass to the dialog (based on react-native-animatable,
57
- * ex. {animation, duration, easing,..})
57
+ * The animation configuration to pass to the dialog (ex. {animation, delay, duration, easing})
58
58
*/
59
59
animationConfig : PropTypes . object ,
60
60
/**
61
61
* The dialog container style
62
62
*/
63
- containerStyle : PropTypes . oneOfType ( [ PropTypes . object , PropTypes . number , PropTypes . array ] ) ,
63
+ containerStyle : PropTypes . oneOfType ( [ PropTypes . object , PropTypes . number , PropTypes . array ] )
64
64
} ;
65
65
66
66
static defaultProps = {
67
67
overlayBackgroundColor : Colors . rgba ( Colors . dark10 , 0.6 ) ,
68
68
width : '90%' ,
69
- height : '70%' ,
70
- dismissSwipeDirection : SWIPE_DIRECTIONS . DOWN ,
69
+ height : '70%'
71
70
} ;
72
71
73
- static swipeDirections = SWIPE_DIRECTIONS ;
72
+ static swipeDirections = SWIPE_DIRECTIONS ; // DEFRECATED
73
+
74
+ constructor ( props ) {
75
+ super ( props ) ;
76
+
77
+ this . initialPosition = props . top ? - Constants . screenHeight : Constants . screenHeight ;
78
+
79
+ this . state = {
80
+ alignments : this . state . alignments ,
81
+ deltaY : new Animated . Value ( this . initialPosition )
82
+ } ;
83
+
84
+ if ( props . dismissSwipeDirection ) {
85
+ console . warn ( 'Dialog component\'s prop \'dismissSwipeDirection\' is deprecated, please remove it' ) ;
86
+ }
87
+ }
74
88
75
89
generateStyles ( ) {
76
90
this . styles = createStyles ( this . props ) ;
77
91
}
78
92
79
- onSwipe ( gestureName ) {
80
- const { SWIPE_UP , SWIPE_DOWN } = swipeDirections ;
81
- const { dismissSwipeDirection} = this . props ;
82
-
83
- switch ( gestureName ) {
84
- case SWIPE_UP :
85
- if ( dismissSwipeDirection === SWIPE_DIRECTIONS . UP ) {
86
- _ . invoke ( this . props , 'onDismiss' ) ;
87
- }
88
- break ;
89
- case SWIPE_DOWN :
90
- if ( dismissSwipeDirection === SWIPE_DIRECTIONS . DOWN ) {
91
- _ . invoke ( this . props , 'onDismiss' ) ;
92
- }
93
- break ;
94
- default :
95
- break ;
96
- }
93
+ onDismiss = ( ) => {
94
+ this . initPositions ( ) ;
95
+ _ . invoke ( this . props , 'onDismiss' ) ;
97
96
}
98
97
99
- render ( ) {
100
- const { visible, overlayBackgroundColor, style, onDismiss, bottom, animationConfig, top} = this . getThemeProps ( ) ;
101
- const { alignments} = this . state ;
102
- const centerByDefault = _ . isEmpty ( alignments ) ;
103
- const config = {
104
- velocityThreshold : 0.3 ,
105
- directionalOffsetThreshold : 80 ,
106
- } ;
98
+ initPositions ( ) {
99
+ this . setState ( {
100
+ deltaY : new Animated . Value ( this . initialPosition )
101
+ } ) ;
102
+ }
103
+
104
+ onModalShow = ( ) => {
105
+ const { animationConfig} = this . getThemeProps ( ) ;
106
+ const { deltaY} = this . state ;
107
+
108
+ Animated . timing ( deltaY , {
109
+ toValue : 0 ,
110
+ duration : _ . get ( animationConfig , 'duration' , 280 ) ,
111
+ delay : _ . get ( animationConfig , 'delay' , 200 ) ,
112
+ easing : _ . get ( animationConfig , 'easing' , Easing . bezier ( 0.165 , 0.84 , 0.44 , 1 ) ) ,
113
+ useNativeDriver : _ . get ( animationConfig , 'useNativeDriver' , true )
114
+ } ) . start ( ) ;
115
+ }
116
+
117
+ renderContent ( ) {
118
+ const { bottom} = this . getThemeProps ( ) ;
107
119
const bottomInsets = Constants . getSafeAreaInsets ( ) . paddingBottom ;
108
- const animation = top ? AnimatableManager . presets . slideInDown : AnimatableManager . presets . slideInUp ;
120
+
121
+ return (
122
+ < TouchableWithoutFeedback >
123
+ < SafeAreaView style = { { flexGrow : 1 } } >
124
+ { this . props . children }
125
+ { Constants . isIphoneX && bottom && < View style = { { height : bottomInsets } } /> }
126
+ </ SafeAreaView >
127
+ </ TouchableWithoutFeedback >
128
+ ) ;
129
+ }
130
+
131
+ renderDraggableContainer ( ) {
132
+ const { style, top} = this . getThemeProps ( ) ;
133
+
134
+ return (
135
+ < PanGestureView
136
+ style = { [ this . styles . dialogContainer , style ] }
137
+ direction = { top && PanGestureView . directions . UP }
138
+ onDismiss = { this . onDismiss }
139
+ >
140
+ { this . renderContent ( ) }
141
+ </ PanGestureView >
142
+ ) ;
143
+ }
144
+
145
+ renderAnimationContainer ( ) {
146
+ const { animationConfig, top} = this . getThemeProps ( ) ;
147
+ const { alignments, deltaY} = this . state ;
148
+ const centerByDefault = _ . isEmpty ( alignments ) ;
149
+ const hasCustomAnimation = ( animationConfig && animationConfig . animation ) ;
150
+ const Container = hasCustomAnimation ? Animatable . View : Animated . View ;
151
+ const defaultAnimation = top ? AnimatableManager . presets . slideInDown : AnimatableManager . presets . slideInUp ;
152
+ const animation = hasCustomAnimation ? Object . assign ( defaultAnimation , animationConfig ) : { } ;
153
+
154
+ return (
155
+ < Container
156
+ style = { [
157
+ this . styles . overlay ,
158
+ { ...alignments } ,
159
+ centerByDefault && this . styles . centerContent ,
160
+ ! hasCustomAnimation && {
161
+ transform : [ {
162
+ translateY : deltaY
163
+ } ]
164
+ }
165
+ ] }
166
+ pointerEvents = 'box-none'
167
+ { ...animation }
168
+ >
169
+ { this . renderDraggableContainer ( ) }
170
+ </ Container >
171
+ ) ;
172
+ }
173
+
174
+ render ( ) {
175
+ const { visible, overlayBackgroundColor} = this . getThemeProps ( ) ;
109
176
110
177
return (
111
178
< Modal
112
179
transparent
113
180
visible = { visible }
114
181
animationType = { 'fade' }
115
- onBackgroundPress = { onDismiss }
116
- onRequestClose = { onDismiss }
182
+ onBackgroundPress = { this . onDismiss }
183
+ onRequestClose = { this . onDismiss }
117
184
overlayBackgroundColor = { overlayBackgroundColor }
185
+ onShow = { this . onModalShow }
118
186
>
119
- < View center = { centerByDefault } style = { [ this . styles . overlay , alignments ] } pointerEvents = "box-none" >
120
- < Animatable . View style = { [ this . styles . dialogContainer , style ] } { ...animation } { ...animationConfig } >
121
- < GestureRecognizer
122
- onSwipe = { ( direction , state ) => this . onSwipe ( direction , state ) }
123
- config = { config }
124
- style = { this . styles . gestureContainer }
125
- >
126
- < TouchableWithoutFeedback >
127
- < SafeAreaView style = { { flexGrow : 1 } } >
128
- { this . props . children }
129
- { Constants . isIphoneX && bottom && < View style = { { height : bottomInsets } } /> }
130
- </ SafeAreaView >
131
- </ TouchableWithoutFeedback >
132
- </ GestureRecognizer >
133
- </ Animatable . View >
134
- </ View >
187
+ { this . renderAnimationContainer ( ) }
135
188
</ Modal >
136
189
) ;
137
190
}
@@ -140,15 +193,16 @@ class Dialog extends BaseComponent {
140
193
function createStyles ( { width, height} ) {
141
194
return StyleSheet . create ( {
142
195
overlay : {
143
- flex : 1 ,
196
+ flex : 1
144
197
} ,
145
198
dialogContainer : {
146
199
width,
147
- height,
148
- } ,
149
- gestureContainer : {
150
- flexGrow : 1 ,
200
+ height
151
201
} ,
202
+ centerContent : {
203
+ justifyContent : 'center' ,
204
+ alignItems : 'center'
205
+ }
152
206
} ) ;
153
207
}
154
208
0 commit comments