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