feat: Schema 中 componentProps 随注册组件联动类型提示

This commit is contained in:
dullathanol
2026-04-03 01:39:49 +08:00
parent 128a131797
commit a6433c2b50
18 changed files with 698 additions and 132 deletions

View File

@@ -0,0 +1,96 @@
import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
/**
* 对象形式:使用适配器里为各 `component` 声明的 Props 类型 `P`
* 与 `Record<string, any>` 相交是为了满足核心库 `MaybeComponentProps` 的索引签名。
* 函数形式:通过联合 `CoreFormSchema['componentProps']`,与表单核心对动态 `componentProps` 的约定保持一致。
*/
type SchemaComponentProps<P> =
| CoreFormSchema<ComponentType>['componentProps']
| (P & Record<string, any>);
/**
* 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
*/
interface FormSchemaComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof FormSchemaComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: SchemaComponentProps<FormSchemaComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@@ -1,9 +1,7 @@
import type {
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui';
import type { ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -41,9 +39,14 @@ async function initSetupVbenForm() {
});
}
const useVbenForm = useForm<ComponentType>;
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z };
export type VbenFormSchema = FormSchema<ComponentType>;
export type { VbenFormProps };
export type { VbenFormProps, VbenFormSchema };

View File

@@ -0,0 +1,96 @@
import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RangePickerProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'antdv-next';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
/**
* 对象形式:使用适配器里为各 `component` 声明的 Props 类型 `P`
* 与 `Record<string, any>` 相交是为了满足核心库 `MaybeComponentProps` 的索引签名。
* 函数形式:通过联合 `CoreFormSchema['componentProps']`,与表单核心对动态 `componentProps` 的约定保持一致。
*/
type SchemaComponentProps<P> =
| CoreFormSchema<ComponentType>['componentProps']
| (P & Record<string, any>);
/**
* 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
*/
interface FormSchemaComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof FormSchemaComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: SchemaComponentProps<FormSchemaComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@@ -1,9 +1,7 @@
import type {
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui';
import type { ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -41,9 +39,14 @@ async function initSetupVbenForm() {
});
}
const useVbenForm = useForm<ComponentType>;
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z };
export type VbenFormSchema = FormSchema<ComponentType>;
export type { VbenFormProps };
export type { VbenFormProps, VbenFormSchema };

View File

@@ -0,0 +1,80 @@
import type {
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
ElTimePicker,
ElTreeSelect,
InputNumberProps,
InputProps,
RadioGroupProps,
SelectV2Props,
SpaceProps,
SwitchProps,
UploadProps,
} from 'element-plus';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
type ElTreeSelectSchemaProps = InstanceType<typeof ElTreeSelect>['$props'];
type ElTimePickerSchemaProps = InstanceType<typeof ElTimePicker>['$props'];
/**
* 对象形式:使用适配器里为各 `component` 声明的 Props 类型 `P`
* 与 `Record<string, any>` 相交是为了满足核心库 `MaybeComponentProps` 的索引签名。
* 函数形式:通过联合 `CoreFormSchema['componentProps']`,与表单核心对动态 `componentProps` 的约定保持一致。
*/
type SchemaComponentProps<P> =
| CoreFormSchema<ComponentType>['componentProps']
| (P & Record<string, any>);
/**
* 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
*/
interface FormSchemaComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectV2Props;
ApiTreeSelect: ApiComponentSharedProps & ElTreeSelectSchemaProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
RadioGroup: RadioGroupProps;
Select: SelectV2Props;
Space: SpaceProps;
Switch: SwitchProps;
TimePicker: ElTimePickerSchemaProps;
TreeSelect: ElTreeSelectSchemaProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof FormSchemaComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: SchemaComponentProps<FormSchemaComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@@ -1,9 +1,7 @@
import type {
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui';
import type { ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -33,9 +31,14 @@ async function initSetupVbenForm() {
});
}
const useVbenForm = useForm<ComponentType>;
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z };
export type VbenFormSchema = FormSchema<ComponentType>;
export type { VbenFormProps };
export type { VbenFormProps, VbenFormSchema };

View File

@@ -0,0 +1,77 @@
import type {
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
RadioGroupProps,
SelectProps,
SpaceProps,
SwitchProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'naive-ui';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
/**
* 对象形式:使用适配器里为各 `component` 声明的 Props 类型 `P`
* 与 `Record<string, any>` 相交是为了满足核心库 `MaybeComponentProps` 的索引签名。
* 函数形式:通过联合 `CoreFormSchema['componentProps']`,与表单核心对动态 `componentProps` 的约定保持一致。
*/
type SchemaComponentProps<P> =
| CoreFormSchema<ComponentType>['componentProps']
| (P & Record<string, any>);
/**
* 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
*/
interface FormSchemaComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
RadioGroup: RadioGroupProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof FormSchemaComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: SchemaComponentProps<FormSchemaComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@@ -1,9 +1,7 @@
import type {
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui';
import type { ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -37,9 +35,14 @@ async function initSetupVbenForm() {
});
}
const useVbenForm = useForm<ComponentType>;
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z };
export type VbenFormSchema = FormSchema<ComponentType>;
export type { VbenFormProps };
export type { VbenFormProps, VbenFormSchema };

