@teamnovu/kit-vue-forms 0.1.11 → 0.1.13
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.js +184 -172
- package/package.json +1 -1
- package/src/composables/useField.ts +11 -9
- package/src/composables/useFieldRegistry.ts +20 -2
- package/src/composables/useForm.ts +1 -1
- package/src/utils/path.ts +1 -1
- package/tests/useForm.test.ts +66 -0
package/dist/index.js
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var w = (t, e, r) =>
|
|
4
|
-
import { toValue as
|
|
5
|
-
import { cloneDeep as
|
|
1
|
+
var G = Object.defineProperty;
|
|
2
|
+
var L = (t, e, r) => e in t ? G(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r;
|
|
3
|
+
var w = (t, e, r) => L(t, typeof e != "symbol" ? e + "" : e, r);
|
|
4
|
+
import { toValue as Z, toRaw as q, computed as u, unref as f, isRef as j, shallowRef as _, reactive as D, watch as F, toRefs as W, shallowReactive as H, toRef as S, onScopeDispose as Q, watchEffect as X, triggerRef as Y, ref as k, getCurrentScope as x, onBeforeUnmount as ee, defineComponent as $, renderSlot as C, normalizeProps as B, guardReactiveProps as I, resolveComponent as re, createBlock as A, openBlock as M, withCtx as z, resolveDynamicComponent as te, mergeProps as se } from "vue";
|
|
5
|
+
import { cloneDeep as ae } from "lodash-es";
|
|
6
6
|
import "zod";
|
|
7
|
-
function
|
|
8
|
-
const e =
|
|
9
|
-
return
|
|
7
|
+
function y(t) {
|
|
8
|
+
const e = Z(t), r = q(e);
|
|
9
|
+
return ae(r);
|
|
10
10
|
}
|
|
11
|
-
function
|
|
11
|
+
function K(t) {
|
|
12
12
|
return t === "" ? [] : t.split(/\s*\.\s*/).filter(Boolean);
|
|
13
13
|
}
|
|
14
14
|
function P(t, e) {
|
|
15
|
-
return (Array.isArray(e) ? e :
|
|
16
|
-
(s,
|
|
15
|
+
return (Array.isArray(e) ? e : K(e)).reduce(
|
|
16
|
+
(s, i) => s == null ? void 0 : s[i],
|
|
17
17
|
t
|
|
18
18
|
);
|
|
19
19
|
}
|
|
20
|
-
function
|
|
21
|
-
const s = Array.isArray(e) ? e :
|
|
22
|
-
if (
|
|
23
|
-
const
|
|
24
|
-
(
|
|
20
|
+
function ie(t, e, r) {
|
|
21
|
+
const s = Array.isArray(e) ? e : K(e), i = s.at(-1);
|
|
22
|
+
if (i) {
|
|
23
|
+
const o = s.slice(0, -1).reduce(
|
|
24
|
+
(p, v) => p == null ? void 0 : p[v],
|
|
25
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
26
|
f(t)
|
|
27
27
|
);
|
|
28
|
-
i
|
|
28
|
+
o[i] = r;
|
|
29
29
|
} else {
|
|
30
|
-
if (!
|
|
30
|
+
if (!j(t))
|
|
31
31
|
return;
|
|
32
32
|
t.value = r;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
const
|
|
35
|
+
const U = (t, e) => u({
|
|
36
36
|
get() {
|
|
37
37
|
return P(f(t), f(e));
|
|
38
38
|
},
|
|
39
39
|
set(r) {
|
|
40
|
-
|
|
40
|
+
ie(t, f(e), r);
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
43
|
function R(t, e) {
|
|
44
44
|
return !t && !e ? "" : !t && e ? e : !e && t ? t : `${t}.${e}`;
|
|
45
45
|
}
|
|
46
|
-
function
|
|
46
|
+
function oe(t, e) {
|
|
47
47
|
if (!e)
|
|
48
48
|
return t;
|
|
49
49
|
const r = `${e}.`, s = Object.fromEntries(
|
|
50
|
-
Object.entries(t.propertyErrors).filter(([
|
|
51
|
-
([
|
|
50
|
+
Object.entries(t.propertyErrors).filter(([i]) => i.startsWith(r)).map(
|
|
51
|
+
([i, o]) => [i.slice(r.length), o]
|
|
52
52
|
)
|
|
53
53
|
);
|
|
54
54
|
return {
|
|
@@ -57,7 +57,7 @@ function se(t, e) {
|
|
|
57
57
|
propertyErrors: s
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
class
|
|
60
|
+
class ne {
|
|
61
61
|
constructor(e) {
|
|
62
62
|
w(this, "rc", 1);
|
|
63
63
|
this.drop = e;
|
|
@@ -69,31 +69,32 @@ class ae {
|
|
|
69
69
|
this.rc > 0 && (this.rc -= 1, this.rc === 0 && this.drop && this.drop());
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
function
|
|
73
|
-
const e =
|
|
74
|
-
E(
|
|
75
|
-
() => f(t.initialValue),
|
|
76
|
-
(u) => {
|
|
77
|
-
e.value = Object.freeze(g(u));
|
|
78
|
-
}
|
|
79
|
-
);
|
|
80
|
-
const r = D({
|
|
72
|
+
function le(t) {
|
|
73
|
+
const e = _(Object.freeze(y(t.initialValue))), r = D({
|
|
81
74
|
value: t.value,
|
|
82
75
|
path: t.path,
|
|
83
76
|
initialValue: e,
|
|
84
77
|
errors: t.errors,
|
|
85
78
|
touched: !1
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
});
|
|
80
|
+
F(
|
|
81
|
+
_(t.initialValue),
|
|
82
|
+
() => {
|
|
83
|
+
e.value = Object.freeze(y(t.initialValue)), r.value = y(t.initialValue);
|
|
84
|
+
},
|
|
85
|
+
{ flush: "sync" }
|
|
86
|
+
);
|
|
87
|
+
const s = u(() => JSON.stringify(r.value) !== JSON.stringify(r.initialValue)), i = (d) => {
|
|
88
|
+
r.value = d;
|
|
89
|
+
}, o = () => {
|
|
89
90
|
r.touched = !0;
|
|
90
|
-
},
|
|
91
|
+
}, p = () => {
|
|
91
92
|
}, v = () => {
|
|
92
|
-
r.value =
|
|
93
|
-
}, V = (
|
|
94
|
-
s.value ||
|
|
95
|
-
}, n = (
|
|
96
|
-
r.errors =
|
|
93
|
+
r.value = y(r.initialValue), r.touched = !1, r.errors = [];
|
|
94
|
+
}, V = (d) => {
|
|
95
|
+
s.value || i(y(d)), r.initialValue = d;
|
|
96
|
+
}, n = (d) => {
|
|
97
|
+
r.errors = d;
|
|
97
98
|
}, a = () => {
|
|
98
99
|
r.errors = [];
|
|
99
100
|
}, c = W(r);
|
|
@@ -104,70 +105,81 @@ function oe(t) {
|
|
|
104
105
|
errors: c.errors,
|
|
105
106
|
touched: c.touched,
|
|
106
107
|
dirty: s,
|
|
107
|
-
setData:
|
|
108
|
+
setData: i,
|
|
108
109
|
setInitialData: V,
|
|
109
|
-
onBlur:
|
|
110
|
-
onFocus:
|
|
110
|
+
onBlur: o,
|
|
111
|
+
onFocus: p,
|
|
111
112
|
reset: v,
|
|
112
113
|
setErrors: n,
|
|
113
114
|
clearErrors: a
|
|
114
115
|
};
|
|
115
116
|
}
|
|
116
|
-
function
|
|
117
|
-
const
|
|
117
|
+
function ce(t) {
|
|
118
|
+
const e = _(t());
|
|
119
|
+
return X(
|
|
120
|
+
() => {
|
|
121
|
+
e.value = t(), Y(e);
|
|
122
|
+
},
|
|
123
|
+
{ flush: "sync" }
|
|
124
|
+
), e;
|
|
125
|
+
}
|
|
126
|
+
function ue(t, e) {
|
|
127
|
+
const r = /* @__PURE__ */ new Map(), s = H(/* @__PURE__ */ new Map()), i = (a) => {
|
|
118
128
|
const c = f(a.path);
|
|
119
129
|
s.set(c, a);
|
|
120
|
-
},
|
|
130
|
+
}, o = (a) => {
|
|
121
131
|
s.delete(a);
|
|
122
|
-
},
|
|
132
|
+
}, p = (a) => {
|
|
123
133
|
var c;
|
|
124
|
-
r.has(a) ? (c = r.get(a)) == null || c.inc() : r.set(a, new
|
|
134
|
+
r.has(a) ? (c = r.get(a)) == null || c.inc() : r.set(a, new ne(() => o(a)));
|
|
125
135
|
}, v = (a) => {
|
|
126
136
|
var c;
|
|
127
137
|
r.has(a) && ((c = r.get(a)) == null || c.dec());
|
|
128
138
|
}, V = (a) => {
|
|
129
139
|
if (!s.has(a)) {
|
|
130
|
-
const
|
|
140
|
+
const d = le({
|
|
131
141
|
path: a,
|
|
132
|
-
value:
|
|
133
|
-
initialValue:
|
|
134
|
-
|
|
142
|
+
value: U(S(t, "data"), a),
|
|
143
|
+
initialValue: ce(
|
|
144
|
+
() => P(t.initialData, a)
|
|
145
|
+
),
|
|
146
|
+
errors: u({
|
|
135
147
|
get() {
|
|
136
148
|
return e.errors.value.propertyErrors[a] || [];
|
|
137
149
|
},
|
|
138
|
-
set(
|
|
139
|
-
e.errors.value.propertyErrors[a] =
|
|
150
|
+
set(E) {
|
|
151
|
+
e.errors.value.propertyErrors[a] = E;
|
|
140
152
|
}
|
|
141
153
|
})
|
|
142
154
|
});
|
|
143
|
-
|
|
155
|
+
i(d);
|
|
144
156
|
}
|
|
145
157
|
const c = s.get(a);
|
|
146
|
-
return
|
|
158
|
+
return p(a), Q(() => {
|
|
147
159
|
v(a);
|
|
148
160
|
}), c;
|
|
149
161
|
}, n = (a) => V(a.path);
|
|
150
162
|
return {
|
|
151
|
-
fields:
|
|
163
|
+
fields: u(() => [...s.values()]),
|
|
152
164
|
getField: V,
|
|
153
|
-
registerField:
|
|
154
|
-
deregisterField:
|
|
165
|
+
registerField: i,
|
|
166
|
+
deregisterField: o,
|
|
155
167
|
defineField: n
|
|
156
168
|
};
|
|
157
169
|
}
|
|
158
|
-
function
|
|
159
|
-
const e =
|
|
170
|
+
function de(t) {
|
|
171
|
+
const e = u(() => t.fields.value.some((s) => f(s.dirty))), r = u(() => t.fields.value.some((s) => f(s.touched)));
|
|
160
172
|
return {
|
|
161
173
|
isDirty: e,
|
|
162
174
|
isTouched: r
|
|
163
175
|
};
|
|
164
176
|
}
|
|
165
|
-
function
|
|
177
|
+
function fe(t) {
|
|
166
178
|
return t.filter(
|
|
167
179
|
(e, r, s) => s.indexOf(e) === r
|
|
168
180
|
);
|
|
169
181
|
}
|
|
170
|
-
function
|
|
182
|
+
function J(...t) {
|
|
171
183
|
return t.slice(1).reduce((e, r) => {
|
|
172
184
|
if (!e && !r)
|
|
173
185
|
return;
|
|
@@ -176,20 +188,20 @@ function U(...t) {
|
|
|
176
188
|
return r;
|
|
177
189
|
if (!s)
|
|
178
190
|
return e;
|
|
179
|
-
const
|
|
180
|
-
return
|
|
191
|
+
const i = (e ?? []).concat(r);
|
|
192
|
+
return fe(i);
|
|
181
193
|
}, t[0]);
|
|
182
194
|
}
|
|
183
|
-
function
|
|
195
|
+
function pe(...t) {
|
|
184
196
|
return t.map((r) => Object.keys(r)).flat().reduce((r, s) => {
|
|
185
|
-
const
|
|
197
|
+
const i = t.map((o) => o[s]).filter(Boolean);
|
|
186
198
|
return {
|
|
187
199
|
...r,
|
|
188
|
-
[s]:
|
|
200
|
+
[s]: J(...i)
|
|
189
201
|
};
|
|
190
202
|
}, {});
|
|
191
203
|
}
|
|
192
|
-
function
|
|
204
|
+
function b(...t) {
|
|
193
205
|
if (!t.length)
|
|
194
206
|
return {
|
|
195
207
|
general: [],
|
|
@@ -198,23 +210,23 @@ function S(...t) {
|
|
|
198
210
|
const e = t[0];
|
|
199
211
|
return t.length === 1 ? e : t.slice(1).reduce(
|
|
200
212
|
(r, s) => ({
|
|
201
|
-
general:
|
|
202
|
-
propertyErrors:
|
|
213
|
+
general: J(r.general, s.general),
|
|
214
|
+
propertyErrors: pe(r.propertyErrors ?? {}, s.propertyErrors ?? {})
|
|
203
215
|
}),
|
|
204
216
|
e
|
|
205
217
|
);
|
|
206
218
|
}
|
|
207
219
|
function N(t) {
|
|
208
220
|
var s;
|
|
209
|
-
const e = (((s = t.general) == null ? void 0 : s.length) ?? 0) > 0, r = Object.entries(t.propertyErrors).filter(([,
|
|
221
|
+
const e = (((s = t.general) == null ? void 0 : s.length) ?? 0) > 0, r = Object.entries(t.propertyErrors).filter(([, i]) => i == null ? void 0 : i.length).length > 0;
|
|
210
222
|
return e || r;
|
|
211
223
|
}
|
|
212
|
-
function
|
|
213
|
-
const e = t.issues.filter((s) => s.path.length === 0).map((s) => s.message), r = t.issues.filter((s) => s.path.length > 0).reduce((s,
|
|
214
|
-
const
|
|
224
|
+
function he(t) {
|
|
225
|
+
const e = t.issues.filter((s) => s.path.length === 0).map((s) => s.message), r = t.issues.filter((s) => s.path.length > 0).reduce((s, i) => {
|
|
226
|
+
const o = i.path.join(".");
|
|
215
227
|
return {
|
|
216
228
|
...s,
|
|
217
|
-
[
|
|
229
|
+
[o]: [...s[o] ?? [], i.message]
|
|
218
230
|
};
|
|
219
231
|
}, {});
|
|
220
232
|
return {
|
|
@@ -229,7 +241,7 @@ const m = {
|
|
|
229
241
|
propertyErrors: {}
|
|
230
242
|
}
|
|
231
243
|
};
|
|
232
|
-
class
|
|
244
|
+
class ve {
|
|
233
245
|
constructor(e) {
|
|
234
246
|
this.schema = e;
|
|
235
247
|
}
|
|
@@ -239,7 +251,7 @@ class de {
|
|
|
239
251
|
const r = await this.schema.safeParseAsync(e);
|
|
240
252
|
if (r.success)
|
|
241
253
|
return m;
|
|
242
|
-
const s =
|
|
254
|
+
const s = he(r.error);
|
|
243
255
|
return {
|
|
244
256
|
isValid: !1,
|
|
245
257
|
errors: {
|
|
@@ -249,7 +261,7 @@ class de {
|
|
|
249
261
|
};
|
|
250
262
|
}
|
|
251
263
|
}
|
|
252
|
-
class
|
|
264
|
+
class me {
|
|
253
265
|
constructor(e) {
|
|
254
266
|
this.validateFn = e;
|
|
255
267
|
}
|
|
@@ -270,11 +282,11 @@ class fe {
|
|
|
270
282
|
}
|
|
271
283
|
}
|
|
272
284
|
}
|
|
273
|
-
class
|
|
285
|
+
class Ve {
|
|
274
286
|
constructor(e, r) {
|
|
275
287
|
w(this, "schemaValidator");
|
|
276
288
|
w(this, "functionValidator");
|
|
277
|
-
this.schema = e, this.validateFn = r, this.schemaValidator = new
|
|
289
|
+
this.schema = e, this.validateFn = r, this.schemaValidator = new ve(this.schema), this.functionValidator = new me(this.validateFn);
|
|
278
290
|
}
|
|
279
291
|
async validate(e) {
|
|
280
292
|
const [r, s] = await Promise.all([
|
|
@@ -283,84 +295,84 @@ class pe {
|
|
|
283
295
|
]);
|
|
284
296
|
return {
|
|
285
297
|
isValid: r.isValid && s.isValid,
|
|
286
|
-
errors:
|
|
298
|
+
errors: b(r.errors, s.errors)
|
|
287
299
|
};
|
|
288
300
|
}
|
|
289
301
|
}
|
|
290
|
-
function
|
|
291
|
-
return
|
|
302
|
+
function O(t) {
|
|
303
|
+
return u(() => new Ve(
|
|
292
304
|
f(t.schema),
|
|
293
305
|
f(t.validateFn)
|
|
294
306
|
));
|
|
295
307
|
}
|
|
296
|
-
function
|
|
308
|
+
function ye(t, e) {
|
|
297
309
|
const r = D({
|
|
298
|
-
validators:
|
|
310
|
+
validators: k([O(e)]),
|
|
299
311
|
isValidated: !1,
|
|
300
312
|
errors: f(e.errors) ?? m.errors
|
|
301
313
|
}), s = (n = m.errors) => {
|
|
302
|
-
r.errors =
|
|
314
|
+
r.errors = b(f(e.errors) ?? m.errors, n);
|
|
303
315
|
};
|
|
304
|
-
|
|
316
|
+
F(() => f(e.errors), async () => {
|
|
305
317
|
if (r.isValidated) {
|
|
306
|
-
const n = await
|
|
318
|
+
const n = await o();
|
|
307
319
|
s(n.errors);
|
|
308
320
|
} else
|
|
309
321
|
s();
|
|
310
|
-
}, { immediate: !0 }),
|
|
322
|
+
}, { immediate: !0 }), F(
|
|
311
323
|
[() => r.validators],
|
|
312
324
|
async (n) => {
|
|
313
325
|
if (r.isValidated)
|
|
314
326
|
if (n) {
|
|
315
|
-
const a = await
|
|
327
|
+
const a = await o();
|
|
316
328
|
r.errors = a.errors;
|
|
317
329
|
} else
|
|
318
330
|
r.errors = m.errors;
|
|
319
331
|
},
|
|
320
332
|
{ immediate: !0 }
|
|
321
|
-
),
|
|
322
|
-
r.isValidated &&
|
|
333
|
+
), F(() => t.data, () => {
|
|
334
|
+
r.isValidated && p();
|
|
323
335
|
});
|
|
324
|
-
const
|
|
325
|
-
const a =
|
|
326
|
-
return r.validators.push(a),
|
|
336
|
+
const i = (n) => {
|
|
337
|
+
const a = j(n) ? n : O(n);
|
|
338
|
+
return r.validators.push(a), x() && ee(() => {
|
|
327
339
|
r.validators = r.validators.filter(
|
|
328
340
|
(c) => c !== a
|
|
329
341
|
);
|
|
330
342
|
}), a;
|
|
331
343
|
};
|
|
332
|
-
async function
|
|
344
|
+
async function o() {
|
|
333
345
|
const n = await Promise.all(
|
|
334
|
-
r.validators.filter((
|
|
335
|
-
), a = n.every((
|
|
346
|
+
r.validators.filter((d) => f(d) !== void 0).map((d) => f(d).validate(t.data))
|
|
347
|
+
), a = n.every((d) => d.isValid);
|
|
336
348
|
let { errors: c } = m;
|
|
337
349
|
if (!a) {
|
|
338
|
-
const
|
|
339
|
-
c =
|
|
350
|
+
const d = n.map((E) => E.errors);
|
|
351
|
+
c = b(...d);
|
|
340
352
|
}
|
|
341
353
|
return {
|
|
342
354
|
errors: c,
|
|
343
355
|
isValid: a
|
|
344
356
|
};
|
|
345
357
|
}
|
|
346
|
-
const
|
|
347
|
-
const n = await
|
|
358
|
+
const p = async () => {
|
|
359
|
+
const n = await o();
|
|
348
360
|
return s(n.errors), r.isValidated = !0, {
|
|
349
361
|
isValid: !N(n.errors),
|
|
350
362
|
errors: r.errors
|
|
351
363
|
};
|
|
352
|
-
}, v =
|
|
364
|
+
}, v = u(() => !N(r.errors)), V = () => {
|
|
353
365
|
r.isValidated = !1, r.errors = f(e.errors) ?? m.errors;
|
|
354
366
|
};
|
|
355
367
|
return {
|
|
356
368
|
...W(r),
|
|
357
|
-
validateForm:
|
|
358
|
-
defineValidator:
|
|
369
|
+
validateForm: p,
|
|
370
|
+
defineValidator: i,
|
|
359
371
|
isValid: v,
|
|
360
372
|
reset: V
|
|
361
373
|
};
|
|
362
374
|
}
|
|
363
|
-
class
|
|
375
|
+
class ge {
|
|
364
376
|
constructor(e, r) {
|
|
365
377
|
this.path = e, this.validator = r;
|
|
366
378
|
}
|
|
@@ -374,94 +386,94 @@ class ve {
|
|
|
374
386
|
errors: {
|
|
375
387
|
general: s.errors.general || [],
|
|
376
388
|
propertyErrors: s.errors.propertyErrors ? Object.fromEntries(
|
|
377
|
-
Object.entries(s.errors.propertyErrors).map(([
|
|
378
|
-
R(this.path,
|
|
379
|
-
|
|
389
|
+
Object.entries(s.errors.propertyErrors).map(([i, o]) => [
|
|
390
|
+
R(this.path, i),
|
|
391
|
+
o
|
|
380
392
|
])
|
|
381
393
|
) : {}
|
|
382
394
|
}
|
|
383
395
|
};
|
|
384
396
|
}
|
|
385
397
|
}
|
|
386
|
-
function
|
|
387
|
-
const s =
|
|
398
|
+
function Ee(t, e, r) {
|
|
399
|
+
const s = U(t.data, e), i = u(() => P(t.initialData.value, e)), o = (l) => ({
|
|
388
400
|
...l,
|
|
389
|
-
path:
|
|
390
|
-
setData: (
|
|
391
|
-
l.setData(
|
|
401
|
+
path: u(() => f(l.path).replace(e + ".", "")),
|
|
402
|
+
setData: (h) => {
|
|
403
|
+
l.setData(h);
|
|
392
404
|
}
|
|
393
|
-
}),
|
|
394
|
-
const
|
|
395
|
-
return
|
|
405
|
+
}), p = (l) => {
|
|
406
|
+
const h = R(e, l), g = t.getField(h);
|
|
407
|
+
return g ? o(g) : {};
|
|
396
408
|
}, v = (l) => {
|
|
397
|
-
const
|
|
409
|
+
const h = R(e, l.path), g = t.defineField({
|
|
398
410
|
...l,
|
|
399
|
-
path:
|
|
411
|
+
path: h
|
|
400
412
|
});
|
|
401
|
-
return
|
|
402
|
-
}, V =
|
|
403
|
-
const
|
|
404
|
-
return
|
|
405
|
-
}).map((l) =>
|
|
406
|
-
const
|
|
407
|
-
return
|
|
408
|
-
}), a =
|
|
413
|
+
return o(g);
|
|
414
|
+
}, V = u(() => t.fields.value.filter((l) => {
|
|
415
|
+
const h = l.path.value;
|
|
416
|
+
return h.startsWith(e + ".") || h === e;
|
|
417
|
+
}).map((l) => o(l))), n = () => t.fields.value.filter((l) => {
|
|
418
|
+
const h = l.path.value;
|
|
419
|
+
return h.startsWith(e + ".") || h === e;
|
|
420
|
+
}), a = u(() => n().some((l) => l.dirty.value)), c = u(() => n().some((l) => l.touched.value)), d = u(() => t.isValid.value), E = u(() => t.isValidated.value), T = u(() => oe(f(t.errors), e));
|
|
409
421
|
return {
|
|
410
422
|
data: s,
|
|
411
423
|
fields: V,
|
|
412
|
-
initialData:
|
|
424
|
+
initialData: i,
|
|
413
425
|
defineField: v,
|
|
414
|
-
getField:
|
|
426
|
+
getField: p,
|
|
415
427
|
isDirty: a,
|
|
416
428
|
isTouched: c,
|
|
417
|
-
isValid:
|
|
418
|
-
isValidated:
|
|
419
|
-
errors:
|
|
429
|
+
isValid: d,
|
|
430
|
+
isValidated: E,
|
|
431
|
+
errors: T,
|
|
420
432
|
defineValidator: (l) => {
|
|
421
|
-
const
|
|
422
|
-
() => new
|
|
433
|
+
const h = j(l) ? l : O(l), g = u(
|
|
434
|
+
() => new ge(e, f(h))
|
|
423
435
|
);
|
|
424
|
-
return t.defineValidator(
|
|
436
|
+
return t.defineValidator(g), h;
|
|
425
437
|
},
|
|
426
438
|
reset: () => n().forEach((l) => l.reset()),
|
|
427
439
|
validateForm: () => t.validateForm(),
|
|
428
|
-
getSubForm: (l,
|
|
429
|
-
const
|
|
440
|
+
getSubForm: (l, h) => {
|
|
441
|
+
const g = R(e, l);
|
|
430
442
|
return t.getSubForm(
|
|
431
|
-
|
|
432
|
-
|
|
443
|
+
g,
|
|
444
|
+
h
|
|
433
445
|
);
|
|
434
446
|
}
|
|
435
447
|
};
|
|
436
448
|
}
|
|
437
|
-
function
|
|
438
|
-
const e =
|
|
449
|
+
function Oe(t) {
|
|
450
|
+
const e = u(() => Object.freeze(y(t.initialData))), r = k(y(e)), s = D({
|
|
439
451
|
initialData: e,
|
|
440
452
|
data: r
|
|
441
453
|
});
|
|
442
|
-
|
|
443
|
-
s.data =
|
|
444
|
-
});
|
|
445
|
-
const
|
|
446
|
-
r.value =
|
|
454
|
+
F(e, (a) => {
|
|
455
|
+
s.data = y(a);
|
|
456
|
+
}, { flush: "sync" });
|
|
457
|
+
const i = ye(s, t), o = ue(s, i), p = de(o), v = () => {
|
|
458
|
+
r.value = y(e), i.reset(), o.fields.value.forEach(
|
|
447
459
|
(a) => a.reset()
|
|
448
460
|
);
|
|
449
461
|
};
|
|
450
462
|
function V(a, c) {
|
|
451
|
-
return
|
|
463
|
+
return Ee(n, a);
|
|
452
464
|
}
|
|
453
465
|
const n = {
|
|
454
|
-
...i,
|
|
455
466
|
...o,
|
|
456
|
-
...
|
|
467
|
+
...i,
|
|
468
|
+
...p,
|
|
457
469
|
reset: v,
|
|
458
470
|
getSubForm: V,
|
|
459
|
-
initialData:
|
|
460
|
-
data:
|
|
471
|
+
initialData: S(s, "initialData"),
|
|
472
|
+
data: S(s, "data")
|
|
461
473
|
};
|
|
462
474
|
return n;
|
|
463
475
|
}
|
|
464
|
-
const
|
|
476
|
+
const je = /* @__PURE__ */ $({
|
|
465
477
|
__name: "Field",
|
|
466
478
|
props: {
|
|
467
479
|
form: {},
|
|
@@ -474,9 +486,9 @@ const _e = /* @__PURE__ */ $({
|
|
|
474
486
|
const e = t, r = e.form.defineField({
|
|
475
487
|
path: e.path
|
|
476
488
|
}), s = D(r);
|
|
477
|
-
return (
|
|
489
|
+
return (i, o) => C(i.$slots, "default", B(I(s)));
|
|
478
490
|
}
|
|
479
|
-
}),
|
|
491
|
+
}), $e = /* @__PURE__ */ $({
|
|
480
492
|
inheritAttrs: !1,
|
|
481
493
|
__name: "FormFieldWrapper",
|
|
482
494
|
props: {
|
|
@@ -487,20 +499,20 @@ const _e = /* @__PURE__ */ $({
|
|
|
487
499
|
},
|
|
488
500
|
setup(t) {
|
|
489
501
|
return (e, r) => {
|
|
490
|
-
const s =
|
|
491
|
-
return M(),
|
|
502
|
+
const s = re("Field");
|
|
503
|
+
return M(), A(s, {
|
|
492
504
|
form: e.form,
|
|
493
505
|
path: e.path
|
|
494
506
|
}, {
|
|
495
|
-
default: z(({ errors:
|
|
496
|
-
(M(),
|
|
497
|
-
"model-value":
|
|
498
|
-
errors:
|
|
507
|
+
default: z(({ errors: i, data: o, setData: p }) => [
|
|
508
|
+
(M(), A(te(e.component), se({ ...e.componentProps, ...e.$attrs }, {
|
|
509
|
+
"model-value": o,
|
|
510
|
+
errors: i,
|
|
499
511
|
name: e.path,
|
|
500
|
-
"onUpdate:modelValue":
|
|
512
|
+
"onUpdate:modelValue": p
|
|
501
513
|
}), {
|
|
502
514
|
default: z(() => [
|
|
503
|
-
|
|
515
|
+
C(e.$slots, "default")
|
|
504
516
|
]),
|
|
505
517
|
_: 2
|
|
506
518
|
}, 1040, ["model-value", "errors", "name", "onUpdate:modelValue"]))
|
|
@@ -509,20 +521,20 @@ const _e = /* @__PURE__ */ $({
|
|
|
509
521
|
}, 8, ["form", "path"]);
|
|
510
522
|
};
|
|
511
523
|
}
|
|
512
|
-
}),
|
|
524
|
+
}), Ce = /* @__PURE__ */ $({
|
|
513
525
|
__name: "FormPart",
|
|
514
526
|
props: {
|
|
515
527
|
form: {},
|
|
516
528
|
path: {}
|
|
517
529
|
},
|
|
518
530
|
setup(t) {
|
|
519
|
-
const e = t, r =
|
|
520
|
-
return (s,
|
|
531
|
+
const e = t, r = u(() => e.form.getSubForm(e.path));
|
|
532
|
+
return (s, i) => C(s.$slots, "default", B(I({ subform: r.value })));
|
|
521
533
|
}
|
|
522
534
|
});
|
|
523
535
|
export {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
536
|
+
je as Field,
|
|
537
|
+
$e as FormFieldWrapper,
|
|
538
|
+
Ce as FormPart,
|
|
539
|
+
Oe as useForm
|
|
528
540
|
};
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, reactive,
|
|
1
|
+
import { computed, reactive, shallowRef, toRefs, watch, type MaybeRef, type MaybeRefOrGetter, type Ref, type WritableComputedRef } from 'vue'
|
|
2
2
|
import type { FormField } from '../types/form'
|
|
3
3
|
import type { ValidationErrorMessage, ValidationErrors } from '../types/validation'
|
|
4
4
|
import { cloneRefValue } from '../utils/general'
|
|
@@ -11,14 +11,7 @@ export interface UseFieldOptions<T, K extends string> {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export function useField<T, K extends string>(options: UseFieldOptions<T, K>): FormField<T, K> {
|
|
14
|
-
const initialValue =
|
|
15
|
-
|
|
16
|
-
watch(
|
|
17
|
-
() => unref(options.initialValue),
|
|
18
|
-
(newInitialValue) => {
|
|
19
|
-
initialValue.value = Object.freeze(cloneRefValue(newInitialValue))
|
|
20
|
-
},
|
|
21
|
-
)
|
|
14
|
+
const initialValue = shallowRef(Object.freeze(cloneRefValue(options.initialValue))) as Ref<Readonly<T | undefined>>
|
|
22
15
|
|
|
23
16
|
const state = reactive({
|
|
24
17
|
value: options.value,
|
|
@@ -28,6 +21,15 @@ export function useField<T, K extends string>(options: UseFieldOptions<T, K>): F
|
|
|
28
21
|
touched: false,
|
|
29
22
|
})
|
|
30
23
|
|
|
24
|
+
watch(
|
|
25
|
+
shallowRef(options.initialValue),
|
|
26
|
+
() => {
|
|
27
|
+
initialValue.value = Object.freeze(cloneRefValue(options.initialValue))
|
|
28
|
+
state.value = cloneRefValue(options.initialValue)
|
|
29
|
+
},
|
|
30
|
+
{ flush: 'sync' },
|
|
31
|
+
)
|
|
32
|
+
|
|
31
33
|
const dirty = computed(() => {
|
|
32
34
|
return JSON.stringify(state.value) !== JSON.stringify(state.initialValue)
|
|
33
35
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, onScopeDispose, shallowReactive, toRef, unref } from 'vue'
|
|
1
|
+
import { computed, onScopeDispose, shallowReactive, shallowRef, toRef, triggerRef, unref, watch, watchEffect, type MaybeRef, type WatchSource } from 'vue'
|
|
2
2
|
import type { FieldsTuple, FormDataDefault, FormField } from '../types/form'
|
|
3
3
|
import type { Paths, PickProps } from '../types/util'
|
|
4
4
|
import { getLens, getNestedValue } from '../utils/path'
|
|
@@ -18,6 +18,22 @@ interface FormState<T extends FormDataDefault, TIn extends FormDataDefault = T>
|
|
|
18
18
|
initialData: TIn
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// A computed that always reflects the latest value from the getter
|
|
22
|
+
// This computed forces updates even if the value is the same (to trigger watchers)
|
|
23
|
+
function alwaysComputed<T>(getter: () => T) {
|
|
24
|
+
const initialValueRef = shallowRef(getter())
|
|
25
|
+
|
|
26
|
+
watchEffect(
|
|
27
|
+
() => {
|
|
28
|
+
initialValueRef.value = getter()
|
|
29
|
+
triggerRef(initialValueRef)
|
|
30
|
+
},
|
|
31
|
+
{ flush: 'sync' },
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
return initialValueRef
|
|
35
|
+
}
|
|
36
|
+
|
|
21
37
|
export function useFieldRegistry<T extends FormDataDefault>(
|
|
22
38
|
formState: FormState<T>,
|
|
23
39
|
validationState: ValidationState<T>,
|
|
@@ -53,7 +69,9 @@ export function useFieldRegistry<T extends FormDataDefault>(
|
|
|
53
69
|
const field = useField({
|
|
54
70
|
path,
|
|
55
71
|
value: getLens(toRef(formState, 'data'), path),
|
|
56
|
-
initialValue:
|
|
72
|
+
initialValue: alwaysComputed(
|
|
73
|
+
() => getNestedValue(formState.initialData, path),
|
|
74
|
+
),
|
|
57
75
|
errors: computed({
|
|
58
76
|
get() {
|
|
59
77
|
return validationState.errors.value.propertyErrors[path] || []
|
|
@@ -28,7 +28,7 @@ export function useForm<T extends FormDataDefault>(options: UseFormOptions<T>) {
|
|
|
28
28
|
|
|
29
29
|
watch(initialData, (newValue) => {
|
|
30
30
|
state.data = cloneRefValue(newValue)
|
|
31
|
-
})
|
|
31
|
+
}, { flush: 'sync' })
|
|
32
32
|
|
|
33
33
|
const validationState = useValidation(state, options)
|
|
34
34
|
const fieldRegistry = useFieldRegistry(state, validationState)
|
package/src/utils/path.ts
CHANGED
|
@@ -33,7 +33,7 @@ export function setNestedValue<T, K extends Paths<T>>(obj: MaybeRef<T>, path: K
|
|
|
33
33
|
const target = keys
|
|
34
34
|
.slice(0, -1)
|
|
35
35
|
.reduce(
|
|
36
|
-
(current, key) => current[key],
|
|
36
|
+
(current, key) => current?.[key],
|
|
37
37
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
38
|
unref(obj) as Record<string, any>,
|
|
39
39
|
)
|
package/tests/useForm.test.ts
CHANGED
|
@@ -290,4 +290,70 @@ describe('useForm', () => {
|
|
|
290
290
|
|
|
291
291
|
expect(form.fields.value.length).toBe(0)
|
|
292
292
|
})
|
|
293
|
+
|
|
294
|
+
it('it should take over the new initial data from the form', { timeout: 500 }, async () => {
|
|
295
|
+
const initialData = ref({
|
|
296
|
+
name: 'foo',
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
const form = useForm({
|
|
300
|
+
initialData,
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
const nameField = form.getField('name')
|
|
304
|
+
|
|
305
|
+
expect(form.isDirty.value).toBe(false)
|
|
306
|
+
expect(nameField.dirty.value).toBe(false)
|
|
307
|
+
|
|
308
|
+
nameField.setData('modified')
|
|
309
|
+
|
|
310
|
+
expect(form.isDirty.value).toBe(true)
|
|
311
|
+
expect(nameField.dirty.value).toBe(true)
|
|
312
|
+
|
|
313
|
+
initialData.value = {
|
|
314
|
+
name: 'bar',
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
expect(form.initialData.value.name).toBe('bar')
|
|
318
|
+
expect(nameField.initialValue.value).toBe('bar')
|
|
319
|
+
expect(nameField.data.value).toBe('bar')
|
|
320
|
+
|
|
321
|
+
nameField.setInitialData('another')
|
|
322
|
+
|
|
323
|
+
expect(nameField.initialValue.value).toBe('another')
|
|
324
|
+
expect(nameField.data.value).toBe('another')
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
it('it should take over the new initial data from the form after setting initial data on field', { timeout: 500 }, async () => {
|
|
328
|
+
const initialData = ref({
|
|
329
|
+
name: null as null | number,
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
const form = useForm({
|
|
333
|
+
initialData,
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
const nameField = form.getField('name')
|
|
337
|
+
|
|
338
|
+
expect(form.isDirty.value).toBe(false)
|
|
339
|
+
expect(nameField.dirty.value).toBe(false)
|
|
340
|
+
|
|
341
|
+
nameField.setInitialData(0)
|
|
342
|
+
|
|
343
|
+
expect(form.isDirty.value).toBe(false)
|
|
344
|
+
expect(nameField.dirty.value).toBe(false)
|
|
345
|
+
|
|
346
|
+
initialData.value = {
|
|
347
|
+
name: null,
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
expect(form.initialData.value.name).toBe(null)
|
|
351
|
+
expect(nameField.initialValue.value).toBe(null)
|
|
352
|
+
expect(nameField.data.value).toBe(null)
|
|
353
|
+
|
|
354
|
+
nameField.setInitialData(23)
|
|
355
|
+
|
|
356
|
+
expect(nameField.initialValue.value).toBe(23)
|
|
357
|
+
expect(nameField.data.value).toBe(23)
|
|
358
|
+
})
|
|
293
359
|
})
|