{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "reveal",
  "title": "Reveal",
  "description": "Scroll-triggered reveals that never flash above the fold.",
  "dependencies": [
    "gsap",
    "radix-ui"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.cuelark.com/r/theme.json",
    "https://ui.cuelark.com/r/motion.json"
  ],
  "files": [
    {
      "path": "src/registry/cuelark/ui/reveal.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Slot } from \"radix-ui\";\nimport { ScrollTrigger } from \"gsap/ScrollTrigger\";\n\nimport { gsap, motionScale, useGSAP } from \"@/lib/motion\";\nimport { cn } from \"@/lib/utils\";\n\nif (typeof window !== \"undefined\") gsap.registerPlugin(ScrollTrigger);\n\ntype Effect = \"rise\" | \"fade\" | \"blur\" | \"scale\" | \"wipe\";\n\ntype RevealProps = React.ComponentProps<\"div\"> & {\n  /** `wipe` uncovers content with a clip-path from the bottom edge, like a print coming out of the tray. */\n  effect?: Effect;\n  /** Animate each direct child in turn (grids, lists) instead of the block as one. */\n  stagger?: boolean;\n  /** The scrolling element when it is not the page (a panel, a modal body). */\n  scroller?: Element | null;\n  asChild?: boolean;\n};\n\nconst FROM: Record<Effect, (s: number) => gsap.TweenVars> = {\n  rise: (s) => ({ opacity: 0, y: 28 * s }),\n  fade: () => ({ opacity: 0 }),\n  blur: (s) => ({ opacity: 0, filter: `blur(${8 * s}px)`, y: 8 * s }),\n  scale: (s) => ({ opacity: 0, scale: 1 - 0.08 * s }),\n  wipe: (s) => ({ clipPath: \"inset(0% 0% 100% 0%)\", y: 12 * s }),\n};\nconst TO: Record<Effect, gsap.TweenVars> = {\n  rise: { opacity: 1, y: 0 },\n  fade: { opacity: 1 },\n  blur: { opacity: 1, filter: \"blur(0px)\", y: 0 },\n  scale: { opacity: 1, scale: 1 },\n  wipe: { clipPath: \"inset(0% 0% 0% 0%)\", y: 0 },\n};\n\n/**\n * Reveals content as it scrolls into view (GSAP ScrollTrigger.batch, so items entering together stagger).\n * On the page, anything already visible at load is left alone, so nothing flashes and crawlers get it all.\n */\nfunction Reveal({ className, effect = \"rise\", stagger = false, scroller, asChild, ...props }: RevealProps) {\n  const ref = React.useRef<HTMLDivElement>(null);\n\n  useGSAP(\n    () => {\n      const root = ref.current;\n      if (!root || !motionScale(root)) return;\n      const scale = motionScale(root);\n      const all = (stagger ? Array.from(root.children) : [root]) as HTMLElement[];\n      const targets = scroller ? all : all.filter((el) => !ScrollTrigger.isInViewport(el, 0.1));\n      if (!targets.length) return;\n      gsap.set(targets, FROM[effect](scale));\n      ScrollTrigger.batch(targets, {\n        scroller: scroller ?? undefined,\n        start: \"top 92%\",\n        once: true,\n        onEnter: (batch) => gsap.to(batch, { ...TO[effect], duration: 0.7, ease: \"cue\", stagger: 0.07, overwrite: true, clearProps: Object.keys(TO[effect]).join(\",\") }),\n      });\n    },\n    { scope: ref, dependencies: [effect, stagger, scroller] },\n  );\n\n  const Comp = asChild ? Slot.Root : \"div\";\n  return <Comp ref={ref} data-slot=\"reveal\" className={cn(className)} {...props} />;\n}\n\nexport { Reveal };\nexport type { RevealProps };\n",
      "type": "registry:ui"
    }
  ],
  "docs": "Docs and examples: https://ui.cuelark.com/components/reveal",
  "categories": [
    "motion"
  ],
  "type": "registry:ui"
}