{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"scroll-area","title":"Scroll Area","description":"Bounded overflow region with native overlay scrollbars, optional edge fades and gutter handling.","dependencies":["@base-ui/react@1.7.0"],"registryDependencies":["@siteplane/base"],"files":[{"path":"packages/ui/src/components/scroll-area/scroll-area.tsx","content":"\"use client\";\n\nimport { ScrollArea as ScrollAreaPrimitive } from \"@base-ui/react/scroll-area\";\nimport type React from \"react\";\n\nimport { cn, type WithStringClassName } from \"../../system/utils/cn\";\nimport { baseClass, slotClass } from \"../../system/utils/slot-class\";\n\nimport \"./scroll-area.css\";\n\nexport function ScrollArea({\n  \"aria-label\": ariaLabel,\n  \"aria-labelledby\": ariaLabelledBy,\n  className,\n  children,\n  scrollFade = false,\n  scrollbar = \"auto\",\n  scrollbarGutter = false,\n  fill = false,\n  clampContentMinWidth = true,\n  ...props\n}: WithStringClassName<ScrollAreaPrimitive.Root.Props> & {\n  scrollFade?: boolean;\n  scrollbar?: \"auto\" | \"hidden\";\n  scrollbarGutter?: boolean;\n  fill?: boolean;\n  clampContentMinWidth?: boolean;\n}): React.ReactElement {\n  // The root is presentational; the viewport is what joins the tab order, so\n  // it carries the accessible name as a labelled region.\n  const viewportLabelProps =\n    ariaLabel || ariaLabelledBy\n      ? {\n          \"aria-label\": ariaLabel,\n          \"aria-labelledby\": ariaLabelledBy,\n          role: \"region\",\n        }\n      : undefined;\n\n  // The root fills its container (design-rework.css); a size utility or a\n  // consumer's own rule replaces either dimension. A keyboard-focused viewport\n  // draws the kit focus outline on the root (design-rework.css), where the\n  // scroll fade's mask cannot clip it.\n  return (\n    <ScrollAreaPrimitive.Root\n      className={cn(baseClass(\"scroll-area\", props), className)}\n      data-foundation=\"scroll-area\"\n      {...props}\n    >\n      <ScrollAreaPrimitive.Viewport\n        {...viewportLabelProps}\n        className={cn(\n          \"sp-scroll-area-viewport\",\n          \"h-full rounded-[inherit] outline-none data-has-overflow-y:overscroll-y-contain data-has-overflow-x:overscroll-x-contain\",\n          scrollFade &&\n            \"mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]\",\n          scrollbarGutter &&\n            \"data-has-overflow-y:pe-2.5 data-has-overflow-x:pb-2.5\",\n        )}\n        data-slot=\"scroll-area-viewport\"\n      >\n        <ScrollAreaPrimitive.Content\n          className={cn(\"sp-scroll-area-content\", fill && \"size-full\")}\n          data-slot=\"scroll-area-content\"\n          style={clampContentMinWidth ? { minWidth: 0 } : undefined}\n        >\n          {children}\n        </ScrollAreaPrimitive.Content>\n      </ScrollAreaPrimitive.Viewport>\n      {scrollbar === \"auto\" ? (\n        <>\n          <ScrollBar orientation=\"vertical\" />\n          <ScrollBar orientation=\"horizontal\" />\n        </>\n      ) : null}\n      <ScrollAreaPrimitive.Corner\n        className=\"sp-scroll-area-corner\"\n        data-slot=\"scroll-area-corner\"\n      />\n    </ScrollAreaPrimitive.Root>\n  );\n}\n\nexport function ScrollBar({\n  className,\n  orientation = \"vertical\",\n  ...props\n}: WithStringClassName<ScrollAreaPrimitive.Scrollbar.Props>): React.ReactElement {\n  return (\n    <ScrollAreaPrimitive.Scrollbar\n      className={cn(\n        slotClass(\"scroll-area-scrollbar\", props),\n        \"sp-scroll-area-scrollbar-motion m-1 flex opacity-0 data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:w-1.5 data-[orientation=horizontal]:flex-col data-hovering:opacity-100 data-scrolling:opacity-100\",\n        className,\n      )}\n      data-slot=\"scroll-area-scrollbar\"\n      orientation={orientation}\n      {...props}\n    >\n      <ScrollAreaPrimitive.Thumb\n        className=\"sp-scroll-area-thumb relative flex-1 rounded-full bg-foreground/20\"\n        data-slot=\"scroll-area-thumb\"\n      />\n    </ScrollAreaPrimitive.Scrollbar>\n  );\n}\n\nexport { ScrollAreaPrimitive };\n","type":"registry:ui","target":"~/src/siteplane/components/scroll-area/scroll-area.tsx"},{"path":"packages/ui/src/components/scroll-area/scroll-area.css","content":"@layer theme, base, components, siteplane, utilities;\n\n@layer siteplane {\n  /* The scrollbar fades in at once while hovered or scrolled. When the pointer\n   * leaves or scrolling stops, it stays for three micro steps (300 ms) and\n   * fades out like a state change. The fade sits at zero specificity, so the\n   * reduced-motion rules below switch it off (M5). */\n  :where(.sp-scroll-area-scrollbar-motion) {\n    transition-property: opacity;\n    transition-timing-function: var(--motion-ease-state);\n    transition-duration: var(--motion-duration-fast);\n    transition-delay: calc(var(--motion-duration-micro) * 3);\n  }\n\n  :where(\n    .sp-scroll-area-scrollbar-motion:is([data-hovering], [data-scrolling])\n  ) {\n    transition-duration: var(--motion-duration-micro);\n    transition-delay: 0ms;\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    :where(.sp-scroll-area-scrollbar-motion) {\n      transition-property: none;\n      transition-delay: 0ms;\n    }\n  }\n\n  html[data-motion-reduce=\"true\"] .sp-scroll-area-scrollbar-motion,\n  [data-sp-motion=\"reduced\"] .sp-scroll-area-scrollbar-motion {\n    transition: none;\n    transition-delay: 0s;\n  }\n}\n","type":"registry:ui","target":"~/src/siteplane/components/scroll-area/scroll-area.css"},{"path":"packages/ui/src/components/scroll-area/index.ts","content":"export * from \"./scroll-area\";\n","type":"registry:ui","target":"~/src/siteplane/components/scroll-area/index.ts"}],"type":"registry:ui","docs":"https://ui.siteplane.io/docs-markdown/components/scroll-area.md","categories":["Layout & utilities"],"meta":{"avoidWhen":["Avoid when the page itself can scroll; a nested scroll region adds a second place to scroll.","Avoid hiding the scrollbars of content that people must find by scrolling."],"description":"Bounded overflow region with native overlay scrollbars, optional edge fades and gutter handling.","knownLimitations":["The viewport joins the tab order while its content overflows; name it with aria-label or aria-labelledby."],"providerNotes":[],"releaseStatus":"stable","searchTerms":["scroll-area","scroll area","scroll","area"],"useWhen":["Use to constrain overflowing content to a fixed region, with styled scrollbars and optional edge fades."]}}