@teamix-evo/ui 0.2.0 → 0.3.0

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 (282) hide show
  1. package/README.md +184 -184
  2. package/manifest.json +680 -492
  3. package/package.json +15 -9
  4. package/src/components/accordion/accordion.meta.md +5 -9
  5. package/src/components/accordion/accordion.stories.tsx +3 -3
  6. package/src/components/accordion/accordion.tsx +104 -8
  7. package/src/components/affix/affix.meta.md +21 -12
  8. package/src/components/affix/affix.stories.tsx +101 -26
  9. package/src/components/affix/affix.tsx +79 -9
  10. package/src/components/alert/alert.meta.md +52 -26
  11. package/src/components/alert/alert.stories.tsx +66 -21
  12. package/src/components/alert/alert.tsx +81 -34
  13. package/src/components/alert-dialog/alert-dialog.meta.md +48 -16
  14. package/src/components/alert-dialog/alert-dialog.stories.tsx +145 -3
  15. package/src/components/alert-dialog/alert-dialog.tsx +60 -13
  16. package/src/components/anchor/anchor.meta.md +10 -14
  17. package/src/components/anchor/anchor.stories.tsx +3 -3
  18. package/src/components/anchor/anchor.tsx +2 -2
  19. package/src/components/app/app.meta.md +10 -14
  20. package/src/components/app/app.stories.tsx +6 -6
  21. package/src/components/aspect-ratio/aspect-ratio.meta.md +4 -8
  22. package/src/components/aspect-ratio/aspect-ratio.stories.tsx +3 -3
  23. package/src/components/auto-complete/auto-complete.meta.md +19 -20
  24. package/src/components/auto-complete/auto-complete.stories.tsx +44 -3
  25. package/src/components/auto-complete/auto-complete.tsx +119 -71
  26. package/src/components/avatar/avatar.meta.md +9 -22
  27. package/src/components/avatar/avatar.stories.tsx +21 -3
  28. package/src/components/avatar/avatar.tsx +24 -23
  29. package/src/components/badge/badge.meta.md +14 -18
  30. package/src/components/badge/badge.stories.tsx +2 -2
  31. package/src/components/badge/badge.tsx +2 -2
  32. package/src/components/breadcrumb/breadcrumb.meta.md +29 -20
  33. package/src/components/breadcrumb/breadcrumb.stories.tsx +120 -5
  34. package/src/components/breadcrumb/breadcrumb.tsx +22 -8
  35. package/src/components/button/button.meta.md +261 -29
  36. package/src/components/button/button.stories.tsx +549 -41
  37. package/src/components/button/button.tsx +335 -33
  38. package/src/components/calendar/calendar.meta.md +19 -14
  39. package/src/components/calendar/calendar.stories.tsx +5 -5
  40. package/src/components/calendar/calendar.tsx +73 -8
  41. package/src/components/card/card.meta.md +31 -34
  42. package/src/components/card/card.stories.tsx +34 -3
  43. package/src/components/card/card.tsx +146 -63
  44. package/src/components/carousel/carousel.meta.md +10 -14
  45. package/src/components/carousel/carousel.stories.tsx +1 -1
  46. package/src/components/cascader/cascader.meta.md +43 -22
  47. package/src/components/cascader/cascader.stories.tsx +13 -2
  48. package/src/components/cascader/cascader.tsx +427 -84
  49. package/src/components/checkbox/checkbox.meta.md +74 -24
  50. package/src/components/checkbox/checkbox.stories.tsx +160 -2
  51. package/src/components/checkbox/checkbox.tsx +77 -9
  52. package/src/components/collapsible/collapsible.meta.md +7 -6
  53. package/src/components/collapsible/collapsible.stories.tsx +2 -2
  54. package/src/components/collapsible/collapsible.tsx +93 -6
  55. package/src/components/color-picker/color-picker.meta.md +16 -20
  56. package/src/components/color-picker/color-picker.stories.tsx +86 -7
  57. package/src/components/color-picker/color-picker.tsx +19 -9
  58. package/src/components/command/command.meta.md +7 -11
  59. package/src/components/command/command.stories.tsx +4 -4
  60. package/src/components/command/command.tsx +18 -7
  61. package/src/components/context-menu/context-menu.meta.md +5 -25
  62. package/src/components/context-menu/context-menu.stories.tsx +4 -4
  63. package/src/components/context-menu/context-menu.tsx +21 -8
  64. package/src/components/data-table/data-table.meta.md +14 -18
  65. package/src/components/data-table/data-table.stories.tsx +1 -1
  66. package/src/components/data-table/data-table.tsx +2 -2
  67. package/src/components/date-picker/date-picker.meta.md +90 -41
  68. package/src/components/date-picker/date-picker.stories.tsx +55 -5
  69. package/src/components/date-picker/date-picker.tsx +1489 -91
  70. package/src/components/descriptions/descriptions.meta.md +12 -16
  71. package/src/components/descriptions/descriptions.stories.tsx +2 -2
  72. package/src/components/descriptions/descriptions.tsx +22 -14
  73. package/src/components/dialog/dialog.meta.md +67 -17
  74. package/src/components/dialog/dialog.stories.tsx +182 -20
  75. package/src/components/dialog/dialog.tsx +67 -15
  76. package/src/components/dialog/imperative.tsx +252 -0
  77. package/src/components/drawer/drawer.meta.md +27 -39
  78. package/src/components/drawer/drawer.stories.tsx +29 -12
  79. package/src/components/drawer/drawer.tsx +22 -114
  80. package/src/components/dropdown-menu/dropdown-menu.meta.md +64 -24
  81. package/src/components/dropdown-menu/dropdown-menu.stories.tsx +81 -3
  82. package/src/components/dropdown-menu/dropdown-menu.tsx +24 -10
  83. package/src/components/ellipsis/ellipsis.meta.md +87 -0
  84. package/src/components/ellipsis/ellipsis.stories.tsx +72 -0
  85. package/src/components/ellipsis/ellipsis.tsx +153 -0
  86. package/src/components/empty/empty.meta.md +10 -14
  87. package/src/components/empty/empty.stories.tsx +3 -3
  88. package/src/components/empty/empty.tsx +10 -3
  89. package/src/components/field/field.meta.md +46 -25
  90. package/src/components/field/field.stories.tsx +380 -3
  91. package/src/components/field/field.tsx +263 -35
  92. package/src/components/filter-bar/filter-bar.meta.md +92 -0
  93. package/src/components/filter-bar/filter-bar.stories.tsx +1083 -0
  94. package/src/components/filter-bar/filter-bar.tsx +568 -0
  95. package/src/components/flex/flex.meta.md +59 -20
  96. package/src/components/flex/flex.stories.tsx +65 -10
  97. package/src/components/flex/flex.tsx +27 -4
  98. package/src/components/float-button/float-button.meta.md +10 -29
  99. package/src/components/float-button/float-button.stories.tsx +6 -6
  100. package/src/components/form/form.meta.md +31 -52
  101. package/src/components/form/form.stories.tsx +350 -3
  102. package/src/components/form/form.tsx +101 -35
  103. package/src/components/grid/grid.meta.md +4 -24
  104. package/src/components/grid/grid.stories.tsx +2 -2
  105. package/src/components/hover-card/hover-card.meta.md +9 -10
  106. package/src/components/hover-card/hover-card.stories.tsx +29 -4
  107. package/src/components/hover-card/hover-card.tsx +51 -13
  108. package/src/components/icon/DEVELOPMENT.md +809 -0
  109. package/src/components/icon/icon.meta.md +170 -0
  110. package/src/components/icon/icon.stories.tsx +344 -0
  111. package/src/components/icon/icon.tsx +248 -0
  112. package/src/components/image/image.meta.md +14 -18
  113. package/src/components/image/image.stories.tsx +3 -3
  114. package/src/components/image/image.tsx +2 -0
  115. package/src/components/input/demo/sizes.tsx +2 -2
  116. package/src/components/input/input.meta.md +44 -43
  117. package/src/components/input/input.stories.tsx +62 -35
  118. package/src/components/input/input.tsx +96 -101
  119. package/src/components/input-group/input-group.meta.md +53 -39
  120. package/src/components/input-group/input-group.stories.tsx +49 -16
  121. package/src/components/input-group/input-group.tsx +43 -8
  122. package/src/components/input-number/input-number.meta.md +68 -20
  123. package/src/components/input-number/input-number.stories.tsx +33 -6
  124. package/src/components/input-number/input-number.tsx +79 -20
  125. package/src/components/input-otp/input-otp.meta.md +8 -20
  126. package/src/components/input-otp/input-otp.stories.tsx +3 -3
  127. package/src/components/input-otp/input-otp.tsx +1 -1
  128. package/src/components/item/item.meta.md +8 -26
  129. package/src/components/item/item.stories.tsx +3 -3
  130. package/src/components/item/item.tsx +7 -6
  131. package/src/components/kbd/kbd.meta.md +7 -19
  132. package/src/components/kbd/kbd.stories.tsx +4 -4
  133. package/src/components/kbd/kbd.tsx +8 -4
  134. package/src/components/label/label.meta.md +21 -18
  135. package/src/components/label/label.stories.tsx +64 -6
  136. package/src/components/label/label.tsx +91 -19
  137. package/src/components/masonry/masonry.meta.md +8 -12
  138. package/src/components/masonry/masonry.stories.tsx +4 -4
  139. package/src/components/mentions/mentions.meta.md +42 -21
  140. package/src/components/mentions/mentions.stories.tsx +120 -6
  141. package/src/components/mentions/mentions.tsx +10 -5
  142. package/src/components/menubar/menubar.meta.md +4 -8
  143. package/src/components/menubar/menubar.stories.tsx +55 -3
  144. package/src/components/menubar/menubar.tsx +9 -9
  145. package/src/components/native-select/native-select.meta.md +7 -11
  146. package/src/components/native-select/native-select.stories.tsx +4 -4
  147. package/src/components/native-select/native-select.tsx +1 -1
  148. package/src/components/navigation-menu/navigation-menu.meta.md +4 -8
  149. package/src/components/navigation-menu/navigation-menu.stories.tsx +106 -3
  150. package/src/components/navigation-menu/navigation-menu.tsx +6 -3
  151. package/src/components/notification/notification.meta.md +41 -8
  152. package/src/components/notification/notification.stories.tsx +9 -9
  153. package/src/components/notification/notification.tsx +34 -19
  154. package/src/components/page-header/DEVELOPMENT.md +842 -0
  155. package/src/components/page-header/page-header.meta.md +208 -0
  156. package/src/components/page-header/page-header.stories.tsx +421 -0
  157. package/src/components/page-header/page-header.tsx +281 -0
  158. package/src/components/pagination/pagination.meta.md +122 -50
  159. package/src/components/pagination/pagination.stories.tsx +227 -11
  160. package/src/components/pagination/pagination.tsx +355 -63
  161. package/src/components/popconfirm/popconfirm.meta.md +19 -23
  162. package/src/components/popconfirm/popconfirm.stories.tsx +2 -2
  163. package/src/components/popconfirm/popconfirm.tsx +1 -1
  164. package/src/components/popover/popover.meta.md +64 -12
  165. package/src/components/popover/popover.stories.tsx +83 -7
  166. package/src/components/popover/popover.tsx +77 -28
  167. package/src/components/progress/progress.meta.md +43 -26
  168. package/src/components/progress/progress.stories.tsx +2 -2
  169. package/src/components/progress/progress.tsx +19 -11
  170. package/src/components/radio-group/radio-group.meta.md +78 -11
  171. package/src/components/radio-group/radio-group.stories.tsx +38 -2
  172. package/src/components/radio-group/radio-group.tsx +149 -18
  173. package/src/components/rate/rate.meta.md +41 -19
  174. package/src/components/rate/rate.stories.tsx +2 -2
  175. package/src/components/rate/rate.tsx +37 -10
  176. package/src/components/resizable/resizable.meta.md +4 -12
  177. package/src/components/resizable/resizable.stories.tsx +5 -5
  178. package/src/components/resizable/resizable.tsx +1 -1
  179. package/src/components/result/result.meta.md +10 -14
  180. package/src/components/result/result.stories.tsx +2 -2
  181. package/src/components/result/result.tsx +21 -12
  182. package/src/components/scroll-area/scroll-area.meta.md +4 -8
  183. package/src/components/scroll-area/scroll-area.stories.tsx +5 -5
  184. package/src/components/segmented/segmented.meta.md +15 -17
  185. package/src/components/segmented/segmented.stories.tsx +3 -3
  186. package/src/components/segmented/segmented.tsx +15 -7
  187. package/src/components/select/select.meta.md +199 -67
  188. package/src/components/select/select.stories.tsx +238 -63
  189. package/src/components/select/select.tsx +718 -171
  190. package/src/components/separator/separator.meta.md +10 -14
  191. package/src/components/separator/separator.stories.tsx +2 -2
  192. package/src/components/separator/separator.tsx +3 -7
  193. package/src/components/sheet/sheet.meta.md +26 -21
  194. package/src/components/sheet/sheet.stories.tsx +116 -10
  195. package/src/components/sheet/sheet.tsx +116 -29
  196. package/src/components/sidebar/sidebar.meta.md +28 -38
  197. package/src/components/sidebar/sidebar.stories.tsx +696 -29
  198. package/src/components/sidebar/sidebar.tsx +615 -142
  199. package/src/components/skeleton/skeleton.meta.md +7 -31
  200. package/src/components/skeleton/skeleton.stories.tsx +3 -3
  201. package/src/components/skeleton/skeleton.tsx +7 -7
  202. package/src/components/slider/slider.meta.md +60 -13
  203. package/src/components/slider/slider.stories.tsx +58 -6
  204. package/src/components/slider/slider.tsx +154 -13
  205. package/src/components/sonner/sonner.meta.md +54 -8
  206. package/src/components/sonner/sonner.stories.tsx +79 -11
  207. package/src/components/sonner/sonner.tsx +137 -8
  208. package/src/components/spinner/spinner.meta.md +57 -21
  209. package/src/components/spinner/spinner.stories.tsx +66 -14
  210. package/src/components/spinner/spinner.tsx +111 -9
  211. package/src/components/statistic/statistic.meta.md +14 -30
  212. package/src/components/statistic/statistic.stories.tsx +1 -1
  213. package/src/components/statistic/statistic.tsx +4 -5
  214. package/src/components/steps/steps.meta.md +20 -15
  215. package/src/components/steps/steps.stories.tsx +37 -2
  216. package/src/components/steps/steps.tsx +15 -12
  217. package/src/components/switch/switch.meta.md +56 -15
  218. package/src/components/switch/switch.stories.tsx +5 -5
  219. package/src/components/switch/switch.tsx +59 -13
  220. package/src/components/table/table.meta.md +3 -7
  221. package/src/components/table/table.stories.tsx +1 -1
  222. package/src/components/table/table.tsx +4 -4
  223. package/src/components/tabs/tabs.meta.md +40 -32
  224. package/src/components/tabs/tabs.stories.tsx +104 -26
  225. package/src/components/tabs/tabs.tsx +125 -54
  226. package/src/components/tag/tag.meta.md +104 -68
  227. package/src/components/tag/tag.stories.tsx +183 -15
  228. package/src/components/tag/tag.tsx +222 -21
  229. package/src/components/textarea/textarea.meta.md +42 -31
  230. package/src/components/textarea/textarea.stories.tsx +32 -6
  231. package/src/components/textarea/textarea.tsx +32 -8
  232. package/src/components/time-picker/time-picker.meta.md +119 -50
  233. package/src/components/time-picker/time-picker.stories.tsx +65 -33
  234. package/src/components/time-picker/time-picker.tsx +889 -101
  235. package/src/components/timeline/timeline.meta.md +16 -17
  236. package/src/components/timeline/timeline.stories.tsx +24 -4
  237. package/src/components/timeline/timeline.tsx +32 -12
  238. package/src/components/toggle/toggle.meta.md +8 -12
  239. package/src/components/toggle/toggle.stories.tsx +4 -4
  240. package/src/components/toggle/toggle.tsx +4 -3
  241. package/src/components/toggle-group/toggle-group.meta.md +10 -14
  242. package/src/components/toggle-group/toggle-group.stories.tsx +3 -3
  243. package/src/components/toggle-group/toggle-group.tsx +2 -2
  244. package/src/components/tooltip/tooltip.meta.md +63 -18
  245. package/src/components/tooltip/tooltip.stories.tsx +42 -5
  246. package/src/components/tooltip/tooltip.tsx +81 -21
  247. package/src/components/tour/tour.meta.md +16 -20
  248. package/src/components/tour/tour.stories.tsx +3 -3
  249. package/src/components/tour/tour.tsx +3 -3
  250. package/src/components/transfer/transfer.meta.md +18 -22
  251. package/src/components/transfer/transfer.stories.tsx +2 -2
  252. package/src/components/transfer/transfer.tsx +28 -21
  253. package/src/components/tree/tree.meta.md +67 -22
  254. package/src/components/tree/tree.stories.tsx +1 -1
  255. package/src/components/tree/tree.tsx +9 -8
  256. package/src/components/tree-select/tree-select.meta.md +59 -23
  257. package/src/components/tree-select/tree-select.stories.tsx +2 -2
  258. package/src/components/tree-select/tree-select.tsx +42 -7
  259. package/src/components/typography/typography.meta.md +61 -39
  260. package/src/components/typography/typography.stories.tsx +14 -9
  261. package/src/components/typography/typography.tsx +38 -25
  262. package/src/components/upload/upload.meta.md +61 -25
  263. package/src/components/upload/upload.stories.tsx +69 -3
  264. package/src/components/upload/upload.tsx +170 -37
  265. package/src/components/watermark/watermark.meta.md +15 -19
  266. package/src/components/watermark/watermark.stories.tsx +98 -8
  267. package/src/hooks/use-breakpoint.ts +117 -0
  268. package/src/hooks/use-debounce-callback.ts +52 -0
  269. package/src/hooks/use-mobile.ts +23 -0
  270. package/src/stories/theme-tokens.stories.tsx +747 -0
  271. package/src/utils/trigger-input.ts +53 -0
  272. package/src/components/button-group/button-group.meta.md +0 -101
  273. package/src/components/button-group/button-group.stories.tsx +0 -93
  274. package/src/components/button-group/button-group.tsx +0 -75
  275. package/src/components/combobox/combobox.meta.md +0 -102
  276. package/src/components/combobox/combobox.stories.tsx +0 -55
  277. package/src/components/combobox/combobox.tsx +0 -130
  278. package/src/components/input/demo/addon.tsx +0 -15
  279. package/src/components/input/demo/with-prefix-suffix.tsx +0 -19
  280. package/src/components/space/space.meta.md +0 -103
  281. package/src/components/space/space.stories.tsx +0 -108
  282. package/src/components/space/space.tsx +0 -106
