组件
AI 任务清单 AI Todo
展示 Agent 计划、执行进度与任务说明。
基础示例
Loading…
pnpm dlx wui@latest add @wui/ai-todo"use client"
import * as React from "react"
import { cva } from "class-variance-authority"
import {
BanIcon,
CheckIcon,
CircleIcon,
LoaderCircleIcon,
ListTodoIcon,
} from "lucide-react"
import { cn } from "@/lib/utils"
export type AiTodoStatus =
| "pending"
| "in-progress"
| "completed"
| "cancelled"
const aiTodoIndicatorVariants = cva(
"flex size-5 shrink-0 items-center justify-center rounded-full border",
{
variants: {
status: {
pending: "border-border text-muted-foreground",
"in-progress": "border-info/40 bg-info/10 text-info",
completed: "border-success bg-success text-success-foreground",
cancelled: "border-border bg-muted text-muted-foreground",
},
},
defaultVariants: { status: "pending" },
}
)
const todoIcons = {
pending: CircleIcon,
"in-progress": LoaderCircleIcon,
completed: CheckIcon,
cancelled: BanIcon,
} as const
function AiTodo({ className, ...props }: React.ComponentProps<"section">) {
return (
<section
data-slot="ai-todo"
className={cn("overflow-hidden rounded-md border bg-background", className)}
{...props}
/>
)
}
function AiTodoHeader({
className,
children,
...props
}: React.ComponentProps<"header">) {
return (
<header
data-slot="ai-todo-header"
className={cn(
"flex items-center gap-2 border-b px-3 py-2.5 text-sm font-medium",
className
)}
{...props}
>
<ListTodoIcon className="size-4 text-muted-foreground" />
{children}
</header>
)
}
function AiTodoList({ className, ...props }: React.ComponentProps<"ol">) {
return (
<ol
data-slot="ai-todo-list"
className={cn("divide-y", className)}
{...props}
/>
)
}
export interface AiTodoItemProps
extends Omit<React.ComponentProps<"li">, "title"> {
/** Main task label. */
title: React.ReactNode
/** Optional supporting detail. */
description?: React.ReactNode
/** Task progression state. @default "pending" */
status?: AiTodoStatus
/** Called when the status control is pressed. */
onStatusChange?: (status: AiTodoStatus) => void
}
/** A readable task row with optional status interaction. */
function AiTodoItem({
className,
title,
description,
status = "pending",
onStatusChange,
...props
}: AiTodoItemProps) {
const Icon = todoIcons[status]
const nextStatus = status === "completed" ? "pending" : "completed"
return (
<li
data-slot="ai-todo-item"
data-status={status}
className={cn("flex items-start gap-3 px-3 py-3", className)}
{...props}
>
<button
type="button"
data-slot="ai-todo-indicator"
aria-label={status === "completed" ? "标记为未完成" : "标记为已完成"}
disabled={!onStatusChange}
className={cn(
aiTodoIndicatorVariants({ status }),
onStatusChange
? "cursor-pointer outline-none focus-visible:ring-[3px] focus-visible:ring-ring/35"
: "cursor-default"
)}
onClick={() => onStatusChange?.(nextStatus)}
>
<Icon
className={cn(
"size-3",
status === "in-progress" && "motion-safe:animate-spin"
)}
/>
</button>
<div className="min-w-0 flex-1">
<div
data-slot="ai-todo-title"
className={cn(
"text-sm font-medium leading-5",
(status === "completed" || status === "cancelled") &&
"text-muted-foreground line-through"
)}
>
{title}
</div>
{description ? (
<div
data-slot="ai-todo-description"
className="mt-0.5 text-xs leading-5 text-muted-foreground"
>
{description}
</div>
) : null}
</div>
</li>
)
}
export {
AiTodo,
AiTodoHeader,
AiTodoItem,
AiTodoList,
aiTodoIndicatorVariants,
}
组件作用
AiTodo 用于展示 Agent 已形成的计划和实时执行进度,让用户知道当前完成了什么、正在处理什么、还剩什么。它适合短到中等长度的工作流,不负责排序、持久化或任务依赖。
需要拖拽流转的团队任务应使用 Kanban,需要按时间说明事件则使用 Timeline。
组件属性
No documented props for "ai-todo".
事件
为 AiTodoItem 传入 onStatusChange 后,状态图标会成为可交互按钮,并在点击时在 completed 与 pending 之间切换建议状态。实际状态仍由调用方控制,便于接入消息流或后端任务数据。
扩展使用
只读执行计划
省略 onStatusChange 即得到只读任务行,适合展示模型生成的计划。in-progress 用于唯一的当前任务;同时出现多个执行中状态时,应确认 Agent 是否真的并行工作。
进度汇总
在 AiTodoHeader 右侧放入“已完成 / 总数”,即可提供稳定的总体进度。取消任务使用 cancelled,不要把取消和失败混成同一个状态。