@strictly/react-form 0.0.11 → 0.0.12

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,27 +1,16 @@
1
- import { useCallback, useMemo, } from 'react';
2
- import { createUnsafePartialObserverComponent, } from 'util/partial';
3
- export function useDefaultMobxFormHooks(presenter, value, { onValidFieldSubmit, onValidFormSubmit, FormFieldsView, } = {}) {
4
- const model = useMemo(function () {
5
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
6
- return presenter.createModel(value);
7
- }, [
8
- presenter,
9
- value,
10
- ]);
1
+ import { useCallback, } from 'react';
2
+ export function useDefaultMobxFormHooks(model, { onValidFieldSubmit, onValidFormSubmit, } = {}) {
11
3
  const onFieldValueChange = useCallback(function (path, value) {
12
- presenter.clearFieldError(model, path);
13
- presenter.setFieldValue(model, path, value);
14
- }, [
15
- presenter,
16
- model,
17
- ]);
4
+ // TODO do in one action
5
+ model.clearFieldError(path);
6
+ model.setFieldValue(path, value);
7
+ }, [model]);
18
8
  const onFieldSubmit = useCallback(function (valuePath) {
19
- if (presenter.validateField(model, valuePath)) {
20
- onValidFieldSubmit === null || onValidFieldSubmit === void 0 ? void 0 : onValidFieldSubmit(model, valuePath);
9
+ if (model.validateField(valuePath)) {
10
+ onValidFieldSubmit === null || onValidFieldSubmit === void 0 ? void 0 : onValidFieldSubmit(valuePath);
21
11
  }
22
12
  return false;
23
13
  }, [
24
- presenter,
25
14
  model,
26
15
  onValidFieldSubmit,
27
16
  ]);
@@ -30,49 +19,24 @@ export function useDefaultMobxFormHooks(presenter, value, { onValidFieldSubmit,
30
19
  // (e.g. changing a discriminator)
31
20
  // TODO debounce?
32
21
  setTimeout(function () {
33
- if (presenter.isValuePathActive(model, path)) {
34
- presenter.validateField(model, path, true);
22
+ if (model.isValuePathActive(path)) {
23
+ model.validateField(path, true);
35
24
  }
36
25
  }, 100);
37
- }, [
38
- presenter,
39
- model,
40
- ]);
26
+ }, [model]);
41
27
  const onFormSubmit = useCallback(function () {
42
- if (presenter.validateAll(model)) {
43
- onValidFormSubmit === null || onValidFormSubmit === void 0 ? void 0 : onValidFormSubmit(model, model.value);
28
+ if (model.validateAll()) {
29
+ onValidFormSubmit === null || onValidFormSubmit === void 0 ? void 0 : onValidFormSubmit(model.value);
44
30
  }
45
31
  }, [
46
- presenter,
47
32
  model,
48
33
  onValidFormSubmit,
49
34
  ]);
50
- const FormFields = useMemo(() => {
51
- if (FormFieldsView == null) {
52
- return undefined;
53
- }
54
- return createUnsafePartialObserverComponent(FormFieldsView, () => {
55
- return {
56
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
57
- fields: model.fields,
58
- onFieldBlur,
59
- onFieldSubmit,
60
- onFieldValueChange,
61
- };
62
- });
63
- }, [
64
- model,
65
- FormFieldsView,
66
- onFieldBlur,
67
- onFieldSubmit,
68
- onFieldValueChange,
69
- ]);
35
+ // TODO have option to automatically bind all these callbacks to a FieldsView parameter
70
36
  return {
71
- model,
72
37
  onFieldValueChange,
73
38
  onFieldSubmit,
74
39
  onFieldBlur,
75
40
  onFormSubmit,
76
- FormFields,
77
41
  };
78
42
  }
@@ -1,7 +1,7 @@
1
1
  import { expectDefinedAndReturn } from '@strictly/base';
2
2
  import { booleanType, list, nullType, numberType, object, record, stringType, union, } from '@strictly/define';
3
3
  import { adapterFromTwoWayConverter, identityAdapter, } from 'core/mobx/field_adapter_builder';
