@strictly/react-form 0.0.6 → 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 (77) 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/form_presenter.tests.js +3 -6
  4. package/.out/core/mobx/specs/{merge_field_adapters_with_two_way_converter.js → merge_field_adapters_with_two_way_converter.tests.js} +15 -16
  5. package/.out/core/mobx/specs/sub_form_field_adapters.tests.js +127 -12
  6. package/.out/core/mobx/sub_form_field_adapters.d.ts +6 -4
  7. package/.out/core/mobx/sub_form_field_adapters.js +28 -4
  8. package/.out/field_converters/nullable_to_boolean_converter.d.ts +2 -2
  9. package/.out/mantine/create_checkbox.js +1 -0
  10. package/.out/mantine/create_fields_view.d.ts +1 -1
  11. package/.out/mantine/create_fields_view.js +4 -4
  12. package/.out/mantine/create_form.d.ts +1 -1
  13. package/.out/mantine/create_list.d.ts +1 -1
  14. package/.out/mantine/create_pill.d.ts +1 -1
  15. package/.out/mantine/create_radio.d.ts +1 -1
  16. package/.out/mantine/create_radio_group.js +1 -0
  17. package/.out/mantine/create_text_input.js +7 -2
  18. package/.out/mantine/create_value_input.js +1 -0
  19. package/.out/mantine/error_renderer.d.ts +1 -1
  20. package/.out/mantine/error_renderer.js +1 -1
  21. package/.out/mantine/hooks.d.ts +9 -9
  22. package/.out/mantine/specs/checkbox_hooks.stories.d.ts +2 -6
  23. package/.out/mantine/specs/checkbox_hooks.stories.js +4 -16
  24. package/.out/mantine/specs/fields_view_hooks.stories.d.ts +1 -1
  25. package/.out/mantine/specs/fields_view_hooks.stories.js +6 -3
  26. package/.out/mantine/specs/form_hooks.stories.d.ts +2 -2
  27. package/.out/mantine/specs/form_hooks.stories.js +4 -1
  28. package/.out/mantine/specs/radio_group_hooks.stories.d.ts +2 -6
  29. package/.out/mantine/specs/radio_group_hooks.stories.js +5 -17
  30. package/.out/mantine/specs/select_hooks.stories.d.ts +2 -6
  31. package/.out/mantine/specs/select_hooks.stories.js +4 -16
  32. package/.out/mantine/specs/text_input_hooks.stories.d.ts +2 -5
  33. package/.out/mantine/specs/text_input_hooks.stories.js +5 -5
  34. package/.out/mantine/specs/value_input_hooks.stories.d.ts +2 -5
  35. package/.out/mantine/specs/value_input_hooks.stories.js +5 -5
  36. package/.out/mantine/types.d.ts +4 -2
  37. package/.out/tsconfig.tsbuildinfo +1 -1
  38. package/.turbo/turbo-build.log +8 -8
  39. package/.turbo/turbo-check-types.log +1 -1
  40. package/.turbo/turbo-release$colon$exports.log +1 -1
  41. package/core/mobx/hooks.ts +24 -6
  42. package/core/mobx/specs/form_presenter.tests.ts +6 -6
  43. package/core/mobx/specs/{merge_field_adapters_with_two_way_converter.ts → merge_field_adapters_with_two_way_converter.tests.ts} +16 -16
  44. package/core/mobx/specs/sub_form_field_adapters.tests.ts +193 -17
  45. package/core/mobx/sub_form_field_adapters.ts +74 -11
  46. package/dist/index.cjs +77 -32
  47. package/dist/index.d.cts +25 -18
  48. package/dist/index.d.ts +25 -18
  49. package/dist/index.js +68 -21
  50. package/field_converters/nullable_to_boolean_converter.ts +2 -3
  51. package/mantine/create_checkbox.tsx +2 -1
  52. package/mantine/create_fields_view.tsx +17 -14
  53. package/mantine/create_form.tsx +2 -2
  54. package/mantine/create_list.tsx +1 -1
  55. package/mantine/create_pill.tsx +1 -1
  56. package/mantine/create_radio.tsx +1 -1
  57. package/mantine/create_radio_group.tsx +6 -2
  58. package/mantine/create_text_input.tsx +9 -3
  59. package/mantine/create_value_input.tsx +2 -1
  60. package/mantine/error_renderer.ts +1 -1
  61. package/mantine/hooks.tsx +19 -14
  62. package/mantine/specs/__snapshots__/checkbox_hooks.tests.tsx.snap +1 -64
  63. package/mantine/specs/__snapshots__/fields_view_hooks.tests.tsx.snap +52 -52
  64. package/mantine/specs/__snapshots__/radio_group_hooks.tests.tsx.snap +1 -179
  65. package/mantine/specs/__snapshots__/select_hooks.tests.tsx.snap +1 -83
  66. package/mantine/specs/__snapshots__/text_input_hooks.tests.tsx.snap +27 -27
  67. package/mantine/specs/__snapshots__/value_input_hooks.tests.tsx.snap +31 -31
  68. package/mantine/specs/checkbox_hooks.stories.tsx +5 -21
  69. package/mantine/specs/fields_view_hooks.stories.tsx +16 -4
  70. package/mantine/specs/form_hooks.stories.tsx +10 -3
  71. package/mantine/specs/radio_group_hooks.stories.tsx +6 -20
  72. package/mantine/specs/select_hooks.stories.tsx +5 -21
  73. package/mantine/specs/text_input_hooks.stories.tsx +5 -8
  74. package/mantine/specs/value_input_hooks.stories.tsx +5 -8
  75. package/mantine/types.ts +7 -3
  76. package/package.json +2 -1
  77. /package/.out/core/mobx/specs/{merge_field_adapters_with_two_way_converter.d.ts → merge_field_adapters_with_two_way_converter.tests.d.ts} +0 -0
