@teamix-evo/ui 0.7.0 → 0.7.2

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.
Files changed (121) hide show
  1. package/manifest.json +16 -7
  2. package/package.json +4 -4
  3. package/src/_design-system/theme-tokens/stories.tsx +2 -2
  4. package/src/components/accordion/index.tsx +1 -1
  5. package/src/components/affix/meta.md +26 -0
  6. package/src/components/alert/index.tsx +2 -2
  7. package/src/components/alert-dialog/index.tsx +3 -3
  8. package/src/components/alert-dialog/meta.md +52 -0
  9. package/src/components/alert-dialog/stories.tsx +45 -48
  10. package/src/components/avatar/index.tsx +1 -1
  11. package/src/components/badge/index.tsx +2 -2
  12. package/src/components/badge/meta.md +48 -0
  13. package/src/components/button/index.tsx +2 -2
  14. package/src/components/button/meta.md +15 -0
  15. package/src/components/button/stories.tsx +1 -1
  16. package/src/components/calendar/index.tsx +2 -2
  17. package/src/components/card/index.tsx +1 -1
  18. package/src/components/carousel/index.tsx +2 -2
  19. package/src/components/carousel/meta.md +34 -2
  20. package/src/components/carousel/stories.tsx +2 -2
  21. package/src/components/cascader-select/index.tsx +2 -1
  22. package/src/components/cascader-select/meta.md +46 -0
  23. package/src/components/checkbox/meta.md +47 -0
  24. package/src/components/color-picker/index.tsx +3 -3
  25. package/src/components/color-picker/meta.md +80 -0
  26. package/src/components/combobox/index.tsx +2 -2
  27. package/src/components/combobox/meta.md +130 -0
  28. package/src/components/data-table/index.tsx +3 -3
  29. package/src/components/data-table/meta.md +419 -0
  30. package/src/components/data-table/stories.tsx +4 -4
  31. package/src/components/date-picker/meta.md +91 -0
  32. package/src/components/descriptions/index.tsx +1 -1
  33. package/src/components/descriptions/meta.md +245 -0
  34. package/src/components/dialog/index.tsx +4 -4
  35. package/src/components/dialog/meta.md +47 -1
  36. package/src/components/dialog/stories.tsx +38 -41
  37. package/src/components/dropdown-menu/index.tsx +5 -5
  38. package/src/components/empty/index.tsx +2 -2
  39. package/src/components/field/index.tsx +4 -4
  40. package/src/components/filter-bar/index.tsx +6 -6
  41. package/src/components/filter-bar/meta.md +323 -0
  42. package/src/components/float-button/index.tsx +2 -2
  43. package/src/components/form/index.tsx +1 -1
  44. package/src/components/form/meta.md +119 -0
  45. package/src/components/hover-card/index.tsx +1 -1
  46. package/src/components/hover-card/meta.md +21 -0
  47. package/src/components/input/meta.md +16 -0
  48. package/src/components/input-group/index.tsx +1 -1
  49. package/src/components/input-group/meta.md +118 -0
  50. package/src/components/input-group/stories.tsx +6 -6
  51. package/src/components/input-ip/index.tsx +2 -2
  52. package/src/components/input-ip/meta.md +30 -0
  53. package/src/components/input-ip/stories.tsx +2 -2
  54. package/src/components/input-number/index.tsx +3 -2
  55. package/src/components/input-number/meta.md +67 -0
  56. package/src/components/input-number/stories.tsx +2 -2
  57. package/src/components/item/index.tsx +4 -4
  58. package/src/components/label/meta.md +8 -0
  59. package/src/components/mentions/meta.md +15 -0
  60. package/src/components/menubar/index.tsx +4 -4
  61. package/src/components/navigation-menu/index.tsx +4 -4
  62. package/src/components/page-header/index.tsx +2 -2
  63. package/src/components/page-header/meta.md +145 -0
  64. package/src/components/page-shell/index.tsx +3 -3
  65. package/src/components/pagination/index.tsx +1 -1
  66. package/src/components/pagination/meta.md +203 -0
  67. package/src/components/popconfirm/meta.md +45 -0
  68. package/src/components/popover/index.tsx +2 -2
  69. package/src/components/popover/meta.md +47 -0
  70. package/src/components/progress/index.tsx +1 -1
  71. package/src/components/progress/meta.md +36 -0
  72. package/src/components/progress/stories.tsx +1 -1
  73. package/src/components/radio-group/meta.md +69 -0
  74. package/src/components/rate/index.tsx +1 -1
  75. package/src/components/rate/meta.md +50 -0
  76. package/src/components/resizable/index.tsx +1 -1
  77. package/src/components/select/index.tsx +2 -2
  78. package/src/components/select/meta.md +20 -0
  79. package/src/components/separator/index.tsx +1 -1
  80. package/src/components/sheet/index.tsx +13 -14
  81. package/src/components/sheet/meta.md +124 -0
  82. package/src/components/sheet/stories.tsx +110 -119
  83. package/src/components/sidebar/index.tsx +5 -5
  84. package/src/components/sidebar/meta.md +383 -0
  85. package/src/components/skeleton/meta.md +13 -0
  86. package/src/components/slider/index.tsx +2 -2
  87. package/src/components/sonner/meta.md +86 -0
  88. package/src/components/spinner/meta.md +46 -0
  89. package/src/components/spinner/stories.tsx +2 -2
  90. package/src/components/steps/meta.md +20 -0
  91. package/src/components/steps/stories.tsx +1 -1
  92. package/src/components/switch/index.tsx +2 -2
  93. package/src/components/switch/meta.md +33 -0
  94. package/src/components/table/index.tsx +4 -4
  95. package/src/components/table/meta.md +11 -0
  96. package/src/components/tabs/index.tsx +7 -7
  97. package/src/components/tabs/meta.md +52 -0
  98. package/src/components/tag/index.tsx +8 -8
  99. package/src/components/tag/meta.md +194 -0
  100. package/src/components/textarea/index.tsx +1 -1
  101. package/src/components/textarea/meta.md +27 -0
  102. package/src/components/textarea/stories.tsx +1 -1
  103. package/src/components/time-picker/index.tsx +3 -3
  104. package/src/components/time-picker/meta.md +76 -0
  105. package/src/components/timeline/index.tsx +1 -0
  106. package/src/components/toggle/index.tsx +1 -1
  107. package/src/components/toggle-group/index.tsx +1 -1
  108. package/src/components/tooltip/index.tsx +1 -1
  109. package/src/components/tooltip/meta.md +23 -0
  110. package/src/components/transfer/index.tsx +2 -2
  111. package/src/components/transfer/meta.md +97 -0
  112. package/src/components/tree/index.tsx +245 -15
  113. package/src/components/tree/meta.md +151 -0
  114. package/src/components/tree-select/index.tsx +16 -2
  115. package/src/components/tree-select/meta.md +150 -0
  116. package/src/components/typography/index.tsx +3 -3
  117. package/src/components/upload/index.tsx +3 -3
  118. package/src/components/upload/meta.md +82 -0
  119. package/src/components/tree/utils.ts +0 -269
  120. package/src/examples/built-in-assets/stories.tsx +0 -572
  121. package/src/examples/evaluators/stories.tsx +0 -502
