@cloudtower/eagle 490.0.5 → 490.0.7

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 (56) hide show
  1. package/README.md +34 -0
  2. package/dist/cjs/core/Cascader/cascader.widget.js +12 -12
  3. package/dist/cjs/core/SearchInput/SearchInput.hook.js +124 -0
  4. package/dist/cjs/core/SearchInput/SearchInput.js +253 -0
  5. package/dist/cjs/core/SearchInput/SearchInput.style.js +13 -0
  6. package/dist/cjs/core/index.js +6 -6
  7. package/dist/cjs/index.js +172 -172
  8. package/dist/cjs/legacy-antd.js +89 -89
  9. package/dist/cjs/stats1.html +1 -1
  10. package/dist/components.css +3836 -3813
  11. package/dist/esm/core/Cascader/cascader.widget.js +1 -1
  12. package/dist/esm/core/SearchInput/SearchInput.hook.js +117 -0
  13. package/dist/esm/core/SearchInput/SearchInput.js +247 -0
  14. package/dist/esm/core/SearchInput/SearchInput.style.js +7 -0
  15. package/dist/esm/index.js +1 -1
  16. package/dist/esm/legacy-antd.js +1 -1
  17. package/dist/esm/stats1.html +1 -1
  18. package/dist/linaria.merged.scss +3611 -3582
  19. package/dist/src/core/Cascader/cascader.type.d.ts +1 -1
  20. package/dist/src/core/ImmersiveDialog/type.d.ts +127 -19
  21. package/dist/src/core/MediumDialog/MediumDialog.type.d.ts +49 -1
  22. package/dist/src/core/SearchInput/SearchInput.d.ts +2 -0
  23. package/dist/src/core/SearchInput/SearchInput.hook.d.ts +9 -0
  24. package/dist/src/core/SearchInput/SearchInput.style.d.ts +5 -0
  25. package/dist/src/core/SearchInput/SearchInput.type.d.ts +150 -0
  26. package/dist/src/core/SearchInput/__test__/SearchInput.hook.test.d.ts +1 -0
  27. package/dist/src/core/SearchInput/index.d.ts +2 -4
  28. package/dist/src/core/SmallDialog/SmallDialog.type.d.ts +150 -21
  29. package/dist/src/core/TableForm/types.d.ts +216 -68
  30. package/dist/src/core/WizardDialog/type.d.ts +147 -13
  31. package/dist/src/core/index.d.ts +0 -1
  32. package/dist/src/coreX/Dialogs/DeleteDialog/DeleteDialog.type.d.ts +100 -9
  33. package/dist/src/coreX/Dialogs/RejectDialog/RejectDialog.type.d.ts +126 -19
  34. package/dist/stories/docs/core/ImmersiveDialog.stories.d.ts +76 -8
  35. package/dist/stories/docs/core/MediumDialog.stories.d.ts +42 -8
  36. package/dist/stories/docs/core/SearchInput.stories.d.ts +6 -1
  37. package/dist/stories/docs/core/SmallDialog.stories.d.ts +86 -7
  38. package/dist/stories/docs/core/TableForm.stories.d.ts +40 -26
  39. package/dist/stories/docs/core/WizardDialog.stories.d.ts +65 -6
  40. package/dist/stories/docs/coreX/Dialogs/DeleteDialog.stories.d.ts +20 -19
  41. package/dist/stories/docs/coreX/Dialogs/RejectDialog.stories.d.ts +24 -23
  42. package/dist/style.css +3836 -3813
  43. package/docs/core/ImmersiveDialog/guide.md +298 -0
  44. package/docs/core/LegacyModal/migrate-guide.md +422 -0
  45. package/docs/core/MediumDialog/guide.md +263 -0
  46. package/docs/core/SearchInput/guide.md +125 -0
  47. package/docs/core/SmallDialog/guide.md +224 -0
  48. package/docs/core/TableForm/guide.md +195 -0
  49. package/docs/core/WizardDialog/guide.md +322 -0
  50. package/docs/coreX/DeleteDialog/guide.md +161 -0
  51. package/docs/coreX/RejectDialog/guide.md +185 -0
  52. package/docs/llms.txt +169 -0
  53. package/package.json +6 -5
  54. package/dist/cjs/core/SearchInput/index.js +0 -164
  55. package/dist/esm/core/SearchInput/index.js +0 -157
  56. package/dist/src/core/SearchInput/searchInput.type.d.ts +0 -63