@@ -4,7 +4,11 @@ import { type FormPresenter } from './form_presenter';
4
4
  import { type ValuePathsOfPresenter } from './types';
5
5
  type ValueOfPresenter<P extends FormPresenter<any, any, any, any>> = P extends FormPresenter<infer T, any, any, any> ? ValueOfType<ReadonlyTypeOfType<T>> : never;
6
6
  type ModelOfPresenter<P extends FormPresenter<any, any, any, any>> = ReturnType<P['createModel']>;
7
- export 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): {
7
+ export declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(presenter: P, value: ValueOfPresenter<P>, { onValidFieldSubmit, onValidFormSubmit, }: {
8
+ onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void;
9
+ onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void;
10
+ }): {
8
11
  model: ModelOfPresenter<P>;
12
+ onFormSubmit?: (value: ValueOfPresenter<P>) => void;
9
13
  } & Omit<FieldsViewProps<ModelOfPresenter<P>['fields']>, 'fields'>;
10
14
  export {};
@@ -1,6 +1,6 @@
1
1
  import { useCallback, useMemo, } from 'react';
2
2
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
- export function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
3
+ export function useDefaultMobxFormHooks(presenter, value, { onValidFieldSubmit, onValidFormSubmit, }) {
4
4
  const model = useMemo(function () {
5
5
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
6
6
  return presenter.createModel(value);
@@ -17,13 +17,13 @@ export function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
17
17
  ]);
18
18
  const onFieldSubmit = useCallback(function (valuePath) {
19
19
  if (presenter.validateField(model, valuePath)) {
20
- onValidSubmit?.(model, valuePath);
20
+ onValidFieldSubmit?.(model, valuePath);
21
21
  }
22
22
  return false;
23
23
  }, [
24
24
  presenter,
25
25
  model,
26
- onValidSubmit,
26
+ onValidFieldSubmit,
27
27
  ]);
28
28
  const onFieldBlur = useCallback(function (path) {
29
29
  // work around potential loss of focus prior to state potentially invalidating change triggering
@@ -38,10 +38,20 @@ export function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
38
38
  presenter,
39
39
  model,
40
40
  ]);
41
+ const onFormSubmit = useCallback(function () {
42
+ if (presenter.validateAll(model)) {
43
+ onValidFormSubmit?.(model, model.value);
44
+ }
45
+ }, [
46
+ presenter,
47
+ model,
48
+ onValidFormSubmit,
49
+ ]);
41
50
  return {
42
51
  model,
43
52
  onFieldValueChange,
44
53
  onFieldSubmit,
45
54
  onFieldBlur,
55
+ onFormSubmit,
46
56
  };
47
57
  }
@@ -21,18 +21,16 @@ describe('all', function () {
21
21
  describe('FlattenedTypePathsToConvertersOf', function () {
22
22
  describe('record', function () {
23
23
  const typeDef = record(numberType);
24
- let t;
25
24
  it('equals expected type', function () {
26
- expectTypeOf(t).toEqualTypeOf();
25
+ expectTypeOf().toEqualTypeOf();
27
26
  });
28
27
  });
29
28
  describe('object', function () {
30
29
  const typeDef = object()
31
30
  .field('x', stringType)
32
31
  .field('y', booleanType);
33
- let t;
34
32
  it('equals expected type', function () {
35
- expectTypeOf(t).toEqualTypeOf();
33
+ expectTypeOf().toEqualTypeOf();
36
34
  });
37
35
  it('matches representative adapters', function () {
38
36
  expectTypeOf().toMatchTypeOf();
@@ -50,9 +48,8 @@ describe('all', function () {
50
48
  '$.b': '$.y',
51
49
  '$.c': '$.z',
52
50
  };
53
- let t;
54
51
  it('equals expected type', function () {
55
- expectTypeOf(t).toEqualTypeOf();
52
+ expectTypeOf().toEqualTypeOf();
56
53
  });
57
54
  });
58
55
  });
@@ -9,9 +9,8 @@ const error3 = Symbol();
9
9
  const error4 = Symbol();
10
10
  const context = Symbol();
11
11
  describe('MergedOfFieldAdapterWithTwoWayConverter', function () {
12
- let m;
13
12
  it('merges the errors', function () {
14
- expectTypeOf().toEqualTypeOf(m);
13
+ expectTypeOf().toEqualTypeOf();
15
14
  });
16
15
  });
17
16
  const originalIntegerAdapter = identityAdapter(0);
@@ -69,20 +68,20 @@ describe('mergeFieldAdaptersWithTwoWayConverter', function () {
69
68
  beforeEach(function () {
70
69
  result = merged.booleanAdapter.revert(true, 'booleanAdapter', context);
71
70
  });
72
- });
73
- it('returns the same value on revert', function () {
74
- expect(result).toEqual(expect.objectContaining({
75
- value: true,
76
- type: UnreliableFieldConversionType.Success,
77
- }));
78
- });
79
- it('calls the mocked converter', function () {
80
- expect(converter.revert).toHaveBeenCalledOnce();
81
- expect(converter.revert).toHaveBeenCalledWith(true, 'booleanAdapter', context);
82
- });
83
- it('calls the mocked adapter', function () {
84
- expect(booleanAdapter.revert).toHaveBeenCalledOnce();
85
- expect(booleanAdapter.revert).toHaveBeenCalledWith(true, 'booleanAdapter', context);
71
+ it('returns the same value on revert', function () {
72
+ expect(result).toEqual(expect.objectContaining({
73
+ value: true,
74
+ type: UnreliableFieldConversionType.Success,
75
+ }));
76
+ });
77
+ it('calls the mocked converter', function () {
78
+ expect(converter.revert).toHaveBeenCalledOnce();
79
+ expect(converter.revert).toHaveBeenCalledWith(true, 'booleanAdapter', context);
80
+ });
81
+ it('calls the mocked adapter', function () {
82
+ expect(booleanAdapter.revert).toHaveBeenCalledOnce();
83
+ expect(booleanAdapter.revert).toHaveBeenCalledWith(true, 'booleanAdapter', context);
84
+ });
86
85
  });
87
86
  });
88
87
  });
@@ -1,10 +1,10 @@
1
+ import { list, numberType, object, stringType, } from '@strictly/define';
1
2
  import { subFormFieldAdapters, } from 'core/mobx/sub_form_field_adapters';
2
- import { mockDeep } from 'vitest-mock-extended';
3
+ import { UnreliableFieldConversionType } from 'types/field_converters';
4
+ import { mockDeep, mockReset, } from 'vitest-mock-extended';
3
5
  describe('subFormFieldAdapters', () => {
4
- const fieldAdapter1 = mockDeep();
5
- const fieldAdapter2 = mockDeep();
6
6
  describe('empty value', () => {
7
- const adapters = subFormFieldAdapters({}, '$.a');
7
+ const adapters = subFormFieldAdapters({}, '$.a', stringType);
8
8
  it('equals expected type', () => {
9
9
  expectTypeOf(adapters).toEqualTypeOf();
10
10
  });
@@ -13,28 +13,143 @@ describe('subFormFieldAdapters', () => {
13
13
  });
14
14
  });
15
15
  describe('single adapter', () => {
16
- const adapters = subFormFieldAdapters({
16
+ const mockedFieldAdapter1 = mockDeep();
17
+ const fieldAdapter1 = mockedFieldAdapter1;
18
+ const type = object().field('a', stringType);
19
+ const subAdapters = {
17
20
  $: fieldAdapter1,
18
- }, '$.a');
21
+ };
22
+ const adapters = subFormFieldAdapters(subAdapters, '$.a', type);
23
+ beforeEach(() => {
24
+ mockReset(mockedFieldAdapter1);
25
+ });
19
26
  it('equals expected type', () => {
20
- expectTypeOf(adapters).toEqualTypeOf();
27
+ // TODO toEqualTypeOf (cannot reason about revert optionality, seems to be a TS issue as they
28
+ // are both optional AFAICT)
29
+ expectTypeOf(adapters).toMatchTypeOf();
21
30
  });
22
31
  it('equals expected value', () => {
23
- expect(adapters).toEqual({ '$.a': fieldAdapter1 });
32
+ expect(adapters).toEqual({ '$.a': expect.anything() });
33
+ });
34
+ it('calls convert with the correct paths and values', () => {
35
+ const mockedReturnedValue = {
36
+ value: false,
37
+ required: false,
38
+ readonly: false,
39
+ };
40
+ mockedFieldAdapter1.convert.mockReturnValue(mockedReturnedValue);
41
+ const returnedValue = adapters['$.a'].convert('x', '$.a', { a: 'y' });
42
+ expect(fieldAdapter1.convert).toHaveBeenCalledWith('x', '$', 'y');
43
+ expect(returnedValue).toEqual(mockedReturnedValue);
44
+ });
45
+ it('calls revert with the correct paths and values', () => {
46
+ const mockedReturnedValue = {
47
+ type: UnreliableFieldConversionType.Success,
48
+ value: 'ok',
49
+ };
50
+ mockedFieldAdapter1.revert.mockReturnValue(mockedReturnedValue);
51
+ const returnedValue = adapters['$.a'].revert?.(true, '$.a', { a: 'y' });
52
+ expect(fieldAdapter1.revert).toHaveBeenCalledWith(true, '$', 'y');
53
+ expect(returnedValue).toEqual(mockedReturnedValue);
54
+ });
55
+ it('calls create with the correct paths and values', () => {
56
+ const mockedReturnedValue = 'x';
57
+ mockedFieldAdapter1.create.mockReturnValue(mockedReturnedValue);
58
+ const returnedValue = adapters['$.a'].create('$.a', { a: 'y' });
59
+ expect(fieldAdapter1.create).toHaveBeenCalledWith('$', 'y');
60
+ expect(returnedValue).toEqual(mockedReturnedValue);
24
61
  });
25
62
  });
26
63
  describe('multiple adapters', () => {
64
+ const mockedFieldAdapter1 = mockDeep();
65
+ const fieldAdapter1 = mockedFieldAdapter1;
66
+ const mockedFieldAdapter2 = mockDeep();
67
+ const fieldAdapter2 = mockedFieldAdapter2;
68
+ const type = object()
69
+ .field('a', object().field('x', stringType).field('y', numberType));
27
70
  const adapters = subFormFieldAdapters({
28
71
  '$.x': fieldAdapter1,
29
72
  '$.y': fieldAdapter2,
30
- }, '$.a');
73
+ }, '$.a', type);
74
+ beforeEach(() => {
75
+ mockReset(mockedFieldAdapter1);
76
+ mockReset(mockedFieldAdapter2);
77
+ });
31
78
  it('equals expected type', () => {
32
- expectTypeOf(adapters).toEqualTypeOf();
79
+ // TODO toEqualTypeOf (seems to be a TS error)
80
+ expectTypeOf(adapters).toMatchTypeOf();
81
+ });
82
+ it('equals expected value', () => {
83
+ expect(adapters).toEqual({
84
+ '$.a.x': expect.anything(),
85
+ '$.a.y': expect.anything(),
86
+ });
87
+ });
88
+ describe('calls convert with correct paths and values', () => {
89
+ const subContext = {
90
+ x: 'a',
91
+ y: 1,
92
+ };
93
+ const context = {
94
+ a: subContext,
95
+ };
96
+ it('calls $.a.x', () => {
97
+ const mockedReturnedValue = {
98
+ value: true,
99
+ readonly: true,
100
+ required: false,
101
+ };
102
+ mockedFieldAdapter1.convert.mockReturnValue(mockedReturnedValue);
103
+ const returnedValue = adapters['$.a.x'].convert('b', '$.a.x', context);
104
+ expect(fieldAdapter1.convert).toHaveBeenCalledWith('b', '$.x', subContext);
105
+ expect(returnedValue).toEqual(mockedReturnedValue);
106
+ });
107
+ it('calls $.a.y', () => {
108
+ const mockedReturnedValue = {
109
+ value: false,
110
+ readonly: false,
111
+ required: false,
112
+ };
113
+ mockedFieldAdapter2.convert.mockReturnValue(mockedReturnedValue);
114
+ const returnedValue = adapters['$.a.y'].convert(2, '$.a.y', context);
115
+ expect(fieldAdapter2.convert).toHaveBeenCalledWith(2, '$.y', subContext);
116
+ expect(returnedValue).toEqual(mockedReturnedValue);
117
+ });
118
+ });
119
+ });
120
+ describe('list adapter', () => {
121
+ const mockedFieldAdapter1 = mockDeep();
122
+ const fieldAdapter1 = mockedFieldAdapter1;
123
+ const type = list(stringType);
124
+ const subAdapters = {
125
+ $: fieldAdapter1,
126
+ };
127
+ const adapters = subFormFieldAdapters(subAdapters, '$.*', type);
128
+ beforeEach(() => {
129
+ mockReset(mockedFieldAdapter1);
130
+ });
131
+ it('equals expected type', () => {
132
+ // TODO toEqualTypeOf (seems to be a TS error)
133
+ expectTypeOf(adapters).toMatchTypeOf();
33
134
  });
34
135
  it('equals expected value', () => {
35
136
  expect(adapters).toEqual({
36
- '$.a.x': fieldAdapter1,
37
- '$.a.y': fieldAdapter2,
137
+ '$.*': expect.anything(),
138
+ });
139
+ });
140
+ describe('calls convert with correct paths and values', () => {
141
+ const subContext = 'a';
142
+ const context = [subContext];
143
+ it('calls $.*', () => {
144
+ const mockedReturnedValue = {
145
+ value: false,
146
+ readonly: false,
147
+ required: false,
148
+ };
149
+ mockedFieldAdapter1.convert.mockReturnValue(mockedReturnedValue);
150
+ const returnedValue = adapters['$.*'].convert('b', '$.0', context);
151
+ expect(fieldAdapter1.convert).toHaveBeenCalledWith('b', '$', subContext);
152
+ expect(returnedValue).toEqual(mockedReturnedValue);
38
153
  });
39
154
  });
40
155
  });
@@ -1,7 +1,9 @@
1
1
  import { type StringConcatOf } from '@strictly/base';
2
- import { type FieldAdapter } from './field_adapter';
3
- type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string> = {
4
- [K in keyof SubAdapters as K extends StringConcatOf<'$', infer S> ? `${P}${S}` : never]: SubAdapters[K];
2
+ import { type Type, type ValueOfType } from '@strictly/define';
3
+ import { type ErrorOfFieldAdapter, type FieldAdapter, type FromOfFieldAdapter, type ToOfFieldAdapter, type ValuePathOfFieldAdapter } from './field_adapter';
4
+ 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>;
5
+ type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, TypePath extends string, ValuePath extends string, Context> = {
6
+ [K in keyof SubAdapters as K extends StringConcatOf<'$', infer TypePathSuffix> ? `${TypePath}${TypePathSuffix}` : never]: SubFormFieldAdapter<SubAdapters[K], ValuePath, Context>;
5
7
  };
6
- export declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string>(subAdapters: SubAdapters, prefix: P): SubFormFieldAdapters<SubAdapters, P>;
8
+ export 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>>;
7
9
  export {};
@@ -1,8 +1,32 @@
1
- export function subFormFieldAdapters(subAdapters, prefix) {
1
+ import { flattenValuesOfType, } from '@strictly/define';
2
+ export function subFormFieldAdapters(subAdapters, parentTypePath, contextType) {
3
+ // assume the number of '.' in the type path will correspond to the number of '.' in the value path
4
+ const dotCount = parentTypePath.split('.').length;
5
+ function getSubValuePathAndContext(valuePath, context) {
6
+ const parentValuePath = valuePath.split('.').slice(0, dotCount).join('.');
7
+ const subValuePath = valuePath.replace(parentValuePath, '$');
8
+ const subContext = flattenValuesOfType(contextType, context)[parentValuePath];
9
+ return [
10
+ subValuePath,
11
+ subContext,
12
+ ];
13
+ }
2
14
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
3
- return Object.entries(subAdapters).reduce((acc, [subKey, subValue,]) => {
4
- const key = subKey.replace('$', prefix);
5
- acc[key] = subValue;
15
+ return Object.entries(subAdapters).reduce((acc, [subTypePath, subAdapter,]) => {
16
+ const typePath = subTypePath.replace('$', parentTypePath);
17
+ // adapt field adapter with new path and context
18
+ const adaptedAdapter = {
19
+ convert: (from, valuePath, context) => {
20
+ return subAdapter.convert(from, ...getSubValuePathAndContext(valuePath, context));
21
+ },
22
+ create: (valuePath, context) => {
23
+ return subAdapter.create(...getSubValuePathAndContext(valuePath, context));
24
+ },
25
+ revert: subAdapter.revert && ((from, valuePath, context) => {
26
+ return subAdapter.revert(from, ...getSubValuePathAndContext(valuePath, context));
27
+ }),
28
+ };
29
+ acc[typePath] = adaptedAdapter;
6
30
  return acc;
7
31
  }, {});
8
32
  }
@@ -1,12 +1,12 @@
1
1
  import { type ReadonlyTypeOfType, type Type, type ValueOfType } from '@strictly/define';
2
2
  import { type AnnotatedFieldConversion, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion } from 'types/field_converters';
3
- export 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> {
3
+ export declare class NullableToBooleanConverter<T extends Type, ValuePath extends string, Context, NullType extends null | undefined> implements TwoWayFieldConverterWithValueFactory<ValueOfType<ReadonlyTypeOfType<T>> | NullType, boolean, never, ValuePath, Context> {
4
4
  private readonly typeDef;
5
5
  private readonly prototype;
6
6
  private readonly nullType;
7
7
  readonly defaultValue: ValueOfType<ReadonlyTypeOfType<T>> | NullType;
8
8
  constructor(typeDef: T, prototype: ValueOfType<ReadonlyTypeOfType<T>>, nullType: NullType, defaultToNull?: boolean);
9
9
  convert(from: ValueOfType<ReadonlyTypeOfType<T>> | NullType): AnnotatedFieldConversion<boolean>;
10
- revert(from: boolean): UnreliableFieldConversion<ValueOfType<ReadonlyTypeOfType<T>> | NullType, E>;
10
+ revert(from: boolean): UnreliableFieldConversion<ValueOfType<ReadonlyTypeOfType<T>> | NullType, never>;
11
11
  create(): ValueOfType<ReadonlyTypeOfType<T>> | NullType;
12
12
  }
@@ -34,5 +34,6 @@ export function createCheckbox(valuePath, Checkbox) {
34
34
  onKeyUp,
35
35
  };
36
36
  };
37
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
37
38
  return createUnsafePartialObserverComponent(Checkbox, propSource, ['ErrorRenderer']);
38
39
  }
@@ -4,4 +4,4 @@ import type { AllFieldsOfFields } from 'types/all_fields_of_fields';
4
4
  import type { Fields } from 'types/field';
5
5
  import type { SubFormFields } from 'types/sub_form_fields';
6
6
  import type { MantineFieldComponent } from './types';
7
- export declare function createFieldsView<F extends Fields, K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>, observableProps: FieldsViewProps<F>): MantineFieldComponent<FieldsViewProps<P['fields']>, P>;
7
+ export declare function createFieldsView<F extends Fields, K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>, observableProps: FieldsViewProps<F>): MantineFieldComponent<FieldsViewProps<P['fields']>, P, never>;
@@ -31,9 +31,9 @@ export function createFieldsView(valuePath, FieldsView, observableProps) {
31
31
  acc[toSubKey(fieldKey)] = fieldValue;
32
32
  }
33
33
  return acc;
34
- }, {});
35
- return (_jsx(FieldsView, { ...props,
36
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
37
- fields: subFields, onFieldBlur: onFieldBlur, onFieldFocus: onFieldFocus, onFieldSubmit: onFieldSubmit, onFieldValueChange: onFieldValueChange }));
34
+ },
35
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
36
+ {});
37
+ return (_jsx(FieldsView, { ...props, fields: subFields, onFieldBlur: onFieldBlur, onFieldFocus: onFieldFocus, onFieldSubmit: onFieldSubmit, onFieldValueChange: onFieldValueChange }));
38
38
  });
