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