{"version":3,"file":"CopilotChatUserMessage.mjs","names":[],"sources":["../../../src/components/chat/CopilotChatUserMessage.tsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { Copy, Check, Edit, ChevronLeft, ChevronRight } from \"lucide-react\";\nimport {\n  useCopilotChatConfiguration,\n  CopilotChatDefaultLabels,\n} from \"@/providers/CopilotChatConfigurationProvider\";\nimport { twMerge } from \"tailwind-merge\";\nimport { Button } from \"@/components/ui/button\";\nimport { UserMessage } from \"@ag-ui/core\";\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { renderSlot, WithSlots } from \"@/lib/slots\";\n\nfunction flattenUserMessageContent(content?: UserMessage[\"content\"]): string {\n  if (!content) {\n    return \"\";\n  }\n\n  if (typeof content === \"string\") {\n    return content;\n  }\n\n  return content\n    .map((part) => {\n      if (\n        part &&\n        typeof part === \"object\" &&\n        \"type\" in part &&\n        (part as { type?: unknown }).type === \"text\" &&\n        typeof (part as { text?: unknown }).text === \"string\"\n      ) {\n        return (part as { text: string }).text;\n      }\n      return \"\";\n    })\n    .filter((text) => text.length > 0)\n    .join(\"\\n\");\n}\n\nexport interface CopilotChatUserMessageOnEditMessageProps {\n  message: UserMessage;\n}\n\nexport interface CopilotChatUserMessageOnSwitchToBranchProps {\n  message: UserMessage;\n  branchIndex: number;\n  numberOfBranches: number;\n}\n\nexport type CopilotChatUserMessageProps = WithSlots<\n  {\n    messageRenderer: typeof CopilotChatUserMessage.MessageRenderer;\n    toolbar: typeof CopilotChatUserMessage.Toolbar;\n    copyButton: typeof CopilotChatUserMessage.CopyButton;\n    editButton: typeof CopilotChatUserMessage.EditButton;\n    branchNavigation: typeof CopilotChatUserMessage.BranchNavigation;\n  },\n  {\n    onEditMessage?: (props: CopilotChatUserMessageOnEditMessageProps) => void;\n    onSwitchToBranch?: (\n      props: CopilotChatUserMessageOnSwitchToBranchProps,\n    ) => void;\n    message: UserMessage;\n    branchIndex?: number;\n    numberOfBranches?: number;\n    additionalToolbarItems?: React.ReactNode;\n  } & React.HTMLAttributes<HTMLDivElement>\n>;\n\nexport function CopilotChatUserMessage({\n  message,\n  onEditMessage,\n  branchIndex,\n  numberOfBranches,\n  onSwitchToBranch,\n  additionalToolbarItems,\n  messageRenderer,\n  toolbar,\n  copyButton,\n  editButton,\n  branchNavigation,\n  children,\n  className,\n  ...props\n}: CopilotChatUserMessageProps) {\n  const flattenedContent = useMemo(\n    () => flattenUserMessageContent(message.content),\n    [message.content],\n  );\n\n  const BoundMessageRenderer = renderSlot(\n    messageRenderer,\n    CopilotChatUserMessage.MessageRenderer,\n    {\n      content: flattenedContent,\n    },\n  );\n\n  const BoundCopyButton = renderSlot(\n    copyButton,\n    CopilotChatUserMessage.CopyButton,\n    {\n      onClick: async () => {\n        if (flattenedContent) {\n          try {\n            await navigator.clipboard.writeText(flattenedContent);\n          } catch (err) {\n            console.error(\"Failed to copy message:\", err);\n          }\n        }\n      },\n    },\n  );\n\n  const BoundEditButton = renderSlot(\n    editButton,\n    CopilotChatUserMessage.EditButton,\n    {\n      onClick: () => onEditMessage?.({ message }),\n    },\n  );\n\n  const BoundBranchNavigation = renderSlot(\n    branchNavigation,\n    CopilotChatUserMessage.BranchNavigation,\n    {\n      currentBranch: branchIndex,\n      numberOfBranches,\n      onSwitchToBranch,\n      message,\n    },\n  );\n\n  const showBranchNavigation =\n    numberOfBranches && numberOfBranches > 1 && onSwitchToBranch;\n\n  const BoundToolbar = renderSlot(toolbar, CopilotChatUserMessage.Toolbar, {\n    children: (\n      <div className=\"cpk:flex cpk:items-center cpk:gap-1 cpk:justify-end\">\n        {additionalToolbarItems}\n        {BoundCopyButton}\n        {onEditMessage && BoundEditButton}\n        {showBranchNavigation && BoundBranchNavigation}\n      </div>\n    ),\n  });\n\n  if (children) {\n    return (\n      <div data-copilotkit style={{ display: \"contents\" }}>\n        {children({\n          messageRenderer: BoundMessageRenderer,\n          toolbar: BoundToolbar,\n          copyButton: BoundCopyButton,\n          editButton: BoundEditButton,\n          branchNavigation: BoundBranchNavigation,\n          message,\n          branchIndex,\n          numberOfBranches,\n          additionalToolbarItems,\n        })}\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-copilotkit\n      data-testid=\"copilot-user-message\"\n      className={twMerge(\n        \"copilotKitMessage copilotKitUserMessage cpk:flex cpk:flex-col cpk:items-end cpk:group cpk:pt-10\",\n        className,\n      )}\n      data-message-id={message.id}\n      {...props}\n    >\n      {BoundMessageRenderer}\n      {BoundToolbar}\n    </div>\n  );\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace CopilotChatUserMessage {\n  export const Container: React.FC<\n    React.PropsWithChildren<React.HTMLAttributes<HTMLDivElement>>\n  > = ({ children, className, ...props }) => (\n    <div\n      className={twMerge(\n        \"cpk:flex cpk:flex-col cpk:items-end cpk:group\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n\n  export const MessageRenderer: React.FC<{\n    content: string;\n    className?: string;\n  }> = ({ content, className }) => (\n    <div\n      className={twMerge(\n        \"cpk:prose cpk:dark:prose-invert cpk:bg-muted cpk:relative cpk:max-w-[80%] cpk:rounded-[18px] cpk:px-4 cpk:py-1.5 cpk:data-[multiline]:py-3 cpk:inline-block cpk:whitespace-pre-wrap\",\n        className,\n      )}\n    >\n      {content}\n    </div>\n  );\n\n  export const Toolbar: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({\n    className,\n    ...props\n  }) => (\n    <div\n      data-testid=\"copilot-user-toolbar\"\n      className={twMerge(\n        \"cpk:w-full cpk:bg-transparent cpk:flex cpk:items-center cpk:justify-end cpk:-mr-[5px] cpk:mt-[4px] cpk:invisible cpk:group-hover:visible\",\n        className,\n      )}\n      {...props}\n    />\n  );\n\n  export const ToolbarButton: React.FC<\n    React.ButtonHTMLAttributes<HTMLButtonElement> & {\n      title: string;\n      children: React.ReactNode;\n    }\n  > = ({ title, children, className, ...props }) => {\n    return (\n      <Tooltip>\n        <TooltipTrigger asChild>\n          <Button\n            type=\"button\"\n            variant=\"assistantMessageToolbarButton\"\n            aria-label={title}\n            className={twMerge(className)}\n            {...props}\n          >\n            {children}\n          </Button>\n        </TooltipTrigger>\n        <TooltipContent side=\"bottom\">\n          <p>{title}</p>\n        </TooltipContent>\n      </Tooltip>\n    );\n  };\n\n  export const CopyButton: React.FC<\n    React.ButtonHTMLAttributes<HTMLButtonElement> & { copied?: boolean }\n  > = ({ className, title, onClick, ...props }) => {\n    const config = useCopilotChatConfiguration();\n    const labels = config?.labels ?? CopilotChatDefaultLabels;\n    const [copied, setCopied] = useState(false);\n\n    const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n      setCopied(true);\n      setTimeout(() => setCopied(false), 2000);\n\n      if (onClick) {\n        onClick(event);\n      }\n    };\n\n    return (\n      <ToolbarButton\n        data-testid=\"copilot-user-copy-button\"\n        title={title || labels.userMessageToolbarCopyMessageLabel}\n        onClick={handleClick}\n        className={className}\n        {...props}\n      >\n        {copied ? (\n          <Check className=\"cpk:size-[18px]\" />\n        ) : (\n          <Copy className=\"cpk:size-[18px]\" />\n        )}\n      </ToolbarButton>\n    );\n  };\n\n  export const EditButton: React.FC<\n    React.ButtonHTMLAttributes<HTMLButtonElement>\n  > = ({ className, title, ...props }) => {\n    const config = useCopilotChatConfiguration();\n    const labels = config?.labels ?? CopilotChatDefaultLabels;\n    return (\n      <ToolbarButton\n        data-testid=\"copilot-edit-button\"\n        title={title || labels.userMessageToolbarEditMessageLabel}\n        className={className}\n        {...props}\n      >\n        <Edit className=\"cpk:size-[18px]\" />\n      </ToolbarButton>\n    );\n  };\n\n  export const BranchNavigation: React.FC<\n    React.HTMLAttributes<HTMLDivElement> & {\n      currentBranch?: number;\n      numberOfBranches?: number;\n      onSwitchToBranch?: (\n        props: CopilotChatUserMessageOnSwitchToBranchProps,\n      ) => void;\n      message: UserMessage;\n    }\n  > = ({\n    className,\n    currentBranch = 0,\n    numberOfBranches = 1,\n    onSwitchToBranch,\n    message,\n    ...props\n  }) => {\n    if (!numberOfBranches || numberOfBranches <= 1 || !onSwitchToBranch) {\n      return null;\n    }\n\n    const canGoPrev = currentBranch > 0;\n    const canGoNext = currentBranch < numberOfBranches - 1;\n\n    return (\n      <div\n        data-testid=\"copilot-branch-navigation\"\n        className={twMerge(\"cpk:flex cpk:items-center cpk:gap-1\", className)}\n        {...props}\n      >\n        <Button\n          type=\"button\"\n          variant=\"assistantMessageToolbarButton\"\n          onClick={() =>\n            onSwitchToBranch?.({\n              branchIndex: currentBranch - 1,\n              numberOfBranches,\n              message,\n            })\n          }\n          disabled={!canGoPrev}\n          className=\"cpk:h-6 cpk:w-6 cpk:p-0\"\n        >\n          <ChevronLeft className=\"cpk:size-[20px]\" />\n        </Button>\n        <span className=\"cpk:text-sm cpk:text-muted-foreground cpk:px-0 cpk:font-medium\">\n          {currentBranch + 1}/{numberOfBranches}\n        </span>\n        <Button\n          type=\"button\"\n          variant=\"assistantMessageToolbarButton\"\n          onClick={() =>\n            onSwitchToBranch?.({\n              branchIndex: currentBranch + 1,\n              numberOfBranches,\n              message,\n            })\n          }\n          disabled={!canGoNext}\n          className=\"cpk:h-6 cpk:w-6 cpk:p-0\"\n        >\n          <ChevronRight className=\"cpk:size-[20px]\" />\n        </Button>\n      </div>\n    );\n  };\n}\n\nCopilotChatUserMessage.Container.displayName =\n  \"CopilotChatUserMessage.Container\";\nCopilotChatUserMessage.MessageRenderer.displayName =\n  \"CopilotChatUserMessage.MessageRenderer\";\nCopilotChatUserMessage.Toolbar.displayName = \"CopilotChatUserMessage.Toolbar\";\nCopilotChatUserMessage.ToolbarButton.displayName =\n  \"CopilotChatUserMessage.ToolbarButton\";\nCopilotChatUserMessage.CopyButton.displayName =\n  \"CopilotChatUserMessage.CopyButton\";\nCopilotChatUserMessage.EditButton.displayName =\n  \"CopilotChatUserMessage.EditButton\";\nCopilotChatUserMessage.BranchNavigation.displayName =\n  \"CopilotChatUserMessage.BranchNavigation\";\n\nexport default CopilotChatUserMessage;\n"],"mappings":"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"}