refactor: form
parent
0a2940e4ad
commit
3d2a04d23d
|
@ -13,11 +13,13 @@ const useProvideSize = <T = SizeType>(props: Record<any, any>): ComputedRef<T> =
|
||||||
return size;
|
return size;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useInjectSize = <T = SizeType>(): ComputedRef<T> => {
|
const useInjectSize = <T = SizeType>(props?: Record<any, any>): ComputedRef<T> => {
|
||||||
const size: ComputedRef<T> = inject(
|
const size: ComputedRef<T> = props
|
||||||
sizeProvider,
|
? computed(() => props.size)
|
||||||
computed(() => ('default' as unknown) as T),
|
: inject(
|
||||||
);
|
sizeProvider,
|
||||||
|
computed(() => ('default' as unknown) as T),
|
||||||
|
);
|
||||||
return size;
|
return size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { useInjectFormItemPrefix } from './context';
|
import { useInjectFormItemPrefix } from './context';
|
||||||
import { VueNode } from '../_util/type';
|
import { VueNode } from '../_util/type';
|
||||||
import { computed, defineComponent, ref, watch } from '@vue/runtime-core';
|
import { defineComponent, ref, watch } from '@vue/runtime-core';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import Transition, { getTransitionProps } from '../_util/transition';
|
import Transition, { getTransitionProps } from '../_util/transition';
|
||||||
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
|
||||||
export interface ErrorListProps {
|
export interface ErrorListProps {
|
||||||
errors?: VueNode[];
|
errors?: VueNode[];
|
||||||
|
@ -12,29 +13,53 @@ export interface ErrorListProps {
|
||||||
onDomErrorVisibleChange?: (visible: boolean) => void;
|
onDomErrorVisibleChange?: (visible: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent<ErrorListProps>({
|
export default defineComponent({
|
||||||
name: 'ErrorList',
|
name: 'ErrorList',
|
||||||
|
props: ['errors', 'help', 'onDomErrorVisibleChange'],
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
const { prefixCls: rootPrefixCls } = useConfigInject('', props);
|
||||||
const { prefixCls, status } = useInjectFormItemPrefix();
|
const { prefixCls, status } = useInjectFormItemPrefix();
|
||||||
const visible = computed(() => props.errors && props.errors.length);
|
const visible = ref(!!(props.errors && props.errors.length));
|
||||||
const innerStatus = ref(status.value);
|
const innerStatus = ref(status.value);
|
||||||
|
let timeout = ref();
|
||||||
|
watch([() => props.errors, () => props.help], () => {
|
||||||
|
window.clearTimeout(timeout.value);
|
||||||
|
if (props.help) {
|
||||||
|
visible.value = !!(props.errors && props.errors.length);
|
||||||
|
} else {
|
||||||
|
timeout.value = window.setTimeout(() => {
|
||||||
|
visible.value = !!(props.errors && props.errors.length);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
// Memo status in same visible
|
// Memo status in same visible
|
||||||
watch([() => visible, () => status], () => {
|
watch([visible, status], () => {
|
||||||
if (visible.value && status.value) {
|
if (visible.value && status.value) {
|
||||||
innerStatus.value = status.value;
|
innerStatus.value = status.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
watch(
|
||||||
|
visible,
|
||||||
|
() => {
|
||||||
|
if (visible.value) {
|
||||||
|
props.onDomErrorVisibleChange?.(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true, flush: 'post' },
|
||||||
|
);
|
||||||
return () => {
|
return () => {
|
||||||
const baseClassName = `${prefixCls.value}-item-explain`;
|
const baseClassName = `${prefixCls.value}-item-explain`;
|
||||||
const transitionProps = getTransitionProps('show-help', {
|
const transitionProps = getTransitionProps(`${rootPrefixCls.value}-show-help`, {
|
||||||
onAfterLeave: () => props.onDomErrorVisibleChange?.(false),
|
onAfterLeave: () => {
|
||||||
|
props.onDomErrorVisibleChange?.(false);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Transition {...transitionProps}>
|
<Transition {...transitionProps}>
|
||||||
{visible ? (
|
{visible.value ? (
|
||||||
<div
|
<div
|
||||||
class={classNames(baseClassName, {
|
class={classNames(baseClassName, {
|
||||||
[`${baseClassName}-${innerStatus}`]: innerStatus,
|
[`${baseClassName}-${innerStatus.value}`]: innerStatus.value,
|
||||||
})}
|
})}
|
||||||
key="help"
|
key="help"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
inject,
|
|
||||||
provide,
|
|
||||||
PropType,
|
PropType,
|
||||||
computed,
|
computed,
|
||||||
ExtractPropTypes,
|
ExtractPropTypes,
|
||||||
HTMLAttributes,
|
HTMLAttributes,
|
||||||
|
watch,
|
||||||
|
ref,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import warning from '../_util/warning';
|
import warning from '../_util/warning';
|
||||||
import FormItem from './FormItem';
|
import FormItem, { FieldExpose } from './FormItem';
|
||||||
import { getSlot } from '../_util/props-util';
|
|
||||||
import { defaultConfigProvider, SizeType } from '../config-provider';
|
|
||||||
import { getNamePath, containsNamePath } from './utils/valueUtil';
|
import { getNamePath, containsNamePath } from './utils/valueUtil';
|
||||||
import { defaultValidateMessages } from './utils/messages';
|
import { defaultValidateMessages } from './utils/messages';
|
||||||
import { allPromiseFinish } from './utils/asyncUtil';
|
import { allPromiseFinish } from './utils/asyncUtil';
|
||||||
|
@ -23,6 +21,10 @@ import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||||||
import { tuple, VueNode } from '../_util/type';
|
import { tuple, VueNode } from '../_util/type';
|
||||||
import { ColProps } from '../grid/Col';
|
import { ColProps } from '../grid/Col';
|
||||||
import { InternalNamePath, NamePath, ValidateErrorEntity, ValidateOptions } from './interface';
|
import { InternalNamePath, NamePath, ValidateErrorEntity, ValidateOptions } from './interface';
|
||||||
|
import { useInjectSize } from '../_util/hooks/useSize';
|
||||||
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
import { useProvideForm } from './context';
|
||||||
|
import { SizeType } from '../config-provider';
|
||||||
|
|
||||||
export type RequiredMark = boolean | 'optional';
|
export type RequiredMark = boolean | 'optional';
|
||||||
export type FormLayout = 'horizontal' | 'inline' | 'vertical';
|
export type FormLayout = 'horizontal' | 'inline' | 'vertical';
|
||||||
|
@ -61,7 +63,7 @@ export const formProps = {
|
||||||
colon: PropTypes.looseBool,
|
colon: PropTypes.looseBool,
|
||||||
labelAlign: PropTypes.oneOf(tuple('left', 'right')),
|
labelAlign: PropTypes.oneOf(tuple('left', 'right')),
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
requiredMark: { type: [String, Boolean] as PropType<RequiredMark> },
|
requiredMark: { type: [String, Boolean] as PropType<RequiredMark | ''>, default: undefined },
|
||||||
/** @deprecated Will warning in future branch. Pls use `requiredMark` instead. */
|
/** @deprecated Will warning in future branch. Pls use `requiredMark` instead. */
|
||||||
hideRequiredMark: PropTypes.looseBool,
|
hideRequiredMark: PropTypes.looseBool,
|
||||||
model: PropTypes.object,
|
model: PropTypes.object,
|
||||||
|
@ -93,92 +95,88 @@ const Form = defineComponent({
|
||||||
colon: true,
|
colon: true,
|
||||||
}),
|
}),
|
||||||
Item: FormItem,
|
Item: FormItem,
|
||||||
setup(props) {
|
emits: ['finishFailed', 'submit', 'finish'],
|
||||||
return {
|
setup(props, { emit, slots, expose }) {
|
||||||
configProvider: inject('configProvider', defaultConfigProvider),
|
const size = useInjectSize(props);
|
||||||
fields: [],
|
const { prefixCls, direction, form: contextForm } = useConfigInject('form', props);
|
||||||
form: undefined,
|
const requiredMark = computed(() => props.requiredMark === '' || props.requiredMark);
|
||||||
lastValidatePromise: null,
|
const mergedRequiredMark = computed(() => {
|
||||||
vertical: computed(() => props.layout === 'vertical'),
|
if (requiredMark.value !== undefined) {
|
||||||
|
return requiredMark.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contextForm && contextForm.value?.requiredMark !== undefined) {
|
||||||
|
return contextForm.value.requiredMark;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.hideRequiredMark) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const formClassName = computed(() =>
|
||||||
|
classNames(prefixCls.value, {
|
||||||
|
[`${prefixCls.value}-${props.layout}`]: true,
|
||||||
|
[`${prefixCls.value}-hide-required-mark`]: mergedRequiredMark.value === false,
|
||||||
|
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||||
|
[`${prefixCls.value}-${size.value}`]: size.value,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const lastValidatePromise = ref();
|
||||||
|
const fields: Record<string, FieldExpose> = {};
|
||||||
|
|
||||||
|
const addField = (eventKey: string, field: FieldExpose) => {
|
||||||
|
fields[eventKey] = field;
|
||||||
};
|
};
|
||||||
},
|
const removeField = (eventKey: string) => {
|
||||||
watch: {
|
delete fields[eventKey];
|
||||||
rules() {
|
};
|
||||||
if (this.validateOnRuleChange) {
|
|
||||||
this.validateFields();
|
const getFieldsByNameList = (nameList: NamePath) => {
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
provide('FormContext', this);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
addField(field: any) {
|
|
||||||
if (field) {
|
|
||||||
this.fields.push(field);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeField(field: any) {
|
|
||||||
if (field.fieldName) {
|
|
||||||
this.fields.splice(this.fields.indexOf(field), 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleSubmit(e: Event) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
this.$emit('submit', e);
|
|
||||||
const res = this.validateFields();
|
|
||||||
res
|
|
||||||
.then(values => {
|
|
||||||
this.$emit('finish', values);
|
|
||||||
})
|
|
||||||
.catch(errors => {
|
|
||||||
this.handleFinishFailed(errors);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getFieldsByNameList(nameList: NamePath) {
|
|
||||||
const provideNameList = !!nameList;
|
const provideNameList = !!nameList;
|
||||||
const namePathList = provideNameList ? toArray(nameList).map(getNamePath) : [];
|
const namePathList = provideNameList ? toArray(nameList).map(getNamePath) : [];
|
||||||
if (!provideNameList) {
|
if (!provideNameList) {
|
||||||
return this.fields;
|
return Object.values(fields);
|
||||||
} else {
|
} else {
|
||||||
return this.fields.filter(
|
return Object.values(fields).filter(
|
||||||
field => namePathList.findIndex(namePath => isEqualName(namePath, field.fieldName)) > -1,
|
field =>
|
||||||
|
namePathList.findIndex(namePath => isEqualName(namePath, field.fieldName.value)) > -1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
resetFields(name: NamePath) {
|
const resetFields = (name: NamePath) => {
|
||||||
if (!this.model) {
|
if (!props.model) {
|
||||||
warning(false, 'Form', 'model is required for resetFields to work.');
|
warning(false, 'Form', 'model is required for resetFields to work.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.getFieldsByNameList(name).forEach(field => {
|
getFieldsByNameList(name).forEach(field => {
|
||||||
field.resetField();
|
field.resetField();
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
clearValidate(name: NamePath) {
|
const clearValidate = (name: NamePath) => {
|
||||||
this.getFieldsByNameList(name).forEach(field => {
|
getFieldsByNameList(name).forEach(field => {
|
||||||
field.clearValidate();
|
field.clearValidate();
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
handleFinishFailed(errorInfo: ValidateErrorEntity) {
|
const handleFinishFailed = (errorInfo: ValidateErrorEntity) => {
|
||||||
const { scrollToFirstError } = this;
|
const { scrollToFirstError } = props;
|
||||||
this.$emit('finishFailed', errorInfo);
|
emit('finishFailed', errorInfo);
|
||||||
if (scrollToFirstError && errorInfo.errorFields.length) {
|
if (scrollToFirstError && errorInfo.errorFields.length) {
|
||||||
let scrollToFieldOptions: Options = {};
|
let scrollToFieldOptions: Options = {};
|
||||||
if (typeof scrollToFirstError === 'object') {
|
if (typeof scrollToFirstError === 'object') {
|
||||||
scrollToFieldOptions = scrollToFirstError;
|
scrollToFieldOptions = scrollToFirstError;
|
||||||
}
|
}
|
||||||
this.scrollToField(errorInfo.errorFields[0].name, scrollToFieldOptions);
|
scrollToField(errorInfo.errorFields[0].name, scrollToFieldOptions);
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
validate(...args: any[]) {
|
const validate = (...args: any[]) => {
|
||||||
return this.validateField(...args);
|
return validateField(...args);
|
||||||
},
|
};
|
||||||
scrollToField(name: NamePath, options = {}) {
|
const scrollToField = (name: NamePath, options = {}) => {
|
||||||
const fields = this.getFieldsByNameList(name);
|
const fields = getFieldsByNameList(name);
|
||||||
if (fields.length) {
|
if (fields.length) {
|
||||||
const fieldId = fields[0].fieldId;
|
const fieldId = fields[0].fieldId.value;
|
||||||
const node = fieldId ? document.getElementById(fieldId) : null;
|
const node = fieldId ? document.getElementById(fieldId) : null;
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
|
@ -189,12 +187,12 @@ const Form = defineComponent({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
getFieldsValue(nameList: NamePath[] | true = true) {
|
const getFieldsValue = (nameList: NamePath[] | true = true) => {
|
||||||
const values: any = {};
|
const values: any = {};
|
||||||
this.fields.forEach(({ fieldName, fieldValue }) => {
|
Object.values(fields).forEach(({ fieldName, fieldValue }) => {
|
||||||
values[fieldName] = fieldValue;
|
values[fieldName.value] = fieldValue.value;
|
||||||
});
|
});
|
||||||
if (nameList === true) {
|
if (nameList === true) {
|
||||||
return values;
|
return values;
|
||||||
|
@ -205,14 +203,14 @@ const Form = defineComponent({
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
validateFields(nameList?: NamePath[], options?: ValidateOptions) {
|
const validateFields = (nameList?: NamePath[], options?: ValidateOptions) => {
|
||||||
warning(
|
warning(
|
||||||
!(nameList instanceof Function),
|
!(nameList instanceof Function),
|
||||||
'Form',
|
'Form',
|
||||||
'validateFields/validateField/validate not support callback, please use promise instead',
|
'validateFields/validateField/validate not support callback, please use promise instead',
|
||||||
);
|
);
|
||||||
if (!this.model) {
|
if (!props.model) {
|
||||||
warning(false, 'Form', 'model is required for validateFields to work.');
|
warning(false, 'Form', 'model is required for validateFields to work.');
|
||||||
return Promise.reject('Form `model` is required for validateFields to work.');
|
return Promise.reject('Form `model` is required for validateFields to work.');
|
||||||
}
|
}
|
||||||
|
@ -227,25 +225,25 @@ const Form = defineComponent({
|
||||||
errors: string[];
|
errors: string[];
|
||||||
}>[] = [];
|
}>[] = [];
|
||||||
|
|
||||||
this.fields.forEach(field => {
|
Object.values(fields).forEach(field => {
|
||||||
// Add field if not provide `nameList`
|
// Add field if not provide `nameList`
|
||||||
if (!provideNameList) {
|
if (!provideNameList) {
|
||||||
namePathList.push(field.getNamePath());
|
namePathList.push(field.namePath.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip if without rule
|
// Skip if without rule
|
||||||
if (!field.getRules().length) {
|
if (!field.rules?.value.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fieldNamePath = field.getNamePath();
|
const fieldNamePath = field.namePath.value;
|
||||||
|
|
||||||
// Add field validate rule in to promise list
|
// Add field validate rule in to promise list
|
||||||
if (!provideNameList || containsNamePath(namePathList, fieldNamePath)) {
|
if (!provideNameList || containsNamePath(namePathList, fieldNamePath)) {
|
||||||
const promise = field.validateRules({
|
const promise = field.validateRules({
|
||||||
validateMessages: {
|
validateMessages: {
|
||||||
...defaultValidateMessages,
|
...defaultValidateMessages,
|
||||||
...this.validateMessages,
|
...props.validateMessages,
|
||||||
},
|
},
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
@ -265,21 +263,21 @@ const Form = defineComponent({
|
||||||
});
|
});
|
||||||
|
|
||||||
const summaryPromise = allPromiseFinish(promiseList);
|
const summaryPromise = allPromiseFinish(promiseList);
|
||||||
this.lastValidatePromise = summaryPromise;
|
lastValidatePromise.value = summaryPromise;
|
||||||
|
|
||||||
const returnPromise = summaryPromise
|
const returnPromise = summaryPromise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (this.lastValidatePromise === summaryPromise) {
|
if (lastValidatePromise.value === summaryPromise) {
|
||||||
return Promise.resolve(this.getFieldsValue(namePathList));
|
return Promise.resolve(getFieldsValue(namePathList));
|
||||||
}
|
}
|
||||||
return Promise.reject([]);
|
return Promise.reject([]);
|
||||||
})
|
})
|
||||||
.catch(results => {
|
.catch(results => {
|
||||||
const errorList = results.filter(result => result && result.errors.length);
|
const errorList = results.filter(result => result && result.errors.length);
|
||||||
return Promise.reject({
|
return Promise.reject({
|
||||||
values: this.getFieldsValue(namePathList),
|
values: getFieldsValue(namePathList),
|
||||||
errorFields: errorList,
|
errorFields: errorList,
|
||||||
outOfDate: this.lastValidatePromise !== summaryPromise,
|
outOfDate: lastValidatePromise.value !== summaryPromise,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -287,29 +285,65 @@ const Form = defineComponent({
|
||||||
returnPromise.catch(e => e);
|
returnPromise.catch(e => e);
|
||||||
|
|
||||||
return returnPromise;
|
return returnPromise;
|
||||||
},
|
};
|
||||||
validateField(...args: any[]) {
|
const validateField = (...args: any[]) => {
|
||||||
return this.validateFields(...args);
|
return validateFields(...args);
|
||||||
},
|
};
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
const handleSubmit = (e: Event) => {
|
||||||
const { prefixCls: customizePrefixCls, hideRequiredMark, layout, handleSubmit, size } = this;
|
e.preventDefault();
|
||||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
e.stopPropagation();
|
||||||
const prefixCls = getPrefixCls('form', customizePrefixCls);
|
emit('submit', e);
|
||||||
const { class: className, ...restProps } = this.$attrs;
|
const res = validateFields();
|
||||||
|
res
|
||||||
|
.then(values => {
|
||||||
|
emit('finish', values);
|
||||||
|
})
|
||||||
|
.catch(errors => {
|
||||||
|
handleFinishFailed(errors);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const formClassName = classNames(prefixCls, className, {
|
expose({
|
||||||
[`${prefixCls}-${layout}`]: true,
|
resetFields,
|
||||||
// [`${prefixCls}-rtl`]: direction === 'rtl',
|
clearValidate,
|
||||||
[`${prefixCls}-${size}`]: size,
|
validateFields,
|
||||||
[`${prefixCls}-hide-required-mark`]: hideRequiredMark,
|
getFieldsValue,
|
||||||
|
validate,
|
||||||
|
scrollToField,
|
||||||
});
|
});
|
||||||
return (
|
|
||||||
<form onSubmit={handleSubmit} class={formClassName} {...restProps}>
|
useProvideForm({
|
||||||
{getSlot(this)}
|
model: computed(() => props.model),
|
||||||
</form>
|
name: computed(() => props.name),
|
||||||
|
labelAlign: computed(() => props.labelAlign),
|
||||||
|
labelCol: computed(() => props.labelCol),
|
||||||
|
wrapperCol: computed(() => props.wrapperCol),
|
||||||
|
vertical: computed(() => props.layout === 'vertical'),
|
||||||
|
colon: computed(() => props.colon),
|
||||||
|
requiredMark: mergedRequiredMark,
|
||||||
|
validateTrigger: computed(() => props.validateTrigger),
|
||||||
|
rules: computed(() => props.rules),
|
||||||
|
addField,
|
||||||
|
removeField,
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.rules,
|
||||||
|
() => {
|
||||||
|
if (props.validateOnRuleChange) {
|
||||||
|
validateFields();
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit} class={formClassName.value}>
|
||||||
|
{slots.default?.()}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,50 +1,47 @@
|
||||||
import {
|
import {
|
||||||
inject,
|
|
||||||
provide,
|
|
||||||
PropType,
|
PropType,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
computed,
|
computed,
|
||||||
nextTick,
|
nextTick,
|
||||||
ExtractPropTypes,
|
ExtractPropTypes,
|
||||||
|
ref,
|
||||||
|
watchEffect,
|
||||||
|
onBeforeUnmount,
|
||||||
|
ComputedRef,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import cloneDeep from 'lodash-es/cloneDeep';
|
import cloneDeep from 'lodash-es/cloneDeep';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import classNames from '../_util/classNames';
|
|
||||||
import { getTransitionProps, Transition } from '../_util/transition';
|
|
||||||
import Row from '../grid/Row';
|
import Row from '../grid/Row';
|
||||||
import Col, { ColProps } from '../grid/Col';
|
import { ColProps } from '../grid/Col';
|
||||||
import hasProp, {
|
import { isValidElement, flattenChildren } from '../_util/props-util';
|
||||||
findDOMNode,
|
|
||||||
getComponent,
|
|
||||||
getOptionProps,
|
|
||||||
getEvents,
|
|
||||||
isValidElement,
|
|
||||||
getSlot,
|
|
||||||
} from '../_util/props-util';
|
|
||||||
import BaseMixin from '../_util/BaseMixin';
|
import BaseMixin from '../_util/BaseMixin';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
|
||||||
import { cloneElement } from '../_util/vnode';
|
import { cloneElement } from '../_util/vnode';
|
||||||
import CheckCircleFilled from '@ant-design/icons-vue/CheckCircleFilled';
|
import { validateRules as validateRulesUtil } from './utils/validateUtil';
|
||||||
import ExclamationCircleFilled from '@ant-design/icons-vue/ExclamationCircleFilled';
|
|
||||||
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
|
|
||||||
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
|
|
||||||
import { validateRules } from './utils/validateUtil';
|
|
||||||
import { getNamePath } from './utils/valueUtil';
|
import { getNamePath } from './utils/valueUtil';
|
||||||
import { toArray } from './utils/typeUtil';
|
import { toArray } from './utils/typeUtil';
|
||||||
import { warning } from '../vc-util/warning';
|
import { warning } from '../vc-util/warning';
|
||||||
import find from 'lodash-es/find';
|
import find from 'lodash-es/find';
|
||||||
import { tuple, VueNode } from '../_util/type';
|
import { tuple } from '../_util/type';
|
||||||
import { ValidateOptions } from './interface';
|
import { InternalNamePath, RuleObject, ValidateOptions } from './interface';
|
||||||
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
import { useInjectForm } from './context';
|
||||||
|
import FormItemLabel from './FormItemLabel';
|
||||||
|
import FormItemInput from './FormItemInput';
|
||||||
|
import { ValidationRule } from './Form';
|
||||||
|
|
||||||
const ValidateStatuses = tuple('success', 'warning', 'error', 'validating', '');
|
const ValidateStatuses = tuple('success', 'warning', 'error', 'validating', '');
|
||||||
export type ValidateStatus = typeof ValidateStatuses[number];
|
export type ValidateStatus = typeof ValidateStatuses[number];
|
||||||
|
|
||||||
const iconMap = {
|
export interface FieldExpose {
|
||||||
success: CheckCircleFilled,
|
fieldValue: ComputedRef<any>;
|
||||||
warning: ExclamationCircleFilled,
|
fieldId: ComputedRef<any>;
|
||||||
error: CloseCircleFilled,
|
fieldName: ComputedRef<any>;
|
||||||
validating: LoadingOutlined,
|
resetField: () => void;
|
||||||
};
|
clearValidate: () => void;
|
||||||
|
namePath: ComputedRef<InternalNamePath>;
|
||||||
|
rules?: ComputedRef<ValidationRule[]>;
|
||||||
|
validateRules: (options: ValidateOptions) => Promise<void> | Promise<string[]>;
|
||||||
|
}
|
||||||
|
|
||||||
function getPropByPath(obj: any, namePathList: any, strict?: boolean) {
|
function getPropByPath(obj: any, namePathList: any, strict?: boolean) {
|
||||||
let tempObj = obj;
|
let tempObj = obj;
|
||||||
|
@ -103,15 +100,25 @@ export const formItemProps = {
|
||||||
|
|
||||||
export type FormItemProps = Partial<ExtractPropTypes<typeof formItemProps>>;
|
export type FormItemProps = Partial<ExtractPropTypes<typeof formItemProps>>;
|
||||||
|
|
||||||
|
let indexGuid = 0;
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'AFormItem',
|
name: 'AFormItem',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
__ANT_NEW_FORM_ITEM: true,
|
__ANT_NEW_FORM_ITEM: true,
|
||||||
props: formItemProps,
|
props: formItemProps,
|
||||||
setup(props) {
|
slots: ['help', 'label', 'extra'],
|
||||||
const FormContext = inject('FormContext', {}) as any;
|
setup(props, { slots }) {
|
||||||
|
warning(props.prop === undefined, `\`prop\` is deprecated. Please use \`name\` instead.`);
|
||||||
|
const eventKey = `form-item-${++indexGuid}`;
|
||||||
|
const { prefixCls } = useConfigInject('form', props);
|
||||||
|
const formContext = useInjectForm();
|
||||||
const fieldName = computed(() => props.name || props.prop);
|
const fieldName = computed(() => props.name || props.prop);
|
||||||
|
const errors = ref([]);
|
||||||
|
const validateMessage = ref('');
|
||||||
|
const validateDisabled = ref(false);
|
||||||
|
const domErrorVisible = ref(false);
|
||||||
|
const inputRef = ref();
|
||||||
const namePath = computed(() => {
|
const namePath = computed(() => {
|
||||||
const val = fieldName.value;
|
const val = fieldName.value;
|
||||||
return getNamePath(val);
|
return getNamePath(val);
|
||||||
|
@ -123,26 +130,30 @@ export default defineComponent({
|
||||||
} else if (!namePath.value.length) {
|
} else if (!namePath.value.length) {
|
||||||
return undefined;
|
return undefined;
|
||||||
} else {
|
} else {
|
||||||
const formName = FormContext.name;
|
const formName = formContext.name.value;
|
||||||
const mergedId = namePath.value.join('_');
|
const mergedId = namePath.value.join('_');
|
||||||
return formName ? `${formName}_${mergedId}` : mergedId;
|
return formName ? `${formName}_${mergedId}` : mergedId;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const fieldValue = computed(() => {
|
const fieldValue = computed(() => {
|
||||||
const model = FormContext.model;
|
const model = formContext.model.value;
|
||||||
if (!model || !fieldName.value) {
|
if (!model || !fieldName.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return getPropByPath(model, namePath.value, true).v;
|
return getPropByPath(model, namePath.value, true).v;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const initialValue = ref(cloneDeep(fieldValue.value));
|
||||||
const mergedValidateTrigger = computed(() => {
|
const mergedValidateTrigger = computed(() => {
|
||||||
let validateTrigger =
|
let validateTrigger =
|
||||||
props.validateTrigger !== undefined ? props.validateTrigger : FormContext.validateTrigger;
|
props.validateTrigger !== undefined
|
||||||
|
? props.validateTrigger
|
||||||
|
: formContext.validateTrigger.value;
|
||||||
validateTrigger = validateTrigger === undefined ? 'change' : validateTrigger;
|
validateTrigger = validateTrigger === undefined ? 'change' : validateTrigger;
|
||||||
return toArray(validateTrigger);
|
return toArray(validateTrigger);
|
||||||
});
|
});
|
||||||
const getRules = () => {
|
const rulesRef = computed<ValidationRule[]>(() => {
|
||||||
let formRules = FormContext.rules;
|
let formRules = formContext.rules.value;
|
||||||
const selfRules = props.rules;
|
const selfRules = props.rules;
|
||||||
const requiredRule =
|
const requiredRule =
|
||||||
props.required !== undefined
|
props.required !== undefined
|
||||||
|
@ -156,9 +167,9 @@ export default defineComponent({
|
||||||
} else {
|
} else {
|
||||||
return rules.concat(requiredRule);
|
return rules.concat(requiredRule);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const isRequired = computed(() => {
|
const isRequired = computed(() => {
|
||||||
const rules = getRules();
|
const rules = rulesRef.value;
|
||||||
let isRequired = false;
|
let isRequired = false;
|
||||||
if (rules && rules.length) {
|
if (rules && rules.length) {
|
||||||
rules.every(rule => {
|
rules.every(rule => {
|
||||||
|
@ -171,360 +182,234 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
return isRequired || props.required;
|
return isRequired || props.required;
|
||||||
});
|
});
|
||||||
return {
|
|
||||||
isFormItemChildren: inject('isFormItemChildren', false),
|
|
||||||
configProvider: inject('configProvider', defaultConfigProvider),
|
|
||||||
FormContext,
|
|
||||||
fieldId,
|
|
||||||
fieldName,
|
|
||||||
namePath,
|
|
||||||
isRequired,
|
|
||||||
getRules,
|
|
||||||
fieldValue,
|
|
||||||
mergedValidateTrigger,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
warning(!hasProp(this, 'prop'), `\`prop\` is deprecated. Please use \`name\` instead.`);
|
|
||||||
return {
|
|
||||||
validateState: this.validateStatus,
|
|
||||||
validateMessage: '',
|
|
||||||
validateDisabled: false,
|
|
||||||
validator: {},
|
|
||||||
helpShow: false,
|
|
||||||
errors: [],
|
|
||||||
initialValue: undefined,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
validateStatus(val) {
|
|
||||||
this.validateState = val;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
provide('isFormItemChildren', true);
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
if (this.fieldName) {
|
|
||||||
const { addField } = this.FormContext;
|
|
||||||
addField && addField(this);
|
|
||||||
this.initialValue = cloneDeep(this.fieldValue);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
const { removeField } = this.FormContext;
|
|
||||||
removeField && removeField(this);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getNamePath() {
|
|
||||||
const { fieldName } = this;
|
|
||||||
const { prefixName = [] } = this.FormContext;
|
|
||||||
|
|
||||||
return fieldName !== undefined ? [...prefixName, ...this.namePath] : [];
|
const validateState = ref();
|
||||||
},
|
watchEffect(() => {
|
||||||
validateRules(options: ValidateOptions) {
|
validateState.value = props.validateStatus;
|
||||||
const { validateFirst = false, messageVariables } = this.$props;
|
});
|
||||||
|
|
||||||
|
const validateRules = (options: ValidateOptions) => {
|
||||||
|
const { validateFirst = false, messageVariables } = props;
|
||||||
const { triggerName } = options || {};
|
const { triggerName } = options || {};
|
||||||
const namePath = this.getNamePath();
|
|
||||||
|
|
||||||
let filteredRules = this.getRules();
|
let filteredRules = rulesRef.value;
|
||||||
if (triggerName) {
|
if (triggerName) {
|
||||||
filteredRules = filteredRules.filter(rule => {
|
filteredRules = filteredRules.filter(rule => {
|
||||||
const { trigger } = rule;
|
const { trigger } = rule;
|
||||||
if (!trigger && !this.mergedValidateTrigger.length) {
|
if (!trigger && !mergedValidateTrigger.value.length) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const triggerList = toArray(trigger || this.mergedValidateTrigger);
|
const triggerList = toArray(trigger || mergedValidateTrigger.value);
|
||||||
return triggerList.includes(triggerName);
|
return triggerList.includes(triggerName);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!filteredRules.length) {
|
if (!filteredRules.length) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
const promise = validateRules(
|
const promise = validateRulesUtil(
|
||||||
namePath,
|
namePath.value,
|
||||||
this.fieldValue,
|
fieldValue.value,
|
||||||
filteredRules,
|
filteredRules as RuleObject[],
|
||||||
options,
|
options,
|
||||||
validateFirst,
|
validateFirst,
|
||||||
messageVariables,
|
messageVariables,
|
||||||
);
|
);
|
||||||
this.validateState = 'validating';
|
validateState.value = 'validating';
|
||||||
this.errors = [];
|
errors.value = [];
|
||||||
|
|
||||||
promise
|
promise
|
||||||
.catch(e => e)
|
.catch(e => e)
|
||||||
.then((errors = []) => {
|
.then((ers = []) => {
|
||||||
if (this.validateState === 'validating') {
|
if (validateState.value === 'validating') {
|
||||||
this.validateState = errors.length ? 'error' : 'success';
|
validateState.value = ers.length ? 'error' : 'success';
|
||||||
this.validateMessage = errors[0];
|
validateMessage.value = ers[0];
|
||||||
this.errors = errors;
|
errors.value = ers;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
},
|
};
|
||||||
onFieldBlur() {
|
|
||||||
this.validateRules({ triggerName: 'blur' });
|
const onFieldBlur = () => {
|
||||||
},
|
validateRules({ triggerName: 'blur' });
|
||||||
onFieldChange() {
|
};
|
||||||
if (this.validateDisabled) {
|
const onFieldChange = () => {
|
||||||
this.validateDisabled = false;
|
if (validateDisabled.value) {
|
||||||
|
validateDisabled.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.validateRules({ triggerName: 'change' });
|
validateRules({ triggerName: 'change' });
|
||||||
},
|
};
|
||||||
clearValidate() {
|
const clearValidate = () => {
|
||||||
this.validateState = '';
|
validateState.value = '';
|
||||||
this.validateMessage = '';
|
validateMessage.value = '';
|
||||||
this.validateDisabled = false;
|
validateDisabled.value = false;
|
||||||
},
|
};
|
||||||
resetField() {
|
|
||||||
this.validateState = '';
|
const resetField = () => {
|
||||||
this.validateMessage = '';
|
validateState.value = '';
|
||||||
const model = this.FormContext.model || {};
|
validateMessage.value = '';
|
||||||
const value = this.fieldValue;
|
const model = formContext.model.value || {};
|
||||||
const prop = getPropByPath(model, this.namePath, true);
|
const value = fieldValue.value;
|
||||||
this.validateDisabled = true;
|
const prop = getPropByPath(model, namePath.value, true);
|
||||||
|
validateDisabled.value = true;
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
prop.o[prop.k] = [].concat(this.initialValue);
|
prop.o[prop.k] = [].concat(initialValue.value);
|
||||||
} else {
|
} else {
|
||||||
prop.o[prop.k] = this.initialValue;
|
prop.o[prop.k] = initialValue.value;
|
||||||
}
|
}
|
||||||
// reset validateDisabled after onFieldChange triggered
|
// reset validateDisabled after onFieldChange triggered
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
this.validateDisabled = false;
|
validateDisabled.value = false;
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
getHelpMessage() {
|
|
||||||
const help = getComponent(this, 'help');
|
|
||||||
|
|
||||||
return this.validateMessage || help;
|
const onLabelClick = () => {
|
||||||
},
|
const id = fieldId.value;
|
||||||
|
if (!id || !inputRef.value) {
|
||||||
onLabelClick() {
|
|
||||||
const id = this.fieldId;
|
|
||||||
if (!id) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const formItemNode = findDOMNode(this);
|
const control = inputRef.value.$el.querySelector(`[id="${id}"]`);
|
||||||
const control = formItemNode.querySelector(`[id="${id}"]`);
|
|
||||||
if (control && control.focus) {
|
if (control && control.focus) {
|
||||||
control.focus();
|
control.focus();
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
formContext.addField(eventKey, {
|
||||||
|
fieldValue,
|
||||||
|
fieldId,
|
||||||
|
fieldName,
|
||||||
|
resetField,
|
||||||
|
clearValidate,
|
||||||
|
namePath,
|
||||||
|
validateRules,
|
||||||
|
rules: rulesRef,
|
||||||
|
});
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
formContext.removeField(eventKey);
|
||||||
|
});
|
||||||
|
// const onHelpAnimEnd = (_key: string, helpShow: boolean) => {
|
||||||
|
// this.helpShow = helpShow;
|
||||||
|
// if (!helpShow) {
|
||||||
|
// this.$forceUpdate();
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
const itemClassName = computed(() => ({
|
||||||
|
[`${prefixCls.value}-item`]: true,
|
||||||
|
|
||||||
onHelpAnimEnd(_key: string, helpShow: boolean) {
|
// Status
|
||||||
this.helpShow = helpShow;
|
[`${prefixCls.value}-item-has-feedback`]: validateState.value && props.hasFeedback,
|
||||||
if (!helpShow) {
|
[`${prefixCls.value}-item-has-success`]: validateState.value === 'success',
|
||||||
this.$forceUpdate();
|
[`${prefixCls.value}-item-has-warning`]: validateState.value === 'warning',
|
||||||
}
|
[`${prefixCls.value}-item-has-error`]: validateState.value === 'error',
|
||||||
},
|
[`${prefixCls.value}-item-is-validating`]: validateState.value === 'validating',
|
||||||
|
[`${prefixCls.value}-item-hidden`]: props.hidden,
|
||||||
renderHelp(prefixCls: string) {
|
}));
|
||||||
const help = this.getHelpMessage();
|
return () => {
|
||||||
const children = help ? (
|
const help = props.help ?? slots.help?.();
|
||||||
<div class={`${prefixCls}-explain`} key="help">
|
const children = flattenChildren(slots.default?.());
|
||||||
{help}
|
let firstChildren = children[0];
|
||||||
</div>
|
if (fieldName.value && props.autoLink && isValidElement(firstChildren)) {
|
||||||
) : null;
|
const originalEvents = firstChildren.props;
|
||||||
if (children) {
|
const originalBlur = originalEvents.onBlur;
|
||||||
this.helpShow = !!children;
|
const originalChange = originalEvents.onChange;
|
||||||
}
|
firstChildren = cloneElement(firstChildren, {
|
||||||
const transitionProps = getTransitionProps('show-help', {
|
...(fieldId.value ? { id: fieldId.value } : undefined),
|
||||||
onAfterEnter: () => this.onHelpAnimEnd('help', true),
|
onBlur: (...args: any[]) => {
|
||||||
onAfterLeave: () => this.onHelpAnimEnd('help', false),
|
if (Array.isArray(originalChange)) {
|
||||||
});
|
for (let i = 0, l = originalChange.length; i < l; i++) {
|
||||||
return (
|
originalBlur[i](...args);
|
||||||
<Transition {...transitionProps} key="help">
|
}
|
||||||
{children}
|
} else if (originalBlur) {
|
||||||
</Transition>
|
originalBlur(...args);
|
||||||
);
|
}
|
||||||
},
|
onFieldBlur();
|
||||||
|
},
|
||||||
renderExtra(prefixCls: string) {
|
onChange: (...args: any[]) => {
|
||||||
const extra = getComponent(this, 'extra');
|
if (Array.isArray(originalChange)) {
|
||||||
return extra ? <div class={`${prefixCls}-extra`}>{extra}</div> : null;
|
for (let i = 0, l = originalChange.length; i < l; i++) {
|
||||||
},
|
originalChange[i](...args);
|
||||||
|
}
|
||||||
renderValidateWrapper(prefixCls: string, c1: VueNode, c2: VueNode, c3: VueNode) {
|
} else if (originalChange) {
|
||||||
const validateStatus = this.validateState;
|
originalChange(...args);
|
||||||
|
}
|
||||||
let classes = `${prefixCls}-item-control`;
|
onFieldChange();
|
||||||
if (validateStatus) {
|
},
|
||||||
classes = classNames(`${prefixCls}-item-control`, {
|
|
||||||
'has-feedback': validateStatus && this.hasFeedback,
|
|
||||||
'has-success': validateStatus === 'success',
|
|
||||||
'has-warning': validateStatus === 'warning',
|
|
||||||
'has-error': validateStatus === 'error',
|
|
||||||
'is-validating': validateStatus === 'validating',
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const IconNode = validateStatus && iconMap[validateStatus];
|
|
||||||
|
|
||||||
const icon =
|
|
||||||
this.hasFeedback && IconNode ? (
|
|
||||||
<span class={`${prefixCls}-item-children-icon`}>
|
|
||||||
<IconNode />
|
|
||||||
</span>
|
|
||||||
) : null;
|
|
||||||
return (
|
return (
|
||||||
<div class={classes}>
|
<Row
|
||||||
<span class={`${prefixCls}-item-children`}>
|
class={[
|
||||||
{c1}
|
itemClassName.value,
|
||||||
{icon}
|
domErrorVisible.value || !!help ? `${prefixCls.value}-item-with-help` : '',
|
||||||
</span>
|
]}
|
||||||
{c2}
|
key="row"
|
||||||
{c3}
|
>
|
||||||
</div>
|
{/* Label */}
|
||||||
);
|
<FormItemLabel
|
||||||
},
|
{...props}
|
||||||
|
htmlFor={fieldId.value}
|
||||||
renderWrapper(prefixCls: string, children: VueNode) {
|
required={isRequired.value}
|
||||||
const { wrapperCol: contextWrapperCol } = (this.isFormItemChildren
|
requiredMark={formContext.requiredMark.value}
|
||||||
? {}
|
prefixCls={prefixCls.value}
|
||||||
: this.FormContext) as any;
|
onClick={onLabelClick}
|
||||||
const { wrapperCol } = this;
|
label={props.label ?? slots.label?.()}
|
||||||
const mergedWrapperCol = wrapperCol || contextWrapperCol || {};
|
/>
|
||||||
const { style, id, ...restProps } = mergedWrapperCol;
|
{/* Input Group */}
|
||||||
const className = classNames(`${prefixCls}-item-control`, mergedWrapperCol.class);
|
<FormItemInput
|
||||||
const colProps = {
|
{...props}
|
||||||
...restProps,
|
errors={errors.value}
|
||||||
class: className,
|
prefixCls={prefixCls.value}
|
||||||
key: 'wrapper',
|
status={validateState.value}
|
||||||
style,
|
onDomErrorVisibleChange={(v: boolean) => (domErrorVisible.value = v)}
|
||||||
id,
|
validateStatus={validateState.value}
|
||||||
};
|
ref={inputRef}
|
||||||
return <Col {...colProps}>{children}</Col>;
|
help={help}
|
||||||
},
|
extra={props.extra ?? slots.extra?.()}
|
||||||
|
|
||||||
renderLabel(prefixCls: string) {
|
|
||||||
const {
|
|
||||||
vertical,
|
|
||||||
labelAlign: contextLabelAlign,
|
|
||||||
labelCol: contextLabelCol,
|
|
||||||
colon: contextColon,
|
|
||||||
} = this.FormContext;
|
|
||||||
const { labelAlign, labelCol, colon, fieldId, htmlFor } = this;
|
|
||||||
const label = getComponent(this, 'label');
|
|
||||||
const required = this.isRequired;
|
|
||||||
const mergedLabelCol = labelCol || contextLabelCol || {};
|
|
||||||
|
|
||||||
const mergedLabelAlign = labelAlign || contextLabelAlign;
|
|
||||||
const labelClsBasic = `${prefixCls}-item-label`;
|
|
||||||
const labelColClassName = classNames(
|
|
||||||
labelClsBasic,
|
|
||||||
mergedLabelAlign === 'left' && `${labelClsBasic}-left`,
|
|
||||||
mergedLabelCol.class,
|
|
||||||
);
|
|
||||||
const {
|
|
||||||
class: labelColClass,
|
|
||||||
style: labelColStyle,
|
|
||||||
id: labelColId,
|
|
||||||
...restProps
|
|
||||||
} = mergedLabelCol;
|
|
||||||
let labelChildren = label;
|
|
||||||
// Keep label is original where there should have no colon
|
|
||||||
const computedColon = colon === true || (contextColon !== false && colon !== false);
|
|
||||||
const haveColon = computedColon && !vertical;
|
|
||||||
// Remove duplicated user input colon
|
|
||||||
if (haveColon && typeof label === 'string' && label.trim() !== '') {
|
|
||||||
labelChildren = label.replace(/[::]\s*$/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
const labelClassName = classNames({
|
|
||||||
[`${prefixCls}-item-required`]: required,
|
|
||||||
[`${prefixCls}-item-no-colon`]: !computedColon,
|
|
||||||
});
|
|
||||||
const colProps = {
|
|
||||||
...restProps,
|
|
||||||
class: labelColClassName,
|
|
||||||
key: 'label',
|
|
||||||
style: labelColStyle,
|
|
||||||
id: labelColId,
|
|
||||||
};
|
|
||||||
|
|
||||||
return label ? (
|
|
||||||
<Col {...colProps}>
|
|
||||||
<label
|
|
||||||
for={htmlFor || fieldId}
|
|
||||||
class={labelClassName}
|
|
||||||
title={typeof label === 'string' ? label : ''}
|
|
||||||
onClick={this.onLabelClick}
|
|
||||||
>
|
>
|
||||||
{labelChildren}
|
{[firstChildren, children.slice(1)]}
|
||||||
</label>
|
</FormItemInput>
|
||||||
</Col>
|
|
||||||
) : null;
|
|
||||||
},
|
|
||||||
renderChildren(prefixCls: string, child: VueNode) {
|
|
||||||
return [
|
|
||||||
this.renderLabel(prefixCls),
|
|
||||||
this.renderWrapper(
|
|
||||||
prefixCls,
|
|
||||||
this.renderValidateWrapper(
|
|
||||||
prefixCls,
|
|
||||||
child,
|
|
||||||
this.renderHelp(prefixCls),
|
|
||||||
this.renderExtra(prefixCls),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
},
|
|
||||||
renderFormItem(child: any[]) {
|
|
||||||
const validateStatus = this.validateState;
|
|
||||||
const { prefixCls: customizePrefixCls, hidden, hasFeedback } = this.$props;
|
|
||||||
const { class: className, ...restProps } = this.$attrs as any;
|
|
||||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
|
||||||
const prefixCls = getPrefixCls('form', customizePrefixCls);
|
|
||||||
const children = this.renderChildren(prefixCls, child);
|
|
||||||
const itemClassName = {
|
|
||||||
[className]: className,
|
|
||||||
[`${prefixCls}-item`]: true,
|
|
||||||
[`${prefixCls}-item-with-help`]: this.helpShow,
|
|
||||||
|
|
||||||
// Status
|
|
||||||
[`${prefixCls}-item-has-feedback`]: validateStatus && hasFeedback,
|
|
||||||
[`${prefixCls}-item-has-success`]: validateStatus === 'success',
|
|
||||||
[`${prefixCls}-item-has-warning`]: validateStatus === 'warning',
|
|
||||||
[`${prefixCls}-item-has-error`]: validateStatus === 'error',
|
|
||||||
[`${prefixCls}-item-is-validating`]: validateStatus === 'validating',
|
|
||||||
[`${prefixCls}-item-hidden`]: hidden,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Row class={classNames(itemClassName)} key="row" {...restProps}>
|
|
||||||
{children}
|
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
},
|
};
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const { autoLink } = getOptionProps(this);
|
|
||||||
const children = getSlot(this);
|
|
||||||
let firstChildren = children[0];
|
|
||||||
if (this.fieldName && autoLink && isValidElement(firstChildren)) {
|
|
||||||
const originalEvents = getEvents(firstChildren);
|
|
||||||
const originalBlur = originalEvents.onBlur;
|
|
||||||
const originalChange = originalEvents.onChange;
|
|
||||||
firstChildren = cloneElement(firstChildren, {
|
|
||||||
...(this.fieldId ? { id: this.fieldId } : undefined),
|
|
||||||
onBlur: (...args: any[]) => {
|
|
||||||
originalBlur && originalBlur(...args);
|
|
||||||
this.onFieldBlur();
|
|
||||||
},
|
|
||||||
onChange: (...args: any[]) => {
|
|
||||||
if (Array.isArray(originalChange)) {
|
|
||||||
for (let i = 0, l = originalChange.length; i < l; i++) {
|
|
||||||
originalChange[i](...args);
|
|
||||||
}
|
|
||||||
} else if (originalChange) {
|
|
||||||
originalChange(...args);
|
|
||||||
}
|
|
||||||
this.onFieldChange();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return this.renderFormItem([firstChildren, children.slice(1)]);
|
|
||||||
},
|
},
|
||||||
|
// data() {
|
||||||
|
// warning(!hasProp(this, 'prop'), `\`prop\` is deprecated. Please use \`name\` instead.`);
|
||||||
|
// return {
|
||||||
|
// validateState: this.validateStatus,
|
||||||
|
// validateMessage: '',
|
||||||
|
// validateDisabled: false,
|
||||||
|
// validator: {},
|
||||||
|
// helpShow: false,
|
||||||
|
// errors: [],
|
||||||
|
// initialValue: undefined,
|
||||||
|
// };
|
||||||
|
// },
|
||||||
|
// render() {
|
||||||
|
// const { autoLink } = getOptionProps(this);
|
||||||
|
// const children = getSlot(this);
|
||||||
|
// let firstChildren = children[0];
|
||||||
|
// if (this.fieldName && autoLink && isValidElement(firstChildren)) {
|
||||||
|
// const originalEvents = getEvents(firstChildren);
|
||||||
|
// const originalBlur = originalEvents.onBlur;
|
||||||
|
// const originalChange = originalEvents.onChange;
|
||||||
|
// firstChildren = cloneElement(firstChildren, {
|
||||||
|
// ...(this.fieldId ? { id: this.fieldId } : undefined),
|
||||||
|
// onBlur: (...args: any[]) => {
|
||||||
|
// originalBlur && originalBlur(...args);
|
||||||
|
// this.onFieldBlur();
|
||||||
|
// },
|
||||||
|
// onChange: (...args: any[]) => {
|
||||||
|
// if (Array.isArray(originalChange)) {
|
||||||
|
// for (let i = 0, l = originalChange.length; i < l; i++) {
|
||||||
|
// originalChange[i](...args);
|
||||||
|
// }
|
||||||
|
// } else if (originalChange) {
|
||||||
|
// originalChange(...args);
|
||||||
|
// }
|
||||||
|
// this.onFieldChange();
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// return this.renderFormItem([firstChildren, children.slice(1)]);
|
||||||
|
// },
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@ import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
|
||||||
import CheckCircleFilled from '@ant-design/icons-vue/CheckCircleFilled';
|
import CheckCircleFilled from '@ant-design/icons-vue/CheckCircleFilled';
|
||||||
import ExclamationCircleFilled from '@ant-design/icons-vue/ExclamationCircleFilled';
|
import ExclamationCircleFilled from '@ant-design/icons-vue/ExclamationCircleFilled';
|
||||||
|
|
||||||
import Col, { ColProps } from '../grid/col';
|
import Col, { ColProps } from '../grid/Col';
|
||||||
import { useProvideForm, useInjectForm, useProvideFormItemPrefix } from './context';
|
import { useProvideForm, useInjectForm, useProvideFormItemPrefix } from './context';
|
||||||
import ErrorList from './ErrorList';
|
import ErrorList from './ErrorList';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
|
@ -11,7 +11,7 @@ import { ValidateStatus } from './FormItem';
|
||||||
import { VueNode } from '../_util/type';
|
import { VueNode } from '../_util/type';
|
||||||
import { computed, defineComponent, HTMLAttributes, onUnmounted } from 'vue';
|
import { computed, defineComponent, HTMLAttributes, onUnmounted } from 'vue';
|
||||||
|
|
||||||
interface FormItemInputMiscProps {
|
export interface FormItemInputMiscProps {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
errors: VueNode[];
|
errors: VueNode[];
|
||||||
hasFeedback?: boolean;
|
hasFeedback?: boolean;
|
||||||
|
@ -32,8 +32,20 @@ const iconMap: { [key: string]: any } = {
|
||||||
error: CloseCircleFilled,
|
error: CloseCircleFilled,
|
||||||
validating: LoadingOutlined,
|
validating: LoadingOutlined,
|
||||||
};
|
};
|
||||||
const FormItemInput = defineComponent<FormItemInputProps & FormItemInputMiscProps>({
|
const FormItemInput = defineComponent({
|
||||||
slots: ['help', 'extra', 'errors'],
|
slots: ['help', 'extra', 'errors'],
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: [
|
||||||
|
'prefixCls',
|
||||||
|
'errors',
|
||||||
|
'hasFeedback',
|
||||||
|
'validateStatus',
|
||||||
|
'onDomErrorVisibleChange',
|
||||||
|
'wrapperCol',
|
||||||
|
'help',
|
||||||
|
'extra',
|
||||||
|
'status',
|
||||||
|
],
|
||||||
setup(props, { slots }) {
|
setup(props, { slots }) {
|
||||||
const formContext = useInjectForm();
|
const formContext = useInjectForm();
|
||||||
const { wrapperCol: contextWrapperCol } = formContext;
|
const { wrapperCol: contextWrapperCol } = formContext;
|
||||||
|
@ -43,12 +55,15 @@ const FormItemInput = defineComponent<FormItemInputProps & FormItemInputMiscProp
|
||||||
delete subFormContext.labelCol;
|
delete subFormContext.labelCol;
|
||||||
delete subFormContext.wrapperCol;
|
delete subFormContext.wrapperCol;
|
||||||
useProvideForm(subFormContext);
|
useProvideForm(subFormContext);
|
||||||
|
|
||||||
useProvideFormItemPrefix({
|
useProvideFormItemPrefix({
|
||||||
prefixCls: computed(() => props.prefixCls),
|
prefixCls: computed(() => props.prefixCls),
|
||||||
status: computed(() => props.status),
|
status: computed(() => props.status),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
props.onDomErrorVisibleChange(false);
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
|
@ -67,10 +82,6 @@ const FormItemInput = defineComponent<FormItemInputProps & FormItemInputMiscProp
|
||||||
|
|
||||||
const className = classNames(`${baseClassName}-control`, mergedWrapperCol.class);
|
const className = classNames(`${baseClassName}-control`, mergedWrapperCol.class);
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
onDomErrorVisibleChange(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Should provides additional icon if `hasFeedback`
|
// Should provides additional icon if `hasFeedback`
|
||||||
const IconNode = validateStatus && iconMap[validateStatus];
|
const IconNode = validateStatus && iconMap[validateStatus];
|
||||||
const icon =
|
const icon =
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Col, { ColProps } from '../grid/col';
|
import Col, { ColProps } from '../grid/Col';
|
||||||
import { FormLabelAlign } from './interface';
|
import { FormLabelAlign } from './interface';
|
||||||
import { useInjectForm } from './context';
|
import { useInjectForm } from './context';
|
||||||
import { RequiredMark } from './Form';
|
import { RequiredMark } from './Form';
|
||||||
|
@ -17,10 +17,14 @@ export interface FormItemLabelProps {
|
||||||
requiredMark?: RequiredMark;
|
requiredMark?: RequiredMark;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
onClick: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FormItemLabel: FunctionalComponent<FormItemLabelProps> = (props, { slots }) => {
|
const FormItemLabel: FunctionalComponent<FormItemLabelProps> = (props, { slots, emit, attrs }) => {
|
||||||
const { prefixCls, htmlFor, labelCol, labelAlign, colon, required, requiredMark } = props;
|
const { prefixCls, htmlFor, labelCol, labelAlign, colon, required, requiredMark } = {
|
||||||
|
...props,
|
||||||
|
...attrs,
|
||||||
|
};
|
||||||
const [formLocale] = useLocaleReceiver('Form');
|
const [formLocale] = useLocaleReceiver('Form');
|
||||||
const label = props.label ?? slots.label?.();
|
const label = props.label ?? slots.label?.();
|
||||||
if (!label) return null;
|
if (!label) return null;
|
||||||
|
@ -68,7 +72,6 @@ const FormItemLabel: FunctionalComponent<FormItemLabelProps> = (props, { slots }
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelClassName = classNames({
|
const labelClassName = classNames({
|
||||||
[`${prefixCls}-item-required`]: required,
|
[`${prefixCls}-item-required`]: required,
|
||||||
[`${prefixCls}-item-required-mark-optional`]: requiredMark === 'optional',
|
[`${prefixCls}-item-required-mark-optional`]: requiredMark === 'optional',
|
||||||
|
@ -80,6 +83,7 @@ const FormItemLabel: FunctionalComponent<FormItemLabelProps> = (props, { slots }
|
||||||
html-for={htmlFor}
|
html-for={htmlFor}
|
||||||
class={labelClassName}
|
class={labelClassName}
|
||||||
title={typeof label === 'string' ? label : ''}
|
title={typeof label === 'string' ? label : ''}
|
||||||
|
onClick={e => emit('click', e)}
|
||||||
>
|
>
|
||||||
{labelChildren}
|
{labelChildren}
|
||||||
</label>
|
</label>
|
||||||
|
@ -88,5 +92,6 @@ const FormItemLabel: FunctionalComponent<FormItemLabelProps> = (props, { slots }
|
||||||
};
|
};
|
||||||
|
|
||||||
FormItemLabel.displayName = 'FormItemLabel';
|
FormItemLabel.displayName = 'FormItemLabel';
|
||||||
|
FormItemLabel.inheritAttrs = false;
|
||||||
|
|
||||||
export default FormItemLabel;
|
export default FormItemLabel;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { inject, InjectionKey, provide, ComputedRef, computed } from 'vue';
|
import { inject, InjectionKey, provide, ComputedRef, computed } from 'vue';
|
||||||
import { ColProps } from '../grid';
|
import { ColProps } from '../grid';
|
||||||
import { RequiredMark } from './Form';
|
import { RequiredMark, ValidationRule } from './Form';
|
||||||
import { ValidateStatus } from './FormItem';
|
import { ValidateStatus, FieldExpose } from './FormItem';
|
||||||
import { FormLabelAlign } from './interface';
|
import { FormLabelAlign } from './interface';
|
||||||
|
|
||||||
export interface FormContextProps {
|
export interface FormContextProps {
|
||||||
|
model?: ComputedRef<any>;
|
||||||
vertical: ComputedRef<boolean>;
|
vertical: ComputedRef<boolean>;
|
||||||
name?: ComputedRef<string>;
|
name?: ComputedRef<string>;
|
||||||
colon?: ComputedRef<boolean>;
|
colon?: ComputedRef<boolean>;
|
||||||
|
@ -13,6 +14,10 @@ export interface FormContextProps {
|
||||||
wrapperCol?: ComputedRef<ColProps>;
|
wrapperCol?: ComputedRef<ColProps>;
|
||||||
requiredMark?: ComputedRef<RequiredMark>;
|
requiredMark?: ComputedRef<RequiredMark>;
|
||||||
//itemRef: (name: (string | number)[]) => (node: React.ReactElement) => void;
|
//itemRef: (name: (string | number)[]) => (node: React.ReactElement) => void;
|
||||||
|
addField: (eventKey: string, field: FieldExpose) => void;
|
||||||
|
removeField: (eventKey: string) => void;
|
||||||
|
validateTrigger?: ComputedRef<string | string[]>;
|
||||||
|
rules?: ComputedRef<{ [k: string]: ValidationRule[] | ValidationRule }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FormContextKey: InjectionKey<FormContextProps> = Symbol('formContextKey');
|
export const FormContextKey: InjectionKey<FormContextProps> = Symbol('formContextKey');
|
||||||
|
@ -25,6 +30,10 @@ export const useInjectForm = () => {
|
||||||
return inject(FormContextKey, {
|
return inject(FormContextKey, {
|
||||||
labelAlign: computed(() => 'right' as FormLabelAlign),
|
labelAlign: computed(() => 'right' as FormLabelAlign),
|
||||||
vertical: computed(() => false),
|
vertical: computed(() => false),
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
addField: (_eventKey: string, _field: FieldExpose) => {},
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
removeField: (_eventKey: string) => {},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { inject, defineComponent, CSSProperties, ExtractPropTypes, computed } from 'vue';
|
import { defineComponent, CSSProperties, ExtractPropTypes, computed } from 'vue';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { rowContextState } from './Row';
|
|
||||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import { useInjectRow } from './context';
|
import { useInjectRow } from './context';
|
||||||
|
|
||||||
|
@ -102,7 +101,7 @@ export default defineComponent({
|
||||||
const mergedStyle = computed(() => {
|
const mergedStyle = computed(() => {
|
||||||
const { flex } = props;
|
const { flex } = props;
|
||||||
const gutterVal = gutter.value;
|
const gutterVal = gutter.value;
|
||||||
let style: CSSProperties = {};
|
const style: CSSProperties = {};
|
||||||
// Horizontal gutter use padding
|
// Horizontal gutter use padding
|
||||||
if (gutterVal && gutterVal[0] > 0) {
|
if (gutterVal && gutterVal[0] > 0) {
|
||||||
const horizontalGutter = `${gutterVal[0] / 2}px`;
|
const horizontalGutter = `${gutterVal[0] / 2}px`;
|
||||||
|
|
|
@ -211,7 +211,7 @@ export default defineComponent({
|
||||||
return (
|
return (
|
||||||
<aside {...attrs} class={siderCls} style={divStyle} ref={ref}>
|
<aside {...attrs} class={siderCls} style={divStyle} ref={ref}>
|
||||||
<div class={`${pre}-children`}>{slots.default?.()}</div>
|
<div class={`${pre}-children`}>{slots.default?.()}</div>
|
||||||
{collapsible || (below && zeroWidthTrigger) ? triggerDom : null}
|
{collapsible || (below.value && zeroWidthTrigger) ? triggerDom : null}
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,8 +3,7 @@ import classNames from '../_util/classNames';
|
||||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import { skeletonElementProps, SkeletonElementProps } from './Element';
|
import { skeletonElementProps, SkeletonElementProps } from './Element';
|
||||||
|
|
||||||
export interface SkeletonImageProps
|
export type SkeletonImageProps = Omit<SkeletonElementProps, 'size' | 'shape' | 'active'>;
|
||||||
extends Omit<SkeletonElementProps, 'size' | 'shape' | 'active'> {}
|
|
||||||
|
|
||||||
const path =
|
const path =
|
||||||
'M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z';
|
'M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z';
|
||||||
|
|
|
@ -12,8 +12,8 @@ export const skeletonParagraphProps = {
|
||||||
export type SkeletonParagraphProps = Partial<ExtractPropTypes<typeof skeletonParagraphProps>>;
|
export type SkeletonParagraphProps = Partial<ExtractPropTypes<typeof skeletonParagraphProps>>;
|
||||||
|
|
||||||
const SkeletonParagraph = defineComponent({
|
const SkeletonParagraph = defineComponent({
|
||||||
props: skeletonParagraphProps,
|
|
||||||
name: 'SkeletonParagraph',
|
name: 'SkeletonParagraph',
|
||||||
|
props: skeletonParagraphProps,
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const getWidth = (index: number) => {
|
const getWidth = (index: number) => {
|
||||||
const { width, rows = 2 } = props;
|
const { width, rows = 2 } = props;
|
||||||
|
|
|
@ -10,7 +10,7 @@ import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import Element from './Element';
|
import Element from './Element';
|
||||||
|
|
||||||
/* This only for skeleton internal. */
|
/* This only for skeleton internal. */
|
||||||
interface SkeletonAvatarProps extends Omit<AvatarProps, 'active'> {}
|
type SkeletonAvatarProps = Omit<AvatarProps, 'active'>;
|
||||||
|
|
||||||
export const skeletonProps = {
|
export const skeletonProps = {
|
||||||
active: PropTypes.looseBool,
|
active: PropTypes.looseBool,
|
||||||
|
|
|
@ -9,8 +9,8 @@ export const skeletonTitleProps = {
|
||||||
export type SkeletonTitleProps = Partial<ExtractPropTypes<typeof skeletonTitleProps>>;
|
export type SkeletonTitleProps = Partial<ExtractPropTypes<typeof skeletonTitleProps>>;
|
||||||
|
|
||||||
const SkeletonTitle = defineComponent({
|
const SkeletonTitle = defineComponent({
|
||||||
props: skeletonTitleProps,
|
|
||||||
name: 'SkeletonTitle',
|
name: 'SkeletonTitle',
|
||||||
|
props: skeletonTitleProps,
|
||||||
setup(props) {
|
setup(props) {
|
||||||
return () => {
|
return () => {
|
||||||
const { prefixCls, width } = props;
|
const { prefixCls, width } = props;
|
||||||
|
|
Loading…
Reference in New Issue