@teamix-evo/ui 0.7.1 → 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 (120) 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 +2 -2
  29. package/src/components/data-table/meta.md +419 -0
  30. package/src/components/date-picker/meta.md +91 -0
  31. package/src/components/descriptions/index.tsx +1 -1
  32. package/src/components/descriptions/meta.md +245 -0
  33. package/src/components/dialog/index.tsx +4 -4
  34. package/src/components/dialog/meta.md +47 -1
  35. package/src/components/dialog/stories.tsx +38 -41
  36. package/src/components/dropdown-menu/index.tsx +5 -5
  37. package/src/components/empty/index.tsx +2 -2
  38. package/src/components/field/index.tsx +4 -4
  39. package/src/components/filter-bar/index.tsx +6 -6
  40. package/src/components/filter-bar/meta.md +323 -0
  41. package/src/components/float-button/index.tsx +2 -2
  42. package/src/components/form/index.tsx +1 -1
  43. package/src/components/form/meta.md +119 -0
  44. package/src/components/hover-card/index.tsx +1 -1
  45. package/src/components/hover-card/meta.md +21 -0
  46. package/src/components/input/meta.md +16 -0
  47. package/src/components/input-group/index.tsx +1 -1
  48. package/src/components/input-group/meta.md +118 -0
  49. package/src/components/input-group/stories.tsx +6 -6
  50. package/src/components/input-ip/index.tsx +2 -2
  51. package/src/components/input-ip/meta.md +30 -0
  52. package/src/components/input-ip/stories.tsx +2 -2
  53. package/src/components/input-number/index.tsx +3 -2
  54. package/src/components/input-number/meta.md +67 -0
  55. package/src/components/input-number/stories.tsx +2 -2
  56. package/src/components/item/index.tsx +4 -4
  57. package/src/components/label/meta.md +8 -0
  58. package/src/components/mentions/meta.md +15 -0
  59. package/src/components/menubar/index.tsx +4 -4
  60. package/src/components/navigation-menu/index.tsx +4 -4
  61. package/src/components/page-header/index.tsx +1 -1
  62. package/src/components/page-header/meta.md +145 -0
  63. package/src/components/page-shell/index.tsx +2 -2
  64. package/src/components/pagination/index.tsx +1 -1
  65. package/src/components/pagination/meta.md +203 -0
  66. package/src/components/popconfirm/meta.md +45 -0
  67. package/src/components/popover/index.tsx +2 -2
  68. package/src/components/popover/meta.md +47 -0
  69. package/src/components/progress/index.tsx +1 -1
  70. package/src/components/progress/meta.md +36 -0
  71. package/src/components/progress/stories.tsx +1 -1
  72. package/src/components/radio-group/meta.md +69 -0
  73. package/src/components/rate/index.tsx +1 -1
  74. package/src/components/rate/meta.md +50 -0
  75. package/src/components/resizable/index.tsx +1 -1
  76. package/src/components/select/index.tsx +2 -2
  77. package/src/components/select/meta.md +20 -0
  78. package/src/components/separator/index.tsx +1 -1
  79. package/src/components/sheet/index.tsx +13 -14
  80. package/src/components/sheet/meta.md +124 -0
  81. package/src/components/sheet/stories.tsx +110 -119
  82. package/src/components/sidebar/index.tsx +5 -5
  83. package/src/components/sidebar/meta.md +383 -0
  84. package/src/components/skeleton/meta.md +13 -0
  85. package/src/components/slider/index.tsx +2 -2
  86. package/src/components/sonner/meta.md +86 -0
  87. package/src/components/spinner/meta.md +46 -0
  88. package/src/components/spinner/stories.tsx +2 -2
  89. package/src/components/steps/meta.md +20 -0
  90. package/src/components/steps/stories.tsx +1 -1
  91. package/src/components/switch/index.tsx +2 -2
  92. package/src/components/switch/meta.md +33 -0
  93. package/src/components/table/index.tsx +2 -2
  94. package/src/components/table/meta.md +11 -0
  95. package/src/components/tabs/index.tsx +7 -7
  96. package/src/components/tabs/meta.md +52 -0
  97. package/src/components/tag/index.tsx +8 -8
  98. package/src/components/tag/meta.md +194 -0
  99. package/src/components/textarea/index.tsx +1 -1
  100. package/src/components/textarea/meta.md +27 -0
  101. package/src/components/textarea/stories.tsx +1 -1
  102. package/src/components/time-picker/index.tsx +3 -3
  103. package/src/components/time-picker/meta.md +76 -0
  104. package/src/components/timeline/index.tsx +1 -0
  105. package/src/components/toggle/index.tsx +1 -1
  106. package/src/components/toggle-group/index.tsx +1 -1
  107. package/src/components/tooltip/index.tsx +1 -1
  108. package/src/components/tooltip/meta.md +23 -0
  109. package/src/components/transfer/index.tsx +2 -2
  110. package/src/components/transfer/meta.md +97 -0
  111. package/src/components/tree/index.tsx +245 -15
  112. package/src/components/tree/meta.md +151 -0
  113. package/src/components/tree-select/index.tsx +16 -2
  114. package/src/components/tree-select/meta.md +150 -0
  115. package/src/components/typography/index.tsx +3 -3
  116. package/src/components/upload/index.tsx +3 -3
  117. package/src/components/upload/meta.md +82 -0
  118. package/src/components/tree/utils.ts +0 -269
  119. package/src/examples/built-in-assets/stories.tsx +0 -572
  120. package/src/examples/evaluators/stories.tsx +0 -502
