@volverjs/form-vue 1.0.0-beta.1 → 1.0.0-beta.3
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 +400 -358
- package/dist/index.umd.js +1 -1
- package/dist/src/VvForm.d.ts +41 -27
- package/dist/src/enums.d.ts +4 -1
- package/dist/src/index.d.ts +119 -78
- package/dist/src/types.d.ts +4 -1
- package/package.json +14 -14
- package/src/VvForm.ts +101 -62
- 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 +16 -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,
|
|
@@ -34,21 +39,57 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
34
39
|
) => {
|
|
35
40
|
const errors = ref<z.inferFormattedError<Schema> | undefined>()
|
|
36
41
|
const status = ref<FormStatus | undefined>()
|
|
42
|
+
const invalid = computed(() => status.value === FormStatus.invalid)
|
|
37
43
|
const formData = ref<Partial<z.infer<Schema> | undefined>>()
|
|
44
|
+
|
|
45
|
+
const validate = async (value = formData.value) => {
|
|
46
|
+
const parseResult = await schema.safeParseAsync(value)
|
|
47
|
+
if (!parseResult.success) {
|
|
48
|
+
errors.value = parseResult.error.format() as ZodFormattedError<
|
|
49
|
+
z.infer<Schema>
|
|
50
|
+
>
|
|
51
|
+
status.value = FormStatus.invalid
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
errors.value = undefined
|
|
55
|
+
status.value = FormStatus.valid
|
|
56
|
+
formData.value = parseResult.data
|
|
57
|
+
return true
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const submit = async () => {
|
|
61
|
+
if (!(await validate())) {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
status.value = FormStatus.submitting
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { ignoreUpdates, stop: stopUpdatesWatch } = watchIgnorable(
|
|
69
|
+
formData,
|
|
70
|
+
() => {
|
|
71
|
+
status.value = FormStatus.updated
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
deep: true,
|
|
75
|
+
eventFilter: throttleFilter(options?.updateThrottle ?? 500),
|
|
76
|
+
},
|
|
77
|
+
)
|
|
78
|
+
|
|
38
79
|
const component = defineComponent({
|
|
39
|
-
name: '
|
|
80
|
+
name: 'VvForm',
|
|
40
81
|
props: {
|
|
82
|
+
continuosValidation: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
default: false,
|
|
85
|
+
},
|
|
41
86
|
modelValue: {
|
|
42
87
|
type: Object,
|
|
43
88
|
default: () => ({}),
|
|
44
89
|
},
|
|
45
|
-
|
|
46
|
-
type:
|
|
47
|
-
default:
|
|
48
|
-
},
|
|
49
|
-
continuosValidation: {
|
|
50
|
-
type: Boolean,
|
|
51
|
-
default: false,
|
|
90
|
+
tag: {
|
|
91
|
+
type: String,
|
|
92
|
+
default: 'form',
|
|
52
93
|
},
|
|
53
94
|
template: {
|
|
54
95
|
type: [Array, Function] as PropType<FormTemplate<Schema>>,
|
|
@@ -63,7 +104,6 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
63
104
|
toRaw(props.modelValue),
|
|
64
105
|
)
|
|
65
106
|
|
|
66
|
-
// clone modelValue and update formData
|
|
67
107
|
watch(
|
|
68
108
|
() => props.modelValue,
|
|
69
109
|
(newValue) => {
|
|
@@ -80,72 +120,60 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
80
120
|
{ deep: true },
|
|
81
121
|
)
|
|
82
122
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
123
|
+
watch(status, async (newValue) => {
|
|
124
|
+
if (newValue === FormStatus.invalid) {
|
|
125
|
+
const toReturn = toRaw(
|
|
126
|
+
errors.value as ZodFormattedError<z.infer<Schema>>,
|
|
127
|
+
)
|
|
128
|
+
emit('invalid', toReturn)
|
|
129
|
+
options?.onInvalid?.(toReturn)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
if (newValue === FormStatus.valid) {
|
|
133
|
+
const toReturn = toRaw(formData.value as z.infer<Schema>)
|
|
134
|
+
emit('valid', toReturn)
|
|
135
|
+
options?.onValid?.(toReturn)
|
|
136
|
+
emit('update:modelValue', toReturn)
|
|
137
|
+
options?.onUpdate?.(toReturn)
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
if (newValue === FormStatus.submitting) {
|
|
141
|
+
const toReturn = toRaw(formData.value as z.infer<Schema>)
|
|
142
|
+
emit('submit', toReturn)
|
|
143
|
+
options?.onSubmit?.(toReturn)
|
|
144
|
+
}
|
|
145
|
+
if (newValue === FormStatus.updated) {
|
|
87
146
|
if (
|
|
88
|
-
|
|
147
|
+
errors.value ||
|
|
148
|
+
options?.continuosValidation ||
|
|
89
149
|
props.continuosValidation
|
|
90
150
|
) {
|
|
91
151
|
await validate()
|
|
92
152
|
}
|
|
93
153
|
if (
|
|
94
|
-
!
|
|
154
|
+
!formData.value ||
|
|
95
155
|
!props.modelValue ||
|
|
96
|
-
JSON.stringify(
|
|
156
|
+
JSON.stringify(formData.value) !==
|
|
97
157
|
JSON.stringify(props.modelValue)
|
|
98
158
|
) {
|
|
99
|
-
|
|
100
|
-
|
|
159
|
+
const toReturn = toRaw(
|
|
160
|
+
formData.value as z.infer<Schema>,
|
|
161
|
+
)
|
|
162
|
+
emit('update:modelValue', toReturn)
|
|
163
|
+
options?.onUpdate?.(toReturn)
|
|
164
|
+
}
|
|
165
|
+
if (status.value === FormStatus.updated) {
|
|
166
|
+
status.value = FormStatus.unknown
|
|
101
167
|
}
|
|
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
168
|
}
|
|
137
|
-
|
|
138
|
-
options?.onSubmit?.(toRaw(formData.value) as z.infer<Schema>)
|
|
139
|
-
return true
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const invalid = computed(() => status.value === FormStatus.invalid)
|
|
169
|
+
})
|
|
143
170
|
|
|
144
|
-
// provide data to children
|
|
145
171
|
provide(provideKey, {
|
|
146
172
|
formData,
|
|
147
173
|
submit,
|
|
148
174
|
validate,
|
|
175
|
+
ignoreUpdates,
|
|
176
|
+
stopUpdatesWatch,
|
|
149
177
|
errors: readonly(errors),
|
|
150
178
|
status: readonly(status),
|
|
151
179
|
invalid,
|
|
@@ -155,6 +183,8 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
155
183
|
formData,
|
|
156
184
|
submit,
|
|
157
185
|
validate,
|
|
186
|
+
ignoreUpdates,
|
|
187
|
+
stopUpdatesWatch,
|
|
158
188
|
errors: readonly(errors),
|
|
159
189
|
status: readonly(status),
|
|
160
190
|
invalid,
|
|
@@ -166,12 +196,14 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
166
196
|
formData: this.formData,
|
|
167
197
|
submit: this.submit,
|
|
168
198
|
validate: this.validate,
|
|
199
|
+
ignoreUpdates: this.ignoreUpdates,
|
|
200
|
+
stopUpdatesWatch: this.stopUpdatesWatch,
|
|
169
201
|
errors: this.errors,
|
|
170
202
|
status: this.status,
|
|
171
203
|
invalid: this.invalid,
|
|
172
204
|
}) ?? this.$slots.default
|
|
173
205
|
return h(
|
|
174
|
-
|
|
206
|
+
this.tag,
|
|
175
207
|
{
|
|
176
208
|
onSubmit: withModifiers(this.submit, ['prevent']),
|
|
177
209
|
},
|
|
@@ -196,7 +228,12 @@ export const defineForm = <Schema extends FormSchema>(
|
|
|
196
228
|
return {
|
|
197
229
|
errors,
|
|
198
230
|
status,
|
|
231
|
+
invalid,
|
|
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,17 @@ 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
|
+
invalid,
|
|
56
|
+
formData,
|
|
57
|
+
validate,
|
|
58
|
+
submit,
|
|
59
|
+
ignoreUpdates,
|
|
60
|
+
stopUpdatesWatch,
|
|
61
|
+
} = defineForm(schema, formInjectionKey, options, VvFormTemplate)
|
|
57
62
|
|
|
58
63
|
return {
|
|
59
64
|
VvForm,
|
|
@@ -65,7 +70,12 @@ const _formFactory = <Schema extends FormSchema>(
|
|
|
65
70
|
formFieldInjectionKey,
|
|
66
71
|
errors,
|
|
67
72
|
status,
|
|
73
|
+
invalid,
|
|
68
74
|
formData,
|
|
75
|
+
validate,
|
|
76
|
+
submit,
|
|
77
|
+
ignoreUpdates,
|
|
78
|
+
stopUpdatesWatch,
|
|
69
79
|
}
|
|
70
80
|
}
|
|
71
81
|
|
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
|
}
|