@teamix-evo/ui 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +336 -0
- package/_data.json +12 -0
- package/manifest.json +1688 -0
- package/package.json +90 -0
- package/src/components/accordion/accordion.meta.md +87 -0
- package/src/components/accordion/accordion.stories.tsx +67 -0
- package/src/components/accordion/accordion.tsx +58 -0
- package/src/components/affix/affix.meta.md +80 -0
- package/src/components/affix/affix.stories.tsx +57 -0
- package/src/components/affix/affix.tsx +97 -0
- package/src/components/alert/alert.meta.md +101 -0
- package/src/components/alert/alert.stories.tsx +93 -0
- package/src/components/alert/alert.tsx +132 -0
- package/src/components/alert-dialog/alert-dialog.meta.md +107 -0
- package/src/components/alert-dialog/alert-dialog.stories.tsx +81 -0
- package/src/components/alert-dialog/alert-dialog.tsx +136 -0
- package/src/components/anchor/anchor.meta.md +87 -0
- package/src/components/anchor/anchor.stories.tsx +74 -0
- package/src/components/anchor/anchor.tsx +130 -0
- package/src/components/app/app.meta.md +86 -0
- package/src/components/app/app.stories.tsx +62 -0
- package/src/components/app/app.tsx +58 -0
- package/src/components/aspect-ratio/aspect-ratio.meta.md +81 -0
- package/src/components/aspect-ratio/aspect-ratio.stories.tsx +59 -0
- package/src/components/aspect-ratio/aspect-ratio.tsx +22 -0
- package/src/components/auto-complete/auto-complete.meta.md +102 -0
- package/src/components/auto-complete/auto-complete.stories.tsx +93 -0
- package/src/components/auto-complete/auto-complete.tsx +205 -0
- package/src/components/avatar/avatar.meta.md +94 -0
- package/src/components/avatar/avatar.stories.tsx +80 -0
- package/src/components/avatar/avatar.tsx +126 -0
- package/src/components/badge/badge.meta.md +119 -0
- package/src/components/badge/badge.stories.tsx +153 -0
- package/src/components/badge/badge.tsx +210 -0
- package/src/components/breadcrumb/breadcrumb.meta.md +107 -0
- package/src/components/breadcrumb/breadcrumb.stories.tsx +84 -0
- package/src/components/breadcrumb/breadcrumb.tsx +122 -0
- package/src/components/button/button.meta.md +98 -0
- package/src/components/button/button.stories.tsx +235 -0
- package/src/components/button/button.tsx +160 -0
- package/src/components/button-group/button-group.meta.md +92 -0
- package/src/components/button-group/button-group.stories.tsx +90 -0
- package/src/components/button-group/button-group.tsx +75 -0
- package/src/components/calendar/calendar.meta.md +118 -0
- package/src/components/calendar/calendar.stories.tsx +68 -0
- package/src/components/calendar/calendar.tsx +107 -0
- package/src/components/card/card.meta.md +117 -0
- package/src/components/card/card.stories.tsx +112 -0
- package/src/components/card/card.tsx +222 -0
- package/src/components/carousel/carousel.meta.md +117 -0
- package/src/components/carousel/carousel.stories.tsx +84 -0
- package/src/components/carousel/carousel.tsx +224 -0
- package/src/components/cascader/cascader.meta.md +110 -0
- package/src/components/cascader/cascader.stories.tsx +108 -0
- package/src/components/cascader/cascader.tsx +198 -0
- package/src/components/checkbox/checkbox.meta.md +99 -0
- package/src/components/checkbox/checkbox.stories.tsx +130 -0
- package/src/components/checkbox/checkbox.tsx +125 -0
- package/src/components/collapsible/collapsible.meta.md +80 -0
- package/src/components/collapsible/collapsible.stories.tsx +35 -0
- package/src/components/collapsible/collapsible.tsx +18 -0
- package/src/components/color-picker/color-picker.meta.md +84 -0
- package/src/components/color-picker/color-picker.stories.tsx +80 -0
- package/src/components/color-picker/color-picker.tsx +160 -0
- package/src/components/combobox/combobox.meta.md +93 -0
- package/src/components/combobox/combobox.stories.tsx +55 -0
- package/src/components/combobox/combobox.tsx +130 -0
- package/src/components/command/command.meta.md +104 -0
- package/src/components/command/command.stories.tsx +59 -0
- package/src/components/command/command.tsx +147 -0
- package/src/components/context-menu/context-menu.meta.md +90 -0
- package/src/components/context-menu/context-menu.stories.tsx +46 -0
- package/src/components/context-menu/context-menu.tsx +191 -0
- package/src/components/data-table/data-table.meta.md +149 -0
- package/src/components/data-table/data-table.stories.tsx +125 -0
- package/src/components/data-table/data-table.tsx +185 -0
- package/src/components/date-picker/date-picker.meta.md +106 -0
- package/src/components/date-picker/date-picker.stories.tsx +58 -0
- package/src/components/date-picker/date-picker.tsx +156 -0
- package/src/components/descriptions/descriptions.meta.md +78 -0
- package/src/components/descriptions/descriptions.stories.tsx +60 -0
- package/src/components/descriptions/descriptions.tsx +129 -0
- package/src/components/dialog/dialog.meta.md +105 -0
- package/src/components/dialog/dialog.stories.tsx +93 -0
- package/src/components/dialog/dialog.tsx +128 -0
- package/src/components/drawer/drawer.meta.md +96 -0
- package/src/components/drawer/drawer.stories.tsx +54 -0
- package/src/components/drawer/drawer.tsx +114 -0
- package/src/components/dropdown-menu/dropdown-menu.meta.md +103 -0
- package/src/components/dropdown-menu/dropdown-menu.stories.tsx +112 -0
- package/src/components/dropdown-menu/dropdown-menu.tsx +195 -0
- package/src/components/empty/empty.meta.md +81 -0
- package/src/components/empty/empty.stories.tsx +46 -0
- package/src/components/empty/empty.tsx +47 -0
- package/src/components/field/field.meta.md +116 -0
- package/src/components/field/field.stories.tsx +117 -0
- package/src/components/field/field.tsx +164 -0
- package/src/components/flex/flex.meta.md +94 -0
- package/src/components/flex/flex.stories.tsx +112 -0
- package/src/components/flex/flex.tsx +122 -0
- package/src/components/float-button/float-button.meta.md +87 -0
- package/src/components/float-button/float-button.stories.tsx +78 -0
- package/src/components/float-button/float-button.tsx +143 -0
- package/src/components/form/form.meta.md +131 -0
- package/src/components/form/form.stories.tsx +122 -0
- package/src/components/form/form.tsx +194 -0
- package/src/components/grid/grid.meta.md +87 -0
- package/src/components/grid/grid.stories.tsx +99 -0
- package/src/components/grid/grid.tsx +130 -0
- package/src/components/hover-card/hover-card.meta.md +92 -0
- package/src/components/hover-card/hover-card.stories.tsx +68 -0
- package/src/components/hover-card/hover-card.tsx +29 -0
- package/src/components/image/image.meta.md +94 -0
- package/src/components/image/image.stories.tsx +55 -0
- package/src/components/image/image.tsx +138 -0
- package/src/components/input/input.meta.md +109 -0
- package/src/components/input/input.stories.tsx +117 -0
- package/src/components/input/input.tsx +213 -0
- package/src/components/input-group/input-group.meta.md +92 -0
- package/src/components/input-group/input-group.stories.tsx +88 -0
- package/src/components/input-group/input-group.tsx +107 -0
- package/src/components/input-number/input-number.meta.md +91 -0
- package/src/components/input-number/input-number.stories.tsx +87 -0
- package/src/components/input-number/input-number.tsx +210 -0
- package/src/components/input-otp/input-otp.meta.md +105 -0
- package/src/components/input-otp/input-otp.stories.tsx +65 -0
- package/src/components/input-otp/input-otp.tsx +97 -0
- package/src/components/item/item.meta.md +116 -0
- package/src/components/item/item.stories.tsx +113 -0
- package/src/components/item/item.tsx +171 -0
- package/src/components/kbd/kbd.meta.md +85 -0
- package/src/components/kbd/kbd.stories.tsx +70 -0
- package/src/components/kbd/kbd.tsx +81 -0
- package/src/components/label/label.meta.md +91 -0
- package/src/components/label/label.stories.tsx +87 -0
- package/src/components/label/label.tsx +66 -0
- package/src/components/masonry/masonry.meta.md +85 -0
- package/src/components/masonry/masonry.stories.tsx +66 -0
- package/src/components/masonry/masonry.tsx +59 -0
- package/src/components/mentions/mentions.meta.md +89 -0
- package/src/components/mentions/mentions.stories.tsx +75 -0
- package/src/components/mentions/mentions.tsx +237 -0
- package/src/components/menubar/menubar.meta.md +100 -0
- package/src/components/menubar/menubar.stories.tsx +81 -0
- package/src/components/menubar/menubar.tsx +232 -0
- package/src/components/native-select/native-select.meta.md +88 -0
- package/src/components/native-select/native-select.stories.tsx +80 -0
- package/src/components/native-select/native-select.tsx +54 -0
- package/src/components/navigation-menu/navigation-menu.meta.md +108 -0
- package/src/components/navigation-menu/navigation-menu.stories.tsx +112 -0
- package/src/components/navigation-menu/navigation-menu.tsx +125 -0
- package/src/components/notification/notification.meta.md +91 -0
- package/src/components/notification/notification.stories.tsx +96 -0
- package/src/components/notification/notification.tsx +84 -0
- package/src/components/pagination/pagination.meta.md +127 -0
- package/src/components/pagination/pagination.stories.tsx +62 -0
- package/src/components/pagination/pagination.tsx +285 -0
- package/src/components/popconfirm/popconfirm.meta.md +109 -0
- package/src/components/popconfirm/popconfirm.stories.tsx +76 -0
- package/src/components/popconfirm/popconfirm.tsx +134 -0
- package/src/components/popover/popover.meta.md +97 -0
- package/src/components/popover/popover.stories.tsx +82 -0
- package/src/components/popover/popover.tsx +55 -0
- package/src/components/progress/progress.meta.md +86 -0
- package/src/components/progress/progress.stories.tsx +75 -0
- package/src/components/progress/progress.tsx +195 -0
- package/src/components/radio-group/radio-group.meta.md +103 -0
- package/src/components/radio-group/radio-group.stories.tsx +77 -0
- package/src/components/radio-group/radio-group.tsx +78 -0
- package/src/components/rate/rate.meta.md +87 -0
- package/src/components/rate/rate.stories.tsx +81 -0
- package/src/components/rate/rate.tsx +153 -0
- package/src/components/resizable/resizable.meta.md +92 -0
- package/src/components/resizable/resizable.stories.tsx +104 -0
- package/src/components/resizable/resizable.tsx +56 -0
- package/src/components/result/result.meta.md +90 -0
- package/src/components/result/result.stories.tsx +71 -0
- package/src/components/result/result.tsx +91 -0
- package/src/components/scroll-area/scroll-area.meta.md +84 -0
- package/src/components/scroll-area/scroll-area.stories.tsx +41 -0
- package/src/components/scroll-area/scroll-area.tsx +51 -0
- package/src/components/segmented/segmented.meta.md +103 -0
- package/src/components/segmented/segmented.stories.tsx +101 -0
- package/src/components/segmented/segmented.tsx +138 -0
- package/src/components/select/select.meta.md +110 -0
- package/src/components/select/select.stories.tsx +100 -0
- package/src/components/select/select.tsx +188 -0
- package/src/components/separator/separator.meta.md +74 -0
- package/src/components/separator/separator.stories.tsx +71 -0
- package/src/components/separator/separator.tsx +104 -0
- package/src/components/sheet/sheet.meta.md +97 -0
- package/src/components/sheet/sheet.stories.tsx +82 -0
- package/src/components/sheet/sheet.tsx +139 -0
- package/src/components/sidebar/sidebar.meta.md +131 -0
- package/src/components/sidebar/sidebar.stories.tsx +82 -0
- package/src/components/sidebar/sidebar.tsx +351 -0
- package/src/components/skeleton/skeleton.meta.md +95 -0
- package/src/components/skeleton/skeleton.stories.tsx +79 -0
- package/src/components/skeleton/skeleton.tsx +144 -0
- package/src/components/slider/slider.meta.md +94 -0
- package/src/components/slider/slider.stories.tsx +69 -0
- package/src/components/slider/slider.tsx +86 -0
- package/src/components/sonner/sonner.meta.md +96 -0
- package/src/components/sonner/sonner.stories.tsx +91 -0
- package/src/components/sonner/sonner.tsx +40 -0
- package/src/components/space/space.meta.md +94 -0
- package/src/components/space/space.stories.tsx +94 -0
- package/src/components/space/space.tsx +106 -0
- package/src/components/spinner/spinner.meta.md +76 -0
- package/src/components/spinner/spinner.stories.tsx +71 -0
- package/src/components/spinner/spinner.tsx +64 -0
- package/src/components/statistic/statistic.meta.md +99 -0
- package/src/components/statistic/statistic.stories.tsx +71 -0
- package/src/components/statistic/statistic.tsx +197 -0
- package/src/components/steps/steps.meta.md +102 -0
- package/src/components/steps/steps.stories.tsx +75 -0
- package/src/components/steps/steps.tsx +170 -0
- package/src/components/switch/switch.meta.md +92 -0
- package/src/components/switch/switch.stories.tsx +75 -0
- package/src/components/switch/switch.tsx +101 -0
- package/src/components/table/table.meta.md +95 -0
- package/src/components/table/table.stories.tsx +75 -0
- package/src/components/table/table.tsx +122 -0
- package/src/components/tabs/tabs.meta.md +98 -0
- package/src/components/tabs/tabs.stories.tsx +70 -0
- package/src/components/tabs/tabs.tsx +119 -0
- package/src/components/tag/tag.meta.md +94 -0
- package/src/components/tag/tag.stories.tsx +77 -0
- package/src/components/tag/tag.tsx +185 -0
- package/src/components/textarea/textarea.meta.md +83 -0
- package/src/components/textarea/textarea.stories.tsx +63 -0
- package/src/components/textarea/textarea.tsx +113 -0
- package/src/components/time-picker/time-picker.meta.md +83 -0
- package/src/components/time-picker/time-picker.stories.tsx +59 -0
- package/src/components/time-picker/time-picker.tsx +94 -0
- package/src/components/timeline/timeline.meta.md +102 -0
- package/src/components/timeline/timeline.stories.tsx +104 -0
- package/src/components/timeline/timeline.tsx +147 -0
- package/src/components/toggle/toggle.meta.md +88 -0
- package/src/components/toggle/toggle.stories.tsx +66 -0
- package/src/components/toggle/toggle.tsx +53 -0
- package/src/components/toggle-group/toggle-group.meta.md +90 -0
- package/src/components/toggle-group/toggle-group.stories.tsx +83 -0
- package/src/components/toggle-group/toggle-group.tsx +78 -0
- package/src/components/tooltip/tooltip.meta.md +99 -0
- package/src/components/tooltip/tooltip.stories.tsx +71 -0
- package/src/components/tooltip/tooltip.tsx +93 -0
- package/src/components/tour/tour.meta.md +116 -0
- package/src/components/tour/tour.stories.tsx +66 -0
- package/src/components/tour/tour.tsx +242 -0
- package/src/components/transfer/transfer.meta.md +90 -0
- package/src/components/transfer/transfer.stories.tsx +68 -0
- package/src/components/transfer/transfer.tsx +251 -0
- package/src/components/tree/tree.meta.md +111 -0
- package/src/components/tree/tree.stories.tsx +109 -0
- package/src/components/tree/tree.tsx +367 -0
- package/src/components/tree-select/tree-select.meta.md +100 -0
- package/src/components/tree-select/tree-select.stories.tsx +80 -0
- package/src/components/tree-select/tree-select.tsx +171 -0
- package/src/components/typography/typography.meta.md +102 -0
- package/src/components/typography/typography.stories.tsx +115 -0
- package/src/components/typography/typography.tsx +245 -0
- package/src/components/upload/upload.meta.md +111 -0
- package/src/components/upload/upload.stories.tsx +75 -0
- package/src/components/upload/upload.tsx +265 -0
- package/src/components/watermark/watermark.meta.md +95 -0
- package/src/components/watermark/watermark.stories.tsx +78 -0
- package/src/components/watermark/watermark.tsx +165 -0
- package/src/utils/cn.ts +6 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: popconfirm
|
|
3
|
+
name: Popconfirm
|
|
4
|
+
type: component
|
|
5
|
+
category: feedback
|
|
6
|
+
since: 0.1.0
|
|
7
|
+
package: "@teamix-evo/ui"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Popconfirm
|
|
11
|
+
|
|
12
|
+
轻量级确认弹层 — antd 独有补足。**等价 antd `Popconfirm`**。用于"小风险"操作的二次确认(删除一行、忽略某条通知),视觉比 `AlertDialog` 更轻、不阻塞页面;`onConfirm` 支持返回 Promise(等待时按钮自动 loading)。
|
|
13
|
+
|
|
14
|
+
## When to use
|
|
15
|
+
|
|
16
|
+
- 删除某一行 / 移除单个标签 / 取消订阅(影响小,可撤销)
|
|
17
|
+
- 列表行末"忽略"、"已读"等次级操作的确认
|
|
18
|
+
- 业务流程中"不希望误点"的轻量动作
|
|
19
|
+
|
|
20
|
+
## When NOT to use
|
|
21
|
+
|
|
22
|
+
- **高风险 / 不可逆操作**(注销账号、删除整库)→ `AlertDialog`(全屏阻塞)
|
|
23
|
+
- 无后果的纯展示 → `Tooltip` / `Popover`
|
|
24
|
+
- 长决策路径(需要填写理由)→ `Dialog` / `Drawer`
|
|
25
|
+
|
|
26
|
+
<!-- auto:props:begin -->
|
|
27
|
+
| 名称 | 类型 | 默认值 | 必填 | 说明 |
|
|
28
|
+
| --- | --- | --- | --- | --- |
|
|
29
|
+
| `children` | `React.ReactElement` | – | ✓ | 触发节点(通常是 Button / a)。 |
|
|
30
|
+
| `title` | `React.ReactNode` | – | ✓ | 主标题(antd `title` 并集)。 |
|
|
31
|
+
| `description` | `React.ReactNode` | – | – | 副描述(antd `description` 并集) — 解释操作后果。 |
|
|
32
|
+
| `icon` | `React.ReactNode` | – | – | 触发图标(antd `icon` 并集) — 默认警示图标。 |
|
|
33
|
+
| `okText` | `string` | `"确定"` | – | 确认按钮文本(antd `okText` 并集)。 |
|
|
34
|
+
| `cancelText` | `string` | `"取消"` | – | 取消按钮文本(antd `cancelText` 并集)。 |
|
|
35
|
+
| `okType` | `'default' \| 'destructive'` | `"default"` | – | 确认按钮 variant(antd `okType` 并集) — 危险操作请用 `destructive`。 |
|
|
36
|
+
| `onConfirm` | `() => void \| Promise<void>` | – | – | 确认回调。 |
|
|
37
|
+
| `onCancel` | `() => void` | – | – | 取消回调。 |
|
|
38
|
+
| `open` | `boolean` | – | – | 受控 open(antd `open` 并集) — 不传时本组件自管 open 状态。 |
|
|
39
|
+
| `onOpenChange` | `(next: boolean) => void` | – | – | open 变化回调。 |
|
|
40
|
+
| `disabled` | `boolean` | – | – | 禁用(子节点点击不弹出)。 |
|
|
41
|
+
<!-- auto:props:end -->
|
|
42
|
+
|
|
43
|
+
<!-- auto:deps:begin -->
|
|
44
|
+
### 同库依赖
|
|
45
|
+
|
|
46
|
+
> `teamix-evo ui add popconfirm` 时,以下 entry 会被自动连带安装(无需手动 add)。
|
|
47
|
+
|
|
48
|
+
| Entry | 类型 | 描述 |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
|
|
51
|
+
| `button` | component | 通用按钮 — shadcn 实现 + antd 功能扩展(loading / icon / shape / block / dashed variant) |
|
|
52
|
+
| `popover` | component | 可交互浮层 — Radix Popover + antd arrow 并集 |
|
|
53
|
+
|
|
54
|
+
### npm 依赖
|
|
55
|
+
|
|
56
|
+
> 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pnpm add lucide-react@^0.460.0
|
|
60
|
+
```
|
|
61
|
+
<!-- auto:deps:end -->
|
|
62
|
+
|
|
63
|
+
## AI 生成纪律
|
|
64
|
+
|
|
65
|
+
- **`title` 短句直白**(动词开头)— "删除此评论?"/"取消订阅?";**不要**用模糊措辞
|
|
66
|
+
- **`description` 写后果**:"删除后无法恢复"/"取消后将停止收到通知";**不要**写废话
|
|
67
|
+
- **危险动作**:`okType="destructive"` 必须配合 destructive variant 视觉,与 `AlertDialog` 一致的语义
|
|
68
|
+
- **`onConfirm` 返回 Promise**:组件会自动给确认按钮加 loading,**不要**自己在 onConfirm 外再做 spinner
|
|
69
|
+
- **`disabled`** 直接返回 children,不挂监听 — 用于"按钮已经做了别的事"的场景
|
|
70
|
+
- **不要嵌套 Popconfirm**:两层确认极少合理,改用 AlertDialog
|
|
71
|
+
|
|
72
|
+
## Examples
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { Popconfirm } from '@/components/ui/popconfirm';
|
|
76
|
+
import { Button } from '@/components/ui/button';
|
|
77
|
+
|
|
78
|
+
// 危险删除
|
|
79
|
+
<Popconfirm
|
|
80
|
+
title="删除此评论?"
|
|
81
|
+
description="删除后无法恢复"
|
|
82
|
+
okType="destructive"
|
|
83
|
+
okText="删除"
|
|
84
|
+
onConfirm={async () => {
|
|
85
|
+
await api.deleteComment(id);
|
|
86
|
+
toast.success('已删除');
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
<Button variant="ghost" size="sm">删除</Button>
|
|
90
|
+
</Popconfirm>
|
|
91
|
+
|
|
92
|
+
// 普通确认
|
|
93
|
+
<Popconfirm
|
|
94
|
+
title="确认取消订阅?"
|
|
95
|
+
description="你将停止收到每日摘要邮件"
|
|
96
|
+
onConfirm={() => unsubscribe()}
|
|
97
|
+
>
|
|
98
|
+
<Button variant="outline">取消订阅</Button>
|
|
99
|
+
</Popconfirm>
|
|
100
|
+
|
|
101
|
+
// 自定义图标
|
|
102
|
+
<Popconfirm
|
|
103
|
+
title="重置筛选条件?"
|
|
104
|
+
icon={<RefreshCcw className="size-4 text-primary" />}
|
|
105
|
+
onConfirm={resetFilters}
|
|
106
|
+
>
|
|
107
|
+
<Button variant="ghost">重置</Button>
|
|
108
|
+
</Popconfirm>
|
|
109
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { RefreshCcw } from 'lucide-react';
|
|
3
|
+
import { Popconfirm } from './popconfirm';
|
|
4
|
+
import { Button } from '@/components/button/button';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Popconfirm> = {
|
|
7
|
+
title: '反馈与浮层 · Feedback/Popconfirm',
|
|
8
|
+
component: Popconfirm,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'轻量级确认弹层 — 小风险操作的二次确认(删除一行 / 忽略一条通知)。视觉比 AlertDialog 更轻、不阻塞页面;onConfirm 支持 Promise(等待时按钮自动 loading)。等价 antd `Popconfirm`。视觉走 OpenTrek tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
type Story = StoryObj<typeof Popconfirm>;
|
|
22
|
+
|
|
23
|
+
export const Playground: Story = {
|
|
24
|
+
parameters: { controls: { disable: true } },
|
|
25
|
+
render: () => (
|
|
26
|
+
<Popconfirm
|
|
27
|
+
title="确认取消订阅?"
|
|
28
|
+
description="你将停止收到每日摘要邮件"
|
|
29
|
+
onConfirm={() => new Promise<void>((r) => setTimeout(r, 400))}
|
|
30
|
+
>
|
|
31
|
+
<Button variant="outline">取消订阅</Button>
|
|
32
|
+
</Popconfirm>
|
|
33
|
+
),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const Destructive: Story = {
|
|
37
|
+
parameters: { controls: { disable: true } },
|
|
38
|
+
render: () => (
|
|
39
|
+
<Popconfirm
|
|
40
|
+
title="删除此评论?"
|
|
41
|
+
description="删除后无法恢复"
|
|
42
|
+
okType="destructive"
|
|
43
|
+
okText="删除"
|
|
44
|
+
onConfirm={() => new Promise<void>((r) => setTimeout(r, 600))}
|
|
45
|
+
>
|
|
46
|
+
<Button variant="ghost" size="sm">
|
|
47
|
+
删除
|
|
48
|
+
</Button>
|
|
49
|
+
</Popconfirm>
|
|
50
|
+
),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const CustomIcon: Story = {
|
|
54
|
+
parameters: { controls: { disable: true } },
|
|
55
|
+
render: () => (
|
|
56
|
+
<Popconfirm
|
|
57
|
+
title="重置所有筛选条件?"
|
|
58
|
+
icon={<RefreshCcw className="size-4 text-primary" />}
|
|
59
|
+
onConfirm={() => {
|
|
60
|
+
// eslint-disable-next-line no-alert
|
|
61
|
+
alert('已重置');
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<Button variant="ghost">重置筛选</Button>
|
|
65
|
+
</Popconfirm>
|
|
66
|
+
),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const Disabled: Story = {
|
|
70
|
+
parameters: { controls: { disable: true } },
|
|
71
|
+
render: () => (
|
|
72
|
+
<Popconfirm disabled title="不会弹出">
|
|
73
|
+
<Button variant="outline">禁用态(直接点击不弹出)</Button>
|
|
74
|
+
</Popconfirm>
|
|
75
|
+
),
|
|
76
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { AlertCircle } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/utils/cn';
|
|
5
|
+
import { Button } from '@/components/button/button';
|
|
6
|
+
import {
|
|
7
|
+
Popover,
|
|
8
|
+
PopoverContent,
|
|
9
|
+
PopoverTrigger,
|
|
10
|
+
} from '@/components/popover/popover';
|
|
11
|
+
|
|
12
|
+
export interface PopconfirmProps {
|
|
13
|
+
/** 触发节点(通常是 Button / a)。 */
|
|
14
|
+
children: React.ReactElement;
|
|
15
|
+
/** 主标题(antd `title` 并集)。 */
|
|
16
|
+
title: React.ReactNode;
|
|
17
|
+
/** 副描述(antd `description` 并集) — 解释操作后果。 */
|
|
18
|
+
description?: React.ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* 触发图标(antd `icon` 并集) — 默认警示图标。
|
|
21
|
+
*/
|
|
22
|
+
icon?: React.ReactNode;
|
|
23
|
+
/** 确认按钮文本(antd `okText` 并集)。 @default "确定" */
|
|
24
|
+
okText?: string;
|
|
25
|
+
/** 取消按钮文本(antd `cancelText` 并集)。 @default "取消" */
|
|
26
|
+
cancelText?: string;
|
|
27
|
+
/**
|
|
28
|
+
* 确认按钮 variant(antd `okType` 并集) — 危险操作请用 `destructive`。
|
|
29
|
+
* @default "default"
|
|
30
|
+
*/
|
|
31
|
+
okType?: 'default' | 'destructive';
|
|
32
|
+
/** 确认回调。 */
|
|
33
|
+
onConfirm?: () => void | Promise<void>;
|
|
34
|
+
/** 取消回调。 */
|
|
35
|
+
onCancel?: () => void;
|
|
36
|
+
/** 受控 open(antd `open` 并集) — 不传时本组件自管 open 状态。 */
|
|
37
|
+
open?: boolean;
|
|
38
|
+
/** open 变化回调。 */
|
|
39
|
+
onOpenChange?: (next: boolean) => void;
|
|
40
|
+
/** 禁用(子节点点击不弹出)。 */
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 轻量级确认弹层 — antd 独有补足。**等价 antd `Popconfirm`**。
|
|
46
|
+
* 用于"小风险"操作的二次确认(删除某一行、忽略某条通知),
|
|
47
|
+
* 视觉比 `AlertDialog` 更轻、不阻塞页面。
|
|
48
|
+
*
|
|
49
|
+
* **风险更高的操作请用 `AlertDialog`**(全屏阻塞模态)。
|
|
50
|
+
*/
|
|
51
|
+
const Popconfirm: React.FC<PopconfirmProps> = ({
|
|
52
|
+
children,
|
|
53
|
+
title,
|
|
54
|
+
description,
|
|
55
|
+
icon,
|
|
56
|
+
okText = '确定',
|
|
57
|
+
cancelText = '取消',
|
|
58
|
+
okType = 'default',
|
|
59
|
+
onConfirm,
|
|
60
|
+
onCancel,
|
|
61
|
+
open,
|
|
62
|
+
onOpenChange,
|
|
63
|
+
disabled = false,
|
|
64
|
+
}) => {
|
|
65
|
+
const [internalOpen, setInternalOpen] = React.useState(false);
|
|
66
|
+
const isControlled = open !== undefined;
|
|
67
|
+
const currentOpen = isControlled ? open! : internalOpen;
|
|
68
|
+
const [loading, setLoading] = React.useState(false);
|
|
69
|
+
|
|
70
|
+
const setOpen = (next: boolean) => {
|
|
71
|
+
if (!isControlled) setInternalOpen(next);
|
|
72
|
+
onOpenChange?.(next);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const handleConfirm = async () => {
|
|
76
|
+
try {
|
|
77
|
+
setLoading(true);
|
|
78
|
+
await onConfirm?.();
|
|
79
|
+
setOpen(false);
|
|
80
|
+
} finally {
|
|
81
|
+
setLoading(false);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const handleCancel = () => {
|
|
86
|
+
onCancel?.();
|
|
87
|
+
setOpen(false);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (disabled) return children;
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<Popover open={currentOpen} onOpenChange={setOpen}>
|
|
94
|
+
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
|
95
|
+
<PopoverContent className="w-72 p-3" align="start">
|
|
96
|
+
<div className="flex items-start gap-2">
|
|
97
|
+
<span className="mt-0.5 text-amber-500">
|
|
98
|
+
{icon ?? <AlertCircle className="size-4" />}
|
|
99
|
+
</span>
|
|
100
|
+
<div className="min-w-0 flex-1">
|
|
101
|
+
<div className="text-sm font-medium">{title}</div>
|
|
102
|
+
{description ? (
|
|
103
|
+
<div className={cn('mt-1 text-xs text-muted-foreground')}>
|
|
104
|
+
{description}
|
|
105
|
+
</div>
|
|
106
|
+
) : null}
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
<div className="mt-3 flex justify-end gap-2">
|
|
110
|
+
<Button
|
|
111
|
+
type="button"
|
|
112
|
+
variant="outline"
|
|
113
|
+
size="sm"
|
|
114
|
+
onClick={handleCancel}
|
|
115
|
+
>
|
|
116
|
+
{cancelText}
|
|
117
|
+
</Button>
|
|
118
|
+
<Button
|
|
119
|
+
type="button"
|
|
120
|
+
variant={okType === 'destructive' ? 'destructive' : 'default'}
|
|
121
|
+
size="sm"
|
|
122
|
+
loading={loading}
|
|
123
|
+
onClick={handleConfirm}
|
|
124
|
+
>
|
|
125
|
+
{okText}
|
|
126
|
+
</Button>
|
|
127
|
+
</div>
|
|
128
|
+
</PopoverContent>
|
|
129
|
+
</Popover>
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
Popconfirm.displayName = 'Popconfirm';
|
|
133
|
+
|
|
134
|
+
export { Popconfirm };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: popover
|
|
3
|
+
name: Popover
|
|
4
|
+
type: component
|
|
5
|
+
category: feedback
|
|
6
|
+
since: 0.1.0
|
|
7
|
+
package: "@teamix-evo/ui"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Popover
|
|
11
|
+
|
|
12
|
+
可交互浮层 — Radix Popover + antd `arrow` 并集。
|
|
13
|
+
**与 Tooltip 区别**:Popover 内可放任意交互元素(button / form / link),触发方式为 click(默认),不是 hover。
|
|
14
|
+
|
|
15
|
+
## When to use
|
|
16
|
+
|
|
17
|
+
- 行内编辑(点字段名跳出编辑面板)
|
|
18
|
+
- 高级筛选 / 设置面板
|
|
19
|
+
- 动作菜单(超过 3 项时考虑 DropdownMenu)
|
|
20
|
+
- 信息卡片(用户头像 + 简介)
|
|
21
|
+
|
|
22
|
+
## When NOT to use
|
|
23
|
+
|
|
24
|
+
- 仅文字提示 → `Tooltip`
|
|
25
|
+
- 必须用户响应(阻断式)→ `Dialog` / `AlertDialog`
|
|
26
|
+
- 选择类下拉 → `Select` / `Combobox`
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
> 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。下表是 `PopoverContent` 的 props;`Popover`(Root)透传 Radix 的 `open / defaultOpen / onOpenChange / modal`。
|
|
31
|
+
|
|
32
|
+
<!-- auto:props:begin -->
|
|
33
|
+
| 名称 | 类型 | 默认值 | 必填 | 说明 |
|
|
34
|
+
| --- | --- | --- | --- | --- |
|
|
35
|
+
| `arrow` | `boolean` | `false` | – | 是否显示三角形箭头(antd `arrow` 并集)。 |
|
|
36
|
+
<!-- auto:props:end -->
|
|
37
|
+
|
|
38
|
+
## 依赖
|
|
39
|
+
|
|
40
|
+
> 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
|
|
41
|
+
|
|
42
|
+
<!-- auto:deps:begin -->
|
|
43
|
+
### 同库依赖
|
|
44
|
+
|
|
45
|
+
> `teamix-evo ui add popover` 时,以下 entry 会被自动连带安装(无需手动 add)。
|
|
46
|
+
|
|
47
|
+
| Entry | 类型 | 描述 |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
|
|
50
|
+
|
|
51
|
+
### npm 依赖
|
|
52
|
+
|
|
53
|
+
> 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pnpm add @radix-ui/react-popover@^1.1.0
|
|
57
|
+
```
|
|
58
|
+
<!-- auto:deps:end -->
|
|
59
|
+
|
|
60
|
+
> 子组件:`Popover`(Root)/ `PopoverTrigger`(触发器,通常 asChild)/ `PopoverContent`(浮层内容)/ `PopoverClose`(关闭按钮)/ `PopoverAnchor`(独立锚点)。
|
|
61
|
+
|
|
62
|
+
## AI 生成纪律
|
|
63
|
+
|
|
64
|
+
- **Trigger 用 `asChild`**:把已有按钮 wrap 进去而非另套层 `<button>`
|
|
65
|
+
- **Content 必有焦点目标**:键盘可达性 — Popover 打开后第一个可聚焦元素自动获焦
|
|
66
|
+
- **不嵌套 Popover**:嵌套会导致焦点陷阱混乱;改用 `Sheet` 或 `Dialog`
|
|
67
|
+
- **`modal={true}` 仅用于阻断场景**:默认 modal=false,允许用户点外部关闭
|
|
68
|
+
|
|
69
|
+
## Examples
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import {
|
|
73
|
+
Popover, PopoverTrigger, PopoverContent,
|
|
74
|
+
} from '@/components/ui/popover';
|
|
75
|
+
import { Button } from '@/components/ui/button';
|
|
76
|
+
|
|
77
|
+
// 基础
|
|
78
|
+
<Popover>
|
|
79
|
+
<PopoverTrigger asChild>
|
|
80
|
+
<Button variant="outline">打开</Button>
|
|
81
|
+
</PopoverTrigger>
|
|
82
|
+
<PopoverContent>
|
|
83
|
+
<h4 className="font-medium">标题</h4>
|
|
84
|
+
<p className="text-sm text-muted-foreground">描述文字...</p>
|
|
85
|
+
</PopoverContent>
|
|
86
|
+
</Popover>
|
|
87
|
+
|
|
88
|
+
// 带箭头
|
|
89
|
+
<Popover>
|
|
90
|
+
<PopoverTrigger asChild>
|
|
91
|
+
<Button>更多</Button>
|
|
92
|
+
</PopoverTrigger>
|
|
93
|
+
<PopoverContent arrow>
|
|
94
|
+
<p>简短说明</p>
|
|
95
|
+
</PopoverContent>
|
|
96
|
+
</Popover>
|
|
97
|
+
```
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Popover, PopoverTrigger, PopoverContent } from './popover';
|
|
3
|
+
import { Button } from '@/components/button/button';
|
|
4
|
+
import { Input } from '@/components/input/input';
|
|
5
|
+
import { Label } from '@/components/label/label';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof PopoverContent> = {
|
|
8
|
+
title: '反馈与浮层 · Feedback/Popover',
|
|
9
|
+
component: PopoverContent,
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
parameters: {
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component:
|
|
15
|
+
'气泡卡片 — 由 trigger 触发,在 portal 中展示富内容(表单、菜单、说明等)。Radix Popover 实现 + antd Popover 的语义并集:相比 Tooltip 仅承载纯文本提示,Popover 可承载任意交互内容;通过 `side` / `align` 控制方位,`arrow` 控制是否带尖角。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
argTypes: {
|
|
20
|
+
side: {
|
|
21
|
+
control: 'inline-radio',
|
|
22
|
+
options: ['top', 'right', 'bottom', 'left'],
|
|
23
|
+
},
|
|
24
|
+
align: {
|
|
25
|
+
control: 'inline-radio',
|
|
26
|
+
options: ['start', 'center', 'end'],
|
|
27
|
+
},
|
|
28
|
+
arrow: { control: 'boolean' },
|
|
29
|
+
},
|
|
30
|
+
args: { side: 'bottom', align: 'center', arrow: false },
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default meta;
|
|
34
|
+
type Story = StoryObj<typeof PopoverContent>;
|
|
35
|
+
|
|
36
|
+
export const Playground: Story = {
|
|
37
|
+
render: (args) => (
|
|
38
|
+
<Popover>
|
|
39
|
+
<PopoverTrigger asChild>
|
|
40
|
+
<Button variant="outline">打开 Popover</Button>
|
|
41
|
+
</PopoverTrigger>
|
|
42
|
+
<PopoverContent {...args}>
|
|
43
|
+
<h4 className="mb-1 font-medium">尺寸调整</h4>
|
|
44
|
+
<p className="text-sm text-muted-foreground">
|
|
45
|
+
设置组件宽高,关闭后自动应用。
|
|
46
|
+
</p>
|
|
47
|
+
</PopoverContent>
|
|
48
|
+
</Popover>
|
|
49
|
+
),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const InteractiveForm: Story = {
|
|
53
|
+
parameters: { controls: { disable: true } },
|
|
54
|
+
render: () => (
|
|
55
|
+
<Popover>
|
|
56
|
+
<PopoverTrigger asChild>
|
|
57
|
+
<Button>边距设置</Button>
|
|
58
|
+
</PopoverTrigger>
|
|
59
|
+
<PopoverContent className="w-80">
|
|
60
|
+
<div className="grid gap-3">
|
|
61
|
+
<h4 className="font-medium">边距</h4>
|
|
62
|
+
<div className="grid grid-cols-3 items-center gap-3">
|
|
63
|
+
<Label htmlFor="m-top">上</Label>
|
|
64
|
+
<Input id="m-top" defaultValue="16" className="col-span-2 h-8" />
|
|
65
|
+
</div>
|
|
66
|
+
<div className="grid grid-cols-3 items-center gap-3">
|
|
67
|
+
<Label htmlFor="m-right">右</Label>
|
|
68
|
+
<Input id="m-right" defaultValue="16" className="col-span-2 h-8" />
|
|
69
|
+
</div>
|
|
70
|
+
<div className="grid grid-cols-3 items-center gap-3">
|
|
71
|
+
<Label htmlFor="m-bottom">下</Label>
|
|
72
|
+
<Input id="m-bottom" defaultValue="16" className="col-span-2 h-8" />
|
|
73
|
+
</div>
|
|
74
|
+
<div className="grid grid-cols-3 items-center gap-3">
|
|
75
|
+
<Label htmlFor="m-left">左</Label>
|
|
76
|
+
<Input id="m-left" defaultValue="16" className="col-span-2 h-8" />
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</PopoverContent>
|
|
80
|
+
</Popover>
|
|
81
|
+
),
|
|
82
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/utils/cn';
|
|
5
|
+
|
|
6
|
+
const Popover = PopoverPrimitive.Root;
|
|
7
|
+
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
8
|
+
const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
9
|
+
const PopoverClose = PopoverPrimitive.Close;
|
|
10
|
+
|
|
11
|
+
export interface PopoverContentProps
|
|
12
|
+
extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> {
|
|
13
|
+
/**
|
|
14
|
+
* 是否显示三角形箭头(antd `arrow` 并集)。
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
arrow?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const PopoverContent = React.forwardRef<
|
|
21
|
+
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
22
|
+
PopoverContentProps
|
|
23
|
+
>(
|
|
24
|
+
(
|
|
25
|
+
{ className, align = 'center', sideOffset = 4, arrow = false, children, ...props },
|
|
26
|
+
ref,
|
|
27
|
+
) => (
|
|
28
|
+
<PopoverPrimitive.Portal>
|
|
29
|
+
<PopoverPrimitive.Content
|
|
30
|
+
ref={ref}
|
|
31
|
+
align={align}
|
|
32
|
+
sideOffset={sideOffset}
|
|
33
|
+
className={cn(
|
|
34
|
+
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
35
|
+
className,
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
{arrow ? (
|
|
41
|
+
<PopoverPrimitive.Arrow className="fill-popover" width={10} height={5} />
|
|
42
|
+
) : null}
|
|
43
|
+
</PopoverPrimitive.Content>
|
|
44
|
+
</PopoverPrimitive.Portal>
|
|
45
|
+
),
|
|
46
|
+
);
|
|
47
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
Popover,
|
|
51
|
+
PopoverTrigger,
|
|
52
|
+
PopoverContent,
|
|
53
|
+
PopoverAnchor,
|
|
54
|
+
PopoverClose,
|
|
55
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: progress
|
|
3
|
+
name: Progress
|
|
4
|
+
type: component
|
|
5
|
+
category: foundation
|
|
6
|
+
since: 0.1.0
|
|
7
|
+
package: "@teamix-evo/ui"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Progress
|
|
11
|
+
|
|
12
|
+
进度条 — Radix Progress + antd 的 `status / showInfo / Progress.Circle` 并集。
|
|
13
|
+
|
|
14
|
+
`Progress`(线性)和 `ProgressCircle`(环形)是两个独立组件,共享 `value / status / showInfo` 三 prop 心智。
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
- **线性 Progress**:文件上传、表单提交、长任务进度;占据一行宽度
|
|
19
|
+
- **环形 ProgressCircle**:数据完成度、空间占用、健康度等需要紧凑展示的场景;不撑宽
|
|
20
|
+
|
|
21
|
+
## When NOT to use
|
|
22
|
+
|
|
23
|
+
- 进度不可知 → 用 `Spinner`(loading 视觉)或 `Skeleton`
|
|
24
|
+
- 仅做"是否完成"二元状态 → 用 `Badge` 或 `Switch`
|
|
25
|
+
|
|
26
|
+
## Props
|
|
27
|
+
|
|
28
|
+
> 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。
|
|
29
|
+
|
|
30
|
+
<!-- auto:props:begin -->
|
|
31
|
+
| 名称 | 类型 | 默认值 | 必填 | 说明 |
|
|
32
|
+
| --- | --- | --- | --- | --- |
|
|
33
|
+
| `value` | `number` | `0` | – | 当前百分比(0~100)。 |
|
|
34
|
+
| `status` | `ProgressStatus` | `"normal"` | – | 状态色,自动优先级:`exception > warning > success > normal`。 |
|
|
35
|
+
| `showInfo` | `boolean` | `false` | – | 是否在右侧显示百分比文字(antd showInfo 并集)。 |
|
|
36
|
+
| `size` | `'sm' \| 'default' \| 'lg'` | `"default"` | – | 进度条尺寸。 |
|
|
37
|
+
<!-- auto:props:end -->
|
|
38
|
+
|
|
39
|
+
## 依赖
|
|
40
|
+
|
|
41
|
+
> 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
|
|
42
|
+
|
|
43
|
+
<!-- auto:deps:begin -->
|
|
44
|
+
### 同库依赖
|
|
45
|
+
|
|
46
|
+
> `teamix-evo ui add progress` 时,以下 entry 会被自动连带安装(无需手动 add)。
|
|
47
|
+
|
|
48
|
+
| Entry | 类型 | 描述 |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
|
|
51
|
+
|
|
52
|
+
### npm 依赖
|
|
53
|
+
|
|
54
|
+
> 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pnpm add @radix-ui/react-progress@^1.1.0
|
|
58
|
+
```
|
|
59
|
+
<!-- auto:deps:end -->
|
|
60
|
+
|
|
61
|
+
> `ProgressCircle` 的 props 详见 [`progress.tsx`](./progress.tsx) 的 `ProgressCircleProps` interface。
|
|
62
|
+
|
|
63
|
+
## AI 生成纪律
|
|
64
|
+
|
|
65
|
+
- **`status` 反映业务语义**:正常进行 `normal`、完成 `success`、警告 `warning`、失败/异常 `exception`,**不要**用颜色 prop 绕过 status 直接调色
|
|
66
|
+
- **`value` 范围 0~100**:超出会被 clamp,但写代码时不要传超出值
|
|
67
|
+
- **showInfo 默认行为不同**:线性默认 `false`(节省横向空间),环形默认 `true`(圆心天然有空位)
|
|
68
|
+
- **不要替代 Spinner**:已知"正在加载但不知比例"应该用 `Spinner` 或 `Skeleton`,**不要**用 `<Progress value={undefined} />` 做不确定态
|
|
69
|
+
- **超过一屏的长任务**:Progress 配 ETA 文字 + 取消按钮,提供退路
|
|
70
|
+
|
|
71
|
+
## Examples
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { Progress, ProgressCircle } from '@/components/ui/progress';
|
|
75
|
+
|
|
76
|
+
// 线性
|
|
77
|
+
<Progress value={42} showInfo />
|
|
78
|
+
<Progress value={100} status="success" showInfo />
|
|
79
|
+
<Progress value={66} status="warning" showInfo />
|
|
80
|
+
<Progress value={20} status="exception" showInfo />
|
|
81
|
+
|
|
82
|
+
// 环形
|
|
83
|
+
<ProgressCircle value={75} />
|
|
84
|
+
<ProgressCircle value={100} status="success" size={120} />
|
|
85
|
+
<ProgressCircle value={42} showInfo={false} size={48} />
|
|
86
|
+
```
|