{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "message-scroller",
  "title": "Message Scroller",
  "author": "@fma-ui/ui",
  "description": "An auto-scrolling viewport for chat message lists: sticks to the latest message as new ones arrive, and shows a jump-to-end/start button once the user scrolls away. Experimental: it doesn't sit on react-aria-components like the rest of this registry, and @shadcn/react is still pre-1.0.",
  "dependencies": [
    "@shadcn/react@^0.3.1",
    "cn@^0.4.0",
    "lucide-react@^1.52.0"
  ],
  "registryDependencies": [
    "@fma-ui/button"
  ],
  "files": [
    {
      "path": "src/core/message-scroller/message-scroller.tsx",
      "content": "\"use client\";\n\nimport {\n  MessageScroller as MessageScrollerPrimitive,\n  useMessageScroller,\n  useMessageScrollerScrollable,\n  useMessageScrollerVisibility,\n} from \"@shadcn/react/message-scroller\";\nimport { cn } from \"cn\";\nimport { ArrowDownIcon } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { Button } from \"@/core/button/button\";\n\nfunction MessageScrollerProvider(\n  props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,\n) {\n  return <MessageScrollerPrimitive.Provider {...props} />;\n}\n\nfunction MessageScroller({\n  className,\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {\n  return (\n    <MessageScrollerPrimitive.Root\n      data-slot=\"message-scroller\"\n      className={cn(\n        \"group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction MessageScrollerViewport({\n  className,\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {\n  return (\n    <MessageScrollerPrimitive.Viewport\n      data-slot=\"message-scroller-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 data-pending-scroll:invisible\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction MessageScrollerContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {\n  return (\n    <MessageScrollerPrimitive.Content\n      data-slot=\"message-scroller-content\"\n      className={cn(\"flex h-max min-h-full flex-col gap-6\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction MessageScrollerItem({\n  className,\n  scrollAnchor = false,\n  ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Item>) {\n  return (\n    <MessageScrollerPrimitive.Item\n      data-slot=\"message-scroller-item\"\n      scrollAnchor={scrollAnchor}\n      className={cn(\n        \"min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction 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  return (\n    <MessageScrollerPrimitive.Button\n      data-slot=\"message-scroller-button\"\n      data-direction={direction}\n      data-variant={variant}\n      data-size={size}\n      direction={direction}\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      render={render ?? <Button variant={variant} size={size} />}\n      {...props}\n    >\n      {children ?? (\n        <>\n          <ArrowDownIcon />\n          <span className=\"sr-only\">\n            {direction === \"end\" ? \"Scroll to end\" : \"Scroll to start\"}\n          </span>\n        </>\n      )}\n    </MessageScrollerPrimitive.Button>\n  );\n}\n\nexport {\n  MessageScroller,\n  MessageScrollerButton,\n  MessageScrollerContent,\n  MessageScrollerItem,\n  MessageScrollerProvider,\n  MessageScrollerViewport,\n  useMessageScroller,\n  useMessageScrollerScrollable,\n  useMessageScrollerVisibility,\n};\n",
      "type": "registry:component",
      "target": "components/fma-ui/message-scroller.tsx"
    }
  ],
  "meta": {
    "status": "experimental",
    "source": "shadcn",
    "origin": "shadcn/ui, style: aria-nova. Built on @shadcn/react/message-scroller, not react-aria-components — upstream hasn't ported this one to the aria base yet.",
    "tags": [
      "chat",
      "scroll",
      "@shadcn/react"
    ]
  },
  "categories": [
    "chat"
  ],
  "type": "registry:ui"
}