@@ -12,3 +12,386 @@
12
12
  - 管理后台布局侧边导航
13
13
  - 需要可收缩的菜单导航
14
14
  - 配合 SidebarProvider 与页面布局使用
15
+
16
+ ## 示例
17
+
18
+ ### CollapsibleIcon
19
+
20
+ 折叠态 + 自动 Tooltip:默认收起,hover icon 弹出文字
21
+
22
+ ```tsx
23
+ <SidebarProvider open={!collapsed} onOpenChange={(o) => setCollapsed(!o)}>
24
+ <Sidebar {...args}>
25
+ <SidebarHeader>
26
+ <div className="flex items-center group-data-[collapsible=icon]:justify-center">
27
+ <h1 className="flex-1 px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
28
+ Teamix Evo
29
+ </h1>
30
+ <SidebarTrigger />
31
+ </div>
32
+ </SidebarHeader>
33
+ <SidebarContent>
34
+ <SidebarGroup>
35
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
36
+ <SidebarGroupContent>
37
+ <SidebarMenu>
38
+ {navItems.map((it) => (
39
+ <SidebarMenuItem key={it.title}>
40
+ <SidebarMenuButton asChild tooltip={it.title}>
41
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
42
+ <it.icon />
43
+ <span>{it.title}</span>
44
+ </a>
45
+ </SidebarMenuButton>
46
+ </SidebarMenuItem>
47
+ ))}
48
+ </SidebarMenu>
49
+ </SidebarGroupContent>
50
+ </SidebarGroup>
51
+ </SidebarContent>
52
+ </Sidebar>
53
+ <MainContent>
54
+ <p>
55
+ 当前折叠状态:<strong>{collapsed ? '已折叠' : '已展开'}</strong>
56
+ </p>
57
+ <p className="mt-2">
58
+ 折叠后 hover 任一 icon,会看到 Tooltip 弹出对应文字。
59
+ </p>
60
+ </MainContent>
61
+ </SidebarProvider>
62
+ ```
63
+
64
+ ### WithSubMenus
65
+
66
+ 二级菜单:配合 Collapsible 实现展开/收起,折叠态自动隐藏
67
+
68
+ ```tsx
69
+ <SidebarProvider>
70
+ <Sidebar {...args}>
71
+ <SidebarHeader>
72
+ <div className="flex items-center group-data-[collapsible=icon]:justify-center">
73
+ <h1 className="flex-1 px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
74
+ Teamix Evo
75
+ </h1>
76
+ <SidebarTrigger />
77
+ </div>
78
+ </SidebarHeader>
79
+ <SidebarContent>
80
+ <SidebarGroup>
81
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
82
+ <SidebarMenu>
83
+ <SidebarMenuItem>
84
+ <SidebarMenuButton asChild tooltip="首页">
85
+ <a href="#home" onClick={(e) => e.preventDefault()}>
86
+ <Home />
87
+ <span>首页</span>
88
+ </a>
89
+ </SidebarMenuButton>
90
+ </SidebarMenuItem>
91
+ {/* 知识库 + 二级 */}
92
+ <Collapsible defaultOpen asChild className="group/collapsible">
93
+ <SidebarMenuItem>
94
+ <CollapsibleTrigger asChild>
95
+ <SidebarMenuButton tooltip="知识库">
96
+ <BookOpen />
97
+ <span>知识库</span>
98
+ <ChevronRight className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
99
+ </SidebarMenuButton>
100
+ </CollapsibleTrigger>
101
+ <CollapsibleContent>
102
+ <SidebarMenuSub>
103
+ {kbSubItems.map((s) => (
104
+ <SidebarMenuSubItem key={s.title}>
105
+ <SidebarMenuSubButton
106
+ href={s.url}
107
+ isActive={s.url === '#kb-public'}
108
+ onClick={(e) => e.preventDefault()}
109
+ >
110
+ <span>{s.title}</span>
111
+ </SidebarMenuSubButton>
112
+ </SidebarMenuSubItem>
113
+ ))}
114
+ </SidebarMenuSub>
115
+ </CollapsibleContent>
116
+ </SidebarMenuItem>
117
+ </Collapsible>
118
+ <SidebarMenuItem>
119
+ <SidebarMenuButton asChild tooltip="设置">
120
+ <a href="#settings" onClick={(e) => e.preventDefault()}>
121
+ <Settings />
122
+ <span>设置</span>
123
+ </a>
124
+ </SidebarMenuButton>
125
+ </SidebarMenuItem>
126
+ </SidebarMenu>
127
+ </SidebarGroup>
128
+ </SidebarContent>
129
+ </Sidebar>
130
+ <MainContent>
131
+ 知识库展开后,折叠 Sidebar — 二级菜单会自动隐藏。
132
+ </MainContent>
133
+ </SidebarProvider>
134
+ ```
135
+
136
+ ### WithBadgeAndAction
137
+
138
+ 徽标 + hover 操作:MenuBadge 显示数字,MenuAction 仅 hover 浮现
139
+
140
+ ```tsx
141
+ <SidebarProvider>
142
+ <Sidebar {...args}>
143
+ <SidebarHeader>
144
+ <div className="flex items-center group-data-[collapsible=icon]:justify-center">
145
+ <h1 className="flex-1 px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
146
+ Teamix Evo
147
+ </h1>
148
+ <SidebarTrigger />
149
+ </div>
150
+ </SidebarHeader>
151
+ <SidebarContent>
152
+ <SidebarGroup>
153
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
154
+ <SidebarMenu>
155
+ {navItems.map((it) => (
156
+ <SidebarMenuItem key={it.title}>
157
+ <SidebarMenuButton asChild tooltip={it.title}>
158
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
159
+ <it.icon />
160
+ <span>{it.title}</span>
161
+ </a>
162
+ </SidebarMenuButton>
163
+ {it.title === '收件箱' && (
164
+ <SidebarMenuBadge>5</SidebarMenuBadge>
165
+ )}
166
+ <SidebarMenuAction
167
+ showOnHover
168
+ aria-label="更多"
169
+ onClick={(e) => e.preventDefault()}
170
+ >
171
+ <MoreHorizontal />
172
+ </SidebarMenuAction>
173
+ </SidebarMenuItem>
174
+ ))}
175
+ </SidebarMenu>
176
+ </SidebarGroup>
177
+ </SidebarContent>
178
+ </Sidebar>
179
+ <MainContent>
180
+ 鼠标移到菜单项 — 右侧浮现「⋯」操作按钮;收件箱有未读徽标。
181
+ </MainContent>
182
+ </SidebarProvider>
183
+ ```
184
+
185
+ ### VariantFloating
186
+
187
+ 浮起变体:Sidebar 脱离边缘,带圆角和阴影
188
+
189
+ ```tsx
190
+ <SidebarProvider>
191
+ <Sidebar {...args}>
192
+ <SidebarHeader>
193
+ <div className="flex items-center group-data-[collapsible=icon]:justify-center">
194
+ <h1 className="flex-1 px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
195
+ Teamix Evo
196
+ </h1>
197
+ <SidebarTrigger />
198
+ </div>
199
+ </SidebarHeader>
200
+ <SidebarContent>
201
+ <SidebarGroup>
202
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
203
+ <SidebarMenu>
204
+ {navItems.map((it) => (
205
+ <SidebarMenuItem key={it.title}>
206
+ <SidebarMenuButton asChild tooltip={it.title}>
207
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
208
+ <it.icon />
209
+ <span>{it.title}</span>
210
+ </a>
211
+ </SidebarMenuButton>
212
+ </SidebarMenuItem>
213
+ ))}
214
+ </SidebarMenu>
215
+ </SidebarGroup>
216
+ </SidebarContent>
217
+ </Sidebar>
218
+ <MainContent>
219
+ variant=&quot;floating&quot; — 浮起、圆角、阴影。
220
+ </MainContent>
221
+ </SidebarProvider>
222
+ ```
223
+
224
+ ### VariantInset
225
+
226
+ 内嵌变体:主内容区圆角内缩
227
+
228
+ ```tsx
229
+ <SidebarProvider>
230
+ <Sidebar {...args}>
231
+ <SidebarHeader>
232
+ <div className="flex items-center group-data-[collapsible=icon]:justify-center">
233
+ <h1 className="flex-1 px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
234
+ Teamix Evo
235
+ </h1>
236
+ <SidebarTrigger />
237
+ </div>
238
+ </SidebarHeader>
239
+ <SidebarContent>
240
+ <SidebarGroup>
241
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
242
+ <SidebarMenu>
243
+ {navItems.map((it) => (
244
+ <SidebarMenuItem key={it.title}>
245
+ <SidebarMenuButton asChild tooltip={it.title}>
246
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
247
+ <it.icon />
248
+ <span>{it.title}</span>
249
+ </a>
250
+ </SidebarMenuButton>
251
+ </SidebarMenuItem>
252
+ ))}
253
+ </SidebarMenu>
254
+ </SidebarGroup>
255
+ </SidebarContent>
256
+ </Sidebar>
257
+ <MainContent>
258
+ variant=&quot;inset&quot; — 主内容区域圆角内嵌。
259
+ </MainContent>
260
+ </SidebarProvider>
261
+ ```
262
+
263
+ ### WithRail
264
+
265
+ Rail 拖拽收合:Sidebar 右边缘 hover 出线条,点击切换
266
+
267
+ ```tsx
268
+ <SidebarProvider>
269
+ <Sidebar {...args}>
270
+ <SidebarHeader>
271
+ <div className="flex items-center group-data-[collapsible=icon]:justify-center">
272
+ <h1 className="flex-1 px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
273
+ Teamix Evo
274
+ </h1>
275
+ <SidebarTrigger />
276
+ </div>
277
+ </SidebarHeader>
278
+ <SidebarContent>
279
+ <SidebarGroup>
280
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
281
+ <SidebarMenu>
282
+ {navItems.map((it) => (
283
+ <SidebarMenuItem key={it.title}>
284
+ <SidebarMenuButton asChild tooltip={it.title}>
285
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
286
+ <it.icon />
287
+ <span>{it.title}</span>
288
+ </a>
289
+ </SidebarMenuButton>
290
+ </SidebarMenuItem>
291
+ ))}
292
+ </SidebarMenu>
293
+ </SidebarGroup>
294
+ </SidebarContent>
295
+ <SidebarRail />
296
+ </Sidebar>
297
+ <MainContent>
298
+ 鼠标移到 Sidebar 右边缘 — 出现窄拖拽柄,点击切换折叠。
299
+ </MainContent>
300
+ </SidebarProvider>
301
+ ```
302
+
303
+ ### WithInputAndGroupAction
304
+
305
+ 搜索输入 + 分组操作:SidebarInput + GroupAction
306
+
307
+ ```tsx
308
+ <SidebarProvider>
309
+ <Sidebar {...args}>
310
+ <SidebarHeader>
311
+ <div className="flex items-center group-data-[collapsible=icon]:justify-center">
312
+ <h1 className="flex-1 px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
313
+ Teamix Evo
314
+ </h1>
315
+ <SidebarTrigger />
316
+ </div>
317
+ <SidebarInput placeholder="搜索…" />
318
+ </SidebarHeader>
319
+ <SidebarContent>
320
+ <SidebarGroup>
321
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
322
+ <SidebarMenu>
323
+ {navItems.slice(0, 3).map((it) => (
324
+ <SidebarMenuItem key={it.title}>
325
+ <SidebarMenuButton asChild tooltip={it.title}>
326
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
327
+ <it.icon />
328
+ <span>{it.title}</span>
329
+ </a>
330
+ </SidebarMenuButton>
331
+ </SidebarMenuItem>
332
+ ))}
333
+ </SidebarMenu>
334
+ </SidebarGroup>
335
+
336
+ <SidebarSeparator />
337
+
338
+ <SidebarGroup>
339
+ <SidebarGroupLabel>收藏</SidebarGroupLabel>
340
+ <SidebarGroupAction
341
+ aria-label="管理收藏"
342
+ onClick={(e) => e.preventDefault()}
343
+ >
344
+ <MoreHorizontal />
345
+ </SidebarGroupAction>
346
+ <SidebarMenu>
347
+ {favoriteItems.map((f) => (
348
+ <SidebarMenuItem key={f.title}>
349
+ <SidebarMenuButton asChild tooltip={f.title} size="sm">
350
+ <a href={f.url} onClick={(e) => e.preventDefault()}>
351
+ <Star />
352
+ <span>{f.title}</span>
353
+ </a>
354
+ </SidebarMenuButton>
355
+ </SidebarMenuItem>
356
+ ))}
357
+ </SidebarMenu>
358
+ </SidebarGroup>
359
+ </SidebarContent>
360
+ </Sidebar>
361
+ <MainContent>
362
+ 顶部 SidebarInput 搜索 + 收藏分组头部「⋯」管理操作。
363
+ </MainContent>
364
+ </SidebarProvider>
365
+ ```
366
+
367
+ ### LoadingSkeleton
368
+
369
+ 加载骨架:异步数据 ready 前的占位
370
+
371
+ ```tsx
372
+ <SidebarProvider>
373
+ <Sidebar {...args}>
374
+ <SidebarHeader>
375
+ <div className="flex items-center group-data-[collapsible=icon]:justify-center">
376
+ <h1 className="flex-1 px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
377
+ Teamix Evo
378
+ </h1>
379
+ <SidebarTrigger />
380
+ </div>
381
+ </SidebarHeader>
382
+ <SidebarContent>
383
+ <SidebarGroup>
384
+ <SidebarGroupLabel>导航(加载中)</SidebarGroupLabel>
385
+ <SidebarMenu>
386
+ {Array.from({ length: 5 }).map((_, i) => (
387
+ <SidebarMenuItem key={i}>
388
+ <SidebarMenuSkeleton showIcon />
389
+ </SidebarMenuItem>
390
+ ))}
391
+ </SidebarMenu>
392
+ </SidebarGroup>
393
+ </SidebarContent>
394
+ </Sidebar>
395
+ <MainContent>真实业务中骨架会在数据 ready 后切换为 Menu。</MainContent>
396
+ </SidebarProvider>
397
+ ```
@@ -99,6 +99,19 @@ pulse / none 两种动画对照。
99
99
  </div>
