{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ds-reading-progress",
  "files": [
    {
      "path": "components/ds/ds-reading-progress.tsx",
      "content": "\"use client\"\n\nimport React, { useEffect, useState } from \"react\"\nimport { cn } from \"@/lib/utils\"\n\n// ── Types ──\n\nexport interface ReadingProgressProps extends React.HTMLAttributes<HTMLDivElement> {\n  /**\n   * Ref to the container whose scroll will be monitored.\n   * If not provided, monitors window scroll.\n   */\n  targetRef?: React.RefObject<HTMLElement | null>\n  /** Bar color, defaults to primary color */\n  progressColor?: string\n  /** Bar height */\n  height?: \"sm\" | \"md\" | \"lg\"\n}\n\n// ── Component ──\n\nconst heights = {\n  sm: \"h-1\",\n  md: \"h-2\",\n  lg: \"h-3\",\n}\n\nexport const ReadingProgress = React.forwardRef<\n  HTMLDivElement,\n  ReadingProgressProps\n>(\n  (\n    {\n      className,\n      targetRef,\n      progressColor = \"bg-primary\",\n      height = \"sm\",\n      ...props\n    },\n    ref\n  ) => {\n    const [progress, setProgress] = useState(0)\n\n    useEffect(() => {\n      const updateScroll = () => {\n        let currentScrollY = 0\n        let scrollHeight = 0\n\n        if (targetRef?.current) {\n          currentScrollY = targetRef.current.scrollTop\n          scrollHeight =\n            targetRef.current.scrollHeight - targetRef.current.clientHeight\n        } else if (typeof window !== \"undefined\") {\n          currentScrollY = window.scrollY\n          scrollHeight =\n            document.documentElement.scrollHeight -\n            document.documentElement.clientHeight\n        }\n\n        if (scrollHeight > 0) {\n          setProgress(\n            Number(((currentScrollY / scrollHeight) * 100).toFixed(2))\n          )\n        } else {\n          setProgress(0)\n        }\n      }\n\n      // Avoid SSR error\n      if (typeof window === \"undefined\") return\n\n      const el = targetRef?.current || window\n      el.addEventListener(\"scroll\", updateScroll, { passive: true })\n      window.addEventListener(\"resize\", updateScroll, { passive: true })\n\n      // Initial call\n      updateScroll()\n\n      return () => {\n        el.removeEventListener(\"scroll\", updateScroll)\n        window.removeEventListener(\"resize\", updateScroll)\n      }\n    }, [targetRef])\n\n    return (\n      <div\n        ref={ref}\n        className={cn(\n          \"pointer-events-none z-50 w-full bg-transparent\",\n          !targetRef ? \"fixed top-0 left-0\" : \"absolute top-0 left-0\",\n          heights[height],\n          className\n        )}\n        {...props}\n      >\n        <div\n          className={cn(\n            \"h-full transition-all duration-150 ease-out\",\n            progressColor\n          )}\n          style={{ width: `${progress}%` }}\n          aria-valuenow={progress}\n          aria-valuemin={0}\n          aria-valuemax={100}\n          aria-label=\"Reading progress\"\n          role=\"progressbar\"\n        />\n      </div>\n    )\n  }\n)\n\nReadingProgress.displayName = \"ReadingProgress\"\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}
