@qin-ui/element-plus-pro 1.4.2 → 1.4.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qin-ui/element-plus-pro",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "基于 element-plus 的二次封装组件",
5
5
  "bin": {
6
6
  "element-plus-pro": "./bin/init-ai.mjs"
@@ -1,205 +1,174 @@
1
- <script lang="ts" setup>
1
+ <script lang="ts">
2
2
  /**
3
- * 表单字段渲染引擎
3
+ * 单字段行渲染组件
4
4
  *
5
5
  * @component BaseFormItem
6
6
  *
7
- * 负责将字段配置数组渲染为实际的表单项,支持:
8
- * - 字段分组(嵌套 fields 递归渲染,嵌套字段 path 须为完整点分路径)
9
- * - 网格布局(grid 属性控制)
10
- * - FormItem 包装(label、rules、校验等)
11
- * - 组件绑定(通过 BaseField 渲染具体组件)
12
- * - 插槽透传(label、error 等 FormItem 插槽)
7
+ * 将单个字段配置渲染为栅格项、FormItem 与控件,支持:
8
+ * - 字段属性分流(grid / formItem / component / slots)
9
+ * - 嵌套字段递归渲染(交由 BaseFormItems)
10
+ * - FormItem / 控件实例登记
13
11
  *
14
- * ## 渲染流程
15
- *
16
- * 1. 遍历 fields 数组,过滤 hidden 字段
17
- * 2. 通过 useGroupFieldAttrs Hook 纯计算将 field 配置拆分为 gridItemProps / formItemProps / componentProps / slots
18
- * 3. 递归渲染 BaseFormItem(嵌套表单)或 BaseField(输入组件)
19
- * 4. 通过 ref 回调收集 FormItem 和 Component 实例,注入到 field 对象上
20
- *
21
- * @param {Fields} [fields] - 字段配置数组
12
+ * @param {Field} field - 字段配置
22
13
  * @param {boolean | GridProps} [grid] - 是否启用网格布局
23
- * @param {boolean} [disabled] - 是否禁用所有子字段
14
+ * @param {boolean} [disabled] - 上层下发的禁用状态
15
+ * @param {Function} [setFormItemRef] - FormItem 实例登记回调
16
+ * @param {Function} [setComponentRef] - 控件实例登记回调
24
17
  *
25
18
  * @internal
26
19
  */
27
20
  import {
28
- getObject,
29
- isObjectItem,
30
- normalizePathKey,
31
- } from '../../../../shared/core';
32
- import type { GridProps } from '../../../../shared/ui';
33
- import {
34
- FormItem,
35
- Grid as ElGrid,
36
- GridItem as ElGridItem,
37
- useProviderDisabled,
38
- } from '../../../../shared/ui';
39
- import { computed, inject, toRaw, toValue } from 'vue';
40
- import type { Fields, Grid } from '../../types';
21
+ computed,
22
+ defineComponent,
23
+ h,
24
+ toValue,
25
+ watch,
26
+ type PropType,
27
+ type VNode,
28
+ } from 'vue';
29
+ import { normalizePathKey } from '../../../../shared/core';
30
+ import { FormItem, GridItem as ElGridItem } from '../../../../shared/ui';
31
+ import type { Field, Grid } from '../../types';
41
32
  import BaseField from '../BaseField/index.vue';
33
+ import BaseFormItems from '../BaseFormItems/index.vue';
42
34
  import SlotComponent from '../SlotComponent/index.vue';
43
- import ContainerFragment from '../ContainerFragment/index.vue';
44
- import { useGroupFieldAttrs } from '../../hooks/useGroupFieldAttrs';
45
- import { INJECT_CONFIG } from '../../../component-provider/constants';
35
+ import {
36
+ useGroupedField,
37
+ type GroupedField,
38
+ } from '../../hooks/useGroupFieldAttrs';
46
39
 