@@ -45,6 +45,81 @@ DescriptionsContent 自由组合,label 与 content 都是 ReactNode 槽位,
45
45
 
46
46
  ## 示例
47
47
 
48
+ ### Vertical
49
+
50
+ 垂直布局:label 与 content 上下堆叠。
51
+
52
+ ```tsx
53
+ <Descriptions {...args}>
54
+ <DescriptionsItem>
55
+ <DescriptionsLabel>CPU</DescriptionsLabel>
56
+ <DescriptionsContent>8 核</DescriptionsContent>
57
+ </DescriptionsItem>
58
+ <DescriptionsItem>
59
+ <DescriptionsLabel>内存</DescriptionsLabel>
60
+ <DescriptionsContent>16 GB</DescriptionsContent>
61
+ </DescriptionsItem>
62
+ <DescriptionsItem>
63
+ <DescriptionsLabel>硬盘</DescriptionsLabel>
64
+ <DescriptionsContent>512 GB SSD</DescriptionsContent>
65
+ </DescriptionsItem>
66
+ <DescriptionsItem>
67
+ <DescriptionsLabel>网络</DescriptionsLabel>
68
+ <DescriptionsContent>千兆</DescriptionsContent>
69
+ </DescriptionsItem>
70
+ </Descriptions>
71
+ ```
72
+
73
+ ### Bordered
74
+
75
+ 带边框矩阵:经典 antd 风格。
76
+
77
+ ```tsx
78
+ <Descriptions {...args}>
79
+ <DescriptionsItem>
80
+ <DescriptionsLabel>订单号</DescriptionsLabel>
81
+ <DescriptionsContent>ORD-20260601-001</DescriptionsContent>
82
+ </DescriptionsItem>
83
+ <DescriptionsItem>
84
+ <DescriptionsLabel>金额</DescriptionsLabel>
85
+ <DescriptionsContent>¥1,299.00</DescriptionsContent>
86
+ </DescriptionsItem>
87
+ <DescriptionsItem>
88
+ <DescriptionsLabel>收货人</DescriptionsLabel>
89
+ <DescriptionsContent>李四</DescriptionsContent>
90
+ </DescriptionsItem>
91
+ <DescriptionsItem>
92
+ <DescriptionsLabel>联系电话</DescriptionsLabel>
93
+ <DescriptionsContent>138****0001</DescriptionsContent>
94
+ </DescriptionsItem>
95
+ <DescriptionsItem span={2}>
96
+ <DescriptionsLabel>收货地址</DescriptionsLabel>
97
+ <DescriptionsContent>杭州市余杭区文一西路</DescriptionsContent>
98
+ </DescriptionsItem>
99
+ </Descriptions>
100
+ ```
101
+
102
+ ### BorderedVertical
103
+
104
+ 带边框 + 垂直布局:label 在上 content 在下。
105
+
106
+ ```tsx
107
+ <Descriptions {...args}>
108
+ <DescriptionsItem>
109
+ <DescriptionsLabel>实例 ID</DescriptionsLabel>
110
+ <DescriptionsContent>i-2zee0xxxxxxx</DescriptionsContent>
111
+ </DescriptionsItem>
112
+ <DescriptionsItem>
113
+ <DescriptionsLabel>可用区</DescriptionsLabel>
114
+ <DescriptionsContent>cn-hangzhou-h</DescriptionsContent>
115
+ </DescriptionsItem>
116
+ <DescriptionsItem>
117
+ <DescriptionsLabel>镜像</DescriptionsLabel>
118
+ <DescriptionsContent>AnolisOS 8.6</DescriptionsContent>
119
+ </DescriptionsItem>
120
+ </Descriptions>
121
+ ```
122
+
48
123
  ### Sizes