@@ -10,52 +10,54 @@ package: '@teamix-evo/ui'
10
10
 
11
11
  # Flex 弹性布局
12
12
 
13
- Flex 布局容器 — antd 独有补足。**等价 antd `Flex`**(v5.10+),把 Tailwind flex 的常用配置(对齐 / 间距 / 换行 / 方向 / 渲染元素)收敛为枚举,避免散落的 `flex flex-col items-start gap-4 ...` 反复手写。
13
+ Flex 布局容器 — antd 独有补足。**等价 antd `Flex`**(v5.10+) **antd `Space`**——一个原子覆盖 layout 类目两个原子场景:
14
+
15
+ - **完整布局容器**(页头 / 卡片体 / 整页): `<Flex as="header" justify="between" align="center" />`
16
+ - **inline 小集合**(按钮组 / tag 组 / 链接组,等价 antd `Space`): `<Flex inline gap="sm" align="center" />`
17
+ - **链接组带分隔**(等价 antd `Space.split`): `<Flex inline gap="sm" split={<Separator orientation="vertical" />} />`
14
18
 
15
19
  ## When to use
16
20
 
17
- - 完整页面 / 卡片 / Section 的容器布局
21
+ - 页面 / 卡片 / Section 的容器布局
18
22
  - 需要语义化 HTML 标签(`<header>` `<aside>` `<main>` `<nav>`)时用 `as`
