返回 DeepSeek-Reasonix
motion.ts
根目录 / desktop / frontend / src / lib / motion.ts
1 // Shared timing configuration for CSS and Web Animations API transitions.
2 // The curves mirror the desktop CSS motion tokens.
3
4 /** 120ms — color/border hovers, tooltips. */
5 export const DUR_FAST = 0.12;
6
7 /** 180ms — popovers, menus, small enters. Matches CSS --dur-base. */
8 export const DUR_BASE = 0.18;
9
10 /** 340ms — drawers, modals, panel slides. Matches CSS --dur-slow. */
11 export const DUR_SLOW = 0.34;
12
13 /** Fast-out/decelerate curve used by expanding and entrance animations. */
14 export const CSS_EASE_OUT = "cubic-bezier(0.2, 0.72, 0.2, 1)";
15
16 /** Accelerating curve used by short exit animations. */
17 export const CSS_EASE_IN = "cubic-bezier(0.8, 0, 0.8, 0.28)";
18
19 /** Runs a short exit transition without letting cosmetic failures block work. */
20 export function animateElementExit(
21 el: HTMLElement,
22 options: { opacity: number; y: number; duration: number; onComplete: () => void },
23 ) {
24 let completed = false;
25 const complete = () => {
26 if (completed) return;
27 completed = true;
28 options.onComplete();
29 };
30 if (typeof el.animate !== "function") {
31 complete();
32 return;
33 }
34 let animation: Animation;
35 try {
36 animation = el.animate(
37 [
38 { opacity: 1, transform: "translateY(0)" },
39 { opacity: options.opacity, transform: `translateY(${options.y}px)` },
40 ],
41 { duration: options.duration * 1000, easing: CSS_EASE_IN },
42 );
43 } catch {
44 complete();
45 return;
46 }
47 animation.onfinish = complete;
48 animation.oncancel = complete;
49 }
50
51 /** Returns true when the user has requested reduced motion at the OS level. */
52 export function prefersReducedMotion(): boolean {
53 if (typeof window === "undefined" || !window.matchMedia) return false;
54 return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
55 }
56
56 lines TYPESCRIPT