4
- import { FormModel, FormPresenter, } from 'core/mobx/form_presenter';
4
+ import { FormModel, } from 'core/mobx/form_model';
5
5
  import { IntegerToStringConverter } from 'field_converters/integer_to_string_converter';
6
6
  import { NullableToBooleanConverter } from 'field_converters/nullable_to_boolean_converter';
7
7
  import { SelectDiscriminatedUnionConverter } from 'field_converters/select_value_type_converter';
@@ -9,11 +9,6 @@ import { prototypingFieldValueFactory } from 'field_value_factories/prototyping_
9
9
  import { UnreliableFieldConversionType, } from 'types/field_converters';
10
10
  import { createMockedAdapter, resetMockAdapter, } from './fixtures';
11
11
  const IS_NAN_ERROR = 1;
12
- class TestFormPresenter extends FormPresenter {
13
- createModel(value) {
14
- return new FormModel(this.type, value, this.adapters);
15
- }
16
- }
17
12
  const originalIntegerToStringAdapter = adapterFromTwoWayConverter(new IntegerToStringConverter(IS_NAN_ERROR), prototypingFieldValueFactory(0));
18
13
  const originalBooleanToBooleanAdapter = identityAdapter(false);
19
14
  describe('all', function () {
@@ -285,22 +280,21 @@ describe('all', function () {
285
280
  });
286
281
  // TODO union
287
282
  });
