{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "tool-invocation",
	"type": "registry:ui",
	"title": "Tool Invocation",
	"description": "A component that displays a tool invocation with a collapsible content.",
	"registryDependencies": ["card", "collapsible"],
	"files": [
		{
			"path": "./src/registry/ui/tool-invocation.tsx",
			"content": "\"use client\";\n\nimport { AlertCircle, CheckCircleIcon } from \"lucide-react\";\nimport { type ComponentProps, useState } from \"react\";\nimport { Card } from \"@/components/ui/card\";\nimport {\n\tCollapsible,\n\tCollapsibleContent,\n\tCollapsibleTrigger,\n} from \"@/components/ui/collapsible\";\nimport { cn } from \"@/lib/utils\";\nimport { idToReadableText } from \"@/registry/lib/id-to-readable-text\";\n\nexport function ToolInvocation({\n\tclassName,\n\t...props\n}: ComponentProps<typeof Card>) {\n\treturn (\n\t\t<Card\n\t\t\tclassName={cn(\"max-w-full overflow-hidden p-0 gap-0\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport function ToolInvocationHeader({\n\tclassName,\n\t...props\n}: ComponentProps<\"div\">) {\n\treturn <div className={cn(\"px-4 py-3 border-b\", className)} {...props} />;\n}\n\nexport function ToolInvocationName({\n\tname,\n\tcapitalize = true,\n\ttype,\n\tisError = false,\n\tclassName,\n}: {\n\tname: string;\n\tcapitalize?: boolean;\n\ttype:\n\t\t| \"input-streaming\"\n\t\t| \"input-available\"\n\t\t| \"output-available\"\n\t\t| \"output-error\";\n\tisError?: boolean;\n\tclassName?: string;\n}) {\n\t// Combine explicit error state with passed error flag\n\tconst hasError = type === \"output-error\" || isError;\n\n\treturn (\n\t\t<div className={cn(\"flex items-center gap-2 text-sm\", className)}>\n\t\t\t{(type === \"input-streaming\" || type === \"input-available\") && (\n\t\t\t\t<ToolInvocationLoadingIcon\n\t\t\t\t\tclassName=\"size-4 text-muted-foreground\"\n\t\t\t\t\tduration=\"2s\"\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{type === \"output-available\" && !hasError && (\n\t\t\t\t<CheckCircleIcon className=\"size-4 text-muted-foreground\" />\n\t\t\t)}\n\t\t\t{hasError && <AlertCircle className=\"size-4 text-red-500\" />}\n\t\t\t<span className={cn(\"font-medium\", hasError && \"text-red-600\")}>\n\t\t\t\t{idToReadableText(name, { capitalize })}\n\t\t\t</span>\n\t\t</div>\n\t);\n}\n\nexport function ToolInvocationContent({\n\tchildren,\n\tclassName,\n}: {\n\tchildren: React.ReactNode;\n\tclassName?: string;\n}) {\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t<span className=\"text-xs font-medium text-muted-foreground\">\n\t\t\t\t\tTool Details\n\t\t\t\t</span>\n\t\t\t</div>\n\n\t\t\t<div className={cn(\"px-4 py-3 space-y-4\", className)}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function ToolInvocationContentCollapsible({\n\tchildren,\n\tclassName,\n\tdefaultOpen = false,\n\topen: controlledOpen,\n}: {\n\tchildren: React.ReactNode;\n\tclassName?: string;\n\tdefaultOpen?: boolean;\n\topen?: boolean;\n}) {\n\tconst [internalOpen, setInternalOpen] = useState(defaultOpen);\n\tconst open = controlledOpen !== undefined ? controlledOpen : internalOpen;\n\n\treturn (\n\t\t<Collapsible\n\t\t\topen={open}\n\t\t\tonOpenChange={\n\t\t\t\tcontrolledOpen !== undefined ? undefined : setInternalOpen\n\t\t\t}\n\t\t>\n\t\t\t<CollapsibleTrigger className=\"w-full px-4 py-2 text-left border-b bg-muted/30 hover:bg-muted/50 transition-colors\">\n\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t<span className=\"text-xs font-medium text-muted-foreground\">\n\t\t\t\t\t\tTool Details\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t{open ? \"collapse\" : \"expand\"}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</CollapsibleTrigger>\n\n\t\t\t<CollapsibleContent>\n\t\t\t\t<div className={cn(\"px-4 py-3 space-y-4\", className)}>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</CollapsibleContent>\n\t\t</Collapsible>\n\t);\n}\n\nexport function ToolInvocationRawData({\n\tdata,\n\ttitle = \"Data\",\n}: {\n\tdata: unknown;\n\ttitle?: string;\n}) {\n\treturn (\n\t\t<div className=\"space-y-2\">\n\t\t\t<h4 className=\"text-xs font-semibold text-muted-foreground uppercase tracking-wide\">\n\t\t\t\t{title}\n\t\t\t</h4>\n\t\t\t<div className=\"max-h-48 overflow-auto\">\n\t\t\t\t<pre className=\"whitespace-pre-wrap break-all font-mono text-xs bg-muted/50 p-3 rounded-md border\">\n\t\t\t\t\t{JSON.stringify(data, null, 2)}\n\t\t\t\t</pre>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function ToolInvocationLoadingIcon({\n\tduration = \"3s\",\n\tsphereRadius = 20,\n\t...props\n}: ComponentProps<\"svg\"> & { duration?: string; sphereRadius?: number }) {\n\tconst topPos = { x: 50, y: sphereRadius };\n\tconst bottomLeftPos = { x: sphereRadius, y: 100 - sphereRadius };\n\tconst bottomRightPos = { x: 100 - sphereRadius, y: 100 - sphereRadius };\n\n\tconst path1to2 = `M 0 0 L ${bottomLeftPos.x - topPos.x} ${bottomLeftPos.y - topPos.y}`;\n\tconst path2to3 = `M 0 0 L ${bottomRightPos.x - bottomLeftPos.x} ${bottomRightPos.y - bottomLeftPos.y}`;\n\tconst path3to1 = `M 0 0 L ${topPos.x - bottomRightPos.x} ${topPos.y - bottomRightPos.y}`;\n\n\treturn (\n\t\t<svg\n\t\t\tviewBox=\"0 0 100 100\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tcolor=\"currentColor\" // Explicitly set color for inheritance\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\tfill=\"currentColor\" // Set default fill for children\n\t\t\t{...props} // Pass className, style, id etc.\n\t\t>\n\t\t\t<title>Loading Pyramid</title>\n\n\t\t\t<circle cx={topPos.x} cy={topPos.y} r={sphereRadius}>\n\t\t\t\t<animateMotion\n\t\t\t\t\tpath={path1to2}\n\t\t\t\t\tdur={duration}\n\t\t\t\t\trepeatCount=\"indefinite\"\n\t\t\t\t\tcalcMode=\"linear\"\n\t\t\t\t/>\n\t\t\t</circle>\n\n\t\t\t<circle cx={bottomLeftPos.x} cy={bottomLeftPos.y} r={sphereRadius}>\n\t\t\t\t<animateMotion\n\t\t\t\t\tpath={path2to3}\n\t\t\t\t\tdur={duration}\n\t\t\t\t\trepeatCount=\"indefinite\"\n\t\t\t\t\tcalcMode=\"linear\"\n\t\t\t\t/>\n\t\t\t</circle>\n\n\t\t\t<circle\n\t\t\t\tcx={bottomRightPos.x}\n\t\t\t\tcy={bottomRightPos.y}\n\t\t\t\tr={sphereRadius}\n\t\t\t>\n\t\t\t\t<animateMotion\n\t\t\t\t\tpath={path3to1}\n\t\t\t\t\tdur={duration}\n\t\t\t\t\trepeatCount=\"indefinite\"\n\t\t\t\t\tcalcMode=\"linear\"\n\t\t\t\t/>\n\t\t\t</circle>\n\t\t</svg>\n\t);\n}\n",
			"type": "registry:ui"
		},
		{
			"path": "./src/registry/lib/id-to-readable-text.ts",
			"content": "export function idToReadableText(\n\tid: string,\n\toptions?: { capitalize?: boolean },\n): string {\n\tconst { capitalize = true } = options || {};\n\tconst readable = id\n\t\t.replace(/([a-z])([A-Z])/g, \"$1 $2\")\n\t\t.replace(/[_-]/g, \" \")\n\t\t.toLowerCase();\n\n\treturn capitalize\n\t\t? readable.replace(/\\b\\w/g, (l) => l.toUpperCase())\n\t\t: readable;\n}\n",
			"type": "registry:lib"
		}
	]
}
