1
1
import React , { Component } from "react" ;
2
2
import PropTypes from "prop-types" ;
3
- import { View , Modal , TouchableOpacity , Animated } from "react-native" ;
3
+ import {
4
+ View ,
5
+ Modal ,
6
+ TouchableOpacity ,
7
+ Animated ,
8
+ PanResponder
9
+ } from "react-native" ;
4
10
import styles from "./style" ;
5
11
6
12
const SUPPORTED_ORIENTATIONS = [
@@ -16,38 +22,51 @@ class RBSheet extends Component {
16
22
super ( ) ;
17
23
this . state = {
18
24
modalVisible : false ,
19
- animatedHeight : new Animated . Value ( 0 )
25
+ animatedHeight : new Animated . Value ( 0 ) ,
26
+ pan : new Animated . ValueXY ( )
20
27
} ;
21
28
22
- this . onPressMask = this . onPressMask . bind ( this ) ;
23
- this . setModalVisible = this . setModalVisible . bind ( this ) ;
29
+ this . createPanResponder ( ) ;
30
+ }
31
+
32
+ createPanResponder ( ) {
33
+ this . panResponder = PanResponder . create ( {
34
+ onStartShouldSetPanResponder : ( ) => this . props . closeOnSwipeDown ,
35
+ onPanResponderMove : ( e , gestureState ) => {
36
+ gestureState . dy < 0
37
+ ? null
38
+ : Animated . event ( [ null , { dy : this . state . pan . y } ] ) ( e , gestureState ) ;
39
+ } ,
40
+ onPanResponderRelease : ( e , gestureState ) => {
41
+ if ( this . props . height / 4 - gestureState . dy < 0 ) {
42
+ this . setModalVisible ( false ) ;
43
+ } else {
44
+ Animated . spring ( this . state . pan , { toValue : { x : 0 , y : 0 } } ) . start ( ) ;
45
+ }
46
+ }
47
+ } ) ;
24
48
}
25
49
26
50
setModalVisible ( visible ) {
27
- const { height, duration } = this . props ;
51
+ const { height, duration, onClose } = this . props ;
28
52
if ( visible ) {
29
53
this . setState ( { modalVisible : visible } ) ;
30
- return Animated . timing ( this . state . animatedHeight , {
54
+ Animated . timing ( this . state . animatedHeight , {
31
55
toValue : height ,
32
56
duration : duration
33
57
} ) . start ( ) ;
34
58
} else {
35
- return Animated . timing ( this . state . animatedHeight , {
59
+ Animated . timing ( this . state . animatedHeight , {
36
60
toValue : 0 ,
37
61
duration : duration
38
62
} ) . start ( ( ) => {
39
63
this . setState ( { modalVisible : visible } ) ;
64
+ this . state . pan . setValue ( { x : 0 , y : 0 } ) ;
65
+ if ( typeof onClose === "function" ) onClose ( ) ;
40
66
} ) ;
41
67
}
42
68
}
43
69
44
- onPressMask ( ) {
45
- this . setModalVisible ( false ) ;
46
- if ( typeof this . props . onPressMask === "function" ) {
47
- this . props . onPressMask ( ) ;
48
- }
49
- }
50
-
51
70
open ( ) {
52
71
this . setModalVisible ( true ) ;
53
72
}
@@ -57,7 +76,10 @@ class RBSheet extends Component {
57
76
}
58
77
59
78
render ( ) {
60
- const { children, customStyles } = this . props ;
79
+ const { closeOnPressMask, children, customStyles } = this . props ;
80
+ const panStyle = {
81
+ transform : this . state . pan . getTranslateTransform ( )
82
+ } ;
61
83
62
84
return (
63
85
< Modal
@@ -69,25 +91,24 @@ class RBSheet extends Component {
69
91
this . setModalVisible ( false ) ;
70
92
} }
71
93
>
72
- < TouchableOpacity
73
- style = { [ styles . mask , customStyles . mask ] }
74
- activeOpacity = { 1 }
75
- onPress = { this . onPressMask }
76
- >
94
+ < View style = { [ styles . wrapper , customStyles . wrapper ] } >
95
+ < TouchableOpacity
96
+ style = { styles . mask }
97
+ activeOpacity = { 1 }
98
+ onPress = { ( ) => ( closeOnPressMask ? this . close ( ) : { } ) }
99
+ />
77
100
< Animated . View
101
+ { ...this . panResponder . panHandlers }
78
102
style = { [
103
+ panStyle ,
79
104
styles . container ,
80
- { height : this . state . animatedHeight } ,
81
- customStyles . container
105
+ customStyles . container ,
106
+ { height : this . state . animatedHeight }
82
107
] }
83
108
>
84
- < TouchableOpacity activeOpacity = { 1 } style = { styles . content } >
85
- < View style = { [ styles . content , customStyles . content ] } >
86
- { children }
87
- </ View >
88
- </ TouchableOpacity >
109
+ { children }
89
110
</ Animated . View >
90
- </ TouchableOpacity >
111
+ </ View >
91
112
</ Modal >
92
113
) ;
93
114
}
@@ -96,13 +117,17 @@ class RBSheet extends Component {
96
117
RBSheet . propTypes = {
97
118
height : PropTypes . number ,
98
119
duration : PropTypes . number ,
120
+ closeOnSwipeDown : PropTypes . bool ,
121
+ closeOnPressMask : PropTypes . bool ,
99
122
customStyles : PropTypes . object ,
100
- onPressMask : PropTypes . func
123
+ onClose : PropTypes . func
101
124
} ;
102
125
103
126
RBSheet . defaultProps = {
104
127
height : 260 ,
105
128
duration : 300 ,
129
+ closeOnSwipeDown : true ,
130
+ closeOnPressMask : true ,
106
131
customStyles : { }
107
132
} ;
108
133
0 commit comments