toast.tsx 1.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import classNames from 'classnames'
  2. import { FC, useCallback, useEffect, useRef } from 'react'
  3. type ToastProps = {
  4. onClose?: () => void
  5. onExited?: () => void
  6. autohide?: boolean
  7. delay?: number
  8. show: boolean
  9. className?: string
  10. }
  11. export const Toast: FC<ToastProps> = ({
  12. children,
  13. delay = 5000,
  14. onClose,
  15. onExited,
  16. autohide,
  17. show,
  18. className,
  19. }) => {
  20. const delayRef = useRef(delay)
  21. const onCloseRef = useRef(onClose)
  22. const onExitedRef = useRef(onExited)
  23. const shouldAutoHide = Boolean(autohide && show)
  24. const handleTimeout = useCallback(() => {
  25. if (shouldAutoHide) {
  26. onCloseRef.current?.()
  27. onExitedRef.current?.()
  28. }
  29. }, [shouldAutoHide])
  30. useEffect(() => {
  31. const timeout = window.setTimeout(handleTimeout, delayRef.current)
  32. return () => window.clearTimeout(timeout)
  33. }, [handleTimeout])
  34. if (!show) {
  35. return null
  36. }
  37. return (
  38. <div
  39. className={classNames('toast', show ? 'show' : 'hide', className)}
  40. aria-live="assertive"
  41. role="alert"
  42. >
  43. {children}
  44. </div>
  45. )
  46. }