{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "scroll-area",
  "title": "Scroll Area",
  "description": "The scrollbar fades in and its thumb springs thicker when you reach for it.",
  "dependencies": [
    "@ui-sdk/core@0.1.0-beta.2",
    "@ui-sdk/react@0.1.0-beta.2"
  ],
  "registryDependencies": [
    "@keyframery/motion"
  ],
  "files": [
    {
      "path": "registry/components/keyframery/primitives/scroll-area.tsx",
      "content": "\"use client\"\n\n/* Animated drop-in for `@ui-sdk/react/scroll-area`: same parts, same props. Swap the import and keep your code.\n   This file adds motion only. Colours, radii, shadows and spacing stay yours.\n   - The scrollbar fades in when it should show, and its thumb slides in from the edge.\n   - The thumb is slim at rest and thickens on a spring while the pointer is on its track or it is\n     dragged. Give the thumb its full (hovered) thickness; at rest it is drawn at half. A\n     `data-hovered` attribute on the scrollbar thickens it too, for scripted demos. */\n\nimport {\n  ScrollAreaScrollbar as ScrollAreaScrollbarPart,\n  ScrollAreaThumb as ScrollAreaThumbPart,\n} from \"@ui-sdk/react/scroll-area\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport * from \"@ui-sdk/react/scroll-area\"\n\nfunction ScrollAreaScrollbar({ className, ...props }: React.ComponentProps<typeof ScrollAreaScrollbarPart>) {\n  return (\n    <ScrollAreaScrollbarPart\n      className={cn(\n        \"group/kf-scrollbar opacity-0 transition-opacity duration-[calc(420ms*var(--kf-speed,1))] ease-house\",\n        \"data-visible:opacity-100 data-visible:duration-[calc(240ms*var(--kf-speed,1))]\",\n        \"motion-reduce:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ScrollAreaThumb({ className, ...props }: React.ComponentProps<typeof ScrollAreaThumbPart>) {\n  return (\n    <ScrollAreaThumbPart\n      className={cn(\n        \"[transition:scale_calc(380ms*var(--kf-speed,1))_var(--ease-spring),translate_calc(420ms*var(--kf-speed,1))_var(--ease-spring),opacity_calc(240ms*var(--kf-speed,1))_var(--ease-house),background-color_calc(150ms*var(--kf-speed,1))_var(--ease-house)]\",\n        /* Slim at rest, from the outer edge. */\n        \"[--kf-thin:0.5] group-hover/kf-scrollbar:[--kf-thin:1] group-data-hovered/kf-scrollbar:[--kf-thin:1] data-dragging:[--kf-thin:1]\",\n        \"data-[orientation=vertical]:origin-right data-[orientation=vertical]:[scale:var(--kf-thin)_1]\",\n        \"data-[orientation=horizontal]:origin-bottom data-[orientation=horizontal]:[scale:1_var(--kf-thin)]\",\n        /* Out of sight, it waits a few pixels past the edge. */\n        \"group-not-data-visible/kf-scrollbar:opacity-0\",\n        \"group-not-data-visible/kf-scrollbar:data-[orientation=vertical]:translate-x-1.5 group-not-data-visible/kf-scrollbar:data-[orientation=horizontal]:translate-y-1.5\",\n        \"motion-reduce:[transition:none]!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { ScrollAreaScrollbar, ScrollAreaThumb }\n",
      "type": "registry:component",
      "target": "components/keyframery/primitives/scroll-area.tsx"
    },
    {
      "path": "registry/components/keyframery/scroll-area.tsx",
      "content": "\"use client\"\n\n/* Styled scroll area: the animated primitive plus the Keyframery look. */\n\nimport * as React from \"react\"\n\nimport {\n  ScrollArea as ScrollAreaRoot,\n  ScrollAreaContent as ScrollAreaContentPart,\n  ScrollAreaCorner as ScrollAreaCornerPart,\n  ScrollAreaScrollbar as ScrollAreaScrollbarPart,\n  ScrollAreaScrollToEnd as ScrollAreaScrollToEndPart,\n  ScrollAreaThumb as ScrollAreaThumbPart,\n  ScrollAreaViewport as ScrollAreaViewportPart,\n} from \"@/components/keyframery/primitives/scroll-area\"\nexport { createScrollAreaController } from \"@/components/keyframery/primitives/scroll-area\"\nimport { cn } from \"@/lib/utils\"\n\n/* Give it a size. The focus ring of the viewport is drawn here, outside the fades. */\nfunction ScrollArea({\n  className,\n  ...props\n}: React.ComponentProps<typeof ScrollAreaRoot>) {\n  return (\n    <ScrollAreaRoot\n      className={cn(\n        \"relative isolate\",\n        \"has-[[data-slot=scroll-area-viewport]:focus-visible]:ring-2 has-[[data-slot=scroll-area-viewport]:focus-visible]:ring-ring\",\n        \"has-[[data-slot=scroll-area-viewport]:focus-visible]:ring-offset-2 has-[[data-slot=scroll-area-viewport]:focus-visible]:ring-offset-background\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The scroller. Its edges fade as far as the content reaches past them, up to 24px:\n   UI SDK writes those distances on the root and the viewport takes them with `inherit`. */\nfunction ScrollAreaViewport({\n  className,\n  ...props\n}: React.ComponentProps<typeof ScrollAreaViewportPart>) {\n  return (\n    <ScrollAreaViewportPart\n      className={cn(\n        \"size-full rounded-[inherit] outline-none\",\n        \"[--scroll-area-overflow-x-end:inherit] [--scroll-area-overflow-x-start:inherit] [--scroll-area-overflow-y-end:inherit] [--scroll-area-overflow-y-start:inherit]\",\n        \"[--fade-bottom:min(24px,var(--scroll-area-overflow-y-end,0px))] [--fade-top:min(24px,var(--scroll-area-overflow-y-start,0px))]\",\n        \"[--fade-end:min(24px,var(--scroll-area-overflow-x-end,0px))] [--fade-start:min(24px,var(--scroll-area-overflow-x-start,0px))]\",\n        \"[mask-image:linear-gradient(to_bottom,transparent,black_var(--fade-top),black_calc(100%_-_var(--fade-bottom)),transparent),linear-gradient(to_right,transparent,black_var(--fade-start),black_calc(100%_-_var(--fade-end)),transparent)]\",\n        \"[mask-composite:intersect]\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ScrollAreaContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof ScrollAreaContentPart>) {\n  return <ScrollAreaContentPart className={cn(className)} {...props} />\n}\n\n/* Hidden until the pointer is over the area or it scrolls. */\nfunction ScrollAreaScrollbar({\n  className,\n  ...props\n}: React.ComponentProps<typeof ScrollAreaScrollbarPart>) {\n  return (\n    <ScrollAreaScrollbarPart\n      className={cn(\n        \"group/scrollbar z-10 flex p-[3px]\",\n        \"data-[orientation=vertical]:w-3.5 data-[orientation=vertical]:justify-end\",\n        \"data-[orientation=horizontal]:h-3.5 data-[orientation=horizontal]:items-end\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* A pill, drawn here at its full thickness. The primitive keeps it slim until the pointer is\n   on its track or it is dragged. */\nfunction ScrollAreaThumb({\n  className,\n  ...props\n}: React.ComponentProps<typeof ScrollAreaThumbPart>) {\n  return (\n    <ScrollAreaThumbPart\n      className={cn(\n        \"rounded-full bg-foreground/30\",\n        \"data-[orientation=vertical]:w-2 data-[orientation=horizontal]:h-2\",\n        \"group-hover/scrollbar:bg-foreground/45 group-data-hovered/scrollbar:bg-foreground/45 data-dragging:bg-foreground/60\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ScrollAreaCorner({\n  className,\n  ...props\n}: React.ComponentProps<typeof ScrollAreaCornerPart>) {\n  return <ScrollAreaCornerPart className={cn(\"z-10\", className)} {...props} />\n}\n\n/* \"Jump to latest\": a small key that rises from the bottom edge once the view leaves the end. */\nfunction ScrollAreaScrollToEnd({\n  className,\n  ...props\n}: React.ComponentProps<typeof ScrollAreaScrollToEndPart>) {\n  return (\n    <ScrollAreaScrollToEndPart\n      className={cn(\n        \"absolute bottom-3 left-1/2 z-10 inline-flex h-7 -translate-x-1/2 cursor-pointer items-center justify-center gap-1.5 rounded-full bg-background px-3\",\n        \"text-[12px] leading-none font-medium whitespace-nowrap text-foreground outline-none select-none [&_svg]:size-3.5 [&_svg]:shrink-0\",\n        \"shadow-[0_0_0_1px_rgb(0_0_0/0.06),0_1px_1px_rgb(0_0_0/0.05),0_3px_6px_-2px_rgb(0_0_0/0.1)]\",\n        \"dark:bg-accent dark:shadow-[0_0_0_1px_rgb(255_255_255/0.07),inset_0_1px_0_rgb(255_255_255/0.08),0_2px_6px_-1px_rgb(0_0_0/0.6)]\",\n        \"origin-bottom transition-[opacity,translate,scale,filter,box-shadow] duration-[calc(220ms*var(--kf-speed,1))] ease-house motion-reduce:transition-none!\",\n        \"not-data-visible:pointer-events-none not-data-visible:translate-y-1 not-data-visible:scale-[0.96] not-data-visible:opacity-0 not-data-visible:blur-[4px] not-data-visible:duration-[calc(140ms*var(--kf-speed,1))]\",\n        \"active:translate-y-px active:scale-[0.985] active:duration-[calc(100ms*var(--kf-speed,1))]\",\n        \"active:shadow-[0_0_0_1px_rgb(0_0_0/0.1),0_1px_1px_rgb(0_0_0/0.04),0_1px_2px_-1px_rgb(0_0_0/0.06)]\",\n        \"dark:active:shadow-[0_0_0_1px_rgb(255_255_255/0.09),inset_0_1px_0_rgb(255_255_255/0.04),0_1px_2px_-1px_rgb(0_0_0/0.6)]\",\n        \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  ScrollArea,\n  ScrollAreaContent,\n  ScrollAreaCorner,\n  ScrollAreaScrollbar,\n  ScrollAreaScrollToEnd,\n  ScrollAreaThumb,\n  ScrollAreaViewport,\n}\n",
      "type": "registry:component",
      "target": "components/keyframery/scroll-area.tsx"
    }
  ],
  "type": "registry:component"
}