plan-tool
agent-elements/plan-toolFreeComponent
agent-elements publishes no description for this item.
Live preview
live · rendered by the registry
Rendered by agent-elements on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://agent-elements.21st.dev/r/plan-tool.jsonSource
1import { memo, useState } from "react";2import {3 IconChevronsDown,4 IconChevronsUp,5 IconFileDescription,6} from "@tabler/icons-react";7import { Markdown } from "../markdown";8import { IconSpinner } from "../icons";9import { areToolPropsEqual, getToolStatus } from "../utils/format-tool";10import { cn } from "../utils/cn";1112export type Plan = {13 id?: string;14 title: string;15 summary?: string;16};1718export type PlanToolProps = {19 part: {20 type: string;21 toolCallId?: string;22 state?: string;23 input?: {24 plan?: Plan;25 onApprove?: () => void;26 approveLabel?: string;27 approved?: boolean;28 };29 };30 chatStatus?: string;31};3233function getPlanFileName(plan: Plan) {34 const rawId = plan.id?.trim();35 if (!rawId) return "plan-working.md";36 if (rawId.endsWith(".md")) return rawId;37 return `plan-${rawId}.md`;38}3940export const PlanTool = memo(function PlanTool({41 part,42 chatStatus,43}: PlanToolProps) {44 const { isPending } = getToolStatus(part, chatStatus);45 const plan = part.input?.plan;46 const [isExpanded, setIsExpanded] = useState(false);47 const [isApproved, setIsApproved] = useState(false);4849 if (!plan) return null;5051 const fileName = getPlanFileName(plan);52 const summary = plan.summary?.trim() ?? "";53 const hasSummary = summary.length > 0;5455 const approveLabel = part.input?.approveLabel ?? "Approve";56 const isAlreadyApproved = part.input?.approved || isApproved;57 const approveText = isAlreadyApproved ? "Approved" : approveLabel;5859 const handleApprove = () => {60 if (isAlreadyApproved) return;61 setIsApproved(true);62 if (typeof part.input?.onApprove === "function") {63 part.input.onApprove();64 }65 };6667 return (68 <div className="an-tool-plan rounded-an-tool-border-radius border border-border bg-an-tool-background overflow-hidden">69 <div className="h-7 pl-3 pr-2.5 flex items-center justify-between">70 <div className="min-w-0 flex items-center gap-1">71 {isPending ? (72 <IconSpinner className="w-3 h-3 text-an-tool-color-muted animate-spin shrink-0" />73 ) : (74 <IconFileDescription className="w-3.5 h-3.5 text-an-tool-color-muted shrink-0" />75 )}76 <span className="text-xs text-an-tool-color-muted truncate">77 {fileName}78 </span>79 </div>80 <button81 type="button"82 onClick={() => setIsExpanded((prev) => !prev)}83 aria-label={isExpanded ? "Collapse plan" : "Expand plan"}84// … truncated
More from agent-elements
All 25 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| agent-chatagent-chat | agent-elements | Components | Free | no deps | |
| attachment-buttonattachment-button | agent-elements | Components | Free | no deps | |
| bash-toolbash-tool | agent-elements | Components | Free | no deps | |
| edit-tooledit-tool | agent-elements | Components | Free | no deps | |
| error-messageerror-message | agent-elements | Components | Free | no deps | |
| file-attachmentfile-attachment | agent-elements | Components | Free | no deps | |
| generic-toolgeneric-tool | agent-elements | Components | Free | no deps | |
| input-barinput-bar | agent-elements | Components | Free | no deps |
