UNPKG

@redocly/theme

Version:

Shared UI components lib

141 lines 5.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useToastLogic = useToastLogic; const react_1 = require("react"); const utils_1 = require("../utils"); const STACK_SHIFT_ENTER_DURATION_MS = 280; const STACK_SHIFT_EXIT_DURATION_MS = 200; function useToastLogic({ toast, onDismiss, stackIndex, }) { const wrapperRef = (0, react_1.useRef)(null); const previousTopRef = (0, react_1.useRef)(null); const previousStackIndexRef = (0, react_1.useRef)(null); const timerRef = (0, react_1.useRef)(null); const startedAtRef = (0, react_1.useRef)(null); const remainingTimeRef = (0, react_1.useRef)(0); const animationFrameRef = (0, react_1.useRef)(null); const isHoveredRef = (0, react_1.useRef)(false); const hasDetails = Boolean(toast.description); const resolvedDuration = (0, react_1.useMemo)(() => (0, utils_1.getAutoDismissDuration)(hasDetails, toast.type, toast.duration), [hasDetails, toast.duration, toast.type]); const ariaRole = toast.type === 'error' ? 'alert' : 'status'; const ariaLive = toast.type === 'error' ? 'assertive' : 'polite'; const clearTimer = (0, react_1.useCallback)(() => { if (timerRef.current) { clearTimeout(timerRef.current); timerRef.current = null; } startedAtRef.current = null; }, []); const dismissToast = (0, react_1.useCallback)(() => { onDismiss(toast.id); }, [onDismiss, toast.id]); const startTimer = (0, react_1.useCallback)((delay) => { clearTimer(); if (delay <= 0) { dismissToast(); return; } remainingTimeRef.current = delay; startedAtRef.current = Date.now(); timerRef.current = setTimeout(() => { dismissToast(); }, delay); }, [clearTimer, dismissToast]); (0, react_1.useEffect)(() => { if (toast.isExiting || resolvedDuration === null) { clearTimer(); return undefined; } if (!isHoveredRef.current) { startTimer(resolvedDuration); } return () => { clearTimer(); }; }, [ clearTimer, resolvedDuration, startTimer, toast.description, toast.isExiting, toast.title, toast.type, ]); (0, react_1.useLayoutEffect)(() => { const node = wrapperRef.current; if (!node) { return undefined; } node.style.transition = 'none'; node.style.transform = ''; const currentTop = node.getBoundingClientRect().top; const previousTop = previousTopRef.current; const previousStackIndex = previousStackIndexRef.current; if (toast.isExiting) { previousTopRef.current = currentTop; previousStackIndexRef.current = stackIndex; return () => { if (animationFrameRef.current !== null) { window.cancelAnimationFrame(animationFrameRef.current); animationFrameRef.current = null; } }; } const didStackIndexChange = previousStackIndex !== null && previousStackIndex !== stackIndex; if (didStackIndexChange && previousTop !== null && previousTop !== currentTop) { const delta = previousTop - currentTop; const shiftDuration = delta > 0 ? STACK_SHIFT_ENTER_DURATION_MS : STACK_SHIFT_EXIT_DURATION_MS; node.style.transform = `translateY(${delta}px)`; node.getBoundingClientRect(); animationFrameRef.current = window.requestAnimationFrame(() => { animationFrameRef.current = null; if (!wrapperRef.current) { return; } wrapperRef.current.style.transition = `transform ${shiftDuration}ms ease-out`; wrapperRef.current.style.transform = 'translateY(0)'; }); } previousTopRef.current = currentTop; previousStackIndexRef.current = stackIndex; return () => { if (animationFrameRef.current !== null) { window.cancelAnimationFrame(animationFrameRef.current); animationFrameRef.current = null; } }; }); (0, react_1.useEffect)(() => { return () => { clearTimer(); if (animationFrameRef.current !== null) { window.cancelAnimationFrame(animationFrameRef.current); } }; }, [clearTimer]); const handleMouseEnter = (0, react_1.useCallback)(() => { isHoveredRef.current = true; if (resolvedDuration === null || startedAtRef.current === null) { return; } const elapsed = Date.now() - startedAtRef.current; remainingTimeRef.current = Math.max(remainingTimeRef.current - elapsed, 0); clearTimer(); }, [clearTimer, resolvedDuration]); const handleMouseLeave = (0, react_1.useCallback)(() => { isHoveredRef.current = false; if (toast.isExiting || resolvedDuration === null) { return; } startTimer(remainingTimeRef.current || resolvedDuration); }, [resolvedDuration, startTimer, toast.isExiting]); return { wrapperRef, hasDetails, dismissToast, handleMouseEnter, handleMouseLeave, ariaRole, ariaLive, }; } //# sourceMappingURL=use-toast-logic.js.map