チャットコンポーザーChatComposerExperimental

チャット入力の前後に選択肢、作業コンテキスト、使用量、補助アクセサリを組み合わせる上位コンテナです。

プレビュー

状態とバリエーション

選択肢付き

AI やシステムからの選択肢を、入力欄の直前に配置します。

どの整理方針で進めますか?

作業状態付き

ブランチ、作業フォルダ、使用量など入力に関係する補助情報を、操作できる状態としてまとめます。

#24feature/insights-panel作業状態を選択できます。

アクセサリ付き

入力欄の周辺に装飾や補助状態を重ねます。入力本体の責務には含めません。

装飾や補助状態は accessory / footer slot に置きます。

プロパティ

表は横にスクロールできます
プロパティ初期値説明
inputPropsChatInputProps-内側の ChatInput に渡す props です。
contextReact.ReactNode-作業フォルダ、ブランチ、PR 状態などの入力コンテキストです。
promptReact.ReactNode-AI からの選択肢や、送信前に確認する質問です。
statusReact.ReactNode-リアルタイム補足状態などを入力欄の上に置くための領域です。
footerReact.ReactNode-使用量など、入力欄の下に置く補足表示です。
accessoryReact.ReactNode-入力欄の周辺に重ねる補助 UI です。

使い方

import * as React from "react";
import { ChatComposer } from "@gunjo/ui";

export function ComposerWithChoices() {
  const [selected, setSelected] = React.useState("hybrid");
  const choices = [
    { id: "hybrid", label: "用途とタイプのハイブリッド" },
    { id: "file", label: "ファイルタイプで分ける" },
    { id: "date", label: "日付で分ける" },
    { id: "proposal", label: "まず提案だけ見たい" },
  ];

  return (
    <ChatComposer
      prompt={
        <div className="rounded-2xl border bg-background p-4 shadow-sm">
          <div className="mb-3 flex items-center justify-between gap-3">
            <p className="text-sm font-semibold">どの整理方針で進めますか?</p>
            <button type="button" className="rounded-md px-2 py-1 text-sm hover:bg-muted">
              スキップ
            </button>
          </div>
          <div className="space-y-2">
            {choices.map((choice, index) => (
              <button
                key={choice.id}
                type="button"
                onClick={() => setSelected(choice.id)}
                className={`flex w-full items-center gap-3 rounded-xl border px-3 py-2 text-left text-sm transition-colors ${selected === choice.id ? "border-primary-border bg-primary-subtle text-foreground" : "border-border bg-muted/20 text-muted-foreground hover:bg-muted/40"}`}
              >
                <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-background font-semibold">
                  {selected === choice.id ? "✓" : index + 1}
                </span>
                <span>{choice.label}</span>
              </button>
            ))}
          </div>
        </div>
      }
      inputProps={{
        onSend: (message, files) => console.log({ message, files }),
        placeholder: "または直接返信...",
        modelOptions: [
          { value: "auto", label: "自動", description: "内容に合わせて選択" },
          { value: "standard", label: "標準モデル", description: "通常の確認向け" },
          { value: "large", label: "大容量モデル", description: "長い文脈向け" },
          { value: "fast", label: "高速モデル", description: "短い確認向け" },
        ],
      }}
    />
  );
}

使用コンポーネント

設計の判断(UIXHERO)

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