39
39
  }
@@ -4,4 +4,4 @@ import { type AllFieldsOfFields } from 'types/all_fields_of_fields';
4
4
  import { type Fields } from 'types/field';
5
5
  import { type ValueTypeOfField } from 'types/value_type_of_field';
6
6
  import { type MantineFieldComponent } from './types';
7
- export declare function createForm<F extends Fields, K extends keyof AllFieldsOfFields<F>, P extends FormProps<ValueTypeOfField<F[K]>> = FormProps<ValueTypeOfField<F[K]>>>(valuePath: K, Form: ComponentType<P>, observableProps: FieldsViewProps<F>): MantineFieldComponent<FormProps<ValueTypeOfField<F[K]>>, P>;
7
+ export declare function createForm<F extends Fields, K extends keyof AllFieldsOfFields<F>, P extends FormProps<ValueTypeOfField<F[K]>> = FormProps<ValueTypeOfField<F[K]>>>(valuePath: K, Form: ComponentType<P>, observableProps: FieldsViewProps<F>): MantineFieldComponent<FormProps<ValueTypeOfField<F[K]>>, P, never>;
@@ -10,7 +10,7 @@ export type SuppliedListProps<Value = any, ListPath extends string = string> = {
10
10
  };
11
11
  export declare function createList<F extends Fields, K extends keyof ListFieldsOfFields<F>, Props extends SuppliedListProps<ElementOfArray<ValueTypeOfField<F[K]>>> & {
12
12
  children: (valuePath: `${K}.${number}`, value: ElementOfArray<ValueTypeOfField<F[K]>>, index: number) => React.ReactNode;
13
- }>(this: MantineForm<F>, valuePath: K, List: ComponentType<Props>): MantineFieldComponent<SuppliedListProps<ElementOfArray<ValueTypeOfField<F[K]>>>, Props>;
13
+ }>(this: MantineForm<F>, valuePath: K, List: ComponentType<Props>): MantineFieldComponent<SuppliedListProps<ElementOfArray<ValueTypeOfField<F[K]>>>, Props, never>;
14
14
  export declare function DefaultList<Value, ListPath extends string>({ values, listPath, children, }: SuppliedListProps<Value, ListPath> & {
15
15
  children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
16
16
  }): import("react/jsx-runtime").JSX.Element;
