@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.
- package/README.md +184 -184
- package/manifest.json +680 -492
- package/package.json +15 -9
- package/src/components/accordion/accordion.meta.md +5 -9
- package/src/components/accordion/accordion.stories.tsx +3 -3
- package/src/components/accordion/accordion.tsx +104 -8
- package/src/components/affix/affix.meta.md +21 -12
- package/src/components/affix/affix.stories.tsx +101 -26
- package/src/components/affix/affix.tsx +79 -9
- package/src/components/alert/alert.meta.md +52 -26
- package/src/components/alert/alert.stories.tsx +66 -21
- package/src/components/alert/alert.tsx +81 -34
- package/src/components/alert-dialog/alert-dialog.meta.md +48 -16
- package/src/components/alert-dialog/alert-dialog.stories.tsx +145 -3
- package/src/components/alert-dialog/alert-dialog.tsx +60 -13
- package/src/components/anchor/anchor.meta.md +10 -14
- package/src/components/anchor/anchor.stories.tsx +3 -3
- package/src/components/anchor/anchor.tsx +2 -2
- package/src/components/app/app.meta.md +10 -14
- package/src/components/app/app.stories.tsx +6 -6
- package/src/components/aspect-ratio/aspect-ratio.meta.md +4 -8
- package/src/components/aspect-ratio/aspect-ratio.stories.tsx +3 -3
- package/src/components/auto-complete/auto-complete.meta.md +19 -20
- package/src/components/auto-complete/auto-complete.stories.tsx +44 -3
- package/src/components/auto-complete/auto-complete.tsx +119 -71
- package/src/components/avatar/avatar.meta.md +9 -22
- package/src/components/avatar/avatar.stories.tsx +21 -3
- package/src/components/avatar/avatar.tsx +24 -23
- package/src/components/badge/badge.meta.md +14 -18
- package/src/components/badge/badge.stories.tsx +2 -2
- package/src/components/badge/badge.tsx +2 -2
- package/src/components/breadcrumb/breadcrumb.meta.md +29 -20
- package/src/components/breadcrumb/breadcrumb.stories.tsx +120 -5
- package/src/components/breadcrumb/breadcrumb.tsx +22 -8
- package/src/components/button/button.meta.md +261 -29
- package/src/components/button/button.stories.tsx +549 -41
- package/src/components/button/button.tsx +335 -33
- package/src/components/calendar/calendar.meta.md +19 -14
- package/src/components/calendar/calendar.stories.tsx +5 -5
- package/src/components/calendar/calendar.tsx +73 -8
- package/src/components/card/card.meta.md +31 -34
- package/src/components/card/card.stories.tsx +34 -3
- package/src/components/card/card.tsx +146 -63
- package/src/components/carousel/carousel.meta.md +10 -14
- package/src/components/carousel/carousel.stories.tsx +1 -1
- package/src/components/cascader/cascader.meta.md +43 -22
- package/src/components/cascader/cascader.stories.tsx +13 -2
- package/src/components/cascader/cascader.tsx +427 -84
- package/src/components/checkbox/checkbox.meta.md +74 -24
- package/src/components/checkbox/checkbox.stories.tsx +160 -2
- package/src/components/checkbox/checkbox.tsx +77 -9
- package/src/components/collapsible/collapsible.meta.md +7 -6
- package/src/components/collapsible/collapsible.stories.tsx +2 -2
- package/src/components/collapsible/collapsible.tsx +93 -6
- package/src/components/color-picker/color-picker.meta.md +16 -20
- package/src/components/color-picker/color-picker.stories.tsx +86 -7
- package/src/components/color-picker/color-picker.tsx +19 -9
- package/src/components/command/command.meta.md +7 -11
- package/src/components/command/command.stories.tsx +4 -4
- package/src/components/command/command.tsx +18 -7
- package/src/components/context-menu/context-menu.meta.md +5 -25
- package/src/components/context-menu/context-menu.stories.tsx +4 -4
- package/src/components/context-menu/context-menu.tsx +21 -8
- package/src/components/data-table/data-table.meta.md +14 -18
- package/src/components/data-table/data-table.stories.tsx +1 -1
- package/src/components/data-table/data-table.tsx +2 -2
- package/src/components/date-picker/date-picker.meta.md +90 -41
- package/src/components/date-picker/date-picker.stories.tsx +55 -5
- package/src/components/date-picker/date-picker.tsx +1489 -91
- package/src/components/descriptions/descriptions.meta.md +12 -16
- package/src/components/descriptions/descriptions.stories.tsx +2 -2
- package/src/components/descriptions/descriptions.tsx +22 -14
- package/src/components/dialog/dialog.meta.md +67 -17
- package/src/components/dialog/dialog.stories.tsx +182 -20
- package/src/components/dialog/dialog.tsx +67 -15
- package/src/components/dialog/imperative.tsx +252 -0
- package/src/components/drawer/drawer.meta.md +27 -39
- package/src/components/drawer/drawer.stories.tsx +29 -12
- package/src/components/drawer/drawer.tsx +22 -114
- package/src/components/dropdown-menu/dropdown-menu.meta.md +64 -24
- package/src/components/dropdown-menu/dropdown-menu.stories.tsx +81 -3
- package/src/components/dropdown-menu/dropdown-menu.tsx +24 -10
- package/src/components/ellipsis/ellipsis.meta.md +87 -0
- package/src/components/ellipsis/ellipsis.stories.tsx +72 -0
- package/src/components/ellipsis/ellipsis.tsx +153 -0
- package/src/components/empty/empty.meta.md +10 -14
- package/src/components/empty/empty.stories.tsx +3 -3
- package/src/components/empty/empty.tsx +10 -3
- package/src/components/field/field.meta.md +46 -25
- package/src/components/field/field.stories.tsx +380 -3
- package/src/components/field/field.tsx +263 -35
- package/src/components/filter-bar/filter-bar.meta.md +92 -0
- package/src/components/filter-bar/filter-bar.stories.tsx +1083 -0
- package/src/components/filter-bar/filter-bar.tsx +568 -0
- package/src/components/flex/flex.meta.md +59 -20
- package/src/components/flex/flex.stories.tsx +65 -10
- package/src/components/flex/flex.tsx +27 -4
- package/src/components/float-button/float-button.meta.md +10 -29
- package/src/components/float-button/float-button.stories.tsx +6 -6
- package/src/components/form/form.meta.md +31 -52
- package/src/components/form/form.stories.tsx +350 -3
- package/src/components/form/form.tsx +101 -35
- package/src/components/grid/grid.meta.md +4 -24
- package/src/components/grid/grid.stories.tsx +2 -2
- package/src/components/hover-card/hover-card.meta.md +9 -10
- package/src/components/hover-card/hover-card.stories.tsx +29 -4
- package/src/components/hover-card/hover-card.tsx +51 -13
- package/src/components/icon/DEVELOPMENT.md +809 -0
- package/src/components/icon/icon.meta.md +170 -0
- package/src/components/icon/icon.stories.tsx +344 -0
- package/src/components/icon/icon.tsx +248 -0
- package/src/components/image/image.meta.md +14 -18
- package/src/components/image/image.stories.tsx +3 -3
- package/src/components/image/image.tsx +2 -0
- package/src/components/input/demo/sizes.tsx +2 -2
- package/src/components/input/input.meta.md +44 -43
- package/src/components/input/input.stories.tsx +62 -35
- package/src/components/input/input.tsx +96 -101
- package/src/components/input-group/input-group.meta.md +53 -39
- package/src/components/input-group/input-group.stories.tsx +49 -16
- package/src/components/input-group/input-group.tsx +43 -8
- package/src/components/input-number/input-number.meta.md +68 -20
- package/src/components/input-number/input-number.stories.tsx +33 -6
- package/src/components/input-number/input-number.tsx +79 -20
- package/src/components/input-otp/input-otp.meta.md +8 -20
- package/src/components/input-otp/input-otp.stories.tsx +3 -3
- package/src/components/input-otp/input-otp.tsx +1 -1
- package/src/components/item/item.meta.md +8 -26
- package/src/components/item/item.stories.tsx +3 -3
- package/src/components/item/item.tsx +7 -6
- package/src/components/kbd/kbd.meta.md +7 -19
- package/src/components/kbd/kbd.stories.tsx +4 -4
- package/src/components/kbd/kbd.tsx +8 -4
- package/src/components/label/label.meta.md +21 -18
- package/src/components/label/label.stories.tsx +64 -6
- package/src/components/label/label.tsx +91 -19
- package/src/components/masonry/masonry.meta.md +8 -12
- package/src/components/masonry/masonry.stories.tsx +4 -4
- package/src/components/mentions/mentions.meta.md +42 -21
- package/src/components/mentions/mentions.stories.tsx +120 -6
- package/src/components/mentions/mentions.tsx +10 -5
- package/src/components/menubar/menubar.meta.md +4 -8
- package/src/components/menubar/menubar.stories.tsx +55 -3
- package/src/components/menubar/menubar.tsx +9 -9
- package/src/components/native-select/native-select.meta.md +7 -11
- package/src/components/native-select/native-select.stories.tsx +4 -4
- package/src/components/native-select/native-select.tsx +1 -1
- package/src/components/navigation-menu/navigation-menu.meta.md +4 -8
- package/src/components/navigation-menu/navigation-menu.stories.tsx +106 -3
- package/src/components/navigation-menu/navigation-menu.tsx +6 -3
- package/src/components/notification/notification.meta.md +41 -8
- package/src/components/notification/notification.stories.tsx +9 -9
- package/src/components/notification/notification.tsx +34 -19
- package/src/components/page-header/DEVELOPMENT.md +842 -0
- package/src/components/page-header/page-header.meta.md +208 -0
- package/src/components/page-header/page-header.stories.tsx +421 -0
- package/src/components/page-header/page-header.tsx +281 -0
- package/src/components/pagination/pagination.meta.md +122 -50
- package/src/components/pagination/pagination.stories.tsx +227 -11
- package/src/components/pagination/pagination.tsx +355 -63
- package/src/components/popconfirm/popconfirm.meta.md +19 -23
- package/src/components/popconfirm/popconfirm.stories.tsx +2 -2
- package/src/components/popconfirm/popconfirm.tsx +1 -1
- package/src/components/popover/popover.meta.md +64 -12
- package/src/components/popover/popover.stories.tsx +83 -7
- package/src/components/popover/popover.tsx +77 -28
- package/src/components/progress/progress.meta.md +43 -26
- package/src/components/progress/progress.stories.tsx +2 -2
- package/src/components/progress/progress.tsx +19 -11
- package/src/components/radio-group/radio-group.meta.md +78 -11
- package/src/components/radio-group/radio-group.stories.tsx +38 -2
- package/src/components/radio-group/radio-group.tsx +149 -18
- package/src/components/rate/rate.meta.md +41 -19
- package/src/components/rate/rate.stories.tsx +2 -2
- package/src/components/rate/rate.tsx +37 -10
- package/src/components/resizable/resizable.meta.md +4 -12
- package/src/components/resizable/resizable.stories.tsx +5 -5
- package/src/components/resizable/resizable.tsx +1 -1
- package/src/components/result/result.meta.md +10 -14
- package/src/components/result/result.stories.tsx +2 -2
- package/src/components/result/result.tsx +21 -12
- package/src/components/scroll-area/scroll-area.meta.md +4 -8
- package/src/components/scroll-area/scroll-area.stories.tsx +5 -5
- package/src/components/segmented/segmented.meta.md +15 -17
- package/src/components/segmented/segmented.stories.tsx +3 -3
- package/src/components/segmented/segmented.tsx +15 -7
- package/src/components/select/select.meta.md +199 -67
- package/src/components/select/select.stories.tsx +238 -63
- package/src/components/select/select.tsx +718 -171
- package/src/components/separator/separator.meta.md +10 -14
- package/src/components/separator/separator.stories.tsx +2 -2
- package/src/components/separator/separator.tsx +3 -7
- package/src/components/sheet/sheet.meta.md +26 -21
- package/src/components/sheet/sheet.stories.tsx +116 -10
- package/src/components/sheet/sheet.tsx +116 -29
- package/src/components/sidebar/sidebar.meta.md +28 -38
- package/src/components/sidebar/sidebar.stories.tsx +696 -29
- package/src/components/sidebar/sidebar.tsx +615 -142
- package/src/components/skeleton/skeleton.meta.md +7 -31
- package/src/components/skeleton/skeleton.stories.tsx +3 -3
- package/src/components/skeleton/skeleton.tsx +7 -7
- package/src/components/slider/slider.meta.md +60 -13
- package/src/components/slider/slider.stories.tsx +58 -6
- package/src/components/slider/slider.tsx +154 -13
- package/src/components/sonner/sonner.meta.md +54 -8
- package/src/components/sonner/sonner.stories.tsx +79 -11
- package/src/components/sonner/sonner.tsx +137 -8
- package/src/components/spinner/spinner.meta.md +57 -21
- package/src/components/spinner/spinner.stories.tsx +66 -14
- package/src/components/spinner/spinner.tsx +111 -9
- package/src/components/statistic/statistic.meta.md +14 -30
- package/src/components/statistic/statistic.stories.tsx +1 -1
- package/src/components/statistic/statistic.tsx +4 -5
- package/src/components/steps/steps.meta.md +20 -15
- package/src/components/steps/steps.stories.tsx +37 -2
- package/src/components/steps/steps.tsx +15 -12
- package/src/components/switch/switch.meta.md +56 -15
- package/src/components/switch/switch.stories.tsx +5 -5
- package/src/components/switch/switch.tsx +59 -13
- package/src/components/table/table.meta.md +3 -7
- package/src/components/table/table.stories.tsx +1 -1
- package/src/components/table/table.tsx +4 -4
- package/src/components/tabs/tabs.meta.md +40 -32
- package/src/components/tabs/tabs.stories.tsx +104 -26
- package/src/components/tabs/tabs.tsx +125 -54
- package/src/components/tag/tag.meta.md +104 -68
- package/src/components/tag/tag.stories.tsx +183 -15
- package/src/components/tag/tag.tsx +222 -21
- package/src/components/textarea/textarea.meta.md +42 -31
- package/src/components/textarea/textarea.stories.tsx +32 -6
- package/src/components/textarea/textarea.tsx +32 -8
- package/src/components/time-picker/time-picker.meta.md +119 -50
- package/src/components/time-picker/time-picker.stories.tsx +65 -33
- package/src/components/time-picker/time-picker.tsx +889 -101
- package/src/components/timeline/timeline.meta.md +16 -17
- package/src/components/timeline/timeline.stories.tsx +24 -4
- package/src/components/timeline/timeline.tsx +32 -12
- package/src/components/toggle/toggle.meta.md +8 -12
- package/src/components/toggle/toggle.stories.tsx +4 -4
- package/src/components/toggle/toggle.tsx +4 -3
- package/src/components/toggle-group/toggle-group.meta.md +10 -14
- package/src/components/toggle-group/toggle-group.stories.tsx +3 -3
- package/src/components/toggle-group/toggle-group.tsx +2 -2
- package/src/components/tooltip/tooltip.meta.md +63 -18
- package/src/components/tooltip/tooltip.stories.tsx +42 -5
- package/src/components/tooltip/tooltip.tsx +81 -21
- package/src/components/tour/tour.meta.md +16 -20
- package/src/components/tour/tour.stories.tsx +3 -3
- package/src/components/tour/tour.tsx +3 -3
- package/src/components/transfer/transfer.meta.md +18 -22
- package/src/components/transfer/transfer.stories.tsx +2 -2
- package/src/components/transfer/transfer.tsx +28 -21
- package/src/components/tree/tree.meta.md +67 -22
- package/src/components/tree/tree.stories.tsx +1 -1
- package/src/components/tree/tree.tsx +9 -8
- package/src/components/tree-select/tree-select.meta.md +59 -23
- package/src/components/tree-select/tree-select.stories.tsx +2 -2
- package/src/components/tree-select/tree-select.tsx +42 -7
- package/src/components/typography/typography.meta.md +61 -39
- package/src/components/typography/typography.stories.tsx +14 -9
- package/src/components/typography/typography.tsx +38 -25
- package/src/components/upload/upload.meta.md +61 -25
- package/src/components/upload/upload.stories.tsx +69 -3
- package/src/components/upload/upload.tsx +170 -37
- package/src/components/watermark/watermark.meta.md +15 -19
- package/src/components/watermark/watermark.stories.tsx +98 -8
- package/src/hooks/use-breakpoint.ts +117 -0
- package/src/hooks/use-debounce-callback.ts +52 -0
- package/src/hooks/use-mobile.ts +23 -0
- package/src/stories/theme-tokens.stories.tsx +747 -0
- package/src/utils/trigger-input.ts +53 -0
- package/src/components/button-group/button-group.meta.md +0 -101
- package/src/components/button-group/button-group.stories.tsx +0 -93
- package/src/components/button-group/button-group.tsx +0 -75
- package/src/components/combobox/combobox.meta.md +0 -102
- package/src/components/combobox/combobox.stories.tsx +0 -55
- package/src/components/combobox/combobox.tsx +0 -130
- package/src/components/input/demo/addon.tsx +0 -15
- package/src/components/input/demo/with-prefix-suffix.tsx +0 -19
- package/src/components/space/space.meta.md +0 -103
- package/src/components/space/space.stories.tsx +0 -108
- 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+)
|
|
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
|
-
-
|
|
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
|
-
-
|
|
24
|
-
-
|
|
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
|
-
| `
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
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`
|
|
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: '
|
|
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
|
|
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+)
|
|
74
|
-
*
|
|
78
|
+
* Flex 布局容器 — antd 独有补足。**等价 antd `Flex`**(v5.10+) ∪ **antd `Space`**(`split`)。
|
|
79
|
+
* 把 Tailwind flex 的常用对齐 / 间距 / 换行 / 方向 / 渲染元素 / 分隔节点收敛为枚举,避免散落的 className 反复手写。
|
|
75
80
|
*
|
|
76
|
-
*
|
|
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:
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
| `
|
|
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`
|
|
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: '
|
|
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:
|
|
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
|
-
|
|
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`
|
|
85
|
-
| `
|
|
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-
|
|
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()
|
|
100
|
-
- **每个字段必有 `<FormField name="..." control={form.control} render={({ field }) => <FormItem>...</FormItem>}
|
|
101
|
-
- **`<FormControl>`
|
|
102
|
-
- **错误消息走 `<FormMessage
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
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
|
|