import type { App, InjectionKey, Plugin } from 'vue' import { getCurrentInstance, inject } from 'vue' import { defineForm } from './VvForm' import { defineFormField } from './VvFormField' import { defineFormFieldsGroup } from './VvFormFieldsGroup' import { defineFormWrapper } from './VvFormWrapper' import { defineFormTemplate } from './VvFormTemplate' import type { InjectedFormData, InjectedFormWrapperData, InjectedFormFieldData, InjectedFormFieldsGroupData, FormComposableOptions, FormPluginOptions, FormTemplateItem, Path, PathValue, FormSchema, FormTemplate, } from './types' function _formType(schema: Schema, options: FormComposableOptions = {}) { // create injection keys const formInjectionKey = Symbol('formInjectionKey') as InjectionKey> const formWrapperInjectionKey = Symbol('formWrapperInjectionKey') as InjectionKey< InjectedFormWrapperData > const formFieldInjectionKey = Symbol('formFieldInjectionKey') as InjectionKey< InjectedFormFieldData > const formFieldsGroupInjectionKey = Symbol('formFieldsGroupInjectionKey') as InjectionKey< InjectedFormFieldsGroupData > // create components const VvFormWrapper = defineFormWrapper( formInjectionKey, formWrapperInjectionKey, ) const VvFormField = defineFormField( formInjectionKey, formWrapperInjectionKey, formFieldInjectionKey, options, ) const VvFormFieldsGroup = defineFormFieldsGroup( formInjectionKey, formWrapperInjectionKey, formFieldsGroupInjectionKey, ) const VvFormTemplate = defineFormTemplate(formInjectionKey, VvFormField) const wrappers = new Map>() const { clear, errors, formData, ignoreUpdates, invalid, readonly, reset, status, stopUpdatesWatch, submit, validate, VvForm, } = defineForm(schema, formInjectionKey, options, VvFormTemplate, wrappers) return { clear, errors, formData, formFieldInjectionKey, formInjectionKey, formWrapperInjectionKey, ignoreUpdates, invalid, readonly, reset, status, stopUpdatesWatch, submit, validate, wrappers, VvForm, VvFormField, VvFormFieldsGroup, VvFormTemplate, VvFormWrapper, } } export const pluginInjectionKey = Symbol('pluginInjectionKey') as InjectionKey export function createForm(options: FormPluginOptions): Plugin & Partial> { let toReturn: Partial> = {} if (options.schema) { // @ts-expect-error - options.schema is always defined toReturn = _formType(options.schema, options) } return { ...toReturn, install(app: App, { global = false } = {}) { app.provide(pluginInjectionKey, options) if (global) { app.config.globalProperties.$vvForm = options if (toReturn?.VvForm) { app.component('VvForm', toReturn.VvForm) } if (toReturn?.VvFormWrapper) { app.component('VvFormWrapper', toReturn.VvFormWrapper) } if (toReturn?.VvFormField) { app.component('VvFormField', toReturn.VvFormField) } if (toReturn?.VvFormFieldsGroup) { app.component('VvFormFieldsGroup', toReturn.VvFormFieldsGroup) } if (toReturn?.VvFormTemplate) { app.component('VvFormTemplate', toReturn.VvFormTemplate) } } }, } } const formInstances: Map> = new Map() export function useForm(schema: Schema, options: FormComposableOptions = {}): ReturnType > { if (options.scope && formInstances.has(options.scope)) { return formInstances.get(options.scope)! } if (!getCurrentInstance()) { const toReturn = _formType(schema, options) if (options.scope) { formInstances.set(options.scope, toReturn) } return toReturn } const toReturn = _formType( schema, { ...inject(pluginInjectionKey, {}), ...options, } as FormComposableOptions, ) if (options.scope) { formInstances.set(options.scope, toReturn) } return toReturn } export { FormFieldType } from './enums' export { defaultObjectByJSONSchema, defaultObjectBySchema } from './utils' type FormComponent = ReturnType type FormWrapperComponent = ReturnType type FormFieldComponent = ReturnType type FormFieldsGroupComponent = ReturnType type FormTemplateComponent = ReturnType export type { FormComponent, FormComposableOptions, FormFieldComponent, FormFieldsGroupComponent, FormPluginOptions, FormSchema, FormTemplate, FormTemplateComponent, FormTemplateItem, FormWrapperComponent, InjectedFormData, InjectedFormFieldData, InjectedFormWrapperData, Path, PathValue, } /** * @deprecated Use `useForm()` instead */ export function formType(schema: Schema, options: FormComposableOptions = {}) { return _formType(schema, options) }