@@ -4,4 +4,4 @@ import { type AllFieldsOfFields } from 'types/all_fields_of_fields';
4
4
  import { type Fields } from 'types/field';
5
5
  import { type MantineFieldComponent, type MantineForm } from './types';
6
6
  export type SuppliedPillProps = Pick<PillProps, 'children' | 'disabled'>;
7
- export declare function createPill<F extends Fields, K extends keyof AllFieldsOfFields<F>, Props extends SuppliedPillProps>(this: MantineForm<F>, valuePath: K, Pill: ComponentType<Props>): MantineFieldComponent<SuppliedPillProps, Props>;
7
+ export declare function createPill<F extends Fields, K extends keyof AllFieldsOfFields<F>, Props extends SuppliedPillProps>(this: MantineForm<F>, valuePath: K, Pill: ComponentType<Props>): MantineFieldComponent<SuppliedPillProps, Props, never>;
@@ -5,4 +5,4 @@ import { type StringFieldsOfFields } from 'types/string_fields_of_fields';
5
5
  import { type ValueTypeOfField } from 'types/value_type_of_field';
6
6
  import { type MantineFieldComponent, type MantineForm } from './types';
7
7
  export type SuppliedRadioProps = Pick<RadioProps, 'value' | 'disabled'>;
8
- export declare function createRadio<F extends Fields, K extends keyof StringFieldsOfFields<F>, Props extends SuppliedRadioProps>(this: MantineForm<F>, valuePath: K, value: ValueTypeOfField<F[K]>, Radio: ComponentType<Props>): MantineFieldComponent<SuppliedRadioProps, Props>;
8
+ export declare function createRadio<F extends Fields, K extends keyof StringFieldsOfFields<F>, Props extends SuppliedRadioProps>(this: MantineForm<F>, valuePath: K, value: ValueTypeOfField<F[K]>, Radio: ComponentType<Props>): MantineFieldComponent<SuppliedRadioProps, Props, never>;
@@ -31,5 +31,6 @@ export function createRadioGroup(valuePath, RadioGroup) {
31
31
  onKeyUp,
32
32
  };