23
+ - 按钮组 / tag 组 / 表单 label-value 对 / 列表行末操作链接组(原 Space 场景 — 加 `inline`)
19
24
  - 多次重复的相同对齐组合(可以靠 Flex 收敛模板)
20
25
 
21
26
  ## When NOT to use
22
27
 
23
- - 小集合 inline 间距 `Space`
24
- - 网格 → `Grid`(`Row + Col`)
28
+ - 网格列分配 `Grid`(`Row + Col`)
29
+ - 按钮粘连共享边线 → `ButtonGroup`
25
30
  - 仅一次性自由布局 → 直接写 className 也行,不强求
26
31
 
27
32
  ## Props
28
33
 
29
34
  <!-- auto:props:begin -->
30
-
31
- | 名称 | 类型 | 默认值 | 必填 | 说明 |
32
- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------- | ---- | ----------------------------------------------------------------------------------------------------- |
33
- | `direction` | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | `"row"` | – | 方向(antd `vertical` 并集) — `row`(默认)/ `column` 直观可读;antd `vertical` boolean 映射为 `column`。 |
34
- | `gap` | `'none' \| 'xs' \| 'sm' \| 'default' \| 'lg' \| 'xl'` | `"default"` | – | 子项之间的间距档位(走 design 间距刻度,不接受任意 number)。 |
35
- | `align` | `keyof typeof alignMap` | `"stretch"` | – | 副轴对齐方式。 |
36
- | `justify` | `keyof typeof justifyMap` | `"start"` | – | 主轴对齐方式。 |
37
- | `wrap` | `boolean` | `false` | – | 是否允许换行(antd `wrap` 并集) |
38
- | `inline` | `boolean` | `false` | – | inline-flex 而非 block-flex。 |
39
- | `as` | `keyof Pick< React.JSX.IntrinsicElements, 'div' \| 'section' \| 'header' \| 'footer' \| 'aside' \| 'main' \| 'nav' \| 'article' >` | `"div"` | | 渲染元素(antd `component` 并集) — 支持 `section / header / aside / main / nav` 等语义标签。 |
40
-
35
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
36
+ | --- | --- | --- | --- | --- |
37
+ | `direction` | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | `"row"` | | 方向(antd `vertical` 并集) — `row`(默认)/ `column` 直观可读;antd `vertical` boolean 映射为 `column`。 |
38
+ | `gap` | `'none' \| 'xs' \| 'sm' \| 'default' \| 'lg' \| 'xl'` | `"default"` | – | 子项之间的间距档位( design 间距刻度,不接受任意 number) |
39
+ | `align` | `keyof typeof alignMap` | `"stretch"` | – | 副轴对齐方式。 |
40
+ | `justify` | `keyof typeof justifyMap` | `"start"` | – | 主轴对齐方式。 |
41
+ | `wrap` | `boolean` | `false` | – | 是否允许换行(antd `wrap` 并集)。 |
42
+ | `inline` | `boolean` | `false` | – | inline-flex 而非 block-flex |
43
+ | `as` | `keyof Pick< React.JSX.IntrinsicElements, 'div' \| 'section' \| 'header' \| 'footer' \| 'aside' \| 'main' \| 'nav' \| 'article' >` | `"div"` | – | 渲染元素(antd `component` 并集) — 支持 `section / header / aside / main / nav` 等语义标签。 |
44
+ | `split` | `React.ReactNode` | | | 子项之间的分隔节点(antd `Space.split` 并集) — 常用 `<Separator orientation="vertical" />`、`'·'`、`'\|'`。 设置后会在每两个相邻子项之间插入该节点。 |
41
45
  <!-- auto:props:end -->
