UNPKG

@bitjourney/react-toastr

Version:
183 lines (164 loc) 4.37 kB
// @flow import _ from "lodash" import cx from "classnames" import React from "react" import on from "dom-helpers/events/on" import { animationEnd } from "dom-helpers/transition/properties" import { ToastMessage as renderToastMessage } from "./ToastMessage" import type { Props as ToastMessageProps } from "./ToastMessage" type Props = ToastMessageProps & { className?: string, /** or other animations from animate.css */ showAnimation?: string, /** or other animations from animate.css */ hideAnimation?: string, /** * Set the time (in ms) after which the toast message should automatically close. */ timeOut?: number, /** * Set the time (in ms) after which the toast message should automatically close after being hovered on. Applied on hover exit. */ extendedTimeOut?: number, /** * Enable dismissing toasts on click. */ tapToDismiss?: boolean, onRemove: func, onClick?: func, onCloseClick?: func, } /** * A decorated component that leverages animate.css for toast showing/hiding. * * @see https://daneden.github.io/animate.css/ */ export class ToastMessageAnimated extends React.PureComponent<Props> { static defaultProps = { className: "toast", showAnimation: "animated bounceIn", hideAnimation: "animated bounceOut", // timeOut: 5000, extendedTimeOut: 1000, // tapToDismiss: true, // onRemove: undefined, onClick: _.noop, onCloseClick: _.noop, } state = { hidingTimoutId: undefined, className: undefined, } componentDidMount() { if (!_.isUndefined(this.props.showAnimation)) { this.setState(() => { on(this.message, animationEnd, this.handleTransitionEnd) return { className: this.props.showAnimation, } }) } if (this.props.timeOut > 0) { this.setState(() => ({ hidingTimoutId: setTimeout(this.handleHide, this.props.timeOut), })) } } componentWillUnmount() { if (!_.isUndefined(this.state.hidingTimoutId)) { clearTimeout(this.state.hidingTimoutId) } this.setState = _.noop } handleMount = ref => { this.message = ref } handleMouseEnter = () => { this.setState(state => { if (!_.isUndefined(state.hidingTimoutId)) { clearTimeout(state.hidingTimoutId) } return { hidingTimoutId: undefined, className: undefined, } }) } handleMouseLeave = () => { this.setState(state => { const timeOut = this.props.extendedTimeOut !== 0 ? this.props.extendedTimeOut : this.props.timeOut if (_.isUndefined(state.hidingTimoutId) && timeOut !== 0) { return { hidingTimoutId: setTimeout(this.handleHide, timeOut), } } return {} }) } handleTransitionEnd = () => { this.setState(() => ({ className: undefined, })) } handleHideHookOnEnd = () => { on( this.message, animationEnd, _.flowRight(this.handleRemove, this.handleTransitionEnd) ) } handleHide = (override = false) => { this.setState(state => { if (override || !_.isUndefined(state.hidingTimoutId)) { if (!_.isNil(this.props.hideAnimation)) { return { hidingTimoutId: setTimeout(this.handleHideHookOnEnd, 50), className: this.props.hideAnimation, } } else { this.handleRemove() return { hidingTimoutId: undefined, className: undefined, } } } }) } handleRemove = () => { this.props.onRemove() } handleOnClick = event => { this.props.onClick(event) if (this.props.tapToDismiss) { this.handleHide(true) } } handleOnCloseClick = event => { event.stopPropagation() this.props.onCloseClick(event) this.handleHide(true) } render() { const restProps = _.omit( this.props, _.keys(ToastMessageAnimated.defaultProps) ) return renderToastMessage({ ...restProps, ref: this.handleMount, className: cx(this.props.className, this.state.className), onClick: this.handleOnClick, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, onCloseClick: this.handleOnCloseClick, }) } } export default ToastMessageAnimated