33
33
  };
34
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
34
35
  return createUnsafePartialObserverComponent(RadioGroup, propSource, ['ErrorRenderer']);
35
36
  }
@@ -19,9 +19,13 @@ export function createTextInput(valuePath, TextInput) {
19
19
  }
20
20
  };
21
21
  const propSource = ({ ErrorRenderer = DefaultErrorRenderer, }) => {
22
- const { readonly, required, value, error,
23
22
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
24
- } = this.fields[valuePath];
23
+ const field = this.fields[valuePath];
24
+ if (field == null) {
25
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
26
+ throw new Error(`invalid field ${valuePath}`);
27
+ }
28
+ const { readonly, required, value, error, } = field;
25
29
  return {
26
30
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
27
31
  name: valuePath,
@@ -35,5 +39,6 @@ export function createTextInput(valuePath, TextInput) {
35
39
  onKeyUp,
36
40
  };
37
41
  };
42
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
38
43
  return createUnsafePartialObserverComponent(TextInput, propSource, ['ErrorRenderer']);
39
44
  }
@@ -35,5 +35,6 @@ export function createValueInput(valuePath, ValueInput) {
35
35
  onKeyUp,
36
36
  };
37
37
  };
38
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
38
39
  return createUnsafePartialObserverComponent(ValueInput, propSource, ['ErrorRenderer']);
