@strictly/react-form 0.0.23 → 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.
- package/.out/core/mobx/form_model.d.ts +5 -1
- package/.out/core/mobx/form_model.js +51 -14
- package/.out/core/mobx/hooks.js +7 -4
- package/.out/core/mobx/specs/form_model.tests.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 +74 -16
- package/core/mobx/hooks.tsx +7 -4
- package/core/mobx/specs/form_model.tests.ts +2 -2
- package/dist/index.cjs +66 -17
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +66 -17
- 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
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m61.91 KB[39m
|
|
11
|
+
[32mCJS[39m ⚡️ Build success in 125ms
|
|
12
|
+
[32mESM[39m [1mdist/index.js [22m[32m57.87 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ Build success in 146ms
|
|
14
14
|
[34mDTS[39m Build start
|
|
15
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
-
[32mDTS[39m [1mdist/index.d.cts [22m[32m37.
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m37.
|
|
18
|
-
Done in
|
|
15
|
+
[32mDTS[39m ⚡️ Build success in 31902ms
|
|
16
|
+
[32mDTS[39m [1mdist/index.d.cts [22m[32m37.37 KB[39m
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m37.37 KB[39m
|
|
18
|
+
Done in 33.10s.
|
package/core/mobx/form_model.ts
CHANGED
|
@@ -89,6 +89,7 @@ type FlattenedFieldOverrides<
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
export enum Validation {
|
|
92
|
+
None = 0,
|
|
92
93
|
Changed = 1,
|
|
93
94
|
Always = 2,
|
|
94
95
|
}
|
|
@@ -211,7 +212,7 @@ export abstract class FormModel<
|
|
|
211
212
|
case 'edit':
|
|
212
213
|
return false
|
|
213
214
|
default:
|
|
214
|
-
|
|
215
|
+
throw new UnreachableError(this.mode)
|
|
215
216
|
}
|
|
216
217
|
}
|
|
217
218
|
|
|
@@ -272,7 +273,7 @@ export abstract class FormModel<
|
|
|
272
273
|
return this.synthesizeFieldByPaths(valuePath, typePath)
|
|
273
274
|
}
|
|
274
275
|
|
|
275
|
-
private
|
|
276
|
+
private getField(valuePath: keyof ValuePathsToAdapters, typePath: keyof TypePathsToAdapters) {
|
|
276
277
|
const adapter = this.adapters[typePath]
|
|
277
278
|
if (adapter == null) {
|
|
278
279
|
// invalid path, which can happen
|
|
@@ -310,12 +311,39 @@ export abstract class FormModel<
|
|
|
310
311
|
valuePath as string,
|
|
311
312
|
context,
|
|
312
313
|
)
|
|
313
|
-
// const error = this.errors[valuePath]
|
|
314
|
-
let error: unknown = undefined
|
|
315
314
|
const displayedValue = fieldOverride != null ? fieldOverride[0] : value
|
|
316
|
-
|
|
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
|
|
343
|
+
const validation = this.validation[valuePath] ?? Validation.None
|
|
344
|
+
let error: unknown
|
|
317
345
|
switch (validation) {
|
|
318
|
-
case
|
|
346
|
+
case Validation.None:
|
|
319
347
|
// skip validation
|
|
320
348
|
break
|
|
321
349
|
case Validation.Changed:
|
|
@@ -347,7 +375,7 @@ export abstract class FormModel<
|
|
|
347
375
|
throw new UnreachableError(validation)
|
|
348
376
|
}
|
|
349
377
|
return {
|
|
350
|
-
value:
|
|
378
|
+
value: displayedValue,
|
|
351
379
|
error,
|
|
352
380
|
readonly: readonly && !this.forceMutableFields,
|
|
353
381
|
required,
|
|
@@ -393,7 +421,7 @@ export abstract class FormModel<
|
|
|
393
421
|
setFieldValue<K extends keyof ValuePathsToAdapters>(
|
|
394
422
|
valuePath: K,
|
|
395
423
|
value: ToOfFieldAdapter<ValuePathsToAdapters[K]>,
|
|
396
|
-
validation
|
|
424
|
+
validation?: Validation,
|
|
397
425
|
): boolean {
|
|
398
426
|
return this.internalSetFieldValue(valuePath, value, validation)
|
|
399
427
|
}
|
|
@@ -563,7 +591,7 @@ export abstract class FormModel<
|
|
|
563
591
|
private internalSetFieldValue<K extends keyof ValuePathsToAdapters>(
|
|
564
592
|
valuePath: K,
|
|
565
593
|
value: ToOfFieldAdapter<ValuePathsToAdapters[K]>,
|
|
566
|
-
validation: Validation | undefined
|
|
594
|
+
validation: Validation | undefined,
|
|
567
595
|
): boolean {
|
|
568
596
|
const { revert } = this.getAdapterForValuePath(valuePath)
|
|
569
597
|
|
|
@@ -576,8 +604,6 @@ export abstract class FormModel<
|
|
|
576
604
|
this.fieldOverrides[valuePath] = [value]
|
|
577
605
|
if (validation != null) {
|
|
578
606
|
this.validation[valuePath] = validation
|
|
579
|
-
} else {
|
|
580
|
-
delete this.validation[valuePath]
|
|
581
607
|
}
|
|
582
608
|
switch (conversion.type) {
|
|
583
609
|
case UnreliableFieldConversionType.Failure:
|
|
@@ -644,12 +670,44 @@ export abstract class FormModel<
|
|
|
644
670
|
return keys.has(valuePath as string)
|
|
645
671
|
}
|
|
646
672
|
|
|
673
|
+
getValidation<K extends keyof ValuePathsToAdapters>(valuePath: K): Validation {
|
|
674
|
+
return this.validation[valuePath] ?? Validation.None
|
|
675
|
+
}
|
|
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
|
+
|
|
647
708
|
validateField<K extends keyof ValuePathsToAdapters>(
|
|
648
709
|
valuePath: K,
|
|
649
|
-
validation: Validation =
|
|
650
|
-
this.mode === 'create' ? Validation.Always : Validation.Changed,
|
|
651
|
-
this.validation[valuePath] ?? Validation.Changed,
|
|
652
|
-
),
|
|
710
|
+
validation: Validation = Validation.Always,
|
|
653
711
|
): boolean {
|
|
654
712
|
runInAction(() => {
|
|
655
713
|
this.validation[valuePath] = validation
|
|
@@ -657,7 +715,7 @@ export abstract class FormModel<
|
|
|
657
715
|
return this.fields[valuePath].error == null
|
|
658
716
|
}
|
|
659
717
|
|
|
660
|
-
validateAll(validation: Validation =
|
|
718
|
+
validateAll(validation: Validation = Validation.Always): boolean {
|
|
661
719
|
const accessors = toArray(this.accessors)
|
|
662
720
|
|
|
663
721
|
runInAction(() => {
|
package/core/mobx/hooks.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import type { ValueTypeOfField } from 'types/value_type_of_field'
|
|
9
9
|
import {
|
|
10
10
|
type FormModel,
|
|
11
|
+
Validation,
|
|
11
12
|
} from './form_model'
|
|
12
13
|
|
|
13
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -40,8 +41,8 @@ export function useDefaultMobxFormHooks<
|
|
|
40
41
|
path: Path,
|
|
41
42
|
value: ValueTypeOfField<F[Path]>,
|
|
42
43
|
) {
|
|
43
|
-
|
|
44
|
-
model.setFieldValue<Path>(path, value,
|
|
44
|
+
const validation = Math.min(model.getValidation(path), Validation.Changed)
|
|
45
|
+
model.setFieldValue<Path>(path, value, validation)
|
|
45
46
|
},
|
|
46
47
|
[model],
|
|
47
48
|
)
|
|
@@ -65,8 +66,10 @@ export function useDefaultMobxFormHooks<
|
|
|
65
66
|
// (e.g. changing a discriminator)
|
|
66
67
|
// TODO debounce?
|
|
67
68
|
setTimeout(function () {
|
|
68
|
-
if
|
|
69
|
-
|
|
69
|
+
// only start validation if the user has changed the field
|
|
70
|
+
if (model.isValuePathActive(path) && model.isDirty(path)) {
|
|
71
|
+
// further workaround to make sure we don't downgrade the existing validation
|
|
72
|
+
model.validateField(path, Math.max(Validation.Changed, model.getValidation(path)))
|
|
70
73
|
}
|
|
71
74
|
}, 100)
|
|
72
75
|
},
|
|
@@ -1267,8 +1267,8 @@ describe('all', function () {
|
|
|
1267
1267
|
expect(model.fields['$.n'].readonly).toBeTruthy()
|
|
1268
1268
|
})
|
|
1269
1269
|
|
|
1270
|
-
it('
|
|
1271
|
-
expect(model.validateAll()).
|
|
1270
|
+
it('fails validation with invalid, clean data', () => {
|
|
1271
|
+
expect(model.validateAll()).toBeFalsy()
|
|
1272
1272
|
})
|
|
1273
1273
|
|
|
1274
1274
|
it('fails validation with invalid, dirty data', () => {
|
package/dist/index.cjs
CHANGED
|
@@ -358,6 +358,7 @@ var import_base2 = require("@strictly/base");
|
|
|
358
358
|
var import_define = require("@strictly/define");
|
|
359
359
|
var import_mobx = require("mobx");
|
|
360
360
|
var Validation = /* @__PURE__ */ ((Validation2) => {
|
|
361
|
+
Validation2[Validation2["None"] = 0] = "None";
|
|
361
362
|
Validation2[Validation2["Changed"] = 1] = "Changed";
|
|
362
363
|
Validation2[Validation2["Always"] = 2] = "Always";
|
|
363
364
|
return Validation2;
|
|
@@ -412,7 +413,7 @@ var FormModel = class {
|
|
|
412
413
|
case "edit":
|
|
413
414
|
return false;
|
|
414
415
|
default:
|
|
415
|
-
|
|
416
|
+
throw new import_base2.UnreachableError(this.mode);
|
|
416
417
|
}
|
|
417
418
|
}
|
|
418
419
|
get fields() {
|
|
@@ -462,7 +463,7 @@ var FormModel = class {
|
|
|
462
463
|
}
|
|
463
464
|
return this.synthesizeFieldByPaths(valuePath, typePath);
|
|
464
465
|
}
|
|
465
|
-
|
|
466
|
+
getField(valuePath, typePath) {
|
|
466
467
|
const adapter2 = this.adapters[typePath];
|
|
467
468
|
if (adapter2 == null) {
|
|
468
469
|
return;
|
|
@@ -490,11 +491,38 @@ var FormModel = class {
|
|
|
490
491
|
valuePath,
|
|
491
492
|
context
|
|
492
493
|
);
|
|
493
|
-
let error = void 0;
|
|
494
494
|
const displayedValue = fieldOverride != null ? fieldOverride[0] : value;
|
|
495
|
-
|
|
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;
|
|
522
|
+
const validation = (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
|
|
523
|
+
let error;
|
|
496
524
|
switch (validation) {
|
|
497
|
-
case
|
|
525
|
+
case 0 /* None */:
|
|
498
526
|
break;
|
|
499
527
|
case 1 /* Changed */:
|
|
500
528
|
if (revert != null) {
|
|
@@ -522,7 +550,7 @@ var FormModel = class {
|
|
|
522
550
|
throw new import_base2.UnreachableError(validation);
|
|
523
551
|
}
|
|
524
552
|
return {
|
|
525
|
-
value:
|
|
553
|
+
value: displayedValue,
|
|
526
554
|
error,
|
|
527
555
|
readonly: readonly && !this.forceMutableFields,
|
|
528
556
|
required
|
|
@@ -555,7 +583,7 @@ var FormModel = class {
|
|
|
555
583
|
typePath(valuePath) {
|
|
556
584
|
return (0, import_define.valuePathToTypePath)(this.type, valuePath, true);
|
|
557
585
|
}
|
|
558
|
-
setFieldValue(valuePath, value, validation
|
|
586
|
+
setFieldValue(valuePath, value, validation) {
|
|
559
587
|
return this.internalSetFieldValue(valuePath, value, validation);
|
|
560
588
|
}
|
|
561
589
|
addListItem(valuePath, elementValue = null, index) {
|
|
@@ -699,8 +727,6 @@ var FormModel = class {
|
|
|
699
727
|
this.fieldOverrides[valuePath] = [value];
|
|
700
728
|
if (validation != null) {
|
|
701
729
|
this.validation[valuePath] = validation;
|
|
702
|
-
} else {
|
|
703
|
-
delete this.validation[valuePath];
|
|
704
730
|
}
|
|
705
731
|
switch (conversion.type) {
|
|
706
732
|
case 1 /* Failure */:
|
|
@@ -757,16 +783,38 @@ var FormModel = class {
|
|
|
757
783
|
const keys = new Set(Object.keys(values));
|
|
758
784
|
return keys.has(valuePath);
|
|
759
785
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
786
|
+
getValidation(valuePath) {
|
|
787
|
+
var _a;
|
|
788
|
+
return (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
|
|
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
|
+
}
|
|
811
|
+
validateField(valuePath, validation = 2 /* Always */) {
|
|
764
812
|
(0, import_mobx.runInAction)(() => {
|
|
765
813
|
this.validation[valuePath] = validation;
|
|
766
814
|
});
|
|
767
815
|
return this.fields[valuePath].error == null;
|
|
768
816
|
}
|
|
769
|
-
validateAll(validation =
|
|
817
|
+
validateAll(validation = 2 /* Always */) {
|
|
770
818
|
const accessors = (0, import_base2.toArray)(this.accessors);
|
|
771
819
|
(0, import_mobx.runInAction)(() => {
|
|
772
820
|
accessors.forEach(([valuePath]) => {
|
|
@@ -801,7 +849,8 @@ function useDefaultMobxFormHooks(model, {
|
|
|
801
849
|
} = {}) {
|
|
802
850
|
const onFieldValueChange = (0, import_react.useCallback)(
|
|
803
851
|
function(path, value) {
|
|
804
|
-
model.
|
|
852
|
+
const validation = Math.min(model.getValidation(path), 1 /* Changed */);
|
|
853
|
+
model.setFieldValue(path, value, validation);
|
|
805
854
|
},
|
|
806
855
|
[model]
|
|
807
856
|
);
|
|
@@ -820,8 +869,8 @@ function useDefaultMobxFormHooks(model, {
|
|
|
820
869
|
const onFieldBlur = (0, import_react.useCallback)(
|
|
821
870
|
function(path) {
|
|
822
871
|
setTimeout(function() {
|
|
823
|
-
if (model.isValuePathActive(path)) {
|
|
824
|
-
model.validateField(path);
|
|
872
|
+
if (model.isValuePathActive(path) && model.isDirty(path)) {
|
|
873
|
+
model.validateField(path, Math.max(1 /* Changed */, model.getValidation(path)));
|
|
825
874
|
}
|
|
826
875
|
}, 100);
|
|
827
876
|
},
|
package/dist/index.d.cts
CHANGED
|
@@ -113,6 +113,7 @@ type FlattenedFieldOverrides<ValuePathsToAdapters extends Readonly<Record<string
|
|
|
113
113
|
-readonly [K in keyof ValuePathsToAdapters]?: FieldOverride<ToOfFieldAdapter<ValuePathsToAdapters[K]>>;
|
|
114
114
|
};
|
|
115
115
|
declare enum Validation {
|
|
116
|
+
None = 0,
|
|
116
117
|
Changed = 1,
|
|
117
118
|
Always = 2
|
|
118
119
|
}
|
|
@@ -141,13 +142,14 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
141
142
|
get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>>;
|
|
142
143
|
private get knownFields();
|
|
143
144
|
private maybeSynthesizeFieldByValuePath;
|
|
145
|
+
private getField;
|
|
144
146
|
private synthesizeFieldByPaths;
|
|
145
147
|
getAccessorForValuePath(valuePath: keyof ValuePathsToAdapters): Accessor | undefined;
|
|
146
148
|
get accessors(): Readonly<Record<string, Accessor>>;
|
|
147
149
|
private maybeGetAdapterForValuePath;
|
|
148
150
|
private getAdapterForValuePath;
|
|
149
151
|
typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K];
|
|
150
|
-
setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation
|
|
152
|
+
setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation): boolean;
|
|
151
153
|
addListItem<K extends keyof FlattenedListTypesOfType<T>>(valuePath: K, elementValue?: Maybe<ElementOfArray<FlattenedValuesOfType<T>[K]>>, index?: number): void;
|
|
152
154
|
removeListItem<K extends keyof FlattenedListTypesOfType<T>>(...elementValuePaths: readonly `${K}.${number}`[]): void;
|
|
153
155
|
private internalSetFieldValue;
|
|
@@ -155,6 +157,8 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
155
157
|
clearFieldValue<K extends StringKeyOf<ValuePathsToAdapters>>(valuePath: K): void;
|
|
156
158
|
clearAll(value: ValueOfType<T>): void;
|
|
157
159
|
isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
160
|
+
getValidation<K extends keyof ValuePathsToAdapters>(valuePath: K): Validation;
|
|
161
|
+
isDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
158
162
|
validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, validation?: Validation): boolean;
|
|
159
163
|
validateAll(validation?: Validation): boolean;
|
|
160
164
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -113,6 +113,7 @@ type FlattenedFieldOverrides<ValuePathsToAdapters extends Readonly<Record<string
|
|
|
113
113
|
-readonly [K in keyof ValuePathsToAdapters]?: FieldOverride<ToOfFieldAdapter<ValuePathsToAdapters[K]>>;
|
|
114
114
|
};
|
|
115
115
|
declare enum Validation {
|
|
116
|
+
None = 0,
|
|
116
117
|
Changed = 1,
|
|
117
118
|
Always = 2
|
|
118
119
|
}
|
|
@@ -141,13 +142,14 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
141
142
|
get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>>;
|
|
142
143
|
private get knownFields();
|
|
143
144
|
private maybeSynthesizeFieldByValuePath;
|
|
145
|
+
private getField;
|
|
144
146
|
private synthesizeFieldByPaths;
|
|
145
147
|
getAccessorForValuePath(valuePath: keyof ValuePathsToAdapters): Accessor | undefined;
|
|
146
148
|
get accessors(): Readonly<Record<string, Accessor>>;
|
|
147
149
|
private maybeGetAdapterForValuePath;
|
|
148
150
|
private getAdapterForValuePath;
|
|
149
151
|
typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K];
|
|
150
|
-
setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation
|
|
152
|
+
setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation): boolean;
|
|
151
153
|
addListItem<K extends keyof FlattenedListTypesOfType<T>>(valuePath: K, elementValue?: Maybe<ElementOfArray<FlattenedValuesOfType<T>[K]>>, index?: number): void;
|
|
152
154
|
removeListItem<K extends keyof FlattenedListTypesOfType<T>>(...elementValuePaths: readonly `${K}.${number}`[]): void;
|
|
153
155
|
private internalSetFieldValue;
|
|
@@ -155,6 +157,8 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
155
157
|
clearFieldValue<K extends StringKeyOf<ValuePathsToAdapters>>(valuePath: K): void;
|
|
156
158
|
clearAll(value: ValueOfType<T>): void;
|
|
157
159
|
isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
160
|
+
getValidation<K extends keyof ValuePathsToAdapters>(valuePath: K): Validation;
|
|
161
|
+
isDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
158
162
|
validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, validation?: Validation): boolean;
|
|
159
163
|
validateAll(validation?: Validation): boolean;
|
|
160
164
|
}
|
package/dist/index.js
CHANGED
|
@@ -327,6 +327,7 @@ import {
|
|
|
327
327
|
runInAction
|
|
328
328
|
} from "mobx";
|
|
329
329
|
var Validation = /* @__PURE__ */ ((Validation2) => {
|
|
330
|
+
Validation2[Validation2["None"] = 0] = "None";
|
|
330
331
|
Validation2[Validation2["Changed"] = 1] = "Changed";
|
|
331
332
|
Validation2[Validation2["Always"] = 2] = "Always";
|
|
332
333
|
return Validation2;
|
|
@@ -381,7 +382,7 @@ var FormModel = class {
|
|
|
381
382
|
case "edit":
|
|
382
383
|
return false;
|
|
383
384
|
default:
|
|
384
|
-
|
|
385
|
+
throw new UnreachableError2(this.mode);
|
|
385
386
|
}
|
|
386
387
|
}
|
|
387
388
|
get fields() {
|
|
@@ -431,7 +432,7 @@ var FormModel = class {
|
|
|
431
432
|
}
|
|
432
433
|
return this.synthesizeFieldByPaths(valuePath, typePath);
|
|
433
434
|
}
|
|
434
|
-
|
|
435
|
+
getField(valuePath, typePath) {
|
|
435
436
|
const adapter2 = this.adapters[typePath];
|
|
436
437
|
if (adapter2 == null) {
|
|
437
438
|
return;
|
|
@@ -459,11 +460,38 @@ var FormModel = class {
|
|
|
459
460
|
valuePath,
|
|
460
461
|
context
|
|
461
462
|
);
|
|
462
|
-
let error = void 0;
|
|
463
463
|
const displayedValue = fieldOverride != null ? fieldOverride[0] : value;
|
|
464
|
-
|
|
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;
|
|
491
|
+
const validation = (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
|
|
492
|
+
let error;
|
|
465
493
|
switch (validation) {
|
|
466
|
-
case
|
|
494
|
+
case 0 /* None */:
|
|
467
495
|
break;
|
|
468
496
|
case 1 /* Changed */:
|
|
469
497
|
if (revert != null) {
|
|
@@ -491,7 +519,7 @@ var FormModel = class {
|
|
|
491
519
|
throw new UnreachableError2(validation);
|
|
492
520
|
}
|
|
493
521
|
return {
|
|
494
|
-
value:
|
|
522
|
+
value: displayedValue,
|
|
495
523
|
error,
|
|
496
524
|
readonly: readonly && !this.forceMutableFields,
|
|
497
525
|
required
|
|
@@ -524,7 +552,7 @@ var FormModel = class {
|
|
|
524
552
|
typePath(valuePath) {
|
|
525
553
|
return valuePathToTypePath(this.type, valuePath, true);
|
|
526
554
|
}
|
|
527
|
-
setFieldValue(valuePath, value, validation
|
|
555
|
+
setFieldValue(valuePath, value, validation) {
|
|
528
556
|
return this.internalSetFieldValue(valuePath, value, validation);
|
|
529
557
|
}
|
|
530
558
|
addListItem(valuePath, elementValue = null, index) {
|
|
@@ -668,8 +696,6 @@ var FormModel = class {
|
|
|
668
696
|
this.fieldOverrides[valuePath] = [value];
|
|
669
697
|
if (validation != null) {
|
|
670
698
|
this.validation[valuePath] = validation;
|
|
671
|
-
} else {
|
|
672
|
-
delete this.validation[valuePath];
|
|
673
699
|
}
|
|
674
700
|
switch (conversion.type) {
|
|
675
701
|
case 1 /* Failure */:
|
|
@@ -726,16 +752,38 @@ var FormModel = class {
|
|
|
726
752
|
const keys = new Set(Object.keys(values));
|
|
727
753
|
return keys.has(valuePath);
|
|
728
754
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
755
|
+
getValidation(valuePath) {
|
|
756
|
+
var _a;
|
|
757
|
+
return (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
|
|
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
|
+
}
|
|
780
|
+
validateField(valuePath, validation = 2 /* Always */) {
|
|
733
781
|
runInAction(() => {
|
|
734
782
|
this.validation[valuePath] = validation;
|
|
735
783
|
});
|
|
736
784
|
return this.fields[valuePath].error == null;
|
|
737
785
|
}
|
|
738
|
-
validateAll(validation =
|
|
786
|
+
validateAll(validation = 2 /* Always */) {
|
|
739
787
|
const accessors = toArray(this.accessors);
|
|
740
788
|
runInAction(() => {
|
|
741
789
|
accessors.forEach(([valuePath]) => {
|
|
@@ -772,7 +820,8 @@ function useDefaultMobxFormHooks(model, {
|
|
|
772
820
|
} = {}) {
|
|
773
821
|
const onFieldValueChange = useCallback(
|
|
774
822
|
function(path, value) {
|
|
775
|
-
model.
|
|
823
|
+
const validation = Math.min(model.getValidation(path), 1 /* Changed */);
|
|
824
|
+
model.setFieldValue(path, value, validation);
|
|
776
825
|
},
|
|
777
826
|
[model]
|
|
778
827
|
);
|
|
@@ -791,8 +840,8 @@ function useDefaultMobxFormHooks(model, {
|
|
|
791
840
|
const onFieldBlur = useCallback(
|
|
792
841
|
function(path) {
|
|
793
842
|
setTimeout(function() {
|
|
794
|
-
if (model.isValuePathActive(path)) {
|
|
795
|
-
model.validateField(path);
|
|
843
|
+
if (model.isValuePathActive(path) && model.isDirty(path)) {
|
|
844
|
+
model.validateField(path, Math.max(1 /* Changed */, model.getValidation(path)));
|
|
796
845
|
}
|
|
797
846
|
}, 100);
|
|
798
847
|
},
|