49
124
 
50
125
  不同尺寸:sm / default 对比。
@@ -102,3 +177,173 @@ DescriptionsContent 自由组合,label 与 content 都是 ReactNode 槽位,
102
177
  </Descriptions>
103
178
  </div>
104
179
  ```
180
+
181
+ ### Responsive
182
+
183
+ 响应式列数:viewport 断点驱动。在 Storybook viewport 切换查看。
184
+
185
+ ```tsx
186
+ <Descriptions {...args}>
187
+ <BaseItems />
188
+ </Descriptions>
189
+ ```
190
+
191
+ ### WithSpan
192
+
193
+ 跨列:通过 span 合并多列。
194
+
195
+ ```tsx
196
+ <Descriptions {...args}>
197
+ <DescriptionsItem>
198
+ <DescriptionsLabel>名称</DescriptionsLabel>
199
+ <DescriptionsContent>Teamix Evo</DescriptionsContent>
200
+ </DescriptionsItem>
201
+ <DescriptionsItem>
202
+ <DescriptionsLabel>版本</DescriptionsLabel>
203
+ <DescriptionsContent>v0.8</DescriptionsContent>
204
+ </DescriptionsItem>
205
+ <DescriptionsItem>
206
+ <DescriptionsLabel>语言</DescriptionsLabel>
207
+ <DescriptionsContent>TypeScript</DescriptionsContent>
208
+ </DescriptionsItem>
209
+ <DescriptionsItem span={3}>
210
+ <DescriptionsLabel>描述</DescriptionsLabel>
211
+ <DescriptionsContent>
212
+ 面向 AI Coding 的研发套件,覆盖设计、组件、技能。
213
+ </DescriptionsContent>
214
+ </DescriptionsItem>
215
+ </Descriptions>
216
+ ```
217
+
218
+ ### WithTooltip
219
+
220
+ label 旁带 Tooltip 图标:在 `<DescriptionsLabel>` 子树内直接拼装 `<Tooltip>`。 高频使用建议在自己工程抽一个 `<HelpLabel label tip />` helper(5 行即可)。
221
+
222
+ ```tsx
223
+ <Descriptions {...args}>
224
+ <DescriptionsItem>
225
+ <DescriptionsLabel>
226
+ 实例 ID
227
+ <Tooltip>
228
+ <TooltipTrigger asChild>
229
+ <button
230
+ type="button"
231
+ aria-label="字段说明"
232
+ className="inline-flex cursor-pointer items-center text-muted-foreground transition-colors hover:text-foreground"
233
+ >
234
+ <InfoIcon className="size-3.5" />
235
+ </button>
236
+ </TooltipTrigger>
237
+ <TooltipContent>云资源唯一标识</TooltipContent>
238
+ </Tooltip>
239
+ </DescriptionsLabel>
240
+ <DescriptionsContent>i-2zee0xxx</DescriptionsContent>
241
+ </DescriptionsItem>
242
+ <DescriptionsItem>
243
+ <DescriptionsLabel>
244
+ 收藏
245
+ <Tooltip>
246
+ <TooltipTrigger asChild>
247
+ <button
248
+ type="button"
249
+ aria-label="字段说明"
250
+ className="inline-flex cursor-pointer items-center text-muted-foreground transition-colors hover:text-foreground"
251
+ >
252
+ <StarIcon className="size-3.5" />
253
+ </button>
254
+ </TooltipTrigger>
255
+ <TooltipContent>收藏后可在工作台直接进入</TooltipContent>
256
+ </Tooltip>
257
+ </DescriptionsLabel>
258
+ <DescriptionsContent>已收藏</DescriptionsContent>
259
+ </DescriptionsItem>
260
+ </Descriptions>
261
+ ```
262
+
263
+ ### WithRichContent
264
+
265
+ content 内部混排其他组件(Tag / 行内按钮等)—— 全部直接塞进 `<DescriptionsContent>`。
266
+
267
+ ```tsx
268
+ <Descriptions {...args}>
269
+ <DescriptionsItem>
270
+ <DescriptionsLabel>实例 ID</DescriptionsLabel>
271
+ <DescriptionsContent>
272
+ <span className="inline-flex items-center gap-2">
273
+ i-2zee0xxxxxxx
274
+ <Button variant="ghost" size="sm" aria-label="复制">
275
+ <CopyIcon />
276
+ </Button>
277
+ </span>
278
+ </DescriptionsContent>
279
+ </DescriptionsItem>
280
+ <DescriptionsItem>
281
+ <DescriptionsLabel>状态</DescriptionsLabel>
282
+ <DescriptionsContent>
283
+ <Tag color="success">运行中</Tag>
284
+ </DescriptionsContent>
285
+ </DescriptionsItem>
286
+ </Descriptions>
287
+ ```
288
+
289
+ ### ControlAlignment
290
+
291
+ 控件高度对齐:horizontal 非 bordered 模式下label 默认 `min-h-6`(24px)与 sm Button / Tag 同高,顶对齐 = 视觉基线对齐。若 content 是 h-8 / h-10 等更高控件, 用 `<DescriptionsItem align="center">` 让 label 与控件整体居中。
292
+
293
+ ```tsx
294
+ <Descriptions {...args}>
295
+ {/* sm 控件 24px:label min-h-6 同高,默认 align="start" 即可对齐 */}
296
+ <DescriptionsItem>
297
+ <DescriptionsLabel>状态</DescriptionsLabel>
298
+ <DescriptionsContent>
299
+ <Tag color="success">运行中</Tag>
300
+ </DescriptionsContent>
301
+ </DescriptionsItem>
302
+ <DescriptionsItem>
303
+ <DescriptionsLabel>实例 ID</DescriptionsLabel>
304
+ <DescriptionsContent>
305
+ <span className="inline-flex items-center gap-2">
306
+ i-2zee0xxxxxxx
307
+ <Button variant="ghost" size="sm" aria-label="复制">
308
+ <CopyIcon />
309
+ </Button>
310
+ </span>
311
+ </DescriptionsContent>
312
+ </DescriptionsItem>
313
+ {/* default 控件 32px:需 align="center" 让 label 与控件整体居中 */}
314
+ <DescriptionsItem align="center">
315
+ <DescriptionsLabel>操作</DescriptionsLabel>
316
+ <DescriptionsContent>
317
+ <Button variant="outline">重启实例</Button>
318
+ </DescriptionsContent>
319
+ </DescriptionsItem>
320
+ <DescriptionsItem align="center">
321
+ <DescriptionsLabel>变更</DescriptionsLabel>
322
+ <DescriptionsContent>
323
+ <Button variant="ghost">
324
+ <RefreshCwIcon /> 同步配置
325
+ </Button>
326
+ </DescriptionsContent>
327
+ </DescriptionsItem>
328
+ </Descriptions>
329
+ ```
330
+
331
+ ### WithHeaderExtra
332
+
333
+ 顶部 extra 槽:放刷新等操作。
334
+
335
+ ```tsx
336
+ <Descriptions {...args}>
337
+ <BaseItems />
338
+ </Descriptions>
339
+ ```
340
+
341
+ ### Collapsible
342
+
343
+ 折叠:头部点击展开收起。
344
+
345
+ ```tsx
346
+ <Descriptions {...args}>
347
+ <BaseItems />
348
+ </Descriptions>
349
+ ```
@@ -74,7 +74,7 @@ function DialogOverlay({
74
74
  <DialogPrimitive.Overlay
75
75
  data-slot="dialog-overlay"
76
76
  className={cn(
77
- 'fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0',
77
+ 'fixed inset-0 isolate z-50 bg-black/10 duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 supports-backdrop-filter:backdrop-blur-xs',
78
78
  className,
79
79
  )}
80
80
  {...props}
@@ -118,7 +118,7 @@ function DialogContent({
118
118
  }}
119
119
  className={cn(
120
120
  // eslint-disable-next-line teamix-evo/no-arbitrary-tw-value -- mobile viewport needs calc(100% - 2rem) for safe inset; box-shadow drives via component-level token --dialog-shadow per ADR 0026.
121
- 'fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-md bg-popover text-sm text-popover-foreground shadow-[var(--dialog-shadow,0px_6px_24px_0px_rgba(0,0,0,0.1))] duration-100 outline-none data-[size=sm]:sm:max-w-md data-[size=md]:sm:max-w-xl data-[size=lg]:sm:max-w-3xl data-[size=xl]:sm:max-w-6xl data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
121
+ 'fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-1/2 rounded-md bg-popover text-sm text-popover-foreground shadow-[var(--dialog-shadow,0px_6px_24px_0px_rgba(0,0,0,0.1))] duration-100 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[size=lg]:sm:max-w-3xl data-[size=md]:sm:max-w-xl data-[size=sm]:sm:max-w-md data-[size=xl]:sm:max-w-6xl',
122
122
  className,
123
123
  )}
124
124
  {...props}
@@ -150,7 +150,7 @@ function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
150
150
  <div
151
151
  data-slot="dialog-header"
152
152
  className={cn(
153
- 'flex flex-col gap-1.5 border-b border-border pt-3 pr-14 pb-3 pl-5 has-data-[slot=dialog-header-extra]:grid has-data-[slot=dialog-header-extra]:grid-cols-[1fr_auto] has-data-[slot=dialog-header-extra]:items-start has-data-[slot=dialog-header-extra]:gap-x-3',
153
+ 'flex flex-col gap-1.5 border-b border-border py-3 pr-14 pl-5 has-data-[slot=dialog-header-extra]:grid has-data-[slot=dialog-header-extra]:grid-cols-[1fr_auto] has-data-[slot=dialog-header-extra]:items-start has-data-[slot=dialog-header-extra]:gap-x-3',
154
154
  className,
155
155
  )}
156
156
  {...props}
@@ -207,7 +207,7 @@ function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
207
207
  <div
208
208
  data-slot="dialog-footer"
209
209
  className={cn(
210
- // eslint-disable-next-line teamix-evo/no-bare-border -- border-footer-separator 是 @theme 声明的语义 token,已加入 lint-core 白名单
210
+
211
211
  'flex flex-col-reverse gap-2 border-t border-footer-separator px-5 py-4 sm:flex-row sm:justify-end',
212
212
  className,
213
213
  )}
@@ -165,6 +165,52 @@
165
165
  </Dialog>
166
166
  ```
