Custom Form 
Custom Form, using useFormComponentLogics with Ant Design UI
Basic 
To define a Form Component, there are three things we need to care:
- props
- emitter
- logics
About props, EzForm provide function getFormDefinePropsObject, let you define props easier. Then emit, you can define it by copy it from this article.
EzForm also provide a composable called useFormComponentLogics which receive props and emitter as parameters. This composable will handle almost logics for your Form. It will return a FormInstance and two functions called submit and reset. You can use them in template.
Now, let's see how our form component look like when be written with getFormDefinePropsObject and useFormComponentLogics.
<!-- AntForm.vue -->
<template>
	<form @submit.prevent="submit()" @reset.prevent="reset()">
		<slot
			:values="meta.values"
			:errors="meta.errors"
			:dirty="meta.dirty"
			:submit="submit"
			:reset="reset"
			:validate="validate"
			:getFieldValue="getFieldValue"
			:setFieldValue="setFieldValue"
			:isDirty="isDirty"
		/>
	</form>
</template>
<script lang="ts" setup>
import {
	getFormDefinePropsObject,
	useFormComponentLogics,
	ValidateError,
} from "@niku/ez-form";
export interface FormEmitter {
	(event: "submit", values: any): void;
	(event: "change", values: any): void;
	(event: "reset"): void;
	(event: "error", errors: ValidateError[]): void;
}
const props = defineProps(getFormDefinePropsObject());
const emit = defineEmits<FormEmitter>();
const { submit, reset, formInstance } = useFormComponentLogics(props, emit);
const { meta, setFieldValue, getFieldValue, validate, isDirty } = formInstance;
</script>So short, right? EzForm has done almost things. You just need to care about UI. How to use Ant Design? Let's see in next step.
Add Ant Design Style 
Form classes 
Just add class ant-form to our tag form.
<!-- AntForm.vue -->
<template>
	...
	<form class="ant-form" ... />
	...
</template>
<script lang="ts" setup>
...
</script>Customizable layout 
Ant Design let's us customize form layout by changing props. So, we will let our component can do the same.
Luckily, Ant Design also provide function formProps, so we can merge our props in previous step with Ant Design's props.
We will pick four props from formProps:
- layout
- labelCol
- labelAlign
- wrapperCol
<!-- AntForm.vue -->
<template>
	<form :class="['ant-form', `ant-form-${layout ?? 'vertical'}`]" ... />
</template>
<script lang="ts" setup>
import { formProps } from "ant-design-vue/es/form";
...
const props = defineProps({
	...getFormDefinePropsObject(),
	labelCol: formProps()["labelCol"],
	labelAlign: formProps()["labelAlign"],
	wrapperCol: formProps()["wrapperCol"],
	layout: formProps()["layout"],
});
...
</script>As you can see, form's property class changed to :class="['ant-form', `ant-form-${layout ?? 'vertical'}`]". That is prop layout, how about remain.
We will provide them, then use in custom FormItem.
Firstly, we need define a inject key and an interface.
// useInjectAntFormStyle.ts
import { ColProps } from "ant-design-vue";
import { FormLabelAlign } from "ant-design-vue/lib/form/interface";
import { inject } from "vue";
export const $injectFormStyleKey = Symbol("injectFormStyleKey");
export interface InjectFormStyle {
	labelCol?: ColProps;
	labelAlign?: FormLabelAlign;
	wrapperCol?: ColProps;
}Then, use them in our component file.
<!-- AntForm.vue -->
...
<script lang="ts" setup>
import {provide} from "vue";
import { $injectFormStyleKey, InjectFormStyle } from "./useInjectAntFormStyle";
...
provide<InjectFormStyle>($injectFormStyleKey, {
	get labelCol() {
		return props.labelCol;
	},
	get labelAlign() {
		return props.labelAlign;
	},
	get wrapperCol() {
		return props.wrapperCol;
	},
});
</script>That's all, our AntForm is completed.
Full source 
// useInjectAntFormStyle.ts
import { ColProps } from "ant-design-vue";
import { FormLabelAlign } from "ant-design-vue/lib/form/interface";
import { inject } from "vue";
export const $injectFormStyleKey = Symbol("injectFormStyleKey");
export interface InjectFormStyle {
	labelCol?: ColProps;
	labelAlign?: FormLabelAlign;
	wrapperCol?: ColProps;
}<!-- AntForm.vue -->
<template>
	<form
		:class="['ant-form', `ant-form-${layout ?? 'vertical'}`]"
		@submit.prevent="submit()"
		@reset.prevent="reset()"
	>
		<slot
			:values="meta.values"
			:errors="meta.errors"
			:dirty="meta.dirty"
			:submit="submit"
			:reset="reset"
			:validate="validate"
			:getFieldValue="getFieldValue"
			:setFieldValue="setFieldValue"
			:isDirty="isDirty"
		/>
	</form>
</template>
<script lang="ts" setup>
import { formProps } from "ant-design-vue/es/form";
import { provide } from "vue";
import {
	getFormDefinePropsObject,
	useFormComponentLogics,
	ValidateError,
} from "@niku/ez-form";
import { $injectFormStyleKey, InjectFormStyle } from "./useInjectAntFormStyle";
export interface FormEmitter {
	(event: "submit", values: any): void;
	(event: "change", values: any): void;
	(event: "reset"): void;
	(event: "error", errors: ValidateError[]): void;
}
const props = defineProps({
	...getFormDefinePropsObject(),
	labelCol: formProps()["labelCol"],
	labelAlign: formProps()["labelAlign"],
	wrapperCol: formProps()["wrapperCol"],
	layout: formProps()["layout"],
});
const emit = defineEmits<FormEmitter>();
const { submit, reset, formInstance } = useFormComponentLogics(props, emit);
const { meta, setFieldValue, getFieldValue, validate, isDirty } = formInstance;
provide<InjectFormStyle>($injectFormStyleKey, {
	get labelCol() {
		return props.labelCol;
	},
	get labelAlign() {
		return props.labelAlign;
	},
	get wrapperCol() {
		return props.wrapperCol;
	},
});
</script>Result 
The final result when you have done Custom FormItem and Custom FormList.
View Code
<template>
	<div class="example-box">
		<AntForm @submit="handleSubmit" @reset="handleReset">
			<AntFormItem label="Username" name="username">
				<a-input />
			</AntFormItem>
			<AntFormItem label="Password" name="password">
				<a-input-password />
			</AntFormItem>
			<a-space>
				<a-button html-type="submit" type="primary"> Submit </a-button>
				<a-button html-type="reset" type="default"> Reset </a-button>
			</a-space>
		</AntForm>
	</div>
</template>
<script lang="ts" setup>
import AntForm from "./AntForm.vue";
import AntFormItem from "./AntFormItem.vue";
const handleSubmit = (values: any) => {
	console.log("Form submit", values);
};
const handleReset = () => {
	console.log("Form reset");
};
</script> Ez Form
Ez Form