{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "scroll-area",
  "type": "registry:component",
  "title": "Scroll Area",
  "description": "A box that scrolls, with a thin scrollbar laid over its content in place of the browser's own.",
  "dependencies": [
    "@base-ui/react",
    "tailwind-variants"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/panelui/scroll-area.tsx",
      "type": "registry:component",
      "target": "@components/panelui/scroll-area.tsx",
      "content": "/**\n * ScrollArea — a box that scrolls, with a thin scrollbar drawn over its\n * content instead of the browser's own.\n *\n * ```tsx\n * <ScrollArea className=\"h-80 rounded-2xl border\">\n *   <article>…</article>\n * </ScrollArea>\n *\n * <ScrollArea.Root className=\"h-80 rounded-2xl border\">\n *   <ScrollArea.Viewport ref={viewport}>\n *     <ScrollArea.Content>…</ScrollArea.Content>\n *   </ScrollArea.Viewport>\n *   <ScrollArea.Scrollbar />\n * </ScrollArea.Root>\n * ```\n *\n * ## The bar takes no room\n *\n * A native scrollbar takes a gutter out of the box on most desktops, so the\n * content is narrower than the frame and anything drawn edge to edge, such as\n * a header's cover, stops short of the right-hand side. Here the bar is laid\n * over the content, so the content keeps the full width. It shows while the\n * box is hovered or scrolled, then fades.\n *\n * ## The corners clip everything\n *\n * The root clips its content and isolates it, and the viewport takes the\n * root's radius. A sticky, blurred or transformed child is painted on a layer\n * of its own, and a scroller's rounded corner does not always clip that\n * layer; the root's clip does. Give the radius to the root, not the viewport.\n *\n * ## The viewport is the scroller\n *\n * Code that listens to scrolling, such as a table of contents or a header\n * that collapses, wants the element that moves. That is the viewport, so it\n * is the one a `ref` reaches: `viewportRef` on `ScrollArea`, or `ref` on\n * `ScrollArea.Viewport`.\n */\nimport { ScrollArea as Primitive } from '@base-ui/react/scroll-area';\nimport { forwardRef, type ComponentProps, type ReactNode, type Ref } from 'react';\nimport { tv } from 'tailwind-variants';\n\nexport type ScrollAreaOrientation = 'vertical' | 'horizontal' | 'both';\n\nconst scrollAreaVariants = tv({\n  slots: {\n    root: 'relative isolate flex min-h-0 flex-col overflow-hidden',\n    viewport: [\n      'min-h-0 flex-1 rounded-[inherit] outline-none',\n      'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset',\n      'data-has-overflow-y:overscroll-y-contain data-has-overflow-x:overscroll-x-contain',\n    ],\n    // Passes the radius on, for children that round their own top corners.\n    content: 'rounded-[inherit]',\n    scrollbar: [\n      'z-10 m-1 flex touch-none select-none rounded-full p-px opacity-0 transition-opacity delay-300 duration-150',\n      'data-[orientation=vertical]:w-2 data-[orientation=horizontal]:h-2 data-[orientation=horizontal]:flex-col',\n      'data-hovering:opacity-100 data-hovering:delay-0 data-scrolling:opacity-100 data-scrolling:delay-0',\n      'motion-reduce:transition-none',\n    ],\n    thumb: [\n      'relative flex-1 rounded-full bg-foreground/20 transition-colors duration-150',\n      'hover:bg-foreground/35 active:bg-foreground/40',\n      // A larger target than the drawn thumb, so it can be caught with a pointer.\n      'before:absolute before:-inset-1 before:content-[\"\"]',\n    ],\n    corner: 'bg-transparent',\n  },\n  variants: {\n    /**\n     * Fades the content out where more of it is scrolled past, by the amount\n     * that is hidden, so an edge with nothing beyond it stays sharp.\n     */\n    fade: {\n      true: {\n        viewport: [\n          '[--scroll-area-fade:1.5rem]',\n          'mask-t-from-[calc(100%-min(var(--scroll-area-fade),var(--scroll-area-overflow-y-start)))]',\n          'mask-b-from-[calc(100%-min(var(--scroll-area-fade),var(--scroll-area-overflow-y-end)))]',\n          'mask-l-from-[calc(100%-min(var(--scroll-area-fade),var(--scroll-area-overflow-x-start)))]',\n          'mask-r-from-[calc(100%-min(var(--scroll-area-fade),var(--scroll-area-overflow-x-end)))]',\n        ],\n      },\n    },\n    /**\n     * Keeps the content clear of the bar while it overflows, for rows with\n     * something at their far end that the thumb would otherwise cover.\n     */\n    gutter: {\n      true: { viewport: 'data-has-overflow-y:pe-3 data-has-overflow-x:pb-3' },\n    },\n  },\n});\n\nexport interface ScrollAreaProps extends Omit<ComponentProps<'div'>, 'dir'> {\n  /** Which ways it scrolls. Each gets its own bar. Default `vertical`. */\n  orientation?: ScrollAreaOrientation;\n  /** Fades the content out at an edge it continues past. Default `false`. */\n  fade?: boolean;\n  /**\n   * Holds the content clear of the bar while there is something to scroll,\n   * instead of letting the bar sit over it. Default `false`.\n   */\n  gutter?: boolean;\n  /**\n   * The element that scrolls, for code that listens to it: pass it as a\n   * table of contents' `root` or a scroll header's `scrollRef`.\n   */\n  viewportRef?: Ref<HTMLDivElement>;\n  /** Classes for the viewport, the element that scrolls. */\n  viewportClassName?: string;\n  /** Classes for the element that holds the content inside the viewport. */\n  contentClassName?: string;\n  children?: ReactNode;\n}\n\n/** A box that scrolls, with a thin bar drawn over its content. */\nconst ScrollAreaBase = forwardRef<HTMLDivElement, ScrollAreaProps>(function ScrollArea(\n  {\n    orientation = 'vertical',\n    fade = false,\n    gutter = false,\n    viewportRef,\n    viewportClassName,\n    contentClassName,\n    className,\n    children,\n    ...props\n  },\n  ref\n) {\n  const slots = scrollAreaVariants({ fade, gutter });\n  const vertical = orientation !== 'horizontal';\n  const horizontal = orientation !== 'vertical';\n  return (\n    <Primitive.Root ref={ref} data-slot=\"scroll-area\" className={slots.root({ className })} {...props}>\n      <Primitive.Viewport\n        ref={viewportRef}\n        data-slot=\"scroll-area-viewport\"\n        className={slots.viewport({ className: viewportClassName })}\n      >\n        <Primitive.Content\n          data-slot=\"scroll-area-content\"\n          className={slots.content({ className: contentClassName })}\n          // Lets wide content wrap to the viewport, unless it is meant to scroll sideways.\n          style={horizontal ? undefined : { minWidth: 0 }}\n        >\n          {children}\n        </Primitive.Content>\n      </Primitive.Viewport>\n      {vertical ? <ScrollAreaScrollbar orientation=\"vertical\" /> : null}\n      {horizontal ? <ScrollAreaScrollbar orientation=\"horizontal\" /> : null}\n      {vertical && horizontal ? <ScrollAreaCorner /> : null}\n    </Primitive.Root>\n  );\n});\nScrollAreaBase.displayName = 'ScrollArea';\n\nexport interface ScrollAreaRootProps extends Omit<ComponentProps<'div'>, 'dir'> {}\n\n/** The frame, for composing the parts yourself. It clips and holds the radius. */\nconst ScrollAreaRoot = forwardRef<HTMLDivElement, ScrollAreaRootProps>(function ScrollAreaRoot(\n  { className, ...props },\n  ref\n) {\n  return (\n    <Primitive.Root ref={ref} data-slot=\"scroll-area\" className={scrollAreaVariants().root({ className })} {...props} />\n  );\n});\nScrollAreaRoot.displayName = 'ScrollArea.Root';\n\nexport interface ScrollAreaViewportProps extends ComponentProps<'div'> {\n  /** Fades the content out at an edge it continues past. Default `false`. */\n  fade?: boolean;\n  /** Holds the content clear of the bar while there is something to scroll. Default `false`. */\n  gutter?: boolean;\n}\n\n/** The element that scrolls. Its `ref` is what scroll listeners want. */\nconst ScrollAreaViewport = forwardRef<HTMLDivElement, ScrollAreaViewportProps>(function ScrollAreaViewport(\n  { fade = false, gutter = false, className, ...props },\n  ref\n) {\n  return (\n    <Primitive.Viewport\n      ref={ref}\n      data-slot=\"scroll-area-viewport\"\n      className={scrollAreaVariants({ fade, gutter }).viewport({ className })}\n      {...props}\n    />\n  );\n});\nScrollAreaViewport.displayName = 'ScrollArea.Viewport';\n\nexport interface ScrollAreaContentProps extends ComponentProps<'div'> {}\n\n/** What is scrolled. Measured to size the thumb. */\nconst ScrollAreaContent = forwardRef<HTMLDivElement, ScrollAreaContentProps>(function ScrollAreaContent(\n  { className, ...props },\n  ref\n) {\n  return (\n    <Primitive.Content\n      ref={ref}\n      data-slot=\"scroll-area-content\"\n      className={scrollAreaVariants().content({ className })}\n      {...props}\n    />\n  );\n});\nScrollAreaContent.displayName = 'ScrollArea.Content';\n\nexport interface ScrollAreaScrollbarProps extends Omit<ComponentProps<'div'>, 'children'> {\n  /** Which way this bar moves. Default `vertical`. */\n  orientation?: 'vertical' | 'horizontal';\n}\n\n/** The track and its thumb, laid over the content's edge. */\nfunction ScrollAreaScrollbar({ orientation = 'vertical', className, ...props }: ScrollAreaScrollbarProps) {\n  const slots = scrollAreaVariants();\n  return (\n    <Primitive.Scrollbar\n      data-slot=\"scroll-area-scrollbar\"\n      orientation={orientation}\n      className={slots.scrollbar({ className })}\n      {...props}\n    >\n      <Primitive.Thumb data-slot=\"scroll-area-thumb\" className={slots.thumb()} />\n    </Primitive.Scrollbar>\n  );\n}\nScrollAreaScrollbar.displayName = 'ScrollArea.Scrollbar';\n\nexport interface ScrollAreaCornerProps extends ComponentProps<'div'> {}\n\n/** The square where two bars meet, when it scrolls both ways. */\nfunction ScrollAreaCorner({ className, ...props }: ScrollAreaCornerProps) {\n  return (\n    <Primitive.Corner\n      data-slot=\"scroll-area-corner\"\n      className={scrollAreaVariants().corner({ className })}\n      {...props}\n    />\n  );\n}\nScrollAreaCorner.displayName = 'ScrollArea.Corner';\n\nexport const ScrollArea = Object.assign(ScrollAreaBase, {\n  Root: ScrollAreaRoot,\n  Viewport: ScrollAreaViewport,\n  Content: ScrollAreaContent,\n  Scrollbar: ScrollAreaScrollbar,\n  Corner: ScrollAreaCorner,\n});\n\nexport {\n  ScrollAreaRoot,\n  ScrollAreaViewport,\n  ScrollAreaContent,\n  ScrollAreaScrollbar,\n  ScrollAreaCorner,\n  scrollAreaVariants,\n};\n"
    }
  ]
}