167
167
 
168
+ ### AsyncSubmit
169
+
170
+ 异步提交 — onSubmit 返回 Promise,按钮 loading 期间禁止关闭。
171
+
172
+ ```tsx
173
+ const [open, setOpen] = React.useState(false);
174
+ const [loading, setLoading] = React.useState(false);
175
+ const onConfirm = async () => {
176
+ setLoading(true);
177
+ await new Promise((r) => setTimeout(r, 1500));
178
+ setLoading(false);
179
+ setOpen(false);
180
+ };
181
+ return (
182
+ <Dialog
183
+ open={open}
184
+ onOpenChange={(next) => {
185
+ if (loading) return;
186
+ setOpen(next);
187
+ }}
188
+ >
189
+ <DialogTrigger asChild>
190
+ <Button>打开</Button>
191
+ </DialogTrigger>
192
+ <DialogContent
193
+ onPointerDownOutside={(e) => loading && e.preventDefault()}
194
+ onEscapeKeyDown={(e) => loading && e.preventDefault()}
195
+ >
196
+ <DialogHeader>
197
+ <DialogTitle>确认删除?</DialogTitle>
198
+ </DialogHeader>
199
+ <DialogFooter>
200
+ <DialogClose asChild>
201
+ <Button variant="outline" disabled={loading}>
202
+ 取消
203
+ </Button>
204
+ </DialogClose>
205
+ <Button loading={loading} onClick={onConfirm}>
206
+ 确认
207
+ </Button>
208
+ </DialogFooter>
209
+ </DialogContent>
210
+ </Dialog>
211
+ );
212
+ ```
213
+
168
214
  ### NoCloseButton
