@volverjs/form-vue 1.0.0-beta.25 → 1.0.0-beta.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,26 +1,30 @@
1
1
  import {
2
+ type Component,
2
3
  type DeepReadonly,
3
4
  type InjectionKey,
4
5
  type Ref,
5
6
  type SlotsType,
6
7
  computed,
7
8
  defineComponent,
9
+ getCurrentInstance,
8
10
  h,
9
11
  inject,
12
+ onBeforeUnmount,
13
+ onMounted,
10
14
  provide,
11
15
  readonly,
12
16
  ref,
13
17
  toRefs,
14
18
  watch,
15
19
  } from 'vue'
16
- import type { inferFormattedError, TypeOf, z } from 'zod'
20
+ import type { inferFormattedError, z } from 'zod'
17
21
  import type {
18
22
  FormSchema,
19
23
  InjectedFormData,
20
24
  InjectedFormWrapperData,
21
25
  } from './types'
22
26
 
23
- export function defineFormWrapper<Schema extends FormSchema>(formProvideKey: InjectionKey<InjectedFormData<Schema>>, wrapperProvideKey: InjectionKey<InjectedFormWrapperData<Schema>>) {
27
+ export function defineFormWrapper<Schema extends FormSchema, Type>(formProvideKey: InjectionKey<InjectedFormData<Schema, Type>>, wrapperProvideKey: InjectionKey<InjectedFormWrapperData<Schema>>) {
24
28
  return defineComponent({
25
29
  name: 'VvFormWrapper',
26
30
  props: {
@@ -50,21 +54,21 @@ export function defineFormWrapper<Schema extends FormSchema>(formProvideKey: Inj
50
54
  slots: Object as SlotsType<{
51
55
  default: {
52
56
  errors?: DeepReadonly<z.inferFormattedError<Schema>>
53
- formData?: Partial<TypeOf<Schema>>
57
+ formData?: undefined extends Type ? Partial<z.infer<Schema>> : Type
54
58
  formErrors?: DeepReadonly<inferFormattedError<Schema, string>>
55
59
  invalid: boolean
56
- submit?: InjectedFormData<Schema>['submit']
57
- validate?: InjectedFormData<Schema>['validate']
60
+ submit?: InjectedFormData<Schema, Type>['submit']
61
+ validate?: InjectedFormData<Schema, Type>['validate']
58
62
  validateWrapper?: () => Promise<boolean>
59
63
  fieldsErrors: Map<string, inferFormattedError<Schema, string>>
60
- clear?: InjectedFormData<Schema>['clear']
61
- reset?: InjectedFormData<Schema>['reset']
64
+ clear?: InjectedFormData<Schema, Type>['clear']
65
+ reset?: InjectedFormData<Schema, Type>['reset']
62
66
  }
63
67
  }>,
64
68
  setup(props, { emit }) {
65
69
  const injectedFormData = inject(formProvideKey)
66
70
  const wrapperProvided = inject(wrapperProvideKey, undefined)
67
- const fields = ref(new Set<string>())
71
+ const fields = ref(new Map<string, string>())
68
72
  const fieldsErrors: Ref<
69
73
  Map<string, z.inferFormattedError<Schema>>
70
74
  > = ref(new Map())
@@ -80,19 +84,28 @@ export function defineFormWrapper<Schema extends FormSchema>(formProvideKey: Inj
80
84
  // add fields to parent wrapper
81
85
  watch(
82
86
  fields,
83
- (newValue) => {
87
+ (newValue, oldValue) => {
84
88
  if (wrapperProvided?.fields) {
85
- newValue.forEach((field) => {
86
- wrapperProvided?.fields.value.add(field)
89
+ oldValue.entries().forEach(([id]) => {
90
+ if (!newValue.has(id)) {
91
+ wrapperProvided?.fields.value.delete(id)
92
+ }
93
+ })
94
+ }
95
+ if (wrapperProvided?.fields) {
96
+ newValue.entries().forEach(([id, field]) => {
97
+ if (!wrapperProvided?.fields.value.has(id)) {
98
+ wrapperProvided?.fields.value.set(id, field)
99
+ }
87
100
  })
88
101
  }
89
102
  },
90
103
  { deep: true },
91
104
  )
92
105
 
93
- // add fields to parent wrapper
106
+ // add fields errors to parent wrapper
94
107
  watch(
95
- () => new Map(fieldsErrors.value),
108
+ fieldsErrors,
96
109
  (newValue, oldValue) => {
97
110
  if (wrapperProvided?.errors) {
98
111
  Array.from(oldValue.keys()).forEach((key) => {
@@ -125,8 +138,26 @@ export function defineFormWrapper<Schema extends FormSchema>(formProvideKey: Inj
125
138
  }
126
139
  })
127
140
 
141
+ onMounted(() => {
142
+ const instance = getCurrentInstance()
143
+ if (!instance || !injectedFormData?.wrappers || !name.value) {
144
+ console.warn('[@volverjs/form-vue]: Invalid wrapper registration state')
145
+ return
146
+ }
147
+ if (injectedFormData.wrappers.has(name.value)) {
148
+ console.warn(`[@volverjs/form-vue]: wrapper name "${name.value}" is already used`)
149
+ return
150
+ }
151
+ injectedFormData.wrappers.set(name.value, instance as unknown as Component)
152
+ })
153
+ onBeforeUnmount(() => {
154
+ if (injectedFormData?.wrappers && name.value) {
155
+ injectedFormData.wrappers.delete(name.value)
156
+ }
157
+ })
158
+
128
159
  const validateWrapper = () => {
129
- return injectedFormData?.validate(undefined, fields.value) ?? Promise.resolve(true)
160
+ return injectedFormData?.validate(undefined, new Set(fields.value.values())) ?? Promise.resolve(true)
130
161
  }
131
162
 
132
163
  return {
package/src/index.ts CHANGED
@@ -25,9 +25,9 @@ import type {
25
25
  FormTemplate,
26
26
  } from './types'
27
27
 
28
- function _formFactory<Schema extends FormSchema>(schema: Schema, options: FormComposableOptions<Schema> = {}) {
28
+ function _formType<Schema extends FormSchema, Type>(schema: Schema, options: FormComposableOptions<Schema, Type> = {}) {
29
29
  // create injection keys
30
- const formInjectionKey = Symbol('formInjectionKey') as InjectionKey<InjectedFormData<Schema>>
30
+ const formInjectionKey = Symbol('formInjectionKey') as InjectionKey<InjectedFormData<Schema, Type>>
31
31
  const formWrapperInjectionKey = Symbol('formWrapperInjectionKey') as InjectionKey<
32
32
  InjectedFormWrapperData<Schema>
33
33
  >
@@ -55,6 +55,7 @@ function _formFactory<Schema extends FormSchema>(schema: Schema, options: FormCo
55
55
  formFieldsGroupInjectionKey,
56
56
  )
57
57
  const VvFormTemplate = defineFormTemplate(formInjectionKey, VvFormField)
58
+ const wrappers = new Map<string, typeof VvFormWrapper>()
58
59
  const {
59
60
  clear,
60
61
  errors,
@@ -68,7 +69,7 @@ function _formFactory<Schema extends FormSchema>(schema: Schema, options: FormCo
68
69
  submit,
69
70
  validate,
70
71
  VvForm,
71
- } = defineForm(schema, formInjectionKey, options, VvFormTemplate)
72
+ } = defineForm(schema, formInjectionKey, options, VvFormTemplate, wrappers)
72
73
 
73
74
  return {
74
75
  clear,
@@ -85,6 +86,7 @@ function _formFactory<Schema extends FormSchema>(schema: Schema, options: FormCo
85
86
  stopUpdatesWatch,
86
87
  submit,
87
88
  validate,
89
+ wrappers,
88
90
  VvForm,
89
91
  VvFormField,
90
92
  VvFormFieldsGroup,
@@ -98,7 +100,7 @@ export const pluginInjectionKey = Symbol('pluginInjectionKey') as InjectionKey<F
98
100
  export function createForm(options: FormPluginOptions): Plugin & Partial<ReturnType<typeof useForm>> {
99
101
  let toReturn: Partial<ReturnType<typeof useForm>> = {}
100
102
  if (options.schema) {
101
- toReturn = _formFactory(options.schema as AnyZodObject, options)
103
+ toReturn = _formType(options.schema as AnyZodObject, options)
102
104
  }
103
105
  return {
104
106
  ...toReturn,
@@ -128,17 +130,29 @@ export function createForm(options: FormPluginOptions): Plugin & Partial<ReturnT
128
130
  }
129
131
  }
130
132
 
131
- export function useForm<Schema extends FormSchema>(schema: Schema, options: FormComposableOptions<Schema> = {}) {
133
+ const formInstances: Map<string, ReturnType<typeof _formType>> = new Map()
134
+ export function useForm<Schema extends FormSchema, Type>(schema: Schema, options: FormComposableOptions<Schema, Type> = {}) {
135
+ if (options.scope && formInstances.has(options.scope)) {
136
+ return formInstances.get(options.scope) as ReturnType<typeof _formType<Schema, Type>>
137
+ }
132
138
  if (!getCurrentInstance()) {
133
- return _formFactory(schema, options)
139
+ const toReturn = _formType(schema, options)
140
+ if (options.scope) {
141
+ formInstances.set(options.scope, toReturn)
142
+ }
143
+ return toReturn
134
144
  }
135
- return _formFactory(
145
+ const toReturn = _formType(
136
146
  schema as AnyZodObject,
137
147
  {
138
148
  ...inject(pluginInjectionKey, {}),
139
149
  ...options,
140
- } as FormComposableOptions<AnyZodObject>,
150
+ } as FormComposableOptions<AnyZodObject, Type>,
141
151
  )
152
+ if (options.scope) {
153
+ formInstances.set(options.scope, toReturn)
154
+ }
155
+ return toReturn
142
156
  }
143
157
 
144
158
  export { FormFieldType } from './enums'
@@ -171,6 +185,6 @@ export type {
171
185
  /**
172
186
  * @deprecated Use `useForm()` instead
173
187
  */
174
- export function formFactory<Schema extends FormSchema>(schema: Schema, options: FormComposableOptions<Schema> = {}) {
175
- return _formFactory(schema, options)
188
+ export function formType<Schema extends FormSchema, Type>(schema: Schema, options: FormComposableOptions<Schema, Type> = {}) {
189
+ return _formType(schema, options)
176
190
  }
package/src/types.ts CHANGED
@@ -19,43 +19,47 @@ export type FormFieldComponentOptions = {
19
19
  sideEffects?: (type: `${FormFieldType}`) => Promise<void> | void
20
20
  }
21
21
 
22
- export type FormComponentOptions<Schema> = {
22
+ export type FormComponentOptions<Schema, Type> = {
23
23
  updateThrottle?: number
24
24
  continuousValidation?: boolean
25
25
  readonly?: boolean
26
- template?: Schema extends FormSchema ? FormTemplate<Schema> : never
26
+ template?: Schema extends FormSchema ? FormTemplate<Schema, Type> : never
27
+ class?: Schema extends FormSchema ? new (data?: Partial<z.infer<Schema>>) => Type : never
27
28
  onUpdate?: Schema extends FormSchema
28
- ? (data?: Partial<z.infer<Schema>>) => void
29
+ ? (data?: undefined extends Type ? Partial<z.infer<Schema>> : Type) => void
29
30
  : never
30
31
  onSubmit?: Schema extends FormSchema
31
- ? (data?: z.infer<Schema>) => void
32
+ ? (data?: undefined extends Type ? Partial<z.infer<Schema>> : Type) => void
32
33
  : never
33
- onReset?: Schema extends FormSchema ? (data?: z.infer<Schema>) => void : never
34
+ onReset?: Schema extends FormSchema ? (data?: undefined extends Type ? Partial<z.infer<Schema>> : Type) => void : never
34
35
  onInvalid?: Schema extends FormSchema
35
36
  ? (error?: z.inferFormattedError<Schema>) => void
36
37
  : never
37
38
  onValid?: Schema extends FormSchema
38
- ? (data?: z.infer<Schema>) => void
39
+ ? (data?: undefined extends Type ? Partial<z.infer<Schema>> : Type) => void
39
40
  : never
40
41
  }
41
42
 
42
- export type FormComposableOptions<Schema> = FormFieldComponentOptions &
43
- FormComponentOptions<Schema>
43
+ export type FormComposableOptions<Schema, Type> = FormFieldComponentOptions &
44
+ FormComponentOptions<Schema, Type> & {
45
+ scope?: string
46
+ }
44
47
 
45
- type FormPluginOptionsSchema = {
48
+ type FormPluginOptionsSchema<T = Partial<z.infer<FormSchema>>> = {
46
49
  schema?: FormSchema
50
+ factory?: (data?: Partial<z.infer<FormSchema>>) => T
47
51
  }
48
52
 
49
53
  export type FormPluginOptions = FormPluginOptionsSchema &
50
- FormComposableOptions<FormPluginOptionsSchema['schema']>
54
+ FormComposableOptions<FormPluginOptionsSchema['schema'], FormPluginOptionsSchema['factory']>
51
55
 
52
- export type InjectedFormData<Schema extends FormSchema> = {
53
- formData: Ref<Partial<z.infer<Schema>> | undefined>
56
+ export type InjectedFormData<Schema extends FormSchema, Type> = {
57
+ formData: Ref<(undefined extends Type ? Partial<z.infer<Schema>> : Type) | undefined>
54
58
  errors: Readonly<
55
59
  Ref<DeepReadonly<z.inferFormattedError<Schema>> | undefined>
56
60
  >
57
61
  submit: () => Promise<boolean>
58
- validate: (formData?: Partial<z.infer<Schema>>, fields?: Set<string>) => Promise<boolean>
62
+ validate: (formData?: undefined extends Type ? Partial<z.infer<Schema>> : Type, fields?: Set<string>) => Promise<boolean>
59
63
  clear: () => void
60
64
  reset: () => void
61
65
  ignoreUpdates: IgnoredUpdater
@@ -63,11 +67,12 @@ export type InjectedFormData<Schema extends FormSchema> = {
63
67
  status: Readonly<Ref<FormStatus | undefined>>
64
68
  invalid: Readonly<Ref<boolean>>
65
69
  readonly: Ref<boolean>
70
+ wrappers: Map<string, Component>
66
71
  }
67
72
 
68
73
  export type InjectedFormWrapperData<Schema extends FormSchema> = {
69
74
  name: Ref<string>
70
- fields: Ref<Set<string>>
75
+ fields: Ref<Map<string, string>>
71
76
  errors: Ref<Map<string, z.inferFormattedError<Schema>>>
72
77
  }
73
78
 
@@ -133,12 +138,12 @@ export type PathValue<T, TPath extends Path<T> | Path<T>[]> = T extends any
133
138
  : never
134
139
  : never
135
140
 
136
- export type AnyBoolean<Schema extends FormSchema> =
141
+ export type AnyBoolean<Schema extends FormSchema, Type> =
137
142
  | boolean
138
143
  | Ref<boolean>
139
- | ((data?: InjectedFormData<Schema>) => boolean | Ref<boolean>)
144
+ | ((data?: InjectedFormData<Schema, Type>) => boolean | Ref<boolean>)
140
145
 
141
- export type SimpleFormTemplateItem<Schema extends FormSchema> = Record<
146
+ export type SimpleFormTemplateItem<Schema extends FormSchema, Type> = Record<
142
147
  string,
143
148
  any
144
149
  > & {
@@ -147,42 +152,42 @@ export type SimpleFormTemplateItem<Schema extends FormSchema> = Record<
147
152
  vvSlots?: Record<string, any>
148
153
  vvChildren?:
149
154
  | Array<
150
- | SimpleFormTemplateItem<Schema>
155
+ | SimpleFormTemplateItem<Schema, Type>
151
156
  | ((
152
- data?: InjectedFormData<Schema>,
157
+ data?: InjectedFormData<Schema, Type>,
153
158
  scope?: Record<string, unknown>,
154
- ) => SimpleFormTemplateItem<Schema>)
159
+ ) => SimpleFormTemplateItem<Schema, Type>)
155
160
  >
156
161
  | ((
157
- data?: InjectedFormData<Schema>,
162
+ data?: InjectedFormData<Schema, Type>,
158
163
  scope?: Record<string, unknown>,
159
164
  ) => Array<
160
- | SimpleFormTemplateItem<Schema>
165
+ | SimpleFormTemplateItem<Schema, Type>
161
166
  | ((
162
- data?: InjectedFormData<Schema>,
167
+ data?: InjectedFormData<Schema, Type>,
163
168
  scope?: Record<string, unknown>,
164
- ) => SimpleFormTemplateItem<Schema>)
169
+ ) => SimpleFormTemplateItem<Schema, Type>)
165
170
  >)
166
- vvIf?: AnyBoolean<Schema> | Path<z.infer<Schema>>
167
- vvElseIf?: AnyBoolean<Schema> | Path<z.infer<Schema>>
171
+ vvIf?: AnyBoolean<Schema, Type> | Path<z.infer<Schema>>
172
+ vvElseIf?: AnyBoolean<Schema, Type> | Path<z.infer<Schema>>
168
173
  vvType?: `${FormFieldType}`
169
174
  vvShowValid?: boolean
170
175
  vvContent?: string
171
176
  vvDefaultValue?: any
172
177
  }
173
178
 
174
- export type FormTemplateItem<Schema extends FormSchema> =
175
- | SimpleFormTemplateItem<Schema>
179
+ export type FormTemplateItem<Schema extends FormSchema, Type> =
180
+ | SimpleFormTemplateItem<Schema, Type>
176
181
  | ((
177
- data?: InjectedFormData<Schema>,
182
+ data?: InjectedFormData<Schema, Type>,
178
183
  scope?: Record<string, unknown>,
179
- ) => SimpleFormTemplateItem<Schema>)
184
+ ) => SimpleFormTemplateItem<Schema, Type>)
180
185
 
181
- export type FormTemplate<Schema extends FormSchema> =
182
- | FormTemplateItem<Schema>[]
186
+ export type FormTemplate<Schema extends FormSchema, Type> =
187
+ | FormTemplateItem<Schema, Type>[]
183
188
  | ((
184
- data?: InjectedFormData<Schema>,
189
+ data?: InjectedFormData<Schema, Type>,
185
190
  scope?: Record<string, unknown>,
186
- ) => FormTemplateItem<Schema>[])
191
+ ) => FormTemplateItem<Schema, Type>[])
187
192
 
188
193
  export type RenderFunctionOutput = VNode<RendererNode, RendererElement, { [key: string]: any }>