UNPKG

@volverjs/form-vue

Version:

Vue 3 Forms with @volverjs/ui-vue

199 lines (193 loc) 7.82 kB
import type { Component, DeepReadonly, InjectionKey, PropType, SlotsType, VNode } from 'vue' import type { FormSchema, InjectedFormData, FormTemplate, RenderFunctionOutput, InferFormattedError, InferSchema, } from './types' import type { FormStatus } from './enums' import { getProperty } from 'dot-prop' import { defineComponent, h, inject, unref, } from 'vue' export function defineFormTemplate<Schema extends FormSchema, Type = undefined>(formProvideKey: InjectionKey<InjectedFormData<Schema, Type>>, VvFormField: Component) { const VvFormTemplate = defineComponent({ name: 'VvFormTemplate', props: { schema: { type: [Array, Function] as PropType<FormTemplate<Schema, Type>>, required: true, }, scope: { type: Object as PropType<Record<string, unknown>>, default: () => ({}), }, }, slots: Object as SlotsType<{ default: { errors?: DeepReadonly<InferFormattedError<Schema>> formData?: undefined extends Type ? Partial<InferSchema<Schema>> : Type invalid: boolean status?: FormStatus submit?: InjectedFormData<Schema, Type>['submit'] validate?: InjectedFormData<Schema, Type>['validate'] clear?: InjectedFormData<Schema, Type>['clear'] reset?: InjectedFormData<Schema, Type>['reset'] } }>, setup(templateProps, { slots: templateSlots }) { const injectedFormData = inject(formProvideKey) if (!injectedFormData?.formData) return return () => { const normalizedSchema = typeof templateProps.schema === 'function' ? templateProps.schema( injectedFormData, templateProps.scope, ) : templateProps.schema let lastIf: boolean | undefined const toReturn = normalizedSchema.reduce< (VNode | VNode[] | undefined)[] >((acc, field) => { const normalizedField = typeof field === 'function' ? field(injectedFormData, templateProps.scope) : field const { vvIs, vvName, vvSlots, vvChildren, vvIf, vvElseIf, vvType, vvDefaultValue, vvShowValid, vvContent, ...props } = normalizedField // conditions if (vvIf !== undefined) { if (typeof vvIf === 'string') { lastIf = Boolean( getProperty( new Object(injectedFormData.formData.value), vvIf, ), ) } else if (typeof vvIf === 'function') { lastIf = unref(vvIf(injectedFormData)) } else { lastIf = unref(vvIf) } if (!lastIf) { return acc } } else if (vvElseIf !== undefined && lastIf !== undefined) { if (lastIf) { return acc } if (typeof vvElseIf === 'string') { lastIf = Boolean( getProperty( new Object(injectedFormData.formData.value), vvElseIf, ), ) } else if (typeof vvElseIf === 'function') { lastIf = unref(vvElseIf(injectedFormData)) } else { lastIf = unref(vvElseIf) } if (!lastIf) { return acc } } else { lastIf = undefined } // children let hChildren: RenderFunctionOutput | { default: (scope: Record<string, unknown>) => RenderFunctionOutput } | undefined if (vvChildren) { if (typeof vvIs === 'string') { hChildren = h(VvFormTemplate, { schema: vvChildren, }) } else { hChildren = { default: (scope: Record<string, unknown>) => h(VvFormTemplate, { schema: vvChildren, scope, }), } } } // render if (vvName) { acc.push( h( VvFormField, { name: vvName, is: vvIs, type: vvType, defaultValue: vvDefaultValue, showValid: vvShowValid, props, }, vvSlots ?? hChildren ?? vvContent, ), ) return acc } if (vvIs) { acc.push( h( vvIs as Component, props, vvSlots ?? hChildren ?? vvContent, ), ) return acc } if (hChildren) { if ('default' in hChildren) { acc.push(hChildren.default(templateProps.scope)) } else { acc.push(hChildren) } return acc } return acc }, []) toReturn.push( templateSlots?.default?.({ errors: injectedFormData?.errors.value, formData: injectedFormData?.formData.value, invalid: injectedFormData?.invalid.value, status: injectedFormData?.status.value, submit: injectedFormData?.submit, validate: injectedFormData?.validate, clear: injectedFormData?.clear, reset: injectedFormData?.reset, }), ) return toReturn } }, }) return VvFormTemplate }