Skip to content

Commit bc5d967

Browse files
Tranceversatya164
authored andcommitted
BREAKING: redesign Snackbar
1 parent 54660ef commit bc5d967

File tree

4 files changed

+446
-386
lines changed

4 files changed

+446
-386
lines changed

docs/assets/screenshots/snackbar.gif

-715 KB
Loading

example/src/SnackbarExample.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class SnackbarExample extends React.Component<Props, State> {
2929
return (
3030
<View style={[styles.container, { backgroundColor: background }]}>
3131
<Button
32-
raised
32+
mode="outlined"
3333
onPress={() => this.setState(state => ({ visible: !state.visible }))}
3434
>
3535
{this.state.visible ? 'Hide' : 'Show'}
@@ -43,7 +43,7 @@ class SnackbarExample extends React.Component<Props, State> {
4343
// Do something
4444
},
4545
}}
46-
duration={Snackbar.DURATION_INDEFINITE}
46+
duration={Snackbar.DURATION_MEDIUM}
4747
>
4848
Hey there! I&apos;m a Snackbar.
4949
</Snackbar>

src/components/Snackbar.js

+63-120
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/* @flow */
22

33
import * as React from 'react';
4-
import { StyleSheet, Animated } from 'react-native';
4+
import { StyleSheet, Animated, View, SafeAreaView } from 'react-native';
55

6+
import Button from './Button';
67
import Text from './Typography/Text';
78
import ThemedPortal from './Portal/ThemedPortal';
89
import withTheme from '../core/withTheme';
@@ -43,19 +44,12 @@ type Props = {
4344
};
4445

4546
type State = {
46-
layout: {
47-
height: number,
48-
measured: boolean,
49-
},
5047
opacity: Animated.Value,
51-
translateY: Animated.Value,
5248
};
5349

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;
5953

6054
/**
6155
* Snackbars provide brief feedback about an operation through a message at the bottom of the screen.
@@ -79,7 +73,6 @@ const DURATION_INDEFINITE = Infinity;
7973
* return (
8074
* <View style={styles.container}>
8175
* <Button
82-
* raised
8376
* onPress={() => this.setState(state => ({ visible: !state.visible }))}
8477
* >
8578
* {this.state.visible ? 'Hide' : 'Show'}
@@ -116,26 +109,21 @@ class Snackbar extends React.Component<Props, State> {
116109
static DURATION_SHORT = DURATION_SHORT;
117110

118111
/**
119-
* Show the Snackbar for a long duration.
112+
* Show the Snackbar for a medium duration.
120113
*/
121-
static DURATION_LONG = DURATION_LONG;
114+
static DURATION_MEDIUM = DURATION_MEDIUM;
122115

123116
/**
124-
* Show the Snackbar for indefinite amount of time.
117+
* Show the Snackbar for a long duration.
125118
*/
126-
static DURATION_INDEFINITE = DURATION_INDEFINITE;
119+
static DURATION_LONG = DURATION_LONG;
127120

128121
static defaultProps = {
129-
duration: DURATION_LONG,
122+
duration: DURATION_MEDIUM,
130123
};
131124

132125
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),
139127
};
140128

141129
componentDidUpdate(prevProps) {
@@ -150,29 +138,6 @@ class Snackbar extends React.Component<Props, State> {
150138

151139
_hideTimeout: TimeoutID;
152140

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-
176141
_toggle = () => {
177142
if (this.props.visible) {
178143
this._show();
@@ -183,123 +148,101 @@ class Snackbar extends React.Component<Props, State> {
183148

184149
_show = () => {
185150
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(() => {
199156
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);
204158
});
205159
};
206160

207161
_hide = () => {
208162
clearTimeout(this._hideTimeout);
209163

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();
222169
};
223170

224171
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;
227174

228175
return (
229176
<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,
236181
transform: [
237182
{
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,
239189
},
240190
],
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+
}}
255192
>
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}
271198
</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>
273214
</Animated.View>
274-
</Animated.View>
215+
</SafeAreaView>
275216
</ThemedPortal>
276217
);
277218
}
278219
}
279220

280221
const styles = StyleSheet.create({
281222
wrapper: {
282-
backgroundColor: '#323232',
283223
position: 'absolute',
284224
bottom: 0,
285225
width: '100%',
286-
elevation: 6,
287226
},
288227
container: {
228+
elevation: 6,
229+
backgroundColor: '#323232',
289230
flexDirection: 'row',
290231
justifyContent: 'space-between',
291232
alignItems: 'center',
233+
margin: 8,
234+
borderRadius: 4,
292235
},
293236
content: {
294237
color: white,
295-
marginLeft: 24,
238+
marginLeft: 16,
296239
marginVertical: 14,
297240
flexWrap: 'wrap',
298241
flex: 1,
299242
},
300243
button: {
301-
paddingHorizontal: 24,
302-
paddingVertical: 14,
244+
marginHorizontal: 8,
245+
marginVertical: 6,
303246
},
304247
});
305248

0 commit comments

Comments
 (0)