@goodie-forms/react 1.2.1-alpha → 1.2.3-alpha

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,15 +1,16 @@
1
1
  import { FieldPath, FormField, NonnullFormField } from '../../../core/src';
2
- import { ChangeEvent, FocusEvent, ReactNode, Ref } from 'react';
2
+ import { ChangeEvent, ReactNode, Ref } from 'react';
3
3
  import { UseForm } from '../hooks/useForm';
4
4
  export interface RenderParams<TOutput extends object, TValue> {
5
5
  ref: Ref<any | null>;
6
6
  value: TValue | undefined;
7
7
  handlers: {
8
- onChange: (event: ChangeEvent<EventTarget>) => void;
9
- onFocus: (event: FocusEvent) => void;
10
- onBlur: (event: FocusEvent) => void;
8
+ onChange: (event: ChangeEvent<EventTarget> | TValue) => void;
9
+ onFocus: () => void;
10
+ onBlur: () => void;
11
11
  };
12
12
  field: undefined extends TValue ? FormField<TOutput, TValue> : NonnullFormField<TOutput, TValue>;
13
+ form: UseForm<TOutput>;
13
14
  }
14
15
  type DefaultValueProps<TValue> = undefined extends TValue ? {
15
16
  defaultValue?: TValue | (() => TValue);
@@ -1 +1 @@
1
- {"version":3,"file":"FieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/FieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EACL,WAAW,EACX,UAAU,EACV,SAAS,EACT,GAAG,EAGJ,MAAM,OAAO,CAAC;AACf,OAAO,EAAW,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAIpD,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM;IAC1D,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAErB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1B,QAAQ,EAAE;QACR,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;QACpD,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;QACrC,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;KACrC,CAAC;IAEF,KAAK,EAAE,SAAS,SAAS,MAAM,GAC3B,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,GAC1B,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,KAAK,iBAAiB,CAAC,MAAM,IAAI,SAAS,SAAS,MAAM,GACrD;IAAE,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;CAAE,GAC1C;IAAE,YAAY,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;CAAE,CAAC;AAE9C,MAAM,MAAM,kBAAkB,CAC5B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,IAC9B;IACF,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,IAAI,EAAE,KAAK,CAAC;IACZ,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,CACN,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KACtE,SAAS,CAAC;CAChB,GAAG,iBAAiB,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAElE,wBAAgB,aAAa,CAC3B,OAAO,SAAS,MAAM,EACtB,KAAK,CAAC,KAAK,SAAS,SAAS,CAAC,QAAQ,EACtC,KAAK,EAAE,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,2CA4E1C"}
1
+ {"version":3,"file":"FieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/FieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,EAAqB,MAAM,OAAO,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM;IAC1D,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAErB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1B,QAAQ,EAAE;QACR,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,WAAW,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC;QAC7D,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,CAAC;IAEF,KAAK,EAAE,SAAS,SAAS,MAAM,GAC3B,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,GAC1B,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAEtC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB;AAED,KAAK,iBAAiB,CAAC,MAAM,IAAI,SAAS,SAAS,MAAM,GACrD;IAAE,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;CAAE,GAC1C;IAAE,YAAY,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;CAAE,CAAC;AAE9C,MAAM,MAAM,kBAAkB,CAC5B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,IAC9B;IACF,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,IAAI,EAAE,KAAK,CAAC;IACZ,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,CACN,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KACtE,SAAS,CAAC;CAChB,GAAG,iBAAiB,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAElE,wBAAgB,aAAa,CAC3B,OAAO,SAAS,MAAM,EACtB,KAAK,CAAC,KAAK,SAAS,SAAS,CAAC,QAAQ,EACtC,KAAK,EAAE,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,2CAqF1C"}
@@ -0,0 +1,4 @@
1
+ import { FieldPath } from '../../../core/src';
2
+ import { UseForm } from '../hooks/useForm';
3
+ export declare function useFieldErrors<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath): import("@standard-schema/spec").StandardSchemaV1.Issue[] | undefined;
4
+ //# sourceMappingURL=useFieldErrors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFieldErrors.d.ts","sourceRoot":"","sources":["../../src/hooks/useFieldErrors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,wBAAgB,cAAc,CAC5B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAChC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,wEAqBpC"}
@@ -0,0 +1,4 @@
1
+ import { FieldPath } from '../../../core/src';
2
+ import { UseForm } from '../hooks/useForm';
3
+ export declare function useFieldValue<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath): FieldPath.Resolve<TOutput, TPath> | undefined;
4
+ //# sourceMappingURL=useFieldValue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFieldValue.d.ts","sourceRoot":"","sources":["../../src/hooks/useFieldValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,wBAAgB,aAAa,CAC3B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAChC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,iDAqBpC"}
@@ -1,5 +1,6 @@
1
1
  import { FieldPath } from '../../../core/src';
2
2
  import { UseForm } from './useForm';
3
+ /** @deprecated */
3
4
  export declare function useFormErrorObserver<TOutput extends object, TInclude extends FieldPath.Segments[] | undefined = undefined>(form: UseForm<TOutput>, options?: {
4
5
  include?: TInclude;
5
6
  }): Record<string, import("@standard-schema/spec").StandardSchemaV1.Issue[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"useFormErrorObserver.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormErrorObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,wBAAgB,oBAAoB,CAClC,OAAO,SAAS,MAAM,EACtB,QAAQ,SAAS,SAAS,CAAC,QAAQ,EAAE,GAAG,SAAS,GAAG,SAAS,EAE7D,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,4EA6BF"}
1
+ {"version":3,"file":"useFormErrorObserver.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormErrorObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,kBAAkB;AAClB,wBAAgB,oBAAoB,CAClC,OAAO,SAAS,MAAM,EACtB,QAAQ,SAAS,SAAS,CAAC,QAAQ,EAAE,GAAG,SAAS,GAAG,SAAS,EAE7D,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,4EA6BF"}
@@ -1,5 +1,6 @@
1
1
  import { FieldPath } from '../../../core/src';
2
2
  import { UseForm } from './useForm';
3
+ /** @deprecated */
3
4
  export declare function useFormValuesObserver<TOutput extends object, TPaths extends FieldPath.Segments[] | undefined = undefined>(form: UseForm<TOutput>, options?: {
4
5
  include?: TPaths;
5
6
  }): import('../../../core/src').DeepPartial<TOutput>;