100
100
  ```
101
101
 
102
+ ### Loading
103
+
104
+ loading + children 条件渲染:loading=false 时直接显示真实内容。
105
+
106
+ ```tsx
107
+ <div className="flex flex-col gap-3">
108
+ <Button onClick={() => setLoading((v) => !v)}>切换</Button>
109
+ <Skeleton loading={loading} className="h-8 w-64">
110
+ <span className="text-xs text-foreground">真实内容已加载</span>
111
+ </Skeleton>
112
+ </div>
113
+ ```
114
+
102
115
  ### Avatar
103
116
 
104
117
  头像骨架:三档尺寸 + 两种形状。
@@ -215,7 +215,7 @@ function Slider({
215
215
  >
216
216
  <SliderPrimitive.Range
217
217
  data-slot="slider-range"
218
- className="absolute bg-primary group-data-[reverse=true]/slider:bg-muted select-none data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
218
+ className="absolute bg-primary select-none group-data-[reverse=true]/slider:bg-muted data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
219
219
  />
220
220
  {parsedMarks.map((m) => (
221
221
  <span
@@ -235,7 +235,7 @@ function Slider({
235
235
  key={`label-${m.value}`}
236
236
  data-slot="slider-mark-label"
237
237
  style={labelStyle(m.value)}
238
- className="pointer-events-none absolute whitespace-nowrap text-xs text-muted-foreground"
238
+ className="pointer-events-none absolute text-xs whitespace-nowrap text-muted-foreground"
239
239
  >
240
240
  {m.label}
241
241
  </span>
@@ -111,6 +111,27 @@
111
111
  </>
112
112
  ```
