チャットメッセージChatMessageExperimental

アシスタント、ユーザー、システム、入力中の会話行を表示するメッセージコンポーネントです。

プレビュー

状態とバリエーション

アシスタント

回答側は本文の枠を持たず、コピー・分岐・Raw の操作を下に並べます。

アシスタント10:01
候補を3件見つけました。条件を変える場合は分岐できます。

ユーザー

送信者側は右寄せの背景付き吹き出しにし、コピーと編集を操作に出します。

あなた10:02
この内容で進めて。

カードを含む回答

通常の文章とカードを同じ回答内に置く場合も、外側のメッセージ枠は増やしません。

アシスタント10:03

確認結果をまとめました。必要であれば、この草案を保存してから編集できます。

成果物ドラフト

drafts/component-audit.md

システム

会話の開始や区切りを中央の補助ラベルで示します。

会話を開始しました。

入力中

回答を生成中の一時状態です。本文が空の場合は入力中ラベルを表示し、複数文言を渡すとタイプ/削除で切り替わります。

アシスタント
内容を作成しています...

プロパティ

表は横にスクロールできます
プロパティ初期値説明
role"assistant" | "user" | "system"-メッセージの種類を指定します。
contentReactNode-本文です。アシスタント側ではカードや進捗表示も渡せます。
copyValuestring-本文が文字列ではない場合にコピーする値です。
userNamestring-表示名です。
timestampstring-時刻や補足メタ情報です。
isTypingbooleanfalse入力中表示に切り替えます。
actionsChatMessageAction[]-既定の操作を差し替える場合に指定します。
showActionsbooleantrue操作フッターの表示を切り替えます。
onAction(actionKey, event) => void-コピー、分岐、Raw、編集などの操作を受け取ります。
typingMessagesstring[]-入力中かつ本文が空の場合に、タイプ/削除で切り替える文言です。
labels.typingstring"内容を作成しています..."入力中かつ本文が空の場合に表示する文言です。

使い方

import { ChatMessage, ToastProvider, useToast } from "@gunjo/ui";

const actionMessages = {
  copy: "メッセージをコピーしました。",
  branch: "この回答から分岐します。",
  raw: "Raw 表示を開きます。",
  edit: "メッセージを編集します。",
};

function ConversationPreviewBody() {
  const { showToast } = useToast();

  const handleMessageAction = (action) => {
    showToast(actionMessages[action] ?? "操作を実行しました。", "success", 1800);
  };

  return (
    <div className="w-full max-w-2xl rounded-lg border bg-background">
      <ChatMessage role="system" content="会話を開始しました。" />
      <ChatMessage
        role="assistant"
        userName="アシスタント"
        content="確認したい内容を送ってください。回答側はカードや進捗を内包しやすいように、本文の背景と枠線を持ちません。"
        copyValue="確認したい内容を送ってください。"
        timestamp="10:01"
        onAction={handleMessageAction}
      />
      <ChatMessage
        role="user"
        userName="あなた"
        content="状態とバリエーションを見直して。"
        timestamp="10:02"
        onAction={handleMessageAction}
      />
      <ChatMessage role="assistant" userName="アシスタント" content="" isTyping />
    </div>
  );
}

export function ConversationPreview() {
  return (
    <ToastProvider labels={{ close: "閉じる" }}>
      <ConversationPreviewBody />
    </ToastProvider>
  );
}

使用コンポーネント

設計の判断(UIXHERO)

「いつ・なぜ使うか」の判断は、姉妹サイト UIXHERO の記事で解説しています。