@@ -1 +1 @@
1
- {"version":3,"file":"useFormValuesObserver.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormValuesObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,wBAAgB,qBAAqB,CACnC,OAAO,SAAS,MAAM,EACtB,MAAM,SAAS,SAAS,CAAC,QAAQ,EAAE,GAAG,SAAS,GAAG,SAAS,EAE3D,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,qDAmCF"}
1
+ {"version":3,"file":"useFormValuesObserver.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormValuesObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,kBAAkB;AAClB,wBAAgB,qBAAqB,CACnC,OAAO,SAAS,MAAM,EACtB,MAAM,SAAS,SAAS,CAAC,QAAQ,EAAE,GAAG,SAAS,GAAG,SAAS,EAE3D,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,qDAmCF"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export * from './hooks/useForm';
2
2
  export * from './hooks/useFormField';
3
+ export * from './hooks/useFieldValue';
4
+ export * from './hooks/useFieldErrors';
3
5
  export * from './hooks/useFormValuesObserver';
4
6
  export * from './hooks/useFormErrorObserver';
5
7
  export * from './hooks/useRenderControl';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AAEzC,cAAc,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AAEzC,cAAc,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -1,169 +1,200 @@
1
- import { FormController as m, FieldPathBuilder as h, FieldPath as o } from "@goodie-forms/core";
2
- import { useState as a, useRef as v, startTransition as F, useEffect as i } from "react";
3
- import { jsx as g, Fragment as C } from "react/jsx-runtime";
4
- function f() {
5
- const [, e] = a(0), n = v(0), r = v(!1);
1
+ import { FormController as F, FieldPathBuilder as m, FieldPath as u } from "@goodie-forms/core";
2
+ import { useState as f, useRef as v, startTransition as C, useEffect as c } from "react";
3
+ import { jsx as g, Fragment as h } from "react/jsx-runtime";
4
+ function a() {
5
+ const [, e] = f(0), n = v(0), t = v(!1);
6
6
  n.current++;
7
- const u = () => {
8
- r.current || (r.current = !0, queueMicrotask(() => {
9
- F(() => {
10
- e((t) => t + 1);
11
- }), r.current = !1;
7
+ const o = () => {
8
+ t.current || (t.current = !0, queueMicrotask(() => {
9
+ C(() => {
10
+ e((r) => r + 1);
11
+ }), t.current = !1;
12
12
  }));
13
13
  };
14
14
  return {
15
15
  renderCount: n.current,
16
- forceRerender: u
16
+ forceRerender: o
17
17
  };
18
18
  }
19
- function s(...e) {
19
+ function i(...e) {
20
20
  return () => {
21
21
  for (const n of e)
22
22
  n();
23
23
  };
24
24
  }
25
25
  function U(e, n) {
26
- const [r] = a(() => new m(e)), [u] = a(() => new h()), t = f();
27
- return i(() => {
26
+ const [t] = f(() => new F(e)), [o] = f(() => new m()), r = a();
27
+ return c(() => {
28
28
  const l = () => {
29
29
  };
30
- return s(
31
- r.events.on("submissionStatusChange", () => {
32
- t.forceRerender();
30
+ return i(
31
+ t.events.on("submissionStatusChange", () => {
32
+ r.forceRerender();
33
33
  }),
34
- n?.watchIssues ? r.events.on(
34
+ n?.watchIssues ? t.events.on(
35
35
  "fieldIssuesUpdated",
36
- () => t.forceRerender()
36
+ () => r.forceRerender()
37
37
  ) : l,
38
- n?.watchValues ? r.events.on(
38
+ n?.watchValues ? t.events.on(
39
39
  "valueChanged",
40
- () => t.forceRerender()
40
+ () => r.forceRerender()
41
41
  ) : l
42
42
  );
43
- }, [r]), {
43
+ }, [t]), {
44
44
  formConfigs: e,
45
- paths: u,
45
+ paths: o,
46
46
  hookConfigs: n,
47
- controller: r
47
+ controller: t
48
48
  };
49
49
  }
50
- function R(e, n, r) {
51
- const u = f(), [t, l] = a(() => {
50
+ function R(e, n, t) {
51
+ const o = a(), [r, l] = f(() => {
52
52
  let d = e.controller.getField(n);
53
- return d == null && r != null && (d = e.controller.bindField(n, r)), d;
53
+ return d == null && t != null && (d = e.controller.bindField(n, t)), d;
54
54
  });
55
- return i(() => {
55
+ return c(() => {
56
56
  const { events: d } = e.controller;
57
- return l(e.controller.getField(n)), s(
58
- d.on("fieldBound", (c) => {
59
- o.equals(c, n) && l(e.controller.getField(n));
57
+ return l(e.controller.getField(n)), i(
58
+ d.on("fieldBound", (s) => {
59
+ u.equals(s, n) && l(e.controller.getField(n));
60
60
  }),
61
- d.on("fieldUnbound", (c) => {
62
- o.equals(c, n) && l(void 0);
61
+ d.on("fieldUnbound", (s) => {
62
+ u.equals(s, n) && l(void 0);
63
63
  }),
64
- d.on("valueChanged", (c) => {
65
- (o.equals(c, n) || o.isDescendant(c, n)) && u.forceRerender();
64
+ d.on("valueChanged", (s) => {
65
+ (u.equals(s, n) || u.isDescendant(s, n)) && o.forceRerender();
66
66
  }),
67
- d.on("fieldTouchUpdated", (c) => {
68
- o.equals(c, n) && u.forceRerender();
67
+ d.on("fieldTouchUpdated", (s) => {
68
+ u.equals(s, n) && o.forceRerender();
69
69
  }),
70
- d.on("fieldDirtyUpdated", (c) => {
71
- o.equals(c, n) && u.forceRerender();
70
+ d.on("fieldDirtyUpdated", (s) => {
71
+ u.equals(s, n) && o.forceRerender();
72
72
  }),
73
- d.on("fieldIssuesUpdated", (c) => {
74
- o.equals(c, n) && u.forceRerender();
73
+ d.on("fieldIssuesUpdated", (s) => {
74
+ u.equals(s, n) && o.forceRerender();
75
75
  })
76
76
  );
77
- }, []), t;
77
+ }, []), r;
78
78
  }
79
79
  function w(e, n) {
80
- const r = f(), u = n?.include == null ? e.controller._data : n.include.reduce((t, l) => {
81
- const d = o.getValue(
80
+ const t = a(), o = e.controller.getField(n)?.value;
81
+ return c(() => i(
82
+ e.controller.events.on("fieldBound", (r) => {
83
+ u.equals(n, r) && t.forceRerender();
84
+ }),
85
+ e.controller.events.on("valueChanged", (r) => {
86
+ u.equals(n, r) && t.forceRerender();
87
+ })
88
+ ), []), o;
89
+ }
90
+ function B(e, n) {
91
+ const t = a(), o = e.controller.getField(n)?.issues;
92
+ return c(() => i(
93
+ e.controller.events.on("fieldBound", (r) => {
94
+ u.equals(n, r) && t.forceRerender();
95
+ }),
96
+ e.controller.events.on("fieldIssuesUpdated", (r) => {
97
+ u.equals(n, r) && t.forceRerender();
98
+ })
99
+ ), []), o;
100
+ }
101
+ function y(e, n) {
102
+ const t = a(), o = n?.include == null ? e.controller._data : n.include.reduce((r, l) => {
103
+ const d = u.getValue(
82
104
  e.controller._data,
83
105
  l
84
106
  );
85
- return o.setValue(t, l, d), t;
107
+ return u.setValue(r, l, d), r;
86
108
  }, {});
87
- return i(() => {
88
- const { events: t } = e.controller;
89
- return s(
90
- t.on("valueChanged", (l) => {
109
+ return c(() => {
110
+ const { events: r } = e.controller;
111
+ return i(
112
+ r.on("valueChanged", (l) => {
91
113
  (n?.include == null || n.include.some(
92
- (c) => o.equals(c, l) || o.isDescendant(c, l)
93
- )) && r.forceRerender();
114
+ (s) => u.equals(s, l) || u.isDescendant(s, l)
115
+ )) && t.forceRerender();
94
116
  })
95
117
  );
96
- }, []), u;
118
+ }, []), o;
97
119
  }
98
- function V(e, n) {
99
- const r = {};
100
- for (const u of e) {
101
- const t = n(u);
102
- (r[t] ??= []).push(u);
120
+ function q(e, n) {
121
+ const t = {};
122
+ for (const o of e) {
123
+ const r = n(o);
124
+ (t[r] ??= []).push(o);
103
125
  }
104
- return r;
126
+ return t;
105
127
  }
106
- function y(e, n) {
107
- const r = f(), u = e.controller._issues.filter((t) => {
128
+ function D(e, n) {
129
+ const t = a(), o = e.controller._issues.filter((r) => {
108
130
  if (n?.include == null) return !0;
109
- const l = o.normalize(t.path);
131
+ const l = u.normalize(r.path);
110
132
  return n.include.some(
111
- (d) => o.equals(d, l)
133
+ (d) => u.equals(d, l)
112
134
  );
113
135
  });
114
- return i(() => {
115
- const { events: t } = e.controller;
116
- return s(
117
- t.on("fieldIssuesUpdated", (l) => {
118
- (n?.include?.includes?.(l) ?? !0) && r.forceRerender();
136
+ return c(() => {
137
+ const { events: r } = e.controller;
138
+ return i(
139
+ r.on("fieldIssuesUpdated", (l) => {
140
+ (n?.include?.includes?.(l) ?? !0) && t.forceRerender();
119
141
  })
120
142
  );
121
- }, []), V(
122
- u,
123
- (t) => t.path == null ? "$" : o.toStringPath(o.normalize(t.path))
143
+ }, []), q(
144
+ o,
145
+ (r) => r.path == null ? "$" : u.toStringPath(u.normalize(r.path))
124
146
  );
125
147
  }
126
- function B(e) {
127
- const n = v(null), r = R(e.form, e.path, {
148
+ function E(e) {
149
+ const n = v(null), t = R(e.form, e.path, {
128
150
  overrideInitialValue: e.overrideInitialValue ?? !0,
129
151
  defaultValue: typeof e.defaultValue == "function" ? e.defaultValue() : e.defaultValue
130
- }), u = {
131
- onChange(t) {
132
- const { target: l } = t;
133
- l === r.boundElement && "value" in l && typeof l.value == "string" && r.setValue(l.value, {
152
+ }), o = {
153
+ onChange(r) {
154
+ let l;
155
+ if ("target" in r) {
156
+ const { target: d } = r;
157
+ if (d !== t.boundElement || !("value" in d) || typeof d.value != "string") return;
158
+ l = d.value;
159
+ } else
160
+ l = r;
161
+ t.setValue(l, {
134
162
  shouldTouch: !0,
135
163
  shouldMarkDirty: !0
136
164
  });
137
165
  },
138
166
  onFocus() {
139
- r.touch();
167
+ t.touch();
140
168
  },
141
169
  onBlur() {
142
170
  (e.form.hookConfigs?.validateMode === "onBlur" || e.form.hookConfigs?.validateMode === "onChange") && e.form.controller.validateField(e.path);
143
171
  }
144
172
  };
145
- return i(() => {
146
- const { events: t } = e.form.controller;
147
- return s(
148
- t.on("valueChanged", (l) => {
149
- !o.equals(l, e.path) && !o.isDescendant(l, e.path) || e.form.hookConfigs?.validateMode === "onChange" && e.form.controller.validateField(e.path);
173
+ return c(() => {
174
+ const { events: r } = e.form.controller;
175
+ return i(
176
+ r.on("valueChanged", (l) => {
177
+ !u.equals(l, e.path) && !u.isDescendant(l, e.path) || e.form.hookConfigs?.validateMode === "onChange" && e.form.controller.validateField(e.path);
150
178
  })
151
179
  );
152
- }, []), i(() => (r.bindElement(n.current), () => {
180
+ }, []), c(() => (t.bindElement(n.current), () => {
153
181
  e.unbindOnUnmount && e.form.controller.unbindField(e.path);
154
- }), []), /* @__PURE__ */ g(C, { children: e.render({
182
+ }), []), /* @__PURE__ */ g(h, { children: e.render({
155
183
  ref: n,
156
- value: r.value,
157
- handlers: u,
158
- field: r
184
+ value: t.value,
185
+ handlers: o,
186
+ field: t,
187
+ form: e.form
159
188
  }) });
160
189
  }
161
190
  export {
162
- B as FieldRenderer,
191
+ E as FieldRenderer,
192
+ B as useFieldErrors,
193
+ w as useFieldValue,
163
194
  U as useForm,
164
- y as useFormErrorObserver,
195
+ D as useFormErrorObserver,
165
196
  R as useFormField,
166
- w as useFormValuesObserver,
167
- f as useRenderControl
197
+ y as useFormValuesObserver,
198
+ a as useRenderControl
168
199
  };
169
200
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/hooks/useRenderControl.tsx","../src/utils/composeFns.ts","../src/hooks/useForm.tsx","../src/hooks/useFormField.tsx","../src/hooks/useFormValuesObserver.ts","../src/utils/groupBy.ts","../src/hooks/useFormErrorObserver.ts","../src/components/FieldRenderer.tsx"],"sourcesContent":["import { startTransition, useRef, useState } from \"react\";\r\n\r\nexport function useRenderControl() {\r\n const [, rerender] = useState(0);\r\n const renderCount = useRef(0);\r\n const renderScheduled = useRef(false);\r\n renderCount.current++;\r\n\r\n const scheduleRerender = () => {\r\n if (renderScheduled.current) return;\r\n renderScheduled.current = true;\r\n\r\n queueMicrotask(() => {\r\n startTransition(() => {\r\n rerender((i) => i + 1);\r\n });\r\n\r\n renderScheduled.current = false;\r\n });\r\n };\r\n\r\n return {\r\n renderCount: renderCount.current,\r\n forceRerender: scheduleRerender,\r\n };\r\n}\r\n","export function composeFns<TFns extends (() => void)[]>(...fns: TFns) {\r\n return () => {\r\n for (const fn of fns) {\r\n fn();\r\n }\r\n };\r\n}\r\n","import { FieldPathBuilder, FormController } from \"@goodie-forms/core\";\r\nimport { useEffect, useState } from \"react\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useForm<TOutput extends object>(\r\n formConfigs: FormController.Configs<TOutput>,\r\n hookConfigs?: {\r\n validateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n revalidateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n watchIssues?: boolean;\r\n watchValues?: boolean;\r\n },\r\n) {\r\n const [controller] = useState(() => new FormController(formConfigs));\r\n const [paths] = useState(() => new FieldPathBuilder<TOutput>());\r\n\r\n const renderControl = useRenderControl();\r\n\r\n useEffect(() => {\r\n const noop = () => {};\r\n\r\n return composeFns(\r\n controller.events.on(\"submissionStatusChange\", () => {\r\n renderControl.forceRerender();\r\n }),\r\n hookConfigs?.watchIssues\r\n ? controller.events.on(\"fieldIssuesUpdated\", () =>\r\n renderControl.forceRerender(),\r\n )\r\n : noop,\r\n hookConfigs?.watchValues\r\n ? controller.events.on(\"valueChanged\", () =>\r\n renderControl.forceRerender(),\r\n )\r\n : noop,\r\n );\r\n }, [controller]);\r\n\r\n return {\r\n formConfigs,\r\n paths,\r\n hookConfigs,\r\n controller,\r\n };\r\n}\r\n\r\nexport type UseForm<TOutput extends object> = ReturnType<\r\n typeof useForm<TOutput>\r\n>;\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect, useState } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n bindingConfig?: Parameters<typeof form.controller.bindField<TPath>>[1],\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const [field, setField] = useState(() => {\r\n let field = form.controller.getField(path);\r\n if (field == null && bindingConfig != null) {\r\n field = form.controller.bindField(path, bindingConfig);\r\n }\r\n return field;\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n setField(form.controller.getField(path));\r\n\r\n return composeFns(\r\n events.on(\"fieldBound\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n setField(form.controller.getField(path));\r\n }),\r\n events.on(\"fieldUnbound\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n setField(undefined);\r\n }),\r\n events.on(\"valueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n events.on(\"fieldTouchUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n events.on(\"fieldDirtyUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n );\r\n }, []);\r\n\r\n return field;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport type { UseForm } from \"./useForm\";\r\nimport { useRenderControl } from \"./useRenderControl\";\r\n\r\nexport function useFormValuesObserver<\r\n TOutput extends object,\r\n TPaths extends FieldPath.Segments[] | undefined = undefined,\r\n>(\r\n form: UseForm<TOutput>,\r\n options?: {\r\n include?: TPaths;\r\n },\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const observedValues =\r\n options?.include == null\r\n ? form.controller._data\r\n : options.include.reduce((data, path) => {\r\n const value = FieldPath.getValue(\r\n form.controller._data as TOutput,\r\n path,\r\n )!;\r\n FieldPath.setValue(data, path, value);\r\n return data;\r\n }, {} as TOutput);\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n return composeFns(\r\n events.on(\"valueChanged\", (changedPath) => {\r\n const watchingChange =\r\n options?.include == null\r\n ? true\r\n : options.include.some(\r\n (path) =>\r\n FieldPath.equals(path, changedPath) ||\r\n FieldPath.isDescendant(path, changedPath),\r\n );\r\n if (watchingChange) renderControl.forceRerender();\r\n }),\r\n );\r\n }, []);\r\n\r\n return observedValues;\r\n}\r\n","export function groupBy<T, K extends PropertyKey>(\r\n items: readonly T[],\r\n key: (item: T) => K,\r\n): Record<K, T[]> {\r\n const result = {} as Record<K, T[]>;\r\n\r\n for (const item of items) {\r\n const k = key(item);\r\n (result[k] ??= []).push(item);\r\n }\r\n\r\n return result;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { groupBy } from \"../utils/groupBy\";\r\nimport { useEffect } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport type { UseForm } from \"./useForm\";\r\nimport { useRenderControl } from \"./useRenderControl\";\r\n\r\nexport function useFormErrorObserver<\r\n TOutput extends object,\r\n TInclude extends FieldPath.Segments[] | undefined = undefined,\r\n>(\r\n form: UseForm<TOutput>,\r\n options?: {\r\n include?: TInclude;\r\n },\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const observedIssues = form.controller._issues.filter((issue) => {\r\n if (options?.include == null) return true;\r\n const normalizedIssuePath = FieldPath.normalize(issue.path);\r\n return options.include.some((path) =>\r\n FieldPath.equals(path, normalizedIssuePath),\r\n );\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldIssuesUpdated\", (path) => {\r\n if (options?.include?.includes?.(path) ?? true) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n return groupBy(observedIssues, (issue) =>\r\n issue.path == null\r\n ? \"$\"\r\n : FieldPath.toStringPath(FieldPath.normalize(issue.path)),\r\n );\r\n}\r\n","import { FieldPath, FormField, NonnullFormField } from \"@goodie-forms/core\";\r\nimport {\r\n ChangeEvent,\r\n FocusEvent,\r\n ReactNode,\r\n Ref,\r\n useEffect,\r\n useRef,\r\n} from \"react\";\r\nimport { useForm, UseForm } from \"../hooks/useForm\";\r\nimport { useFormField } from \"../hooks/useFormField\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport interface RenderParams<TOutput extends object, TValue> {\r\n ref: Ref<any | null>;\r\n\r\n value: TValue | undefined;\r\n\r\n handlers: {\r\n onChange: (event: ChangeEvent<EventTarget>) => void;\r\n onFocus: (event: FocusEvent) => void;\r\n onBlur: (event: FocusEvent) => void;\r\n };\r\n\r\n field: undefined extends TValue\r\n ? FormField<TOutput, TValue>\r\n : NonnullFormField<TOutput, TValue>;\r\n}\r\n\r\ntype DefaultValueProps<TValue> = undefined extends TValue\r\n ? { defaultValue?: TValue | (() => TValue) }\r\n : { defaultValue: TValue | (() => TValue) };\r\n\r\nexport type FieldRendererProps<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n> = {\r\n form: UseForm<TOutput>;\r\n path: TPath;\r\n overrideInitialValue?: boolean;\r\n unbindOnUnmount?: boolean;\r\n render: (\r\n params: RenderParams<TOutput, FieldPath.Resolve<TOutput, NoInfer<TPath>>>,\r\n ) => ReactNode;\r\n} & DefaultValueProps<FieldPath.Resolve<TOutput, NoInfer<TPath>>>;\r\n\r\nexport function FieldRenderer<\r\n TOutput extends object,\r\n const TPath extends FieldPath.Segments,\r\n>(props: FieldRendererProps<TOutput, TPath>) {\r\n type TValue = FieldPath.Resolve<TOutput, TPath>;\r\n\r\n const elementRef = useRef<HTMLElement>(null);\r\n\r\n const field = useFormField(props.form, props.path, {\r\n overrideInitialValue: props.overrideInitialValue ?? true,\r\n defaultValue:\r\n typeof props.defaultValue === \"function\"\r\n ? (props.defaultValue as any)()\r\n : props.defaultValue,\r\n })!;\r\n\r\n const handlers: RenderParams<TOutput, TValue>[\"handlers\"] = {\r\n onChange(event) {\r\n const { target } = event;\r\n if (target !== field.boundElement) return;\r\n if (!(\"value\" in target)) return;\r\n if (typeof target.value !== \"string\") return;\r\n field.setValue(target.value as TValue, {\r\n shouldTouch: true,\r\n shouldMarkDirty: true,\r\n });\r\n },\r\n onFocus() {\r\n field.touch();\r\n },\r\n onBlur() {\r\n if (\r\n props.form.hookConfigs?.validateMode === \"onBlur\" ||\r\n props.form.hookConfigs?.validateMode === \"onChange\"\r\n ) {\r\n props.form.controller.validateField(props.path);\r\n }\r\n },\r\n };\r\n\r\n useEffect(() => {\r\n const { events } = props.form.controller;\r\n\r\n return composeFns(\r\n events.on(\"valueChanged\", (_path) => {\r\n if (\r\n !FieldPath.equals(_path, props.path) &&\r\n !FieldPath.isDescendant(_path, props.path)\r\n ) {\r\n return;\r\n }\r\n\r\n if (props.form.hookConfigs?.validateMode === \"onChange\") {\r\n props.form.controller.validateField(props.path);\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n useEffect(() => {\r\n field.bindElement(elementRef.current!);\r\n\r\n return () => {\r\n if (props.unbindOnUnmount) {\r\n props.form.controller.unbindField(props.path);\r\n }\r\n };\r\n }, []);\r\n\r\n return (\r\n <>\r\n {props.render({\r\n ref: elementRef,\r\n value: field.value,\r\n handlers: handlers,\r\n field: field as any,\r\n })}\r\n </>\r\n );\r\n}\r\n\r\n/* ---- TESTS ---------------- */\r\n\r\n// function TestComp() {\r\n// const form = useForm<{ a?: { b: 99 } }>({});\r\n\r\n// const jsx = (\r\n// <>\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a.b)}\r\n// defaultValue={() => 99 as const}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n\r\n// {/* defaultField olmayabilir, çünkü \"a\" nullable */}\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a)}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromStringPath(\"a.b\")}\r\n// defaultValue={() => 99 as const}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n// </>\r\n// );\r\n// }\r\n"],"names":["useRenderControl","rerender","useState","renderCount","useRef","renderScheduled","scheduleRerender","startTransition","i","composeFns","fns","fn","useForm","formConfigs","hookConfigs","controller","FormController","paths","FieldPathBuilder","renderControl","useEffect","noop","useFormField","form","path","bindingConfig","field","setField","events","_path","FieldPath","changedPath","useFormValuesObserver","options","observedValues","data","value","groupBy","items","key","result","item","k","useFormErrorObserver","observedIssues","issue","normalizedIssuePath","FieldRenderer","props","elementRef","handlers","event","target","jsx","Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/hooks/useRenderControl.tsx","../src/utils/composeFns.ts","../src/hooks/useForm.tsx","../src/hooks/useFormField.tsx","../src/hooks/useFieldValue.ts","../src/hooks/useFieldErrors.ts","../src/hooks/useFormValuesObserver.ts","../src/utils/groupBy.ts","../src/hooks/useFormErrorObserver.ts","../src/components/FieldRenderer.tsx"],"sourcesContent":["import { startTransition, useRef, useState } from \"react\";\r\n\r\nexport function useRenderControl() {\r\n const [, rerender] = useState(0);\r\n const renderCount = useRef(0);\r\n const renderScheduled = useRef(false);\r\n renderCount.current++;\r\n\r\n const scheduleRerender = () => {\r\n if (renderScheduled.current) return;\r\n renderScheduled.current = true;\r\n\r\n queueMicrotask(() => {\r\n startTransition(() => {\r\n rerender((i) => i + 1);\r\n });\r\n\r\n renderScheduled.current = false;\r\n });\r\n };\r\n\r\n return {\r\n renderCount: renderCount.current,\r\n forceRerender: scheduleRerender,\r\n };\r\n}\r\n","export function composeFns<TFns extends (() => void)[]>(...fns: TFns) {\r\n return () => {\r\n for (const fn of fns) {\r\n fn();\r\n }\r\n };\r\n}\r\n","import { FieldPathBuilder, FormController } from \"@goodie-forms/core\";\r\nimport { useEffect, useState } from \"react\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useForm<TOutput extends object>(\r\n formConfigs: FormController.Configs<TOutput>,\r\n hookConfigs?: {\r\n validateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n revalidateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n watchIssues?: boolean;\r\n watchValues?: boolean;\r\n },\r\n) {\r\n const [controller] = useState(() => new FormController(formConfigs));\r\n const [paths] = useState(() => new FieldPathBuilder<TOutput>());\r\n\r\n const renderControl = useRenderControl();\r\n\r\n useEffect(() => {\r\n const noop = () => {};\r\n\r\n return composeFns(\r\n controller.events.on(\"submissionStatusChange\", () => {\r\n renderControl.forceRerender();\r\n }),\r\n hookConfigs?.watchIssues\r\n ? controller.events.on(\"fieldIssuesUpdated\", () =>\r\n renderControl.forceRerender(),\r\n )\r\n : noop,\r\n hookConfigs?.watchValues\r\n ? controller.events.on(\"valueChanged\", () =>\r\n renderControl.forceRerender(),\r\n )\r\n : noop,\r\n );\r\n }, [controller]);\r\n\r\n return {\r\n formConfigs,\r\n paths,\r\n hookConfigs,\r\n controller,\r\n };\r\n}\r\n\r\nexport type UseForm<TOutput extends object> = ReturnType<\r\n typeof useForm<TOutput>\r\n>;\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect, useState } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n bindingConfig?: Parameters<typeof form.controller.bindField<TPath>>[1],\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const [field, setField] = useState(() => {\r\n let field = form.controller.getField(path);\r\n if (field == null && bindingConfig != null) {\r\n field = form.controller.bindField(path, bindingConfig);\r\n }\r\n return field;\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n setField(form.controller.getField(path));\r\n\r\n return composeFns(\r\n events.on(\"fieldBound\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n setField(form.controller.getField(path));\r\n }),\r\n events.on(\"fieldUnbound\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n setField(undefined);\r\n }),\r\n events.on(\"valueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n events.on(\"fieldTouchUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n events.on(\"fieldDirtyUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (_path) => {\r\n if (!FieldPath.equals(_path, path)) return;\r\n renderControl.forceRerender();\r\n }),\r\n );\r\n }, []);\r\n\r\n return field;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFieldValue<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const renderControl = useRenderControl();\r\n\r\n const value = form.controller.getField(path)?.value;\r\n\r\n useEffect(() => {\r\n return composeFns(\r\n form.controller.events.on(\"fieldBound\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n form.controller.events.on(\"valueChanged\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n return value;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useRenderControl } from \"../hooks/useRenderControl\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFieldErrors<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const renderControl = useRenderControl();\r\n\r\n const issues = form.controller.getField(path)?.issues;\r\n\r\n useEffect(() => {\r\n return composeFns(\r\n form.controller.events.on(\"fieldBound\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n form.controller.events.on(\"fieldIssuesUpdated\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n return issues;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useEffect } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport type { UseForm } from \"./useForm\";\r\nimport { useRenderControl } from \"./useRenderControl\";\r\n\r\n/** @deprecated */\r\nexport function useFormValuesObserver<\r\n TOutput extends object,\r\n TPaths extends FieldPath.Segments[] | undefined = undefined,\r\n>(\r\n form: UseForm<TOutput>,\r\n options?: {\r\n include?: TPaths;\r\n },\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const observedValues =\r\n options?.include == null\r\n ? form.controller._data\r\n : options.include.reduce((data, path) => {\r\n const value = FieldPath.getValue(\r\n form.controller._data as TOutput,\r\n path,\r\n )!;\r\n FieldPath.setValue(data, path, value);\r\n return data;\r\n }, {} as TOutput);\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n return composeFns(\r\n events.on(\"valueChanged\", (changedPath) => {\r\n const watchingChange =\r\n options?.include == null\r\n ? true\r\n : options.include.some(\r\n (path) =>\r\n FieldPath.equals(path, changedPath) ||\r\n FieldPath.isDescendant(path, changedPath),\r\n );\r\n if (watchingChange) renderControl.forceRerender();\r\n }),\r\n );\r\n }, []);\r\n\r\n return observedValues;\r\n}\r\n","export function groupBy<T, K extends PropertyKey>(\r\n items: readonly T[],\r\n key: (item: T) => K,\r\n): Record<K, T[]> {\r\n const result = {} as Record<K, T[]>;\r\n\r\n for (const item of items) {\r\n const k = key(item);\r\n (result[k] ??= []).push(item);\r\n }\r\n\r\n return result;\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { groupBy } from \"../utils/groupBy\";\r\nimport { useEffect } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport type { UseForm } from \"./useForm\";\r\nimport { useRenderControl } from \"./useRenderControl\";\r\n\r\n/** @deprecated */\r\nexport function useFormErrorObserver<\r\n TOutput extends object,\r\n TInclude extends FieldPath.Segments[] | undefined = undefined,\r\n>(\r\n form: UseForm<TOutput>,\r\n options?: {\r\n include?: TInclude;\r\n },\r\n) {\r\n const renderControl = useRenderControl();\r\n\r\n const observedIssues = form.controller._issues.filter((issue) => {\r\n if (options?.include == null) return true;\r\n const normalizedIssuePath = FieldPath.normalize(issue.path);\r\n return options.include.some((path) =>\r\n FieldPath.equals(path, normalizedIssuePath),\r\n );\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = form.controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldIssuesUpdated\", (path) => {\r\n if (options?.include?.includes?.(path) ?? true) {\r\n renderControl.forceRerender();\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n return groupBy(observedIssues, (issue) =>\r\n issue.path == null\r\n ? \"$\"\r\n : FieldPath.toStringPath(FieldPath.normalize(issue.path)),\r\n );\r\n}\r\n","import { FieldPath, FormField, NonnullFormField } from \"@goodie-forms/core\";\r\nimport { ChangeEvent, ReactNode, Ref, useEffect, useRef } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useFormField } from \"../hooks/useFormField\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport interface RenderParams<TOutput extends object, TValue> {\r\n ref: Ref<any | null>;\r\n\r\n value: TValue | undefined;\r\n\r\n handlers: {\r\n onChange: (event: ChangeEvent<EventTarget> | TValue) => void;\r\n onFocus: () => void;\r\n onBlur: () => void;\r\n };\r\n\r\n field: undefined extends TValue\r\n ? FormField<TOutput, TValue>\r\n : NonnullFormField<TOutput, TValue>;\r\n\r\n form: UseForm<TOutput>;\r\n}\r\n\r\ntype DefaultValueProps<TValue> = undefined extends TValue\r\n ? { defaultValue?: TValue | (() => TValue) }\r\n : { defaultValue: TValue | (() => TValue) };\r\n\r\nexport type FieldRendererProps<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n> = {\r\n form: UseForm<TOutput>;\r\n path: TPath;\r\n overrideInitialValue?: boolean;\r\n unbindOnUnmount?: boolean;\r\n render: (\r\n params: RenderParams<TOutput, FieldPath.Resolve<TOutput, NoInfer<TPath>>>,\r\n ) => ReactNode;\r\n} & DefaultValueProps<FieldPath.Resolve<TOutput, NoInfer<TPath>>>;\r\n\r\nexport function FieldRenderer<\r\n TOutput extends object,\r\n const TPath extends FieldPath.Segments,\r\n>(props: FieldRendererProps<TOutput, TPath>) {\r\n type TValue = FieldPath.Resolve<TOutput, TPath>;\r\n\r\n const elementRef = useRef<HTMLElement>(null);\r\n\r\n const field = useFormField(props.form, props.path, {\r\n overrideInitialValue: props.overrideInitialValue ?? true,\r\n defaultValue:\r\n typeof props.defaultValue === \"function\"\r\n ? (props.defaultValue as any)()\r\n : props.defaultValue,\r\n })!;\r\n\r\n const handlers: RenderParams<TOutput, TValue>[\"handlers\"] = {\r\n onChange(arg) {\r\n let newValue: TValue;\r\n\r\n if (\"target\" in arg) {\r\n const { target } = arg;\r\n if (target !== field.boundElement) return;\r\n if (!(\"value\" in target)) return;\r\n if (typeof target.value !== \"string\") return;\r\n newValue = target.value as TValue;\r\n } else {\r\n newValue = arg;\r\n }\r\n\r\n field.setValue(newValue, {\r\n shouldTouch: true,\r\n shouldMarkDirty: true,\r\n });\r\n },\r\n onFocus() {\r\n field.touch();\r\n },\r\n onBlur() {\r\n if (\r\n props.form.hookConfigs?.validateMode === \"onBlur\" ||\r\n props.form.hookConfigs?.validateMode === \"onChange\"\r\n ) {\r\n props.form.controller.validateField(props.path);\r\n }\r\n },\r\n };\r\n\r\n useEffect(() => {\r\n const { events } = props.form.controller;\r\n\r\n return composeFns(\r\n events.on(\"valueChanged\", (_path) => {\r\n if (\r\n !FieldPath.equals(_path, props.path) &&\r\n !FieldPath.isDescendant(_path, props.path)\r\n ) {\r\n return;\r\n }\r\n\r\n if (props.form.hookConfigs?.validateMode === \"onChange\") {\r\n props.form.controller.validateField(props.path);\r\n }\r\n }),\r\n );\r\n }, []);\r\n\r\n useEffect(() => {\r\n field.bindElement(elementRef.current!);\r\n\r\n return () => {\r\n if (props.unbindOnUnmount) {\r\n props.form.controller.unbindField(props.path);\r\n }\r\n };\r\n }, []);\r\n\r\n return (\r\n <>\r\n {props.render({\r\n ref: elementRef,\r\n value: field.value,\r\n handlers: handlers,\r\n field: field as any,\r\n form: props.form,\r\n })}\r\n </>\r\n );\r\n}\r\n\r\n/* ---- TESTS ---------------- */\r\n\r\n// function TestComp() {\r\n// const form = useForm<{ a?: { b: 99 } }>({});\r\n\r\n// const jsx = (\r\n// <>\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a.b)}\r\n// defaultValue={() => 99 as const}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n\r\n// {/* defaultField olmayabilir, çünkü \"a\" nullable */}\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a)}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromStringPath(\"a.b\")}\r\n// defaultValue={() => 99 as const}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n// </>\r\n// );\r\n// }\r\n"],"names":["useRenderControl","rerender","useState","renderCount","useRef","renderScheduled","scheduleRerender","startTransition","i","composeFns","fns","fn","useForm","formConfigs","hookConfigs","controller","FormController","paths","FieldPathBuilder","renderControl","useEffect","noop","useFormField","form","path","bindingConfig","field","setField","events","_path","FieldPath","changedPath","useFieldValue","value","fieldPath","useFieldErrors","issues","useFormValuesObserver","options","observedValues","data","groupBy","items","key","result","item","k","useFormErrorObserver","observedIssues","issue","normalizedIssuePath","FieldRenderer","props","elementRef","handlers","arg","newValue","target","jsx","Fragment"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodie-forms/react",
3
- "version": "1.2.1-alpha",
3
+ "version": "1.2.3-alpha",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  "react-dom": "^18 || ^19"
19
19
  },
20
20
  "dependencies": {
21
- "@goodie-forms/core": "1.2.1-alpha"
21
+ "@goodie-forms/core": "1.2.3-alpha"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/react": "^19.2.9",
@@ -1,13 +1,6 @@
1
1
  import { FieldPath, FormField, NonnullFormField } from "@goodie-forms/core";
2
- import {
3
- ChangeEvent,
4
- FocusEvent,
5
- ReactNode,
6
- Ref,
7
- useEffect,
8
- useRef,
9
- } from "react";
10
- import { useForm, UseForm } from "../hooks/useForm";
2
+ import { ChangeEvent, ReactNode, Ref, useEffect, useRef } from "react";
3
+ import { UseForm } from "../hooks/useForm";
11
4
  import { useFormField } from "../hooks/useFormField";
12
5
  import { composeFns } from "../utils/composeFns";
13
6
 
@@ -17,14 +10,16 @@ export interface RenderParams<TOutput extends object, TValue> {
17
10
  value: TValue | undefined;
18
11
 
19
12
  handlers: {
20
- onChange: (event: ChangeEvent<EventTarget>) => void;
21
- onFocus: (event: FocusEvent) => void;
22
- onBlur: (event: FocusEvent) => void;
13
+ onChange: (event: ChangeEvent<EventTarget> | TValue) => void;
14
+ onFocus: () => void;
15
+ onBlur: () => void;
23
16
  };
24
17
 
25
18
  field: undefined extends TValue
26
19
  ? FormField<TOutput, TValue>
27
20
  : NonnullFormField<TOutput, TValue>;
21
+
22
+ form: UseForm<TOutput>;
28
23
  }
29
24
 
30
25
  type DefaultValueProps<TValue> = undefined extends TValue
@@ -61,12 +56,20 @@ export function FieldRenderer<
61
56
  })!;
62
57
 
63
58
  const handlers: RenderParams<TOutput, TValue>["handlers"] = {
64
- onChange(event) {
65
- const { target } = event;
66
- if (target !== field.boundElement) return;
67
- if (!("value" in target)) return;
68
- if (typeof target.value !== "string") return;
69
- field.setValue(target.value as TValue, {
59
+ onChange(arg) {
60
+ let newValue: TValue;
61
+
62
+ if ("target" in arg) {
63
+ const { target } = arg;
64
+ if (target !== field.boundElement) return;
65
+ if (!("value" in target)) return;
66
+ if (typeof target.value !== "string") return;
67
+ newValue = target.value as TValue;
68
+ } else {
69
+ newValue = arg;
70
+ }
71
+
72
+ field.setValue(newValue, {
70
73
  shouldTouch: true,
71
74
  shouldMarkDirty: true,
72
75
  });
@@ -120,6 +123,7 @@ export function FieldRenderer<
120
123
  value: field.value,
121
124
  handlers: handlers,
122
125
  field: field as any,
126
+ form: props.form,
123
127
  })}
124
128
  </>
125
129
  );
@@ -0,0 +1,31 @@
1
+ import { FieldPath } from "@goodie-forms/core";
2
+ import { useEffect } from "react";
3
+ import { UseForm } from "../hooks/useForm";
4
+ import { useRenderControl } from "../hooks/useRenderControl";
5
+ import { composeFns } from "../utils/composeFns";
6
+
7
+ export function useFieldErrors<
8
+ TOutput extends object,
9
+ TPath extends FieldPath.Segments,
10
+ >(form: UseForm<TOutput>, path: TPath) {
11
+ const renderControl = useRenderControl();
12
+
13
+ const issues = form.controller.getField(path)?.issues;
14
+
15
+ useEffect(() => {
16
+ return composeFns(
17
+ form.controller.events.on("fieldBound", (fieldPath) => {
18
+ if (FieldPath.equals(path, fieldPath)) {
19
+ renderControl.forceRerender();
20
+ }
21
+ }),
22
+ form.controller.events.on("fieldIssuesUpdated", (fieldPath) => {
23
+ if (FieldPath.equals(path, fieldPath)) {
24
+ renderControl.forceRerender();
25
+ }
26
+ }),
27
+ );
28
+ }, []);
29
+
30
+ return issues;
31
+ }
@@ -0,0 +1,31 @@
1
+ import { FieldPath } from "@goodie-forms/core";
2
+ import { useEffect } from "react";
3
+ import { UseForm } from "../hooks/useForm";
4
+ import { useRenderControl } from "../hooks/useRenderControl";
5
+ import { composeFns } from "../utils/composeFns";
6
+
7
+ export function useFieldValue<
8
+ TOutput extends object,
9
+ TPath extends FieldPath.Segments,
10
+ >(form: UseForm<TOutput>, path: TPath) {
11
+ const renderControl = useRenderControl();
12
+
13
+ const value = form.controller.getField(path)?.value;
14
+
15
+ useEffect(() => {
16
+ return composeFns(
17
+ form.controller.events.on("fieldBound", (fieldPath) => {
18
+ if (FieldPath.equals(path, fieldPath)) {
19
+ renderControl.forceRerender();
20
+ }
21
+ }),
22
+ form.controller.events.on("valueChanged", (fieldPath) => {
23
+ if (FieldPath.equals(path, fieldPath)) {
24
+ renderControl.forceRerender();
25
+ }
26
+ }),
27
+ );
28
+ }, []);
29
+
30
+ return value;
31
+ }
@@ -5,6 +5,7 @@ import { composeFns } from "../utils/composeFns";
5
5
  import type { UseForm } from "./useForm";
6
6
  import { useRenderControl } from "./useRenderControl";
7
7
 
8
+ /** @deprecated */
8
9
  export function useFormErrorObserver<
9
10
  TOutput extends object,
10
11
  TInclude extends FieldPath.Segments[] | undefined = undefined,
@@ -4,6 +4,7 @@ import { composeFns } from "../utils/composeFns";
4
4
  import type { UseForm } from "./useForm";
5
5
  import { useRenderControl } from "./useRenderControl";
6
6
 
7
+ /** @deprecated */
7
8
  export function useFormValuesObserver<
8
9
  TOutput extends object,
9
10
  TPaths extends FieldPath.Segments[] | undefined = undefined,
package/src/index.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export * from "./hooks/useForm";
2
2
  export * from "./hooks/useFormField";
3
+ export * from "./hooks/useFieldValue";
4
+ export * from "./hooks/useFieldErrors";
3
5
  export * from "./hooks/useFormValuesObserver";
4
6
  export * from "./hooks/useFormErrorObserver";
5
7
  export * from "./hooks/useRenderControl";