@strictly/react-form 0.0.24 → 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 +14 -0
- package/.out/core/mobx/form_model.js +127 -36
- package/.out/core/mobx/hooks.js +5 -4
- package/.out/tsconfig.tsbuildinfo +1 -1
- package/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-check-types.log +1 -1
- package/.turbo/turbo-release$colon$exports.log +1 -1
- package/core/mobx/form_model.ts +150 -29
- package/core/mobx/hooks.tsx +5 -4
- package/dist/index.cjs +126 -32
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +127 -32
- package/package.json +1 -1
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;
|
|
@@ -142,23 +146,33 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
142
146
|
get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>>;
|
|
143
147
|
private get knownFields();
|
|
144
148
|
private maybeSynthesizeFieldByValuePath;
|
|
149
|
+
private getField;
|
|
145
150
|
private synthesizeFieldByPaths;
|
|
146
151
|
getAccessorForValuePath(valuePath: keyof ValuePathsToAdapters): Accessor | undefined;
|
|
147
152
|
get accessors(): Readonly<Record<string, Accessor>>;
|
|
148
153
|
private maybeGetAdapterForValuePath;
|
|
149
154
|
private getAdapterForValuePath;
|
|
155
|
+
get dirty(): boolean;
|
|
150
156
|
typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K];
|
|
151
157
|
setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation): boolean;
|
|
152
158
|
addListItem<K extends keyof FlattenedListTypesOfType<T>>(valuePath: K, elementValue?: Maybe<ElementOfArray<FlattenedValuesOfType<T>[K]>>, index?: number): void;
|
|
153
159
|
removeListItem<K extends keyof FlattenedListTypesOfType<T>>(...elementValuePaths: readonly `${K}.${number}`[]): void;
|
|
154
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;
|
|
155
167
|
clearFieldError<K extends keyof ValuePathsToAdapters>(valuePath: K): void;
|
|
156
168
|
clearFieldValue<K extends StringKeyOf<ValuePathsToAdapters>>(valuePath: K): void;
|
|
157
169
|
clearAll(value: ValueOfType<T>): void;
|
|
158
170
|
isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
159
171
|
getValidation<K extends keyof ValuePathsToAdapters>(valuePath: K): Validation;
|
|
172
|
+
isFieldDirty<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
160
173
|
validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, validation?: Validation): boolean;
|
|
161
174
|
validateAll(validation?: Validation): boolean;
|
|
175
|
+
validateSubmit(): boolean;
|
|
162
176
|
}
|
|
163
177
|
|
|
164
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.js
CHANGED
|
@@ -313,6 +313,7 @@ import {
|
|
|
313
313
|
UnreachableError as UnreachableError2
|
|
314
314
|
} from "@strictly/base";
|
|
315
315
|
import {
|
|
316
|
+
equals,
|
|
316
317
|
flattenAccessorsOfType,
|
|
317
318
|
flattenTypesOfType,
|
|
318
319
|
flattenValuesOfType,
|
|
@@ -332,8 +333,8 @@ var Validation = /* @__PURE__ */ ((Validation2) => {
|
|
|
332
333
|
Validation2[Validation2["Always"] = 2] = "Always";
|
|
333
334
|
return Validation2;
|
|
334
335
|
})(Validation || {});
|
|
335
|
-
var _accessors_dec, _knownFields_dec, _fields_dec, _validation_dec, _fieldOverrides_dec, _value_dec, _init, _value, _fieldOverrides, _validation;
|
|
336
|
-
_value_dec = [observable.ref], _fieldOverrides_dec = [observable.shallow], _validation_dec = [observable.shallow], _fields_dec = [computed], _knownFields_dec = [computed], _accessors_dec = [computed];
|
|
336
|
+
var _dirty_dec, _accessors_dec, _knownFields_dec, _fields_dec, _validation_dec, _errorOverrides_dec, _fieldOverrides_dec, _value_dec, _init, _value, _fieldOverrides, _errorOverrides, _validation;
|
|
337
|
+
_value_dec = [observable.ref], _fieldOverrides_dec = [observable.shallow], _errorOverrides_dec = [observable.shallow], _validation_dec = [observable.shallow], _fields_dec = [computed], _knownFields_dec = [computed], _accessors_dec = [computed], _dirty_dec = [computed];
|
|
337
338
|
var FormModel = class {
|
|
338
339
|
constructor(type, originalValue, adapters, mode) {
|
|
339
340
|
this.type = type;
|
|
@@ -342,7 +343,8 @@ var FormModel = class {
|
|
|
342
343
|
__runInitializers(_init, 5, this);
|
|
343
344
|
__privateAdd(this, _value, __runInitializers(_init, 8, this)), __runInitializers(_init, 11, this);
|
|
344
345
|
__privateAdd(this, _fieldOverrides, __runInitializers(_init, 12, this)), __runInitializers(_init, 15, this);
|
|
345
|
-
__privateAdd(this,
|
|
346
|
+
__privateAdd(this, _errorOverrides, __runInitializers(_init, 16, this, {})), __runInitializers(_init, 19, this);
|
|
347
|
+
__privateAdd(this, _validation, __runInitializers(_init, 20, this, {})), __runInitializers(_init, 23, this);
|
|
346
348
|
__publicField(this, "flattenedTypeDefs");
|
|
347
349
|
// cannot be type safe
|
|
348
350
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -432,8 +434,7 @@ var FormModel = class {
|
|
|
432
434
|
}
|
|
433
435
|
return this.synthesizeFieldByPaths(valuePath, typePath);
|
|
434
436
|
}
|
|
435
|
-
|
|
436
|
-
var _a;
|
|
437
|
+
getField(valuePath, typePath) {
|
|
437
438
|
const adapter2 = this.adapters[typePath];
|
|
438
439
|
if (adapter2 == null) {
|
|
439
440
|
return;
|
|
@@ -461,39 +462,68 @@ var FormModel = class {
|
|
|
461
462
|
valuePath,
|
|
462
463
|
context
|
|
463
464
|
);
|
|
464
|
-
let error = void 0;
|
|
465
465
|
const displayedValue = fieldOverride != null ? fieldOverride[0] : value;
|
|
466
|
+
return {
|
|
467
|
+
context,
|
|
468
|
+
convert,
|
|
469
|
+
create,
|
|
470
|
+
revert,
|
|
471
|
+
displayedValue,
|
|
472
|
+
// value,
|
|
473
|
+
required,
|
|
474
|
+
readonly,
|
|
475
|
+
defaultValue
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
synthesizeFieldByPaths(valuePath, typePath) {
|
|
479
|
+
var _a;
|
|
480
|
+
const field = this.getField(valuePath, typePath);
|
|
481
|
+
if (field == null) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const {
|
|
485
|
+
context,
|
|
486
|
+
convert,
|
|
487
|
+
revert,
|
|
488
|
+
displayedValue,
|
|
489
|
+
required,
|
|
490
|
+
readonly,
|
|
491
|
+
defaultValue
|
|
492
|
+
} = field;
|
|
466
493
|
const validation = (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
const
|
|
494
|
+
let error = this.errorOverrides[valuePath];
|
|
495
|
+
if (error == null) {
|
|
496
|
+
switch (validation) {
|
|
497
|
+
case 0 /* None */:
|
|
498
|
+
break;
|
|
499
|
+
case 1 /* Changed */:
|
|
500
|
+
if (revert != null) {
|
|
501
|
+
const originalValue = valuePath in this.originalValues ? this.originalValues[valuePath] : defaultValue;
|
|
502
|
+
const { value: originalDisplayedValue } = convert(originalValue, valuePath, context);
|
|
503
|
+
if (displayedValue !== originalDisplayedValue) {
|
|
504
|
+
const revertResult = revert(displayedValue, valuePath, context);
|
|
505
|
+
if ((revertResult == null ? void 0 : revertResult.type) === 1 /* Failure */) {
|
|
506
|
+
;
|
|
507
|
+
({ error } = revertResult);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
case 2 /* Always */:
|
|
513
|
+
{
|
|
514
|
+
const revertResult = revert == null ? void 0 : revert(displayedValue, valuePath, context);
|
|
476
515
|
if ((revertResult == null ? void 0 : revertResult.type) === 1 /* Failure */) {
|
|
477
516
|
;
|
|
478
517
|
({ error } = revertResult);
|
|
479
518
|
}
|
|
480
519
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const revertResult = revert == null ? void 0 : revert(displayedValue, valuePath, context);
|
|
486
|
-
if ((revertResult == null ? void 0 : revertResult.type) === 1 /* Failure */) {
|
|
487
|
-
;
|
|
488
|
-
({ error } = revertResult);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
break;
|
|
492
|
-
default:
|
|
493
|
-
throw new UnreachableError2(validation);
|
|
520
|
+
break;
|
|
521
|
+
default:
|
|
522
|
+
throw new UnreachableError2(validation);
|
|
523
|
+
}
|
|
494
524
|
}
|
|
495
525
|
return {
|
|
496
|
-
value:
|
|
526
|
+
value: displayedValue,
|
|
497
527
|
error,
|
|
498
528
|
readonly: readonly && !this.forceMutableFields,
|
|
499
529
|
required
|
|
@@ -523,6 +553,11 @@ var FormModel = class {
|
|
|
523
553
|
valuePath
|
|
524
554
|
);
|
|
525
555
|
}
|
|
556
|
+
get dirty() {
|
|
557
|
+
return Object.keys(this.accessors).some((valuePath) => {
|
|
558
|
+
return this.isFieldDirty(valuePath);
|
|
559
|
+
});
|
|
560
|
+
}
|
|
526
561
|
typePath(valuePath) {
|
|
527
562
|
return valuePathToTypePath(this.type, valuePath, true);
|
|
528
563
|
}
|
|
@@ -668,6 +703,7 @@ var FormModel = class {
|
|
|
668
703
|
const accessor = this.getAccessorForValuePath(valuePath);
|
|
669
704
|
return runInAction(() => {
|
|
670
705
|
this.fieldOverrides[valuePath] = [value];
|
|
706
|
+
delete this.errorOverrides[valuePath];
|
|
671
707
|
if (validation != null) {
|
|
672
708
|
this.validation[valuePath] = validation;
|
|
673
709
|
}
|
|
@@ -685,11 +721,26 @@ var FormModel = class {
|
|
|
685
721
|
}
|
|
686
722
|
});
|
|
687
723
|
}
|
|
724
|
+
/**
|
|
725
|
+
* Forces an error onto a field. Error will be removed if the field value changes
|
|
726
|
+
* @param valuePath the field to display an error for
|
|
727
|
+
* @param error the error to display
|
|
728
|
+
*/
|
|
729
|
+
overrideFieldError(valuePath, error) {
|
|
730
|
+
runInAction(() => {
|
|
731
|
+
if (error) {
|
|
732
|
+
this.errorOverrides[valuePath] = error;
|
|
733
|
+
} else {
|
|
734
|
+
delete this.errorOverrides[valuePath];
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
}
|
|
688
738
|
clearFieldError(valuePath) {
|
|
689
739
|
const fieldOverride = this.fieldOverrides[valuePath];
|
|
690
740
|
if (fieldOverride != null) {
|
|
691
741
|
runInAction(() => {
|
|
692
742
|
delete this.validation[valuePath];
|
|
743
|
+
delete this.errorOverrides[valuePath];
|
|
693
744
|
});
|
|
694
745
|
}
|
|
695
746
|
}
|
|
@@ -712,12 +763,14 @@ var FormModel = class {
|
|
|
712
763
|
runInAction(() => {
|
|
713
764
|
this.fieldOverrides[key] = [displayValue];
|
|
714
765
|
delete this.validation[key];
|
|
766
|
+
delete this.errorOverrides[key];
|
|
715
767
|
});
|
|
716
768
|
}
|
|
717
769
|
clearAll(value) {
|
|
718
770
|
runInAction(() => {
|
|
719
771
|
this.validation = {};
|
|
720
772
|
this.fieldOverrides = {};
|
|
773
|
+
this.errorOverrides = {};
|
|
721
774
|
this.value = mobxCopy(this.type, value);
|
|
722
775
|
});
|
|
723
776
|
}
|
|
@@ -730,9 +783,44 @@ var FormModel = class {
|
|
|
730
783
|
var _a;
|
|
731
784
|
return (_a = this.validation[valuePath]) != null ? _a : 0 /* None */;
|
|
732
785
|
}
|
|
786
|
+
isFieldDirty(valuePath) {
|
|
787
|
+
const typePath = valuePathToTypePath(
|
|
788
|
+
this.type,
|
|
789
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
790
|
+
valuePath,
|
|
791
|
+
true
|
|
792
|
+
);
|
|
793
|
+
const field = this.getField(valuePath, typePath);
|
|
794
|
+
if (field == null) {
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
const {
|
|
798
|
+
displayedValue,
|
|
799
|
+
convert,
|
|
800
|
+
revert,
|
|
801
|
+
context,
|
|
802
|
+
defaultValue
|
|
803
|
+
} = field;
|
|
804
|
+
const originalValue = valuePath in this.originalValues ? this.originalValues[valuePath] : defaultValue;
|
|
805
|
+
if (revert != null) {
|
|
806
|
+
const typeDef = this.flattenedTypeDefs[typePath];
|
|
807
|
+
const {
|
|
808
|
+
value,
|
|
809
|
+
type
|
|
810
|
+
} = revert(displayedValue, valuePath, context);
|
|
811
|
+
if (type === 0 /* Success */) {
|
|
812
|
+
if (equals(typeDef, originalValue, value)) {
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
const { value: originalDisplayedValue } = convert(originalValue, valuePath, context);
|
|
818
|
+
return displayedValue !== originalDisplayedValue;
|
|
819
|
+
}
|
|
733
820
|
validateField(valuePath, validation = 2 /* Always */) {
|
|
734
821
|
runInAction(() => {
|
|
735
822
|
this.validation[valuePath] = validation;
|
|
823
|
+
delete this.errorOverrides[valuePath];
|
|
736
824
|
});
|
|
737
825
|
return this.fields[valuePath].error == null;
|
|
738
826
|
}
|
|
@@ -750,17 +838,23 @@ var FormModel = class {
|
|
|
750
838
|
}
|
|
751
839
|
);
|
|
752
840
|
}
|
|
841
|
+
validateSubmit() {
|
|
842
|
+
return this.validateAll();
|
|
843
|
+
}
|
|
753
844
|
};
|
|
754
845
|
_init = __decoratorStart(null);
|
|
755
846
|
_value = new WeakMap();
|
|
756
847
|
_fieldOverrides = new WeakMap();
|
|
848
|
+
_errorOverrides = new WeakMap();
|
|
757
849
|
_validation = new WeakMap();
|
|
758
850
|
__decorateElement(_init, 4, "value", _value_dec, FormModel, _value);
|
|
759
851
|
__decorateElement(_init, 4, "fieldOverrides", _fieldOverrides_dec, FormModel, _fieldOverrides);
|
|
852
|
+
__decorateElement(_init, 4, "errorOverrides", _errorOverrides_dec, FormModel, _errorOverrides);
|
|
760
853
|
__decorateElement(_init, 4, "validation", _validation_dec, FormModel, _validation);
|
|
761
854
|
__decorateElement(_init, 2, "fields", _fields_dec, FormModel);
|
|
762
855
|
__decorateElement(_init, 2, "knownFields", _knownFields_dec, FormModel);
|
|
763
856
|
__decorateElement(_init, 2, "accessors", _accessors_dec, FormModel);
|
|
857
|
+
__decorateElement(_init, 2, "dirty", _dirty_dec, FormModel);
|
|
764
858
|
__decoratorMetadata(_init, FormModel);
|
|
765
859
|
|
|
766
860
|
// core/mobx/hooks.tsx
|
|
@@ -773,7 +867,8 @@ function useDefaultMobxFormHooks(model, {
|
|
|
773
867
|
} = {}) {
|
|
774
868
|
const onFieldValueChange = useCallback(
|
|
775
869
|
function(path, value) {
|
|
776
|
-
model.
|
|
870
|
+
const validation = Math.min(model.getValidation(path), 1 /* Changed */);
|
|
871
|
+
model.setFieldValue(path, value, validation);
|
|
777
872
|
},
|
|
778
873
|
[model]
|
|
779
874
|
);
|
|
@@ -792,7 +887,7 @@ function useDefaultMobxFormHooks(model, {
|
|
|
792
887
|
const onFieldBlur = useCallback(
|
|
793
888
|
function(path) {
|
|
794
889
|
setTimeout(function() {
|
|
795
|
-
if (model.isValuePathActive(path)) {
|
|
890
|
+
if (model.isValuePathActive(path) && model.isFieldDirty(path)) {
|
|
796
891
|
model.validateField(path, Math.max(1 /* Changed */, model.getValidation(path)));
|
|
797
892
|
}
|
|
798
893
|
}, 100);
|
|
@@ -801,7 +896,7 @@ function useDefaultMobxFormHooks(model, {
|
|
|
801
896
|
);
|
|
802
897
|
const onFormSubmit = useCallback(
|
|
803
898
|
function() {
|
|
804
|
-
if (model.
|
|
899
|
+
if (model.validateSubmit()) {
|
|
805
900
|
onValidFormSubmit == null ? void 0 : onValidFormSubmit(model.value);
|
|
806
901
|
}
|
|
807
902
|
},
|