42
46
 
43
47
  ## 依赖
44
48
 
45
49
  <!-- auto:deps:begin -->
46
-
47
50
  ### 同库依赖
48
51
 
49
52
  > `teamix-evo ui add flex` 时,以下 entry 会被自动连带安装(无需手动 add)。
50
53
 
51
- | Entry | 类型 | 描述 |
52
- | ----- | ---- | -------------------------------------------------- |
53
- | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
54
+ | Entry | 类型 | 描述 |
55
+ | --- | --- | --- |
56
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
54
57
 
55
58
  ### npm 依赖
56
59
 
57
60
  _无 — 本组件不依赖任何 npm 包。_
58
-
59
61
  <!-- auto:deps:end -->
60
62
 
61
63
  ## AI 生成纪律
@@ -63,13 +65,37 @@ _无 — 本组件不依赖任何 npm 包。_
63
65
  - **`gap` 是档位枚举**(none / xs / sm / default / lg / xl),**不接受 number** — 走 design 间距刻度
64
66
  - **`direction="column"` 等价 antd `vertical`** — antd 的 `vertical={true}` 我们没沿用 boolean,直接走 direction 更直观
65
67
  - **`as` 仅限语义化标签集**(`section / header / aside / main / nav / footer / article / div`)— 不要传 `'span' / 'h1'` 等非 block 标签
68
+ - **`inline` 是原 Space 的入口** — 表达 inline 小集合请加 `inline gap="sm" align="center"`,不要再去找 `Space`(已与 Flex 合并)
69
+ - **`split` 应是无状态轻节点**(Separator / `|` / dot 字符),不要传 Button 等复杂组件,语义混乱
66
70
  - **不要嵌套 Flex 表达栅格** — 用 `Grid (Row/Col)`
67
71
  - **align/justify 默认值**:`align="stretch"`(子项填满高度)、`justify="start"`(主轴起始)— 大部分场景符合直觉
68
72
 
73
+ ## 从 antd `Space` 迁移
74
+
75
+ v0.x 起 `Space` 已合并进 `Flex`。迁移 mapping(IDE 全局替换可解):
76
+
77
+ ```tsx
78
+ // before
79
+ <Space size="sm" align="center">…</Space>
80
+ // after
81
+ <Flex inline gap="sm" align="center">…</Flex>
82
+
83
+ // before
84
+ <Space split={<Separator orientation="vertical" />} size="sm">…</Space>
85
+ // after
86
+ <Flex inline gap="sm" align="center" split={<Separator orientation="vertical" />}>…</Flex>
87
+
88
+ // before
89
+ <Space direction="vertical" align="start">…</Space>
90
+ // after
91
+ <Flex direction="column" gap="sm" align="start">…</Flex>
92
+ ```
93
+
69
94
  ## Examples
