@teamnovu/kit-vue-forms 0.1.16 → 0.1.18
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/components/FormPart.vue.d.ts +1 -1
- package/dist/composables/useFieldRegistry.d.ts +2 -2
- package/dist/composables/useForm.d.ts +25 -4
- package/dist/composables/useSubform.d.ts +2 -1
- package/dist/composables/useSubmitHandler.d.ts +8 -0
- package/dist/index.js +222 -214
- package/dist/types/form.d.ts +1 -1
- package/dist/utils/path.d.ts +1 -1
- package/package.json +2 -2
- package/src/composables/useFieldRegistry.ts +74 -74
- package/src/composables/useForm.ts +12 -28
- package/src/composables/useSubform.ts +112 -69
- package/src/composables/useSubmitHandler.ts +29 -0
- package/src/types/form.ts +1 -1
- package/src/utils/path.ts +41 -42
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Awaitable, MaybeRef } from '@vueuse/core'
|
|
2
|
+
import { unref } from 'vue'
|
|
3
|
+
import type { Form, FormDataDefault } from '../types/form'
|
|
4
|
+
import type { ValidationStrategy } from '../types/validation'
|
|
5
|
+
|
|
6
|
+
interface SubmitHandlerOptions {
|
|
7
|
+
validationStrategy?: MaybeRef<ValidationStrategy>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function useSubmitHandler<T extends FormDataDefault>(
|
|
11
|
+
form: Omit<Form<T>, 'submitHandler'>,
|
|
12
|
+
options: SubmitHandlerOptions,
|
|
13
|
+
) {
|
|
14
|
+
return (onSubmit: (data: T) => Awaitable<void>) => {
|
|
15
|
+
return async (event: SubmitEvent) => {
|
|
16
|
+
event.preventDefault()
|
|
17
|
+
|
|
18
|
+
if (unref(options.validationStrategy) !== 'none') {
|
|
19
|
+
await form.validateForm()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!form.isValid.value) {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
await onSubmit(form.data.value)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/types/form.ts
CHANGED
package/src/utils/path.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { computed, isRef, unref, type MaybeRef } from
|
|
2
|
-
import type { Paths, PickProps, SplitPath } from
|
|
3
|
-
import type { ErrorBag, ValidationErrors } from
|
|
4
|
-
import type { FormField } from
|
|
1
|
+
import { computed, isRef, unref, type MaybeRef } from 'vue'
|
|
2
|
+
import type { Paths, PickProps, SplitPath } from '../types/util'
|
|
3
|
+
import type { ErrorBag, ValidationErrors } from '../types/validation'
|
|
4
|
+
import type { FormField } from '../types/form'
|
|
5
5
|
|
|
6
6
|
export function splitPath(path: string): string[] {
|
|
7
|
-
if (path ===
|
|
8
|
-
return []
|
|
7
|
+
if (path === '') {
|
|
8
|
+
return []
|
|
9
9
|
}
|
|
10
|
-
return path.split(/\s*\.\s*/).filter(Boolean)
|
|
10
|
+
return path.split(/\s*\.\s*/).filter(Boolean)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export function existsPath<T, K extends Paths<T>>(
|
|
14
14
|
obj: T,
|
|
15
15
|
path: K | SplitPath<K>,
|
|
16
16
|
): boolean {
|
|
17
|
-
const splittedPath = Array.isArray(path) ? path : splitPath(path) as SplitPath<K
|
|
18
|
-
return !!getNestedValue(obj, splittedPath.slice(0, -1) as SplitPath<K>)
|
|
17
|
+
const splittedPath = Array.isArray(path) ? path : splitPath(path) as SplitPath<K>
|
|
18
|
+
return !!getNestedValue(obj, splittedPath.slice(0, -1) as SplitPath<K>)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function existsFieldPath<T, K extends Paths<T>>(field: FormField<T, K>) {
|
|
@@ -26,11 +26,11 @@ export function getNestedValue<T, K extends Paths<T>>(
|
|
|
26
26
|
obj: T,
|
|
27
27
|
path: K | SplitPath<K>,
|
|
28
28
|
) {
|
|
29
|
-
const splittedPath = Array.isArray(path) ? path : splitPath(path)
|
|
29
|
+
const splittedPath = Array.isArray(path) ? path : splitPath(path)
|
|
30
30
|
return splittedPath.reduce(
|
|
31
31
|
(current, key) => current?.[key],
|
|
32
32
|
obj as Record<string, never>,
|
|
33
|
-
) as PickProps<T, K
|
|
33
|
+
) as PickProps<T, K>
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export function setNestedValue<T, K extends Paths<T>>(
|
|
@@ -38,31 +38,31 @@ export function setNestedValue<T, K extends Paths<T>>(
|
|
|
38
38
|
path: K | SplitPath<K>,
|
|
39
39
|
value: PickProps<T, K>,
|
|
40
40
|
): void {
|
|
41
|
-
const keys = Array.isArray(path) ? path : splitPath(path)
|
|
41
|
+
const keys = Array.isArray(path) ? path : splitPath(path)
|
|
42
42
|
|
|
43
|
-
const lastKey = keys.at(-1)
|
|
43
|
+
const lastKey = keys.at(-1)!
|
|
44
44
|
|
|
45
45
|
if (!lastKey) {
|
|
46
46
|
if (!isRef(obj)) {
|
|
47
47
|
// We cannot do anything here as we have nothing we can assign to
|
|
48
|
-
return
|
|
48
|
+
return
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
obj.value = value
|
|
51
|
+
obj.value = value
|
|
52
52
|
} else {
|
|
53
53
|
const target = keys.slice(0, -1).reduce(
|
|
54
54
|
(current, key) => {
|
|
55
55
|
if (current?.[key] === undefined) {
|
|
56
56
|
// Create the nested object if it doesn't exist
|
|
57
|
-
current[key] = {}
|
|
57
|
+
current[key] = {}
|
|
58
58
|
}
|
|
59
|
-
return current?.[key]
|
|
59
|
+
return current?.[key]
|
|
60
60
|
},
|
|
61
61
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
62
|
unref(obj) as Record<string, any>,
|
|
63
|
-
)
|
|
63
|
+
)
|
|
64
64
|
|
|
65
|
-
target[lastKey] = value
|
|
65
|
+
target[lastKey] = value
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -72,58 +72,57 @@ export const getLens = <T, K extends Paths<T>>(
|
|
|
72
72
|
) => {
|
|
73
73
|
return computed({
|
|
74
74
|
get() {
|
|
75
|
-
return getNestedValue(unref(data), unref(key))
|
|
75
|
+
return getNestedValue(unref(data), unref(key))
|
|
76
76
|
},
|
|
77
77
|
set(value: PickProps<T, K>) {
|
|
78
|
-
setNestedValue(data, unref(key), value)
|
|
78
|
+
setNestedValue(data, unref(key), value)
|
|
79
79
|
},
|
|
80
|
-
})
|
|
81
|
-
}
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
82
|
|
|
83
83
|
type JoinPath<
|
|
84
84
|
Base extends string,
|
|
85
85
|
Sub extends string,
|
|
86
|
-
> = `${Base}${Base extends
|
|
86
|
+
> = `${Base}${Base extends '' ? '' : Sub extends '' ? '' : '.'}${Sub}`
|
|
87
87
|
export function joinPath<Base extends string, Sub extends string>(
|
|
88
88
|
basePath: Base,
|
|
89
89
|
subPath: Sub,
|
|
90
90
|
): JoinPath<Base, Sub> {
|
|
91
91
|
if (!basePath && !subPath) {
|
|
92
|
-
return
|
|
92
|
+
return '' as JoinPath<Base, Sub>
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
if (!basePath && subPath) {
|
|
96
|
-
return subPath as JoinPath<Base, Sub
|
|
96
|
+
return subPath as JoinPath<Base, Sub>
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
if (!subPath && basePath) {
|
|
100
|
-
return basePath as JoinPath<Base, Sub
|
|
100
|
+
return basePath as JoinPath<Base, Sub>
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
return `${basePath}.${subPath}` as JoinPath<Base, Sub
|
|
103
|
+
return `${basePath}.${subPath}` as JoinPath<Base, Sub>
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
export function filterErrorsForPath(errors: ErrorBag, path: string): ErrorBag {
|
|
107
107
|
// Handle empty path - return all errors
|
|
108
108
|
if (!path) {
|
|
109
|
-
return errors
|
|
109
|
+
return errors
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
const pathPrefix = `${path}
|
|
113
|
-
const filteredPropertyErrors: Record<string, ValidationErrors> =
|
|
114
|
-
Object.
|
|
115
|
-
|
|
116
|
-
.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
);
|
|
112
|
+
const pathPrefix = `${path}.`
|
|
113
|
+
const filteredPropertyErrors: Record<string, ValidationErrors> = Object.fromEntries(
|
|
114
|
+
Object.entries(errors.propertyErrors)
|
|
115
|
+
.filter(([errorPath]) => {
|
|
116
|
+
return errorPath.startsWith(pathPrefix)
|
|
117
|
+
})
|
|
118
|
+
.map(([errorPath, errorMessages]) => [
|
|
119
|
+
errorPath.slice(pathPrefix.length),
|
|
120
|
+
errorMessages,
|
|
121
|
+
]),
|
|
122
|
+
)
|
|
124
123
|
|
|
125
124
|
return {
|
|
126
125
|
general: errors.general, // Keep general errors
|
|
127
126
|
propertyErrors: filteredPropertyErrors,
|
|
128
|
-
}
|
|
127
|
+
}
|
|
129
128
|
}
|