@teamnovu/kit-vue-forms 0.1.22 → 0.1.23
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 +228 -229
- package/dist/types/form.d.ts +11 -11
- package/package.json +1 -1
- package/src/composables/useFieldArray.ts +35 -21
- package/src/types/form.ts +12 -11
- package/tests/useFieldArray.test.ts +25 -163
|
@@ -10,4 +10,4 @@ export declare class HashStore<T, Item = unknown> {
|
|
|
10
10
|
get(item: Item): T | undefined;
|
|
11
11
|
set(item: Item, value: T): void;
|
|
12
12
|
}
|
|
13
|
-
export declare function useFieldArray<T extends FormDataDefault, K extends Paths<T>>(form: Form<T>, path: PickProps<T, K> extends unknown[] ? K : never, options?: FieldArrayOptions<PickProps<T, K> extends (infer U)[] ? U : never>): FieldArray<PickProps<T, K> extends (infer U)[] ? U : never>;
|
|
13
|
+
export declare function useFieldArray<T extends FormDataDefault, K extends Paths<T>>(form: Form<T>, path: PickProps<T, K> extends unknown[] ? K : never, options?: FieldArrayOptions<PickProps<T, K> extends (infer U)[] ? U : never>): FieldArray<PickProps<T, K> extends (infer U)[] ? U : never, typeof path>;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var Q = Object.defineProperty;
|
|
2
2
|
var X = (r, t, e) => t in r ? Q(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
|
|
3
3
|
var R = (r, t, e) => X(r, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
-
import { toValue as Y, toRaw as ee, unref as
|
|
4
|
+
import { toValue as Y, toRaw as ee, unref as f, shallowRef as $, watch as D, computed as m, isRef as x, reactive as k, toRefs as K, shallowReactive as te, toRef as j, onScopeDispose as re, triggerRef as ae, ref as J, getCurrentScope as se, onBeforeUnmount as ne, defineComponent as C, renderSlot as b, normalizeProps as T, guardReactiveProps as N, resolveComponent as ie, createBlock as z, openBlock as H, withCtx as U, resolveDynamicComponent as oe, mergeProps as le, createSlots as ce, renderList as ue } from "vue";
|
|
5
5
|
import { cloneDeep as de } from "lodash-es";
|
|
6
6
|
import "zod";
|
|
7
7
|
function g(r) {
|
|
@@ -10,7 +10,7 @@ function g(r) {
|
|
|
10
10
|
}
|
|
11
11
|
function L(r, t) {
|
|
12
12
|
return (e) => async (a) => {
|
|
13
|
-
a.preventDefault(),
|
|
13
|
+
a.preventDefault(), f(t.validationStrategy) !== "none" && await r.validateForm(), r.isValid.value && await e(r.data.value);
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
class fe {
|
|
@@ -36,51 +36,50 @@ class fe {
|
|
|
36
36
|
this.isReferenceType(a) ? this.weakMap.set(a, e) : this.map.set(a, e);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
function he(r, t) {
|
|
40
|
-
const
|
|
41
|
-
return t.map((
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
return
|
|
45
|
-
id:
|
|
46
|
-
item:
|
|
39
|
+
function he(r, t, e) {
|
|
40
|
+
const a = /* @__PURE__ */ new Set();
|
|
41
|
+
return t.map((s, n) => {
|
|
42
|
+
const d = [...r.get(s) ?? []], V = d.findIndex((p) => !a.has(p)), c = (V === -1 ? [] : d.slice(V))[0];
|
|
43
|
+
if (c)
|
|
44
|
+
return a.add(c), {
|
|
45
|
+
id: c,
|
|
46
|
+
item: s,
|
|
47
|
+
path: `${e}.${n}`
|
|
47
48
|
};
|
|
48
|
-
const
|
|
49
|
-
return r.set(
|
|
50
|
-
id:
|
|
51
|
-
item:
|
|
49
|
+
const o = crypto.randomUUID();
|
|
50
|
+
return r.set(s, d.concat([o])), a.add(o), {
|
|
51
|
+
id: o,
|
|
52
|
+
item: s,
|
|
53
|
+
path: `${e}.${n}`
|
|
52
54
|
};
|
|
53
55
|
});
|
|
54
56
|
}
|
|
55
57
|
function G(r, t, e) {
|
|
56
|
-
const a = new fe(e == null ? void 0 : e.hashFn), s = r.getField(t), n =
|
|
58
|
+
const a = new fe(e == null ? void 0 : e.hashFn), s = r.getField(t), n = $([]);
|
|
57
59
|
return D(
|
|
58
60
|
s.data,
|
|
59
|
-
(
|
|
60
|
-
n.value = he(a,
|
|
61
|
+
(h) => {
|
|
62
|
+
n.value = he(a, h, t);
|
|
61
63
|
},
|
|
62
64
|
{
|
|
63
65
|
immediate: !0,
|
|
64
66
|
flush: "sync"
|
|
65
67
|
}
|
|
66
68
|
), {
|
|
67
|
-
|
|
68
|
-
push: (
|
|
69
|
-
const
|
|
70
|
-
s.setData([...
|
|
69
|
+
items: n,
|
|
70
|
+
push: (h) => {
|
|
71
|
+
const c = s.data.value ?? [];
|
|
72
|
+
return s.setData([...c, h]), n.value.at(-1);
|
|
71
73
|
},
|
|
72
|
-
remove: (
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
remove: (h) => {
|
|
75
|
+
const c = s.data.value ?? [], o = n.value.findIndex(
|
|
76
|
+
({ id: p }) => p === h
|
|
77
|
+
);
|
|
78
|
+
o !== -1 && s.setData(
|
|
79
|
+
c.slice(0, o).concat(c.slice(o + 1))
|
|
76
80
|
);
|
|
77
81
|
},
|
|
78
|
-
|
|
79
|
-
const i = s.data.value ?? [];
|
|
80
|
-
s.setData((i == null ? void 0 : i.filter((h, l) => l !== c)) ?? []);
|
|
81
|
-
},
|
|
82
|
-
errors: s.errors,
|
|
83
|
-
dirty: s.dirty
|
|
82
|
+
field: s
|
|
84
83
|
};
|
|
85
84
|
}
|
|
86
85
|
function W(r) {
|
|
@@ -100,26 +99,26 @@ function ve(r, t, e) {
|
|
|
100
99
|
const a = Array.isArray(t) ? t : W(t), s = a.at(-1);
|
|
101
100
|
if (s) {
|
|
102
101
|
const n = a.slice(0, -1).reduce(
|
|
103
|
-
(
|
|
102
|
+
(d, V) => ((d == null ? void 0 : d[V]) === void 0 && (d[V] = {}), d == null ? void 0 : d[V]),
|
|
104
103
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
|
-
|
|
104
|
+
f(r)
|
|
106
105
|
);
|
|
107
106
|
n[s] = e;
|
|
108
107
|
} else {
|
|
109
|
-
if (!
|
|
108
|
+
if (!x(r))
|
|
110
109
|
return;
|
|
111
110
|
r.value = e;
|
|
112
111
|
}
|
|
113
112
|
}
|
|
114
|
-
const Z = (r, t) =>
|
|
113
|
+
const Z = (r, t) => m({
|
|
115
114
|
get() {
|
|
116
|
-
return S(
|
|
115
|
+
return S(f(r), f(t));
|
|
117
116
|
},
|
|
118
117
|
set(e) {
|
|
119
|
-
ve(r,
|
|
118
|
+
ve(r, f(t), e);
|
|
120
119
|
}
|
|
121
120
|
});
|
|
122
|
-
function
|
|
121
|
+
function I(r, t) {
|
|
123
122
|
return !r && !t ? "" : !r && t ? t : !t && r ? r : `${r}.${t}`;
|
|
124
123
|
}
|
|
125
124
|
function me(r, t) {
|
|
@@ -149,13 +148,13 @@ class Ve {
|
|
|
149
148
|
this.rc > 0 && (this.rc -= 1, this.rc === 0 && this.drop && this.drop());
|
|
150
149
|
}
|
|
151
150
|
}
|
|
152
|
-
function
|
|
151
|
+
function Fe(r) {
|
|
153
152
|
const e = {
|
|
154
153
|
...{
|
|
155
154
|
existsInForm: !0
|
|
156
155
|
},
|
|
157
156
|
...r
|
|
158
|
-
}, a =
|
|
157
|
+
}, a = $(Object.freeze(g(e.initialValue))), s = k({
|
|
159
158
|
value: e.value,
|
|
160
159
|
path: e.path,
|
|
161
160
|
initialValue: a,
|
|
@@ -163,51 +162,51 @@ function ye(r) {
|
|
|
163
162
|
touched: !1
|
|
164
163
|
});
|
|
165
164
|
D(
|
|
166
|
-
|
|
165
|
+
$(e.initialValue),
|
|
167
166
|
() => {
|
|
168
|
-
a.value = Object.freeze(g(e.initialValue)), s.value !==
|
|
167
|
+
a.value = Object.freeze(g(e.initialValue)), s.value !== f(e.initialValue) && (s.value = g(e.initialValue));
|
|
169
168
|
},
|
|
170
169
|
{ flush: "sync" }
|
|
171
170
|
);
|
|
172
|
-
const n =
|
|
173
|
-
s.value =
|
|
174
|
-
},
|
|
175
|
-
var
|
|
176
|
-
s.touched = !0, s.errors = [], (
|
|
177
|
-
},
|
|
178
|
-
var
|
|
179
|
-
(
|
|
171
|
+
const n = m(() => JSON.stringify(s.value) !== JSON.stringify(s.initialValue)), d = (v) => {
|
|
172
|
+
s.value = v;
|
|
173
|
+
}, V = () => {
|
|
174
|
+
var v;
|
|
175
|
+
s.touched = !0, s.errors = [], (v = e.onBlur) == null || v.call(e);
|
|
176
|
+
}, h = () => {
|
|
177
|
+
var v;
|
|
178
|
+
(v = e.onFocus) == null || v.call(e);
|
|
180
179
|
}, c = () => {
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
},
|
|
184
|
-
n.value ||
|
|
185
|
-
},
|
|
186
|
-
s.errors =
|
|
180
|
+
const v = s.path.split(".").at(-1) || "";
|
|
181
|
+
f(e.existsInForm) && !/^\d+$/.test(v) && (s.value = g(s.initialValue)), s.touched = !1, s.errors = [];
|
|
182
|
+
}, o = (v) => {
|
|
183
|
+
n.value || d(g(v)), s.initialValue = v;
|
|
184
|
+
}, p = (v) => {
|
|
185
|
+
s.errors = v;
|
|
187
186
|
}, l = () => {
|
|
188
187
|
s.errors = [];
|
|
189
|
-
},
|
|
188
|
+
}, i = K(s);
|
|
190
189
|
return {
|
|
191
|
-
data:
|
|
192
|
-
path:
|
|
193
|
-
initialValue:
|
|
194
|
-
errors:
|
|
195
|
-
touched:
|
|
190
|
+
data: i.value,
|
|
191
|
+
path: i.path,
|
|
192
|
+
initialValue: i.initialValue,
|
|
193
|
+
errors: i.errors,
|
|
194
|
+
touched: i.touched,
|
|
196
195
|
dirty: n,
|
|
197
|
-
setData:
|
|
198
|
-
setInitialData:
|
|
199
|
-
onBlur:
|
|
200
|
-
onFocus:
|
|
196
|
+
setData: d,
|
|
197
|
+
setInitialData: o,
|
|
198
|
+
onBlur: V,
|
|
199
|
+
onFocus: h,
|
|
201
200
|
reset: c,
|
|
202
|
-
setErrors:
|
|
201
|
+
setErrors: p,
|
|
203
202
|
clearErrors: l
|
|
204
203
|
};
|
|
205
204
|
}
|
|
206
|
-
const
|
|
205
|
+
const ye = {
|
|
207
206
|
keepValuesOnUnmount: !0
|
|
208
207
|
};
|
|
209
208
|
function ge(r, t) {
|
|
210
|
-
const e = () => S(r.initialData, t), a =
|
|
209
|
+
const e = () => S(r.initialData, t), a = $(e());
|
|
211
210
|
return D(
|
|
212
211
|
() => r.initialData,
|
|
213
212
|
() => {
|
|
@@ -218,68 +217,68 @@ function ge(r, t) {
|
|
|
218
217
|
}
|
|
219
218
|
function Ee(r, t, e) {
|
|
220
219
|
const a = /* @__PURE__ */ new Map(), s = te(/* @__PURE__ */ new Map()), n = {
|
|
221
|
-
...
|
|
220
|
+
...ye,
|
|
222
221
|
...e
|
|
223
|
-
},
|
|
224
|
-
const
|
|
225
|
-
s.set(
|
|
226
|
-
},
|
|
227
|
-
var
|
|
228
|
-
n != null && n.keepValuesOnUnmount || (
|
|
229
|
-
},
|
|
230
|
-
var
|
|
231
|
-
a.has(l) ? (
|
|
222
|
+
}, d = (l) => {
|
|
223
|
+
const i = f(l.path);
|
|
224
|
+
s.set(i, l);
|
|
225
|
+
}, V = (l) => {
|
|
226
|
+
var i;
|
|
227
|
+
n != null && n.keepValuesOnUnmount || (i = s.get(l)) == null || i.reset(), s.delete(l);
|
|
228
|
+
}, h = (l) => {
|
|
229
|
+
var i;
|
|
230
|
+
a.has(l) ? (i = a.get(l)) == null || i.inc() : a.set(l, new Ve(() => V(l)));
|
|
232
231
|
}, c = (l) => {
|
|
233
|
-
var
|
|
234
|
-
a.has(l) && ((
|
|
235
|
-
},
|
|
236
|
-
const { path:
|
|
237
|
-
if (!s.has(
|
|
238
|
-
const
|
|
239
|
-
path:
|
|
240
|
-
value: Z(
|
|
241
|
-
initialValue: ge(r,
|
|
242
|
-
existsInForm:
|
|
243
|
-
errors:
|
|
232
|
+
var i;
|
|
233
|
+
a.has(l) && ((i = a.get(l)) == null || i.dec());
|
|
234
|
+
}, o = (l) => {
|
|
235
|
+
const { path: i } = l;
|
|
236
|
+
if (!s.has(i)) {
|
|
237
|
+
const A = Fe({
|
|
238
|
+
path: i,
|
|
239
|
+
value: Z(j(r, "data"), i),
|
|
240
|
+
initialValue: ge(r, i),
|
|
241
|
+
existsInForm: m(() => pe(r.data, f(i))),
|
|
242
|
+
errors: m({
|
|
244
243
|
get() {
|
|
245
|
-
return t.errors.value.propertyErrors[
|
|
244
|
+
return t.errors.value.propertyErrors[i] || [];
|
|
246
245
|
},
|
|
247
246
|
set(E) {
|
|
248
|
-
t.errors.value.propertyErrors[
|
|
247
|
+
t.errors.value.propertyErrors[i] = E;
|
|
249
248
|
}
|
|
250
249
|
}),
|
|
251
250
|
onBlur: async () => {
|
|
252
251
|
var E, P;
|
|
253
252
|
await Promise.all([
|
|
254
|
-
(E = n == null ? void 0 : n.onBlur) == null ? void 0 : E.call(n,
|
|
253
|
+
(E = n == null ? void 0 : n.onBlur) == null ? void 0 : E.call(n, f(i)),
|
|
255
254
|
(P = l.onBlur) == null ? void 0 : P.call(l)
|
|
256
255
|
]);
|
|
257
256
|
},
|
|
258
257
|
onFocus: async () => {
|
|
259
258
|
var E, P;
|
|
260
259
|
await Promise.all([
|
|
261
|
-
(E = n == null ? void 0 : n.onFocus) == null ? void 0 : E.call(n,
|
|
260
|
+
(E = n == null ? void 0 : n.onFocus) == null ? void 0 : E.call(n, f(i)),
|
|
262
261
|
(P = l.onFocus) == null ? void 0 : P.call(l)
|
|
263
262
|
]);
|
|
264
263
|
}
|
|
265
264
|
});
|
|
266
|
-
|
|
265
|
+
d(A);
|
|
267
266
|
}
|
|
268
|
-
const
|
|
269
|
-
return
|
|
270
|
-
c(
|
|
271
|
-
}),
|
|
272
|
-
},
|
|
267
|
+
const v = s.get(i);
|
|
268
|
+
return h(i), re(() => {
|
|
269
|
+
c(i);
|
|
270
|
+
}), v;
|
|
271
|
+
}, p = (l) => o(l);
|
|
273
272
|
return {
|
|
274
|
-
fields:
|
|
275
|
-
getField: (l) =>
|
|
276
|
-
registerField:
|
|
277
|
-
deregisterField:
|
|
278
|
-
defineField:
|
|
273
|
+
fields: m(() => [...s.values()]),
|
|
274
|
+
getField: (l) => o({ path: l }),
|
|
275
|
+
registerField: d,
|
|
276
|
+
deregisterField: V,
|
|
277
|
+
defineField: p
|
|
279
278
|
};
|
|
280
279
|
}
|
|
281
280
|
function we(r) {
|
|
282
|
-
const t =
|
|
281
|
+
const t = m(() => r.fields.value.some((a) => f(a.dirty))), e = m(() => r.fields.value.some((a) => f(a.touched)));
|
|
283
282
|
return {
|
|
284
283
|
isDirty: t,
|
|
285
284
|
isTouched: e
|
|
@@ -312,7 +311,7 @@ function De(...r) {
|
|
|
312
311
|
};
|
|
313
312
|
}, {});
|
|
314
313
|
}
|
|
315
|
-
function
|
|
314
|
+
function B(...r) {
|
|
316
315
|
if (!r.length)
|
|
317
316
|
return {
|
|
318
317
|
general: [],
|
|
@@ -345,7 +344,7 @@ function Pe(r) {
|
|
|
345
344
|
propertyErrors: e
|
|
346
345
|
};
|
|
347
346
|
}
|
|
348
|
-
const
|
|
347
|
+
const y = {
|
|
349
348
|
isValid: !0,
|
|
350
349
|
errors: {
|
|
351
350
|
general: [],
|
|
@@ -358,10 +357,10 @@ class Se {
|
|
|
358
357
|
}
|
|
359
358
|
async validate(t) {
|
|
360
359
|
if (!this.schema)
|
|
361
|
-
return
|
|
360
|
+
return y;
|
|
362
361
|
const e = await this.schema.safeParseAsync(t);
|
|
363
362
|
if (e.success)
|
|
364
|
-
return
|
|
363
|
+
return y;
|
|
365
364
|
const a = Pe(e.error);
|
|
366
365
|
return {
|
|
367
366
|
isValid: !1,
|
|
@@ -372,16 +371,16 @@ class Se {
|
|
|
372
371
|
};
|
|
373
372
|
}
|
|
374
373
|
}
|
|
375
|
-
class
|
|
374
|
+
class Ie {
|
|
376
375
|
constructor(t) {
|
|
377
376
|
this.validateFn = t;
|
|
378
377
|
}
|
|
379
378
|
async validate(t) {
|
|
380
379
|
if (!this.validateFn)
|
|
381
|
-
return
|
|
380
|
+
return y;
|
|
382
381
|
try {
|
|
383
382
|
const e = await this.validateFn(t);
|
|
384
|
-
return e.isValid ?
|
|
383
|
+
return e.isValid ? y : e;
|
|
385
384
|
} catch (e) {
|
|
386
385
|
return {
|
|
387
386
|
isValid: !1,
|
|
@@ -393,11 +392,11 @@ class be {
|
|
|
393
392
|
}
|
|
394
393
|
}
|
|
395
394
|
}
|
|
396
|
-
class
|
|
395
|
+
class $e {
|
|
397
396
|
constructor(t, e) {
|
|
398
397
|
R(this, "schemaValidator");
|
|
399
398
|
R(this, "functionValidator");
|
|
400
|
-
this.schema = t, this.validateFn = e, this.schemaValidator = new Se(this.schema), this.functionValidator = new
|
|
399
|
+
this.schema = t, this.validateFn = e, this.schemaValidator = new Se(this.schema), this.functionValidator = new Ie(this.validateFn);
|
|
401
400
|
}
|
|
402
401
|
async validate(t) {
|
|
403
402
|
const [e, a] = await Promise.all([
|
|
@@ -406,103 +405,103 @@ class Ie {
|
|
|
406
405
|
]);
|
|
407
406
|
return {
|
|
408
407
|
isValid: e.isValid && a.isValid,
|
|
409
|
-
errors:
|
|
408
|
+
errors: B(e.errors, a.errors)
|
|
410
409
|
};
|
|
411
410
|
}
|
|
412
411
|
}
|
|
413
|
-
function
|
|
414
|
-
return
|
|
415
|
-
|
|
416
|
-
|
|
412
|
+
function O(r) {
|
|
413
|
+
return m(() => new $e(
|
|
414
|
+
f(r.schema),
|
|
415
|
+
f(r.validateFn)
|
|
417
416
|
));
|
|
418
417
|
}
|
|
419
|
-
function
|
|
420
|
-
const e =
|
|
421
|
-
validators: J([
|
|
418
|
+
function be(r, t) {
|
|
419
|
+
const e = k({
|
|
420
|
+
validators: J([O(t)]),
|
|
422
421
|
isValidated: !1,
|
|
423
|
-
errors:
|
|
424
|
-
}), a = (
|
|
425
|
-
e.errors =
|
|
422
|
+
errors: f(t.errors) ?? y.errors
|
|
423
|
+
}), a = (o = y.errors) => {
|
|
424
|
+
e.errors = B(f(t.errors) ?? y.errors, o);
|
|
426
425
|
};
|
|
427
|
-
D(() =>
|
|
426
|
+
D(() => f(t.errors), async () => {
|
|
428
427
|
if (e.isValidated) {
|
|
429
|
-
const
|
|
430
|
-
a(
|
|
428
|
+
const o = await n();
|
|
429
|
+
a(o.errors);
|
|
431
430
|
} else
|
|
432
431
|
a();
|
|
433
432
|
}, { immediate: !0 }), D(
|
|
434
433
|
[() => e.validators],
|
|
435
|
-
async (
|
|
434
|
+
async (o) => {
|
|
436
435
|
if (e.isValidated)
|
|
437
|
-
if (
|
|
438
|
-
const
|
|
439
|
-
e.errors =
|
|
436
|
+
if (o) {
|
|
437
|
+
const p = await n();
|
|
438
|
+
e.errors = p.errors;
|
|
440
439
|
} else
|
|
441
|
-
e.errors =
|
|
440
|
+
e.errors = y.errors;
|
|
442
441
|
},
|
|
443
442
|
{ immediate: !0 }
|
|
444
|
-
), D([() => r.data, () =>
|
|
445
|
-
e.isValidated &&
|
|
443
|
+
), D([() => r.data, () => f(t.schema)], () => {
|
|
444
|
+
e.isValidated && d();
|
|
446
445
|
});
|
|
447
|
-
const s = (
|
|
448
|
-
const
|
|
449
|
-
return e.validators.push(
|
|
446
|
+
const s = (o) => {
|
|
447
|
+
const p = x(o) ? o : O(o);
|
|
448
|
+
return e.validators.push(p), se() && ne(() => {
|
|
450
449
|
e.validators = e.validators.filter(
|
|
451
|
-
(l) => l !==
|
|
450
|
+
(l) => l !== p
|
|
452
451
|
);
|
|
453
|
-
}),
|
|
452
|
+
}), p;
|
|
454
453
|
};
|
|
455
454
|
async function n() {
|
|
456
|
-
const
|
|
457
|
-
e.validators.filter((
|
|
458
|
-
),
|
|
459
|
-
let { errors: l } =
|
|
460
|
-
if (!
|
|
461
|
-
const
|
|
462
|
-
l =
|
|
455
|
+
const o = await Promise.all(
|
|
456
|
+
e.validators.filter((i) => f(i) !== void 0).map((i) => f(i).validate(r.data))
|
|
457
|
+
), p = o.every((i) => i.isValid);
|
|
458
|
+
let { errors: l } = y;
|
|
459
|
+
if (!p) {
|
|
460
|
+
const i = o.map((v) => v.errors);
|
|
461
|
+
l = B(...i);
|
|
463
462
|
}
|
|
464
463
|
return {
|
|
465
464
|
errors: l,
|
|
466
|
-
isValid:
|
|
465
|
+
isValid: p
|
|
467
466
|
};
|
|
468
467
|
}
|
|
469
|
-
const
|
|
470
|
-
const
|
|
471
|
-
return a(
|
|
472
|
-
isValid: !_(
|
|
468
|
+
const d = async () => {
|
|
469
|
+
const o = await n();
|
|
470
|
+
return a(o.errors), e.isValidated = !0, {
|
|
471
|
+
isValid: !_(o.errors),
|
|
473
472
|
errors: e.errors
|
|
474
473
|
};
|
|
475
|
-
},
|
|
476
|
-
const
|
|
474
|
+
}, V = async (o) => {
|
|
475
|
+
const p = await n();
|
|
477
476
|
return a({
|
|
478
|
-
general:
|
|
477
|
+
general: p.errors.general,
|
|
479
478
|
propertyErrors: {
|
|
480
|
-
[
|
|
479
|
+
[o]: p.errors.propertyErrors[o]
|
|
481
480
|
}
|
|
482
481
|
}), {
|
|
483
|
-
isValid: !_(
|
|
482
|
+
isValid: !_(p.errors),
|
|
484
483
|
errors: e.errors
|
|
485
484
|
};
|
|
486
|
-
},
|
|
487
|
-
e.isValidated = !1, e.errors =
|
|
485
|
+
}, h = m(() => !_(e.errors)), c = () => {
|
|
486
|
+
e.isValidated = !1, e.errors = f(t.errors) ?? y.errors;
|
|
488
487
|
};
|
|
489
488
|
return {
|
|
490
489
|
...K(e),
|
|
491
|
-
validateForm:
|
|
492
|
-
validateField:
|
|
490
|
+
validateForm: d,
|
|
491
|
+
validateField: V,
|
|
493
492
|
defineValidator: s,
|
|
494
|
-
isValid:
|
|
493
|
+
isValid: h,
|
|
495
494
|
reset: c
|
|
496
495
|
};
|
|
497
496
|
}
|
|
498
|
-
class
|
|
497
|
+
class ke {
|
|
499
498
|
constructor(t, e) {
|
|
500
499
|
this.path = t, this.validator = e;
|
|
501
500
|
}
|
|
502
501
|
async validate(t) {
|
|
503
502
|
const e = S(t, this.path);
|
|
504
503
|
if (!this.validator)
|
|
505
|
-
return
|
|
504
|
+
return y;
|
|
506
505
|
const a = await this.validator.validate(e);
|
|
507
506
|
return {
|
|
508
507
|
isValid: a.isValid,
|
|
@@ -510,68 +509,68 @@ class Ae {
|
|
|
510
509
|
general: a.errors.general || [],
|
|
511
510
|
propertyErrors: a.errors.propertyErrors ? Object.fromEntries(
|
|
512
511
|
Object.entries(a.errors.propertyErrors).map(
|
|
513
|
-
([s, n]) => [
|
|
512
|
+
([s, n]) => [I(this.path, s), n]
|
|
514
513
|
)
|
|
515
514
|
) : {}
|
|
516
515
|
}
|
|
517
516
|
};
|
|
518
517
|
}
|
|
519
518
|
}
|
|
520
|
-
function
|
|
521
|
-
const s = Z(r.data, t), n =
|
|
519
|
+
function Ae(r, t, e, a) {
|
|
520
|
+
const s = Z(r.data, t), n = m(() => S(r.initialData.value, t)), d = (u) => ({
|
|
522
521
|
...u,
|
|
523
|
-
path:
|
|
524
|
-
setData: (
|
|
525
|
-
u.setData(
|
|
522
|
+
path: m(() => f(u.path).replace(t + ".", "")),
|
|
523
|
+
setData: (F) => {
|
|
524
|
+
u.setData(F);
|
|
526
525
|
}
|
|
527
|
-
}),
|
|
528
|
-
const
|
|
529
|
-
return w ?
|
|
530
|
-
},
|
|
531
|
-
const
|
|
526
|
+
}), V = (u) => {
|
|
527
|
+
const F = I(t, u), w = r.getField(F);
|
|
528
|
+
return w ? d(w) : {};
|
|
529
|
+
}, h = (u) => {
|
|
530
|
+
const F = I(t, u.path), w = r.defineField({
|
|
532
531
|
...u,
|
|
533
|
-
path:
|
|
532
|
+
path: F
|
|
534
533
|
});
|
|
535
|
-
return
|
|
536
|
-
}, c =
|
|
537
|
-
const
|
|
538
|
-
return
|
|
539
|
-
}).map((u) =>
|
|
540
|
-
const
|
|
541
|
-
return
|
|
542
|
-
}),
|
|
534
|
+
return d(w);
|
|
535
|
+
}, c = m(() => r.fields.value.filter((u) => {
|
|
536
|
+
const F = u.path.value;
|
|
537
|
+
return F.startsWith(t + ".") || F === t;
|
|
538
|
+
}).map((u) => d(u))), o = () => r.fields.value.filter((u) => {
|
|
539
|
+
const F = u.path.value;
|
|
540
|
+
return F.startsWith(t + ".") || F === t;
|
|
541
|
+
}), p = m(() => o().some((u) => u.dirty.value)), l = m(() => o().some((u) => u.touched.value)), i = m(() => r.isValid.value), v = m(() => r.isValidated.value), A = m(() => me(f(r.errors), t)), M = {
|
|
543
542
|
data: s,
|
|
544
543
|
fields: c,
|
|
545
544
|
initialData: n,
|
|
546
|
-
defineField:
|
|
547
|
-
getField:
|
|
548
|
-
isDirty:
|
|
545
|
+
defineField: h,
|
|
546
|
+
getField: V,
|
|
547
|
+
isDirty: p,
|
|
549
548
|
isTouched: l,
|
|
550
|
-
isValid:
|
|
551
|
-
isValidated:
|
|
552
|
-
errors:
|
|
549
|
+
isValid: i,
|
|
550
|
+
isValidated: v,
|
|
551
|
+
errors: A,
|
|
553
552
|
defineValidator: (u) => {
|
|
554
|
-
const
|
|
555
|
-
() => new
|
|
553
|
+
const F = x(u) ? u : O(u), w = m(
|
|
554
|
+
() => new ke(t, f(F))
|
|
556
555
|
);
|
|
557
|
-
return r.defineValidator(w),
|
|
556
|
+
return r.defineValidator(w), F;
|
|
558
557
|
},
|
|
559
|
-
reset: () =>
|
|
558
|
+
reset: () => o().forEach((u) => u.reset()),
|
|
560
559
|
validateForm: () => r.validateForm(),
|
|
561
|
-
getSubForm: (u,
|
|
562
|
-
const w =
|
|
560
|
+
getSubForm: (u, F) => {
|
|
561
|
+
const w = I(t, u);
|
|
563
562
|
return r.getSubForm(
|
|
564
563
|
w,
|
|
565
|
-
|
|
564
|
+
F
|
|
566
565
|
);
|
|
567
566
|
},
|
|
568
|
-
submitHandler: (u) => L(
|
|
569
|
-
useFieldArray: (u,
|
|
567
|
+
submitHandler: (u) => L(M, e ?? {})(u),
|
|
568
|
+
useFieldArray: (u, F) => G(M, u, F)
|
|
570
569
|
};
|
|
571
|
-
return
|
|
570
|
+
return M;
|
|
572
571
|
}
|
|
573
|
-
function
|
|
574
|
-
const t =
|
|
572
|
+
function xe(r) {
|
|
573
|
+
const t = m(() => g(r.initialData)), e = J(g(t)), a = k({
|
|
575
574
|
initialData: t,
|
|
576
575
|
data: e
|
|
577
576
|
});
|
|
@@ -582,29 +581,29 @@ function Oe(r) {
|
|
|
582
581
|
},
|
|
583
582
|
{ flush: "sync" }
|
|
584
583
|
);
|
|
585
|
-
const s =
|
|
584
|
+
const s = be(a, r), n = Ee(a, s, {
|
|
586
585
|
keepValuesOnUnmount: r.keepValuesOnUnmount,
|
|
587
586
|
onBlur: async (c) => {
|
|
588
|
-
|
|
587
|
+
f(r.validationStrategy) === "onTouch" && s.validateField(c);
|
|
589
588
|
}
|
|
590
|
-
}),
|
|
589
|
+
}), d = we(n), V = () => {
|
|
591
590
|
e.value = g(t), s.reset();
|
|
592
591
|
for (const c of n.fields.value)
|
|
593
592
|
c.reset();
|
|
594
593
|
};
|
|
595
|
-
|
|
596
|
-
const
|
|
594
|
+
f(r.validationStrategy) === "onFormOpen" && s.validateForm();
|
|
595
|
+
const h = {
|
|
597
596
|
...n,
|
|
598
597
|
...s,
|
|
599
|
-
...
|
|
600
|
-
reset:
|
|
601
|
-
initialData:
|
|
602
|
-
data:
|
|
603
|
-
submitHandler: (c) => L(
|
|
604
|
-
getSubForm: (c,
|
|
605
|
-
useFieldArray: (c,
|
|
598
|
+
...d,
|
|
599
|
+
reset: V,
|
|
600
|
+
initialData: j(a, "initialData"),
|
|
601
|
+
data: j(a, "data"),
|
|
602
|
+
submitHandler: (c) => L(h, r)(c),
|
|
603
|
+
getSubForm: (c, o) => Ae(h, c, r),
|
|
604
|
+
useFieldArray: (c, o) => G(h, c, o)
|
|
606
605
|
};
|
|
607
|
-
return
|
|
606
|
+
return h;
|
|
608
607
|
}
|
|
609
608
|
const Ce = /* @__PURE__ */ C({
|
|
610
609
|
__name: "Field",
|
|
@@ -621,8 +620,8 @@ const Ce = /* @__PURE__ */ C({
|
|
|
621
620
|
setup(r) {
|
|
622
621
|
const t = r, e = t.form.defineField({
|
|
623
622
|
path: t.path
|
|
624
|
-
}), a =
|
|
625
|
-
return (s, n) =>
|
|
623
|
+
}), a = k(e);
|
|
624
|
+
return (s, n) => b(s.$slots, "default", T(N(a)));
|
|
626
625
|
}
|
|
627
626
|
}), Te = /* @__PURE__ */ C({
|
|
628
627
|
inheritAttrs: !1,
|
|
@@ -640,22 +639,22 @@ const Ce = /* @__PURE__ */ C({
|
|
|
640
639
|
form: r.form,
|
|
641
640
|
path: r.path
|
|
642
641
|
}, {
|
|
643
|
-
default:
|
|
642
|
+
default: U(({ errors: s, data: n, setData: d }) => [
|
|
644
643
|
(H(), z(oe(r.component), le({ ...r.componentProps, ...t.$attrs }, {
|
|
645
644
|
"model-value": n,
|
|
646
645
|
errors: s,
|
|
647
646
|
name: r.path,
|
|
648
|
-
"onUpdate:modelValue":
|
|
647
|
+
"onUpdate:modelValue": d
|
|
649
648
|
}), ce({
|
|
650
|
-
default:
|
|
651
|
-
|
|
649
|
+
default: U(() => [
|
|
650
|
+
b(t.$slots, "default")
|
|
652
651
|
]),
|
|
653
652
|
_: 2
|
|
654
653
|
}, [
|
|
655
|
-
ue(t.$slots, (
|
|
656
|
-
name:
|
|
657
|
-
fn:
|
|
658
|
-
|
|
654
|
+
ue(t.$slots, (V, h) => ({
|
|
655
|
+
name: h,
|
|
656
|
+
fn: U((c) => [
|
|
657
|
+
b(t.$slots, h, T(N(c ?? {})))
|
|
659
658
|
])
|
|
660
659
|
}))
|
|
661
660
|
]), 1040, ["model-value", "errors", "name", "onUpdate:modelValue"]))
|
|
@@ -671,13 +670,13 @@ const Ce = /* @__PURE__ */ C({
|
|
|
671
670
|
path: {}
|
|
672
671
|
},
|
|
673
672
|
setup(r) {
|
|
674
|
-
const t = r, e =
|
|
675
|
-
return (a, s) =>
|
|
673
|
+
const t = r, e = m(() => t.form.getSubForm(t.path));
|
|
674
|
+
return (a, s) => b(a.$slots, "default", T(N({ subform: e.value })));
|
|
676
675
|
}
|
|
677
676
|
});
|
|
678
677
|
export {
|
|
679
678
|
Ce as Field,
|
|
680
679
|
Te as FormFieldWrapper,
|
|
681
680
|
Ne as FormPart,
|
|
682
|
-
|
|
681
|
+
xe as useForm
|
|
683
682
|
};
|
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,16 @@ 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
|
+
field: FormField<Item[], Path>;
|
|
23
23
|
}
|
|
24
24
|
export interface FormField<T, P extends string> {
|
|
25
25
|
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,31 @@ 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
|
|
126
|
-
|
|
127
|
-
(
|
|
135
|
+
const remove = (id: Id) => {
|
|
136
|
+
const currentData = (arrayField.data.value ?? []) as Item[]
|
|
137
|
+
const currentItem = items.value.findIndex(
|
|
138
|
+
({ id: itemId }) => itemId === id,
|
|
128
139
|
)
|
|
129
|
-
}
|
|
130
140
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
141
|
+
if (currentItem === -1) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
arrayField.setData(
|
|
146
|
+
currentData
|
|
147
|
+
.slice(0, currentItem)
|
|
148
|
+
.concat(currentData.slice(currentItem + 1)) as Items,
|
|
149
|
+
)
|
|
134
150
|
}
|
|
135
151
|
|
|
136
152
|
return {
|
|
137
|
-
|
|
153
|
+
items,
|
|
138
154
|
push,
|
|
139
155
|
remove,
|
|
140
|
-
|
|
141
|
-
errors: arrayField.errors,
|
|
142
|
-
dirty: arrayField.dirty,
|
|
156
|
+
field: arrayField,
|
|
143
157
|
}
|
|
144
158
|
}
|
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,17 @@ 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
|
+
field: FormField<Item[], Path>
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export interface FormField<T, P extends string> {
|
|
@@ -70,121 +70,6 @@ describe('useFieldArray', () => {
|
|
|
70
70
|
})
|
|
71
71
|
})
|
|
72
72
|
|
|
73
|
-
describe('Core Functionality', () => {
|
|
74
|
-
it('should initialize with array data and generate IDs', () => {
|
|
75
|
-
const form = useForm({
|
|
76
|
-
initialData: {
|
|
77
|
-
items: [
|
|
78
|
-
{
|
|
79
|
-
id: 1,
|
|
80
|
-
name: 'Item 1',
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
id: 2,
|
|
84
|
-
name: 'Item 2',
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
},
|
|
88
|
-
})
|
|
89
|
-
const fieldArray = useFieldArray(form, 'items')
|
|
90
|
-
|
|
91
|
-
expect(fieldArray.fields.value).toHaveLength(2)
|
|
92
|
-
expect(fieldArray.fields.value[0]).toHaveProperty('id')
|
|
93
|
-
expect(fieldArray.fields.value[0]).toHaveProperty('item')
|
|
94
|
-
expect(fieldArray.fields.value[0].item).toEqual({
|
|
95
|
-
id: 1,
|
|
96
|
-
name: 'Item 1',
|
|
97
|
-
})
|
|
98
|
-
expect(typeof fieldArray.fields.value[0].id).toBe('string')
|
|
99
|
-
expect(fieldArray.errors.value).toEqual([])
|
|
100
|
-
expect(fieldArray.dirty.value).toBe(false)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('should push new items to the array', async () => {
|
|
104
|
-
const form = useForm({
|
|
105
|
-
initialData: {
|
|
106
|
-
items: [
|
|
107
|
-
{
|
|
108
|
-
id: 1,
|
|
109
|
-
name: 'First',
|
|
110
|
-
},
|
|
111
|
-
],
|
|
112
|
-
},
|
|
113
|
-
})
|
|
114
|
-
const fieldArray = useFieldArray(form, 'items')
|
|
115
|
-
|
|
116
|
-
expect(fieldArray.fields.value).toHaveLength(1)
|
|
117
|
-
|
|
118
|
-
fieldArray.push({
|
|
119
|
-
id: 2,
|
|
120
|
-
name: 'Second',
|
|
121
|
-
})
|
|
122
|
-
await nextTick()
|
|
123
|
-
|
|
124
|
-
expect(fieldArray.fields.value).toHaveLength(2)
|
|
125
|
-
expect(fieldArray.fields.value[1].item).toEqual({
|
|
126
|
-
id: 2,
|
|
127
|
-
name: 'Second',
|
|
128
|
-
})
|
|
129
|
-
expect(fieldArray.dirty.value).toBe(true)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('should remove item by reference', async () => {
|
|
133
|
-
const form = useForm({
|
|
134
|
-
initialData: {
|
|
135
|
-
items: [
|
|
136
|
-
{
|
|
137
|
-
id: 1,
|
|
138
|
-
name: 'Keep',
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
id: 2,
|
|
142
|
-
name: 'Remove',
|
|
143
|
-
},
|
|
144
|
-
],
|
|
145
|
-
},
|
|
146
|
-
})
|
|
147
|
-
const fieldArray = useFieldArray(form, 'items')
|
|
148
|
-
const itemToRemove = fieldArray.fields.value[1].item
|
|
149
|
-
|
|
150
|
-
fieldArray.remove(itemToRemove)
|
|
151
|
-
await nextTick()
|
|
152
|
-
|
|
153
|
-
expect(fieldArray.fields.value).toHaveLength(1)
|
|
154
|
-
expect(fieldArray.fields.value[0].item.name).toBe('Keep')
|
|
155
|
-
expect(fieldArray.dirty.value).toBe(true)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('should remove item by index', async () => {
|
|
159
|
-
const form = useForm({
|
|
160
|
-
initialData: {
|
|
161
|
-
items: [
|
|
162
|
-
{
|
|
163
|
-
id: 1,
|
|
164
|
-
name: 'First',
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
id: 2,
|
|
168
|
-
name: 'Second',
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
id: 3,
|
|
172
|
-
name: 'Third',
|
|
173
|
-
},
|
|
174
|
-
],
|
|
175
|
-
},
|
|
176
|
-
})
|
|
177
|
-
const fieldArray = useFieldArray(form, 'items')
|
|
178
|
-
|
|
179
|
-
fieldArray.removeByIndex(1)
|
|
180
|
-
await nextTick()
|
|
181
|
-
|
|
182
|
-
expect(fieldArray.fields.value).toHaveLength(2)
|
|
183
|
-
expect(fieldArray.fields.value[0].item.name).toBe('First')
|
|
184
|
-
expect(fieldArray.fields.value[1].item.name).toBe('Third')
|
|
185
|
-
})
|
|
186
|
-
})
|
|
187
|
-
|
|
188
73
|
describe('ID Persistence', () => {
|
|
189
74
|
it('should maintain IDs when items are reordered', async () => {
|
|
190
75
|
const form = useForm({
|
|
@@ -210,9 +95,9 @@ describe('useFieldArray', () => {
|
|
|
210
95
|
})
|
|
211
96
|
|
|
212
97
|
// Capture initial IDs
|
|
213
|
-
const id1 = fieldArray.
|
|
214
|
-
const id2 = fieldArray.
|
|
215
|
-
const id3 = fieldArray.
|
|
98
|
+
const id1 = fieldArray.items.value[0].id
|
|
99
|
+
const id2 = fieldArray.items.value[1].id
|
|
100
|
+
const id3 = fieldArray.items.value[2].id
|
|
216
101
|
|
|
217
102
|
// Reverse the array
|
|
218
103
|
const arrayField = form.getField('items')
|
|
@@ -220,12 +105,15 @@ describe('useFieldArray', () => {
|
|
|
220
105
|
await nextTick()
|
|
221
106
|
|
|
222
107
|
// Verify order changed but IDs followed the items
|
|
223
|
-
expect(fieldArray.
|
|
224
|
-
expect(fieldArray.
|
|
225
|
-
expect(fieldArray.
|
|
226
|
-
expect(fieldArray.
|
|
227
|
-
expect(fieldArray.
|
|
228
|
-
expect(fieldArray.
|
|
108
|
+
expect(fieldArray.items.value[0].item.name).toBe('Third')
|
|
109
|
+
expect(fieldArray.items.value[0].id).toBe(id3)
|
|
110
|
+
expect(fieldArray.items.value[0].path).toBe('items.0')
|
|
111
|
+
expect(fieldArray.items.value[1].item.name).toBe('Second')
|
|
112
|
+
expect(fieldArray.items.value[1].id).toBe(id2)
|
|
113
|
+
expect(fieldArray.items.value[1].path).toBe('items.1')
|
|
114
|
+
expect(fieldArray.items.value[2].item.name).toBe('First')
|
|
115
|
+
expect(fieldArray.items.value[2].id).toBe(id1)
|
|
116
|
+
expect(fieldArray.items.value[2].path).toBe('items.2')
|
|
229
117
|
})
|
|
230
118
|
|
|
231
119
|
it('should maintain IDs based on custom hash function', async () => {
|
|
@@ -249,8 +137,8 @@ describe('useFieldArray', () => {
|
|
|
249
137
|
hashFn: (item: { sku: string }) => item.sku,
|
|
250
138
|
})
|
|
251
139
|
|
|
252
|
-
const idABC = fieldArray.
|
|
253
|
-
const idDEF = fieldArray.
|
|
140
|
+
const idABC = fieldArray.items.value[0].id
|
|
141
|
+
const idDEF = fieldArray.items.value[1].id
|
|
254
142
|
|
|
255
143
|
// Update price and swap order
|
|
256
144
|
const arrayField = form.getField('products')
|
|
@@ -269,8 +157,8 @@ describe('useFieldArray', () => {
|
|
|
269
157
|
await nextTick()
|
|
270
158
|
|
|
271
159
|
// IDs should persist because SKUs didn't change
|
|
272
|
-
expect(fieldArray.
|
|
273
|
-
expect(fieldArray.
|
|
160
|
+
expect(fieldArray.items.value[0].id).toBe(idDEF)
|
|
161
|
+
expect(fieldArray.items.value[1].id).toBe(idABC)
|
|
274
162
|
|
|
275
163
|
// Change SKU - should get new ID
|
|
276
164
|
arrayField.setData([
|
|
@@ -287,8 +175,8 @@ describe('useFieldArray', () => {
|
|
|
287
175
|
])
|
|
288
176
|
await nextTick()
|
|
289
177
|
|
|
290
|
-
expect(fieldArray.
|
|
291
|
-
expect(fieldArray.
|
|
178
|
+
expect(fieldArray.items.value[0].id).not.toBe(idABC)
|
|
179
|
+
expect(fieldArray.items.value[1].id).toBe(idDEF)
|
|
292
180
|
})
|
|
293
181
|
|
|
294
182
|
it('should assign IDs in order for items with same hash', async () => {
|
|
@@ -319,7 +207,7 @@ describe('useFieldArray', () => {
|
|
|
319
207
|
})
|
|
320
208
|
|
|
321
209
|
// All items get unique IDs despite same hash
|
|
322
|
-
const [id1, id2, id3] = fieldArray.
|
|
210
|
+
const [id1, id2, id3] = fieldArray.items.value.map(f => f.id)
|
|
323
211
|
expect(new Set([id1, id2, id3]).size).toBe(3)
|
|
324
212
|
|
|
325
213
|
// Reorder: move last item to first position
|
|
@@ -342,40 +230,14 @@ describe('useFieldArray', () => {
|
|
|
342
230
|
|
|
343
231
|
// IDs are assigned in order from stored list, NOT following items
|
|
344
232
|
// This is expected behavior with hash collisions
|
|
345
|
-
expect(fieldArray.
|
|
346
|
-
expect(fieldArray.
|
|
347
|
-
expect(fieldArray.
|
|
233
|
+
expect(fieldArray.items.value[0].id).toBe(id1) // svelte gets id1 (was vue's)
|
|
234
|
+
expect(fieldArray.items.value[1].id).toBe(id2) // vue gets id2 (was react's)
|
|
235
|
+
expect(fieldArray.items.value[2].id).toBe(id3) // react gets id3 (was svelte's)
|
|
348
236
|
|
|
349
237
|
// The values confirm the reorder happened
|
|
350
|
-
expect(fieldArray.
|
|
351
|
-
expect(fieldArray.
|
|
352
|
-
expect(fieldArray.
|
|
353
|
-
})
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
describe('Form Integration', () => {
|
|
357
|
-
it('should track dirty state correctly', async () => {
|
|
358
|
-
const form = useForm({
|
|
359
|
-
initialData: { items: [{ name: 'Item' }] },
|
|
360
|
-
})
|
|
361
|
-
const fieldArray = useFieldArray(form, 'items')
|
|
362
|
-
|
|
363
|
-
expect(form.isDirty.value).toBe(false)
|
|
364
|
-
expect(fieldArray.dirty.value).toBe(false)
|
|
365
|
-
|
|
366
|
-
// Make a change
|
|
367
|
-
fieldArray.push({ name: 'New Item' })
|
|
368
|
-
await nextTick()
|
|
369
|
-
|
|
370
|
-
expect(form.isDirty.value).toBe(true)
|
|
371
|
-
expect(fieldArray.dirty.value).toBe(true)
|
|
372
|
-
|
|
373
|
-
// Reset form
|
|
374
|
-
form.reset()
|
|
375
|
-
await nextTick()
|
|
376
|
-
|
|
377
|
-
expect(form.isDirty.value).toBe(false)
|
|
378
|
-
expect(fieldArray.dirty.value).toBe(false)
|
|
238
|
+
expect(fieldArray.items.value[0].item.value).toBe('svelte')
|
|
239
|
+
expect(fieldArray.items.value[1].item.value).toBe('vue')
|
|
240
|
+
expect(fieldArray.items.value[2].item.value).toBe('react')
|
|
379
241
|
})
|
|
380
242
|
})
|
|
381
243
|
})
|