70
95
 
71
96
  ```tsx
72
97
  import { Flex } from '@/components/ui/flex';
98
+ import { Separator } from '@/components/ui/separator';
73
99
 
74
100
  // 居中对话框
75
101
  <Flex justify="center" align="center" className="min-h-screen">
@@ -96,6 +122,19 @@ import { Flex } from '@/components/ui/flex';
96
122
  <Button>提交</Button>
97
123
  </Flex>
98
124
 
125
+ // inline 小集合(原 Space 场景)
126
+ <Flex inline gap="sm" align="center">
127
+ <Button variant="outline">取消</Button>
128
+ <Button>确定</Button>
129
+ </Flex>
130
+
131
+ // 链接组 + split(原 Space.split 场景)
132
+ <Flex inline gap="sm" align="center" split={<Separator orientation="vertical" className="h-4" />}>
133
+ <a href="#">查看</a>
134
+ <a href="#">编辑</a>
135
+ <a href="#">删除</a>
136
+ </Flex>
137
+
99
138
  // 标签云
100
139
  <Flex wrap gap="sm">
101
140
  {tags.map((t) => <Tag key={t}>{t}</Tag>)}
@@ -1,16 +1,17 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import { Flex } from './flex';
3
3
  import { Button } from '@/components/button/button';
4
+ import { Separator } from '@/components/separator/separator';
4
5
 
5
6
  const meta: Meta<typeof Flex> = {
6
- title: '布局与容器 · Layout/Flex',
7
+ title: '布局 · Layout/Flex',
7
8
  component: Flex,
8
9
  tags: ['autodocs'],
9
10
  parameters: {
10
11
  docs: {
11
12
  description: {
12
13
  component:
13
- 'Flex 布局容器 Tailwind flex 的常用配置(对齐 / 间距 / 换行 / 方向 / 渲染元素)收敛为枚举。等价 antd `Flex`(v5.10+),与 Space 互补:Flex 偏完整布局容器,Space inline 小集合。',
14
+ 'Flex 弹性布局 —— 以架构者语言描述一维 / 二维的子项排列。**等价 antd `Flex`**(v5.10+) **∪ antd `Space`**——覆盖完整布局容器(页头 / 卡片 / 整页)与 inline 小集合(按钮组 / tag / 链接组)两类场景:`direction`(row/column/-reverse) / `gap`(none→xl 6 档走 design 间距刻度) / `align` / `justify` / `wrap` / `inline`(等价 antd `Space`) / `as`(语义标签 section/header/main…) / `split`(等价 antd `Space.split`,在相邻子项间插入分隔节点)。视觉走 OpenTrek semantic tokens,所有样式来自 `@teamix-evo/design`,无 mock。',
14
15
  },
15
16
  },
16
17
  },
@@ -48,14 +49,14 @@ export default meta;
48
49
  type Story = StoryObj<typeof Flex>;
49
50
 
50
51
  const swatch = (label: string) => (
51
- <div className="grid h-12 w-20 place-items-center rounded-md border bg-muted text-xs">
52
+ <div className="grid h-12 w-20 place-items-center rounded-md border border-border bg-muted text-xs">
52
53
  {label}
53
54
  </div>
54
55
  );
55
56
 
56
57
  export const Playground: Story = {
57
58
  render: (args) => (
58
- <Flex {...args} className="min-h-32 rounded-md border bg-card p-4">
59
+ <Flex {...args} className="min-h-32 rounded-md border border-border bg-card p-4">
59
60
  {swatch('A')}
60
61
  {swatch('B')}
61
62
  {swatch('C')}
@@ -70,7 +71,7 @@ export const Header: Story = {
70
71
  as="header"
71
72
  justify="between"
72
73
  align="center"
73
- className="rounded-md border bg-card px-6 py-3"
74
+ className="rounded-md border border-border bg-card px-6 py-3"
74
75
  >
75
76
  <span className="font-semibold">Logo</span>
76
77
  <Flex gap="sm">
@@ -95,7 +96,7 @@ export const ColumnStack: Story = {
95
96
  <Flex
96
97
  direction="column"
97
98
  gap="sm"
98
- className="w-80 rounded-md border bg-card p-6"
99
+ className="w-80 rounded-md border border-border bg-card p-6"
99
100
  >
100
101
  <span className="text-lg font-semibold">标题</span>
101
102
  <span className="text-sm text-muted-foreground">这是一段描述文字</span>
@@ -107,17 +108,71 @@ export const ColumnStack: Story = {
107
108
  export const Toolbar: Story = {
108
109
  parameters: { controls: { disable: true } },
109
110
  render: () => (
110
- <Flex justify="end" gap="sm" className="rounded-md border bg-card p-3">
111
+ <Flex justify="end" gap="sm" className="rounded-md border border-border bg-card p-3">
111
112
  <Button variant="outline">取消</Button>
112
113
  <Button>提交</Button>
113
114
  </Flex>
114
115
  ),
115
116
  };
116
117
 
118
+ /**
119
+ * inline 小集合——等价 antd `Space`。加 `inline` + 小 `gap` + `align="center"` 即可覆盖原 Space 场景。
120
+ */
121
+ export const InlineGroup: Story = {
122
+ parameters: { controls: { disable: true } },
123
+ render: () => (
124
+ <Flex inline gap="sm" align="center">
125
+ <Button variant="outline">取消</Button>
126
+ <Button>确定</Button>
127
+ <Button variant="ghost">更多</Button>
128
+ </Flex>
129
+ ),
130
+ };
131
+
132
+ /**
133
+ * 链接组带分隔——等价 antd `Space.split`。`split` 接受任意 ReactNode,常用 `<Separator orientation="vertical" />`。
134
+ */
135
+ export const WithSplit: Story = {
136
+ parameters: { controls: { disable: true } },
137
+ render: () => (
138
+ <Flex
139
+ inline
140
+ gap="sm"
141
+ align="center"
142
+ split={<Separator orientation="vertical" className="h-4" />}
143
+ >
144
+ <a href="#" className="text-sm text-primary hover:underline">
145
+ 查看
146
+ </a>
147
+ <a href="#" className="text-sm text-primary hover:underline">
148
+ 编辑
149
+ </a>
150
+ <a href="#" className="text-sm text-destructive hover:underline">
151
+ 删除
152
+ </a>
153
+ </Flex>
154
+ ),
155
+ };
156
+
157
+ /**
158
+ * 主轴分几——表单行 “总计 / 金额”。等价 antd `Space justify="between"`。
159
+ */
160
+ export const Between: Story = {
161
+ parameters: { controls: { disable: true } },
162
+ render: () => (
163
+ <div className="w-80 rounded-md border border-border p-3">
164
+ <Flex justify="between" align="center">
165
+ <span className="text-sm text-muted-foreground">总计</span>
166
+ <span className="text-lg font-semibold">¥ 1,299</span>
167
+ </Flex>
168
+ </div>
169
+ ),
170
+ };
171
+
117
172
  export const WrapCloud: Story = {
118
173
  parameters: { controls: { disable: true } },
119
174
  render: () => (
120
- <Flex wrap gap="sm" className="w-96 rounded-md border bg-card p-3">
175
+ <Flex wrap gap="sm" className="w-96 rounded-md border border-border bg-card p-3">
121
176
  {[
122
177
  'React',
123
178
  'Vue',
@@ -134,7 +189,7 @@ export const WrapCloud: Story = {
134
189
  ].map((t) => (
135
190
  <span
136
191
  key={t}
137
- className="rounded-md border bg-muted px-2 py-0.5 text-xs"
192
+ className="rounded-md border border-border bg-muted px-2 py-0.5 text-xs"
138
193
  >
139
194
  {t}
140
195
  </span>
@@ -67,13 +67,21 @@ export interface FlexProps extends React.HTMLAttributes<HTMLDivElement> {
67
67
  React.JSX.IntrinsicElements,
68
68
  'div' | 'section' | 'header' | 'footer' | 'aside' | 'main' | 'nav' | 'article'
69
69
  >;
70
+ /**
71
+ * 子项之间的分隔节点(antd `Space.split` 并集) — 常用 `<Separator orientation="vertical" />`、`'·'`、`'|'`。
72
+ * 设置后会在每两个相邻子项之间插入该节点。
73
+ */
74
+ split?: React.ReactNode;
70
75
  }
71
76
 
72
77
  /**
73
- * Flex 布局容器 — antd 独有补足。**等价 antd `Flex`**(v5.10+),提供 Tailwind flex 的语义封装,
74
- * 把常用对齐 / 间距 / 换行 / 方向 / 渲染元素收敛为枚举,避免散落的 className 反复手写。
78
+ * Flex 布局容器 — antd 独有补足。**等价 antd `Flex`**(v5.10+) **antd `Space`**(`split`)。
79
+ * Tailwind flex 的常用对齐 / 间距 / 换行 / 方向 / 渲染元素 / 分隔节点收敛为枚举,避免散落的 className 反复手写。
75
80
  *
76
- * 与 `Space` 区别:Flex 偏向**完整布局容器**(页头、卡片体、整页),Space 偏向 inline 小集合。
81
+ * 用法约定:
82
+ * - 完整布局容器(页头、卡片体、整页): `<Flex as="header" justify="between" align="center" />`
83
+ * - inline 小集合(按钮组、tag 组、链接组): `<Flex inline gap="sm" align="center" />`(等价 antd `Space`)
84
+ * - 链接组带分隔: `<Flex inline gap="sm" split={<Separator orientation="vertical" />} />`
77
85
  */
78
86
  const Flex = React.forwardRef<HTMLDivElement, FlexProps>(
79
87
  (
@@ -85,7 +93,9 @@ const Flex = React.forwardRef<HTMLDivElement, FlexProps>(
85
93
  wrap = false,
86
94
  inline = false,
87
95
  as = 'div',
96
+ split,
88
97
  className,
98
+ children,
89
99
  ...props
90
100
  },
91
101
  ref,
@@ -100,6 +110,17 @@ const Flex = React.forwardRef<HTMLDivElement, FlexProps>(
100
110
  ? 'flex-row-reverse'
101
111
  : 'flex-col-reverse';
102
112
 
113
+ const content = split
114
+ ? React.Children.toArray(children)
115
+ .filter(Boolean)
116
+ .map((child, i) => (
117
+ <React.Fragment key={i}>
118
+ {i > 0 ? split : null}
119
+ {child}
120
+ </React.Fragment>
121
+ ))
122
+ : children;
123
+
103
124
  return (
104
125
  <Tag
105
126
  ref={ref}
@@ -113,7 +134,9 @@ const Flex = React.forwardRef<HTMLDivElement, FlexProps>(
113
134
  className,
114
135
  )}
115
136
  {...props}
116
- />
137
+ >
138
+ {content}
139
+ </Tag>
117
140
  );
118
141
  },
119
142
  );
@@ -2,7 +2,7 @@
2
2
  id: float-button
3
3
  name: FloatButton
4
4
  type: component
5
- category: navigation
5
+ category: deprecated
6
6
  since: 0.1.0
7
7
  package: '@teamix-evo/ui'
8
8
  displayName: 悬浮按钮
@@ -28,42 +28,24 @@ displayName: 悬浮按钮
28
28
  ## Props
29
29
 
30
30
  <!-- auto:props:begin -->
31
-
32
- #### FloatButton
33
-
34
- | 名称 | 类型 | 默认值 | 必填 | 说明 |
35
- | --------- | ------------------------ | ----------- | ---- | -------------------------------------------------- |
36
- | `icon` | `React.ReactNode` | – | – | 图标(antd `icon` 并集)|
37
- | `variant` | `'primary' \| 'default'` | `"primary"` | – | 视觉风格 — `primary` 主色填充;`default` 灰色轮廓。 |
38
- | `shape` | `'circle' \| 'square'` | `"circle"` | – | 形状 — `circle`(默认)圆形;`square` 方形圆角。 |
39
- | `badge` | `React.ReactNode` | – | – | 触发徽标(antd `badge` 并集) — 简短数字 / 字符。 |
40
-
41
- #### FloatButtonGroup
42
-
43
- | 名称 | 类型 | 默认值 | 必填 | 说明 |
44
- | -------- | -------- | ------ | ---- | -------------------- |
45
- | `right` | `number` | `24` | – | 距视口右侧距离(px)。 |
46
- | `bottom` | `number` | `24` | – | 距视口底部距离(px)。 |
47
-
48
- #### FloatButtonBackTop
49
-
50
- | 名称 | 类型 | 默认值 | 必填 | 说明 |
51
- | ------------------ | -------- | ------ | ---- | -------------------------------------- |
52
- | `visibilityHeight` | `number` | `200` | – | 滚动距离超过此值(px)时才显示回到顶部。 |
53
-
31
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
32
+ | --- | --- | --- | --- | --- |
33
+ | `icon` | `React.ReactNode` | – | – | 图标(antd `icon` 并集)。 |
34
+ | `variant` | `'primary' \| 'default'` | `"primary"` | | 视觉风格 — `primary` 主色填充;`default` 灰色轮廓。 |
35
+ | `shape` | `'circle' \| 'square'` | `"circle"` | | 形状 — `circle`(默认)圆形;`square` 方形圆角。 |
36
+ | `badge` | `React.ReactNode` | – | – | 触发徽标(antd `badge` 并集) — 简短数字 / 字符。 |
54
37
  <!-- auto:props:end -->
55
38
 
56
39
  ## 依赖
57
40
 
58
41
  <!-- auto:deps:begin -->
59
-
60
42
  ### 同库依赖
61
43
 
62
44
  > `teamix-evo ui add float-button` 时,以下 entry 会被自动连带安装(无需手动 add)。
63
45
 
64
- | Entry | 类型 | 描述 |
65
- | ----- | ---- | -------------------------------------------------- |
66
- | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
46
+ | Entry | 类型 | 描述 |
47
+ | --- | --- | --- |
48
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
67
49
 
68
50
  ### npm 依赖
69
51
 
@@ -72,7 +54,6 @@ displayName: 悬浮按钮
72
54
  ```bash
