@strictly/react-form 0.0.25 → 0.0.26
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.
- package/.out/core/mobx/form_model.d.ts +13 -1
- package/.out/core/mobx/form_model.js +91 -37
- package/.out/core/mobx/hooks.js +2 -2
- package/.out/tsconfig.tsbuildinfo +1 -1
- package/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-check-types.log +1 -1
- package/core/mobx/form_model.ts +92 -30
- package/core/mobx/hooks.tsx +2 -2
- package/dist/index.cjs +75 -29
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +76 -29
- package/package.json +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -7,12 +7,12 @@ $ tsup
|
|
|
7
7
|
[34mCLI[39m Target: es6
|
|
8
8
|
[34mCJS[39m Build start
|
|
9
9
|
[34mESM[39m Build start
|
|
10
|
-
[
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
10
|
+
[32mESM[39m [1mdist/index.js [22m[32m59.53 KB[39m
|
|
11
|
+
[32mESM[39m ⚡️ Build success in 105ms
|
|
12
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m63.62 KB[39m
|
|
13
|
+
[32mCJS[39m ⚡️ Build success in 110ms
|
|
14
14
|
[34mDTS[39m Build start
|
|
15
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
-
[32mDTS[39m [1mdist/index.d.cts [22m[
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
18
|
-
Done in
|
|
15
|
+
[32mDTS[39m ⚡️ Build success in 30914ms
|
|
16
|
+
[32mDTS[39m [1mdist/index.d.cts [22m[32m38.03 KB[39m
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m38.03 KB[39m
|
|
18
|
+
Done in 32.12s.
|
package/core/mobx/form_model.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
type Accessor,
|
|
14
14
|
type AnyValueType,
|
|
15
|
+
equals,
|
|
15
16
|
flattenAccessorsOfType,
|
|
16
17
|
type FlattenedValuesOfType,
|
|
17
18
|
flattenTypesOfType,
|
|
@@ -88,6 +89,12 @@ type FlattenedFieldOverrides<
|
|
|
88
89
|
>
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
type FlattenedErrorOverrides<
|
|
93
|
+
ValuePathsToAdapters extends Readonly<Record<string, FieldAdapter>>,
|
|
94
|
+
> = {
|
|
95
|
+
-readonly [K in keyof ValuePathsToAdapters]?: ErrorOfFieldAdapter<ValuePathsToAdapters[K]>
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
export enum Validation {
|
|
92
99
|
None = 0,
|
|
93
100
|
Changed = 1,
|
|
@@ -144,6 +151,8 @@ export abstract class FormModel<
|
|
|
144
151
|
@observable.shallow
|
|
145
152
|
accessor fieldOverrides: FlattenedFieldOverrides<ValuePathsToAdapters>
|
|
146
153
|
@observable.shallow
|
|
154
|
+
accessor errorOverrides: FlattenedErrorOverrides<ValuePathsToAdapters> = {}
|
|
155
|
+
@observable.shallow
|
|
147
156
|
accessor validation: FlattenedValidation<ValuePathsToAdapters> = {}
|
|
148
157
|
|
|
149
158
|
private readonly flattenedTypeDefs: Readonly<Record<string, Type>>
|
|
@@ -341,39 +350,42 @@ export abstract class FormModel<
|
|
|
341
350
|
defaultValue,
|
|
342
351
|
} = field
|
|
343
352
|
const validation = this.validation[valuePath] ?? Validation.None
|
|
344
|
-
let error: unknown
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
353
|
+
let error: unknown = this.errorOverrides[valuePath]
|
|
354
|
+
if (error == null) {
|
|
355
|
+
switch (validation) {
|
|
356
|
+
case Validation.None:
|
|
357
|
+
// skip validation
|
|
358
|
+
break
|
|
359
|
+
case Validation.Changed:
|
|
360
|
+
if (revert != null) {
|
|
361
|
+
const originalValue = valuePath in this.originalValues
|
|
362
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
363
|
+
? this.originalValues[valuePath as string]
|
|
364
|
+
: defaultValue
|
|
352
365
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
366
|
+
const { value: originalDisplayedValue } = convert(originalValue, valuePath as string, context)
|
|
367
|
+
// TODO better comparisons, displayed values can still be complex
|
|
368
|
+
if (displayedValue !== originalDisplayedValue) {
|
|
369
|
+
const revertResult = revert(displayedValue, valuePath, context)
|
|
370
|
+
if (revertResult?.type === UnreliableFieldConversionType.Failure) {
|
|
371
|
+
;({ error } = revertResult)
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
break
|
|
376
|
+
case Validation.Always:
|
|
377
|
+
{
|
|
378
|
+
const revertResult = revert?.(displayedValue, valuePath, context)
|
|
360
379
|
if (revertResult?.type === UnreliableFieldConversionType.Failure) {
|
|
361
380
|
;({ error } = revertResult)
|
|
362
381
|
}
|
|
363
382
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const revertResult = revert?.(displayedValue, valuePath, context)
|
|
369
|
-
if (revertResult?.type === UnreliableFieldConversionType.Failure) {
|
|
370
|
-
;({ error } = revertResult)
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
break
|
|
374
|
-
default:
|
|
375
|
-
throw new UnreachableError(validation)
|
|
383
|
+
break
|
|
384
|
+
default:
|
|
385
|
+
throw new UnreachableError(validation)
|
|
386
|
+
}
|
|
376
387
|
}
|
|
388
|
+
|
|
377
389
|
return {
|
|
378
390
|
value: displayedValue,
|
|
379
391
|
error,
|
|
@@ -414,6 +426,14 @@ export abstract class FormModel<
|
|
|
414
426
|
)
|
|
415
427
|
}
|
|
416
428
|
|
|
429
|
+
@computed
|
|
430
|
+
get dirty() {
|
|
431
|
+
return Object.keys(this.accessors).some((valuePath) => {
|
|
432
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
433
|
+
return this.isFieldDirty(valuePath as keyof ValuePathsToAdapters)
|
|
434
|
+
})
|
|
435
|
+
}
|
|
436
|
+
|
|
417
437
|
typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K] {
|
|
418
438
|
return valuePathToTypePath<ValueToTypePaths, K>(this.type, valuePath, true)
|
|
419
439
|
}
|
|
@@ -602,6 +622,7 @@ export abstract class FormModel<
|
|
|
602
622
|
const accessor = this.getAccessorForValuePath(valuePath)
|
|
603
623
|
return runInAction(() => {
|
|
604
624
|
this.fieldOverrides[valuePath] = [value]
|
|
625
|
+
delete this.errorOverrides[valuePath]
|
|
605
626
|
if (validation != null) {
|
|
606
627
|
this.validation[valuePath] = validation
|
|
607
628
|
}
|
|
@@ -620,11 +641,30 @@ export abstract class FormModel<
|
|
|
620
641
|
})
|
|
621
642
|
}
|
|
622
643
|
|
|
644
|
+
/**
|
|
645
|
+
* Forces an error onto a field. Error will be removed if the field value changes
|
|
646
|
+
* @param valuePath the field to display an error for
|
|
647
|
+
* @param error the error to display
|
|
648
|
+
*/
|
|
649
|
+
overrideFieldError<K extends keyof ValuePathsToAdapters>(
|
|
650
|
+
valuePath: K,
|
|
651
|
+
error?: ErrorOfFieldAdapter<ValuePathsToAdapters[K]>,
|
|
652
|
+
) {
|
|
653
|
+
runInAction(() => {
|
|
654
|
+
if (error) {
|
|
655
|
+
this.errorOverrides[valuePath] = error
|
|
656
|
+
} else {
|
|
657
|
+
delete this.errorOverrides[valuePath]
|
|
658
|
+
}
|
|
659
|
+
})
|
|
660
|
+
}
|
|
661
|
+
|
|
623
662
|
clearFieldError<K extends keyof ValuePathsToAdapters>(valuePath: K) {
|
|
624
663
|
const fieldOverride = this.fieldOverrides[valuePath]
|
|
625
664
|
if (fieldOverride != null) {
|
|
626
665
|
runInAction(() => {
|
|
627
666
|
delete this.validation[valuePath]
|
|
667
|
+
delete this.errorOverrides[valuePath]
|
|
628
668
|
})
|
|
629
669
|
}
|
|
630
670
|
}
|
|
@@ -651,6 +691,7 @@ export abstract class FormModel<
|
|
|
651
691
|
runInAction(() => {
|
|
652
692
|
this.fieldOverrides[key] = [displayValue]
|
|
653
693
|
delete this.validation[key]
|
|
694
|
+
delete this.errorOverrides[key]
|
|
654
695
|
})
|
|
655
696
|
}
|
|
656
697
|
|
|
@@ -659,6 +700,7 @@ export abstract class FormModel<
|
|
|
659
700
|
this.validation = {}
|
|
660
701
|
// TODO this isn't correct, should reload from value
|
|
661
702
|
this.fieldOverrides = {}
|
|
703
|
+
this.errorOverrides = {}
|
|
662
704
|
this.value = mobxCopy(this.type, value)
|
|
663
705
|
})
|
|
664
706
|
}
|
|
@@ -674,7 +716,7 @@ export abstract class FormModel<
|
|
|
674
716
|
return this.validation[valuePath] ?? Validation.None
|
|
675
717
|
}
|
|
676
718
|
|
|
677
|
-
|
|
719
|
+
isFieldDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean {
|
|
678
720
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
679
721
|
const typePath = valuePathToTypePath<ValueToTypePaths, keyof ValueToTypePaths>(
|
|
680
722
|
this.type,
|
|
@@ -691,18 +733,33 @@ export abstract class FormModel<
|
|
|
691
733
|
const {
|
|
692
734
|
displayedValue,
|
|
693
735
|
convert,
|
|
736
|
+
revert,
|
|
694
737
|
context,
|
|
695
738
|
defaultValue,
|
|
696
739
|
} = field
|
|
697
740
|
|
|
741
|
+
// if either the display value, or the stored value, match the original, then assume it's not dirty
|
|
698
742
|
const originalValue = valuePath in this.originalValues
|
|
699
743
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
700
744
|
? this.originalValues[valuePath as string]
|
|
701
745
|
: defaultValue
|
|
746
|
+
if (revert != null) {
|
|
747
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
748
|
+
const typeDef = this.flattenedTypeDefs[typePath as string]
|
|
749
|
+
const {
|
|
750
|
+
value,
|
|
751
|
+
type,
|
|
752
|
+
} = revert(displayedValue, valuePath, context)
|
|
753
|
+
if (type === UnreliableFieldConversionType.Success) {
|
|
754
|
+
if (equals(typeDef, originalValue, value)) {
|
|
755
|
+
return false
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
702
759
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
703
760
|
const { value: originalDisplayedValue } = convert(originalValue, valuePath as string, context)
|
|
704
|
-
//
|
|
705
|
-
return
|
|
761
|
+
// try to compare the displayed values directly if we can't revert the displayed value
|
|
762
|
+
return displayedValue !== originalDisplayedValue
|
|
706
763
|
}
|
|
707
764
|
|
|
708
765
|
validateField<K extends keyof ValuePathsToAdapters>(
|
|
@@ -711,6 +768,7 @@ export abstract class FormModel<
|
|
|
711
768
|
): boolean {
|
|
712
769
|
runInAction(() => {
|
|
713
770
|
this.validation[valuePath] = validation
|
|
771
|
+
delete this.errorOverrides[valuePath]
|
|
714
772
|
})
|
|
715
773
|
return this.fields[valuePath].error == null
|
|
716
774
|
}
|
|
@@ -732,4 +790,8 @@ export abstract class FormModel<
|
|
|
732
790
|
},
|
|
733
791
|
)
|
|
734
792
|
}
|
|
793
|
+
|
|
794
|
+
validateSubmit() {
|
|
795
|
+
return this.validateAll()
|
|
796
|
+
}
|
|
735
797
|
}
|
package/core/mobx/hooks.tsx
CHANGED
|
@@ -67,7 +67,7 @@ export function useDefaultMobxFormHooks<
|
|
|
67
67
|
// TODO debounce?
|
|
68
68
|
setTimeout(function () {
|
|
69
69
|
// only start validation if the user has changed the field
|
|
70
|
-
if (model.isValuePathActive(path) && model.
|
|
70
|
+
if (model.isValuePathActive(path) && model.isFieldDirty(path)) {
|
|
71
71
|
// further workaround to make sure we don't downgrade the existing validation
|
|
72
72
|
model.validateField(path, Math.max(Validation.Changed, model.getValidation(path)))
|
|
73
73
|
}
|
|
@@ -78,7 +78,7 @@ export function useDefaultMobxFormHooks<
|
|
|
78
78
|
|
|
79
79
|
const onFormSubmit = useCallback(
|
|
80
80
|
function () {
|
|
81
|
-
if (model.
|
|
81
|
+
if (model.validateSubmit()) {
|
|
82
82
|
onValidFormSubmit?.(model.value)
|
|
83
83
|
}
|
|
84
84
|
},
|
package/dist/index.cjs
CHANGED
|
@@ -363,8 +363,8 @@ var Validation = /* @__PURE__ */ ((Validation2) => {
|
|
|
363
363
|
Validation2[Validation2["Always"] = 2] = "Always";
|
|
364
364
|
return Validation2;
|
|
365
365
|
})(Validation || {});
|
|
366
|
-
var _accessors_dec, _knownFields_dec, _fields_dec, _validation_dec, _fieldOverrides_dec, _value_dec, _init, _value, _fieldOverrides, _validation;
|
|
367
|
-
_value_dec = [import_mobx.observable.ref], _fieldOverrides_dec = [import_mobx.observable.shallow], _validation_dec = [import_mobx.observable.shallow], _fields_dec = [import_mobx.computed], _knownFields_dec = [import_mobx.computed], _accessors_dec = [import_mobx.computed];
|
|
366
|
+
var _dirty_dec, _accessors_dec, _knownFields_dec, _fields_dec, _validation_dec, _errorOverrides_dec, _fieldOverrides_dec, _value_dec, _init, _value, _fieldOverrides, _errorOverrides, _validation;
|
|
367
|
+
_value_dec = [import_mobx.observable.ref], _fieldOverrides_dec = [import_mobx.observable.shallow], _errorOverrides_dec = [import_mobx.observable.shallow], _validation_dec = [import_mobx.observable.shallow], _fields_dec = [import_mobx.computed], _knownFields_dec = [import_mobx.computed], _accessors_dec = [import_mobx.computed], _dirty_dec = [import_mobx.computed];
|
|
368
368
|
var FormModel = class {
|
|
369
369
|
constructor(type, originalValue, adapters, mode) {
|
|
370
370
|
this.type = type;
|
|
@@ -373,7 +373,8 @@ var FormModel = class {
|
|
|
373
373
|
__runInitializers(_init, 5, this);
|
|
374
374
|
__privateAdd(this, _value, __runInitializers(_init, 8, this)), __runInitializers(_init, 11, this);
|
|
375
375
|
__privateAdd(this, _fieldOverrides, __runInitializers(_init, 12, this)), __runInitializers(_init, 15, this);
|
|
376
|
-
__privateAdd(this,
|
|
376
|
+
__privateAdd(this, _errorOverrides, __runInitializers(_init, 16, this, {})), __runInitializers(_init, 19, this);
|
|
377
|
+
__privateAdd(this, _validation, __runInitializers(_init, 20, this, {})), __runInitializers(_init, 23, this);
|
|
377
378
|
__publicField(this, "flattenedTypeDefs");
|
|
378
379
|
// cannot be type safe
|
|
379
380
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -520,34 +521,36 @@ var FormModel = class {
|
|
|
520
521
|
defaultValue
|
|
521
522
|
} = field;
|
|
522
523
|
const validation = (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
|
|
523
|
-
let error;
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
524
|
+
let error = this.errorOverrides[valuePath];
|
|
525
|
+
if (error == null) {
|
|
526
|
+
switch (validation) {
|
|
527
|
+
case 0 /* None */:
|
|
528
|
+
break;
|
|
529
|
+
case 1 /* Changed */:
|
|
530
|
+
if (revert != null) {
|
|
531
|
+
const originalValue = valuePath in this.originalValues ? this.originalValues[valuePath] : defaultValue;
|
|
532
|
+
const { value: originalDisplayedValue } = convert(originalValue, valuePath, context);
|
|
533
|
+
if (displayedValue !== originalDisplayedValue) {
|
|
534
|
+
const revertResult = revert(displayedValue, valuePath, context);
|
|
535
|
+
if ((revertResult == null ? void 0 : revertResult.type) === 1 /* Failure */) {
|
|
536
|
+
;
|
|
537
|
+
({ error } = revertResult);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
break;
|
|
542
|
+
case 2 /* Always */:
|
|
543
|
+
{
|
|
544
|
+
const revertResult = revert == null ? void 0 : revert(displayedValue, valuePath, context);
|
|
533
545
|
if ((revertResult == null ? void 0 : revertResult.type) === 1 /* Failure */) {
|
|
534
546
|
;
|
|
535
547
|
({ error } = revertResult);
|
|
536
548
|
}
|
|
537
549
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const revertResult = revert == null ? void 0 : revert(displayedValue, valuePath, context);
|
|
543
|
-
if ((revertResult == null ? void 0 : revertResult.type) === 1 /* Failure */) {
|
|
544
|
-
;
|
|
545
|
-
({ error } = revertResult);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
break;
|
|
549
|
-
default:
|
|
550
|
-
throw new import_base2.UnreachableError(validation);
|
|
550
|
+
break;
|
|
551
|
+
default:
|
|
552
|
+
throw new import_base2.UnreachableError(validation);
|
|
553
|
+
}
|
|
551
554
|
}
|
|
552
555
|
return {
|
|
553
556
|
value: displayedValue,
|
|
@@ -580,6 +583,11 @@ var FormModel = class {
|
|
|
580
583
|
valuePath
|
|
581
584
|
);
|
|
582
585
|
}
|
|
586
|
+
get dirty() {
|
|
587
|
+
return Object.keys(this.accessors).some((valuePath) => {
|
|
588
|
+
return this.isFieldDirty(valuePath);
|
|
589
|
+
});
|
|
590
|
+
}
|
|
583
591
|
typePath(valuePath) {
|
|
584
592
|
return (0, import_define.valuePathToTypePath)(this.type, valuePath, true);
|
|
585
593
|
}
|
|
@@ -725,6 +733,7 @@ var FormModel = class {
|
|
|
725
733
|
const accessor = this.getAccessorForValuePath(valuePath);
|
|
726
734
|
return (0, import_mobx.runInAction)(() => {
|
|
727
735
|
this.fieldOverrides[valuePath] = [value];
|
|
736
|
+
delete this.errorOverrides[valuePath];
|
|
728
737
|
if (validation != null) {
|
|
729
738
|
this.validation[valuePath] = validation;
|
|
730
739
|
}
|
|
@@ -742,11 +751,26 @@ var FormModel = class {
|
|
|
742
751
|
}
|
|
743
752
|
});
|
|
744
753
|
}
|
|
754
|
+
/**
|
|
755
|
+
* Forces an error onto a field. Error will be removed if the field value changes
|
|
756
|
+
* @param valuePath the field to display an error for
|
|
757
|
+
* @param error the error to display
|
|
758
|
+
*/
|
|
759
|
+
overrideFieldError(valuePath, error) {
|
|
760
|
+
(0, import_mobx.runInAction)(() => {
|
|
761
|
+
if (error) {
|
|
762
|
+
this.errorOverrides[valuePath] = error;
|
|
763
|
+
} else {
|
|
764
|
+
delete this.errorOverrides[valuePath];
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
}
|
|
745
768
|
clearFieldError(valuePath) {
|
|
746
769
|
const fieldOverride = this.fieldOverrides[valuePath];
|
|
747
770
|
if (fieldOverride != null) {
|
|
748
771
|
(0, import_mobx.runInAction)(() => {
|
|
749
772
|
delete this.validation[valuePath];
|
|
773
|
+
delete this.errorOverrides[valuePath];
|
|
750
774
|
});
|
|
751
775
|
}
|
|
752
776
|
}
|
|
@@ -769,12 +793,14 @@ var FormModel = class {
|
|
|
769
793
|
(0, import_mobx.runInAction)(() => {
|
|
770
794
|
this.fieldOverrides[key] = [displayValue];
|
|
771
795
|
delete this.validation[key];
|
|
796
|
+
delete this.errorOverrides[key];
|
|
772
797
|
});
|
|
773
798
|
}
|
|
774
799
|
clearAll(value) {
|
|
775
800
|
(0, import_mobx.runInAction)(() => {
|
|
776
801
|
this.validation = {};
|
|
777
802
|
this.fieldOverrides = {};
|
|
803
|
+
this.errorOverrides = {};
|
|
778
804
|
this.value = (0, import_define.mobxCopy)(this.type, value);
|
|
779
805
|
});
|
|
780
806
|
}
|
|
@@ -787,7 +813,7 @@ var FormModel = class {
|
|
|
787
813
|
var _a;
|
|
788
814
|
return (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
|
|
789
815
|
}
|
|
790
|
-
|
|
816
|
+
isFieldDirty(valuePath) {
|
|
791
817
|
const typePath = (0, import_define.valuePathToTypePath)(
|
|
792
818
|
this.type,
|
|
793
819
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
@@ -801,16 +827,30 @@ var FormModel = class {
|
|
|
801
827
|
const {
|
|
802
828
|
displayedValue,
|
|
803
829
|
convert,
|
|
830
|
+
revert,
|
|
804
831
|
context,
|
|
805
832
|
defaultValue
|
|
806
833
|
} = field;
|
|
807
834
|
const originalValue = valuePath in this.originalValues ? this.originalValues[valuePath] : defaultValue;
|
|
835
|
+
if (revert != null) {
|
|
836
|
+
const typeDef = this.flattenedTypeDefs[typePath];
|
|
837
|
+
const {
|
|
838
|
+
value,
|
|
839
|
+
type
|
|
840
|
+
} = revert(displayedValue, valuePath, context);
|
|
841
|
+
if (type === 0 /* Success */) {
|
|
842
|
+
if ((0, import_define.equals)(typeDef, originalValue, value)) {
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
808
847
|
const { value: originalDisplayedValue } = convert(originalValue, valuePath, context);
|
|
809
848
|
return displayedValue !== originalDisplayedValue;
|
|
810
849
|
}
|
|
811
850
|
validateField(valuePath, validation = 2 /* Always */) {
|
|
812
851
|
(0, import_mobx.runInAction)(() => {
|
|
813
852
|
this.validation[valuePath] = validation;
|
|
853
|
+
delete this.errorOverrides[valuePath];
|
|
814
854
|
});
|
|
815
855
|
return this.fields[valuePath].error == null;
|
|
816
856
|
}
|
|
@@ -828,17 +868,23 @@ var FormModel = class {
|
|
|
828
868
|
}
|
|
829
869
|
);
|
|
830
870
|
}
|
|
871
|
+
validateSubmit() {
|
|
872
|
+
return this.validateAll();
|
|
873
|
+
}
|
|
831
874
|
};
|
|
832
875
|
_init = __decoratorStart(null);
|
|
833
876
|
_value = new WeakMap();
|
|
834
877
|
_fieldOverrides = new WeakMap();
|
|
878
|
+
_errorOverrides = new WeakMap();
|
|
835
879
|
_validation = new WeakMap();
|
|
836
880
|
__decorateElement(_init, 4, "value", _value_dec, FormModel, _value);
|
|
837
881
|
__decorateElement(_init, 4, "fieldOverrides", _fieldOverrides_dec, FormModel, _fieldOverrides);
|
|
882
|
+
__decorateElement(_init, 4, "errorOverrides", _errorOverrides_dec, FormModel, _errorOverrides);
|
|
838
883
|
__decorateElement(_init, 4, "validation", _validation_dec, FormModel, _validation);
|
|
839
884
|
__decorateElement(_init, 2, "fields", _fields_dec, FormModel);
|
|
840
885
|
__decorateElement(_init, 2, "knownFields", _knownFields_dec, FormModel);
|
|
841
886
|
__decorateElement(_init, 2, "accessors", _accessors_dec, FormModel);
|
|
887
|
+
__decorateElement(_init, 2, "dirty", _dirty_dec, FormModel);
|
|
842
888
|
__decoratorMetadata(_init, FormModel);
|
|
843
889
|
|
|
844
890
|
// core/mobx/hooks.tsx
|
|
@@ -869,7 +915,7 @@ function useDefaultMobxFormHooks(model, {
|
|
|
869
915
|
const onFieldBlur = (0, import_react.useCallback)(
|
|
870
916
|
function(path) {
|
|
871
917
|
setTimeout(function() {
|
|
872
|
-
if (model.isValuePathActive(path) && model.
|
|
918
|
+
if (model.isValuePathActive(path) && model.isFieldDirty(path)) {
|
|
873
919
|
model.validateField(path, Math.max(1 /* Changed */, model.getValidation(path)));
|
|
874
920
|
}
|
|
875
921
|
}, 100);
|
|
@@ -878,7 +924,7 @@ function useDefaultMobxFormHooks(model, {
|
|
|
878
924
|
);
|
|
879
925
|
const onFormSubmit = (0, import_react.useCallback)(
|
|
880
926
|
function() {
|
|
881
|
-
if (model.
|
|
927
|
+
if (model.validateSubmit()) {
|
|
882
928
|
onValidFormSubmit == null ? void 0 : onValidFormSubmit(model.value);
|
|
883
929
|
}
|
|
884
930
|
},
|
package/dist/index.d.cts
CHANGED
|
@@ -112,6 +112,9 @@ type FieldOverride<V = any> = Maybe<V>;
|
|
|
112
112
|
type FlattenedFieldOverrides<ValuePathsToAdapters extends Readonly<Record<string, FieldAdapter>>> = {
|
|
113
113
|
-readonly [K in keyof ValuePathsToAdapters]?: FieldOverride<ToOfFieldAdapter<ValuePathsToAdapters[K]>>;
|
|
114
114
|
};
|
|
115
|
+
type FlattenedErrorOverrides<ValuePathsToAdapters extends Readonly<Record<string, FieldAdapter>>> = {
|
|
116
|
+
-readonly [K in keyof ValuePathsToAdapters]?: ErrorOfFieldAdapter<ValuePathsToAdapters[K]>;
|
|
117
|
+
};
|
|
115
118
|
declare enum Validation {
|
|
116
119
|
None = 0,
|
|
117
120
|
Changed = 1,
|
|
@@ -133,6 +136,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
133
136
|
protected readonly mode: FormMode;
|
|
134
137
|
accessor value: MobxValueOfType<T>;
|
|
135
138
|
accessor fieldOverrides: FlattenedFieldOverrides<ValuePathsToAdapters>;
|
|
139
|
+
accessor errorOverrides: FlattenedErrorOverrides<ValuePathsToAdapters>;
|
|
136
140
|
accessor validation: FlattenedValidation<ValuePathsToAdapters>;
|
|
137
141
|
private readonly flattenedTypeDefs;
|
|
138
142
|
private readonly originalValues;
|
|
@@ -148,19 +152,27 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
148
152
|
get accessors(): Readonly<Record<string, Accessor>>;
|
|
149
153
|
private maybeGetAdapterForValuePath;
|
|
150
154
|
private getAdapterForValuePath;
|
|
155
|
+
get dirty(): boolean;
|
|
151
156
|
typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K];
|
|
152
157
|
setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation): boolean;
|
|
153
158
|
addListItem<K extends keyof FlattenedListTypesOfType<T>>(valuePath: K, elementValue?: Maybe<ElementOfArray<FlattenedValuesOfType<T>[K]>>, index?: number): void;
|
|
154
159
|
removeListItem<K extends keyof FlattenedListTypesOfType<T>>(...elementValuePaths: readonly `${K}.${number}`[]): void;
|
|
155
160
|
private internalSetFieldValue;
|
|
161
|
+
/**
|
|
162
|
+
* Forces an error onto a field. Error will be removed if the field value changes
|
|
163
|
+
* @param valuePath the field to display an error for
|
|
164
|
+
* @param error the error to display
|
|
165
|
+
*/
|
|
166
|
+
overrideFieldError<K extends keyof ValuePathsToAdapters>(valuePath: K, error?: ErrorOfFieldAdapter<ValuePathsToAdapters[K]>): void;
|
|
156
167
|
clearFieldError<K extends keyof ValuePathsToAdapters>(valuePath: K): void;
|
|
157
168
|
clearFieldValue<K extends StringKeyOf<ValuePathsToAdapters>>(valuePath: K): void;
|
|
158
169
|
clearAll(value: ValueOfType<T>): void;
|
|
159
170
|
isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
160
171
|
getValidation<K extends keyof ValuePathsToAdapters>(valuePath: K): Validation;
|
|
161
|
-
|
|
172
|
+
isFieldDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
162
173
|
validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, validation?: Validation): boolean;
|
|
163
174
|
validateAll(validation?: Validation): boolean;
|
|
175
|
+
validateSubmit(): boolean;
|
|
164
176
|
}
|
|
165
177
|
|
|
166
178
|
type ValueOfModel<M extends FormModel<any, any, any, any, any>> = M extends FormModel<infer T, any, any, any, any> ? ValueOfType<ReadonlyTypeOfType<T>> : never;
|
package/dist/index.d.ts
CHANGED
|
@@ -112,6 +112,9 @@ type FieldOverride<V = any> = Maybe<V>;
|
|
|
112
112
|
type FlattenedFieldOverrides<ValuePathsToAdapters extends Readonly<Record<string, FieldAdapter>>> = {
|
|
113
113
|
-readonly [K in keyof ValuePathsToAdapters]?: FieldOverride<ToOfFieldAdapter<ValuePathsToAdapters[K]>>;
|
|
114
114
|
};
|
|
115
|
+
type FlattenedErrorOverrides<ValuePathsToAdapters extends Readonly<Record<string, FieldAdapter>>> = {
|
|
116
|
+
-readonly [K in keyof ValuePathsToAdapters]?: ErrorOfFieldAdapter<ValuePathsToAdapters[K]>;
|
|
117
|
+
};
|
|
115
118
|
declare enum Validation {
|
|
116
119
|
None = 0,
|
|
117
120
|
Changed = 1,
|
|
@@ -133,6 +136,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
133
136
|
protected readonly mode: FormMode;
|
|
134
137
|
accessor value: MobxValueOfType<T>;
|
|
135
138
|
accessor fieldOverrides: FlattenedFieldOverrides<ValuePathsToAdapters>;
|
|
139
|
+
accessor errorOverrides: FlattenedErrorOverrides<ValuePathsToAdapters>;
|
|
136
140
|
accessor validation: FlattenedValidation<ValuePathsToAdapters>;
|
|
137
141
|
private readonly flattenedTypeDefs;
|
|
138
142
|
private readonly originalValues;
|
|
@@ -148,19 +152,27 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
148
152
|
get accessors(): Readonly<Record<string, Accessor>>;
|
|
149
153
|
private maybeGetAdapterForValuePath;
|
|
150
154
|
private getAdapterForValuePath;
|
|
155
|
+
get dirty(): boolean;
|
|
151
156
|
typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K];
|
|
152
157
|
setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation): boolean;
|
|
153
158
|
addListItem<K extends keyof FlattenedListTypesOfType<T>>(valuePath: K, elementValue?: Maybe<ElementOfArray<FlattenedValuesOfType<T>[K]>>, index?: number): void;
|
|
154
159
|
removeListItem<K extends keyof FlattenedListTypesOfType<T>>(...elementValuePaths: readonly `${K}.${number}`[]): void;
|
|
155
160
|
private internalSetFieldValue;
|
|
161
|
+
/**
|
|
162
|
+
* Forces an error onto a field. Error will be removed if the field value changes
|
|
163
|
+
* @param valuePath the field to display an error for
|
|
164
|
+
* @param error the error to display
|
|
165
|
+
*/
|
|
166
|
+
overrideFieldError<K extends keyof ValuePathsToAdapters>(valuePath: K, error?: ErrorOfFieldAdapter<ValuePathsToAdapters[K]>): void;
|
|
156
167
|
clearFieldError<K extends keyof ValuePathsToAdapters>(valuePath: K): void;
|
|
157
168
|
clearFieldValue<K extends StringKeyOf<ValuePathsToAdapters>>(valuePath: K): void;
|
|
158
169
|
clearAll(value: ValueOfType<T>): void;
|
|
159
170
|
isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
160
171
|
getValidation<K extends keyof ValuePathsToAdapters>(valuePath: K): Validation;
|
|
161
|
-
|
|
172
|
+
isFieldDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
162
173
|
validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, validation?: Validation): boolean;
|
|
163
174
|
validateAll(validation?: Validation): boolean;
|
|
175
|
+
validateSubmit(): boolean;
|
|
164
176
|
}
|
|
165
177
|
|
|
166
178
|
type ValueOfModel<M extends FormModel<any, any, any, any, any>> = M extends FormModel<infer T, any, any, any, any> ? ValueOfType<ReadonlyTypeOfType<T>> : never;
|