Files
app/frontend/src/lib/motion.ts
T

75 lines
2.7 KiB
TypeScript

/**
* Shared motion presets (Fluksio design system).
*
* Pure data: variants and transitions consumed by `motion/react` components
* across the app. Mirrors the `--ease-*` / `--duration-*` timing tokens defined
* in `index.css`, so CSS transitions and JS animations stay in sync.
*
* See DESIGN-GUIDELINES.md at the repository root for the motion rules.
*
* Reduced motion: wrap each app root in `<MotionConfig reducedMotion="user">` so
* transform/layout animations are disabled automatically when the OS requests it.
*/
import type { Transition, Variants } from "motion/react"
/** Easing curves, mirroring the `--ease-*` tokens. */
export const easeEmphasized: [number, number, number, number] = [0.2, 0, 0, 1]
export const easeStandard: [number, number, number, number] = [0.4, 0, 0.2, 1]
/** Durations in seconds, mirroring the `--duration-*` tokens (ms). */
export const duration = {
fast: 0.15,
base: 0.2,
slow: 0.3,
/** One-shot feedback, not a state change. See `--duration-pulse`. */
pulse: 0.5,
} as const
export const transitions = {
/** Enter / expressive moves (decelerate). */
emphasized: { duration: duration.base, ease: easeEmphasized },
/** Neutral state changes. */
standard: { duration: duration.base, ease: easeStandard },
/** Springy, for hover tilt / direct-manipulation feedback. */
spring: { type: "spring", stiffness: 250, damping: 20, mass: 0.5 },
} satisfies Record<string, Transition>
const exitFast: Transition = { duration: duration.fast, ease: easeStandard }
/** Opacity fade. */
export const fadeIn: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1, transition: transitions.standard },
exit: { opacity: 0, transition: exitFast },
}
/** Fade + subtle scale: popovers, dialogs, floating panels. */
export const scaleIn: Variants = {
hidden: { opacity: 0, scale: 0.96 },
visible: { opacity: 1, scale: 1, transition: transitions.emphasized },
exit: { opacity: 0, scale: 0.96, transition: exitFast },
}
/** Fade + rise: list/grid items, toolbars, content blocks. */
export const slideUp: Variants = {
hidden: { opacity: 0, y: 8 },
visible: { opacity: 1, y: 0, transition: transitions.emphasized },
exit: { opacity: 0, y: 8, transition: exitFast },
}
/** Dialog / drawer scrim. */
export const overlayFade: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1, transition: exitFast },
exit: { opacity: 0, transition: exitFast },
}
/**
* Stagger container for lists/grids. Children animate with `slideUp` / `fadeIn`
* via `variants` inheritance (set the same `initial`/`animate` state names).
*/
export const listStagger: Variants = {
hidden: {},
visible: { transition: { staggerChildren: 0.05, delayChildren: 0.02 } },
}