73
55
  pnpm add lucide-react@^0.460.0
74
56
  ```
75
-
76
57
  <!-- auto:deps:end -->
77
58
 
78
59
  ## AI 生成纪律
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import { MessageCircle, Plus } from 'lucide-react';
3
3
  import {
4
4
  FloatButton,
@@ -7,14 +7,14 @@ import {
7
7
  } from './float-button';
8
8
 
9
9
  const meta: Meta<typeof FloatButton> = {
10
- title: '导航 · Navigation/FloatButton',
10
+ title: '废弃 · Deprecated/FloatButton',
11
11
  component: FloatButton,
12
12
  tags: ['autodocs'],
13
13
  parameters: {
14
14
  docs: {
15
15
  description: {
16
16
  component:
17
- '悬浮按钮 — position: fixed 在右下角的强主张操作按钮(回到顶部 / 客服 / 新建)。配 FloatButtonGroup 堆叠多个,FloatButtonBackTop 是预置的“回到顶部”。等价 antd `FloatButton`(v5.0,替代旧 BackTop)。',
17
+ '⚠️ **已废弃** — 仅 Storybook 留档,不通过 manifest 对外发布。\n\n悬浮按钮 — position: fixed 在右下角的强主张操作按钮(回到顶部 / 客服 / 新建)。配 FloatButtonGroup 堆叠多个,FloatButtonBackTop 是预置的“回到顶部”。等价 antd `FloatButton`(v5.0,替代旧 BackTop)。',
18
18
  },
19
19
  },
20
20
  },
@@ -26,7 +26,7 @@ type Story = StoryObj<typeof FloatButton>;
26
26
  export const Playground: Story = {
27
27
  parameters: { controls: { disable: true } },
28
28
  render: () => (
29
- <div className="relative h-72 overflow-hidden rounded-md border">
29
+ <div className="relative h-72 overflow-hidden rounded-md border border-border">
30
30
  <div className="p-4 text-sm text-muted-foreground">
31
31
  ← 右下角是 FloatButton 演示
32
32
  </div>
@@ -40,7 +40,7 @@ export const Playground: Story = {
40
40
  export const Group: Story = {
41
41
  parameters: { controls: { disable: true } },
42
42
  render: () => (
43
- <div className="relative h-96 overflow-hidden rounded-md border">
43
+ <div className="relative h-96 overflow-hidden rounded-md border border-border">
44
44
  <div className="p-4 text-sm text-muted-foreground">右下角浮动按钮组</div>
45
45
  <div className="absolute bottom-6 right-6 flex flex-col items-end gap-3">
46
46
  <FloatButton
@@ -67,7 +67,7 @@ export const BackTopReal: Story = {
67
67
  </div>
68
68
  <div className="mt-3 space-y-3">
69
69
  {Array.from({ length: 30 }).map((_, i) => (
70
- <div key={i} className="rounded-md border bg-muted/30 p-6">
70
+ <div key={i} className="rounded-md border border-border bg-muted/30 p-6">
71
71
  占位段落 {i + 1}
72
72
  </div>
73
73
  ))}
@@ -3,7 +3,7 @@ id: form
3
3
  name: Form
4
4
  displayName: 表单
5
5
  type: component
6
- category: form
6
+ category: data-entry
7
7
  since: 0.1.0
8
8
  package: '@teamix-evo/ui'
9
9
  ---
@@ -30,43 +30,9 @@ package: '@teamix-evo/ui'
30
30
  > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成。`Form` 是 `FormProvider` 别名,直接接受 `useForm()` 返回值;下表按子组件分节列出各自的 Props。
31
31
 
32
32
  <!-- auto:props:begin -->
33
-
34
- #### Form
35
-
36
- | 名称 | 类型 | 默认值 | 必填 | 说明 |
37
- | ---------- | ----------------- | ------ | ---- | ------------------------------------------------- |
38
- | `children` | `React.ReactNode` | – | – | 表单内容 — 通常是 `<form>` + `<FormField>` 列表。 |
39
-
40
- > `Form` 透传 `useForm()` 返回值的所有属性(`UseFormReturn`),作为 `FormProvider` 下发给子组件。
41
-
42
- #### FormField
43
-
44
- | 名称 | 类型 | 默认值 | 必填 | 说明 |
45
- | --------- | ---------------------------------------------------------- | ------ | ---- | ------------------------------------------- |
46
- | `name` | `FieldPath<TFieldValues>` | – | ✔ | 字段名称,对应 schema 中的 key。 |
47
- | `control` | `Control<TFieldValues>` | – | ✔ | `useForm()` 返回的 `control` 实例。 |
48
- | `render` | `({ field, fieldState, formState }) => React.ReactElement` | – | ✔ | 渲染函数,接收 field/fieldState 注入到控件。 |
49
-
50
- #### FormItem
51
-
52
- > 单个表单字段容器,生成稳定 id 供 Label/Description/Message 关联。无自定义 props,仅透传 `HTMLDivElement` 属性。
53
-
54
- #### FormLabel
55
-
56
- > 扩展自 `Label` 组件,自动通过 `useFormField()` 关联 `htmlFor`,校验失败时自动变红。支持 `Label` 的所有 props(`required` / `disabled`)。
57
-
58
- #### FormControl
59
-
60
- > Slot 包装器,自动注入 `id` / `aria-describedby` / `aria-invalid` 到子控件。无自定义 props。
61
-
62
- #### FormDescription
63
-
64
- > 辅助说明文本(`text-xs text-muted-foreground`)。无自定义 props,仅透传 `HTMLParagraphElement` 属性。
65
-
66
- #### FormMessage
67
-
68
- > 错误消息显示,自动从 `fieldState.error` 读取。无自定义 props,仅透传 `HTMLParagraphElement` 属性。
69
-
33
+ | 名称 | 类型 | 默认值 | 必填 | 说明 |
34
+ | --- | --- | --- | --- | --- |
35
+ | `children` | `React.ReactNode` | – | – | 表单内容 — 通常是 `<form>` + `<FormField>` 列表。 |
70
36
  <!-- auto:props:end -->
71
37
 
72
38
  ## 依赖
@@ -74,35 +40,48 @@ package: '@teamix-evo/ui'
74
40
  > 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
75
41
 
76
42
  <!-- auto:deps:begin -->
77
-
78
43
  ### 同库依赖
79
44
 
80
45
  > `teamix-evo ui add form` 时,以下 entry 会被自动连带安装(无需手动 add)。
81
46
 
82
- | Entry | 类型 | 描述 |
83
- | ------- | --------- | ------------------------------------------------------------------------------------- |
84
- | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
85
- | `label` | component | 表单字段标签Radix Label 包装,补 antd Form.Item 风格的 required / disabled 显式视觉 |
47
+ | Entry | 类型 | 描述 |
48
+ | --- | --- | --- |
49
+ | `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
50
+ | `field` | component | 通用表单字段抽象shadcn 2025-10 新增。Field / FieldLabel / FieldDescription / FieldError / FieldGroup / FieldSet / FieldLegend 7 个语义槽,跟任何状态管理(Server Actions / RHF / TanStack Form)都能搭,与 form 共存 |
86
51
 
