[ PROMPT_NODE_28018 ]
composition
[ SKILL_DOCUMENTATION ]
# 组件组合
## 内容
- 项目必须始终位于其 Group 组件内
- Callouts 使用 Alert
- 空状态使用 Empty 组件
- Toast 通知使用 sonner
- 在覆盖层组件之间进行选择
- Dialog, Sheet 和 Drawer 始终需要 Title
- Card 结构
- Button 没有 isPending 或 isLoading 属性
- TabsTrigger 必须位于 TabsList 内
- Avatar 始终需要 AvatarFallback
- 使用 Separator 代替原始的 hr 或边框 div
- 使用 Skeleton 作为加载占位符
- 使用 Badge 代替自定义样式的 span
---
## 项目必须始终位于其 Group 组件内
切勿将项目直接渲染在内容容器内。
**错误:**
tsx
Apple
Banana
**正确:**
tsx
Apple
Banana
这适用于所有基于组的组件:
| 项目 | 组 |
|------|-------|
| `SelectItem`, `SelectLabel` | `SelectGroup` |
| `DropdownMenuItem`, `DropdownMenuLabel`, `DropdownMenuSub` | `DropdownMenuGroup` |
| `MenubarItem` | `MenubarGroup` |
| `ContextMenuItem` | `ContextMenuGroup` |
| `CommandItem` | `CommandGroup` |
---
## Callouts 使用 Alert
tsx
Warning
Something needs attention.
---
## 空状态使用 Empty 组件
tsx
No projects yet
Get started by creating a new project.
---
## Toast 通知使用 sonner
tsx
import { toast } from "sonner"
toast.success("Changes saved.")
toast.error("Something went wrong.")
toast("File deleted.", {
action: { label: "Undo", onClick: () => undoDelete() },
})
---
## 在覆盖层组件之间进行选择
| 用例 | 组件 |
|----------|-----------|
| 需要输入的聚焦任务 | `Dialog` |
| 破坏性操作确认 | `AlertDialog` |
| 带有详情或过滤器的侧边栏 | `Sheet` |
| 移动端优先的底部面板 | `Drawer` |
| 悬停时的快速信息 | `HoverCard` |
| 点击时的小型上下文内容 | `Popover` |
---
## Dialog, Sheet 和 Drawer 始终需要 Title
`Dia