@volverjs/form-vue 1.0.0-beta.1 → 1.0.0-beta.2
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.
- package/dist/index.es.js +390 -349
- package/dist/index.umd.js +1 -1
- package/dist/src/VvForm.d.ts +40 -27
- package/dist/src/enums.d.ts +4 -1
- package/dist/src/index.d.ts +116 -78
- package/dist/src/types.d.ts +4 -1
- package/package.json +14 -14
- package/src/VvForm.ts +99 -60
- package/src/VvFormField.ts +1 -1
- package/src/VvFormTemplate.ts +1 -0
- package/src/VvFormWrapper.ts +1 -1
- package/src/enums.ts +3 -0
- package/src/index.ts +14 -6
- package/src/types.ts +4 -1
package/src/VvForm.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type DeepReadonly,
|
|
5
5
|
type Ref,
|
|
6
6
|
type PropType,
|
|
7
|
+
type WatchStopHandle,
|
|
7
8
|
withModifiers,
|
|
8
9
|
defineComponent,
|
|
9
10
|
ref,
|
|
@@ -15,8 +16,12 @@ import {
|
|
|
15
16
|
isProxy,
|
|
16
17
|
computed,
|
|
17
18
|
} from 'vue'
|
|
18
|
-
import {
|
|
19
|
-
|
|
19
|
+
import {
|
|
20
|
+
watchIgnorable,
|
|
21
|
+
throttleFilter,
|
|
22
|
+
type IgnoredUpdater,
|
|
23
|
+
} from '@vueuse/core'
|
|
24
|
+
import { type z, type ZodFormattedError, type TypeOf } from 'zod'
|
|
20
25
|
import type {
|
|
21
26
|
FormComponentOptions,
|
|
22
27
|
FormSchema,
|
|
@@ -35,20 +40,55 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
35
40
|
const errors = ref<z.inferFormattedError<Schema> | undefined>()
|
|
36
41
|
const status = ref<FormStatus | undefined>()
|
|
37
42
|
const formData = ref<Partial<z.infer<Schema> | undefined>>()
|
|
43
|
+
|
|
44
|
+
const validate = async (value = formData.value) => {
|
|
45
|
+
const parseResult = await schema.safeParseAsync(value)
|
|
46
|
+
if (!parseResult.success) {
|
|
47
|
+
errors.value = parseResult.error.format() as ZodFormattedError<
|
|
48
|
+
z.infer<Schema>
|
|
49
|
+
>
|
|
50
|
+
status.value = FormStatus.invalid
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
errors.value = undefined
|
|
54
|
+
status.value = FormStatus.valid
|
|
55
|
+
formData.value = parseResult.data
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const submit = async () => {
|
|
60
|
+
if (!(await validate())) {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
status.value = FormStatus.submitting
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { ignoreUpdates, stop: stopUpdatesWatch } = watchIgnorable(
|
|
68
|
+
formData,
|
|
69
|
+
() => {
|
|
70
|
+
status.value = FormStatus.updated
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
deep: true,
|
|
74
|
+
eventFilter: throttleFilter(options?.updateThrottle ?? 500),
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
|
|
38
78
|
const component = defineComponent({
|
|
39
|
-
name: '
|
|
79
|
+
name: 'VvForm',
|
|
40
80
|
props: {
|
|
81
|
+
continuosValidation: {
|
|
82
|
+
type: Boolean,
|
|
83
|
+
default: false,
|
|
84
|
+
},
|
|
41
85
|
modelValue: {
|
|
42
86
|
type: Object,
|
|
43
87
|
default: () => ({}),
|
|
44
88
|
},
|
|
45
|
-
|
|
46
|
-
type:
|
|
47
|
-
default:
|
|
48
|
-
},
|
|
49
|
-
continuosValidation: {
|
|
50
|
-
type: Boolean,
|
|
51
|
-
default: false,
|
|
89
|
+
tag: {
|
|
90
|
+
type: String,
|
|
91
|
+
default: 'form',
|
|
52
92
|
},
|
|
53
93
|
template: {
|
|
54
94
|
type: [Array, Function] as PropType<FormTemplate<Schema>>,
|
|
@@ -63,7 +103,6 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
63
103
|
toRaw(props.modelValue),
|
|
64
104
|
)
|
|
65
105
|
|
|
66
|
-
// clone modelValue and update formData
|
|
67
106
|
watch(
|
|
68
107
|
() => props.modelValue,
|
|
69
108
|
(newValue) => {
|
|
@@ -80,72 +119,62 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
80
119
|
{ deep: true },
|
|
81
120
|
)
|
|
82
121
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
122
|
+
watch(status, async (newValue) => {
|
|
123
|
+
if (newValue === FormStatus.invalid) {
|
|
124
|
+
const toReturn = toRaw(
|
|
125
|
+
errors.value as ZodFormattedError<z.infer<Schema>>,
|
|
126
|
+
)
|
|
127
|
+
emit('invalid', toReturn)
|
|
128
|
+
options?.onInvalid?.(toReturn)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
if (newValue === FormStatus.valid) {
|
|
132
|
+
const toReturn = toRaw(formData.value as z.infer<Schema>)
|
|
133
|
+
emit('valid', toReturn)
|
|
134
|
+
options?.onValid?.(toReturn)
|
|
135
|
+
emit('update:modelValue', toReturn)
|
|
136
|
+
options?.onUpdate?.(toReturn)
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
if (newValue === FormStatus.submitting) {
|
|
140
|
+
const toReturn = toRaw(formData.value as z.infer<Schema>)
|
|
141
|
+
emit('submit', toReturn)
|
|
142
|
+
options?.onSubmit?.(toReturn)
|
|
143
|
+
}
|
|
144
|
+
if (newValue === FormStatus.updated) {
|
|
87
145
|
if (
|
|
88
|
-
|
|
146
|
+
errors.value ||
|
|
147
|
+
options?.continuosValidation ||
|
|
89
148
|
props.continuosValidation
|
|
90
149
|
) {
|
|
91
150
|
await validate()
|
|
92
151
|
}
|
|
93
152
|
if (
|
|
94
|
-
!
|
|
153
|
+
!formData.value ||
|
|
95
154
|
!props.modelValue ||
|
|
96
|
-
JSON.stringify(
|
|
155
|
+
JSON.stringify(formData.value) !==
|
|
97
156
|
JSON.stringify(props.modelValue)
|
|
98
157
|
) {
|
|
99
|
-
|
|
100
|
-
|
|
158
|
+
const toReturn = toRaw(
|
|
159
|
+
formData.value as z.infer<Schema>,
|
|
160
|
+
)
|
|
161
|
+
emit('update:modelValue', toReturn)
|
|
162
|
+
options?.onUpdate?.(toReturn)
|
|
163
|
+
}
|
|
164
|
+
if (status.value === FormStatus.updated) {
|
|
165
|
+
status.value = FormStatus.unknown
|
|
101
166
|
}
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
deep: true,
|
|
105
|
-
throttle: options?.updateThrottle ?? props.updateThrottle,
|
|
106
|
-
},
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
// validate formData with safeParse
|
|
110
|
-
const validate = async (value = formData.value) => {
|
|
111
|
-
const parseResult = await schema.safeParseAsync(value)
|
|
112
|
-
if (!parseResult.success) {
|
|
113
|
-
errors.value =
|
|
114
|
-
parseResult.error.format() as ZodFormattedError<
|
|
115
|
-
z.infer<Schema>
|
|
116
|
-
>
|
|
117
|
-
status.value = FormStatus.invalid
|
|
118
|
-
emit('invalid', errors.value)
|
|
119
|
-
options?.onInvalid?.(toRaw(errors.value))
|
|
120
|
-
return false
|
|
121
|
-
}
|
|
122
|
-
errors.value = undefined
|
|
123
|
-
status.value = FormStatus.valid
|
|
124
|
-
formData.value = parseResult.data
|
|
125
|
-
emit('update:modelValue', formData.value)
|
|
126
|
-
options?.onUpdate?.(toRaw(formData.value))
|
|
127
|
-
emit('valid', parseResult.data)
|
|
128
|
-
options?.onValid?.(toRaw(formData.value))
|
|
129
|
-
return true
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// emit submit event if form is valid
|
|
133
|
-
const submit = async () => {
|
|
134
|
-
if (!(await validate())) {
|
|
135
|
-
return false
|
|
136
167
|
}
|
|
137
|
-
|
|
138
|
-
options?.onSubmit?.(toRaw(formData.value) as z.infer<Schema>)
|
|
139
|
-
return true
|
|
140
|
-
}
|
|
168
|
+
})
|
|
141
169
|
|
|
142
170
|
const invalid = computed(() => status.value === FormStatus.invalid)
|
|
143
171
|
|
|
144
|
-
// provide data to children
|
|
145
172
|
provide(provideKey, {
|
|
146
173
|
formData,
|
|
147
174
|
submit,
|
|
148
175
|
validate,
|
|
176
|
+
ignoreUpdates,
|
|
177
|
+
stopUpdatesWatch,
|
|
149
178
|
errors: readonly(errors),
|
|
150
179
|
status: readonly(status),
|
|
151
180
|
invalid,
|
|
@@ -155,6 +184,8 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
155
184
|
formData,
|
|
156
185
|
submit,
|
|
157
186
|
validate,
|
|
187
|
+
ignoreUpdates,
|
|
188
|
+
stopUpdatesWatch,
|
|
158
189
|
errors: readonly(errors),
|
|
159
190
|
status: readonly(status),
|
|
160
191
|
invalid,
|
|
@@ -166,12 +197,14 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
166
197
|
formData: this.formData,
|
|
167
198
|
submit: this.submit,
|
|
168
199
|
validate: this.validate,
|
|
200
|
+
ignoreUpdates: this.ignoreUpdates,
|
|
201
|
+
stopUpdatesWatch: this.stopUpdatesWatch,
|
|
169
202
|
errors: this.errors,
|
|
170
203
|
status: this.status,
|
|
171
204
|
invalid: this.invalid,
|
|
172
205
|
}) ?? this.$slots.default
|
|
173
206
|
return h(
|
|
174
|
-
|
|
207
|
+
this.tag,
|
|
175
208
|
{
|
|
176
209
|
onSubmit: withModifiers(this.submit, ['prevent']),
|
|
177
210
|
},
|
|
@@ -197,6 +230,10 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
197
230
|
errors,
|
|
198
231
|
status,
|
|
199
232
|
formData,
|
|
233
|
+
validate,
|
|
234
|
+
submit,
|
|
235
|
+
ignoreUpdates,
|
|
236
|
+
stopUpdatesWatch,
|
|
200
237
|
/**
|
|
201
238
|
* An hack to add types to the default slot
|
|
202
239
|
*/
|
|
@@ -211,6 +248,8 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
211
248
|
: Partial<TypeOf<Schema>> | undefined
|
|
212
249
|
submit: () => Promise<boolean>
|
|
213
250
|
validate: () => Promise<boolean>
|
|
251
|
+
ignoreUpdates: IgnoredUpdater
|
|
252
|
+
stopUpdatesWatch: WatchStopHandle
|
|
214
253
|
errors: Readonly<
|
|
215
254
|
Ref<DeepReadonly<z.inferFormattedError<Schema>>>
|
|
216
255
|
>
|
package/src/VvFormField.ts
CHANGED
package/src/VvFormTemplate.ts
CHANGED
package/src/VvFormWrapper.ts
CHANGED
|
@@ -24,7 +24,7 @@ export const defineFormWrapper = <Schema extends FormSchema>(
|
|
|
24
24
|
wrapperProvideKey: InjectionKey<InjectedFormWrapperData<Schema>>,
|
|
25
25
|
) => {
|
|
26
26
|
const VvFormWrapper = defineComponent({
|
|
27
|
-
name: '
|
|
27
|
+
name: 'VvFormWrapper',
|
|
28
28
|
props: {
|
|
29
29
|
name: {
|
|
30
30
|
type: String,
|
package/src/enums.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -48,12 +48,16 @@ const _formFactory = <Schema extends FormSchema>(
|
|
|
48
48
|
options,
|
|
49
49
|
)
|
|
50
50
|
const VvFormTemplate = defineFormTemplate(formInjectionKey, VvFormField)
|
|
51
|
-
const {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
const {
|
|
52
|
+
VvForm,
|
|
53
|
+
errors,
|
|
54
|
+
status,
|
|
55
|
+
formData,
|
|
56
|
+
validate,
|
|
57
|
+
submit,
|
|
58
|
+
ignoreUpdates,
|
|
59
|
+
stopUpdatesWatch,
|
|
60
|
+
} = defineForm(schema, formInjectionKey, options, VvFormTemplate)
|
|
57
61
|
|
|
58
62
|
return {
|
|
59
63
|
VvForm,
|
|
@@ -66,6 +70,10 @@ const _formFactory = <Schema extends FormSchema>(
|
|
|
66
70
|
errors,
|
|
67
71
|
status,
|
|
68
72
|
formData,
|
|
73
|
+
validate,
|
|
74
|
+
submit,
|
|
75
|
+
ignoreUpdates,
|
|
76
|
+
stopUpdatesWatch,
|
|
69
77
|
}
|
|
70
78
|
}
|
|
71
79
|
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Component, DeepReadonly, Ref, WatchStopHandle } from 'vue'
|
|
2
2
|
import type { z, AnyZodObject, ZodEffects, inferFormattedError } from 'zod'
|
|
3
|
+
import type { IgnoredUpdater } from '@vueuse/core'
|
|
3
4
|
import type { FormFieldType, FormStatus } from './enums'
|
|
4
5
|
|
|
5
6
|
export type FormSchema =
|
|
@@ -47,6 +48,8 @@ export type InjectedFormData<Schema extends FormSchema> = {
|
|
|
47
48
|
>
|
|
48
49
|
submit: () => Promise<boolean>
|
|
49
50
|
validate: () => Promise<boolean>
|
|
51
|
+
ignoreUpdates: IgnoredUpdater
|
|
52
|
+
stopUpdatesWatch: WatchStopHandle
|
|
50
53
|
status: Readonly<Ref<FormStatus | undefined>>
|
|
51
54
|
invalid: Readonly<Ref<boolean>>
|
|
52
55
|
}
|