@strictly/react-form 0.0.24 → 0.0.25

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.
@@ -7,12 +7,12 @@ $ tsup
7
7
  CLI Target: es6
8
8
  CJS Build start
9
9
  ESM Build start
10
- CJS dist/index.cjs 60.74 KB
11
- CJS ⚡️ Build success in 148ms
12
- ESM dist/index.js 56.72 KB
13
- ESM ⚡️ Build success in 148ms
10
+ CJS dist/index.cjs 61.91 KB
11
+ CJS ⚡️ Build success in 125ms
12
+ ESM dist/index.js 57.87 KB
13
+ ESM ⚡️ Build success in 146ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 31697ms
16
- DTS dist/index.d.cts 37.27 KB
17
- DTS dist/index.d.ts 37.27 KB
18
- Done in 32.89s.
15
+ DTS ⚡️ Build success in 31902ms
16
+ DTS dist/index.d.cts 37.37 KB
17
+ DTS dist/index.d.ts 37.37 KB
18
+ Done in 33.10s.
@@ -1,3 +1,3 @@
1
1
  yarn run v1.22.22
2
2
  $ tsc -b
3
- Done in 0.41s.
3
+ Done in 0.35s.
@@ -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.11s.
@@ -273,7 +273,7 @@ export abstract class FormModel<
273
273
  return this.synthesizeFieldByPaths(valuePath, typePath)
274
274
  }
275
275
 
