@teamnovu/kit-vue-forms 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { Form } from '../types/form.ts';
2
2
  import { Paths, PickProps } from '../types/util.ts';
3
3
  import { UseFieldOptions } from '../composables/useField.ts';
4
- import { VNodeProps, AllowedComponentProps, ComponentCustomProps, PublicProps, ShallowUnwrapRef, Ref, VNode } from 'vue';
4
+ import { VNodeProps, AllowedComponentProps, ComponentCustomProps, PublicProps, ShallowUnwrapRef, VNode } from 'vue';
5
5
  import { ValidationErrors, ErrorMessage } from '../index.js';
6
6
  export interface FieldProps<TData extends object, TPath extends string> extends UseFieldOptions<PickProps<TData, TPath>, TPath> {
7
7
  form: Form<TData>;
@@ -12,12 +12,12 @@ declare const _default: <TData extends object, TPath extends Paths<TData>>(__VLS
12
12
  attrs: any;
13
13
  slots: {
14
14
  default?(_: {
15
- data: Ref<PickProps<TData, TPath>, PickProps<TData, TPath>>;
16
- path: Ref<TPath, TPath>;
17
- initialValue: Readonly< Ref<PickProps<TData, TPath>, PickProps<TData, TPath>>>;
18
- errors: Ref<ValidationErrors>;
19
- touched: Ref<boolean>;
20
- dirty: Ref<boolean>;
15
+ data: PickProps<TData, TPath>;
16
+ path: TPath;
17
+ initialValue: PickProps<TData, TPath>;
18
+ errors: ValidationErrors;
19
+ touched: boolean;
20
+ dirty: boolean;
21
21
  setData: (newData: PickProps<TData, TPath>) => void;
22
22
  onBlur: () => void;
23
23
  onFocus: () => void;
@@ -1,19 +1,19 @@
1
- import { FormDataDefault, FormField } from '../types/form';
1
+ import { FieldsTuple, FormDataDefault, FormField } from '../types/form';
2
2
  import { Paths, PickProps } from '../types/util';
3
3
  import { UseFieldOptions } from './useField';
4
4
  type FieldRegistryCache<T> = Record<Paths<T>, FormField<any, string>>;
5
5
  export type ResolvedFormField<T, K extends Paths<T>> = FormField<PickProps<T, K>, K>;
6
- export type DefineFieldOptions<F, K extends string> = Pick<UseFieldOptions<F, K>, 'path' | 'type' | 'required'>;
6
+ export type DefineFieldOptions<F, K extends string> = Pick<UseFieldOptions<F, K>, 'path'>;
7
7
  interface FormState<T extends FormDataDefault, TIn extends FormDataDefault = T> {
8
8
  data: T;
9
9
  initialData: TIn;
10
10
  }
11
11
  export declare function useFieldRegistry<T extends FormDataDefault>(formState: FormState<T>): {
12
12
  fields: FieldRegistryCache<T>;
13
- getField: <K extends Paths<T>>(path: K) => ResolvedFormField<T, K> | undefined;
14
- getFields: () => ResolvedFormField<T, Paths<T>>[];
13
+ getField: <K extends Paths<T>>(path: K) => ResolvedFormField<T, K>;
14
+ getFields: <TData extends T>() => FieldsTuple<TData>;
15
15
  registerField: <K extends Paths<T>>(field: ResolvedFormField<T, K>) => void;
16
- defineField: <K extends Paths<T>>(options: DefineFieldOptions<PickProps<T, K>, K>) => FormField<PickProps<any, K>, K>;
16
+ defineField: <K extends Paths<T>>(options: DefineFieldOptions<PickProps<T, K>, K>) => FormField<K extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_1 ? T_1 extends TRest ? T_1 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_2 ? T_2 extends TRest ? T_2 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_3 ? T_3 extends TRest ? T_3 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_4 ? T_4 extends TRest ? T_4 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_5 ? T_5 extends TRest ? T_5 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_6 ? T_6 extends TRest ? T_6 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_7 ? T_7 extends TRest ? T_7 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_8 ? T_8 extends TRest ? T_8 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_9 ? T_9 extends TRest ? T_9 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? TRest extends infer T_10 ? T_10 extends TRest ? T_10 extends `${infer TRoot}.${infer TRest}` ? TRoot extends string | number | symbol ? TRest extends string ? /*elided*/ any : never : TRoot extends `${number}` ? never : never : T_10 extends string | number | symbol ? Required<any>[T_10] : T_10 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_9 extends string | number | symbol ? Required<any>[T_9] : T_9 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_8 extends string | number | symbol ? Required<any>[T_8] : T_8 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_7 extends string | number | symbol ? Required<any>[T_7] : T_7 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_6 extends string | number | symbol ? Required<any>[T_6] : T_6 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_5 extends string | number | symbol ? Required<any>[T_5] : T_5 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_4 extends string | number | symbol ? Required<any>[T_4] : T_4 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_3 extends string | number | symbol ? Required<any>[T_3] : T_3 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_2 extends string | number | symbol ? Required<any>[T_2] : T_2 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : T_1 extends string | number | symbol ? Required<any>[T_1] : T_1 extends `${number}` ? never : never : never : never : never : TRoot extends `${number}` ? never : never : K extends string | number | symbol ? any : K extends `${number}` ? never : never, K>;
17
17
  };
18
18
  export type FieldRegistry<T extends FormDataDefault> = ReturnType<typeof useFieldRegistry<T>>;
19
19
  export {};
@@ -16,7 +16,7 @@ export declare function useValidation<T extends FormDataDefault>(formState: {
16
16
  data: T;
17
17
  }, options: ValidationOptions<T>): {
18
18
  validateForm: () => Promise<ValidationResult>;
19
- defineValidator: (options: ValidatorOptions<T> | Ref<Validator<T>>) => Ref<Validator<T> | undefined, Validator<T> | undefined>;
19
+ defineValidator: <TData extends T>(options: ValidatorOptions<TData> | Ref<Validator<TData>>) => Ref<Validator<TData> | undefined, Validator<TData> | undefined>;
20
20
  isValid: ComputedRef<boolean>;
21
21
  validators: Ref<Ref<Validator<T> | undefined, Validator<T> | undefined>[], Ref<Validator<T> | undefined, Validator<T> | undefined>[]>;
22
22
  isValidated: Ref<boolean, boolean>;
package/dist/index.mjs CHANGED
@@ -1,22 +1,22 @@
1
1
  var x = Object.defineProperty;
2
2
  var K = (e, r, t) => r in e ? x(e, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[r] = t;
3
- var R = (e, r, t) => K(e, typeof r != "symbol" ? r + "" : r, t);
4
- import { toValue as W, toRaw as q, computed as d, unref as c, reactive as b, watch as F, toRefs as O, toRef as S, ref as A, isRef as _, getCurrentScope as I, onBeforeUnmount as J, defineComponent as T, renderSlot as B, normalizeProps as G, guardReactiveProps as L } from "vue";
3
+ var S = (e, r, t) => K(e, typeof r != "symbol" ? r + "" : r, t);
4
+ import { toValue as W, toRaw as I, computed as d, unref as c, reactive as m, watch as F, toRefs as O, toRef as D, ref as A, isRef as _, getCurrentScope as J, onBeforeUnmount as T, defineComponent as B, renderSlot as G, normalizeProps as L, guardReactiveProps as U } from "vue";
5
5
  import "zod";
6
6
  function y(e) {
7
- const r = W(e), t = q(r);
7
+ const r = W(e), t = I(r);
8
8
  return structuredClone(t);
9
9
  }
10
10
  function N(e) {
11
11
  return e === "" ? [] : e.split(/\s*\.\s*/).filter(Boolean);
12
12
  }
13
- function m(e, r) {
13
+ function w(e, r) {
14
14
  return (Array.isArray(r) ? r : N(r)).reduce(
15
15
  (a, s) => a == null ? void 0 : a[s],
16
16
  e
17
17
  );
18
18
  }
19
- function U(e, r, t) {
19
+ function Z(e, r, t) {
20
20
  const a = Array.isArray(r) ? r : N(r);
21
21
  if (a.length === 0)
22
22
  throw new Error("Path cannot be empty");
@@ -29,16 +29,16 @@ function U(e, r, t) {
29
29
  }
30
30
  const z = (e, r) => d({
31
31
  get() {
32
- return m(c(e), c(r));
32
+ return w(c(e), c(r));
33
33
  },
34
34
  set(t) {
35
- U(c(e), c(r), t);
35
+ Z(c(e), c(r), t);
36
36
  }
37
37
  });
38
38
  function E(e, r) {
39
39
  return !e && !r ? "" : !e && r ? r : !r && e ? e : `${e}.${r}`;
40
40
  }
41
- function Z(e, r) {
41
+ function k(e, r) {
42
42
  if (!r)
43
43
  return e;
44
44
  const t = `${r}.`, a = Object.fromEntries(
@@ -52,8 +52,8 @@ function Z(e, r) {
52
52
  propertyErrors: a
53
53
  };
54
54
  }
55
- function k(e) {
56
- const r = b({
55
+ function q(e) {
56
+ const r = m({
57
57
  value: e.value,
58
58
  path: e.path,
59
59
  initialValue: d(() => Object.freeze(y(e.initialValue))),
@@ -97,14 +97,14 @@ function H(e) {
97
97
  };
98
98
  return {
99
99
  fields: r,
100
- getField: (u) => r[u],
100
+ getField: (u) => r[u] ?? {},
101
101
  getFields: () => Object.values(r),
102
102
  registerField: t,
103
103
  defineField: (u) => {
104
- const v = k({
104
+ const v = q({
105
105
  ...u,
106
- value: z(S(e, "data"), u.path),
107
- initialValue: d(() => m(e.initialData, c(u.path)))
106
+ value: z(D(e, "data"), u.path),
107
+ initialValue: d(() => w(e.initialData, c(u.path)))
108
108
  });
109
109
  return t(v), v;
110
110
  }
@@ -144,7 +144,7 @@ function Y(...e) {
144
144
  };
145
145
  }, {});
146
146
  }
147
- function D(...e) {
147
+ function P(...e) {
148
148
  if (!e.length)
149
149
  return {
150
150
  general: [],
@@ -227,8 +227,8 @@ class tr {
227
227
  }
228
228
  class ar {
229
229
  constructor(r, t) {
230
- R(this, "schemaValidator");
231
- R(this, "functionValidator");
230
+ S(this, "schemaValidator");
231
+ S(this, "functionValidator");
232
232
  this.schema = r, this.validateFn = t, this.schemaValidator = new er(this.schema), this.functionValidator = new tr(this.validateFn);
233
233
  }
234
234
  async validate(r) {
@@ -238,19 +238,19 @@ class ar {
238
238
  ]);
239
239
  return {
240
240
  isValid: t.isValid && a.isValid,
241
- errors: D(t.errors, a.errors)
241
+ errors: P(t.errors, a.errors)
242
242
  };
243
243
  }
244
244
  }
245
- function P(e) {
245
+ function b(e) {
246
246
  return d(() => new ar(
247
247
  c(e.schema),
248
248
  c(e.validateFn)
249
249
  ));
250
250
  }
251
251
  function sr(e, r) {
252
- const t = b({
253
- validators: A([P(r)]),
252
+ const t = m({
253
+ validators: A([b(r)]),
254
254
  isValidated: !1,
255
255
  errors: c(r.errors) ?? V.errors
256
256
  });
@@ -272,8 +272,8 @@ function sr(e, r) {
272
272
  t.isValidated && u();
273
273
  });
274
274
  const a = (o) => {
275
- const l = _(o) ? o : P(o);
276
- return t.validators.push(l), I() && J(() => {
275
+ const l = _(o) ? o : b(o);
276
+ return t.validators.push(l), J() && T(() => {
277
277
  t.validators = t.validators.filter(
278
278
  (f) => f !== l
279
279
  );
@@ -285,8 +285,8 @@ function sr(e, r) {
285
285
  ), l = o.every((p) => p.isValid);
286
286
  let { errors: f } = V;
287
287
  if (!l) {
288
- const p = o.map((w) => w.errors);
289
- f = D(...p);
288
+ const p = o.map((R) => R.errors);
289
+ f = P(...p);
290
290
  }
291
291
  return {
292
292
  errors: f,
@@ -294,7 +294,7 @@ function sr(e, r) {
294
294
  };
295
295
  }
296
296
  const n = (o) => {
297
- t.errors = D(c(r.errors) ?? V.errors, o);
297
+ t.errors = P(c(r.errors) ?? V.errors, o);
298
298
  }, u = async () => {
299
299
  const o = await s();
300
300
  return n(o.errors), t.isValidated = !0, {
@@ -314,7 +314,7 @@ class ir {
314
314
  this.path = r, this.validator = t;
315
315
  }
316
316
  async validate(r) {
317
- const t = m(r, this.path);
317
+ const t = w(r, this.path);
318
318
  if (!this.validator)
319
319
  return V;
320
320
  const a = await this.validator.validate(t);
@@ -333,7 +333,7 @@ class ir {
333
333
  }
334
334
  }
335
335
  function nr(e, r, t) {
336
- const a = z(e.data, r), s = d(() => m(e.initialData.value, r)), n = (i) => ({
336
+ const a = z(e.data, r), s = d(() => w(e.initialData.value, r)), n = (i) => ({
337
337
  ...i,
338
338
  path: d(() => c(i.path).replace(r + ".", "")),
339
339
  setData: (h) => {
@@ -341,8 +341,7 @@ function nr(e, r, t) {
341
341
  }
342
342
  }), u = (i) => {
343
343
  const h = E(r, i), g = e.getField(h);
344
- if (g)
345
- return n(g);
344
+ return g ? n(g) : {};
346
345
  }, v = (i) => {
347
346
  const h = E(r, i.path), g = e.defineField({
348
347
  ...i,
@@ -355,7 +354,7 @@ function nr(e, r, t) {
355
354
  }).map((i) => n(i)), l = () => e.getFields().filter((i) => {
356
355
  const h = i.path.value;
357
356
  return h.startsWith(r + ".") || h === r;
358
- }), f = d(() => l().some((i) => i.dirty.value)), p = d(() => l().some((i) => i.touched.value)), w = d(() => e.isValid.value), M = d(() => e.isValidated.value), $ = d(() => Z(c(e.errors), r));
357
+ }), f = d(() => l().some((i) => i.dirty.value)), p = d(() => l().some((i) => i.touched.value)), R = d(() => e.isValid.value), M = d(() => e.isValidated.value), $ = d(() => k(c(e.errors), r));
359
358
  return {
360
359
  data: a,
361
360
  initialData: s,
@@ -364,11 +363,11 @@ function nr(e, r, t) {
364
363
  getFields: o,
365
364
  isDirty: f,
366
365
  isTouched: p,
367
- isValid: w,
366
+ isValid: R,
368
367
  isValidated: M,
369
368
  errors: $,
370
369
  defineValidator: (i) => {
371
- const h = _(i) ? i : P(i), g = d(
370
+ const h = _(i) ? i : b(i), g = d(
372
371
  () => new ir(r, c(h))
373
372
  );
374
373
  return e.defineValidator(g), h;
@@ -385,11 +384,13 @@ function nr(e, r, t) {
385
384
  };
386
385
  }
387
386
  function vr(e) {
388
- const r = d(() => Object.freeze(y(e.initialData))), t = A(y(r)), a = b({
387
+ const r = d(() => Object.freeze(y(e.initialData))), t = A(y(r)), a = m({
389
388
  initialData: r,
390
389
  data: t
391
390
  }), s = H(a), n = sr(a, e), u = Q(s), v = () => {
392
- t.value = y(r), s.getFields().forEach((f) => f.reset());
391
+ t.value = y(r), s.getFields().forEach(
392
+ (f) => f.reset()
393
+ );
393
394
  };
394
395
  function o(f, p) {
395
396
  return nr(l, f);
@@ -400,12 +401,12 @@ function vr(e) {
400
401
  ...u,
401
402
  reset: v,
402
403
  getSubForm: o,
403
- initialData: S(a, "initialData"),
404
- data: S(a, "data")
404
+ initialData: D(a, "initialData"),
405
+ data: D(a, "data")
405
406
  };
406
407
  return l;
407
408
  }
408
- const pr = /* @__PURE__ */ T({
409
+ const pr = /* @__PURE__ */ B({
409
410
  __name: "Field",
410
411
  props: {
411
412
  form: {},
@@ -416,10 +417,9 @@ const pr = /* @__PURE__ */ T({
416
417
  },
417
418
  setup(e) {
418
419
  const r = e, t = r.form.defineField({
419
- path: r.path,
420
- required: r.required
420
+ path: r.path
421
421
  });
422
- return (a, s) => B(a.$slots, "default", G(L(c(t))));
422
+ return (a, s) => G(a.$slots, "default", L(U(m(c(t)))));
423
423
  }
424
424
  });
425
425
  export {
@@ -19,18 +19,22 @@ export interface FormField<T, P extends string> {
19
19
  setErrors: (newErrors: ValidationErrorMessage[]) => void;
20
20
  clearErrors: () => void;
21
21
  }
22
+ export type FieldsTuple<T, TPaths = Paths<T>> = [
23
+ ...(TPaths extends infer P ? P extends string ? FormField<PickProps<T, P>, P> : never : never)[]
24
+ ];
25
+ export type AnyField<T> = FormField<PickProps<T, Paths<T>>, Paths<T>>;
22
26
  export interface Form<T extends FormDataDefault> {
23
27
  data: Ref<T>;
24
28
  initialData: Readonly<Ref<T>>;
25
29
  defineField: <P extends Paths<T>>(options: DefineFieldOptions<PickProps<T, P>, P>) => FormField<PickProps<T, P>, P>;
26
- getField: <P extends Paths<T>>(path: P) => FormField<PickProps<T, P>, P> | undefined;
27
- getFields: () => FormField<PickProps<T, Paths<T>>, Paths<T>>[];
30
+ getField: <P extends Paths<T>>(path: P) => FormField<PickProps<T, P>, P>;
31
+ getFields: <TData extends T>() => FieldsTuple<TData>;
28
32
  isDirty: Ref<boolean>;
29
33
  isTouched: Ref<boolean>;
30
34
  isValid: Ref<boolean>;
31
35
  isValidated: Ref<boolean>;
32
36
  errors: Ref<ErrorBag>;
33
- defineValidator: (options: ValidatorOptions<T> | Ref<Validator<T>>) => Ref<Validator<T> | undefined>;
37
+ defineValidator: <TData extends T>(options: ValidatorOptions<TData> | Ref<Validator<TData>>) => Ref<Validator<TData> | undefined>;
34
38
  reset: () => void;
35
39
  validateForm: () => Promise<ValidationResult>;
36
40
  getSubForm: <P extends EntityPaths<T>>(path: P, options?: SubformOptions<PickEntity<T, P>>) => Form<PickEntity<T, P>>;
@@ -6,7 +6,7 @@ export type SplitPath<TPath extends string> = TPath extends `${infer T1}.${infer
6
6
  /**
7
7
  * Picks the exact type of the Entity at the nested PropertyKeys path.
8
8
  */
9
- export type PickProps<Entity, PropertyKeys extends string> = PropertyKeys extends `${infer TRoot}.${infer TRest}` ? TRoot extends keyof Entity ? TRest extends string ? Entity[TRoot] extends object ? PickProps<Entity[TRoot], TRest> : never : never : TRoot extends `${number}` ? Entity extends unknown[] ? TRest extends string ? Entity[number] extends object ? PickProps<Entity[number], TRest> : never : never : never : never : PropertyKeys extends keyof Entity ? Entity[PropertyKeys] : PropertyKeys extends `${number}` ? Entity extends unknown[] ? Entity[number] : never : never;
9
+ export type PickProps<Entity, PropertyKeys extends string> = Entity extends NonNullable<infer NonNullEntity> ? Required<NonNullEntity> extends infer RequiredEntity ? PropertyKeys extends `${infer TRoot}.${infer TRest}` ? TRoot extends keyof RequiredEntity ? TRest extends string ? RequiredEntity[TRoot] extends object ? PickProps<RequiredEntity[TRoot], TRest> : never : never : TRoot extends `${number}` ? RequiredEntity extends unknown[] ? TRest extends string ? RequiredEntity[number] extends object ? PickProps<RequiredEntity[number], TRest> : never : never : never : never : PropertyKeys extends keyof Required<RequiredEntity> ? RequiredEntity[PropertyKeys] : PropertyKeys extends `${number}` ? RequiredEntity extends unknown[] ? RequiredEntity[number] : never : never : never : never;
10
10
  /**
11
11
  * Resolves to a union of dot-connected paths of all nested properties of T.
12
12
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamnovu/kit-vue-forms",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -1,11 +1,12 @@
1
1
  <template>
2
- <slot v-bind="field" />
2
+ <slot v-bind="reactive(field)" />
3
3
  </template>
4
4
 
5
5
  <script
6
6
  setup lang="ts"
7
7
  generic="TData extends object, TPath extends Paths<TData>"
8
8
  >
9
+ import { reactive } from 'vue'
9
10
  import type { Form } from '../types/form.ts'
10
11
  import type { Paths, PickProps } from '../types/util.ts'
11
12
  import type { UseFieldOptions } from '../composables/useField.ts'
@@ -18,6 +19,5 @@ const props = defineProps<FieldProps<TData, TPath>>()
18
19
 
19
20
  const field = props.form.defineField({
20
21
  path: props.path,
21
- required: props.required,
22
22
  })
23
23
  </script>
@@ -1,5 +1,5 @@
1
1
  import { computed, toRef, unref } from 'vue'
2
- import type { FormDataDefault, FormField } from '../types/form'
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
5
  import { useField, type UseFieldOptions } from './useField'
@@ -9,7 +9,7 @@ type FieldRegistryCache<T> = Record<Paths<T>, FormField<any, string>>
9
9
 
10
10
  export type ResolvedFormField<T, K extends Paths<T>> = FormField<PickProps<T, K>, K>
11
11
 
12
- export type DefineFieldOptions<F, K extends string> = Pick<UseFieldOptions<F, K>, 'path' | 'type' | 'required'>
12
+ export type DefineFieldOptions<F, K extends string> = Pick<UseFieldOptions<F, K>, 'path'>
13
13
 
14
14
  interface FormState<T extends FormDataDefault, TIn extends FormDataDefault = T> {
15
15
  data: T
@@ -27,11 +27,11 @@ export function useFieldRegistry<T extends FormDataDefault>(
27
27
  }
28
28
 
29
29
  const getField = <K extends Paths<T>>(path: K) => {
30
- return fields[path] as ResolvedFormField<T, K> | undefined
30
+ return (fields[path] ?? {}) as ResolvedFormField<T, K>
31
31
  }
32
32
 
33
- const getFields = () => {
34
- return Object.values(fields) as ResolvedFormField<T, Paths<T>>[]
33
+ const getFields = <TData extends T>() => {
34
+ return Object.values(fields) as FieldsTuple<TData>
35
35
  }
36
36
 
37
37
  const defineField = <K extends Paths<T>>(options: DefineFieldOptions<PickProps<T, K>, K>) => {
@@ -1,5 +1,5 @@
1
1
  import { computed, reactive, ref, toRef, type MaybeRef, type MaybeRefOrGetter, type Ref } from 'vue'
2
- import type { Form, FormDataDefault } from '../types/form'
2
+ import type { AnyField, Form, FormDataDefault } from '../types/form'
3
3
  import type { EntityPaths, PickEntity } from '../types/util'
4
4
  import type { ValidationStrategy } from '../types/validation'
5
5
  import { cloneRefValue } from '../utils/general'
@@ -32,7 +32,9 @@ export function useForm<T extends FormDataDefault>(options: UseFormOptions<T>) {
32
32
 
33
33
  const reset = () => {
34
34
  data.value = cloneRefValue(initialData)
35
- fields.getFields().forEach(field => field.reset())
35
+ fields.getFields().forEach(
36
+ (field: AnyField<T>) => field.reset(),
37
+ )
36
38
  }
37
39
 
38
40
  function getSubForm<K extends EntityPaths<T>>(
@@ -1,16 +1,16 @@
1
1
  import { computed, unref } from 'vue'
2
- import type { FormDataDefault } from '../types/form'
2
+ import type { AnyField, FormDataDefault } from '../types/form'
3
3
  import type { FieldRegistry } from './useFieldRegistry'
4
4
 
5
5
  export function useFormState<T extends FormDataDefault>(
6
6
  formFieldRegistry: FieldRegistry<T>,
7
7
  ) {
8
8
  const isDirty = computed(() => {
9
- return formFieldRegistry.getFields().some(field => unref(field.dirty))
9
+ return formFieldRegistry.getFields().some((field: AnyField<T>) => unref(field.dirty))
10
10
  })
11
11
 
12
12
  const isTouched = computed(() => {
13
- return formFieldRegistry.getFields().some(field => unref(field.touched))
13
+ return formFieldRegistry.getFields().some((field: AnyField<T>) => unref(field.touched))
14
14
  })
15
15
 
16
16
  return {
@@ -1,5 +1,5 @@
1
1
  import { computed, isRef, unref, type Ref } from 'vue'
2
- import type { Form, FormDataDefault, FormField } from '../types/form'
2
+ import type { FieldsTuple, Form, FormDataDefault, FormField } from '../types/form'
3
3
  import type { EntityPaths, Paths, PickEntity, PickProps } from '../types/util'
4
4
  import type { ValidationResult, Validator } from '../types/validation'
5
5
  import { filterErrorsForPath, getLens, getNestedValue, joinPath } from '../utils/path'
@@ -81,7 +81,7 @@ export function createSubformInterface<
81
81
  const mainFormField = mainForm.getField(fullPath as ScopedMainPaths)
82
82
 
83
83
  if (!mainFormField) {
84
- return
84
+ return {} as FormField<PickProps<ST, P>, P>
85
85
  }
86
86
 
87
87
  return adaptMainFormField<P>(mainFormField)
@@ -99,13 +99,13 @@ export function createSubformInterface<
99
99
  return adaptMainFormField<P>(mainField)
100
100
  }
101
101
 
102
- const getFields = <P extends SP>(): FormField<PickProps<ST, P>, P>[] => {
102
+ const getFields = <P extends SP>() => {
103
103
  return (mainForm.getFields() as FormField<PickProps<T, ScopedMainPaths>, ScopedMainPaths>[])
104
104
  .filter((field) => {
105
105
  const fieldPath = field.path.value
106
106
  return fieldPath.startsWith(path + '.') || fieldPath === path
107
107
  })
108
- .map(field => adaptMainFormField(field))
108
+ .map(field => adaptMainFormField(field)) as FieldsTuple<ST, P>
109
109
  }
110
110
 
111
111
  // Helper function to get all fields without type parameter
@@ -155,10 +155,10 @@ export function useValidation<T extends FormDataDefault>(
155
155
  }
156
156
  })
157
157
 
158
- const defineValidator = (options: ValidatorOptions<T> | Ref<Validator<T>>) => {
158
+ const defineValidator = <TData extends T>(options: ValidatorOptions<TData> | Ref<Validator<TData>>) => {
159
159
  const validator = isRef(options) ? options : createValidator(options)
160
160
 
161
- validationState.validators.push(validator)
161
+ validationState.validators.push(validator as Ref<Validator<T> | undefined>)
162
162
 
163
163
  if (getCurrentScope()) {
164
164
  onBeforeUnmount(() => {
package/src/types/form.ts CHANGED
@@ -22,6 +22,16 @@ export interface FormField<T, P extends string> {
22
22
  clearErrors: () => void
23
23
  }
24
24
 
25
+ export type FieldsTuple<T, TPaths = Paths<T>> = [...(
26
+ TPaths extends infer P
27
+ ? P extends string
28
+ ? FormField<PickProps<T, P>, P>
29
+ : never
30
+ : never
31
+ )[]]
32
+
33
+ export type AnyField<T> = FormField<PickProps<T, Paths<T>>, Paths<T>>
34
+
25
35
  export interface Form<T extends FormDataDefault> {
26
36
  // Data properties
27
37
  data: Ref<T>
@@ -29,8 +39,8 @@ export interface Form<T extends FormDataDefault> {
29
39
 
30
40
  // Field operations
31
41
  defineField: <P extends Paths<T>>(options: DefineFieldOptions<PickProps<T, P>, P>) => FormField<PickProps<T, P>, P>
32
- getField: <P extends Paths<T>>(path: P) => FormField<PickProps<T, P>, P> | undefined
33
- getFields: () => FormField<PickProps<T, Paths<T>>, Paths<T>>[]
42
+ getField: <P extends Paths<T>>(path: P) => FormField<PickProps<T, P>, P>
43
+ getFields: <TData extends T>() => FieldsTuple<TData>
34
44
 
35
45
  // State properties
36
46
  isDirty: Ref<boolean>
@@ -39,7 +49,7 @@ export interface Form<T extends FormDataDefault> {
39
49
  isValidated: Ref<boolean>
40
50
  errors: Ref<ErrorBag>
41
51
 
42
- defineValidator: (options: ValidatorOptions<T> | Ref<Validator<T>>) => Ref<Validator<T> | undefined>
52
+ defineValidator: <TData extends T>(options: ValidatorOptions<TData> | Ref<Validator<TData>>) => Ref<Validator<TData> | undefined>
43
53
 
44
54
  // Operations
45
55
  reset: () => void
package/src/types/util.ts CHANGED
@@ -12,31 +12,35 @@ export type SplitPath<TPath extends string> =
12
12
  * Picks the exact type of the Entity at the nested PropertyKeys path.
13
13
  */
14
14
  export type PickProps<Entity, PropertyKeys extends string> =
15
- PropertyKeys extends `${infer TRoot}.${infer TRest}`
16
- ? TRoot extends keyof Entity
17
- ? TRest extends string
18
- ? Entity[TRoot] extends object
19
- ? PickProps<Entity[TRoot], TRest>
20
- : never
21
- : never
22
- // We might have an array at hand but the key is a string with a number in it
23
- : TRoot extends `${number}`
24
- ? Entity extends unknown[]
15
+ Entity extends NonNullable<infer NonNullEntity>
16
+ ? Required<NonNullEntity> extends infer RequiredEntity
17
+ ? PropertyKeys extends `${infer TRoot}.${infer TRest}`
18
+ ? TRoot extends keyof RequiredEntity
25
19
  ? TRest extends string
26
- ? Entity[number] extends object
27
- ? PickProps<Entity[number], TRest>
20
+ ? RequiredEntity[TRoot] extends object
21
+ ? PickProps<RequiredEntity[TRoot], TRest>
28
22
  : never
29
23
  : never
30
- : never
31
- : never
32
- // We might have an array at hand but the key is a string with a number in it
33
- : PropertyKeys extends keyof Entity
34
- ? Entity[PropertyKeys]
35
- : PropertyKeys extends `${number}`
36
- ? Entity extends unknown[]
37
- ? Entity[number]
38
- : never
39
- : never
24
+ // We might have an array at hand but the key is a string with a number in it
25
+ : TRoot extends `${number}`
26
+ ? RequiredEntity extends unknown[]
27
+ ? TRest extends string
28
+ ? RequiredEntity[number] extends object
29
+ ? PickProps<RequiredEntity[number], TRest>
30
+ : never
31
+ : never
32
+ : never
33
+ : never
34
+ // We might have an array at hand but the key is a string with a number in it
35
+ : PropertyKeys extends keyof Required<RequiredEntity>
36
+ ? RequiredEntity[PropertyKeys]
37
+ : PropertyKeys extends `${number}`
38
+ ? RequiredEntity extends unknown[]
39
+ ? RequiredEntity[number]
40
+ : never
41
+ : never
42
+ : never
43
+ : never
40
44
 
41
45
  /**
42
46
  * Resolves to a union of dot-connected paths of all nested properties of T.
package/tsconfig.json CHANGED
@@ -4,12 +4,11 @@
4
4
  "outDir": "dist",
5
5
  "verbatimModuleSyntax": true,
6
6
  "types": [
7
- "vue",
8
- "vite/client",
9
- ],
7
+ "vite/client"
8
+ ]
10
9
  },
11
10
  "include": [
12
- "src/**/*",
11
+ "src/**/*"
13
12
  ],
14
13
  "exclude": [
15
14
  "dist",