1
1
/* @flow */
2
2
3
3
import * as React from 'react' ;
4
- import {
5
- StyleSheet ,
6
- Animated ,
7
- Text ,
8
- View ,
9
- TouchableWithoutFeedback ,
10
- } from 'react-native' ;
4
+ import { StyleSheet , Animated } from 'react-native' ;
11
5
6
+ import Text from './Typography/Text' ;
12
7
import ThemedPortal from './Portal/ThemedPortal' ;
13
8
import withTheme from '../core/withTheme' ;
14
9
import { white } from '../styles/colors' ;
@@ -48,8 +43,10 @@ type Props = {
48
43
} ;
49
44
50
45
type State = {
51
- rendered : boolean ,
52
- height : number ,
46
+ layout : {
47
+ height : number ,
48
+ measured : boolean ,
49
+ } ,
53
50
opacity : Animated . Value ,
54
51
translateY : Animated . Value ,
55
52
} ;
@@ -129,25 +126,17 @@ class Snackbar extends React.Component<Props, State> {
129
126
} ;
130
127
131
128
state = {
132
- rendered : false ,
133
- height : 0 ,
129
+ layout : {
130
+ height : 0 ,
131
+ measured : false ,
132
+ } ,
134
133
opacity : new Animated . Value ( 0 ) ,
135
134
translateY : new Animated . Value ( 0 ) ,
136
135
} ;
137
136
138
- componentDidMount ( ) {
139
- if ( this . props . visible ) {
140
- this . _show ( ) ;
141
- }
142
- }
143
-
144
137
componentDidUpdate ( prevProps ) {
145
138
if ( prevProps . visible !== this . props . visible ) {
146
- if ( this . props . visible ) {
147
- this . _show ( ) ;
148
- } else {
149
- this . _hide ( ) ;
150
- }
139
+ this . _toggle ( ) ;
151
140
}
152
141
}
153
142
@@ -159,16 +148,38 @@ class Snackbar extends React.Component<Props, State> {
159
148
160
149
_handleLayout = e => {
161
150
const { height } = e . nativeEvent . layout ;
151
+ const { measured } = this . state . layout ;
162
152
163
- this . setState ( {
164
- height,
165
- rendered : true ,
153
+ this . setState ( { layout : { height, measured : true } } , ( ) => {
154
+ if ( measured ) {
155
+ if ( ! this . props . visible ) {
156
+ // If height changed and Snackbar was hidden, adjust the translate to keep it hidden
157
+ this . state . translateY . setValue ( height ) ;
158
+ }
159
+ } else {
160
+ // Set the appropriate initial values if height was previously unknown
161
+ this . state . translateY . setValue ( height ) ;
162
+ this . state . opacity . setValue ( 0 ) ;
163
+
164
+ // Perform the animation only if we're showing
165
+ if ( this . props . visible ) {
166
+ this . _show ( ) ;
167
+ }
168
+ }
166
169
} ) ;
170
+ } ;
167
171
168
- this . state . translateY . setValue ( height ) ;
172
+ _toggle = ( ) = > {
173
+ if ( this . props . visible ) {
174
+ this . _show ( ) ;
175
+ } else {
176
+ this . _hide ( ) ;
177
+ }
169
178
} ;
170
179
171
180
_show = ( ) => {
181
+ clearTimeout ( this . _hideTimeout ) ;
182
+
172
183
Animated . parallel ( [
173
184
Animated . timing ( this . state . opacity , {
174
185
toValue : 1 ,
@@ -199,7 +210,7 @@ class Snackbar extends React.Component<Props, State> {
199
210
useNativeDriver : true ,
200
211
} ) ,
201
212
Animated . timing ( this . state . translateY , {
202
- toValue : this . state . height ,
213
+ toValue : this . state . layout . height ,
203
214
duration : SNACKBAR_ANIMATION_DURATION ,
204
215
useNativeDriver : true ,
205
216
} ) ,
@@ -210,17 +221,14 @@ class Snackbar extends React.Component<Props, State> {
210
221
const { children , action , onDismiss , theme , style } = this . props ;
211
222
const { fonts, colors } = theme ;
212
223
213
- const buttonMargin = action ? 24 : 0 ;
214
- const contentRightMargin = action ? 0 : 24 ;
215
-
216
224
return (
217
225
< ThemedPortal >
218
226
< Animated . View
219
227
onLayout = { this . _handleLayout }
220
228
style = { [
221
229
styles . wrapper ,
222
230
{
223
- opacity : this . state . rendered ? 1 : 0 ,
231
+ opacity : this . state . layout . measured ? 1 : 0 ,
224
232
transform : [
225
233
{
226
234
translateY : this . state . translateY ,
@@ -241,36 +249,22 @@ class Snackbar extends React.Component<Props, State> {
241
249
} ,
242
250
] }
243
251
>
244
- < Text
245
- style = { [
246
- styles . content ,
247
- {
248
- fontFamily : fonts . regular ,
249
- marginRight : contentRightMargin ,
250
- } ,
251
- ] }
252
- >
252
+ < Text style = { [ styles . content , { marginRight : action ? 0 : 24 } ] } >
253
253
{ children }
254
254
</ Text >
255
255
{ action ? (
256
- < View
257
- style = { {
258
- marginHorizontal : buttonMargin ,
256
+ < Text
257
+ style = { [
258
+ styles . button ,
259
+ { color : colors . accent , fontFamily : fonts . medium } ,
260
+ ] }
261
+ onPress = { ( ) => {
262
+ action . onPress ( ) ;
263
+ onDismiss ( ) ;
259
264
} }
260
265
>
261
- < TouchableWithoutFeedback
262
- onPress = { ( ) => {
263
- action . onPress ( ) ;
264
- onDismiss ( ) ;
265
- } }
266
- >
267
- < View >
268
- < Text style = { { color : colors . accent } } >
269
- { action . label . toUpperCase ( ) }
270
- </ Text >
271
- </ View >
272
- </ TouchableWithoutFeedback >
273
- </ View >
266
+ { action . label . toUpperCase ( ) }
267
+ </ Text >
274
268
) : null }
275
269
</ Animated . View >
276
270
</ Animated . View >
@@ -299,6 +293,10 @@ const styles = StyleSheet.create({
299
293
flexWrap : 'wrap' ,
300
294
flex : 1 ,
301
295
} ,
296
+ button : {
297
+ paddingHorizontal : 24 ,
298
+ paddingVertical : 14 ,
299
+ } ,
302
300
} ) ;
303
301
304
302
export default withTheme ( Snackbar ) ;
0 commit comments