UNPKG

ubiatar-react-native-material-ui

Version:
236 lines (210 loc) 6.57 kB
/* 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;