113
113
 
114
+ ### PromiseToast
115
+
116
+ Promise 链式更新 — 一次声明 loading / success / error 三态文案,自动跟随 Promise 状态。
117
+
118
+ ```tsx
119
+ <>
120
+ <Button
121
+ onClick={() =>
122
+ toast.promise(mockRequest(), {
123
+ loading: '正在提交订单...',
124
+ success: (data) => `${data.name} 已提交`,
125
+ error: (err: Error) => `提交失败:${err.message}`,
126
+ })
127
+ }
128
+ >
129
+ 触发
130
+ </Button>
131
+ <Toaster />
132
+ </>
133
+ ```
134
+
114
135
  ### Duration
115
136
 
116
137
  持续时长 — `duration` 控制关闭延迟,`Infinity` 持久不关。对应 cloud-design `duration: 0`。
@@ -137,6 +158,30 @@
137
158
  </div>
138
159
  ```
139
160
 
161
+ ### Placement
162
+
163
+ 容器位置 — `placement` 6 档形态,对应 cloud-design `Notification.config({ placement })`。
164
+
165
+ ```tsx
166
+ <div className="flex flex-col gap-3">
167
+ <div className="flex flex-wrap gap-2">
168
+ {placements.map((p) => (
169
+ <Button
170
+ key={p}
171
+ variant={p === placement ? 'default' : 'outline'}
172
+ onClick={() => {
173
+ setPlacement(p);
174
+ toast.success(`位置:${p}`);
175
+ }}
176
+ >
177
+ {p}
178
+ </Button>
179
+ ))}
180
+ </div>
181
+ <Toaster placement={placement} />
182
+ </div>
183
+ ```
184
+
140
185
  ### Custom
141
186
 
142
187
  自定义渲染 — `toast.custom` 完全接管节点,用于嵌入富内容卡片。
@@ -170,3 +215,44 @@
170
215
  <Toaster />
171
216
  </>
172
217
  ```
