@redocly/theme
Version:
Shared UI components lib
141 lines • 5.51 kB
JavaScript
;
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