View File

@@ -0,0 +1,90 @@
import type {
AutoCompleteProps,
ButtonProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DateRangePickerProps,
DividerProps,
InputNumberProps,
InputProps,
RadioGroupProps,
RadioProps,
SelectProps,
SpaceProps,
SwitchProps,
TextareaProps,
TimePickerProps,
TreeSelectProps,
} from 'tdesign-vue-next';
import type { TdRateProps } from 'tdesign-vue-next/es/rate/type';
import type { UploadProps } from 'tdesign-vue-next/es/upload/types';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
/**
* 对象形式:使用适配器里为各 `component` 声明的 Props 类型 `P`
* 与 `Record<string, any>` 相交是为了满足核心库 `MaybeComponentProps` 的索引签名。
* 函数形式:通过联合 `CoreFormSchema['componentProps']`,与表单核心对动态 `componentProps` 的约定保持一致。
*/
type SchemaComponentProps<P> =
| CoreFormSchema<ComponentType>['componentProps']
| (P & Record<string, any>);
/**
* 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
*/
interface FormSchemaComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: DateRangePickerProps;
Rate: TdRateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextareaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof FormSchemaComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: SchemaComponentProps<FormSchemaComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@@ -1,9 +1,7 @@
import type {
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui';
import type { ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -41,9 +39,14 @@ async function initSetupVbenForm() {
});
}
const useVbenForm = useForm<ComponentType>;
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z };
export type VbenFormSchema = FormSchema<ComponentType>;
export type { VbenFormProps };
export type { VbenFormProps, VbenFormSchema };

View File

