TypeScript · 1737 bytes Raw Blame History
1 import { useState } from "react";
2
3 interface ToolUseBlockProps {
4 name: string;
5 input: unknown;
6 }
7
8 export function ToolUseBlock({ name, input }: ToolUseBlockProps) {
9 const [expanded, setExpanded] = useState(false);
10 const preview = summarizeInput(input);
11
12 return (
13 <div className="my-2 overflow-hidden rounded border border-border bg-bg-2">
14 <button
15 type="button"
16 onClick={() => setExpanded((x) => !x)}
17 className="flex w-full items-center justify-between gap-2 px-3 py-1.5 text-left text-[12px] transition hover:bg-bg-3"
18 >
19 <span className="flex items-center gap-2 font-mono">
20 <span className="text-accent"></span>
21 <span className="font-semibold text-fg-0">{name}</span>
22 {preview && (
23 <span className="truncate text-fg-3">{preview}</span>
24 )}
25 </span>
26 <span className="text-[10px] text-fg-3">
27 {expanded ? "hide" : "show"}
28 </span>
29 </button>
30 {expanded && (
31 <pre className="max-h-96 overflow-auto border-t border-border bg-bg-1 p-3 font-mono text-[11px] leading-relaxed text-fg-1">
32 {JSON.stringify(input, null, 2)}
33 </pre>
34 )}
35 </div>
36 );
37 }
38
39 function summarizeInput(input: unknown): string {
40 if (typeof input !== "object" || input === null) return "";
41 const obj = input as Record<string, unknown>;
42 // Common first-argument fields across Claude Code tools.
43 for (const key of [
44 "file_path",
45 "path",
46 "command",
47 "pattern",
48 "url",
49 "query",
50 "notebook_path",
51 ]) {
52 if (typeof obj[key] === "string") {
53 const s = obj[key] as string;
54 return s.length > 80 ? `${s.slice(0, 77)}…` : s;
55 }
56 }
57 return "";
58 }