{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"focus-pull","type":"registry:ui","title":"Focus Pull","description":"Fades and un-blurs its children as they scroll into view, like a lens pulling focus.","dependencies":[],"registryDependencies":[],"files":[{"path":"registry/ui/focus-pull.tsx","type":"registry:ui","content":"\"use client\";\n\nimport { useEffect, useRef, useState, type ReactNode, type RefObject } from \"react\";\n\nexport interface FocusPullProps {\n  children: ReactNode;\n  /** Starting blur in px. */\n  blur?: number;\n  /** Ms. */\n  duration?: number;\n  /** Ms to wait once in view. */\n  delay?: number;\n  /** Any CSS timing function. */\n  easing?: string;\n  /** Starting opacity. */\n  initialOpacity?: number;\n  /** Fraction of the element that must be visible to trigger. */\n  threshold?: number;\n  /** Fade only the first time; otherwise it fades out and back in. */\n  once?: boolean;\n  /** Scrolling ancestor to observe. Defaults to the viewport. */\n  scrollContainerRef?: RefObject<HTMLElement | null>;\n  className?: string;\n}\n\nexport function FocusPull({\n  children,\n  blur = 12,\n  duration = 1000,\n  delay = 0,\n  easing = \"ease-out\",\n  initialOpacity = 0,\n  threshold = 0.2,\n  once = true,\n  scrollContainerRef,\n  className,\n}: FocusPullProps) {\n  const ref = useRef<HTMLDivElement>(null);\n  const [shown, setShown] = useState(false);\n\n  useEffect(() => {\n    const io = new IntersectionObserver(\n      ([entry]) => {\n        if (entry.isIntersecting) {\n          setShown(true);\n          if (once) io.disconnect();\n        } else if (!once) setShown(false);\n      },\n      { threshold, root: scrollContainerRef?.current ?? null },\n    );\n    io.observe(ref.current!);\n    return () => io.disconnect();\n  }, [threshold, once, scrollContainerRef]);\n\n  const timing = `${duration}ms ${easing} ${delay}ms`;\n\n  return (\n    <div\n      ref={ref}\n      data-fade-content=\"\"\n      className={className}\n      style={{\n        opacity: shown ? 1 : initialOpacity,\n        filter: shown || !blur ? \"none\" : `blur(${blur}px)`,\n        transition: `opacity ${timing}, filter ${timing}`,\n      }}\n    >\n      <style href=\"focus-pull\" precedence=\"default\">\n        {`@media (prefers-reduced-motion: reduce){[data-fade-content]{filter:none!important;transition:opacity .2s!important}}`}\n      </style>\n      {children}\n    </div>\n  );\n}\n"}]}