@strictly/react-form 0.0.7 → 0.0.8

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.
Files changed (72) hide show
  1. package/.out/core/mobx/hooks.d.ts +5 -1
  2. package/.out/core/mobx/hooks.js +13 -3
  3. package/.out/core/mobx/specs/sub_form_field_adapters.tests.js +56 -9
  4. package/.out/core/mobx/sub_form_field_adapters.d.ts +5 -5
  5. package/.out/core/mobx/sub_form_field_adapters.js +13 -10
  6. package/.out/field_converters/nullable_to_boolean_converter.d.ts +2 -2
  7. package/.out/mantine/create_checkbox.js +1 -0
  8. package/.out/mantine/create_fields_view.d.ts +1 -1
  9. package/.out/mantine/create_fields_view.js +4 -4
  10. package/.out/mantine/create_form.d.ts +1 -1
  11. package/.out/mantine/create_list.d.ts +1 -1
  12. package/.out/mantine/create_pill.d.ts +1 -1
  13. package/.out/mantine/create_radio.d.ts +1 -1
  14. package/.out/mantine/create_radio_group.js +1 -0
  15. package/.out/mantine/create_text_input.js +7 -2
  16. package/.out/mantine/create_value_input.js +1 -0
  17. package/.out/mantine/error_renderer.d.ts +1 -1
  18. package/.out/mantine/error_renderer.js +1 -1
  19. package/.out/mantine/hooks.d.ts +9 -9
  20. package/.out/mantine/specs/checkbox_hooks.stories.d.ts +2 -6
  21. package/.out/mantine/specs/checkbox_hooks.stories.js +4 -16
  22. package/.out/mantine/specs/fields_view_hooks.stories.d.ts +1 -1
  23. package/.out/mantine/specs/fields_view_hooks.stories.js +6 -3
  24. package/.out/mantine/specs/form_hooks.stories.d.ts +2 -2
  25. package/.out/mantine/specs/form_hooks.stories.js +4 -1
  26. package/.out/mantine/specs/radio_group_hooks.stories.d.ts +2 -6
  27. package/.out/mantine/specs/radio_group_hooks.stories.js +5 -17
  28. package/.out/mantine/specs/select_hooks.stories.d.ts +2 -6
  29. package/.out/mantine/specs/select_hooks.stories.js +4 -16
  30. package/.out/mantine/specs/text_input_hooks.stories.d.ts +2 -5
  31. package/.out/mantine/specs/text_input_hooks.stories.js +5 -5
  32. package/.out/mantine/specs/value_input_hooks.stories.d.ts +2 -5
  33. package/.out/mantine/specs/value_input_hooks.stories.js +5 -5
  34. package/.out/mantine/types.d.ts +4 -2
  35. package/.out/tsconfig.tsbuildinfo +1 -1
  36. package/.turbo/turbo-build.log +8 -8
  37. package/.turbo/turbo-check-types.log +1 -1
  38. package/.turbo/turbo-release$colon$exports.log +1 -1
  39. package/core/mobx/hooks.ts +24 -6
  40. package/core/mobx/specs/sub_form_field_adapters.tests.ts +108 -15
  41. package/core/mobx/sub_form_field_adapters.ts +41 -25
  42. package/dist/index.cjs +52 -27
  43. package/dist/index.d.cts +25 -19
  44. package/dist/index.d.ts +25 -19
  45. package/dist/index.js +52 -27
  46. package/field_converters/nullable_to_boolean_converter.ts +2 -3
  47. package/mantine/create_checkbox.tsx +2 -1
  48. package/mantine/create_fields_view.tsx +17 -14
  49. package/mantine/create_form.tsx +2 -2
  50. package/mantine/create_list.tsx +1 -1
  51. package/mantine/create_pill.tsx +1 -1
  52. package/mantine/create_radio.tsx +1 -1
  53. package/mantine/create_radio_group.tsx +6 -2
  54. package/mantine/create_text_input.tsx +9 -3
  55. package/mantine/create_value_input.tsx +2 -1
  56. package/mantine/error_renderer.ts +1 -1
  57. package/mantine/hooks.tsx +19 -14
  58. package/mantine/specs/__snapshots__/checkbox_hooks.tests.tsx.snap +1 -64
  59. package/mantine/specs/__snapshots__/fields_view_hooks.tests.tsx.snap +52 -52
  60. package/mantine/specs/__snapshots__/radio_group_hooks.tests.tsx.snap +1 -179
  61. package/mantine/specs/__snapshots__/select_hooks.tests.tsx.snap +1 -83
  62. package/mantine/specs/__snapshots__/text_input_hooks.tests.tsx.snap +27 -27
  63. package/mantine/specs/__snapshots__/value_input_hooks.tests.tsx.snap +31 -31
  64. package/mantine/specs/checkbox_hooks.stories.tsx +5 -21
  65. package/mantine/specs/fields_view_hooks.stories.tsx +16 -4
  66. package/mantine/specs/form_hooks.stories.tsx +10 -3
  67. package/mantine/specs/radio_group_hooks.stories.tsx +6 -20
  68. package/mantine/specs/select_hooks.stories.tsx +5 -21
  69. package/mantine/specs/text_input_hooks.stories.tsx +5 -8
  70. package/mantine/specs/value_input_hooks.stories.tsx +5 -8
  71. package/mantine/types.ts +7 -3
  72. package/package.json +2 -1
