1
1
/* @flow */
2
2
3
3
import * as React from 'react' ;
4
- import { StyleSheet , Animated } from 'react-native' ;
4
+ import { StyleSheet , Animated , View , SafeAreaView } from 'react-native' ;
5
5
6
+ import Button from './Button' ;
6
7
import Text from './Typography/Text' ;
7
8
import ThemedPortal from './Portal/ThemedPortal' ;
8
9
import withTheme from '../core/withTheme' ;
@@ -43,19 +44,12 @@ type Props = {
43
44
} ;
44
45
45
46
type State = {
46
- layout : {
47
- height : number ,
48
- measured : boolean ,
49
- } ,
50
47
opacity : Animated . Value ,
51
- translateY : Animated . Value ,
52
48
} ;
53
49
54
- const SNACKBAR_ANIMATION_DURATION = 250 ;
55
-
56
- const DURATION_SHORT = 2500 ;
57
- const DURATION_LONG = 3500 ;
58
- const DURATION_INDEFINITE = Infinity ;
50
+ const DURATION_SHORT = 4000 ;
51
+ const DURATION_MEDIUM = 7000 ;
52
+ const DURATION_LONG = 10000 ;
59
53
60
54
/**
61
55
* Snackbars provide brief feedback about an operation through a message at the bottom of the screen.
@@ -79,7 +73,6 @@ const DURATION_INDEFINITE = Infinity;
79
73
* return (
80
74
* <View style={styles.container}>
81
75
* <Button
82
- * raised
83
76
* onPress={() => this.setState(state => ({ visible: !state.visible }))}
84
77
* >
85
78
* {this.state.visible ? 'Hide' : 'Show'}
@@ -116,26 +109,21 @@ class Snackbar extends React.Component<Props, State> {
116
109
static DURATION_SHORT = DURATION_SHORT ;
117
110
118
111
/**
119
- * Show the Snackbar for a long duration.
112
+ * Show the Snackbar for a medium duration.
120
113
*/
121
- static DURATION_LONG = DURATION_LONG ;
114
+ static DURATION_MEDIUM = DURATION_MEDIUM ;
122
115
123
116
/**
124
- * Show the Snackbar for indefinite amount of time .
117
+ * Show the Snackbar for a long duration .
125
118
*/
126
- static DURATION_INDEFINITE = DURATION_INDEFINITE ;
119
+ static DURATION_LONG = DURATION_LONG ;
127
120
128
121
static defaultProps = {
129
- duration : DURATION_LONG ,
122
+ duration : DURATION_MEDIUM ,
130
123
} ;
131
124
132
125
state = {
133
- layout : {
134
- height : 0 ,
135
- measured : false ,
136
- } ,
137
- opacity : new Animated . Value ( 0 ) ,
138
- translateY : new Animated . Value ( 0 ) ,
126
+ opacity : new Animated . Value ( 0.0 ) ,
139
127
} ;
140
128
141
129
componentDidUpdate ( prevProps ) {
@@ -150,29 +138,6 @@ class Snackbar extends React.Component<Props, State> {
150
138
151
139
_hideTimeout : TimeoutID ;
152
140
153
- _handleLayout = e => {
154
- const { height } = e . nativeEvent . layout ;
155
- const { measured } = this . state . layout ;
156
-
157
- this . setState ( { layout : { height, measured : true } } , ( ) => {
158
- if ( measured ) {
159
- if ( ! this . props . visible ) {
160
- // If height changed and Snackbar was hidden, adjust the translate to keep it hidden
161
- this . state . translateY . setValue ( height ) ;
162
- }
163
- } else {
164
- // Set the appropriate initial values if height was previously unknown
165
- this . state . translateY . setValue ( height ) ;
166
- this . state . opacity . setValue ( 0 ) ;
167
-
168
- // Perform the animation only if we're showing
169
- if ( this . props . visible ) {
170
- this . _show ( ) ;
171
- }
172
- }
173
- } ) ;
174
- } ;
175
-
176
141
_toggle = ( ) => {
177
142
if ( this . props . visible ) {
178
143
this . _show ( ) ;
@@ -183,123 +148,101 @@ class Snackbar extends React.Component<Props, State> {
183
148
184
149
_show = ( ) => {
185
150
clearTimeout ( this . _hideTimeout ) ;
186
-
187
- Animated . parallel ( [
188
- Animated . timing ( this . state . opacity , {
189
- toValue : 1 ,
190
- duration : SNACKBAR_ANIMATION_DURATION ,
191
- useNativeDriver : true ,
192
- } ) ,
193
- Animated . timing ( this . state . translateY , {
194
- toValue : 0 ,
195
- duration : SNACKBAR_ANIMATION_DURATION ,
196
- useNativeDriver : true ,
197
- } ) ,
198
- ] ) . start ( ( ) => {
151
+ Animated . timing ( this . state . opacity , {
152
+ toValue : 1 ,
153
+ duration : 200 ,
154
+ useNativeDriver : true ,
155
+ } ) . start ( ( ) => {
199
156
const { duration } = this . props ;
200
-
201
- if ( duration !== DURATION_INDEFINITE ) {
202
- this . _hideTimeout = setTimeout ( this . props . onDismiss , duration ) ;
203
- }
157
+ this . _hideTimeout = setTimeout ( this . props . onDismiss , duration ) ;
204
158
} ) ;
205
159
} ;
206
160
207
161
_hide = ( ) => {
208
162
clearTimeout ( this . _hideTimeout ) ;
209
163
210
- Animated . parallel ( [
211
- Animated . timing ( this . state . opacity , {
212
- toValue : 0 ,
213
- duration : SNACKBAR_ANIMATION_DURATION ,
214
- useNativeDriver : true ,
215
- } ) ,
216
- Animated . timing ( this . state . translateY , {
217
- toValue : this . state . layout . height ,
218
- duration : SNACKBAR_ANIMATION_DURATION ,
219
- useNativeDriver : true ,
220
- } ) ,
221
- ] ) . start ( ) ;
164
+ Animated . timing ( this . state . opacity , {
165
+ toValue : 0 ,
166
+ duration : 100 ,
167
+ useNativeDriver : true ,
168
+ } ) . start ( ) ;
222
169
} ;
223
170
224
171
render ( ) {
225
- const { children , action , onDismiss , theme , style } = this . props ;
226
- const { fonts , colors } = theme ;
172
+ const { children, visible , action, onDismiss, theme, style } = this . props ;
173
+ const { colors , roundness } = theme ;
227
174
228
175
return (
229
176
< ThemedPortal >
230
- < Animated . View
231
- onLayout = { this . _handleLayout }
232
- style = { [
233
- styles . wrapper ,
234
- {
235
- opacity : this . state . layout . measured ? 1 : 0 ,
177
+ < SafeAreaView style = { styles . wrapper } >
178
+ < Animated . View
179
+ style = { {
180
+ opacity : this . state . opacity ,
236
181
transform : [
237
182
{
238
- translateY : this . state . translateY ,
183
+ scale : visible
184
+ ? this . state . opacity . interpolate ( {
185
+ inputRange : [ 0 , 1 ] ,
186
+ outputRange : [ 0.9 , 1 ] ,
187
+ } )
188
+ : 1 ,
239
189
} ,
240
190
] ,
241
- } ,
242
- style ,
243
- ] }
244
- >
245
- < Animated . View
246
- style = { [
247
- styles . container ,
248
- {
249
- opacity : this . state . opacity . interpolate ( {
250
- inputRange : [ 0 , 0.8 , 1 ] ,
251
- outputRange : [ 0 , 0.2 , 1 ] ,
252
- } ) ,
253
- } ,
254
- ] }
191
+ } }
255
192
>
256
- < Text style = { [ styles . content , { marginRight : action ? 0 : 24 } ] } >
257
- { children }
258
- </ Text >
259
- { action ? (
260
- < Text
261
- style = { [
262
- styles . button ,
263
- { color : colors . accent , fontFamily : fonts . medium } ,
264
- ] }
265
- onPress = { ( ) => {
266
- action . onPress ( ) ;
267
- onDismiss ( ) ;
268
- } }
269
- >
270
- { action . label . toUpperCase ( ) }
193
+ < View
194
+ style = { [ styles . container , { borderRadius : roundness } , style ] }
195
+ >
196
+ < Text style = { [ styles . content , { marginRight : action ? 0 : 16 } ] } >
197
+ { children }
271
198
</ Text >
272
- ) : null }
199
+ { action ? (
200
+ < Button
201
+ onPress = { ( ) => {
202
+ action . onPress ( ) ;
203
+ onDismiss ( ) ;
204
+ } }
205
+ style = { styles . button }
206
+ color = { colors . accent }
207
+ compact
208
+ mode = "text"
209
+ >
210
+ { action . label . toUpperCase ( ) }
211
+ </ Button >
212
+ ) : null }
213
+ </ View >
273
214
</ Animated . View >
274
- </ Animated . View >
215
+ </ SafeAreaView >
275
216
</ ThemedPortal >
276
217
) ;
277
218
}
278
219
}
279
220
280
221
const styles = StyleSheet . create ( {
281
222
wrapper : {
282
- backgroundColor : '#323232' ,
283
223
position : 'absolute' ,
284
224
bottom : 0 ,
285
225
width : '100%' ,
286
- elevation : 6 ,
287
226
} ,
288
227
container : {
228
+ elevation : 6 ,
229
+ backgroundColor : '#323232' ,
289
230
flexDirection : 'row' ,
290
231
justifyContent : 'space-between' ,
291
232
alignItems : 'center' ,
233
+ margin : 8 ,
234
+ borderRadius : 4 ,
292
235
} ,
293
236
content : {
294
237
color : white ,
295
- marginLeft : 24 ,
238
+ marginLeft : 16 ,
296
239
marginVertical : 14 ,
297
240
flexWrap : 'wrap' ,
298
241
flex : 1 ,
299
242
} ,
300
243
button : {
301
- paddingHorizontal : 24 ,
302
- paddingVertical : 14 ,
244
+ marginHorizontal : 8 ,
245
+ marginVertical : 6 ,
303
246
} ,
304
247
} ) ;
305
248
0 commit comments