import React, { forwardRef, HTMLAttributes, useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' import { Transition } from 'react-transition-group' import { CToastContext } from './CToastContext' import { useForkedRef } from '../../hooks' import { colorPropType } from '../../props' import type { Colors } from '../../types' export interface CToastProps extends Omit, 'title'> { /** * Apply a CSS fade transition to the toast. */ animation?: boolean /** * Auto hide the toast. */ autohide?: boolean /** * A string of all className you want applied to the base component. */ className?: string /** * Sets the color context of the component to one of CoreUI’s themed colors. * * @type 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'dark' | 'light' | string */ color?: Colors /** * Delay hiding the toast (ms). */ delay?: number /** * @ignore */ index?: number /** * @ignore */ innerKey?: number | string /** * Callback fired when the component requests to be closed. */ onClose?: (index: number | null) => void /** * Callback fired when the component requests to be shown. */ onShow?: (index: number | null) => void /** * Toggle the visibility of component. */ visible?: boolean } export const CToast = forwardRef( ( { children, animation = true, autohide = true, className, color, delay = 5000, index, innerKey, visible = false, onClose, onShow, ...rest }, ref ) => { const toastRef = useRef(null) const forkedRef = useForkedRef(ref, toastRef) const [_visible, setVisible] = useState(false) const timeout = useRef(undefined) useEffect(() => { setVisible(visible) }, [visible]) const contextValues = { visible: _visible, setVisible, } // triggered on mount and destroy useEffect(() => () => clearTimeout(timeout.current), []) useEffect(() => { _autohide() }, [_visible]) const _autohide = () => { if (autohide) { clearTimeout(timeout.current) timeout.current = window.setTimeout(() => { setVisible(false) }, delay) } } return ( onShow && onShow(index ?? null)} onExited={() => onClose && onClose(index ?? null)} timeout={250} unmountOnExit > {(state) => ( clearTimeout(timeout.current)} onMouseLeave={() => _autohide()} {...rest} key={innerKey} ref={forkedRef} > {children} )} ) } ) CToast.propTypes = { animation: PropTypes.bool, autohide: PropTypes.bool, children: PropTypes.node, className: PropTypes.string, color: colorPropType, delay: PropTypes.number, index: PropTypes.number, innerKey: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), onClose: PropTypes.func, onShow: PropTypes.func, visible: PropTypes.bool, } CToast.displayName = 'CToast'