@@ -7,12 +7,12 @@ $ tsup
7
7
  CLI Target: esnext
8
8
  CJS Build start
9
9
  ESM Build start
10
- CJS dist/index.cjs 50.08 KB
11
- CJS ⚡️ Build success in 121ms
12
- ESM dist/index.js 46.21 KB
13
- ESM ⚡️ Build success in 122ms
10
+ CJS dist/index.cjs 50.73 KB
11
+ CJS ⚡️ Build success in 112ms
12
+ ESM dist/index.js 46.84 KB
13
+ ESM ⚡️ Build success in 113ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 9863ms
16
- DTS dist/index.d.cts 36.28 KB
17
- DTS dist/index.d.ts 36.28 KB
18
- Done in 10.98s.
15
+ DTS ⚡️ Build success in 9662ms
16
+ DTS dist/index.d.cts 36.94 KB
17
+ DTS dist/index.d.ts 36.94 KB
18
+ Done in 10.73s.
@@ -1,3 +1,3 @@
1
1
  yarn run v1.22.22
2
2
  $ tsc
3
- Done in 7.67s.
3
+ Done in 7.38s.
@@ -1,3 +1,3 @@
1
1
  yarn run v1.22.22
2
2
  $ json -f package.json -f package.exports.json --merge > package.release.json
3
- Done in 0.12s.
3
+ Done in 0.13s.
@@ -25,12 +25,16 @@ type ModelOfPresenter<P extends FormPresenter<any, any, any, any>> = ReturnType<
25
25
  export function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(
26
26
  presenter: P,
27
27
  value: ValueOfPresenter<P>,
28
- onValidSubmit?: <Path extends ValuePathsOfPresenter<P>>(
29
- model: ModelOfPresenter<P>,
30
- valuePath: Path,
31
- ) => void,
28
+ {
29
+ onValidFieldSubmit,
30
+ onValidFormSubmit,
31
+ }: {
32
+ onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void,
33
+ onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void,
34
+ },
32
35
  ): {
33
36
  model: ModelOfPresenter<P>,
37
+ onFormSubmit?: (value: ValueOfPresenter<P>) => void,
34
38
  } & Omit<FieldsViewProps<ModelOfPresenter<P>['fields']>, 'fields'> {
35
39
  const model = useMemo(function () {
36
40
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
@@ -57,14 +61,14 @@ export function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, a
57
61
  const onFieldSubmit = useCallback(
58
62
  function<Path extends ValuePathsOfPresenter<P>> (valuePath: Path) {
59
63
  if (presenter.validateField(model, valuePath)) {
60
- onValidSubmit?.(model, valuePath)
64
+ onValidFieldSubmit?.(model, valuePath)
61
65
  }
62
66
  return false
63
67
  },
64
68
  [
65
69
  presenter,
66
70
  model,
67
- onValidSubmit,
71
+ onValidFieldSubmit,
68
72
  ],
69
73
  )
70
74
 
@@ -85,10 +89,24 @@ export function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, a
85
89
  ],
86
90
  )
87
91
 
92
+ const onFormSubmit = useCallback(
93
+ function () {
94
+ if (presenter.validateAll(model)) {
95
+ onValidFormSubmit?.(model, model.value)
96
+ }
97
+ },
98
+ [
99
+ presenter,
100
+ model,
101
+ onValidFormSubmit,
102
+ ],
103
+ )
104
+
88
105
  return {
89
106
  model,
90
107
  onFieldValueChange,
91
108
  onFieldSubmit,
92
109
  onFieldBlur,
110
+ onFormSubmit,
93
111
  }
94
112
  }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ list,
2
3
  numberType,
3
4
  object,
4
5
  stringType,
@@ -8,16 +9,18 @@ import {
8
9
  subFormFieldAdapters,
9
10
  } from 'core/mobx/sub_form_field_adapters'
10
11
  import { UnreliableFieldConversionType } from 'types/field_converters'
11
- import { mockDeep } from 'vitest-mock-extended'
12
+ import {
13
+ mockDeep,
14
+ mockReset,
15
+ } from 'vitest-mock-extended'
12
16
 
