{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "document-viewer-sidebar",
  "title": "Document Viewer Sidebar",
  "description": "Shared thumbnail sidebar behavior for document viewers, including viewer-width responsive overlay and inline modes.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "components/extend/document-viewer-sidebar.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst INLINE_THUMBNAIL_SIDEBAR_MIN_WIDTH = 768\nexport function useElementWidth<TElement extends HTMLElement>() {\n  const ref = React.useRef<TElement | null>(null)\n  const [width, setWidth] = React.useState(0)\n  React.useLayoutEffect(() => {\n    const element = ref.current\n    if (!element) return\n    const updateWidth = () => {\n      const nextWidth = element.getBoundingClientRect().width\n      // Keep the last real measurement while the element is hidden or\n      // detached (keep-alive preview pools, display:none ancestors): a\n      // zero-width pass would re-lay-out the viewer for nothing, clearing\n      // its rendered canvases, and force a blank-then-repaint flash when\n      // the element comes back at its old size.\n      if (nextWidth === 0) return\n      setWidth(nextWidth)\n    }\n    updateWidth()\n    const observer = new ResizeObserver(updateWidth)\n    observer.observe(element)\n    return () => observer.disconnect()\n  }, [])\n  return [ref, width] as const\n}\nexport function useInlineThumbnailSidebar(width: number) {\n  return width >= INLINE_THUMBNAIL_SIDEBAR_MIN_WIDTH\n}\nexport function DocumentViewerThumbnailSidebar({\n  children,\n  className,\n  closedInlineClassName = \"-ml-40\",\n  inline,\n  open,\n  widthClassName = \"w-40\",\n}: {\n  children: React.ReactNode\n  className?: string\n  closedInlineClassName?: string\n  inline: boolean\n  open: boolean\n  widthClassName?: string\n}) {\n  const [transitionsReady, setTransitionsReady] = React.useState(false)\n  const shouldAnimateSidebar = transitionsReady && open\n  React.useEffect(() => {\n    let secondFrameId = 0\n    const firstFrameId = window.requestAnimationFrame(() => {\n      secondFrameId = window.requestAnimationFrame(() => {\n        setTransitionsReady(true)\n      })\n    })\n    return () => {\n      window.cancelAnimationFrame(firstFrameId)\n      window.cancelAnimationFrame(secondFrameId)\n    }\n  }, [])\n  return (\n    <aside\n      data-document-thumbnail-sidebar=\"\"\n      data-sidebar-mode={inline ? \"inline\" : \"overlay\"}\n      data-sidebar-open={open ? \"true\" : \"false\"}\n      className={cn(\n        \"absolute inset-y-0 left-0 z-30 shrink-0 overflow-hidden border-r bg-sidebar shadow-lg\",\n        widthClassName,\n        shouldAnimateSidebar\n          ? \"transition-[translate,margin-left,border-color] duration-200 ease-out\"\n          : \"transition-none\",\n        inline && \"relative z-auto translate-x-0 shadow-none\",\n        open\n          ? \"ml-0 translate-x-0\"\n          : inline\n            ? cn(\"pointer-events-auto border-r-0\", closedInlineClassName)\n            : \"pointer-events-none -translate-x-full border-r-0\",\n        className\n      )}\n    >\n      {children}\n    </aside>\n  )\n}\nexport function DocumentViewerSidebarSkeleton({\n  className,\n  inline,\n}: {\n  className?: string\n  inline: boolean\n}) {\n  if (!inline) return null\n  return (\n    <div className={cn(\"w-40 shrink-0 border-r bg-sidebar p-4\", className)}>\n      <div className=\"mx-auto h-28 w-20 overflow-hidden rounded-md bg-background shadow-xs\">\n        <div className=\"h-full animate-pulse bg-muted\" />\n      </div>\n      <div className=\"mx-auto mt-3 h-3 w-10 rounded-full bg-muted\" />\n    </div>\n  )\n}\n",
      "type": "registry:ui",
      "target": "@components/extend/document-viewer-sidebar.tsx"
    }
  ],
  "categories": [
    "documents"
  ],
  "type": "registry:ui",
  "dependencies": []
}
