{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "reveal-on-scroll",
  "type": "registry:ui",
  "title": "Reveal On Scroll",
  "description": "Animates elements into view as they enter the viewport (Intersection Observer + Motion).",
  "dependencies": [
    "@saasflare/ui",
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/reveal-on-scroll.tsx",
      "type": "registry:ui",
      "content": "\"use client\"\n\n/**\n * @fileoverview Reveal-on-scroll wrapper with fade/slide entrance animations.\n * @author Saasflare™\n * Uses Intersection Observer to trigger Motion animations when the\n * element enters the viewport. Supports multiple direction presets.\n * @module packages/ui/components/ui/reveal-on-scroll\n * @package ui\n *\n * @component\n * @example\n * import { RevealOnScroll } from '@saasflare/ui';\n * <RevealOnScroll>\n *   <Card>Appears when scrolled into view</Card>\n * </RevealOnScroll>\n *\n * @example\n * // Slide in from the left with delay\n * <RevealOnScroll direction=\"left\" delay={0.2}>\n *   <p>Content slides in from left</p>\n * </RevealOnScroll>\n */\n\nimport * as React from \"react\"\nimport { m, useInView, type UseInViewOptions } from \"motion/react\"\nimport { cn } from \"@saasflare/ui\"\nimport { useSaasflareProps, type SaasflareComponentProps } from \"@saasflare/ui\"\nimport { useSaasflareMotion, springGentle } from \"@saasflare/ui\"\n\n/** Motion event overrides that conflict with React HTML events. */\ntype MotionConflicts = \"onDrag\" | \"onDragStart\" | \"onDragEnd\" | \"onAnimationStart\" | \"onAnimationEnd\"\n\n/** Direction the element slides in from. */\ntype RevealDirection = \"up\" | \"down\" | \"left\" | \"right\" | \"none\"\n\n/** Axis offsets per direction. */\nconst DIRECTION_OFFSET: Record<RevealDirection, { x: number; y: number }> = {\n  up: { x: 0, y: 24 },\n  down: { x: 0, y: -24 },\n  left: { x: -24, y: 0 },\n  right: { x: 24, y: 0 },\n  none: { x: 0, y: 0 },\n}\n\n/** Props for the RevealOnScroll component. */\nexport interface RevealOnScrollProps\n  extends Omit<React.ComponentProps<\"div\">, MotionConflicts | keyof SaasflareComponentProps>,\n    SaasflareComponentProps {\n  /** Direction the element slides in from. Default: `\"up\"` */\n  direction?: RevealDirection\n  /** Animation delay in seconds. Default: `0` */\n  delay?: number\n  /** Intersection Observer root margin. Default: `\"-80px\"` */\n  rootMargin?: string\n  /** Whether the animation triggers only once. Default: `true` */\n  once?: boolean\n}\n\n/**\n * Wrapper that animates children into view on scroll intersection.\n *\n * - Fades in with an optional directional slide\n * - Uses a gentle spring for natural motion\n * - Renders children statically when motion is disabled (`animated={false}`,\n *   provider opt-out, or `prefers-reduced-motion`)\n * - Triggers once by default (configurable via `once`)\n *\n * @component\n * @package ui\n */\nexport function RevealOnScroll({\n  children,\n  direction = \"up\",\n  delay = 0,\n  rootMargin = \"-80px\",\n  once = true,\n  className,\n  surface,\n  radius,\n  animated,\n  iconWeight,\n  ...props\n}: RevealOnScrollProps) {\n  const sf = useSaasflareProps({ surface, radius, animated, iconWeight })\n  const motion = useSaasflareMotion(sf.animated, springGentle)\n  const ref = React.useRef<HTMLDivElement>(null)\n  const isInView = useInView(ref, {\n    once,\n    margin: rootMargin as UseInViewOptions[\"margin\"],\n  })\n\n  if (motion.disabled) {\n    return (\n      <div\n        {...props}\n        ref={ref}\n        data-slot=\"reveal-on-scroll\"\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 offset = DIRECTION_OFFSET[direction]\n\n  return (\n    <m.div\n      {...props}\n      ref={ref}\n      initial={{ opacity: 0, x: offset.x, y: offset.y }}\n      animate={isInView ? { opacity: 1, x: 0, y: 0 } : { opacity: 0, x: offset.x, y: offset.y }}\n      transition={{ ...springGentle, delay }}\n      data-slot=\"reveal-on-scroll\"\n      data-surface={sf.surface}\n      data-radius={sf.radius}\n      data-animated={String(sf.animated)}\n      className={cn(\"will-change-[opacity,transform]\", className)}\n    >\n      {children}\n    </m.div>\n  )\n}\n",
      "target": "components/ui/reveal-on-scroll.tsx"
    }
  ],
  "$meta": {
    "source": "https://ui.saasflare.io/r/reveal-on-scroll.json"
  }
}
