{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "page-transition",
  "type": "registry:ui",
  "title": "Page Transition",
  "description": "Wraps route content with enter/exit animations for smooth client-side page transitions.",
  "dependencies": [
    "@saasflare/ui",
    "motion",
    "next"
  ],
  "files": [
    {
      "path": "components/ui/page-transition.tsx",
      "type": "registry:ui",
      "content": "\"use client\"\n\n/**\n * @fileoverview Page transition wrapper with Motion AnimatePresence.\n * @author Saasflare™\n * Wraps page content with enter/exit animations for route transitions.\n * Uses the pathname as the animation key in Next.js App Router.\n * @module packages/ui/components/ui/page-transition\n * @package ui\n *\n * @component\n * @example\n * import { PageTransition } from '@saasflare/ui';\n * // In your layout.tsx — the current pathname is used as the animation key.\n * export default function Layout({ children }: { children: React.ReactNode }) {\n *   return <PageTransition>{children}</PageTransition>;\n * }\n *\n * @example\n * // Custom animation variant\n * <PageTransition variant=\"slideUp\" duration={0.4}>\n *   {children}\n * </PageTransition>\n */\n\nimport * as React from \"react\"\nimport { type ReactNode } from \"react\"\nimport { usePathname } from \"next/navigation\"\nimport { AnimatePresence, m } from \"motion/react\"\nimport { cn } from \"@saasflare/ui\"\nimport { useSaasflareProps, type SaasflareComponentProps } from \"@saasflare/ui\"\nimport { useSaasflareMotion } from \"@saasflare/ui\"\n\n/** Motion props that conflict with native DOM event handlers on the root element. */\ntype MotionConflicts = \"onDrag\" | \"onDragStart\" | \"onDragEnd\" | \"onAnimationStart\" | \"onAnimationEnd\"\n\n/** Animation variant presets for page transitions. */\nconst VARIANTS = {\n  fade: {\n    initial: { opacity: 0 },\n    animate: { opacity: 1 },\n    exit: { opacity: 0 },\n  },\n  slideUp: {\n    initial: { opacity: 0, y: 16 },\n    animate: { opacity: 1, y: 0 },\n    exit: { opacity: 0, y: -16 },\n  },\n  slideDown: {\n    initial: { opacity: 0, y: -16 },\n    animate: { opacity: 1, y: 0 },\n    exit: { opacity: 0, y: 16 },\n  },\n  scale: {\n    initial: { opacity: 0, scale: 0.96 },\n    animate: { opacity: 1, scale: 1 },\n    exit: { opacity: 0, scale: 0.96 },\n  },\n} as const\n\n/** Props for the PageTransition component. */\nexport interface PageTransitionProps\n  extends Omit<\n      React.ComponentProps<\"div\">,\n      MotionConflicts | \"children\" | keyof SaasflareComponentProps\n    >,\n    SaasflareComponentProps {\n  /** Child content to animate. */\n  children: ReactNode\n  /** Animation preset. Default: `\"fade\"` */\n  variant?: keyof typeof VARIANTS\n  /** Transition duration in seconds. Default: `0.3` */\n  duration?: number\n  /**\n   * Unique key for AnimatePresence to trigger re-animation on route changes.\n   * Default: the current pathname (Next.js App Router).\n   */\n  transitionKey?: string\n}\n\n/**\n * Page transition wrapper with configurable enter/exit animations.\n *\n * - Provides `fade`, `slideUp`, `slideDown`, and `scale` presets\n * - Renders children directly (no animation) when `animated` is `false` or\n *   reduced motion is preferred\n * - Defaults the AnimatePresence key to the current pathname, so route changes\n *   trigger the exit/enter sequence with zero configuration; override via\n *   `transitionKey` when needed\n *\n * @component\n * @package ui\n */\nexport function PageTransition({\n  children,\n  variant = \"fade\",\n  duration = 0.3,\n  transitionKey,\n  className,\n  surface,\n  radius,\n  animated,\n  iconWeight,\n  ...props\n}: PageTransitionProps) {\n  const sf = useSaasflareProps({ surface, radius, animated, iconWeight })\n  const motion = useSaasflareMotion(sf.animated, { duration, ease: \"easeInOut\" })\n  const pathname = usePathname()\n  const key = transitionKey ?? pathname ?? undefined\n\n  if (motion.disabled) {\n    return (\n      <div\n        {...props}\n        data-slot=\"page-transition\"\n        data-surface={sf.surface}\n        data-radius={sf.radius}\n        data-animated={String(sf.animated)}\n        className={className}\n      >\n        {children}\n      </div>\n    )\n  }\n\n  const preset = VARIANTS[variant]\n\n  return (\n    <AnimatePresence mode=\"wait\">\n      <m.div\n        {...props}\n        key={key}\n        data-slot=\"page-transition\"\n        data-surface={sf.surface}\n        data-radius={sf.radius}\n        data-animated={String(sf.animated)}\n        initial={preset.initial}\n        animate={preset.animate}\n        exit={preset.exit}\n        transition={motion.transition}\n        className={cn(\"will-change-[opacity,transform]\", className)}\n      >\n        {children}\n      </m.div>\n    </AnimatePresence>\n  )\n}\n",
      "target": "components/ui/page-transition.tsx"
    }
  ],
  "$meta": {
    "source": "https://ui.saasflare.io/r/page-transition.json"
  }
}