87
52
  ### npm 依赖
88
53
 
89
54
  > 业务侧需要先 `pnpm add` / `npm install` 这些包。CLI 在 `ui add` 完成后会列出此提示。
90
55
 
91
56
  ```bash
92
- pnpm add react-hook-form@^7.50.0 @hookform/resolvers@^3.0.0 zod@^3.22.0 @radix-ui/react-label@^2.1.0 @radix-ui/react-slot@^1.1.0
57
+ pnpm add react-hook-form@^7.50.0 @hookform/resolvers@^3.0.0 zod@^3.22.0 @radix-ui/react-slot@^1.1.0
93
58
  ```
94
-
95
59
  <!-- auto:deps:end -->
96
60
 
61
+ ## 子组件
62
+
63
+ 除 shadcn 7 件套(`Form / FormField / FormItem / FormLabel / FormControl / FormDescription / FormMessage`)外,本包补两个表单骨架子组件:
64
+
65
+ - **`FormSection`**:表单分组容器,支持 `title`(组标题,14px medium)和 `columns`(`1 \| 2 \| 3 \| 4` 多栏 grid)。代替手写 h3 + Row/Col。
66
+ - **`FormActions`**:表单操作按钮容器,支持 `position`(`'inline'` / `'sticky'`)、`align`(`'start'` / `'end'`)和 `alignWithInput`(与输入域基线对齐,避免按钮与 label 列重叠)。
67
+
68
+ > **实现共享**:`FormSection` / `FormActions` 是 Field 包同名组件的 re-export 别名(一处实现,规范变更只改一处)。Props 与行为完全等同 `FieldSection` / `FieldActions`,详见 [`field.meta.md`](../field/field.meta.md)。
69
+
97
70
  ## AI 生成纪律
