@teamnovu/kit-vue-forms 0.1.22 → 0.1.24
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/composables/useFieldArray.d.ts +1 -1
- package/dist/index.js +217 -212
- package/dist/types/form.d.ts +12 -11
- package/package.json +1 -1
- package/src/composables/useFieldArray.ts +47 -19
- package/src/types/form.ts +13 -11
- package/tests/useFieldArray.test.ts +237 -268
package/dist/types/form.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Awaitable } from '@vueuse/core';
|
|
2
|
-
import { Ref } from 'vue';
|
|
2
|
+
import { Ref, ShallowRef } from 'vue';
|
|
3
3
|
import { DefineFieldOptions } from '../composables/useFieldRegistry';
|
|
4
4
|
import { SubformOptions } from '../composables/useSubform';
|
|
5
5
|
import { ValidatorOptions } from '../composables/useValidation';
|
|
@@ -10,16 +10,17 @@ export type HashFn<H, I> = (item: I) => H;
|
|
|
10
10
|
export interface FieldArrayOptions<Item> {
|
|
11
11
|
hashFn?: HashFn<unknown, Item>;
|
|
12
12
|
}
|
|
13
|
-
export interface
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
export interface FieldItem<Item, Path extends string> {
|
|
14
|
+
id: string;
|
|
15
|
+
item: Item;
|
|
16
|
+
path: `${Path}.${number}`;
|
|
17
|
+
}
|
|
18
|
+
export interface FieldArray<Item, Path extends string> {
|
|
19
|
+
items: ShallowRef<FieldItem<Item, Path>[]>;
|
|
20
|
+
push: (item: Item) => FieldItem<Item, Path>;
|
|
21
|
+
remove: (id: string) => void;
|
|
22
|
+
insert: (item: Item, index: number) => FieldItem<Item, Path>;
|
|
23
|
+
field: FormField<Item[], Path>;
|
|
23
24
|
}
|
|
24
25
|
export interface FormField<T, P extends string> {
|
|
25
26
|
data: Ref<T>;
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { shallowRef,
|
|
1
|
+
import { shallowRef, watch } from 'vue'
|
|
2
2
|
import type {
|
|
3
3
|
FieldArray,
|
|
4
4
|
FieldArrayOptions,
|
|
5
|
+
FieldItem,
|
|
5
6
|
Form,
|
|
6
7
|
FormDataDefault,
|
|
8
|
+
FormField,
|
|
7
9
|
HashFn,
|
|
8
10
|
} from '../types/form'
|
|
9
11
|
import type { Paths, PickProps } from '../types/util'
|
|
@@ -49,13 +51,15 @@ export class HashStore<T, Item = unknown> {
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
function mapIds<Item>(
|
|
53
|
-
hashStore: HashStore<string[],
|
|
54
|
+
function mapIds<Item, Path extends string>(
|
|
55
|
+
hashStore: HashStore<string[],
|
|
56
|
+
Item>,
|
|
54
57
|
items: Item[],
|
|
55
|
-
|
|
58
|
+
basePath: Path,
|
|
59
|
+
): FieldItem<Item, Path>[] {
|
|
56
60
|
const mappedIds = new Set<string>()
|
|
57
61
|
|
|
58
|
-
return items.map((item) => {
|
|
62
|
+
return items.map((item, i) => {
|
|
59
63
|
const storeIds = [...(hashStore.get(item) ?? [])]
|
|
60
64
|
|
|
61
65
|
// Remove all used ids
|
|
@@ -70,6 +74,7 @@ function mapIds<Item>(
|
|
|
70
74
|
return {
|
|
71
75
|
id: matchingId,
|
|
72
76
|
item,
|
|
77
|
+
path: `${basePath}.${i}`,
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
|
|
@@ -82,6 +87,7 @@ function mapIds<Item>(
|
|
|
82
87
|
return {
|
|
83
88
|
id: newId,
|
|
84
89
|
item,
|
|
90
|
+
path: `${basePath}.${i}`,
|
|
85
91
|
}
|
|
86
92
|
})
|
|
87
93
|
}
|
|
@@ -90,25 +96,28 @@ export function useFieldArray<T extends FormDataDefault, K extends Paths<T>>(
|
|
|
90
96
|
form: Form<T>,
|
|
91
97
|
path: PickProps<T, K> extends unknown[] ? K : never,
|
|
92
98
|
options?: FieldArrayOptions<PickProps<T, K> extends (infer U)[] ? U : never>,
|
|
93
|
-
): FieldArray<PickProps<T, K> extends (infer U)[] ? U : never> {
|
|
99
|
+
): FieldArray<PickProps<T, K> extends (infer U)[] ? U : never, typeof path> {
|
|
94
100
|
type Items = PickProps<T, K>
|
|
95
101
|
type Item = Items extends (infer U)[] ? U : never
|
|
96
102
|
type Id = string
|
|
103
|
+
type Path = typeof path
|
|
97
104
|
type Field = {
|
|
98
105
|
id: Id
|
|
99
106
|
item: Item
|
|
107
|
+
path: `${Path}.${number}`
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
const hashStore = new HashStore<string[], Item>(options?.hashFn)
|
|
103
111
|
|
|
104
|
-
|
|
112
|
+
// We only cast to unknown because we know that the constriant holds true
|
|
113
|
+
const arrayField = form.getField(path) as unknown as FormField<Item[], Path>
|
|
105
114
|
|
|
106
|
-
const
|
|
115
|
+
const items = shallowRef<Field[]>([])
|
|
107
116
|
|
|
108
117
|
watch(
|
|
109
118
|
arrayField.data,
|
|
110
119
|
(newItems) => {
|
|
111
|
-
|
|
120
|
+
items.value = mapIds(hashStore, newItems, path) as Field[]
|
|
112
121
|
},
|
|
113
122
|
{
|
|
114
123
|
immediate: true,
|
|
@@ -119,26 +128,45 @@ export function useFieldArray<T extends FormDataDefault, K extends Paths<T>>(
|
|
|
119
128
|
const push = (item: Item) => {
|
|
120
129
|
const current = (arrayField.data.value ?? []) as Item[]
|
|
121
130
|
arrayField.setData([...current, item] as Items)
|
|
131
|
+
|
|
132
|
+
return items.value.at(-1)!
|
|
122
133
|
}
|
|
123
134
|
|
|
124
|
-
const remove = (
|
|
125
|
-
const
|
|
135
|
+
const remove = (id: Id) => {
|
|
136
|
+
const currentData = (arrayField.data.value ?? []) as Item[]
|
|
137
|
+
const currentItem = items.value.findIndex(
|
|
138
|
+
({ id: itemId }) => itemId === id,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
if (currentItem === -1) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
126
145
|
arrayField.setData(
|
|
127
|
-
|
|
146
|
+
currentData
|
|
147
|
+
.slice(0, currentItem)
|
|
148
|
+
.concat(currentData.slice(currentItem + 1)) as Items,
|
|
128
149
|
)
|
|
129
150
|
}
|
|
130
151
|
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
|
|
152
|
+
const insert = (item: Item, index: number) => {
|
|
153
|
+
const currentData = (arrayField.data.value ?? []) as Item[]
|
|
154
|
+
|
|
155
|
+
arrayField.setData(
|
|
156
|
+
currentData
|
|
157
|
+
.slice(0, index)
|
|
158
|
+
.concat([item])
|
|
159
|
+
.concat(currentData.slice(index)) as Items,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
return items.value[index]!
|
|
134
163
|
}
|
|
135
164
|
|
|
136
165
|
return {
|
|
137
|
-
|
|
166
|
+
items,
|
|
138
167
|
push,
|
|
139
168
|
remove,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
dirty: arrayField.dirty,
|
|
169
|
+
insert,
|
|
170
|
+
field: arrayField,
|
|
143
171
|
}
|
|
144
172
|
}
|
package/src/types/form.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Awaitable } from '@vueuse/core'
|
|
2
|
-
import type { Ref } from 'vue'
|
|
2
|
+
import type { Ref, ShallowRef } from 'vue'
|
|
3
3
|
import type { DefineFieldOptions } from '../composables/useFieldRegistry'
|
|
4
4
|
import type { SubformOptions } from '../composables/useSubform'
|
|
5
5
|
import type { ValidatorOptions } from '../composables/useValidation'
|
|
@@ -20,16 +20,18 @@ export interface FieldArrayOptions<Item> {
|
|
|
20
20
|
hashFn?: HashFn<unknown, Item>
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export interface
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
export interface FieldItem<Item, Path extends string> {
|
|
24
|
+
id: string
|
|
25
|
+
item: Item
|
|
26
|
+
path: `${Path}.${number}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface FieldArray<Item, Path extends string> {
|
|
30
|
+
items: ShallowRef<FieldItem<Item, Path>[]>
|
|
31
|
+
push: (item: Item) => FieldItem<Item, Path>
|
|
32
|
+
remove: (id: string) => void
|
|
33
|
+
insert: (item: Item, index: number) => FieldItem<Item, Path>
|
|
34
|
+
field: FormField<Item[], Path>
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export interface FormField<T, P extends string> {
|