"use client"; import { useEffect, useState } from "react"; // 弹层进出场:打开即挂载并在下一帧置为可见(触发入场过渡);关闭先置不可见播放出场, // 延迟 durationMs 后再卸载。调用方用 motion-safe: 门控过渡类——reduced-motion 下无动画, // 仍功能正常(仅多挂载 durationMs)。守住既有 focus-trap/scroll-lock:它们仍由 open 驱动, // 本 hook 只负责“延迟卸载”以便播放退场。 export function useMountTransition( isOpen: boolean, durationMs: number, ): { shouldRender: boolean; isVisible: boolean } { const [shouldRender, setShouldRender] = useState(isOpen); const [isVisible, setIsVisible] = useState(false); useEffect(() => { if (isOpen) { setShouldRender(true); // 下一帧再置可见,确保入场从初始(隐藏)态开始过渡。 const raf = requestAnimationFrame(() => setIsVisible(true)); return () => cancelAnimationFrame(raf); } setIsVisible(false); const timer = window.setTimeout(() => setShouldRender(false), durationMs); return () => window.clearTimeout(timer); }, [isOpen, durationMs]); return { shouldRender, isVisible }; }