39
40
  }
@@ -3,4 +3,4 @@ export type ErrorRendererProps<E> = {
3
3
  error: E;
4
4
  };
5
5
  export type ErrorRenderer<E = any> = ComponentType<ErrorRendererProps<E>>;
6
- export declare function DefaultErrorRenderer({ error, }: ErrorRendererProps<any>): any;
6
+ export declare function DefaultErrorRenderer({ error, }: ErrorRendererProps<any>): string;
@@ -1,5 +1,5 @@
1
1
  export function DefaultErrorRenderer({ error,
2
2
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
3
  }) {
4
- return error;
4
+ return JSON.stringify(error);
5
5
  }
@@ -38,20 +38,20 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
38
38
  onFieldBlur: ((this: void, key: keyof F) => void) | undefined;
39
39
  onFieldSubmit: ((this: void, key: keyof F) => boolean | void) | undefined;
40
40
  constructor(fields: F);
41
- textInput<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, TextInputProps>;
42
- textInput<K extends keyof StringFieldsOfFields<F>, P extends SuppliedTextInputProps<any>>(valuePath: K, TextInput?: ComponentType<P>): MantineFieldComponent<SuppliedTextInputProps, P>;
41
+ textInput<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, TextInputProps, ErrorOfField<F[K]>>;
42
+ textInput<K extends keyof StringFieldsOfFields<F>, P extends SuppliedTextInputProps<any>>(valuePath: K, TextInput?: ComponentType<P>): MantineFieldComponent<SuppliedTextInputProps, P, ErrorOfField<F[K]>>;
43
43
  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]>>;