98
71
 
99
- - **`Form` 必包 `useForm()`**:`<Form {...form}>...</Form>`,把整个 form instance 散开传入(FormProvider 期望)
100
- - **每个字段必有 `<FormField name="..." control={form.control} render={({ field }) => <FormItem>...</FormItem>} />`**:不要直接渲染 input 不走 Field,会失去校验关联
101
- - **`<FormControl>` 只放真正的输入控件**:input / textarea / Select / Checkbox 等;Slot 模式自动注入 id / aria-describedby / aria-invalid
102
- - **错误消息走 `<FormMessage />`**:不要手写 `{errors.x?.message}` — FormMessage 自动连接 fieldState
103
- - **schema 优先**:用 zod schema `useForm({ resolver: zodResolver(schema) })`;校验逻辑集中在 schema,不要散在 input 上
104
- - **提交后保留状态**:`form.reset()` 重置;**不要**手动清空每个字段
105
- - **不要嵌套 Form**:嵌套会破坏 React Context
72
+ - **`Form` 必包 `useForm()`**:`<Form {...form}>...</Form>`,把整个 form instance 散开传入(FormProvider 期望)
73
+ - **每个字段必有 `<FormField name="..." control={form.control} render={({ field }) => <FormItem>...</FormItem>} />`**:不要直接渲染 input 不走 Field,会失去校验关联
74
+ - **`<FormControl>` 只放真正的输入控件**:input / textarea / Select / Checkbox 等;Slot 模式自动注入 id / aria-describedby / aria-invalid
75
+ - **错误消息走 `<FormMessage />`**:不要手写 `{errors.x?.message}` — FormMessage 自动连接 fieldState
76
+ - **必填标记 `*` 总是后置**:`<FormLabel required>` 由底层 `Label` 组件在文字与 tooltip icon **后**渲染红色 `*`(顺序为 `文字 ⓘ *`),对齐设计规范;不要手写 `<FormLabel>邮箱 *</FormLabel>` 或 `<FormLabel>* 邮箱</FormLabel>`。同时记得在 schema `z.string().min(1)` 或控件上 `aria-required="true"`。
77
+ - **schema 优先**:用 zod 写 schema → `useForm({ resolver: zodResolver(schema) })`;校验逻辑集中在 schema,不要散在 input 上
78
+ - **提交后保留状态**:`form.reset()` 重置;**不要**手动清空每个字段
79
+ - **不要嵌套 Form**:嵌套会破坏 React Context
80
+ - ✅ 复杂表单必须用 `FormSection` 分组(组标题用 `title` prop,不要手写 `<h3>`)
81
+ - ✅ 多栏布局用 `FormSection columns={N}`(不要手写 `Row`/`Col` 或 `grid grid-cols-N`)
82
+ - ✅ 表单提交 / 取消按钮必须用 `FormActions`
83
+ - ✅ 多个 `FormSection` 的父容器必须用 `gap-8`(32px 组间距)
84
+ - ✅ 错误信息(`FormMessage`)紧贴 input,不要额外加 `mt-*` 或包裹 `<div>`
106
85
 
107
86
  ## Examples
108
87