218
+
219
+ ### DismissProgrammatic
220
+
221
+ 主动关闭 — `toast.dismiss(id)` 关闭指定通知,`toast.dismiss()` 清空全部。
222
+
223
+ ```tsx
224
+ <div className="flex flex-wrap gap-2">
225
+ <Button
226
+ onClick={() => {
227
+ idRef.current = toast('一条可被定向关闭的通知', {
228
+ description: '保留这条 id,再点“关闭它”按钮。',
229
+ duration: Infinity,
230
+ });
231
+ }}
232
+ >
233
+ 打开 1 条
234
+ </Button>
235
+ <Button
236
+ variant="outline"
237
+ onClick={() => {
238
+ for (let i = 0; i < 3; i += 1) {
239
+ toast.info(`批量通知 ${i + 1}`);
240
+ }
241
+ }}
242
+ >
243
+ 打开 3 条
244
+ </Button>
245
+ <Button
246
+ variant="destructive"
247
+ onClick={() => {
248
+ if (idRef.current !== undefined) toast.dismiss(idRef.current);
249
+ }}
250
+ >
251
+ 关闭它(按 id)
252
+ </Button>
253
+ <Button variant="destructive" onClick={() => toast.dismiss()}>
254
+ 全部关闭
255
+ </Button>
256
+ <Toaster />
257
+ </div>
258
+ ```
@@ -136,6 +136,37 @@ tip 位置:right(行内) 与 bottom(堆叠)。
136
136
  </div>