44
44
  select<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, ComponentProps<typeof SimpleSelect>, ErrorOfField<F[K]>>;
45
- checkbox<K extends keyof BooleanFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedCheckboxProps, CheckboxProps>;
45
+ checkbox<K extends keyof BooleanFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedCheckboxProps, CheckboxProps, ErrorOfField<F[K]>>;
46
46
  checkbox<K extends keyof BooleanFieldsOfFields<F>, P extends SuppliedCheckboxProps>(valuePath: K, Checkbox: ComponentType<P>): MantineFieldComponent<SuppliedCheckboxProps, P, ErrorOfField<F[K]>>;
47
- radioGroup<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedRadioGroupProps, RadioGroupProps>;
48
- radioGroup<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioGroupProps>(valuePath: K, RadioGroup: ComponentType<P>): MantineFieldComponent<SuppliedRadioGroupProps, P>;
47
+ radioGroup<K extends keyof StringFieldsOfFields<F>, P extends RadioGroupProps = RadioGroupProps>(valuePath: K): MantineFieldComponent<SuppliedRadioGroupProps, P, ErrorOfField<F[K]>>;
48
+ radioGroup<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioGroupProps>(valuePath: K, RadioGroup: ComponentType<P>): MantineFieldComponent<SuppliedRadioGroupProps, P, ErrorOfField<F[K]>>;
49
49
  radio<K extends keyof StringFieldsOfFields<F>>(valuePath: K, value: ValueTypeOfField<F[K]>): MantineFieldComponent<SuppliedRadioProps, RadioProps, ErrorOfField<F[K]>>;
