@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.
@@ -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 FieldArray<Item> {
14
- fields: Ref<{
15
- id: string;
16
- item: Item;
17
- }[]>;
18
- push: (item: Item) => void;
19
- remove: (item: Item) => void;
20
- removeByIndex: (index: number) => void;
21
- errors: Ref<ValidationErrors>;
22
- dirty: Ref<boolean>;
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamnovu/kit-vue-forms",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,9 +1,11 @@
1
- import { shallowRef, unref, watch } from 'vue'
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[], Item>,
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
- const arrayField = form.getField(path)
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 fields = shallowRef<Field[]>([])
115
+ const items = shallowRef<Field[]>([])
107
116
 
108
117
  watch(
109
118
  arrayField.data,
110
119
  (newItems) => {
111
- fields.value = mapIds(hashStore, newItems) as Field[]
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 = (value: Item) => {
125
- const current = (arrayField.data.value ?? []) as Item[]
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
- (current?.filter(item => item !== unref(value)) ?? []) as Items,
146
+ currentData
147
+ .slice(0, currentItem)
148
+ .concat(currentData.slice(currentItem + 1)) as Items,
128
149
  )
129
150
  }
130
151
 
131
- const removeByIndex = (index: number) => {
132
- const current = (arrayField.data.value ?? []) as Item[]
133
- arrayField.setData((current?.filter((_, i) => i !== index) ?? []) as Items)
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
- fields,
166
+ items,
138
167
  push,
139
168
  remove,
140
- removeByIndex,
141
- errors: arrayField.errors,
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 FieldArray<Item> {
24
- fields: Ref<{
25
- id: string
26
- item: Item
27
- }[]>
28
- push: (item: Item) => void
29
- remove: (item: Item) => void
30
- removeByIndex: (index: number) => void
31
- errors: Ref<ValidationErrors>
32
- dirty: Ref<boolean>
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> {