Files
writer-work-flow/apps/web/lib/ui/useMountTransition.ts
Yaojia Wang f4bea7f26d feat(ui): 弹层进出场过渡 + 首屏暖深色英雄(P2-6/P4-6)
- useMountTransition hook(延迟卸载播放退场,尊重 reduced-motion)+ vitest
- Drawer 淡入+滑入进出场;focus/scroll-lock 仍由 open 驱动、focus 键 shouldRender 防丢首焦
- Toast 入场 toast-in 动画(motion-safe)
- P4-6 首屏零作品用 callout 暖深色编辑部英雄(对标 cta-band-dark,不干扰工作库)
  新增 callout/on-callout/on-callout-soft 双主题成对 token
2026-07-11 14:04:14 +02:00

30 lines
1.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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 };
}