"use client"; import { motion } from "framer-motion"; import { useAppReducedMotion as useReducedMotion } from "@/lib/motion-pref"; import { usePathname } from "next/navigation"; import { useEffect, useState } from "react"; import { screenVariants, tabVariants } from "@/lib/motion"; /** * Direction-aware screen entrance for the page content column. * * Deeper paths (library → deck, library → create/homework) slide in from the * right; going back slides from the left; same-depth switches crossfade. * The wrapper only ever wraps the scrolling content column — fixed chrome * (tab bar, sheets) stays outside it, so a transform can never capture it. * * Note: the App Router unmounts the outgoing page immediately, so this is an * entrance animation (exits animate for in-page elements via AnimatePresence, * e.g. list items). */ /** Module-level so the direction survives the per-route remount. */ let lastPath: string | null = null; function depth(path: string): number { if (path === "/") return 0; return path.split("/").filter(Boolean).length; } export function RouteTransition({ children }: { children: React.ReactNode }) { const pathname = usePathname(); const reduceMotion = useReducedMotion(); const [{ isTabSwitch, direction }] = useState(() => { const previous = typeof window === "undefined" ? null : lastPath; return { isTabSwitch: previous !== null && depth(previous) === depth(pathname) && previous !== pathname, direction: (previous === null || depth(pathname) >= depth(previous) ? 1 : -1) as 1 | -1, }; }); useEffect(() => { lastPath = pathname; }, [pathname]); const variants = isTabSwitch ? tabVariants(!!reduceMotion) : screenVariants(direction, !!reduceMotion); return ( {children} ); }