288
- describe('FormPresenter', function () {
283
+ describe('FormModel', function () {
289
284
  describe('literal', function () {
290
285
  const typeDef = numberType;
291
286
  const adapters = {
292
287
  $: integerToStringAdapter,
293
288
  };
294
- const presenter = new TestFormPresenter(typeDef, adapters);
295
289
  const originalValue = 2;
296
290
  let model;
297
291
  beforeEach(function () {
298
- model = presenter.createModel(originalValue);
292
+ model = new FormModel(typeDef, originalValue, adapters);
299
293
  });
300
294
  describe('setFieldValueAndValidate', function () {
301
295
  describe('success', function () {
302
296
  beforeEach(function () {
303
- presenter.setFieldValueAndValidate(model, '$', '1');
297
+ model.setFieldValueAndValidate('$', '1');
304
298
  });
305
299
  it('does set the underlying value', function () {
306
300
  expect(model.value).toEqual(1);
@@ -317,7 +311,7 @@ describe('all', function () {
317
311
  describe('failure', function () {
318
312
  describe('conversion fails', function () {
319
313
  beforeEach(function () {
320
- presenter.setFieldValueAndValidate(model, '$', 'x');
314
+ model.setFieldValueAndValidate('$', 'x');
321
315
  });
322
316
  it('does not set the underlying value', function () {
323
317
  expect(model.value).toEqual(originalValue);
@@ -341,7 +335,7 @@ describe('all', function () {
341
335
  error: errorCode,
342
336
  value: [newValue],
343
337
  });
344
- presenter.setFieldValueAndValidate(model, '$', '-1');
338
+ model.setFieldValueAndValidate('$', '-1');
345
339
  });
346
340
  it('does set the underlying value', function () {
347
341
  expect(model.value).toEqual(newValue);
@@ -369,7 +363,7 @@ describe('all', function () {
369
363
  ],
370
364
  ])('setFieldValue to %s', function (newValue, expectedValue) {
371
365
  beforeEach(function () {
372
- presenter.setFieldValue(model, '$', newValue);
366
+ model.setFieldValue('$', newValue);
373
367
  });
374
368
  it('does set the underlying value', function () {
375
369
  expect(model.value).toEqual(expectedValue);
@@ -389,7 +383,6 @@ describe('all', function () {
389
383
  const converters = {
390
384
  '$.*': integerToStringAdapter,
391
385
  };
392
- const presenter = new TestFormPresenter(typeDef, converters);
393
386
  let originalValue;
394
387
  let model;
395
388
  beforeEach(function () {
@@ -398,12 +391,12 @@ describe('all', function () {
398
391
  3,
399
392
  7,
400
393
  ];
401
- model = presenter.createModel(originalValue);
394
+ model = new FormModel(typeDef, originalValue, converters);
402
395
  });
403
396
  describe('setFieldValueAndValidate', function () {
404
397
  describe('success', function () {
405
398
  beforeEach(function () {
406
- presenter.setFieldValueAndValidate(model, '$.0', '100');
399
+ model.setFieldValueAndValidate('$.0', '100');
407
400
  });
408
401
  it('sets the underlying value', function () {
409
402
  expect(model.value).toEqual([
@@ -423,7 +416,7 @@ describe('all', function () {
423
416
  });
424
417
  describe('failure', function () {
425
418
  beforeEach(function () {
426
- presenter.setFieldValueAndValidate(model, '$.0', 'x');
419
+ model.setFieldValueAndValidate('$.0', 'x');
427
420
  });
428
421
  it('does not set the underlying value', function () {
429
422
  expect(model.value).toEqual(originalValue);
@@ -443,7 +436,7 @@ describe('all', function () {
443
436
  'x',
444
437
  ])('setFieldValue to %s', function (newValue) {
445
438
  beforeEach(function () {
446
- presenter.setFieldValue(model, '$.0', newValue);
439
+ model.setFieldValue('$.0', newValue);
447
440
  });
448
441
  it('does not set the underlying value', function () {
449
442
  expect(model.value).toEqual(originalValue);
@@ -459,10 +452,10 @@ describe('all', function () {
459
452
  });
460
453
  describe('validate', function () {
461
454
  beforeEach(function () {
462
- presenter.setFieldValue(model, '$.0', 'x');
463
- presenter.setFieldValue(model, '$.1', '2');
464
- presenter.setFieldValue(model, '$.2', 'z');
465
- presenter.validateAll(model);
455
+ model.setFieldValue('$.0', 'x');
456
+ model.setFieldValue('$.1', '2');
457
+ model.setFieldValue('$.2', 'z');
458
+ model.validateAll();
466
459
  });
467
460
  it('contains errors for all invalid fields', function () {
468
461
  expect(model.fields).toEqual(expect.objectContaining({
@@ -501,7 +494,7 @@ describe('all', function () {
501
494
  });
502
495
  });
503
496
  it('supplies the full, previous context when converting', function () {
504
- presenter.setFieldValueAndValidate(model, '$.2', '4');
497
+ model.setFieldValueAndValidate('$.2', '4');
505
498
  expect(integerToStringAdapter.revert).toHaveBeenCalledOnce();
506
499
  expect(integerToStringAdapter.revert).toHaveBeenCalledWith('4', '$.2',
507
500
  // uses the same pointer
@@ -521,7 +514,7 @@ describe('all', function () {
521
514
  model.errors['$.0'] = 0;
522
515
  model.errors['$.1'] = 1;
523
516
  model.errors['$.2'] = 2;
524
- presenter.addListItem(model, '$', null, 0);
517
+ model.addListItem('$', null, 0);
525
518
  });
526
519
  it('adds the list item to the underlying value', function () {
527
520
  expect(model.value).toEqual([
@@ -576,7 +569,7 @@ describe('all', function () {
576
569
  });
577
570
  describe('add defined value', function () {
578
571
  beforeEach(function () {
579
- presenter.addListItem(model, '$', [5]);
572
+ model.addListItem('$', [5]);
580
573
  });
581
574
  it('adds the expected value at the end', function () {
582
575
  expect(model.fields).toEqual(expect.objectContaining({
@@ -612,7 +605,7 @@ describe('all', function () {
612
605
  });
613
606
  describe('remove first item', function () {
614
607
  beforeEach(function () {
615
- presenter.removeListItem(model, '$.0');
608
+ model.removeListItem('$.0');
616
609
  });
617
610
  it('updates the underlying value', function () {
618
611
  expect(model.value).toEqual([
@@ -635,7 +628,7 @@ describe('all', function () {
635
628
  });
636
629
  describe('remove second item', function () {
637
630
  beforeEach(function () {
638
- presenter.removeListItem(model, '$.1');
631
+ model.removeListItem('$.1');
639
632
  });
640
633
  it('updates the underlying value', function () {
641
634
  expect(model.value).toEqual([
@@ -656,6 +649,22 @@ describe('all', function () {
656
649
  });
657
650
  });
658
651
  });
652
+ describe('remove two items', function () {
653
+ beforeEach(function () {
654
+ model.removeListItem('$.0', '$.1');
655
+ });
656
+ it('updates the underlying value', function () {
657
+ expect(model.value).toEqual([7]);
658
+ });
659
+ it('updates the field values and errors', function () {
660
+ expect(model.fields).toEqual({
661
+ '$.0': expect.objectContaining({
662
+ value: '7',
663
+ error: 2,
664
+ }),
665
+ });
666
+ });
667
+ });
659
668
  });
660
669
  });
661
670
  // TODO record / object
@@ -669,12 +678,11 @@ describe('all', function () {
669
678
  $: adapterFromTwoWayConverter(new NullableToBooleanConverter(type, [1], null)),
670
679
  '$.*': integerToStringAdapter,
671
680
  };
672
- const presenter = new TestFormPresenter(type, adapters);
673
681
  let originalValue;
674
682
  let model;
675
683
  beforeEach(function () {
676
684
  originalValue = null;
677
- model = presenter.createModel(originalValue);
685
+ model = new FormModel(type, originalValue, adapters);
678
686
  });
679
687
  it('has the expected fields', function () {
680
688
  expect(model.fields).toEqual({
@@ -689,7 +697,7 @@ describe('all', function () {
689
697
  describe('setFieldValueAndValidate', function () {
690
698
  describe('success', function () {
691
699
  beforeEach(function () {
692
- presenter.setFieldValueAndValidate(model, '$', true);
700
+ model.setFieldValueAndValidate('$', true);
693
701
  });
694
702
  it('sets the underlying value', function () {
695
703
  expect(model.value).toEqual([1]);
@@ -717,13 +725,12 @@ describe('all', function () {
717
725
  '$.x:a': identityAdapter(0).narrow,
718
726
  '$.y:b': identityAdapter(false).narrow,
719
727
  };
720
- const presenter = new TestFormPresenter(type, adapters);
721
728
  describe('isValuePathActive', function () {
722
729
  describe('discriminator x', function () {
723
- const model = presenter.createModel({
730
+ const model = new FormModel(type, {
724
731
  d: 'x',
725
732
  a: 1,
726
- });
733
+ }, adapters);
727
734
  it.each([
728
735
  [
729
736
  '$',
@@ -738,15 +745,15 @@ describe('all', function () {
738
745
  false,
739
746
  ],
740
747
  ])('value path %s is active %s', function (path, expected) {
741
- const isValid = presenter.isValuePathActive(model, path);
748
+ const isValid = model.isValuePathActive(path);
742
749
  expect(isValid).toBe(expected);
743
750
  });
744
751
  });
745
752
  describe('discriminator y', function () {
746
- const model = presenter.createModel({
753
+ const model = new FormModel(type, {
747
754
  d: 'y',
748
755
  b: false,
749
- });
756
+ }, adapters);
750
757
  it.each([
751
758
  [
752
759
  '$',
@@ -761,7 +768,7 @@ describe('all', function () {
761
768
  true,
762
769
  ],
763
770
  ])('value path %s is active %s', function (path, expected) {
764
- const isValid = presenter.isValuePathActive(model, path);
771
+ const isValid = model.isValuePathActive(path);
765
772
  expect(isValid).toBe(expected);
766
773
  });
767
774
  });
@@ -774,12 +781,11 @@ describe('all', function () {
774
781
  $: integerToStringAdapter,
775
782
  '$.fake': booleanToBooleanAdapter,
776
783
  };
777
- const presenter = new TestFormPresenter(typeDef, converters);
778
784
  let originalValue;
779
785
  let model;
780
786
  beforeEach(function () {
781
787
  originalValue = 1;
782
- model = presenter.createModel(originalValue);
788
+ model = new FormModel(typeDef, originalValue, converters);
783
789
  });
784
790
  it('returns the default value for the fake field', function () {
785
791
  expect(model.fields['$.fake']).toEqual(expect.objectContaining({
@@ -788,7 +794,7 @@ describe('all', function () {
788
794
  });
789
795
  describe('setting fake field', function () {
790
796
  beforeEach(function () {
791
- presenter.setFieldValue(model, '$.fake', true);
797
+ model.setFieldValue('$.fake', true);
792
798
  });
793
799
  it('stores the new value', function () {
794
800
  expect(model.fields['$.fake']).toEqual(expect.objectContaining({
@@ -1,14 +1,14 @@
1
1
  import { type ToOfFieldAdapter } from './field_adapter';
2
- import { type FlattenedConvertedFieldsOf, type FormPresenter } from './form_presenter';
2
+ import { type FlattenedConvertedFieldsOf, type FormModel } from './form_model';
3
3
  /**
4
4
  * Used to extract the supported value paths from a presenter
5
5
  */
6
- export type ValuePathsOfPresenter<Presenter extends FormPresenter<any, any, any, any>> = Presenter extends FormPresenter<infer _1, infer _2, infer _3, infer ValuePathsToAdapters> ? keyof ValuePathsToAdapters : never;
6
+ export type ValuePathsOfModel<Presenter extends FormModel<any, any, any, any>> = Presenter extends FormModel<infer _1, infer _2, infer _3, infer ValuePathsToAdapters> ? keyof ValuePathsToAdapters : never;
7
7
  /**
8
8
  * Used to extract the render type (so the value that is passed to the view) of a given value path
9
9
  * from a presenter
10
10
  */
11
- export type ToValueOfPresenterValuePath<Presenter extends FormPresenter<any, any, any, any>, K extends ValuePathsOfPresenter<Presenter>> = Presenter extends FormPresenter<infer _1, infer _2, infer _3, infer ValuePathsToAdapters> ? ToOfFieldAdapter<ValuePathsToAdapters[K]> : never;
11
+ export type ToValueOfModelValuePath<Presenter extends FormModel<any, any, any, any>, K extends ValuePathsOfModel<Presenter>> = Presenter extends FormModel<infer _1, infer _2, infer _3, infer ValuePathsToAdapters> ? ToOfFieldAdapter<ValuePathsToAdapters[K]> : never;
12
12
  /**
13
13
  * Extracts the form fields from the presenter. The recommended way is to
14
14
  * define the form fields explicitly and use that type to enforce the types
@@ -16,4 +16,4 @@ export type ToValueOfPresenterValuePath<Presenter extends FormPresenter<any, any
16
16
  * is less typing, albeit at the cost of potentially getting type errors
17
17
  * reported a long way away from the source
18
18
  */
19
- export type FormFieldsOfPresenter<Presenter extends FormPresenter<any, any, any, any>> = Presenter extends FormPresenter<infer _1, infer _2, infer _3, infer ValuePathsToAdapters> ? FlattenedConvertedFieldsOf<ValuePathsToAdapters> : never;
19
+ export type FormFieldsOfModel<Presenter extends FormModel<any, any, any, any>> = Presenter extends FormModel<infer _1, infer _2, infer _3, infer ValuePathsToAdapters> ? FlattenedConvertedFieldsOf<ValuePathsToAdapters> : never;
package/.out/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export * from './core/mobx/field_adapter_builder';
3
3
  export * from './core/mobx/field_adapters_of_values';
4
4
  export * from './core/mobx/flattened_adapters_of_fields';
5
5
  export * from './core/mobx/form_fields_of_field_adapters';
6
- export * from './core/mobx/form_presenter';
6
+ export * from './core/mobx/form_model';
7
7
  export * from './core/mobx/hooks';
8
8
  export * from './core/mobx/merge_field_adapters_with_two_way_converter';
9
9
  export * from './core/mobx/merge_field_adapters_with_validators';
package/.out/index.js CHANGED
@@ -3,7 +3,7 @@ export * from './core/mobx/field_adapter_builder';
3
3
  export * from './core/mobx/field_adapters_of_values';
4
4
  export * from './core/mobx/flattened_adapters_of_fields';
5
5
  export * from './core/mobx/form_fields_of_field_adapters';
6
- export * from './core/mobx/form_presenter';
6
+ export * from './core/mobx/form_model';
7
7
  export * from './core/mobx/hooks';
8
8
  export * from './core/mobx/merge_field_adapters_with_two_way_converter';
9
9
  export * from './core/mobx/merge_field_adapters_with_validators';