"use client"; import { type TargetAndTransition, type Target, AnimatePresence, motion, } from "motion/react"; import { LayoutRouterContext } from "next/dist/shared/lib/app-router-context.shared-runtime"; import { useSelectedLayoutSegment } from "next/navigation"; import { type ReactNode, type ComponentProps, useContext, useEffect, useRef, } from "react"; type OwnProps = { children: ReactNode; variants?: Record< string, | TargetAndTransition | (( custom: VariantArg, current: Target, velocity: Target, ) => TargetAndTransition | string) >; }; export type VariantArg = { segment: ReturnType; prevSegment: ReturnType; }; type Props = Omit, keyof OwnProps> & OwnProps; export const LayoutTransition = ({ children, ...props }: Props) => { const segment = useSelectedLayoutSegment(); const prevSegment = useRef>(segment); const nextSegment = useRef>(segment); useEffect(() => { nextSegment.current = segment; }, [segment]); const updatePrevSegment = () => { prevSegment.current = nextSegment.current; }; return ( {children} ); }; const FrozenRouter = ({ children }: { children: ReactNode }) => { const context = useContext(LayoutRouterContext); // eslint-disable-next-line unicorn/no-null const prevContext = usePreviousValue(context) ?? null; const segment = useSelectedLayoutSegment(); const prevSegment = usePreviousValue(segment); const changed = segment !== prevSegment && prevSegment !== undefined; return ( {children} ); }; const usePreviousValue = (value: T): T | undefined => { const prevValue = useRef(undefined); useEffect(() => { prevValue.current = value; return () => { prevValue.current = undefined; }; }); return prevValue.current; };