169
215
 
170
216
  隐藏关闭按钮 — 强制通过底部操作关闭,常用于流程类强引导。
@@ -196,7 +242,7 @@
196
242
  <DialogTrigger asChild>
197
243
  <Button>全屏打开</Button>
198
244
  </DialogTrigger>
199
- <DialogContent className="inset-0 top-0 left-0 max-w-none -translate-x-0 -translate-y-0 grid-rows-[auto_1fr_auto] rounded-none data-[state=open]:zoom-in-100 data-[state=open]:slide-in-from-bottom-2 data-[state=closed]:zoom-out-100 data-[state=closed]:slide-out-to-bottom-2 sm:max-w-none">
245
+ <DialogContent className="inset-0 top-0 left-0 max-w-none grid-rows-[auto_1fr_auto] rounded-none data-[state=open]:zoom-in-100 data-[state=open]:slide-in-from-bottom-2 data-[state=closed]:zoom-out-100 data-[state=closed]:slide-out-to-bottom-2 sm:max-w-none -translate-0">
200
246
  <DialogHeader>
201
247
  <DialogTitle>全屏编辑</DialogTitle>
202
248
  </DialogHeader>
@@ -206,48 +206,45 @@ export const LargeContent: Story = {
206
206
  export const AsyncSubmit: Story = {
207
207
  name: '异步提交',
208
208
  render: () => {
209
- function Demo() {
210
- const [open, setOpen] = React.useState(false);
211
- const [loading, setLoading] = React.useState(false);
212
- const onConfirm = async () => {
213
- setLoading(true);
214
- await new Promise((r) => setTimeout(r, 1500));
215
- setLoading(false);
216
- setOpen(false);
217
- };
218
- return (
219
- <Dialog
220
- open={open}
221
- onOpenChange={(next) => {
222
- if (loading) return;
223
- setOpen(next);
224
- }}
209
+ const [open, setOpen] = React.useState(false);
210
+ const [loading, setLoading] = React.useState(false);
211
+ const onConfirm = async () => {
212
+ setLoading(true);
213
+ await new Promise((r) => setTimeout(r, 1500));
214
+ setLoading(false);
215
+ setOpen(false);
216
+ };
217
+ return (
218
+ <Dialog
219
+ open={open}
220
+ onOpenChange={(next) => {
221
+ if (loading) return;
222
+ setOpen(next);
223
+ }}
224
+ >
225
+ <DialogTrigger asChild>
226
+ <Button>打开</Button>
227
+ </DialogTrigger>
228
+ <DialogContent
229
+ onPointerDownOutside={(e) => loading && e.preventDefault()}
230
+ onEscapeKeyDown={(e) => loading && e.preventDefault()}
225
231
  >
226
- <DialogTrigger asChild>
227
- <Button>打开</Button>
228
- </DialogTrigger>
229
- <DialogContent
230
- onPointerDownOutside={(e) => loading && e.preventDefault()}
231
- onEscapeKeyDown={(e) => loading && e.preventDefault()}
232
- >
233
- <DialogHeader>
234
- <DialogTitle>确认删除?</DialogTitle>
235
- </DialogHeader>
236
- <DialogFooter>
237
- <DialogClose asChild>
238
- <Button variant="outline" disabled={loading}>
239
- 取消
240
- </Button>
241
- </DialogClose>
242
- <Button loading={loading} onClick={onConfirm}>
243
- 确认
232
+ <DialogHeader>
233
+ <DialogTitle>确认删除?</DialogTitle>
234
+ </DialogHeader>
235
+ <DialogFooter>
236
+ <DialogClose asChild>
237
+ <Button variant="outline" disabled={loading}>
238
+ 取消
244
239
  </Button>
245
- </DialogFooter>
246
- </DialogContent>
247
- </Dialog>
248
- );
249
- }
250
- return <Demo />;
240
+ </DialogClose>
241
+ <Button loading={loading} onClick={onConfirm}>
242
+ 确认
243
+ </Button>
244
+ </DialogFooter>
245
+ </DialogContent>
246
+ </Dialog>
247
+ );
251
248
  },
252
249
  };
253
250
 
@@ -281,7 +278,7 @@ export const Fullscreen: Story = {
281
278
  <DialogTrigger asChild>
282
279
  <Button>全屏打开</Button>
283
280
  </DialogTrigger>
284
- <DialogContent className="inset-0 top-0 left-0 max-w-none -translate-x-0 -translate-y-0 grid-rows-[auto_1fr_auto] rounded-none data-[state=open]:zoom-in-100 data-[state=open]:slide-in-from-bottom-2 data-[state=closed]:zoom-out-100 data-[state=closed]:slide-out-to-bottom-2 sm:max-w-none">
281
+ <DialogContent className="inset-0 top-0 left-0 max-w-none grid-rows-[auto_1fr_auto] rounded-none data-[state=open]:zoom-in-100 data-[state=open]:slide-in-from-bottom-2 data-[state=closed]:zoom-out-100 data-[state=closed]:slide-out-to-bottom-2 sm:max-w-none -translate-0">
285
282
  <DialogHeader>
286
283
  <DialogTitle>全屏编辑</DialogTitle>
287
284
  </DialogHeader>
@@ -72,7 +72,7 @@ function DropdownMenuContent({
72
72
  sideOffset={sideOffset}
73
73
  align={align}
74
74
  className={cn(
75
- 'z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 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 data-[state=closed]:overflow-hidden data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
75
+ 'z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 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 data-[state=closed]:animate-out data-[state=closed]:overflow-hidden data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
76
76
  className,
77
77
  )}
78
78
  {...props}
@@ -104,7 +104,7 @@ function DropdownMenuItem({
104
104
  data-inset={inset}
105
105
  data-variant={variant}
106
106
  className={cn(
107
- "group/dropdown-menu-item relative flex h-8 cursor-pointer items-center gap-1.5 rounded-md px-1.5 py-1 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
107
+ "group/dropdown-menu-item relative flex h-8 cursor-pointer items-center gap-1.5 rounded-md px-1.5 py-1 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
108
108
  className,
109
109
  )}
110
110
  {...props}
@@ -126,7 +126,7 @@ function DropdownMenuCheckboxItem({
126
126
  data-slot="dropdown-menu-checkbox-item"
127
127
  data-inset={inset}
128
128
  className={cn(
129
- "relative flex h-8 cursor-pointer items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
129
+ "relative flex h-8 cursor-pointer items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
130
130
  className,
131
131
  )}
132
132
  checked={checked}
@@ -169,7 +169,7 @@ function DropdownMenuRadioItem({
169
169
  data-slot="dropdown-menu-radio-item"
170
170
  data-inset={inset}
171
171
  className={cn(
172
- "relative flex h-8 cursor-pointer items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
172
+ "relative flex h-8 cursor-pointer items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
173
173
  className,
174
174
  )}
175
175
  {...props}
@@ -274,7 +274,7 @@ function DropdownMenuSubContent({
274
274
  <DropdownMenuPrimitive.SubContent
275
275
  data-slot="dropdown-menu-sub-content"
276
276
  className={cn(
277
- 'z-50 min-w-24 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 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 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
277
+ 'z-50 min-w-24 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
278
278
  className,
279
279
  )}
280
280
  {...props}
@@ -43,7 +43,7 @@ const emptyVariants = cva(
43
43
  variants: {
44
44
  layout: {
45
45
  vertical: 'flex-col text-center',
46
- horizontal: 'flex-row text-left min-h-80',
46
+ horizontal: 'min-h-80 flex-row text-left',
47
47
  },
48
48
  size: {
49
49
  sm: 'p-4',
@@ -386,7 +386,7 @@ function EmptyTitle({ className, ...props }: React.ComponentProps<'div'>) {
386
386
  <div
387
387
  data-slot="empty-title"
388
388
  className={cn(
389
- 'font-medium tracking-tight text-foreground group-data-[size=sm]/empty:text-sm group-data-[size=default]/empty:text-base group-data-[size=lg]/empty:text-2xl group-data-[size=lg]/empty:leading-9 group-data-[layout=horizontal]/empty:text-muted-foreground',
389
+ 'font-medium tracking-tight text-foreground group-data-[layout=horizontal]/empty:text-muted-foreground group-data-[size=default]/empty:text-base group-data-[size=lg]/empty:text-2xl group-data-[size=lg]/empty:leading-9 group-data-[size=sm]/empty:text-sm',
390
390
  className,
391
391
  )}
392
392
  {...props}
@@ -158,7 +158,7 @@ function FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {
158
158
  <div
159
159
  data-slot="field-group"
160
160
  className={cn(
161
- 'group/field-group @container/field-group flex w-full flex-col gap-5 [&>[data-slot=field-set]+[data-slot=field-set]]:mt-3 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4',
161
+ 'group/field-group @container/field-group flex w-full flex-col gap-5 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4 [&>[data-slot=field-set]+[data-slot=field-set]]:mt-3',
162
162
  className,
163
163
  )}
164
164
  {...props}
@@ -173,7 +173,7 @@ const fieldVariants = cva(
173
173
  orientation: {
174
174
  vertical: 'flex-col gap-1 *:w-full [&>.sr-only]:w-auto',
175
175
  responsive:
176
- 'flex-col gap-1 *:w-full @[30rem]/field-group:grid @[30rem]/field-group:grid-cols-12 @[30rem]/field-group:gap-x-4 @[30rem]/field-group:gap-y-1 @[30rem]/field-group:items-start @[30rem]/field-group:[&>[data-slot=field-label]]:col-span-2 @[30rem]/field-group:[&>:not([data-slot=field-label])]:col-span-8 @[30rem]/field-group:[&>:not([data-slot=field-label])]:col-start-3 [&>.sr-only]:w-auto',
176
+ 'flex-col gap-1 *:w-full @[30rem]/field-group:grid @[30rem]/field-group:grid-cols-12 @[30rem]/field-group:items-start @[30rem]/field-group:gap-x-4 @[30rem]/field-group:gap-y-1 [&>.sr-only]:w-auto @[30rem]/field-group:[&>:not([data-slot=field-label])]:col-span-8 @[30rem]/field-group:[&>:not([data-slot=field-label])]:col-start-3 @[30rem]/field-group:[&>[data-slot=field-label]]:col-span-2',
177
177
  inset: 'flex-col gap-1',
178
178
  },
179
179
  },
@@ -243,7 +243,7 @@ function FieldLabel({
243
243
  className={cn(
244
244
  'group/field-label peer/field-label flex w-fit gap-1 leading-8 group-data-[disabled=true]/field:opacity-50 has-data-[state=checked]:border-primary/30 has-data-[state=checked]:bg-primary/5 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border *:data-[slot=field]:p-2.5',
245
245
  'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col',
246
- 'group-data-[orientation=inset]/field:h-full group-data-[orientation=inset]/field:shrink-0 group-data-[orientation=inset]/field:items-center group-data-[orientation=inset]/field:pl-3 group-data-[orientation=inset]/field:pr-2 group-data-[orientation=inset]/field:leading-normal group-data-[orientation=inset]/field:text-muted-foreground',
246
+ 'group-data-[orientation=inset]/field:h-full group-data-[orientation=inset]/field:shrink-0 group-data-[orientation=inset]/field:items-center group-data-[orientation=inset]/field:pr-2 group-data-[orientation=inset]/field:pl-3 group-data-[orientation=inset]/field:leading-normal group-data-[orientation=inset]/field:text-muted-foreground',
247
247
  className,
248
248
  )}
249
249
  {...props}
@@ -351,7 +351,7 @@ function FieldError({
351
351
  <div
352
352
  role="alert"
353
353
  data-slot="field-error"
354
- className={cn('text-xs font-normal text-destructive -mt-1', className)}
354
+ className={cn('-mt-1 text-xs font-normal text-destructive', className)}
355
355
  {...props}
356
356
  >
357
357
  {content}
@@ -470,7 +470,7 @@ function FilterBarSearchKey({ options, className }: FilterBarSearchKeyProps) {
470
470
  <SelectTrigger
471
471
  size="sm"
472
472
  className={cn(
473
- 'h-full rounded-none border-0 border-r border-r-input bg-transparent shadow-none focus-visible:ring-0 focus:border-r-input data-[state=open]:border-r-input',
473
+ 'h-full rounded-none border-0 border-r border-r-input bg-transparent shadow-none focus:border-r-input focus-visible:ring-0 data-[state=open]:border-r-input',
474
474
  className,
475
475
  )}
476
476
  >
@@ -624,12 +624,12 @@ function FilterBarContent({
624
624
  >
625
625
  <div
626
626
  className={cn(
627
- 'grid gap-x-4 gap-y-3 rounded-md bg-muted px-4 py-4',
628
- '[&_[data-slot=input]]:bg-card [&_[data-slot=select-trigger]]:bg-card [&_[data-slot=input-number]]:bg-card [&_[data-slot=textarea]]:bg-card',
627
+ 'grid gap-x-4 gap-y-3 rounded-md bg-muted p-4',
628
+ '[&_[data-slot=input-number]]:bg-card [&_[data-slot=input]]:bg-card [&_[data-slot=select-trigger]]:bg-card [&_[data-slot=textarea]]:bg-card',
629
629
  // 面板内表单控件统一全宽(仅作用于 FilterBarContent 子树)
630
- '[&_[data-slot=input]]:w-full [&_[data-slot=input-group]]:w-full [&_[data-slot=input-number]]:w-full [&_[data-slot=input-ip]]:w-full [&_[data-slot=textarea]]:w-full',
631
- '[&_[data-slot=select-trigger]]:w-full [&_[data-slot=cascader-select-trigger]]:w-full [&_[data-slot=tree-select-trigger]]:w-full',
632
- '[&_[data-slot=date-picker]]:w-full [&_[data-slot=date-range-picker]]:w-full [&_[data-slot=time-picker]]:w-full [&_[data-slot=time-range-picker]]:w-full [&_[data-slot=mentions]]:w-full',
630
+ '[&_[data-slot=input-group]]:w-full [&_[data-slot=input-ip]]:w-full [&_[data-slot=input-number]]:w-full [&_[data-slot=input]]:w-full [&_[data-slot=textarea]]:w-full',
631
+ '[&_[data-slot=cascader-select-trigger]]:w-full [&_[data-slot=select-trigger]]:w-full [&_[data-slot=tree-select-trigger]]:w-full',
632
+ '[&_[data-slot=date-picker]]:w-full [&_[data-slot=date-range-picker]]:w-full [&_[data-slot=mentions]]:w-full [&_[data-slot=time-picker]]:w-full [&_[data-slot=time-range-picker]]:w-full',
633
633
  colClass,
634
634
  )}
635
635
  >