ubiatar-react-native-material-ui
Version:
Ubiatar React Native Material Design Components
236 lines (210 loc) • 6.57 kB
JavaScript
/* eslint-disable import/no-unresolved, import/extensions */
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { Text, Animated, Easing, StyleSheet } from 'react-native';
import { ViewPropTypes } from '../utils';
import Button from '../Button';
const propTypes = {
/**
* The text message to display.
*/
message: PropTypes.string.isRequired,
/**
* Whether or not the snackbar is visible.
*/
visible: PropTypes.bool,
/**
* The amount of time in milliseconds to show the snackbar.
*/
timeout: PropTypes.number,
/**
* Callback for when the timeout finishes.
*/
onRequestClose: PropTypes.func.isRequired,
/**
* Whether or not there is a bottom navigation on the screen.
*/
bottomNavigation: PropTypes.bool,
/**
* The function to execute when the action is clicked.
*/
onActionPress: PropTypes.func,
/**
* The function to execute when the action is clicked.
*/
actionText: PropTypes.string,
/**
* Take a look at the Button component for more details.
*/
button: PropTypes.shape({
...Button.propTypes,
text: PropTypes.string,
}),
/**
* Inline style of snackbar
*/
style: PropTypes.shape({
container: ViewPropTypes.style,
message: ViewPropTypes.style,
}),
};
const defaultProps = {
onActionPress: null,
actionText: null,
visible: false,
timeout: 2750,
bottomNavigation: false,
style: {},
button: {},
};
const contextTypes = {
uiTheme: PropTypes.object.isRequired,
};
function getStyles(props, context) {
const { snackbar } = context.uiTheme;
const local = {};
return {
container: [
snackbar.container,
local.container,
props.style.container,
],
message: [
snackbar.message,
local.message,
props.style.message,
],
};
}
/**
* Component for snackbars
* https://material.io/guidelines/components/snackbars-toasts.html
*/
class Snackbar extends PureComponent {
constructor(props, context) {
super(props, context);
const styles = getStyles(props, context);
this.state = {
styles,
moveAnimated: new Animated.Value(StyleSheet.flatten(styles.container).height),
};
}
componentWillReceiveProps(nextProps) {
const { style, visible, bottomNavigation } = this.props;
if (nextProps.style !== style) {
this.setState({ styles: getStyles(nextProps, this.context) });
}
if (nextProps.visible !== visible) {
if (nextProps.visible === true) {
this.show(nextProps.bottomNavigation);
this.setHideTimer();
} else {
this.hide();
}
} else if ((nextProps.bottomNavigation !== bottomNavigation)
&& nextProps.visible) {
this.move(nextProps.bottomNavigation);
}
}
componentWillUnmount() {
clearTimeout(this.hideTimer);
}
setHideTimer() {
const { timeout, onRequestClose } = this.props;
if (timeout > 0) {
clearTimeout(this.hideTimer);
this.hideTimer = setTimeout(() => {
onRequestClose();
}, timeout);
}
}
show = (bottomNavigation) => {
const { container } = this.context.uiTheme.bottomNavigation;
let toValue = 0;
if (bottomNavigation) {
toValue = -StyleSheet.flatten(container).height;
}
Animated.timing(this.state.moveAnimated, {
toValue,
duration: 225,
easing: Easing.bezier(0.0, 0.0, 0.2, 1),
useNativeDriver: true,
}).start();
}
hide = () => {
const { moveAnimated, styles } = this.state;
Animated.timing(moveAnimated, {
toValue: (StyleSheet.flatten(styles.container).height),
duration: 195,
easing: Easing.bezier(0.4, 0.0, 1, 1),
useNativeDriver: true,
}).start();
}
move = (bottomNavigation) => {
const { container } = this.context.uiTheme.bottomNavigation;
const { moveAnimated } = this.state;
const toValue = bottomNavigation ? -StyleSheet.flatten(container).height : 0;
const duration = bottomNavigation ? 225 : 195;
const easing = bottomNavigation ?
Easing.bezier(0.0, 0.0, 0.2, 1) : Easing.bezier(0.4, 0.0, 0.6, 1);
Animated.timing(moveAnimated, {
toValue,
duration,
easing,
useNativeDriver: true,
}).start();
}
renderAction = () => {
const { snackbar } = this.context.uiTheme;
const { button, actionText, onActionPress } = this.props;
const styles = {};
if (actionText && (typeof onActionPress === 'function')) {
if (button !== 'undefined' && 'style' in button) {
if ('container' in button.style) {
styles.container = {
...StyleSheet.flatten(snackbar.actionContainer),
...button.style.container,
};
}
if ('text' in button.style) {
styles.text = {
...StyleSheet.flatten(snackbar.actionText),
...button.style.text,
};
}
} else {
styles.container = snackbar.actionContainer;
styles.text = snackbar.actionText;
}
return (
<Button
{...button}
style={styles}
text={actionText}
onPress={onActionPress}
/>
);
}
return null;
}
render() {
const { message } = this.props;
const { styles, moveAnimated } = this.state;
return (
<Animated.View
style={[styles.container, {
transform: [{
translateY: moveAnimated,
}],
}]}
>
<Text style={styles.message} >{ message }</Text>
{this.renderAction()}
</Animated.View>
);
}
}
Snackbar.propTypes = propTypes;
Snackbar.defaultProps = defaultProps;
Snackbar.contextTypes = contextTypes;
export default Snackbar;