{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"user-message","type":"registry:ui","title":"User Message","description":"The user's chat bubble — right-aligned, with hover actions to copy, edit the prompt, or regenerate the answer.","author":"Scrim UI (https://scrimui.dev)","categories":["messages"],"docs":"https://scrimui.dev/components/user-message","dependencies":[],"registryDependencies":[],"files":[{"path":"src/showcase/user-message/user-message.tsx","content":"\"use client\";\n\nimport * as React from \"react\";\n\n/* ------------------------------------------------------------------ */\n/* Types                                                               */\n/* ------------------------------------------------------------------ */\n\nexport type UserMessageProps = {\n  text: string;\n  /** Shows an \"Edited\" chip next to the sender name. */\n  edited?: boolean;\n  showActions?: boolean;\n  onCopy?: () => void;\n  onEdit?: () => void;\n  onRegenerate?: () => void;\n  avatar?: React.ReactNode;\n  className?: string;\n};\n\n/* ------------------------------------------------------------------ */\n/* Icons                                                               */\n/* ------------------------------------------------------------------ */\n\nfunction CopyIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"13\" height=\"13\">\n      <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" />\n      <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n    </svg>\n  );\n}\n\nfunction EditIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"13\" height=\"13\">\n      <path d=\"M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z\" />\n    </svg>\n  );\n}\n\nfunction RegenerateIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"13\" height=\"13\">\n      <path d=\"M21 12a9 9 0 1 1-2.64-6.36L21 8\" />\n      <path d=\"M21 3v5h-5\" />\n    </svg>\n  );\n}\n\n/* ------------------------------------------------------------------ */\n/* UserMessage                                                         */\n/* ------------------------------------------------------------------ */\n\nexport function UserMessage({\n  text,\n  edited = false,\n  showActions = true,\n  onCopy,\n  onEdit,\n  onRegenerate,\n  avatar,\n  className = \"\",\n}: UserMessageProps) {\n  const [copied, setCopied] = React.useState(false);\n\n  const copy = () => {\n    onCopy?.();\n    setCopied(true);\n    window.setTimeout(() => setCopied(false), 1500);\n  };\n\n  return (\n    <div className={`flex items-start justify-end gap-3 ${className}`}>\n      <div className=\"min-w-0 max-w-[85%]\">\n        <div className=\"flex flex-wrap items-center justify-end gap-2\">\n          <span className=\"text-sm font-medium\">You</span>\n          {edited && (\n            <span className=\"rounded-full bg-zinc-100 px-2 py-0.5 text-[11px] text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400\">\n              Edited\n            </span>\n          )}\n        </div>\n\n        <div className=\"mt-1.5 whitespace-pre-wrap rounded-2xl rounded-tr-md bg-zinc-900 px-4 py-3 text-[15px] leading-6 text-white dark:bg-zinc-100 dark:text-zinc-900\">\n          {text}\n        </div>\n\n        {showActions && (onCopy || onEdit || onRegenerate) && (\n          <div className=\"mt-2 flex items-center justify-end gap-1\">\n            {onCopy && (\n              <button\n                type=\"button\"\n                onClick={copy}\n                className=\"inline-flex h-7 items-center gap-1.5 rounded-lg px-2 text-xs text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-900 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-100\"\n              >\n                <CopyIcon />\n                {copied ? \"Copied\" : \"Copy\"}\n              </button>\n            )}\n            {onEdit && (\n              <button\n                type=\"button\"\n                onClick={onEdit}\n                className=\"inline-flex h-7 items-center gap-1.5 rounded-lg px-2 text-xs text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-900 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-100\"\n              >\n                <EditIcon />\n                Edit\n              </button>\n            )}\n            {onRegenerate && (\n              <button\n                type=\"button\"\n                onClick={onRegenerate}\n                className=\"inline-flex h-7 items-center gap-1.5 rounded-lg px-2 text-xs text-zinc-500 transition-colors hover:bg-zinc-100 hover:text-zinc-900 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-100\"\n              >\n                <RegenerateIcon />\n                Regenerate\n              </button>\n            )}\n          </div>\n        )}\n      </div>\n\n      {avatar ?? (\n        <div className=\"flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-lg bg-zinc-200 text-xs font-semibold text-zinc-700 dark:bg-zinc-700 dark:text-zinc-200\">\n          You\n        </div>\n      )}\n    </div>\n  );\n}\n","type":"registry:ui","target":"components/ui/user-message.tsx"}]}