137
137
  ```
138
138
 
139
+ ### OverlayControlled
140
+
141
+ 受控 visible + 100ms 防闪:短任务 (800ms) 不闪烁,长任务 (2000ms) 正常展示。
142
+
143
+ ```tsx
144
+ <div className="flex flex-col gap-4">
145
+ <Button
146
+ onClick={() => {
147
+ setVisible1(true);
148
+ setVisible2(true);
149
+ setTimeout(() => setVisible1(false), 800);
150
+ setTimeout(() => setVisible2(false), 2000);
151
+ }}
152
+ >
153
+ 开始加载
154
+ </Button>
155
+ <div className="flex gap-6">
156
+ <SpinnerOverlay visible={visible1} tip="800ms 快任务">
157
+ <div className="h-20 w-40 rounded border border-border p-4 text-xs">
158
+ 面板 1
159
+ </div>
160
+ </SpinnerOverlay>
161
+ <SpinnerOverlay visible={visible2} tip="2000ms 慢任务">
162
+ <div className="h-20 w-40 rounded border border-border p-4 text-xs">
163
+ 面板 2
164
+ </div>
165
+ </SpinnerOverlay>
166
+ </div>
167
+ </div>
168
+ ```
169
+
139
170
  ### OverlayCustomIndicator
140
171
 
141
172
  自定义 indicator 替换默认 Spinner。
@@ -148,6 +179,21 @@ tip 位置:right(行内) 与 bottom(堆叠)。
148
179
  </SpinnerOverlay>
149
180
  ```