@@ -1,7 +1,8 @@
<script lang="ts" setup>
import type { Component } from 'vue';
import type { AnyPromiseFunction } from '@vben/types';
import type {
ApiComponentProps,
ApiComponentOptionsItem as OptionsItem,
} from './types';
import { computed, nextTick, ref, unref, useAttrs, watch } from 'vue';
@@ -11,72 +12,9 @@ import { cloneDeep, get, isEqual, isFunction } from '@vben-core/shared/utils';
import { objectOmit } from '@vueuse/core';
type OptionsItem = {
[name: string]: any;
children?: OptionsItem[];
disabled?: boolean;
label?: string;
value?: string;
};
interface Props {
/** 组件 */
component: Component;
/** 是否将value从数字转为string */
numberToString?: boolean;
/** 获取options数据的函数 */
api?: (arg?: any) => Promise<OptionsItem[] | Record<string, any>>;
/** 传递给api的参数 */
params?: Record<string, any>;
/** 从api返回的结果中提取options数组的字段名 */
resultField?: string;
/** label字段名 */
labelField?: string;
/** children字段名需要层级数据的组件可用 */
childrenField?: string;
/** value字段名 */
valueField?: string;
/** disabled字段名 */
disabledField?: string;
/** 组件接收options数据的属性名 */
optionsPropName?: string;
/** 是否立即调用api */
immediate?: boolean;
/** 每次`visibleEvent`事件发生时都重新请求数据 */
alwaysLoad?: boolean;
/** 在api请求之前的回调函数 */
beforeFetch?: AnyPromiseFunction<any, any>;
/** 在api请求之前的判断是否允许请求的回调函数 */
shouldFetch?: AnyPromiseFunction<any, boolean>;
/** 在api请求之后的回调函数 */
afterFetch?: AnyPromiseFunction<any, any>;
/** 直接传入选项数据也作为api返回空数据时的后备数据 */
options?: OptionsItem[];
/** 组件的插槽名称,用来显示一个"加载中"的图标 */
loadingSlot?: string;
/** 触发api请求的事件名 */
visibleEvent?: string;
/** 组件的v-model属性名默认为modelValue。部分组件可能为value */
modelPropName?: string;
/**
* 自动选择
* - `first`:自动选择第一个选项
* - `last`:自动选择最后一个选项
* - `one`: 当请求的结果只有一个选项时,自动选择该选项
* - 函数:自定义选择逻辑,函数的参数为请求的结果数组,返回值为选择的选项
* - false不自动选择(默认)
*/
autoSelect?:
| 'first'
| 'last'
| 'one'
| ((item: OptionsItem[]) => OptionsItem)
| false;
}
defineOptions({ name: 'ApiComponent', inheritAttrs: false });
const props = withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps<ApiComponentProps>(), {
labelField: 'label',
valueField: 'value',
disabledField: 'disabled',

View File

@@ -1 +1,6 @@
export { default as ApiComponent } from './api-component.vue';
export type {
ApiComponentOptionsItem,
ApiComponentProps,
ApiComponentSharedProps,
} from './types';

View File

@@ -0,0 +1,68 @@
import type { Component } from 'vue';
import type { AnyPromiseFunction } from '@vben/types';
export type ApiComponentOptionsItem = {
[name: string]: any;
children?: ApiComponentOptionsItem[];
disabled?: boolean;
label?: string;
value?: string;
};
export interface ApiComponentProps {
/** 组件 */
component: Component;
/** 是否将value从数字转为string */
numberToString?: boolean;
/** 获取options数据的函数 */
api?: (arg?: any) => Promise<ApiComponentOptionsItem[] | Record<string, any>>;
/** 传递给api的参数 */
params?: Record<string, any>;
/** 从api返回的结果中提取options数组的字段名 */
resultField?: string;
/** label字段名 */
labelField?: string;
/** children字段名需要层级数据的组件可用 */
childrenField?: string;
/** value字段名 */
valueField?: string;
/** disabled字段名 */
disabledField?: string;
/** 组件接收options数据的属性名 */
optionsPropName?: string;
/** 是否立即调用api */
immediate?: boolean;
/** 每次`visibleEvent`事件发生时都重新请求数据 */
alwaysLoad?: boolean;
/** 在api请求之前的回调函数 */
beforeFetch?: AnyPromiseFunction<any, any>;
/** 在api请求之前的判断是否允许请求的回调函数 */
shouldFetch?: AnyPromiseFunction<any, boolean>;
/** 在api请求之后的回调函数 */
afterFetch?: AnyPromiseFunction<any, any>;
/** 直接传入选项数据也作为api返回空数据时的后备数据 */
options?: ApiComponentOptionsItem[];
/** 组件的插槽名称,用来显示一个"加载中"的图标 */
loadingSlot?: string;
/** 触发api请求的事件名 */
visibleEvent?: string;
/** 组件的v-model属性名默认为modelValue。部分组件可能为value */
modelPropName?: string;
/**
* 自动选择
* - `first`:自动选择第一个选项
* - `last`:自动选择最后一个选项
* - `one`: 当请求的结果只有一个选项时,自动选择该选项
* - 函数:自定义选择逻辑,函数的参数为请求的结果数组,返回值为选择的选项
* - false不自动选择(默认)
*/
autoSelect?:
| 'first'
| 'last'
| 'one'
| ((item: ApiComponentOptionsItem[]) => ApiComponentOptionsItem)
| false;
}
export type ApiComponentSharedProps = Omit<ApiComponentProps, 'component'>;

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { VNode } from 'vue';
import type { IconPickerProps } from './types';
import { computed, ref, useAttrs, watch, watchEffect } from 'vue';
@@ -28,28 +28,7 @@ import { objectOmit, refDebounced, watchDebounced } from '@vueuse/core';
import { fetchIconsData } from './icons';
interface Props {
pageSize?: number;
/** 图标集的名字 */
prefix?: string;
/** 是否自动请求API以获得图标集的数据.提供prefix时有效 */
autoFetchApi?: boolean;
/**
* 图标列表
*/
icons?: string[];
/** Input组件 */
inputComponent?: VNode;
/** 图标插槽名,预览图标将被渲染到此插槽中 */
iconSlot?: string;
/** input组件的值属性名称 */
modelValueProp?: string;
/** 图标样式 */
iconClass?: string;
type?: 'icon' | 'input';
}
const props = withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps<IconPickerProps>(), {
prefix: 'ant-design',
pageSize: 36,
icons: () => [],

View File

@@ -1 +1,2 @@
export { default as IconPicker } from './icon-picker.vue';
export type { IconPickerProps } from './types';

View File

@@ -0,0 +1,22 @@
import type { VNode } from 'vue';
export interface IconPickerProps {
pageSize?: number;
/** 图标集的名字 */
prefix?: string;
/** 是否自动请求API以获得图标集的数据.提供prefix时有效 */
autoFetchApi?: boolean;
/**
* 图标列表
*/
icons?: string[];
/** Input组件 */
inputComponent?: VNode;
/** 图标插槽名,预览图标将被渲染到此插槽中 */
iconSlot?: string;
/** input组件的值属性名称 */
modelValueProp?: string;
/** 图标样式 */
iconClass?: string;
type?: 'icon' | 'input';
}

View File

@@ -0,0 +1,96 @@
import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
/**
* 对象形式:使用适配器里为各 `component` 声明的 Props 类型 `P`
* 与 `Record<string, any>` 相交是为了满足核心库 `MaybeComponentProps` 的索引签名。
* 函数形式:通过联合 `CoreFormSchema['componentProps']`,与表单核心对动态 `componentProps` 的约定保持一致。
*/
type SchemaComponentProps<P> =
| CoreFormSchema<ComponentType>['componentProps']
| (P & Record<string, any>);
/**
* 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
*/
interface FormSchemaComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof FormSchemaComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: SchemaComponentProps<FormSchemaComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@@ -1,9 +1,7 @@
import type {
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui';
import type { ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -40,8 +38,13 @@ async function initSetupVbenForm() {
});
}
const useVbenForm = useForm<ComponentType>;
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z };
export type VbenFormSchema = FormSchema<ComponentType>;
export type { VbenFormProps };
export type { VbenFormProps, VbenFormSchema };