Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x | import {useCallback, useEffect, useRef, useState} from 'react' import cx from 'classnames' import PropTypes from 'prop-types' import {AUTO_CLOSE_TIMES, BASE_CLASS, EFFECT_DELAY, POSITIONS} from './config.js' const AtomToast = ({ autoClose = true, autoCloseTime = AUTO_CLOSE_TIMES.medium, children, effect = true, globalClose = false, iconClose = null, onClose, position = POSITIONS.topRight, show: showFromProps = true }) => { const [show, setShow] = useState(showFromProps) const [delay, setDelay] = useState(true) const autoCloseTimeout = useRef() const delayTimeout = useRef() const toastRef = useRef() const containerClassName = cx(`${BASE_CLASS}-container`, `${BASE_CLASS}-position--${position}`, { [`${BASE_CLASS}-effect--${position}`]: effect, [`${BASE_CLASS}-effect--hide`]: effect && delay }) const handleClose = useCallback(() => { if (effect) setDelay(true) setShow(false) if (!effect && typeof onClose === 'function') onClose() }, [effect, onClose]) useEffect(() => { setShow(showFromProps) }, [showFromProps]) useEffect(() => { Eif (autoClose) { autoCloseTimeout.current = setTimeout(() => { handleClose() }, autoCloseTime) } return () => clearTimeout(autoCloseTimeout.current) }, [autoClose, autoCloseTime, handleClose]) useEffect(() => { // open effect Eif (effect && show && delay) { delayTimeout.current = setTimeout(() => { setDelay(false) }, EFFECT_DELAY.open) } // close effect Iif (effect && !show) { delayTimeout.current = setTimeout(() => { setDelay(false) typeof onClose === 'function' && onClose() }, EFFECT_DELAY.close) } return () => clearTimeout(delayTimeout.current) }, [delay, effect, onClose, show]) useEffect(() => { Iif (globalClose) { const handleClickOutside = e => { if (!toastRef.current.contains(e.target)) { handleClose() } } window.addEventListener('mousedown', handleClickOutside) return () => { window.removeEventListener('mousedown', handleClickOutside) } } }, [globalClose, handleClose]) Iif (!show && !delay) return null return ( <div className={containerClassName}> <div className={BASE_CLASS} ref={toastRef}> <div onClick={handleClose} className={`${BASE_CLASS}-icon`}> {iconClose} </div> {children} </div> </div> ) } AtomToast.displayName = 'AtomToast' AtomToast.propTypes = { /** Enable/disable auto close */ autoClose: PropTypes.bool, /** Auto close times: 'short' (3000s), 'medium' (6000s), 'long' (9000s) */ autoCloseTime: PropTypes.oneOf(Object.keys(AUTO_CLOSE_TIMES)), /** Toast content */ children: PropTypes.node.isRequired, /** Enable/disable toast transition */ effect: PropTypes.bool, /** Custom close icon */ iconClose: PropTypes.node, /** On close callback */ onClose: PropTypes.func, /** Positions: 'top-left', 'top', 'top-right', 'bottom-left', 'bottom', 'bottom-right' */ position: PropTypes.oneOf(Object.values(POSITIONS)), /** Show/hide notification */ show: PropTypes.bool, /** Enable/disable global close */ globalClose: PropTypes.bool } export {POSITIONS as atomToastPositions, AUTO_CLOSE_TIMES as atomToastAutoCloseTimes} export default AtomToast |