@@ -0,0 +1,125 @@
1
+ # SearchInput
2
+
3
+ ## 简介
4
+
5
+ 搜索输入框组件,基于 Input 封装,提供防抖搜索、结果导航(上一个/下一个/计数器)和最近搜索历史功能。支持受控和非受控两种模式,宽度默认 276px。
6
+
7
+ ## 何时使用
8
+
9
+ - 表格内搜索高亮匹配结果,需要上下翻页定位
10
+ - 页面全局搜索,需要防抖避免频繁请求
11
+ - 需要保留最近搜索记录的搜索场景
12
+
13
+ 不要使用:
14
+
15
+ - 仅需要简单输入框 --> 请用 `Input`
16
+ - 下拉选择过滤 --> 请用 `Select` 的搜索模式
17
+ - 级联选择中的搜索 --> `Cascader` 已内置 SearchInput
18
+
19
+ ## 基础用法
20
+
21
+ 最简单的搜索框,仅响应输入变化并防抖处理:
22
+
23
+ ```tsx
24
+ import React, { useState } from "react";
25
+ import { SearchInput } from "@cloudtower/eagle";
26
+
27
+ const App = () => {
28
+ const [keyword, setKeyword] = useState("");
29
+
30
+ return (
31
+ <SearchInput
32
+ debounceWait={300}
33
+ onChange={(value) => setKeyword(value)}
34
+ />
35
+ );
36
+ };
37
+ ```
38
+
39
+ ## 常见模式
40
+
41
+ ### 模式一:带结果导航
42
+
43
+ 适用于搜索后需要在匹配结果之间上下翻页的场景(如表格内搜索高亮)。同时提供 `onSearchNext` 和 `onSearchPrev` 后,输入框后缀会显示 "current/total" 计数器和上下翻页按钮。按 Enter 键等同于点击"下一个"。
44
+
45
+ ```tsx
46
+ import React, { useState } from "react";
47
+ import { SearchInput } from "@cloudtower/eagle";
48
+
49
+ const VmTableSearch = () => {
50
+ const [matchedVms, setMatchedVms] = useState<string[]>([]);
51
+
52
+ return (
53
+ <SearchInput
54
+ total={matchedVms.length}
55
+ onChange={(value) => {
56
+ // 根据关键词过滤匹配的虚拟机列表
57
+ const matched = allVms.filter((vm) => vm.name.includes(value));
58
+ setMatchedVms(matched);
59
+ }}
60
+ onSearchNext={(value, current) => {
61
+ // 滚动到第 current 个匹配结果
62
+ scrollToVm(matchedVms[current - 1]);
63
+ }}
64
+ onSearchPrev={(value, current) => {
65
+ scrollToVm(matchedVms[current - 1]);
66
+ }}
67
+ />
68
+ );
69
+ };
70
+ ```
71
+
72
+ ### 模式二:受控模式(外部控制当前索引)
73
+
74
+ 适用于需要从组件外部控制当前高亮索引的场景,例如同步多个搜索结果视图。通过 `current` prop 传入索引值,组件不再内部管理位置状态。
75
+
76
+ ```tsx
77
+ import React, { useState } from "react";
78
+ import { SearchInput, Button } from "@cloudtower/eagle";
79
+
80
+ const App = () => {
81
+ const [value, setValue] = useState("");
82
+ const [current, setCurrent] = useState(1);
83
+ const total = 10;
84
+
85
+ return (
86
+ <div>
87
+ <SearchInput
88
+ value={value}
89
+ current={current}
90
+ total={total}
91
+ debounceWait={0}
92
+ onChange={(v) => setValue(v)}
93
+ onSearchNext={(v, nextCurrent) => setCurrent(nextCurrent)}
94
+ onSearchPrev={(v, prevCurrent) => setCurrent(prevCurrent)}
95
+ />
96
+ <Button onClick={() => setCurrent(1)}>回到第一个</Button>
97
+ </div>
98
+ );
99
+ };
100
+ ```
101
+
102
+ 注意:使用受控模式(传入 `value`)时,需把 `debounceWait` 设置为 0,否则输入时会有卡顿。
103
+
104
+ ### 模式三:最近搜索历史
105
+
106
+ 启用 `enableRecentSearch` 后,搜索记录会通过 localStorage 持久化存储。聚焦空输入框时自动显示最近搜索记录的下拉菜单,点击记录项可直接填入搜索。不同业务场景应使用不同的 `recentSearchLocalStorageKey` 以隔离数据。
107
+
108
+ ```tsx
109
+ import React from "react";
110
+ import { SearchInput } from "@cloudtower/eagle";
111
+
112
+ const App = () => (
113
+ <SearchInput
114
+ enableRecentSearch
115
+ recentSearchLocalStorageKey="host-search"
116
+ maxRecentCount={5}
117
+ onChange={(value) => console.log("搜索:", value)}
118
+ />
119
+ );
120
+ ```
121
+
122
+ ## 相关组件
123
+
124
+ - `Input`:基础输入框,SearchInput 基于它封装
125
+ - `Cascader`:级联选择器,内置了 SearchInput 作为搜索区域
@@ -0,0 +1,224 @@
1
+ # SmallDialog
2
+
3
+ ## 简介
4
+
5
+ SmallDialog 是一个固定 492px 宽度的轻量级对话框组件,适用于简单确认、信息提示和自定义轻量弹窗场景。通过 `usePushModal` / `popModal` 管理弹窗生命周期,内置初始化加载态、错误信息展示和骨架屏等能力。
6
+
7
+ ## 何时使用
8
+
9
+ - 简单确认操作(如"确认关闭虚拟机?")
10
+ - 纯信息提示(隐藏确认按钮,仅展示关闭按钮)
11
+ - 需要异步提交并展示加载状态的轻量弹窗
12
+ - 需要初始化加载数据后再展示内容的弹窗
13
+
14
+ 不要使用:
15
+
16
+ - 包含表单的场景 --> 请用 `MediumDialog`
17
+ - 多步骤向导流程 --> 请用 `WizardDialog`
18
+ - 全屏沉浸式操作 --> 请用 `ImmersiveDialog`
19
+ - 删除确认场景 --> 请用 `DeleteDialog`(已封装删除确认样式和交互)
20
+ - 操作被拒绝 / 不可执行的反馈 --> 请用 `RejectDialog`(支持 Single / All / Part / Custom 四种模式)
21
+
22
+ ## 基础用法
23
+
24
+ ```tsx
25
+ import React from "react";
26
+ import { SmallDialog, Button, KitStoreProvider, ModalStack } from "@cloudtower/eagle";
27
+ import { usePushModal } from "@cloudtower/eagle";
28
+
29
+ const App = () => {
30
+ const pushModal = usePushModal();
31
+
32
+ const openDialog = () => {
33
+ pushModal({
34
+ component: () => (
35
+ <SmallDialog
36
+ title="关闭虚拟机"
37
+ onOk={(popModal) => {
38
+ console.log("确认关闭");
39
+ popModal();
40
+ }}
41
+ onCancel={(popModal) => {
42
+ popModal();
43
+ }}
44
+ >
45
+ <p>确定要关闭虚拟机 "vm-prod-01" 吗?</p>
46
+ </SmallDialog>
47
+ ),
48
+ props: {},
49
+ });
50
+ };
51
+
52
+ return (
53
+ <Button type="primary" onClick={openDialog}>
54
+ 关闭虚拟机
55
+ </Button>
56
+ );
57
+ };
58
+ ```
59
+
60
+ ## 常见模式
61
+
62
+ ### 模式一:异步提交弹窗
63
+
64
+ 适用于点击确认后需要执行异步操作(如 API 请求)的场景。通过 `confirmLoading` 控制按钮加载状态,操作完成后再关闭弹窗。
65
+
66
+ ```tsx
67
+ import React, { useState } from "react";
68
+ import { SmallDialog, Button } from "@cloudtower/eagle";
69
+ import { usePushModal } from "@cloudtower/eagle";
70
+
71
+ const ShutdownVmDialog: React.FC = () => {
72
+ const [loading, setLoading] = useState(false);
73
+ const [error, setError] = useState<string>();
74
+
75
+ return (
76
+ <SmallDialog
77
+ title="关闭虚拟机"
78
+ confirmLoading={loading}
79
+ error={error}
80
+ onOk={async (popModal) => {
81
+ setLoading(true);
82
+ setError(undefined);
83
+ try {
84
+ await shutdownVm("vm-prod-01");
85
+ popModal();
86
+ } catch (e) {
87
+ setError("关闭虚拟机失败,请重试");
88
+ } finally {
89
+ setLoading(false);
90
+ }
91
+ }}
92
+ >
93
+ <p>确定要关闭虚拟机 "vm-prod-01" 吗?</p>
94
+ <p>关闭后该虚拟机上运行的所有服务将停止。</p>
95
+ </SmallDialog>
96
+ );
97
+ };
98
+
99
+ // 使用方式
100
+ const App = () => {
101
+ const pushModal = usePushModal();
102
+
103
+ return (
104
+ <Button
105
+ type="primary"
106
+ onClick={() =>
107
+ pushModal({ component: () => <ShutdownVmDialog />, props: {} })
108
+ }
109
+ >
110
+ 关闭虚拟机
111
+ </Button>
112
+ );
113
+ };
114
+ ```
115
+
116
+ ### 模式二:初始化加载弹窗
117
+
118
+ 适用于弹窗打开后需要先请求数据再展示内容的场景。利用 `initializing`、`initializingError` 和 `initializingSkeletonRows` 三个属性组合控制加载、失败、成功三种状态。
119
+
120
+ ```tsx
121
+ import React, { useEffect, useMemo, useState } from "react";
122
+ import { SmallDialog, Button } from "@cloudtower/eagle";
123
+ import type { SmallDialogProps } from "@cloudtower/eagle";
124
+ import { usePushModal } from "@cloudtower/eagle";
125
+
126
+ const HostDetailDialog: React.FC = () => {
127
+ const [loading, setLoading] = useState(true);
128
+ const [error, setError] = useState<string>();
129
+ const [data, setData] = useState<{ name: string; ip: string }>();
130
+
131
+ const fetchData = async () => {
132
+ setLoading(true);
133
+ setError(undefined);
134
+ try {
135
+ const result = await fetchHostDetail("host-01");
136
+ setData(result);
137
+ } catch (e) {
138
+ setError("加载主机信息失败");
139
+ } finally {
140
+ setLoading(false);
141
+ }
142
+ };
143
+
144
+ useEffect(() => {
145
+ fetchData();
146
+ }, []);
147
+
148
+ const modalProps: SmallDialogProps = useMemo(() => {
149
+ if (loading) {
150
+ return { title: "", initializing: true, initializingSkeletonRows: 3 };
151
+ }
152
+ if (error) {
153
+ return { title: "", initializingError: error, onOk: fetchData };
154
+ }
155
+ return { title: `主机详情 - ${data?.name}` };
156
+ }, [loading, error, data]);
157
+
158
+ return (
159
+ <SmallDialog {...modalProps}>
160
+ <p>主机名称:{data?.name}</p>
161
+ <p>IP 地址:{data?.ip}</p>
162
+ </SmallDialog>
163
+ );
164
+ };
165
+
166
+ // 使用方式
167
+ const App = () => {
168
+ const pushModal = usePushModal();
169
+
170
+ return (
171
+ <Button
172
+ onClick={() =>
173
+ pushModal({ component: () => <HostDetailDialog />, props: {} })
174
+ }
175
+ >
176
+ 查看主机详情
177
+ </Button>
178
+ );
179
+ };
180
+ ```
181
+
182
+ ### 模式三:自定义确认弹窗(纯信息提示)
183
+
184
+ 适用于仅需要展示信息,不需要用户做"确认/取消"选择的场景。通过 `showOk={false}` 隐藏确认按钮,将取消按钮文案改为"我知道了"。
185
+
186
+ ```tsx
187
+ import React from "react";
188
+ import { SmallDialog, Button } from "@cloudtower/eagle";
189
+ import { usePushModal } from "@cloudtower/eagle";
190
+
191
+ const App = () => {
192
+ const pushModal = usePushModal();
193
+
194
+ return (
195
+ <Button
196
+ onClick={() =>
197
+ pushModal({
198
+ component: () => (
199
+ <SmallDialog
200
+ title="集群升级完成"
201
+ showOk={false}
202
+ cancelText="我知道了"
203
+ >
204
+ <p>集群 "cluster-prod" 已成功升级到 v4.2.0。</p>
205
+ <p>所有节点均已完成滚动更新,当前运行状态正常。</p>
206
+ </SmallDialog>
207
+ ),
208
+ props: {},
209
+ })
210
+ }
211
+ >
212
+ 查看升级结果
213
+ </Button>
214
+ );
215
+ };
216
+ ```
217
+
218
+ ## 相关组件
219
+
220
+ - `MediumDialog` — 中等尺寸对话框(720px),适用于包含表单输入的场景
221
+ - `ImmersiveDialog` — 全屏沉浸式对话框,适用于需要大量操作空间的场景
222
+ - `WizardDialog` — 向导式对话框,适用于多步骤流程
223
+ - `DeleteDialog` — 删除确认对话框,封装了删除场景的标准样式和交互(位于 `@cloudtower/eagle` 的 coreX 模块)
224
+ - `RejectDialog` — 操作拒绝反馈对话框,支持 Single(单条拒绝)、All(全部拒绝)、Part(部分拒绝)、Custom(自定义内容)四种模式(位于 `@cloudtower/eagle` 的 coreX 模块)
@@ -0,0 +1,195 @@
1
+ # TableForm
2
+
3
+ ## 简介
4
+
5
+ TableForm 是行内编辑的表格表单组件,适用于批量数据录入场景。支持多种内置列类型(text/input/password/checkbox/affix)和自定义列渲染,表头批量填充、行的增删和拖拽排序、三种校验触发模式(Normal/Aggressive/Lazy),以及通过 `errors` 属性注入外部错误信息。通过 `useRef<TableFormHandle>` 可命令式操作数据和校验。
6
+
7
+ ## 何时使用
8
+
9
+ - 需要批量录入结构化数据(如添加多台主机、配置多个网络接口)
10
+ - 每行数据结构相同,需要行内直接编辑
11
+ - 需要表头批量填充功能(一次输入应用到所有行)
12
+ - 需要行级别的增删和拖拽排序
13
+
14
+ 不要使用:
15
+
16
+ - 只有单行数据录入 --> 请用 `Form`
17
+ - 纯展示型表格(不需要编辑) --> 请用 `Table`
18
+ - 仅需拖拽排序(不需要编辑) --> 请用 `SortableList`
19
+
20
+ ## 基础用法
21
+
22
+ ```tsx
23
+ import React, { useRef } from "react";
24
+ import { TableForm } from "@cloudtower/eagle";
25
+ import type { TableFormColumn, TableFormHandle } from "@cloudtower/eagle";
26
+
27
+ const columns: TableFormColumn[] = [
28
+ { key: "name", title: "主机名", type: "input", autoIncrease: true },
29
+ {
30
+ key: "ip",
31
+ title: "管理 IP",
32
+ type: "input",
33
+ validator: ({ value }) => (!value ? "IP 不能为空" : undefined),
34
+ },
35
+ { key: "password", title: "密码", type: "password" },
36
+ ];
37
+
38
+ const App = () => {
39
+ const ref = useRef<TableFormHandle>(null);
40
+
41
+ return (
42
+ <TableForm
43
+ ref={ref}
44
+ columns={columns}
45
+ defaultData={[
46
+ { name: "host0", ip: "", password: "" },
47
+ { name: "host1", ip: "", password: "" },
48
+ ]}
49
+ rowAddConfig={{ addible: true, maximum: 10 }}
50
+ row={{ deletable: true }}
51
+ onBodyChange={(data) => console.log("数据变更:", data)}
52
+ />
53
+ );
54
+ };
55
+ ```
56
+
57
+ ## 常见模式
58
+
59
+ ### 模式一:批量填充 + 自动递增
60
+
61
+ 适用于需要快速填入相似数据的场景。表头输入框的值会批量应用到所有行,配合 `autoIncrease` 可以自动递增末尾数字。
62
+
63
+ ```tsx
64
+ import React from "react";
65
+ import { TableForm } from "@cloudtower/eagle";
66
+ import type { TableFormColumn } from "@cloudtower/eagle";
67
+
68
+ const columns: TableFormColumn[] = [
69
+ {
70
+ key: "hostname",
71
+ title: "主机名",
72
+ type: "input",
73
+ autoIncrease: true,
74
+ defaultValue: "host0",
75
+ },
76
+ { key: "ip", title: "管理 IP", type: "input" },
77
+ { key: "enabled", title: "启用", type: "checkbox", align: "center" },
78
+ ];
79
+
80
+ const App = () => (
81
+ <TableForm
82
+ columns={columns}
83
+ defaultData={[
84
+ { hostname: "host0", ip: "10.0.0.1", enabled: true },
85
+ { hostname: "host1", ip: "10.0.0.2", enabled: true },
86
+ { hostname: "host2", ip: "10.0.0.3", enabled: false },
87
+ ]}
88
+ onHeaderChange={(data, columnKey) =>
89
+ console.log("批量填充:", columnKey, data)
90
+ }
91
+ />
92
+ );
93
+ ```
94
+
95
+ ### 模式二:自定义列渲染
96
+
97
+ 适用于内置列类型无法满足需求的场景。通过 `render` 函数可以渲染任意组件(如 Select、DatePicker 等)。
98
+
99
+ ```tsx
100
+ import React from "react";
101
+ import { TableForm, Select } from "@cloudtower/eagle";
102
+ import type { TableFormColumn } from "@cloudtower/eagle";
103
+
104
+ const columns: TableFormColumn[] = [
105
+ { key: "name", title: "名称", type: "input" },
106
+ {
107
+ key: "role",
108
+ title: "角色",
109
+ defaultValue: "worker",
110
+ render({ isHeader, value, onChange, placeholder }) {
111
+ return (
112
+ <Select
113
+ size="small"
114
+ value={value as string}
115
+ onChange={onChange}
116
+ placeholder={isHeader ? "批量选择" : "请选择"}
117
+ options={[
118
+ { label: "Master", value: "master" },
119
+ { label: "Worker", value: "worker" },
120
+ ]}
121
+ />
122
+ );
123
+ },
124
+ validator({ value }) {
125
+ if (!value) return "请选择角色";
126
+ },
127
+ },
128
+ ];
129
+
130
+ const App = () => (
131
+ <TableForm
132
+ columns={columns}
133
+ defaultData={[{ name: "", role: "worker" }]}
134
+ rowAddConfig={{ addible: true }}
135
+ row={{ deletable: true }}
136
+ />
137
+ );
138
+ ```
139
+
140
+ ### 模式三:行配置 + 外部错误注入
141
+
142
+ 适用于校验逻辑在外部(如服务端返回错误)的场景。通过 `row` 统一配置行行为,通过 `errors` 注入外部错误信息。
143
+
144
+ ```tsx
145
+ import React, { useState } from "react";
146
+ import { TableForm } from "@cloudtower/eagle";
147
+ import type { TableFormColumn, TableFormErrorsType } from "@cloudtower/eagle";
148
+
149
+ const columns: TableFormColumn[] = [
150
+ { key: "name", title: "名称", type: "input" },
151
+ { key: "value", title: "值", type: "input" },
152
+ ];
153
+
154
+ const App = () => {
155
+ const [errors, setErrors] = useState<TableFormErrorsType>([null]);
156
+
157
+ return (
158
+ <TableForm
159
+ columns={columns}
160
+ defaultData={[{ name: "key1", value: "" }]}
161
+ row={{
162
+ deletable: true,
163
+ draggable: true,
164
+ splitType: "zebraMarking",
165
+ validator: (rowIndex, rowData) =>
166
+ !rowData.name ? "名称不能为空" : undefined,
167
+ }}
168
+ errors={errors}
169
+ onBodyChange={(data) => {
170
+ // 模拟服务端校验
171
+ const newErrors = data.map((row) =>
172
+ row.value === "error" ? { value: "该值不合法" } : null,
173
+ );
174
+ setErrors(newErrors);
175
+ }}
176
+ />
177
+ );
178
+ };
179
+ ```
180
+
181
+ ## 废弃说明
182
+
183
+ 以下属性已废弃,请迁移至 `row` 配置:
184
+
185
+ - `draggable` --> `row.draggable`
186
+ - `deleteConfig` --> `row.deletable` + `row.disableActions`
187
+ - `rowSplitType` --> `row.splitType`
188
+ - `renderRowDescription` --> `row.customizedDescription`
189
+ - `rowValidator` --> `row.validator`
190
+
191
+ ## 相关组件
192
+
193
+ - `Form`: 标准表单容器,适用于非表格化的表单场景
194
+ - `Table`: 数据展示表格,适用于只读场景
195
+ - `SortableList`: 可拖拽排序列表,适用于纯排序(无编辑)场景