Toast.tsx 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import { useCallback, useEffect, useRef } from "react";
  2. import { CloseIcon } from "./icons";
  3. import "./Toast.scss";
  4. import { ToolButton } from "./ToolButton";
  5. const DEFAULT_TOAST_TIMEOUT = 5000;
  6. export const Toast = ({
  7. message,
  8. onClose,
  9. closable = false,
  10. // To prevent autoclose, pass duration as Infinity
  11. duration = DEFAULT_TOAST_TIMEOUT,
  12. }: {
  13. message: string;
  14. onClose: () => void;
  15. closable?: boolean;
  16. duration?: number;
  17. }) => {
  18. const timerRef = useRef<number>(0);
  19. const shouldAutoClose = duration !== Infinity;
  20. const scheduleTimeout = useCallback(() => {
  21. if (!shouldAutoClose) {
  22. return;
  23. }
  24. timerRef.current = window.setTimeout(() => onClose(), duration);
  25. }, [onClose, duration, shouldAutoClose]);
  26. useEffect(() => {
  27. if (!shouldAutoClose) {
  28. return;
  29. }
  30. scheduleTimeout();
  31. return () => clearTimeout(timerRef.current);
  32. }, [scheduleTimeout, message, duration, shouldAutoClose]);
  33. const onMouseEnter = shouldAutoClose
  34. ? () => clearTimeout(timerRef?.current)
  35. : undefined;
  36. const onMouseLeave = shouldAutoClose ? scheduleTimeout : undefined;
  37. return (
  38. <div
  39. className="Toast"
  40. onMouseEnter={onMouseEnter}
  41. onMouseLeave={onMouseLeave}
  42. >
  43. <p className="Toast__message">{message}</p>
  44. {closable && (
  45. <ToolButton
  46. icon={CloseIcon}
  47. aria-label="close"
  48. type="icon"
  49. onClick={onClose}
  50. className="close"
  51. />
  52. )}
  53. </div>
  54. );
  55. };