150
181
 
182
+ ### Fullscreen
183
+
184
+ 全屏遮罩 + Portal 投放 + Esc 关闭。
185
+
186
+ ```tsx
187
+ <div>
188
+ <Button onClick={() => setVisible(true)}>打开全屏 Loading</Button>
189
+ <SpinnerFullscreen
190
+ visible={visible}
191
+ tip="加载中,按 Esc 关闭"
192
+ onVisibleChange={setVisible}
193
+ />
194
+ </div>
195
+ ```
196
+
151
197
  ### DotsDefault
152
198
 
153
199
  SpinnerDots 三档尺寸:四点沿弧线轨道位移动画。
@@ -113,7 +113,7 @@ export const OverlayTipAlign: Story = {
113
113
 
114
114
  /** 受控 visible + 100ms 防闪:短任务 (800ms) 不闪烁,长任务 (2000ms) 正常展示。 */
115
115
  export const OverlayControlled: Story = {
116
- render: function OverlayControlledRender() {
116
+ render: () => {
117
117
  const [visible1, setVisible1] = React.useState(false);
118
118
  const [visible2, setVisible2] = React.useState(false);
119
119
  return (
@@ -158,7 +158,7 @@ export const OverlayCustomIndicator: Story = {
158
158
 
159
159
  /** 全屏遮罩 + Portal 投放 + Esc 关闭。 */
160
160
  export const Fullscreen: Story = {
161
- render: function FullscreenRender() {
161
+ render: () => {
162
162
  const [visible, setVisible] = React.useState(false);
163
163
  return (
164
164
  <div>
@@ -197,6 +197,26 @@ labelPlacement="horizontal"——标签在指示器右侧水平排列。
197
197
  </div>
198
198
  ```
199
199
 
200
+ ### Clickable
201
+
202
+ 可点击步骤——传入 onChange 后步骤可交互切换。
203
+
204
+ ```tsx
205
+ <div className="flex flex-col gap-6">
206
+ <Steps
207
+ shape="circle"
208
+ current={current}
209
+ onChange={setCurrent}
210
+ items={[
211
+ { title: '选择类型', description: '点击可跳转' },
212
+ { title: '填写内容', description: '点击可跳转' },
213
+ { title: '确认发布', description: '点击可跳转' },
214
+ ]}
215
+ />
216
+ <p className="text-xs text-muted-foreground">当前步骤:{current + 1}</p>
217
+ </div>
218
+ ```
219
+
200
220
  ### AllStatuses
201
221
 
202
222
  所有状态一览。
@@ -221,7 +221,7 @@ export const Small: Story = {
221
221
 
222
222
  /** 可点击步骤——传入 onChange 后步骤可交互切换。 */
223
223
  export const Clickable: Story = {
224
- render: function ClickableSteps() {
224
+ render: () => {
225
225
  const [current, setCurrent] = useState(0);
226
226
  return (
227
227
  <div className="flex flex-col gap-6">
@@ -23,7 +23,7 @@ import { cn } from '@/lib/utils';
23
23
  // ─── cva ────────────────────────────────────────────────────────────────────
24
24
 
25
25
  const switchVariants = cva(
26
- 'peer group/switch relative inline-flex shrink-0 cursor-pointer items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-ring/20 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input data-disabled:cursor-not-allowed data-disabled:opacity-50 data-[loading=true]:pointer-events-none data-[loading=true]:opacity-70',
26
+ 'peer group/switch relative inline-flex shrink-0 cursor-pointer items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-ring/20 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 data-disabled:cursor-not-allowed data-disabled:opacity-50 data-[loading=true]:pointer-events-none data-[loading=true]:opacity-70 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
27
27
  {
28
28
  variants: {
29
29
  size: {
@@ -80,7 +80,7 @@ const thumbVariants = cva(
80
80
 
81
81
  const textVariants = cva(
82
82
  // padding 与 order 跟随 root data-state 切换:满足"thumb 紧贴边缘"规范(root 不加 px)
83
- 'inline-flex select-none items-center justify-center whitespace-nowrap leading-none transition-colors group-data-[state=checked]/switch:order-1 group-data-[state=checked]/switch:text-primary-foreground group-data-[state=unchecked]/switch:order-2 group-data-[state=unchecked]/switch:text-muted-foreground',
83
+ 'inline-flex items-center justify-center leading-none whitespace-nowrap transition-colors select-none group-data-[state=checked]/switch:order-1 group-data-[state=checked]/switch:text-primary-foreground group-data-[state=unchecked]/switch:order-2 group-data-[state=unchecked]/switch:text-muted-foreground',
84
84
  {
85
85
  variants: {
86
86
  size: {