{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "elements-message-actions",
  "type": "registry:component",
  "title": "Message actions",
  "description": "Copy, rate, and regenerate. Each action confirms itself with a small state change.",
  "registryDependencies": [
    "https://r.assistant-ui.com/elements-surfaces.json"
  ],
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "type": "registry:component",
      "path": "components/assistant-ui/elements/message-actions.tsx",
      "sourcePath": "packages/ui/src/components/react/assistant-ui/elements/message-actions.tsx",
      "content": "\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport {\n  CheckIcon,\n  CopyIcon,\n  EllipsisIcon,\n  RefreshCwIcon,\n  ThumbsDownIcon,\n  ThumbsUpIcon,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { ghostButton, iconSwap, iconSwapIn, iconSwapOut } from \"./surfaces\";\n\nexport type Reaction = \"up\" | \"down\" | null;\n\nexport interface MessageActionsProps extends Omit<\n  ComponentProps<\"div\">,\n  \"children\"\n> {\n  copied: boolean;\n  reaction: Reaction;\n  regenerating: boolean;\n  onCopy: () => void;\n  onReactionChange: (reaction: Reaction) => void;\n  onRegenerate: () => void;\n  onMore: () => void;\n}\n\nexport function MessageActions({\n  copied,\n  reaction,\n  regenerating,\n  onCopy,\n  onReactionChange,\n  onRegenerate,\n  onMore,\n  className,\n  ...props\n}: MessageActionsProps) {\n  const buttonClassName = cn(ghostButton, \"size-7\");\n\n  return (\n    <div\n      data-slot=\"message-actions\"\n      className={cn(\"flex items-center gap-1\", className)}\n\n      {...props}\n    >\n      <button\n        type=\"button\"\n        aria-label={copied ? \"Copied response\" : \"Copy response\"}\n        onClick={onCopy}\n        className={cn(\n          buttonClassName,\n          \"grid place-items-center\",\n          copied && \"text-emerald-500\",\n        )}\n      >\n        <CopyIcon\n          className={cn(\n            iconSwap,\n            \"size-3.5\",\n            copied ? iconSwapOut : iconSwapIn,\n          )}\n        />\n        <CheckIcon\n          className={cn(\n            iconSwap,\n            \"size-3.5\",\n            copied ? iconSwapIn : iconSwapOut,\n          )}\n        />\n      </button>\n      <button\n        type=\"button\"\n        aria-label=\"Mark response helpful\"\n        aria-pressed={reaction === \"up\"}\n        onClick={() => onReactionChange(reaction === \"up\" ? null : \"up\")}\n        className={cn(\n          buttonClassName,\n          reaction === \"up\" &&\n            \"bg-foreground/[0.06] text-foreground/90 dark:bg-foreground/[0.09]\",\n        )}\n      >\n        <ThumbsUpIcon className=\"size-3.5\" />\n      </button>\n      <button\n        type=\"button\"\n        aria-label=\"Mark response unhelpful\"\n        aria-pressed={reaction === \"down\"}\n        onClick={() => onReactionChange(reaction === \"down\" ? null : \"down\")}\n        className={cn(\n          buttonClassName,\n          reaction === \"down\" &&\n            \"bg-foreground/[0.06] text-foreground/90 dark:bg-foreground/[0.09]\",\n        )}\n      >\n        <ThumbsDownIcon className=\"size-3.5\" />\n      </button>\n      <button\n        type=\"button\"\n        aria-label=\"Regenerate response\"\n        onClick={onRegenerate}\n        className={buttonClassName}\n      >\n        <RefreshCwIcon\n          className={cn(\n            \"size-3.5\",\n            regenerating && \"animate-spin motion-reduce:animate-none\",\n          )}\n        />\n      </button>\n      <button\n        type=\"button\"\n        aria-label=\"More response actions\"\n        onClick={onMore}\n        className={buttonClassName}\n      >\n        <EllipsisIcon className=\"size-3.5\" />\n      </button>\n    </div>\n  );\n}\n"
    }
  ]
}