13
17
  describe('subFormFieldAdapters', () => {
14
- const mockedFieldAdapter1 = mockDeep<Required<FieldAdapter<string, boolean>>>()
15
- const fieldAdapter1: FieldAdapter<string, boolean> = mockedFieldAdapter1
16
- const mockedFieldAdapter2 = mockDeep<FieldAdapter<number, boolean>>()
17
- const fieldAdapter2: FieldAdapter<number, boolean> = mockedFieldAdapter2
18
-
19
18
  describe('empty value', () => {
20
- const adapters = subFormFieldAdapters({}, '$.a', stringType)
19
+ const adapters = subFormFieldAdapters(
20
+ {},
21
+ '$.a',
22
+ stringType,
23
+ )
21
24
 
22
25
  it('equals expected type', () => {
23
26
  expectTypeOf(adapters).toEqualTypeOf<{}>()
@@ -29,15 +32,35 @@ describe('subFormFieldAdapters', () => {
29
32
  })
30
33
 
31
34
  describe('single adapter', () => {
35
+ const mockedFieldAdapter1 = mockDeep<Required<FieldAdapter<string, boolean, number, '$', string>>>()
36
+ const fieldAdapter1: FieldAdapter<string, boolean, number, '$', string> = mockedFieldAdapter1
37
+
32
38
  const type = object().field('a', stringType)
33
- const adapters = subFormFieldAdapters({
39
+ const subAdapters = {
34
40
  $: fieldAdapter1,
35
- }, '$.a', type)
41
+ } as const
42
+ const adapters = subFormFieldAdapters<
43
+ typeof subAdapters,
44
+ '$.a',
45
+ { '$.a': '$.a' },
46
+ typeof type
47
+ >(
48
+ subAdapters,
49
+ '$.a',
50
+ type,
51
+ )
52
+
53
+ beforeEach(() => {
54
+ mockReset(mockedFieldAdapter1)
55
+ })
36
56
 
37
57
  it('equals expected type', () => {
38
- // TODO toEqualTypeOf (seems to be a TS error)
58
+ // TODO toEqualTypeOf (cannot reason about revert optionality, seems to be a TS issue as they
59
+ // are both optional AFAICT)
39
60
  expectTypeOf(adapters).toMatchTypeOf<{
40
- '$.a': FieldAdapter<string, boolean>,
61
+ '$.a': FieldAdapter<string, boolean, number, '$.a', {
62
+ a: string,
63
+ }>,
41
64
  }>()
42
65
  })
43
66
 
@@ -81,12 +104,26 @@ describe('subFormFieldAdapters', () => {
81
104
  })
82
105
 
83
106
  describe('multiple adapters', () => {
107
+ const mockedFieldAdapter1 = mockDeep<Required<FieldAdapter<string, boolean>>>()
108
+ const fieldAdapter1: FieldAdapter<string, boolean, number> = mockedFieldAdapter1
109
+ const mockedFieldAdapter2 = mockDeep<FieldAdapter<number, boolean>>()
110
+ const fieldAdapter2: FieldAdapter<number, boolean> = mockedFieldAdapter2
111
+
84
112
  const type = object()
85
113
  .field('a', object().field('x', stringType).field('y', numberType))
86
- const adapters = subFormFieldAdapters({
87
- '$.x': fieldAdapter1,
88
- '$.y': fieldAdapter2,
89
- }, '$.a', type)
114
+ const adapters = subFormFieldAdapters(
115
+ {
116
+ '$.x': fieldAdapter1,
117
+ '$.y': fieldAdapter2,
118
+ },
119
+ '$.a',
120
+ type,
121
+ )
122
+
123
+ beforeEach(() => {
124
+ mockReset(mockedFieldAdapter1)
125
+ mockReset(mockedFieldAdapter2)
126
+ })
90
127
 
91
128
  it('equals expected type', () => {
92
129
  // TODO toEqualTypeOf (seems to be a TS error)
@@ -139,4 +176,60 @@ describe('subFormFieldAdapters', () => {
139
176
  })
140
177
  })
141
178
  })
179
+
180
+ describe('list adapter', () => {
181
+ const mockedFieldAdapter1 = mockDeep<Required<FieldAdapter<string, boolean, number, '$', string>>>()
182
+ const fieldAdapter1: FieldAdapter<string, boolean, number, '$', string> = mockedFieldAdapter1
183
+ const type = list(stringType)
184
+ const subAdapters = {
185
+ $: fieldAdapter1,
186
+ }
187
+ const adapters = subFormFieldAdapters<
188
+ typeof subAdapters,
189
+ '$.*',
190
+ {
191
+ '$.*': `$.${number}`,
192
+ },
193
+ typeof type
194
+ >(
195
+ subAdapters,
196
+ '$.*',
197
+ type,
198
+ )
199
+
200
+ beforeEach(() => {
201
+ mockReset(mockedFieldAdapter1)
202
+ })
203
+
204
+ it('equals expected type', () => {
205
+ // TODO toEqualTypeOf (seems to be a TS error)
206
+ expectTypeOf(adapters).toMatchTypeOf<{
207
+ '$.*': FieldAdapter<string, boolean, number, `$.${number}`, string[]>,
208
+ }>()
209
+ })
210
+
211
+ it('equals expected value', () => {
212
+ expect(adapters).toEqual({
213
+ '$.*': expect.anything(),
214
+ })
215
+ })
216
+
217
+ describe('calls convert with correct paths and values', () => {
218
+ const subContext = 'a'
219
+ const context = [subContext]
220
+
221
+ it('calls $.*', () => {
222
+ const mockedReturnedValue = {
223
+ value: false,
224
+ readonly: false,
225
+ required: false,
226
+ }
227
+ mockedFieldAdapter1.convert.mockReturnValue(mockedReturnedValue)
228
+
229
+ const returnedValue = adapters['$.*'].convert('b', '$.0', context)
230
+ expect(fieldAdapter1.convert).toHaveBeenCalledWith('b', '$', subContext)
231
+ expect(returnedValue).toEqual(mockedReturnedValue)
232
+ })
233
+ })
234
+ })
142
235
  })
@@ -9,35 +9,51 @@ import {
9
9
  type FieldAdapter,
10
10
  type FromOfFieldAdapter,
11
11
  type ToOfFieldAdapter,
12
+ type ValuePathOfFieldAdapter,
12
13
  } from './field_adapter'
13
14
 
14
- type SubFormFieldAdapter<F extends FieldAdapter, P extends string, Context> = FieldAdapter<
15
+ type SubFormFieldAdapter<F extends FieldAdapter, ValuePath extends string, Context> = FieldAdapter<
15
16
  FromOfFieldAdapter<F>,
16
17
  ToOfFieldAdapter<F>,
17
18
  ErrorOfFieldAdapter<F>,
18
- P,
19
+ ValuePathOfFieldAdapter<F> extends StringConcatOf<'$', infer ValuePathSuffix> ? `${ValuePath}${ValuePathSuffix}`
20
+ // assume string (they don't care about the value path as a type) if there the path doesn't have a $ prefix
21
+ : string,
19
22
  Context
20
23
  >
21
24
 
22
- type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string, Context> = {
23
- [K in keyof SubAdapters as K extends StringConcatOf<'$', infer S> ? `${P}${S}` : never]: K extends
24
- StringConcatOf<'$', infer S> ? SubFormFieldAdapter<
25
- SubAdapters[K],
26
- `${P}${S}`,
27
- Context
28
- >
29
- : never
25
+ type SubFormFieldAdapters<
26
+ SubAdapters extends Record<string, FieldAdapter>,
27
+ TypePath extends string,
28
+ ValuePath extends string,
29
+ Context,
30
+ > = {
31
+ [
32
+ K in keyof SubAdapters as K extends StringConcatOf<'$', infer TypePathSuffix> ? `${TypePath}${TypePathSuffix}`
33
+ : never
34
+ ]: SubFormFieldAdapter<
35
+ SubAdapters[K],
36
+ ValuePath,
37
+ Context
38
+ >
30
39
  }
31
40
 
32
- export function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string,
33
- ContextType extends Type>(
41
+ export function subFormFieldAdapters<
42
+ SubAdapters extends Record<string, FieldAdapter>,
43
+ TypePath extends string,
44
+ TypePathsToValuePaths extends Record<TypePath, string>,
45
+ ContextType extends Type,
46
+ >(
34
47
  subAdapters: SubAdapters,
35
- prefix: P,
48
+ parentTypePath: TypePath,
36
49
  contextType: ContextType,
37
- ): SubFormFieldAdapters<SubAdapters, P, ValueOfType<ContextType>> {
50
+ ): SubFormFieldAdapters<SubAdapters, TypePath, TypePathsToValuePaths[TypePath], ValueOfType<ContextType>> {
51
+ // assume the number of '.' in the type path will correspond to the number of '.' in the value path
52
+ const dotCount = parentTypePath.split('.').length
38
53
  function getSubValuePathAndContext(valuePath: string, context: ValueOfType<ContextType>) {
39
- const subValuePath = valuePath.replace(prefix, '$')
40
- const subContext = flattenValuesOfType(contextType, context)[prefix]
54
+ const parentValuePath = valuePath.split('.').slice(0, dotCount).join('.')
55
+ const subValuePath = valuePath.replace(parentValuePath, '$')
56
+ const subContext = flattenValuesOfType(contextType, context)[parentValuePath]
41
57
  return [
42
58
  subValuePath,
43
59
  subContext,
@@ -46,23 +62,23 @@ export function subFormFieldAdapters<SubAdapters extends Record<string, FieldAda
46
62
 
47
63
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
48
64
  return Object.entries(subAdapters).reduce<Record<string, FieldAdapter>>((acc, [
49
- subKey,
50
- subValue,
65
+ subTypePath,
66
+ subAdapter,
51
67
  ]) => {
52
- const key = subKey.replace('$', prefix)
68
+ const typePath = subTypePath.replace('$', parentTypePath)
53
69
  // adapt field adapter with new path and context
54
70
  const adaptedAdapter: FieldAdapter = {
55
71
  convert: (from, valuePath, context) => {
56
- return subValue.convert(from, ...getSubValuePathAndContext(valuePath, context))
72
+ return subAdapter.convert(from, ...getSubValuePathAndContext(valuePath, context))
57
73
  },
58
74
  create: (valuePath, context) => {
59
- return subValue.create(...getSubValuePathAndContext(valuePath, context))
75
+ return subAdapter.create(...getSubValuePathAndContext(valuePath, context))
60
76
  },
61
- revert: subValue.revert && ((from, valuePath, context) => {
62
- return subValue.revert!(from, ...getSubValuePathAndContext(valuePath, context))
77
+ revert: subAdapter.revert && ((from, valuePath, context) => {
78
+ return subAdapter.revert!(from, ...getSubValuePathAndContext(valuePath, context))
63
79
  }),
64
80
  }
65
- acc[key] = adaptedAdapter
81
+ acc[typePath] = adaptedAdapter
66
82
  return acc
67
- }, {}) as SubFormFieldAdapters<SubAdapters, P, ValueOfType<ContextType>>
83
+ }, {}) as SubFormFieldAdapters<SubAdapters, TypePath, TypePathsToValuePaths[TypePath], ValueOfType<ContextType>>
68
84
  }
package/dist/index.cjs CHANGED
@@ -690,7 +690,10 @@ var FormModel = class {
690
690
 
691
691
  // core/mobx/hooks.ts
692
692
  var import_react = require("react");
693
- function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
693
+ function useDefaultMobxFormHooks(presenter, value, {
694
+ onValidFieldSubmit,
695
+ onValidFormSubmit
696
+ }) {
694
697
  const model = (0, import_react.useMemo)(function() {
695
698
  return presenter.createModel(value);
696
699
  }, [
@@ -710,14 +713,14 @@ function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
710
713
  const onFieldSubmit = (0, import_react.useCallback)(
711
714
  function(valuePath) {
712
715
  if (presenter.validateField(model, valuePath)) {
713
- onValidSubmit?.(model, valuePath);
716
+ onValidFieldSubmit?.(model, valuePath);
714
717
  }
715
718
  return false;
716
719
  },
717
720
  [
718
721
  presenter,
719
722
  model,
720
- onValidSubmit
723
+ onValidFieldSubmit
721
724
  ]
722
725
  );
723
726
  const onFieldBlur = (0, import_react.useCallback)(
@@ -733,11 +736,24 @@ function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
733
736
  model
734
737
  ]
735
738
  );
739
+ const onFormSubmit = (0, import_react.useCallback)(
740
+ function() {
741
+ if (presenter.validateAll(model)) {
742
+ onValidFormSubmit?.(model, model.value);
743
+ }
744
+ },
745
+ [
746
+ presenter,
747
+ model,
748
+ onValidFormSubmit
749
+ ]
750
+ );
736
751
  return {
737
752
  model,
738
753
  onFieldValueChange,
739
754
  onFieldSubmit,
740
- onFieldBlur
755
+ onFieldBlur,
756
+ onFormSubmit
741
757
  };
742
758
  }
743
759
 
@@ -818,32 +834,34 @@ function mergeAdaptersWithValidators(adapters, validators) {
818
834
 
819
835
  // core/mobx/sub_form_field_adapters.ts
820
836
  var import_define3 = require("@strictly/define");
821
- function subFormFieldAdapters(subAdapters, prefix, contextType) {
837
+ function subFormFieldAdapters(subAdapters, parentTypePath, contextType) {
838
+ const dotCount = parentTypePath.split(".").length;
822
839
  function getSubValuePathAndContext(valuePath, context) {
823
- const subValuePath = valuePath.replace(prefix, "$");
824
- const subContext = (0, import_define3.flattenValuesOfType)(contextType, context)[prefix];
840
+ const parentValuePath = valuePath.split(".").slice(0, dotCount).join(".");
841
+ const subValuePath = valuePath.replace(parentValuePath, "$");
842
+ const subContext = (0, import_define3.flattenValuesOfType)(contextType, context)[parentValuePath];
825
843
  return [
826
844
  subValuePath,
827
845
  subContext
828
846
  ];
829
847
  }
830
848
  return Object.entries(subAdapters).reduce((acc, [
831
- subKey,
832
- subValue
849
+ subTypePath,
850
+ subAdapter
833
851
  ]) => {
834
- const key = subKey.replace("$", prefix);
852
+ const typePath = subTypePath.replace("$", parentTypePath);
835
853
  const adaptedAdapter = {
836
854
  convert: (from, valuePath, context) => {
837
- return subValue.convert(from, ...getSubValuePathAndContext(valuePath, context));
855
+ return subAdapter.convert(from, ...getSubValuePathAndContext(valuePath, context));
838
856
  },
839
857
  create: (valuePath, context) => {
840
- return subValue.create(...getSubValuePathAndContext(valuePath, context));
858
+ return subAdapter.create(...getSubValuePathAndContext(valuePath, context));
841
859
  },
842
- revert: subValue.revert && ((from, valuePath, context) => {
843
- return subValue.revert(from, ...getSubValuePathAndContext(valuePath, context));
860
+ revert: subAdapter.revert && ((from, valuePath, context) => {
861
+ return subAdapter.revert(from, ...getSubValuePathAndContext(valuePath, context));
844
862
  })
845
863
  };
846
- acc[key] = adaptedAdapter;
864
+ acc[typePath] = adaptedAdapter;
847
865
  return acc;
848
866
  }, {});
849
867
  }
@@ -1057,7 +1075,7 @@ function DefaultErrorRenderer({
1057
1075
  error
1058
1076
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1059
1077
  }) {
1060
- return error;
1078
+ return JSON.stringify(error);
1061
1079
  }
1062
1080
 
1063
1081
  // mantine/hooks.tsx
@@ -1288,15 +1306,19 @@ function createFieldsView(valuePath, FieldsView, observableProps) {
1288
1306
  observableProps.onFieldSubmit?.(toKey(subKey));
1289
1307
  }
1290
1308
  return (0, import_mobx_react2.observer)(function(props) {
1291
- const subFields = Object.entries(observableProps.fields).reduce((acc, [
1292
- fieldKey,
1293
- fieldValue
1294
- ]) => {
1295
- if (fieldKey.startsWith(valuePath)) {
1296
- acc[toSubKey(fieldKey)] = fieldValue;
1297
- }
1298
- return acc;
1299
- }, {});
1309
+ const subFields = Object.entries(observableProps.fields).reduce(
1310
+ (acc, [
1311
+ fieldKey,
1312
+ fieldValue
1313
+ ]) => {
1314
+ if (fieldKey.startsWith(valuePath)) {
1315
+ acc[toSubKey(fieldKey)] = fieldValue;
1316
+ }
1317
+ return acc;
1318
+ },
1319
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1320
+ {}
1321
+ );
1300
1322
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1301
1323
  FieldsView,
1302
1324
  {
@@ -1452,13 +1474,16 @@ function createTextInput(valuePath, TextInput) {
1452
1474
  const propSource = ({
1453
1475
  ErrorRenderer = DefaultErrorRenderer
1454
1476
  }) => {
1477
+ const field = this.fields[valuePath];
1478
+ if (field == null) {
1479
+ throw new Error(`invalid field ${valuePath}`);
1480
+ }
1455
1481
  const {
1456
1482
  readonly,
1457
1483
  required,
1458
1484
  value,
1459
1485
  error
1460
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1461
- } = this.fields[valuePath];
1486
+ } = field;
1462
1487
  return {
1463
1488
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1464
1489
  name: valuePath,
package/dist/index.d.cts CHANGED
@@ -181,8 +181,12 @@ type FormFieldsOfPresenter<Presenter extends FormPresenter<any, any, any, any>>
181
181
 
182
182
  type ValueOfPresenter<P extends FormPresenter<any, any, any, any>> = P extends FormPresenter<infer T, any, any, any> ? ValueOfType<ReadonlyTypeOfType<T>> : never;
183
183
  type ModelOfPresenter<P extends FormPresenter<any, any, any, any>> = ReturnType<P['createModel']>;
184
- declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(presenter: P, value: ValueOfPresenter<P>, onValidSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void): {
184
+ declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(presenter: P, value: ValueOfPresenter<P>, { onValidFieldSubmit, onValidFormSubmit, }: {
185
+ onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void;
186
+ onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void;
187
+ }): {
185
188
  model: ModelOfPresenter<P>;
189
+ onFormSubmit?: (value: ValueOfPresenter<P>) => void;
186
190
  } & Omit<FieldsViewProps<ModelOfPresenter<P>['fields']>, 'fields'>;
187
191
 
188
192
  type MergedOfFieldAdaptersWithTwoWayConverter<FieldAdapters extends Readonly<Record<string, FieldAdapter>>, E, Context> = {
@@ -204,11 +208,11 @@ type MergedOfFieldAdaptersWithValidators<FieldAdapters extends Readonly<Record<K
204
208
  type MergedOfFieldAdapterWithValidator<A extends FieldAdapter, V extends Validator | undefined> = undefined extends V ? A : A extends FieldAdapter<infer From, infer To, infer E1, infer P1, infer C1> ? V extends Validator<From, infer E2, infer P2, infer C2> ? FieldAdapter<From, To, E1 | E2, P1 | P2, C1 | C2> : never : never;
205
209
  declare function mergeAdaptersWithValidators<FieldAdapters extends Readonly<Record<Key, FieldAdapter>>, Validators extends Readonly<Record<string, Validator>>, Key extends keyof Validators = keyof Validators>(adapters: FieldAdapters, validators: Validators): MergedOfFieldAdaptersWithValidators<FieldAdapters, Validators, Key>;
206
210
 
207
- type SubFormFieldAdapter<F extends FieldAdapter, P extends string, Context> = FieldAdapter<FromOfFieldAdapter<F>, ToOfFieldAdapter<F>, ErrorOfFieldAdapter<F>, P, Context>;
208
- type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string, Context> = {
209
- [K in keyof SubAdapters as K extends StringConcatOf<'$', infer S> ? `${P}${S}` : never]: K extends StringConcatOf<'$', infer S> ? SubFormFieldAdapter<SubAdapters[K], `${P}${S}`, Context> : never;
211
+ type SubFormFieldAdapter<F extends FieldAdapter, ValuePath extends string, Context> = FieldAdapter<FromOfFieldAdapter<F>, ToOfFieldAdapter<F>, ErrorOfFieldAdapter<F>, ValuePathOfFieldAdapter<F> extends StringConcatOf<'$', infer ValuePathSuffix> ? `${ValuePath}${ValuePathSuffix}` : string, Context>;
212
+ type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, TypePath extends string, ValuePath extends string, Context> = {
213
+ [K in keyof SubAdapters as K extends StringConcatOf<'$', infer TypePathSuffix> ? `${TypePath}${TypePathSuffix}` : never]: SubFormFieldAdapter<SubAdapters[K], ValuePath, Context>;
210
214
  };
211
- declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string, ContextType extends Type>(subAdapters: SubAdapters, prefix: P, contextType: ContextType): SubFormFieldAdapters<SubAdapters, P, ValueOfType<ContextType>>;
215
+ declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, TypePath extends string, TypePathsToValuePaths extends Record<TypePath, string>, ContextType extends Type>(subAdapters: SubAdapters, parentTypePath: TypePath, contextType: ContextType): SubFormFieldAdapters<SubAdapters, TypePath, TypePathsToValuePaths[TypePath], ValueOfType<ContextType>>;
212
216
 
213
217
  declare class IntegerToStringConverter<E, ValuePath extends string, Context> implements TwoWayFieldConverter<number, string, E, ValuePath, Context> {
214
218
  private readonly isNanError;
@@ -218,14 +222,14 @@ declare class IntegerToStringConverter<E, ValuePath extends string, Context> imp
218
222
  revert(from: string): UnreliableFieldConversion<number, E>;
219
223
  }
220
224
 
221
- declare class NullableToBooleanConverter<T extends Type, E, ValuePath extends string, Context, NullType extends null | undefined> implements TwoWayFieldConverterWithValueFactory<ValueOfType<ReadonlyTypeOfType<T>> | NullType, boolean, E, ValuePath, Context> {
225
+ declare class NullableToBooleanConverter<T extends Type, ValuePath extends string, Context, NullType extends null | undefined> implements TwoWayFieldConverterWithValueFactory<ValueOfType<ReadonlyTypeOfType<T>> | NullType, boolean, never, ValuePath, Context> {
222
226
  private readonly typeDef;
223
227
  private readonly prototype;
224
228
  private readonly nullType;
225
229
  readonly defaultValue: ValueOfType<ReadonlyTypeOfType<T>> | NullType;
226
230
  constructor(typeDef: T, prototype: ValueOfType<ReadonlyTypeOfType<T>>, nullType: NullType, defaultToNull?: boolean);
227
231
  convert(from: ValueOfType<ReadonlyTypeOfType<T>> | NullType): AnnotatedFieldConversion<boolean>;
228
- revert(from: boolean): UnreliableFieldConversion<ValueOfType<ReadonlyTypeOfType<T>> | NullType, E>;
232
+ revert(from: boolean): UnreliableFieldConversion<ValueOfType<ReadonlyTypeOfType<T>> | NullType, never>;
229
233
  create(): ValueOfType<ReadonlyTypeOfType<T>> | NullType;
230
234
  }
231
235
 
@@ -269,7 +273,7 @@ type ErrorRendererProps<E> = {
269
273
  error: E;
270
274
  };
271
275
  type ErrorRenderer<E = any> = ComponentType<ErrorRendererProps<E>>;
272
- declare function DefaultErrorRenderer({ error, }: ErrorRendererProps<any>): any;
276
+ declare function DefaultErrorRenderer({ error, }: ErrorRendererProps<any>): string;
273
277
 
274
278
  type ValueTypeOfField<F extends Field> = F extends Field<infer V> ? V : never;
275
279
 
@@ -319,8 +323,10 @@ type MantineForm<F extends Fields> = {
319
323
  onFieldBlur: ((this: void, key: keyof F) => void) | undefined;
320
324
  onFieldSubmit: ((this: void, key: keyof F) => boolean | void) | undefined;
321
325
  };
322
- type MantineFieldComponent<T, P = T, E = any> = UnsafePartialComponent<ComponentType<P>, T, {
323
- ErrorRenderer?: ErrorRenderer<E>;
326
+ type MantineFieldComponent<T, P = T, E = any> = UnsafePartialComponent<ComponentType<P>, T, [
327
+ E
328
+ ] extends [never] ? {} : {
329
+ ErrorRenderer: ErrorRenderer<E>;
324
330
  }>;
325
331
 
326
332
  type SuppliedCheckboxProps = Pick<CheckboxProps, 'name' | 'checked' | 'disabled' | 'required' | 'error' | 'onChange' | 'onFocus' | 'onBlur' | 'onKeyUp'>;
@@ -384,21 +390,21 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
384
390
  onFieldBlur: ((this: void, key: keyof F) => void) | undefined;
385
391
  onFieldSubmit: ((this: void, key: keyof F) => boolean | void) | undefined;
386
392
  constructor(fields: F);
387
- textInput<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, TextInputProps>;
388
- textInput<K extends keyof StringFieldsOfFields<F>, P extends SuppliedTextInputProps<any>>(valuePath: K, TextInput?: ComponentType<P>): MantineFieldComponent<SuppliedTextInputProps, P>;
393
+ textInput<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, TextInputProps, ErrorOfField<F[K]>>;
394
+ textInput<K extends keyof StringFieldsOfFields<F>, P extends SuppliedTextInputProps<any>>(valuePath: K, TextInput?: ComponentType<P>): MantineFieldComponent<SuppliedTextInputProps, P, ErrorOfField<F[K]>>;
389
395
  valueInput<K extends keyof AllFieldsOfFields<F>, P extends SuppliedValueInputProps<ValueTypeOfField<F[K]>, any>>(valuePath: K, ValueInput: ComponentType<P>): MantineFieldComponent<SuppliedValueInputProps<ValueTypeOfField<F[K]>>, P, ErrorOfField<F[K]>>;
390
396
  select<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, ComponentProps<typeof SimpleSelect>, ErrorOfField<F[K]>>;
391
- checkbox<K extends keyof BooleanFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedCheckboxProps, CheckboxProps>;
397
+ checkbox<K extends keyof BooleanFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedCheckboxProps, CheckboxProps, ErrorOfField<F[K]>>;
392
398
  checkbox<K extends keyof BooleanFieldsOfFields<F>, P extends SuppliedCheckboxProps>(valuePath: K, Checkbox: ComponentType<P>): MantineFieldComponent<SuppliedCheckboxProps, P, ErrorOfField<F[K]>>;
393
- radioGroup<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedRadioGroupProps, RadioGroupProps>;
394
- radioGroup<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioGroupProps>(valuePath: K, RadioGroup: ComponentType<P>): MantineFieldComponent<SuppliedRadioGroupProps, P>;
399
+ radioGroup<K extends keyof StringFieldsOfFields<F>, P extends RadioGroupProps = RadioGroupProps>(valuePath: K): MantineFieldComponent<SuppliedRadioGroupProps, P, ErrorOfField<F[K]>>;
400
+ radioGroup<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioGroupProps>(valuePath: K, RadioGroup: ComponentType<P>): MantineFieldComponent<SuppliedRadioGroupProps, P, ErrorOfField<F[K]>>;
395
401
  radio<K extends keyof StringFieldsOfFields<F>>(valuePath: K, value: ValueTypeOfField<F[K]>): MantineFieldComponent<SuppliedRadioProps, RadioProps, ErrorOfField<F[K]>>;
396
402
  radio<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioProps>(valuePath: K, value: ValueTypeOfField<F[K]>, Radio: ComponentType<P>): MantineFieldComponent<SuppliedRadioProps, P, ErrorOfField<F[K]>>;
397
403
  pill<K extends keyof AllFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedPillProps, PillProps, ErrorOfField<F[K]>>;
398
- pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P>;
399
- list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K>>>;
400
- fieldsView<K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>): MantineFieldComponent<FieldsViewProps<P['fields']>, P>;
401
- form<K extends keyof AllFieldsOfFields<F>, P extends FormProps<ValueTypeOfField<F[K]>> = FormProps<ValueTypeOfField<F[K]>>>(valuePath: K, Form: ComponentType<P>): MantineFieldComponent<FormProps<ValueTypeOfField<F[K]>>, P>;
404
+ pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P, ErrorOfField<F[K]>>;
405
+ list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K>>, never>;
406
+ fieldsView<K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>): MantineFieldComponent<FieldsViewProps<P['fields']>, P, never>;
407
+ form<K extends keyof AllFieldsOfFields<F>, P extends FormProps<ValueTypeOfField<F[K]>> = FormProps<ValueTypeOfField<F[K]>>>(valuePath: K, Form: ComponentType<P>): MantineFieldComponent<FormProps<ValueTypeOfField<F[K]>>, P, never>;
402
408
  }
403
409
 
404
410
  type MergedOfValidators<Validators1 extends Partial<Readonly<Record<Keys, Validator>>>, Validators2 extends Partial<Readonly<Record<Keys, Validator>>>, Keys extends string = Extract<keyof Validators1 | keyof Validators2, string>> = Simplify<{