47
- defineOptions({ name: 'BaseFormItem', inheritAttrs: false });
40
+ export default defineComponent({
41
+ name: 'BaseFormItem',
42
+ inheritAttrs: false,
43
+ props: {
44
+ /** 字段配置 */
45
+ field: { type: Object as PropType<Field>, required: true },
46
+ /** 是否启用网格布局 */
47
+ grid: {
48
+ type: [Boolean, Object] as PropType<Grid>,
49
+ default: undefined,
50
+ },
51
+ /** 上层下发的禁用状态 */
52
+ disabled: { type: Boolean, default: undefined },
53
+ /** FormItem 实例登记回调 */
54
+ setFormItemRef: {
55
+ type: Function as PropType<
56
+ (field: Field, el: any, getFormItemProps: () => any) => void
57
+ >,
58
+ default: undefined,
59
+ },
60
+ /** 控件实例登记回调 */
61
+ setComponentRef: {
62
+ type: Function as PropType<(field: Field, el: any) => void>,
63
+ default: undefined,
64
+ },
65
+ },
66
+ setup(props) {
67
+ const grouped = useGroupedField(() => props.field);
68
+ const enableGrid = computed(() => !!props.grid);
48
69
 
49
- type Props = {
50
- grid?: Grid;
51
- fields?: Fields;
52
- disabled?: boolean;
53
- };
54
- const props = withDefaults(defineProps<Props>(), {
55
- grid: undefined,
56
- fields: () => [],
57
- disabled: undefined,
58
- });
70
+ // 控件级配置身份:字符串组件名 + type 段;组件对象无 Provider 配置,使用固定值
71
+ const componentKey = computed(() => {
72
+ const field = props.field as any;
73
+ const component = toValue(field.component);
74
+ if (typeof component !== 'string') return 'component-object';
75
+ return `string:${component}:${toValue(field.type) ?? ''}`;
76
+ });
77
+ const effectiveDisabled = computed(
78
+ () => toValue(props.field.disabled) ?? props.disabled
79
+ );
59
80
 
60
- // 分组字段的禁用状态向下注入,供 BaseField 经禁用上下文消费
61
- useProviderDisabled(computed(() => props.disabled));
81
+ const setItemRef = (el: any) => {
82
+ props.setFormItemRef?.(
83
+ props.field,
84
+ el,
85
+ () => grouped.value.formItemProps
86
+ );
87
+ };
62
88
 
63
- const validFields = computed(() =>
64
- // hidden 支持 Ref / ComputedRef 响应式形态(统一使用 toValue 取值)
65
- (props.fields ?? []).filter(
66
- field => isObjectItem(field) && !toValue((field as any).hidden)
67
- )
68
- );
89
+ const setFieldRef = (el: any) => {
90
+ props.setComponentRef?.(props.field, el);
91
+ };
69
92
 
70
- const config = INJECT_CONFIG['pro-form'];
71
- const injectFormConfig = inject(config.injectionKey, config.default);
72
- const injectGrid = computed(() => toValue(injectFormConfig)?.grid);
93
+ // 字段对象变化后,实例访问器归属当前字段
94
+ watch(
95
+ () => props.field,
96
+ (next, prev) => {
97
+ if (!prev || prev === next) return;
98
+ props.setFormItemRef?.(prev, null, () => grouped.value.formItemProps);
99
+ props.setComponentRef?.(prev, null);
100
+ },
101
+ { flush: 'pre' }
102
+ );
73
103
 
74
- const enableGrid = computed(() => !!props.grid);
104
+ /** 按容器组件逐层包裹当前节点 */
105
+ const withContainer = (
106
+ node: VNode,
107
+ component: any,
108
+ containerProps: Record<string, any>
109
+ ): VNode =>
110
+ component ? h(component, containerProps, { default: () => node }) : node;
75
111
 
76
- const computedGridProps = computed<GridProps>(() => {
77
- return enableGrid.value
78
- ? { ...getObject(injectGrid.value), ...getObject(props.grid) }
79
- : {};
80
- });
112
+ /** 组装 FormItem 的动态插槽与默认插槽 */
113
+ const renderFormItemSlots = (groupedField: GroupedField) => {
114
+ const slots: Record<string, any> = {};
115
+ Object.entries(groupedField.formItemSlots).forEach(([name, slot]) => {
116
+ slots[name] = (scope?: Record<string, any>) =>
117
+ h(SlotComponent as any, {
118
+ path: groupedField.path,
119
+ component: slot,
120
+ ...(scope || {}),
121
+ });
122
+ });
81
123
 
82
- /**
83
- * 以字段原始对象为 key 登记 FormItem / 控件实例,供 getFormItemRef / getComponentRef 读取;
84
- * 字段对象被回收后对应条目不再可读。
85
- */
86
- const formItemInstanceMap = new WeakMap<object, any>();
87
- const componentInstanceMap = new WeakMap<object, any>();
124
+ slots.default = () => {
125
+ const field = props.field as any;
126
+ if (field.fields) {
127
+ return h(BaseFormItems as any, {
128
+ grid: field.grid ?? props.grid,
129
+ fields: field.fields,
130
+ disabled: effectiveDisabled.value,
131
+ });
132
+ }
133
+ return h(BaseField as any, {
134
+ key: componentKey.value,
135
+ ref: setFieldRef,
136
+ ...groupedField.componentProps,
137
+ path: groupedField.path,
138
+ disabled: effectiveDisabled.value,
139
+ });
140
+ };
141
+ return slots;
142
+ };
88
143
 
89
- /** 已告警过的字段对象(不可写场景去重) */
90
- const warnedFrozenFields = new WeakSet<object>();
91
- const defineFieldAccessors = (
92
- raw: object,
93
- accessors: Record<string, () => any>
94
- ) => {
95
- try {
96
- for (const [key, getter] of Object.entries(accessors)) {
97
- // 访问器仅用于字段对象读取,不参与属性遍历与字段配置透传
98
- Object.defineProperty(raw, key, {
99
- value: getter,
100
- enumerable: false,
101
- configurable: true,
102
- writable: true,
144
+ return () => {
145
+ const groupedField = grouped.value;
146
+ let node: VNode = h(
147
+ FormItem as any,
148
+ {
149
+ ...groupedField.formItemProps,
150
+ ref: setItemRef,
151
+ prop: normalizePathKey(groupedField.path),
152
+ path: groupedField.path,
153
+ },
154
+ renderFormItemSlots(groupedField)
155
+ );
156
+ node = withContainer(node, groupedField.container, {
157
+ path: groupedField.path,
103
158
  });
104
- }
105
- } catch {
106
- if (!warnedFrozenFields.has(raw)) {
107
- warnedFrozenFields.add(raw);
108
- console.warn(
109
- '[pro-components] 字段配置对象不可写(如被 Object.freeze),getFormItemRef / getComponentRef 等实例访问器挂载失败。'
159
+ node = withContainer(
160
+ node,
161
+ enableGrid.value ? ElGridItem : undefined,
162
+ groupedField.gridItemProps
110
163
  );
111
- }
112
- }
113
- };
114
-
115
- const setFormItemRef = (field: any, el: any, formItemProps?: any) => {
116
- if (!field || typeof field !== 'object') return;
117
- const raw = toRaw(field);
118
- if (el) {
119
- formItemInstanceMap.set(raw, el);
120
- defineFieldAccessors(raw, {
121
- getFormItemRef: () => formItemInstanceMap.get(raw),
122
- getFormItemComputedProps: () => formItemProps,
123
- });
124
- } else {
125
- formItemInstanceMap.delete(raw);
126
- delete raw.getFormItemRef;
127
- delete raw.getFormItemComputedProps;
128
- }
129
- };
130
-
131
- const setComponentRef = (field: any, el: any) => {
132
- if (!field || typeof field !== 'object') return;
133
- const raw = toRaw(field);
134
- if (el) {
135
- componentInstanceMap.set(raw, el);
136
- defineFieldAccessors(raw, {
137
- getComponentRef: () => componentInstanceMap.get(raw)?.getComponentRef(),
138
- getComponentComputedProps: () =>
139
- componentInstanceMap.get(raw)?.getComponentComputedProps(),
140
- });
141
- } else {
142
- componentInstanceMap.delete(raw);
143
- delete raw.getComponentRef;
144
- delete raw.getComponentComputedProps;
145
- }
146
- };
147
-
148
- const groupedFields = useGroupFieldAttrs(validFields);
164
+ return node;
165
+ };
166
+ },
167
+ });
149
168
  </script>
150
169
 
151
- <template>
152
- <ContainerFragment
153
- :component="enableGrid ? ElGrid : undefined"
154
- v-bind="computedGridProps"
155
- style="width: 100%"
156
- >
157
- <template v-for="item of groupedFields" :key="item.renderKey">
158
- <ContainerFragment
159
- :component="enableGrid ? ElGridItem : undefined"
160
- v-bind="item.gridItemProps"
161
- >
162
- <ContainerFragment :component="item.container" :path="item.path">
163
- <FormItem
164
- v-bind="item.formItemProps"
165
- :ref="el => setFormItemRef(item.rawField, el, item.formItemProps)"
166
- :prop="normalizePathKey(item.path)"
167
- :path="item.path"
168
- >
169
- <template
170
- v-for="(slot, name) in item.formItemSlots"
171
- :key="name"
172
- #[name]="scoped"
173
- >
174
- <SlotComponent
175
- :path="item.path"
176
- :component="slot"
177
- v-bind="scoped"
178
- />
179
- </template>
180
- <template v-if="item.rawField.fields">
181
- <BaseFormItem
182
- :grid="(item.rawField as any).grid ?? props.grid"
183
- :fields="item.rawField.fields"
184
- :disabled="toValue(item.rawField.disabled) ?? props.disabled"
185
- />
186
- </template>
187
- <template v-else>
188
- <BaseField
189
- :ref="el => setComponentRef(item.rawField, el)"
190
- v-bind="item.componentProps"
191
- :path="item.path"
192
- :disabled="toValue(item.rawField.disabled) ?? props.disabled"
193
- />
194
- </template>
195
- </FormItem>
196
- </ContainerFragment>
197
- </ContainerFragment>
198
- </template>
199
- </ContainerFragment>
200
- </template>
201
-
202
170
  <style scoped lang="less">
171
+ /* 分组字段的嵌套 FormItem 间距 */
203
172
  [class*='-form-item'] [class*='-form-item'] {
204
173
  margin-bottom: 18px;
205
174
  }
@@ -0,0 +1,183 @@
1
+ <script lang="ts" setup>
2
+ /**
3
+ * 表单字段渲染引擎
4
+ *
5
+ * @component BaseFormItems
6
+ *
7
+ * 负责将字段配置数组渲染为实际的表单项,支持:
8
+ * - 字段分组(嵌套 fields 递归渲染,嵌套字段 path 须为完整点分路径)
9
+ * - 网格布局(grid 属性控制)
10
+ * - FormItem 包装(label、rules、校验等)
11
+ * - 组件绑定(通过 BaseField 渲染具体组件)
12
+ * - 插槽透传(label、error 等 FormItem 插槽)
13
+ *
14
+ * ## 渲染流程
15
+ *
16
+ * 1. 遍历 fields 数组,过滤 hidden 字段
17
+ * 2. 每个字段交由 BaseFormItem 拆分为 GridItem / FormItem / 组件 / 插槽并渲染
18
+ * 3. 嵌套 fields 递归渲染下一层 BaseFormItems
19
+ * 4. 渲染后字段对象上可读取 FormItem 与组件实例
20
+ *
21
+ * @param {Fields} [fields] - 字段配置数组
22
+ * @param {boolean | GridProps} [grid] - 是否启用网格布局
23
+ * @param {boolean} [disabled] - 是否禁用所有子字段
24
+ *
25
+ * @internal
26
+ */
27
+ import {
28
+ InjectionFormKey,
29
+ getObject,
30
+ isObjectItem,
31
+ } from '../../../../shared/core';
32
+ import type { GridProps } from '../../../../shared/ui';
33
+ import { Grid as ElGrid, useProviderDisabled } from '../../../../shared/ui';
34
+ import { computed, inject, toRaw, toValue } from 'vue';
35
+ import type { Fields, Grid } from '../../types';
36
+ import BaseFormItem from '../BaseFormItem/index.vue';
37
+ import { getFieldDataKey } from '../../utils/fieldKey';
38
+ import { INJECT_CONFIG } from '../../../component-provider/constants';
39
+
40
+ defineOptions({ name: 'BaseFormItems', inheritAttrs: false });
41
+
42
+ type Props = {
43
+ grid?: Grid;
44
+ fields?: Fields;
45
+ disabled?: boolean;
46
+ };
47
+ const props = withDefaults(defineProps<Props>(), {
48
+ grid: undefined,
49
+ fields: () => [],
50
+ disabled: undefined,
51
+ });
52
+
53
+ // 分组字段的禁用状态向下注入,供 BaseField 经禁用上下文消费
54
+ useProviderDisabled(computed(() => props.disabled));
55
+
56
+ const validFields = computed(() =>
57
+ // hidden 支持 Ref / ComputedRef 响应式形态(统一使用 toValue 取值)
58
+ (props.fields ?? []).filter(
59
+ field => isObjectItem(field) && !toValue((field as any).hidden)
60
+ )
61
+ );
62
+
63
+ // 数组行按数据对象身份派生 key,字段配置重建后行实例保持复用
64
+ const injectedForm = inject(InjectionFormKey, undefined) as any;
65
+ const renderedFields = computed(() => {
66
+ const rawFormData = injectedForm?.formData
67
+ ? toRaw(injectedForm.formData)
68
+ : undefined;
69
+ const seen = new Map<string | number, number>();
70
+ return validFields.value.map(field => {
71
+ const baseKey = getFieldDataKey(field, rawFormData);
72
+ const count = seen.get(baseKey) ?? 0;
73
+ seen.set(baseKey, count + 1);
74
+ return {
75
+ field,
76
+ key: count === 0 ? baseKey : `${String(baseKey)}#${count}`,
77
+ };
78
+ });
79
+ });
80
+
81
+ const config = INJECT_CONFIG['pro-form'];
82
+ const injectFormConfig = inject(config.injectionKey, config.default);
83
+ const injectGrid = computed(() => toValue(injectFormConfig)?.grid);
84
+
85
+ const enableGrid = computed(() => !!props.grid);
86
+
87
+ const computedGridProps = computed<GridProps>(() => {
88
+ return enableGrid.value
89
+ ? { ...getObject(injectGrid.value), ...getObject(props.grid) }
90
+ : {};
91
+ });
92
+
93
+ /**
94
+ * 以字段原始对象为 key 登记 FormItem / 控件实例,供 getFormItemRef / getComponentRef 读取;
95
+ * 字段对象被回收后对应条目不再可读。
96
+ */
97
+ const formItemInstanceMap = new WeakMap<object, any>();
98
+ const componentInstanceMap = new WeakMap<object, any>();
99
+
100
+ /** 已告警过的字段对象(不可写场景去重) */
101
+ const warnedFrozenFields = new WeakSet<object>();
102
+ const defineFieldAccessors = (
103
+ raw: object,
104
+ accessors: Record<string, () => any>
105
+ ) => {
106
+ try {
107
+ for (const [key, getter] of Object.entries(accessors)) {
108
+ // 访问器仅用于字段对象读取,不参与属性遍历与字段配置透传
109
+ Object.defineProperty(raw, key, {
110
+ value: getter,
111
+ enumerable: false,
112
+ configurable: true,
113
+ writable: true,
114
+ });
115
+ }
116
+ } catch {
117
+ if (!warnedFrozenFields.has(raw)) {
118
+ warnedFrozenFields.add(raw);
119
+ console.warn(
120
+ '[pro-components] 字段配置对象不可写(如被 Object.freeze),getFormItemRef / getComponentRef 等实例访问器挂载失败。'
121
+ );
122
+ }
123
+ }
124
+ };
125
+
126
+ const setFormItemRef = (field: any, el: any, getFormItemProps: () => any) => {
127
+ if (!field || typeof field !== 'object') return;
128
+ const raw = toRaw(field);
129
+ if (el) {
130
+ formItemInstanceMap.set(raw, el);
131
+ defineFieldAccessors(raw, {
132
+ getFormItemRef: () => formItemInstanceMap.get(raw),
133
+ getFormItemComputedProps: getFormItemProps,
134
+ });
135
+ } else {
136
+ formItemInstanceMap.delete(raw);
137
+ delete raw.getFormItemRef;
138
+ delete raw.getFormItemComputedProps;
139
+ }
140
+ };
141
+
142
+ const setComponentRef = (field: any, el: any) => {
143
+ if (!field || typeof field !== 'object') return;
144
+ const raw = toRaw(field);
145
+ if (el) {
146
+ componentInstanceMap.set(raw, el);
147
+ defineFieldAccessors(raw, {
148
+ getComponentRef: () => componentInstanceMap.get(raw)?.getComponentRef(),
149
+ getComponentComputedProps: () =>
150
+ componentInstanceMap.get(raw)?.getComponentComputedProps(),
151
+ });
152
+ } else {
153
+ componentInstanceMap.delete(raw);
154
+ delete raw.getComponentRef;
155
+ delete raw.getComponentComputedProps;
156
+ }
157
+ };
158
+ </script>
159
+
160
+ <template>
161
+ <ElGrid v-if="enableGrid" v-bind="computedGridProps" style="width: 100%">
162
+ <BaseFormItem
163
+ v-for="item of renderedFields"
164
+ :key="item.key"
165
+ :field="item.field"
166
+ :grid="props.grid"
167
+ :disabled="props.disabled"
168
+ :set-form-item-ref="setFormItemRef"
169
+ :set-component-ref="setComponentRef"
170
+ />
171
+ </ElGrid>
172
+ <template v-else>
173
+ <BaseFormItem
174
+ v-for="item of renderedFields"
175
+ :key="item.key"
176
+ :field="item.field"
177
+ :grid="props.grid"
178
+ :disabled="props.disabled"
179
+ :set-form-item-ref="setFormItemRef"
180
+ :set-component-ref="setComponentRef"
181
+ />
182
+ </template>
183
+ </template>
@@ -6,12 +6,12 @@
6
6
  *
7
7
  * 架构设计说明 (Architecture Overview)
8
8
  *
9
- * [ 数据层 (Core) ] => [ 绑定层 (ProForm) ] => [ 渲染层 (BaseFormItem / BaseField) ]
9
+ * [ 数据层 (Core) ] => [ 绑定层 (ProForm) ] => [ 渲染层 (BaseFormItems / BaseFormItem / BaseField) ]
10
10
  *
11
11
  * 1. 数据隔离:ProForm 本身不负责存储和管理表单状态,所有核心状态(formData, fields, 校验规则)
12
12
  * 均交由底层的 `useForm`(@qin-ui/pro-components-core)驱动。
13
13
  * 2. 上下文透传:通过 `provide` 将核心状态下发给子组件。
14
- * 3. 递归渲染:网格布局和具体字段的解析交由 `<BaseFormItem>` 递归完成。
14
+ * 3. 递归渲染:网格布局和具体字段的解析交由 `<BaseFormItems>` 递归完成。
15
15
  *
16
16
  * @public
17
17
  *
@@ -57,7 +57,7 @@ import {
57
57
  type Slot,
58
58
  } from 'vue';
59
59
  import { INJECT_CONFIG } from '../../../component-provider/constants';
60
- import BaseFormItem from '../BaseFormItem/index.vue';
60
+ import BaseFormItems from '../BaseFormItems/index.vue';
61
61
  import { InjectionFormKey, InjectionFormSlotsKey } from '../../constants';
62
62
  import type { Grid, VModelProps, PathProps } from '../../types';
63
63
  import type { Path } from '../../../../shared/core';
@@ -178,7 +178,7 @@ provide(InjectionFormSlotsKey, formSlotsRef);
178
178
  class="pro-form"
179
179
  @submit.prevent
180
180
  >
181
- <BaseFormItem
181
+ <BaseFormItems
182
182
  :fields="fields"
183
183
  :grid="props.grid"
184
184
  :disabled="formDisabled"
@@ -3,12 +3,12 @@ import type {
3
3
  ComponentExposed,
4
4
  } from 'vue-component-type-helpers';
5
5
  import ProForm from './ProForm/index.vue';
6
- import BaseFormItem from './BaseFormItem/index.vue';
6
+ import BaseFormItems from './BaseFormItems/index.vue';
7
7
 
8
8
  export { default as BaseField } from './BaseField/index.vue';
9
9
  export { default as ContainerFragment } from './ContainerFragment/index.vue';
10
10
  export { default as SlotComponent } from './SlotComponent/index.vue';
11
- export { ProForm, BaseFormItem };
11
+ export { ProForm, BaseFormItems };
12
12
 
13
13
  // instance
14
14
  /** ProForm 组件实例 */
@@ -16,7 +16,7 @@ export type ProFormInstance = ComponentExposed<typeof ProForm>;
16
16
  /** ProForm 组件属性 */
17
17
  export type ProFormProps = ComponentProps<typeof ProForm>;
18
18
 
19
- /** BaseFormItem 组件实例(字段级 FormItem) */
20
- export type ProFormItemInstance = ComponentExposed<typeof BaseFormItem>;
21
- /** BaseFormItem 组件属性(字段级 FormItem) */
22
- export type ProFormItemProps = ComponentProps<typeof BaseFormItem>;
19
+ /** BaseFormItems 组件实例(字段级 FormItem) */
20
+ export type ProFormItemsInstance = ComponentExposed<typeof BaseFormItems>;
21
+ /** BaseFormItems 组件属性(字段级 FormItem) */
22
+ export type ProFormItemsProps = ComponentProps<typeof BaseFormItems>;