{
  "$schema": "https://blode.co/ui/schema/registry-item.json",
  "name": "message-scroller",
  "title": "Message Scroller",
  "author": "Matthew Blode",
  "description": "A chat scroll container that anchors turns, opens saved transcripts, follows streamed responses, loads history without jumping, and jumps to any message.",
  "dependencies": ["@shadcn/react"],
  "registryDependencies": ["button"],
  "files": [
    {
      "path": "ui/message-scroller.tsx",
      "content": "\"use client\";\n\nimport { MessageScroller as MessageScrollerPrimitive } from \"@shadcn/react/message-scroller\";\nimport { ArrowDownIcon } from \"blode-icons-react\";\nimport type * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\n\nexport {\n  useMessageScroller,\n  useMessageScrollerScrollable,\n  useMessageScrollerVisibility,\n} from \"@shadcn/react/message-scroller\";\n\nconst MessageScrollerProvider = (\n  props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,\n) => <MessageScrollerPrimitive.Provider {...props} />;\n\nconst MessageScroller = ({\n  className,\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) => (\n  <MessageScrollerPrimitive.Root\n    className={cn(\n      \"group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden\",\n      className,\n    )}\n    data-slot=\"message-scroller\"\n    {...props}\n  />\n);\n\nconst MessageScrollerViewport = ({\n  className,\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) => (\n  <MessageScrollerPrimitive.Viewport\n    className={cn(\n      \"size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin scrollbar-gutter-stable overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-thumb-transparent data-autoscrolling:scrollbar-track-transparent\",\n      className,\n    )}\n    data-slot=\"message-scroller-viewport\"\n    {...props}\n  />\n);\n\nconst MessageScrollerContent = ({\n  className,\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) => (\n  <MessageScrollerPrimitive.Content\n    className={cn(\"flex h-max min-h-full flex-col gap-8\", className)}\n    data-slot=\"message-scroller-content\"\n    {...props}\n  />\n);\n\nconst MessageScrollerItem = ({\n  className,\n  scrollAnchor = false,\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Item>) => (\n  <MessageScrollerPrimitive.Item\n    className={cn(\n      \"min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]\",\n      className,\n    )}\n    data-slot=\"message-scroller-item\"\n    scrollAnchor={scrollAnchor}\n    {...props}\n  />\n);\n\nconst MessageScrollerButton = ({\n  direction = \"end\",\n  className,\n  children,\n  render,\n  variant = \"secondary\",\n  size = \"icon-sm\",\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &\n  Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) => (\n  <MessageScrollerPrimitive.Button\n    className={cn(\n      \"absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180\",\n      className,\n    )}\n    data-direction={direction}\n    data-size={size}\n    data-slot=\"message-scroller-button\"\n    data-variant={variant}\n    direction={direction}\n    render={render ?? <Button size={size} variant={variant} />}\n    {...props}\n  >\n    {children ?? (\n      <>\n        <ArrowDownIcon />\n        <span className=\"sr-only\">{direction === \"end\" ? \"Scroll to end\" : \"Scroll to start\"}</span>\n      </>\n    )}\n  </MessageScrollerPrimitive.Button>\n);\n\nexport {\n  MessageScroller,\n  MessageScrollerButton,\n  MessageScrollerContent,\n  MessageScrollerItem,\n  MessageScrollerProvider,\n  MessageScrollerViewport,\n};\n",
      "type": "registry:ui",
      "target": ""
    }
  ],
  "type": "registry:ui"
}