276
- private synthesizeFieldByPaths(valuePath: keyof ValuePathsToAdapters, typePath: keyof TypePathsToAdapters) {
276
+ private getField(valuePath: keyof ValuePathsToAdapters, typePath: keyof TypePathsToAdapters) {
277
277
  const adapter = this.adapters[typePath]
278
278
  if (adapter == null) {
279
279
  // invalid path, which can happen
@@ -311,9 +311,37 @@ export abstract class FormModel<
311
311
  valuePath as string,
312
312
  context,
313
313
  )
314
- let error: unknown = undefined
315
314
  const displayedValue = fieldOverride != null ? fieldOverride[0] : value
315
+
316
+ return {
317
+ context,
318
+ convert,
319
+ create,
320
+ revert,
321
+ displayedValue,
322
+ // value,
323
+ required,
324
+ readonly,
325
+ defaultValue,
326
+ }
327
+ }
328
+
329
+ private synthesizeFieldByPaths(valuePath: keyof ValuePathsToAdapters, typePath: keyof TypePathsToAdapters) {
330
+ const field = this.getField(valuePath, typePath)
331
+ if (field == null) {
332
+ return
333
+ }
334
+ const {
335
+ context,
336
+ convert,
337
+ revert,
338
+ displayedValue,
339
+ required,
340
+ readonly,
341
+ defaultValue,
342
+ } = field
316
343
  const validation = this.validation[valuePath] ?? Validation.None
344
+ let error: unknown
317
345
  switch (validation) {
318
346
  case Validation.None:
319
347
  // skip validation
@@ -347,7 +375,7 @@ export abstract class FormModel<
347
375
  throw new UnreachableError(validation)
348
376
  }
349
377
  return {
350
- value: fieldOverride != null ? fieldOverride[0] : value,
378
+ value: displayedValue,
351
379
  error,
352
380
  readonly: readonly && !this.forceMutableFields,
353
381
  required,
@@ -646,6 +674,37 @@ export abstract class FormModel<
646
674
  return this.validation[valuePath] ?? Validation.None
647
675
  }
648
676
 
677
+ isDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean {
678
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
679
+ const typePath = valuePathToTypePath<ValueToTypePaths, keyof ValueToTypePaths>(
680
+ this.type,
681
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
682
+ valuePath as keyof ValueToTypePaths,
683
+ true,
684
+ ) as keyof TypePathsToAdapters
685
+ const field = this.getField(valuePath, typePath)
686
+
687
+ if (field == null) {
688
+ return false
689
+ }
690
+
691
+ const {
692
+ displayedValue,
693
+ convert,
694
+ context,
695
+ defaultValue,
696
+ } = field
697
+
698
+ const originalValue = valuePath in this.originalValues
699
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
700
+ ? this.originalValues[valuePath as string]
701
+ : defaultValue
702
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
703
+ const { value: originalDisplayedValue } = convert(originalValue, valuePath as string, context)
704
+ // TODO better comparisons, displayed values can still be complex
705
+ return (displayedValue !== originalDisplayedValue)
706
+ }
707
+
649
708
  validateField<K extends keyof ValuePathsToAdapters>(
650
709
  valuePath: K,
651
710
  validation: Validation = Validation.Always,
@@ -41,8 +41,8 @@ export function useDefaultMobxFormHooks<
41
41
  path: Path,
42
42
  value: ValueTypeOfField<F[Path]>,
43
43
  ) {
44
- // clear validation once there are no errors for the field
45
- model.setFieldValue<Path>(path, value)
44
+ const validation = Math.min(model.getValidation(path), Validation.Changed)
45
+ model.setFieldValue<Path>(path, value, validation)
46
46
  },
47
47
  [model],
48
48
  )
@@ -66,7 +66,8 @@ export function useDefaultMobxFormHooks<
66
66
  // (e.g. changing a discriminator)
67
67
  // TODO debounce?
68
68
  setTimeout(function () {
69
- if (model.isValuePathActive(path)) {
69
+ // only start validation if the user has changed the field
70
+ if (model.isValuePathActive(path) && model.isDirty(path)) {
70
71
  // further workaround to make sure we don't downgrade the existing validation
71
72
  model.validateField(path, Math.max(Validation.Changed, model.getValidation(path)))
72
73
  }
package/dist/index.cjs CHANGED
@@ -463,8 +463,7 @@ var FormModel = class {
463
463
  }
464
464
  return this.synthesizeFieldByPaths(valuePath, typePath);
465
465
  }
466
- synthesizeFieldByPaths(valuePath, typePath) {
467
- var _a;
466
+ getField(valuePath, typePath) {
468
467
  const adapter2 = this.adapters[typePath];
469
468
  if (adapter2 == null) {
470
469
  return;
@@ -492,9 +491,36 @@ var FormModel = class {
492
491
  valuePath,
493
492
  context
494
493
  );
495
- let error = void 0;
496
494
  const displayedValue = fieldOverride != null ? fieldOverride[0] : value;
495
+ return {
496
+ context,
497
+ convert,
498
+ create,
499
+ revert,
500
+ displayedValue,
501
+ // value,
502
+ required,
503
+ readonly,
504
+ defaultValue
505
+ };
506
+ }
507
+ synthesizeFieldByPaths(valuePath, typePath) {
508
+ var _a;
509
+ const field = this.getField(valuePath, typePath);
510
+ if (field == null) {
511
+ return;
512
+ }
513
+ const {
514
+ context,
515
+ convert,
516
+ revert,
517
+ displayedValue,
518
+ required,
519
+ readonly,
520
+ defaultValue
521
+ } = field;
497
522
  const validation = (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
523
+ let error;
498
524
  switch (validation) {
499
525
  case 0 /* None */:
500
526
  break;
@@ -524,7 +550,7 @@ var FormModel = class {
524
550
  throw new import_base2.UnreachableError(validation);
525
551
  }
526
552
  return {
527
- value: fieldOverride != null ? fieldOverride[0] : value,
553
+ value: displayedValue,
528
554
  error,
529
555
  readonly: readonly && !this.forceMutableFields,
530
556
  required
@@ -761,6 +787,27 @@ var FormModel = class {
761
787
  var _a;
762
788
  return (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
763
789
  }
790
+ isDirty(valuePath) {
791
+ const typePath = (0, import_define.valuePathToTypePath)(
792
+ this.type,
793
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
794
+ valuePath,
795
+ true
796
+ );
797
+ const field = this.getField(valuePath, typePath);
798
+ if (field == null) {
799
+ return false;
800
+ }
801
+ const {
802
+ displayedValue,
803
+ convert,
804
+ context,
805
+ defaultValue
806
+ } = field;
807
+ const originalValue = valuePath in this.originalValues ? this.originalValues[valuePath] : defaultValue;
808
+ const { value: originalDisplayedValue } = convert(originalValue, valuePath, context);
809
+ return displayedValue !== originalDisplayedValue;
810
+ }
764
811
  validateField(valuePath, validation = 2 /* Always */) {
765
812
  (0, import_mobx.runInAction)(() => {
766
813
  this.validation[valuePath] = validation;
@@ -802,7 +849,8 @@ function useDefaultMobxFormHooks(model, {
802
849
  } = {}) {
803
850
  const onFieldValueChange = (0, import_react.useCallback)(
804
851
  function(path, value) {
805
- model.setFieldValue(path, value);
852
+ const validation = Math.min(model.getValidation(path), 1 /* Changed */);
853
+ model.setFieldValue(path, value, validation);
806
854
  },
807
855
  [model]
808
856
  );
@@ -821,7 +869,7 @@ function useDefaultMobxFormHooks(model, {
821
869
  const onFieldBlur = (0, import_react.useCallback)(
822
870
  function(path) {
823
871
  setTimeout(function() {
824
- if (model.isValuePathActive(path)) {
872
+ if (model.isValuePathActive(path) && model.isDirty(path)) {
825
873
  model.validateField(path, Math.max(1 /* Changed */, model.getValidation(path)));
826
874
  }
827
875
  }, 100);
package/dist/index.d.cts CHANGED
@@ -142,6 +142,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
142
142
  get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>>;
143
143
  private get knownFields();
144
144
  private maybeSynthesizeFieldByValuePath;
145
+ private getField;
145
146
  private synthesizeFieldByPaths;
146
147
  getAccessorForValuePath(valuePath: keyof ValuePathsToAdapters): Accessor | undefined;
147
148
  get accessors(): Readonly<Record<string, Accessor>>;
@@ -157,6 +158,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
157
158
  clearAll(value: ValueOfType<T>): void;
158
159
  isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
159
160
  getValidation<K extends keyof ValuePathsToAdapters>(valuePath: K): Validation;
161
+ isDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
160
162
  validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, validation?: Validation): boolean;
161
163
  validateAll(validation?: Validation): boolean;
162
164
  }
package/dist/index.d.ts CHANGED
@@ -142,6 +142,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
142
142
  get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>>;
143
143
  private get knownFields();
144
144
  private maybeSynthesizeFieldByValuePath;
145
+ private getField;
145
146
  private synthesizeFieldByPaths;
146
147
  getAccessorForValuePath(valuePath: keyof ValuePathsToAdapters): Accessor | undefined;
147
148
  get accessors(): Readonly<Record<string, Accessor>>;
@@ -157,6 +158,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
157
158
  clearAll(value: ValueOfType<T>): void;
158
159
  isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
159
160
  getValidation<K extends keyof ValuePathsToAdapters>(valuePath: K): Validation;
161
+ isDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
160
162
  validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, validation?: Validation): boolean;
161
163
  validateAll(validation?: Validation): boolean;
162
164
  }
package/dist/index.js CHANGED
@@ -432,8 +432,7 @@ var FormModel = class {
432
432
  }
433
433
  return this.synthesizeFieldByPaths(valuePath, typePath);
434
434
  }
435
- synthesizeFieldByPaths(valuePath, typePath) {
436
- var _a;
435
+ getField(valuePath, typePath) {
437
436
  const adapter2 = this.adapters[typePath];
438
437
  if (adapter2 == null) {
439
438
  return;
@@ -461,9 +460,36 @@ var FormModel = class {
461
460
  valuePath,
462
461
  context
463
462
  );
464
- let error = void 0;
465
463
  const displayedValue = fieldOverride != null ? fieldOverride[0] : value;
464
+ return {
465
+ context,
466
+ convert,
467
+ create,
468
+ revert,
469
+ displayedValue,
470
+ // value,
471
+ required,
472
+ readonly,
473
+ defaultValue
474
+ };
475
+ }
476
+ synthesizeFieldByPaths(valuePath, typePath) {
477
+ var _a;
478
+ const field = this.getField(valuePath, typePath);
479
+ if (field == null) {
480
+ return;
481
+ }
482
+ const {
483
+ context,
484
+ convert,
485
+ revert,
486
+ displayedValue,
487
+ required,
488
+ readonly,
489
+ defaultValue
490
+ } = field;
466
491
  const validation = (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
492
+ let error;
467
493
  switch (validation) {
468
494
  case 0 /* None */:
469
495
  break;
@@ -493,7 +519,7 @@ var FormModel = class {
493
519
  throw new UnreachableError2(validation);
494
520
  }
495
521
  return {
496
- value: fieldOverride != null ? fieldOverride[0] : value,
522
+ value: displayedValue,
497
523
  error,
498
524
  readonly: readonly && !this.forceMutableFields,
499
525
  required
@@ -730,6 +756,27 @@ var FormModel = class {
730
756
  var _a;
731
757
  return (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
732
758
  }
759
+ isDirty(valuePath) {
760
+ const typePath = valuePathToTypePath(
761
+ this.type,
762
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
763
+ valuePath,
764
+ true
765
+ );
766
+ const field = this.getField(valuePath, typePath);
767
+ if (field == null) {
768
+ return false;
769
+ }
770
+ const {
771
+ displayedValue,
772
+ convert,
773
+ context,
774
+ defaultValue
775
+ } = field;
776
+ const originalValue = valuePath in this.originalValues ? this.originalValues[valuePath] : defaultValue;
777
+ const { value: originalDisplayedValue } = convert(originalValue, valuePath, context);
778
+ return displayedValue !== originalDisplayedValue;
779
+ }
733
780
  validateField(valuePath, validation = 2 /* Always */) {
734
781
  runInAction(() => {
735
782
  this.validation[valuePath] = validation;
@@ -773,7 +820,8 @@ function useDefaultMobxFormHooks(model, {
773
820
  } = {}) {
774
821
  const onFieldValueChange = useCallback(
775
822
  function(path, value) {
776
- model.setFieldValue(path, value);
823
+ const validation = Math.min(model.getValidation(path), 1 /* Changed */);
824
+ model.setFieldValue(path, value, validation);
777
825
  },
778
826
  [model]
779
827
  );
@@ -792,7 +840,7 @@ function useDefaultMobxFormHooks(model, {
792
840
  const onFieldBlur = useCallback(
793
841
  function(path) {
794
842
  setTimeout(function() {
795
- if (model.isValuePathActive(path)) {
843
+ if (model.isValuePathActive(path) && model.isDirty(path)) {
796
844
  model.validateField(path, Math.max(1 /* Changed */, model.getValidation(path)));
797
845
  }
798
846
  }, 100);
package/package.json CHANGED
@@ -72,7 +72,7 @@
72
72
  "test:watch": "vitest"
73
73
  },
74
74
  "type": "module",
75
- "version": "0.0.24",
75
+ "version": "0.0.25",
76
76
  "exports": {
77
77
  ".": {
78
78
  "import": {