50
50
  radio<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioProps>(valuePath: K, value: ValueTypeOfField<F[K]>, Radio: ComponentType<P>): MantineFieldComponent<SuppliedRadioProps, P, ErrorOfField<F[K]>>;
51
51
  pill<K extends keyof AllFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedPillProps, PillProps, ErrorOfField<F[K]>>;
52
- pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P>;
53
- list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K>>>;
54
- fieldsView<K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>): MantineFieldComponent<FieldsViewProps<P['fields']>, P>;
55
- 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>;
52
+ pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P, ErrorOfField<F[K]>>;
53
+ list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K>>, never>;
54
+ 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>;
55
+ 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>;
56
56
  }
57
57
  export {};
@@ -1,12 +1,9 @@
1
1
  import { type Meta, type StoryObj } from '@storybook/react';
2
2
  import { type FieldsViewProps } from 'core/props';
3
- import { type ErrorRenderer } from 'mantine/error_renderer';
4
3
  import { type Field } from 'types/field';
5
- declare function Component({ ErrorRenderer, ...props }: FieldsViewProps<{
4
+ declare function Component({ ...props }: FieldsViewProps<{
6
5
  $: Field<boolean, string>;
7
- }> & {
8
- ErrorRenderer?: ErrorRenderer;
9
- }): import("react/jsx-runtime").JSX.Element;
6
+ }>): import("react/jsx-runtime").JSX.Element;
10
7
  declare const meta: Meta<typeof Component>;
11
8
  export default meta;
12
9
  type Story = StoryObj<typeof Component>;
@@ -15,4 +12,3 @@ export declare const On: Story;
15
12
  export declare const Required: Story;
16
13
  export declare const Disabled: Story;
17
14
  export declare const Error: Story;
18
- export declare const CustomError: Story;
@@ -2,7 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { action } from '@storybook/addon-actions';
3
3
  import { useMantineFormFields } from 'mantine/hooks';
4
4
  import { CHECKBOX_LABEL } from './checkbox_constants';
5
- function Component({ ErrorRenderer, ...props }) {
5
+ function ErrorRenderer({ error }) {
6
+ return `Error ${error}`;
7
+ }
8
+ function Component({ ...props }) {
6
9
  const inputProps = useMantineFormFields(props);
7
10
  const CheckboxComponent = inputProps.checkbox('$');
8
11
  return (_jsx(CheckboxComponent, { ErrorRenderer: ErrorRenderer, label: CHECKBOX_LABEL }));
@@ -73,18 +76,3 @@ export const Error = {
73
76
  },
74
77
  },
75
78
  };
76
- export const CustomError = {
77
- args: {
78
- fields: {
79
- $: {
80
- readonly: false,
81
- required: false,
82
- value: true,
83
- error: 'error',
84
- },
85
- },
86
- ErrorRenderer: function () {
87
- return 'custom error';
88
- },
89
- },
90
- };
@@ -12,4 +12,4 @@ export declare const Empty: Story;
12
12
  export declare const Populated: Story;
13
13
  export declare const Required: Story;
14
14
  export declare const Disabled: Story;
15
- export declare const CustomError: Story;
15
+ export declare const Errors: Story;
@@ -3,16 +3,19 @@ import { Button, Stack, } from '@mantine/core';
3
3
  import { action } from '@storybook/addon-actions';
4
4
  import { useMantineFormFields } from 'mantine/hooks';
5
5
  const onClick = action('some button clicked');
6
+ function ErrorRenderer({ error }) {
7
+ return `error ${error}`;
8
+ }
6
9
  function SubFieldsView(props) {
7
10
  const form = useMantineFormFields(props);
8
11
  const TextInput = form.textInput('$');
9
- return (_jsxs(Stack, { children: [_jsx(TextInput, { label: 'sub fields view' }), _jsx(Button, { onClick: props.onClick, children: "Bonus Button" })] }));
12
+ return (_jsxs(Stack, { children: [_jsx(TextInput, { ErrorRenderer: ErrorRenderer, label: 'sub fields view' }), _jsx(Button, { onClick: props.onClick, children: "Bonus Button" })] }));
10
13
  }
11
14
  function Component(props) {
12
15
  const form = useMantineFormFields(props);
13
16
  const FieldsView = form.fieldsView('$.a', SubFieldsView);
14
17
  const TextInput = form.textInput('$');
15
- return (_jsxs(Stack, { children: [_jsx(TextInput, { label: 'fields view' }), _jsx(FieldsView, { onClick: onClick })] }));
18
+ return (_jsxs(Stack, { children: [_jsx(TextInput, { ErrorRenderer: ErrorRenderer, label: 'fields view' }), _jsx(FieldsView, { onClick: onClick })] }));
16
19
  }
17
20
  const meta = {
18
21
  component: Component,
@@ -88,7 +91,7 @@ export const Disabled = {
88
91
  },
89
92
  },
90
93
  };
91
- export const CustomError = {
94
+ export const Errors = {
92
95
  args: {
93
96
  fields: {
94
97
  $: {