@strictly/react-form 0.0.16 → 0.0.17
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 +6 -2
- package/.out/core/mobx/form_model.js +53 -22
- package/.out/core/mobx/specs/form_model.tests.js +62 -12
- package/.out/core/props.d.ts +2 -0
- package/.out/mantine/hooks.js +1 -1
- 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 +49 -23
- package/core/mobx/specs/form_model.tests.ts +103 -0
- package/core/props.ts +4 -0
- package/dist/index.cjs +44 -22
- package/dist/index.d.cts +20 -15
- package/dist/index.d.ts +20 -15
- package/dist/index.js +44 -22
- package/mantine/hooks.tsx +1 -1
- 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[32m62.28 KB[39m
|
|
11
|
+
[32mCJS[39m ⚡️ Build success in 117ms
|
|
12
|
+
[32mESM[39m [1mdist/index.js [22m[32m58.27 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ Build success in 140ms
|
|
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 10.
|
|
15
|
+
[32mDTS[39m ⚡️ Build success in 9749ms
|
|
16
|
+
[32mDTS[39m [1mdist/index.d.cts [22m[32m38.08 KB[39m
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m38.08 KB[39m
|
|
18
|
+
Done in 10.88s.
|
package/core/mobx/form_model.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type ValueOfType,
|
|
27
27
|
valuePathToTypePath,
|
|
28
28
|
} from '@strictly/define'
|
|
29
|
+
import { type FormMode } from 'core/props'
|
|
29
30
|
import {
|
|
30
31
|
computed,
|
|
31
32
|
observable,
|
|
@@ -142,10 +143,11 @@ export abstract class FormModel<
|
|
|
142
143
|
|
|
143
144
|
constructor(
|
|
144
145
|
readonly type: T,
|
|
145
|
-
|
|
146
|
+
private readonly originalValue: ValueOfType<ReadonlyTypeOfType<T>>,
|
|
146
147
|
protected readonly adapters: TypePathsToAdapters,
|
|
148
|
+
protected readonly mode: FormMode,
|
|
147
149
|
) {
|
|
148
|
-
this.value = mobxCopy(type,
|
|
150
|
+
this.value = mobxCopy(type, originalValue)
|
|
149
151
|
this.flattenedTypeDefs = flattenTypesOfType(type)
|
|
150
152
|
// pre-populate field overrides for consistent behavior when default information is overwritten
|
|
151
153
|
// then returned to
|
|
@@ -161,7 +163,7 @@ export abstract class FormModel<
|
|
|
161
163
|
valuePath,
|
|
162
164
|
): AnnotatedFieldConversion<FieldOverride> | undefined => {
|
|
163
165
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
164
|
-
const contextValue = this.toContext(
|
|
166
|
+
const contextValue = this.toContext(originalValue, valuePath as keyof ValuePathsToAdapters)
|
|
165
167
|
|
|
166
168
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
167
169
|
const adapter = this.adapters[typePath as keyof TypePathsToAdapters]
|
|
@@ -191,6 +193,17 @@ export abstract class FormModel<
|
|
|
191
193
|
valuePath: keyof ValuePathsToAdapters,
|
|
192
194
|
): ContextType
|
|
193
195
|
|
|
196
|
+
get forceMutableFields() {
|
|
197
|
+
switch (this.mode) {
|
|
198
|
+
case 'create':
|
|
199
|
+
return true
|
|
200
|
+
case 'edit':
|
|
201
|
+
return false
|
|
202
|
+
default:
|
|
203
|
+
return this.mode satisfies never
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
194
207
|
@computed
|
|
195
208
|
get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>> {
|
|
196
209
|
return new Proxy<SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>>>(
|
|
@@ -288,7 +301,7 @@ export abstract class FormModel<
|
|
|
288
301
|
return {
|
|
289
302
|
value: fieldOverride != null ? fieldOverride[0] : value,
|
|
290
303
|
error,
|
|
291
|
-
readonly,
|
|
304
|
+
readonly: readonly && !this.forceMutableFields,
|
|
292
305
|
required,
|
|
293
306
|
}
|
|
294
307
|
}
|
|
@@ -646,11 +659,14 @@ export abstract class FormModel<
|
|
|
646
659
|
})
|
|
647
660
|
}
|
|
648
661
|
|
|
649
|
-
validateAll(): boolean {
|
|
662
|
+
validateAll(force: boolean = this.mode === 'create'): boolean {
|
|
650
663
|
// sort keys shortest to longest so parent changes don't overwrite child changes
|
|
651
664
|
const accessors = toArray(this.accessors).toSorted(function ([a], [b]) {
|
|
652
665
|
return a.length - b.length
|
|
653
666
|
})
|
|
667
|
+
|
|
668
|
+
const flattenedOriginalValues = flattenValuesOfType(this.type, this.originalValue)
|
|
669
|
+
|
|
654
670
|
return runInAction(() => {
|
|
655
671
|
return accessors.reduce(
|
|
656
672
|
(
|
|
@@ -684,26 +700,36 @@ export abstract class FormModel<
|
|
|
684
700
|
const value = fieldOverride != null
|
|
685
701
|
? fieldOverride[0]
|
|
686
702
|
: storedValue
|
|
687
|
-
// TODO
|
|
703
|
+
// TODO customizable comparisons
|
|
688
704
|
const dirty = fieldOverride != null && fieldOverride[0] !== storedValue
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
705
|
+
const needsValidation = force
|
|
706
|
+
|| !(valuePath in flattenedOriginalValues)
|
|
707
|
+
|| storedValue !== convert(
|
|
708
|
+
flattenedOriginalValues[valuePath],
|
|
709
|
+
valuePath,
|
|
710
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
711
|
+
this.toContext(this.originalValue, valuePath as keyof ValuePathsToAdapters),
|
|
712
|
+
).value
|
|
713
|
+
if (needsValidation) {
|
|
714
|
+
const conversion = revert(value, valuePath, context)
|
|
715
|
+
switch (conversion.type) {
|
|
716
|
+
case UnreliableFieldConversionType.Failure:
|
|
717
|
+
this.errors[adapterPath] = conversion.error
|
|
718
|
+
if (conversion.value != null && dirty) {
|
|
719
|
+
accessor.set(conversion.value[0])
|
|
720
|
+
}
|
|
721
|
+
return false
|
|
722
|
+
case UnreliableFieldConversionType.Success:
|
|
723
|
+
if (dirty) {
|
|
724
|
+
accessor.set(conversion.value)
|
|
725
|
+
}
|
|
726
|
+
delete this.errors[adapterPath]
|
|
727
|
+
return success
|
|
728
|
+
default:
|
|
729
|
+
throw new UnreachableError(conversion)
|
|
730
|
+
}
|
|
706
731
|
}
|
|
732
|
+
return success
|
|
707
733
|
},
|
|
708
734
|
true,
|
|
709
735
|
)
|
|
@@ -2,6 +2,7 @@ import { expectDefinedAndReturn } from '@strictly/base'
|
|
|
2
2
|
import {
|
|
3
3
|
booleanType,
|
|
4
4
|
type FlattenedValuesOfType,
|
|
5
|
+
flattenValidatorsOfValidatingType,
|
|
5
6
|
list,
|
|
6
7
|
nullType,
|
|
7
8
|
numberType,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
FormModel,
|
|
26
27
|
type ValuePathsToAdaptersOf,
|
|
27
28
|
} from 'core/mobx/form_model'
|
|
29
|
+
import { mergeAdaptersWithValidators } from 'core/mobx/merge_field_adapters_with_validators'
|
|
28
30
|
import { IntegerToStringConverter } from 'field_converters/integer_to_string_converter'
|
|
29
31
|
import { NullableToBooleanConverter } from 'field_converters/nullable_to_boolean_converter'
|
|
30
32
|
import { SelectDiscriminatedUnionConverter } from 'field_converters/select_value_type_converter'
|
|
@@ -203,6 +205,7 @@ describe('all', function () {
|
|
|
203
205
|
typeDef,
|
|
204
206
|
originalValue,
|
|
205
207
|
adapters,
|
|
208
|
+
'create',
|
|
206
209
|
)
|
|
207
210
|
})
|
|
208
211
|
|
|
@@ -263,6 +266,7 @@ describe('all', function () {
|
|
|
263
266
|
typeDef,
|
|
264
267
|
originalValue,
|
|
265
268
|
adapters,
|
|
269
|
+
'create',
|
|
266
270
|
)
|
|
267
271
|
})
|
|
268
272
|
|
|
@@ -304,6 +308,7 @@ describe('all', function () {
|
|
|
304
308
|
typeDef,
|
|
305
309
|
value,
|
|
306
310
|
adapters,
|
|
311
|
+
'create',
|
|
307
312
|
)
|
|
308
313
|
})
|
|
309
314
|
|
|
@@ -382,6 +387,7 @@ describe('all', function () {
|
|
|
382
387
|
typeDef,
|
|
383
388
|
value,
|
|
384
389
|
converters,
|
|
390
|
+
'create',
|
|
385
391
|
)
|
|
386
392
|
})
|
|
387
393
|
|
|
@@ -452,6 +458,7 @@ describe('all', function () {
|
|
|
452
458
|
typeDef,
|
|
453
459
|
value,
|
|
454
460
|
converters,
|
|
461
|
+
'create',
|
|
455
462
|
)
|
|
456
463
|
})
|
|
457
464
|
|
|
@@ -517,6 +524,7 @@ describe('all', function () {
|
|
|
517
524
|
typeDef,
|
|
518
525
|
originalValue,
|
|
519
526
|
adapters,
|
|
527
|
+
'create',
|
|
520
528
|
)
|
|
521
529
|
})
|
|
522
530
|
|
|
@@ -643,6 +651,7 @@ describe('all', function () {
|
|
|
643
651
|
typeDef,
|
|
644
652
|
originalValue,
|
|
645
653
|
converters,
|
|
654
|
+
'create',
|
|
646
655
|
)
|
|
647
656
|
})
|
|
648
657
|
|
|
@@ -993,6 +1002,7 @@ describe('all', function () {
|
|
|
993
1002
|
type,
|
|
994
1003
|
originalValue,
|
|
995
1004
|
adapters,
|
|
1005
|
+
'create',
|
|
996
1006
|
)
|
|
997
1007
|
})
|
|
998
1008
|
|
|
@@ -1061,6 +1071,7 @@ describe('all', function () {
|
|
|
1061
1071
|
a: 1,
|
|
1062
1072
|
},
|
|
1063
1073
|
adapters,
|
|
1074
|
+
'create',
|
|
1064
1075
|
)
|
|
1065
1076
|
it.each([
|
|
1066
1077
|
[
|
|
@@ -1093,6 +1104,7 @@ describe('all', function () {
|
|
|
1093
1104
|
b: false,
|
|
1094
1105
|
},
|
|
1095
1106
|
adapters,
|
|
1107
|
+
'create',
|
|
1096
1108
|
)
|
|
1097
1109
|
it.each([
|
|
1098
1110
|
[
|
|
@@ -1142,6 +1154,7 @@ describe('all', function () {
|
|
|
1142
1154
|
typeDef,
|
|
1143
1155
|
originalValue,
|
|
1144
1156
|
converters,
|
|
1157
|
+
'create',
|
|
1145
1158
|
)
|
|
1146
1159
|
})
|
|
1147
1160
|
|
|
@@ -1167,5 +1180,95 @@ describe('all', function () {
|
|
|
1167
1180
|
})
|
|
1168
1181
|
})
|
|
1169
1182
|
})
|
|
1183
|
+
|
|
1184
|
+
describe('interaction with create and edit modes', () => {
|
|
1185
|
+
const typeDef = object().readonlyField('n', numberType.enforce(n => n < 10 ? 'err' : null))
|
|
1186
|
+
const adapters = mergeAdaptersWithValidators(
|
|
1187
|
+
{
|
|
1188
|
+
$: identityAdapter({ n: 0 }),
|
|
1189
|
+
'$.n': integerToStringAdapter,
|
|
1190
|
+
} as const,
|
|
1191
|
+
flattenValidatorsOfValidatingType(typeDef),
|
|
1192
|
+
)
|
|
1193
|
+
type JsonPaths = {
|
|
1194
|
+
$: '$',
|
|
1195
|
+
'$.n': '$.n',
|
|
1196
|
+
}
|
|
1197
|
+
let originalValue: ValueOfType<typeof typeDef>
|
|
1198
|
+
beforeEach(() => {
|
|
1199
|
+
originalValue = {
|
|
1200
|
+
n: 1,
|
|
1201
|
+
}
|
|
1202
|
+
})
|
|
1203
|
+
describe('create mode', () => {
|
|
1204
|
+
let model: FormModel<
|
|
1205
|
+
typeof typeDef,
|
|
1206
|
+
JsonPaths,
|
|
1207
|
+
typeof adapters
|
|
1208
|
+
>
|
|
1209
|
+
beforeEach(() => {
|
|
1210
|
+
model = new TestFormModel<
|
|
1211
|
+
typeof typeDef,
|
|
1212
|
+
JsonPaths,
|
|
1213
|
+
typeof adapters
|
|
1214
|
+
>(
|
|
1215
|
+
typeDef,
|
|
1216
|
+
originalValue,
|
|
1217
|
+
adapters,
|
|
1218
|
+
'create',
|
|
1219
|
+
)
|
|
1220
|
+
})
|
|
1221
|
+
|
|
1222
|
+
it('makes the field editable', () => {
|
|
1223
|
+
expect(model.fields['$.n'].readonly).toBeFalsy()
|
|
1224
|
+
})
|
|
1225
|
+
|
|
1226
|
+
it('fails validation', () => {
|
|
1227
|
+
expect(model.validateAll()).toBeFalsy()
|
|
1228
|
+
})
|
|
1229
|
+
|
|
1230
|
+
it('passes validation with valid data', () => {
|
|
1231
|
+
model.setFieldValue('$.n', '10')
|
|
1232
|
+
expect(model.validateAll()).toBeTruthy()
|
|
1233
|
+
})
|
|
1234
|
+
})
|
|
1235
|
+
describe('edit model', () => {
|
|
1236
|
+
let model: FormModel<
|
|
1237
|
+
typeof typeDef,
|
|
1238
|
+
JsonPaths,
|
|
1239
|
+
typeof adapters
|
|
1240
|
+
>
|
|
1241
|
+
beforeEach(function () {
|
|
1242
|
+
model = new TestFormModel<
|
|
1243
|
+
typeof typeDef,
|
|
1244
|
+
JsonPaths,
|
|
1245
|
+
typeof adapters
|
|
1246
|
+
>(
|
|
1247
|
+
typeDef,
|
|
1248
|
+
originalValue,
|
|
1249
|
+
adapters,
|
|
1250
|
+
'edit',
|
|
1251
|
+
)
|
|
1252
|
+
})
|
|
1253
|
+
|
|
1254
|
+
it('respects the field being readonly', () => {
|
|
1255
|
+
expect(model.fields['$.n'].readonly).toBeTruthy()
|
|
1256
|
+
})
|
|
1257
|
+
|
|
1258
|
+
it('validates successfully with clean, but invalid data', () => {
|
|
1259
|
+
expect(model.validateAll()).toBeTruthy()
|
|
1260
|
+
})
|
|
1261
|
+
|
|
1262
|
+
it('fails validation with invalid, dirty data', () => {
|
|
1263
|
+
model.setFieldValue('$.n', '2')
|
|
1264
|
+
expect(model.validateAll()).toBeFalsy()
|
|
1265
|
+
})
|
|
1266
|
+
|
|
1267
|
+
it('passes validation with valid, dirty data', () => {
|
|
1268
|
+
model.setFieldValue('$.n', '10')
|
|
1269
|
+
expect(model.validateAll()).toBeTruthy()
|
|
1270
|
+
})
|
|
1271
|
+
})
|
|
1272
|
+
})
|
|
1170
1273
|
})
|
|
1171
1274
|
})
|
package/core/props.ts
CHANGED
|
@@ -14,8 +14,12 @@ export type FieldsViewProps<F extends Fields> = {
|
|
|
14
14
|
onFieldSubmit?(this: void, key: keyof F): boolean | void,
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
export type FormMode = 'edit' | 'create'
|
|
18
|
+
|
|
17
19
|
export type FormProps<O> = {
|
|
18
20
|
value: O,
|
|
19
21
|
|
|
20
22
|
onValueChange: (value: O) => void,
|
|
23
|
+
|
|
24
|
+
mode: FormMode,
|
|
21
25
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -359,15 +359,17 @@ var import_mobx = require("mobx");
|
|
|
359
359
|
var _accessors_dec, _knownFields_dec, _fields_dec, _errors_dec, _fieldOverrides_dec, _value_dec, _init, _value, _fieldOverrides, _errors;
|
|
360
360
|
_value_dec = [import_mobx.observable.ref], _fieldOverrides_dec = [import_mobx.observable.shallow], _errors_dec = [import_mobx.observable.shallow], _fields_dec = [import_mobx.computed], _knownFields_dec = [import_mobx.computed], _accessors_dec = [import_mobx.computed];
|
|
361
361
|
var FormModel = class {
|
|
362
|
-
constructor(type,
|
|
362
|
+
constructor(type, originalValue, adapters, mode) {
|
|
363
363
|
this.type = type;
|
|
364
|
+
this.originalValue = originalValue;
|
|
364
365
|
this.adapters = adapters;
|
|
366
|
+
this.mode = mode;
|
|
365
367
|
__runInitializers(_init, 5, this);
|
|
366
368
|
__privateAdd(this, _value, __runInitializers(_init, 8, this)), __runInitializers(_init, 11, this);
|
|
367
369
|
__privateAdd(this, _fieldOverrides, __runInitializers(_init, 12, this)), __runInitializers(_init, 15, this);
|
|
368
370
|
__privateAdd(this, _errors, __runInitializers(_init, 16, this, {})), __runInitializers(_init, 19, this);
|
|
369
371
|
__publicField(this, "flattenedTypeDefs");
|
|
370
|
-
this.value = (0, import_define.mobxCopy)(type,
|
|
372
|
+
this.value = (0, import_define.mobxCopy)(type, originalValue);
|
|
371
373
|
this.flattenedTypeDefs = (0, import_define.flattenTypesOfType)(type);
|
|
372
374
|
const conversions = (0, import_define.flattenValueTo)(
|
|
373
375
|
type,
|
|
@@ -375,7 +377,7 @@ var FormModel = class {
|
|
|
375
377
|
() => {
|
|
376
378
|
},
|
|
377
379
|
(_t, fieldValue, _setter, typePath, valuePath) => {
|
|
378
|
-
const contextValue = this.toContext(
|
|
380
|
+
const contextValue = this.toContext(originalValue, valuePath);
|
|
379
381
|
const adapter2 = this.adapters[typePath];
|
|
380
382
|
if (adapter2 == null) {
|
|
381
383
|
return;
|
|
@@ -394,6 +396,16 @@ var FormModel = class {
|
|
|
394
396
|
return v && [v.value];
|
|
395
397
|
});
|
|
396
398
|
}
|
|
399
|
+
get forceMutableFields() {
|
|
400
|
+
switch (this.mode) {
|
|
401
|
+
case "create":
|
|
402
|
+
return true;
|
|
403
|
+
case "edit":
|
|
404
|
+
return false;
|
|
405
|
+
default:
|
|
406
|
+
return this.mode;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
397
409
|
get fields() {
|
|
398
410
|
return new Proxy(
|
|
399
411
|
this.knownFields,
|
|
@@ -472,7 +484,7 @@ var FormModel = class {
|
|
|
472
484
|
return {
|
|
473
485
|
value: fieldOverride != null ? fieldOverride[0] : value,
|
|
474
486
|
error,
|
|
475
|
-
readonly,
|
|
487
|
+
readonly: readonly && !this.forceMutableFields,
|
|
476
488
|
required
|
|
477
489
|
};
|
|
478
490
|
}
|
|
@@ -754,10 +766,11 @@ var FormModel = class {
|
|
|
754
766
|
}
|
|
755
767
|
});
|
|
756
768
|
}
|
|
757
|
-
validateAll() {
|
|
769
|
+
validateAll(force = this.mode === "create") {
|
|
758
770
|
const accessors = (0, import_base2.toArray)(this.accessors).toSorted(function([a], [b]) {
|
|
759
771
|
return a.length - b.length;
|
|
760
772
|
});
|
|
773
|
+
const flattenedOriginalValues = (0, import_define.flattenValuesOfType)(this.type, this.originalValue);
|
|
761
774
|
return (0, import_mobx.runInAction)(() => {
|
|
762
775
|
return accessors.reduce(
|
|
763
776
|
(success, [
|
|
@@ -783,23 +796,32 @@ var FormModel = class {
|
|
|
783
796
|
} = convert(accessor.value, valuePath, context);
|
|
784
797
|
const value = fieldOverride != null ? fieldOverride[0] : storedValue;
|
|
785
798
|
const dirty = fieldOverride != null && fieldOverride[0] !== storedValue;
|
|
786
|
-
const
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
799
|
+
const needsValidation = force || !(valuePath in flattenedOriginalValues) || storedValue !== convert(
|
|
800
|
+
flattenedOriginalValues[valuePath],
|
|
801
|
+
valuePath,
|
|
802
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
803
|
+
this.toContext(this.originalValue, valuePath)
|
|
804
|
+
).value;
|
|
805
|
+
if (needsValidation) {
|
|
806
|
+
const conversion = revert(value, valuePath, context);
|
|
807
|
+
switch (conversion.type) {
|
|
808
|
+
case 1 /* Failure */:
|
|
809
|
+
this.errors[adapterPath] = conversion.error;
|
|
810
|
+
if (conversion.value != null && dirty) {
|
|
811
|
+
accessor.set(conversion.value[0]);
|
|
812
|
+
}
|
|
813
|
+
return false;
|
|
814
|
+
case 0 /* Success */:
|
|
815
|
+
if (dirty) {
|
|
816
|
+
accessor.set(conversion.value);
|
|
817
|
+
}
|
|
818
|
+
delete this.errors[adapterPath];
|
|
819
|
+
return success;
|
|
820
|
+
default:
|
|
821
|
+
throw new import_base2.UnreachableError(conversion);
|
|
822
|
+
}
|
|
802
823
|
}
|
|
824
|
+
return success;
|
|
803
825
|
},
|
|
804
826
|
true
|
|
805
827
|
);
|
|
@@ -1753,7 +1775,7 @@ function useMantineFormFields({
|
|
|
1753
1775
|
function() {
|
|
1754
1776
|
return new MantineFormImpl(fields);
|
|
1755
1777
|
},
|
|
1756
|
-
// handled separately below
|
|
1778
|
+
// fields handled separately below
|
|
1757
1779
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1758
1780
|
[]
|
|
1759
1781
|
);
|
package/dist/index.d.cts
CHANGED
|
@@ -97,6 +97,20 @@ type FormFieldsOfFieldAdapters<ValuePathsToTypePaths extends Readonly<Record<str
|
|
|
97
97
|
};
|
|
98
98
|
type FormFieldOfFieldAdapter<F extends FieldAdapter | undefined> = F extends FieldAdapter<infer _From, infer To, infer E> ? Field<To, E> : never;
|
|
99
99
|
|
|
100
|
+
type FieldsViewProps<F extends Fields> = {
|
|
101
|
+
fields: F;
|
|
102
|
+
onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void;
|
|
103
|
+
onFieldFocus?(this: void, key: keyof F): void;
|
|
104
|
+
onFieldBlur?(this: void, key: keyof F): void;
|
|
105
|
+
onFieldSubmit?(this: void, key: keyof F): boolean | void;
|
|
106
|
+
};
|
|
107
|
+
type FormMode = 'edit' | 'create';
|
|
108
|
+
type FormProps<O> = {
|
|
109
|
+
value: O;
|
|
110
|
+
onValueChange: (value: O) => void;
|
|
111
|
+
mode: FormMode;
|
|
112
|
+
};
|
|
113
|
+
|
|
100
114
|
type FlattenedListTypesOfType<T extends Type> = FlattenedListTypesOfTypes<SimplifyDeep<FlattenedTypesOfType<T, null>>>;
|
|
101
115
|
type FlattenedListTypesOfTypes<T extends Readonly<Record<string, Type>>> = {
|
|
102
116
|
[K in keyof T as T[K]['definition'] extends ListTypeDef ? K : never]: T[K];
|
|
@@ -123,13 +137,16 @@ type ContextOf<TypePathsToAdapters extends Partial<Readonly<Record<string, Field
|
|
|
123
137
|
}[keyof TypePathsToAdapters] | {}>;
|
|
124
138
|
declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readonly<Record<string, string>>, TypePathsToAdapters extends FlattenedTypePathsToAdaptersOf<FlattenedValuesOfType<T, '*'>, ContextType>, ContextType = ContextOf<TypePathsToAdapters>, ValuePathsToAdapters extends ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths> = ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths>> {
|
|
125
139
|
readonly type: T;
|
|
140
|
+
private readonly originalValue;
|
|
126
141
|
protected readonly adapters: TypePathsToAdapters;
|
|
142
|
+
protected readonly mode: FormMode;
|
|
127
143
|
accessor value: MobxValueOfType<T>;
|
|
128
144
|
accessor fieldOverrides: FlattenedFieldOverrides<ValuePathsToAdapters>;
|
|
129
145
|
accessor errors: FlattenedErrors<ValuePathsToAdapters>;
|
|
130
146
|
private readonly flattenedTypeDefs;
|
|
131
|
-
constructor(type: T,
|
|
147
|
+
constructor(type: T, originalValue: ValueOfType<ReadonlyTypeOfType<T>>, adapters: TypePathsToAdapters, mode: FormMode);
|
|
132
148
|
protected abstract toContext(value: ValueOfType<ReadonlyTypeOfType<T>>, valuePath: keyof ValuePathsToAdapters): ContextType;
|
|
149
|
+
get forceMutableFields(): boolean;
|
|
133
150
|
get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>>;
|
|
134
151
|
private get knownFields();
|
|
135
152
|
private maybeSynthesizeFieldByValuePath;
|
|
@@ -149,7 +166,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
149
166
|
clearAll(value: ValueOfType<T>): void;
|
|
150
167
|
isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
151
168
|
validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, ignoreDefaultValue?: boolean): boolean;
|
|
152
|
-
validateAll(): boolean;
|
|
169
|
+
validateAll(force?: boolean): boolean;
|
|
153
170
|
}
|
|
154
171
|
|
|
155
172
|
/**
|
|
@@ -207,18 +224,6 @@ type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, Type
|
|
|
207
224
|
};
|
|
208
225
|
declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, TypePath extends string, TypePathsToValuePaths extends Record<TypePath, string>>(subAdapters: SubAdapters, parentTypePath: TypePath): SubFormFieldAdapters<SubAdapters, TypePath, TypePathsToValuePaths[TypePath]>;
|
|
209
226
|
|
|
210
|
-
type FieldsViewProps<F extends Fields> = {
|
|
211
|
-
fields: F;
|
|
212
|
-
onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void;
|
|
213
|
-
onFieldFocus?(this: void, key: keyof F): void;
|
|
214
|
-
onFieldBlur?(this: void, key: keyof F): void;
|
|
215
|
-
onFieldSubmit?(this: void, key: keyof F): boolean | void;
|
|
216
|
-
};
|
|
217
|
-
type FormProps<O> = {
|
|
218
|
-
value: O;
|
|
219
|
-
onValueChange: (value: O) => void;
|
|
220
|
-
};
|
|
221
|
-
|
|
222
227
|
declare class IntegerToStringConverter<E, ValuePath extends string, Context> implements TwoWayFieldConverter<number, string, E, ValuePath, Context> {
|
|
223
228
|
private readonly isNanError;
|
|
224
229
|
private readonly base;
|
|
@@ -445,4 +450,4 @@ declare function mergeValidators<Validators1 extends Partial<Readonly<Record<Key
|
|
|
445
450
|
|
|
446
451
|
declare function Empty(): null;
|
|
447
452
|
|
|
448
|
-
export { AbstractSelectValueTypeConverter, type AnnotatedFieldConversion, type AnnotatedFieldConverter, type Annotation, type ContextOf, type ContextOfFieldAdapter, DefaultErrorRenderer, Empty, type ErrorOfField, type ErrorOfFieldAdapter, type ErrorRenderer, type ErrorRendererProps, type Field, type FieldAdapter, type FieldAdaptersOfValues, type FieldValueFactory, type Fields, type FieldsViewProps, type FlattenedAdaptersOfFields, type FlattenedConvertedFieldsOf, type FlattenedTypePathsToAdaptersOf, type FormFieldsOfFieldAdapters, type FormFieldsOfModel, FormModel, type FormProps, type FromOfFieldAdapter, IntegerToStringConverter, type MergedOfFieldAdaptersWithTwoWayConverter, type MergedOfFieldAdaptersWithValidators, type MergedOfValidator, type MergedOfValidators, NullableToBooleanConverter, type PartialComponent, SelectDiscriminatedUnionConverter, SelectLiteralConverter, SelectStringConverter, type ToOfFieldAdapter, type ToValueOfModelValuePath, TrimmingStringConverter, type TwoWayFieldConverter, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion, UnreliableFieldConversionType, type UnreliableFieldConverter, type UnsafePartialComponent, type ValuePathOfFieldAdapter, type ValuePathsOfModel, type ValuePathsToAdaptersOf, adapter, adapterFromPrototype, adapterFromTwoWayConverter, createPartialComponent, createPartialObserverComponent, createSimplePartialComponent, createUnsafePartialObserverComponent, identityAdapter, listAdapter, mergeAdaptersWithValidators, mergeFieldAdaptersWithTwoWayConverter, mergeValidators, prototypingFieldValueFactory, subFormFieldAdapters, trimmingStringAdapter, useDefaultMobxFormHooks, useMantineFormFields, usePartialComponent, usePartialObserverComponent, validatingConverter };
|
|
453
|
+
export { AbstractSelectValueTypeConverter, type AnnotatedFieldConversion, type AnnotatedFieldConverter, type Annotation, type ContextOf, type ContextOfFieldAdapter, DefaultErrorRenderer, Empty, type ErrorOfField, type ErrorOfFieldAdapter, type ErrorRenderer, type ErrorRendererProps, type Field, type FieldAdapter, type FieldAdaptersOfValues, type FieldValueFactory, type Fields, type FieldsViewProps, type FlattenedAdaptersOfFields, type FlattenedConvertedFieldsOf, type FlattenedTypePathsToAdaptersOf, type FormFieldsOfFieldAdapters, type FormFieldsOfModel, type FormMode, FormModel, type FormProps, type FromOfFieldAdapter, IntegerToStringConverter, type MergedOfFieldAdaptersWithTwoWayConverter, type MergedOfFieldAdaptersWithValidators, type MergedOfValidator, type MergedOfValidators, NullableToBooleanConverter, type PartialComponent, SelectDiscriminatedUnionConverter, SelectLiteralConverter, SelectStringConverter, type ToOfFieldAdapter, type ToValueOfModelValuePath, TrimmingStringConverter, type TwoWayFieldConverter, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion, UnreliableFieldConversionType, type UnreliableFieldConverter, type UnsafePartialComponent, type ValuePathOfFieldAdapter, type ValuePathsOfModel, type ValuePathsToAdaptersOf, adapter, adapterFromPrototype, adapterFromTwoWayConverter, createPartialComponent, createPartialObserverComponent, createSimplePartialComponent, createUnsafePartialObserverComponent, identityAdapter, listAdapter, mergeAdaptersWithValidators, mergeFieldAdaptersWithTwoWayConverter, mergeValidators, prototypingFieldValueFactory, subFormFieldAdapters, trimmingStringAdapter, useDefaultMobxFormHooks, useMantineFormFields, usePartialComponent, usePartialObserverComponent, validatingConverter };
|
package/dist/index.d.ts
CHANGED
|
@@ -97,6 +97,20 @@ type FormFieldsOfFieldAdapters<ValuePathsToTypePaths extends Readonly<Record<str
|
|
|
97
97
|
};
|
|
98
98
|
type FormFieldOfFieldAdapter<F extends FieldAdapter | undefined> = F extends FieldAdapter<infer _From, infer To, infer E> ? Field<To, E> : never;
|
|
99
99
|
|
|
100
|
+
type FieldsViewProps<F extends Fields> = {
|
|
101
|
+
fields: F;
|
|
102
|
+
onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void;
|
|
103
|
+
onFieldFocus?(this: void, key: keyof F): void;
|
|
104
|
+
onFieldBlur?(this: void, key: keyof F): void;
|
|
105
|
+
onFieldSubmit?(this: void, key: keyof F): boolean | void;
|
|
106
|
+
};
|
|
107
|
+
type FormMode = 'edit' | 'create';
|
|
108
|
+
type FormProps<O> = {
|
|
109
|
+
value: O;
|
|
110
|
+
onValueChange: (value: O) => void;
|
|
111
|
+
mode: FormMode;
|
|
112
|
+
};
|
|
113
|
+
|
|
100
114
|
type FlattenedListTypesOfType<T extends Type> = FlattenedListTypesOfTypes<SimplifyDeep<FlattenedTypesOfType<T, null>>>;
|
|
101
115
|
type FlattenedListTypesOfTypes<T extends Readonly<Record<string, Type>>> = {
|
|
102
116
|
[K in keyof T as T[K]['definition'] extends ListTypeDef ? K : never]: T[K];
|
|
@@ -123,13 +137,16 @@ type ContextOf<TypePathsToAdapters extends Partial<Readonly<Record<string, Field
|
|
|
123
137
|
}[keyof TypePathsToAdapters] | {}>;
|
|
124
138
|
declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readonly<Record<string, string>>, TypePathsToAdapters extends FlattenedTypePathsToAdaptersOf<FlattenedValuesOfType<T, '*'>, ContextType>, ContextType = ContextOf<TypePathsToAdapters>, ValuePathsToAdapters extends ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths> = ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths>> {
|
|
125
139
|
readonly type: T;
|
|
140
|
+
private readonly originalValue;
|
|
126
141
|
protected readonly adapters: TypePathsToAdapters;
|
|
142
|
+
protected readonly mode: FormMode;
|
|
127
143
|
accessor value: MobxValueOfType<T>;
|
|
128
144
|
accessor fieldOverrides: FlattenedFieldOverrides<ValuePathsToAdapters>;
|
|
129
145
|
accessor errors: FlattenedErrors<ValuePathsToAdapters>;
|
|
130
146
|
private readonly flattenedTypeDefs;
|
|
131
|
-
constructor(type: T,
|
|
147
|
+
constructor(type: T, originalValue: ValueOfType<ReadonlyTypeOfType<T>>, adapters: TypePathsToAdapters, mode: FormMode);
|
|
132
148
|
protected abstract toContext(value: ValueOfType<ReadonlyTypeOfType<T>>, valuePath: keyof ValuePathsToAdapters): ContextType;
|
|
149
|
+
get forceMutableFields(): boolean;
|
|
133
150
|
get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>>;
|
|
134
151
|
private get knownFields();
|
|
135
152
|
private maybeSynthesizeFieldByValuePath;
|
|
@@ -149,7 +166,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
|
|
|
149
166
|
clearAll(value: ValueOfType<T>): void;
|
|
150
167
|
isValuePathActive<K extends keyof ValuePathsToAdapters>(valuePath: K): boolean;
|
|
151
168
|
validateField<K extends keyof ValuePathsToAdapters>(valuePath: K, ignoreDefaultValue?: boolean): boolean;
|
|
152
|
-
validateAll(): boolean;
|
|
169
|
+
validateAll(force?: boolean): boolean;
|
|
153
170
|
}
|
|
154
171
|
|
|
155
172
|
/**
|
|
@@ -207,18 +224,6 @@ type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, Type
|
|
|
207
224
|
};
|
|
208
225
|
declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, TypePath extends string, TypePathsToValuePaths extends Record<TypePath, string>>(subAdapters: SubAdapters, parentTypePath: TypePath): SubFormFieldAdapters<SubAdapters, TypePath, TypePathsToValuePaths[TypePath]>;
|
|
209
226
|
|
|
210
|
-
type FieldsViewProps<F extends Fields> = {
|
|
211
|
-
fields: F;
|
|
212
|
-
onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void;
|
|
213
|
-
onFieldFocus?(this: void, key: keyof F): void;
|
|
214
|
-
onFieldBlur?(this: void, key: keyof F): void;
|
|
215
|
-
onFieldSubmit?(this: void, key: keyof F): boolean | void;
|
|
216
|
-
};
|
|
217
|
-
type FormProps<O> = {
|
|
218
|
-
value: O;
|
|
219
|
-
onValueChange: (value: O) => void;
|
|
220
|
-
};
|
|
221
|
-
|
|
222
227
|
declare class IntegerToStringConverter<E, ValuePath extends string, Context> implements TwoWayFieldConverter<number, string, E, ValuePath, Context> {
|
|
223
228
|
private readonly isNanError;
|
|
224
229
|
private readonly base;
|
|
@@ -445,4 +450,4 @@ declare function mergeValidators<Validators1 extends Partial<Readonly<Record<Key
|
|
|
445
450
|
|
|
446
451
|
declare function Empty(): null;
|
|
447
452
|
|
|
448
|
-
export { AbstractSelectValueTypeConverter, type AnnotatedFieldConversion, type AnnotatedFieldConverter, type Annotation, type ContextOf, type ContextOfFieldAdapter, DefaultErrorRenderer, Empty, type ErrorOfField, type ErrorOfFieldAdapter, type ErrorRenderer, type ErrorRendererProps, type Field, type FieldAdapter, type FieldAdaptersOfValues, type FieldValueFactory, type Fields, type FieldsViewProps, type FlattenedAdaptersOfFields, type FlattenedConvertedFieldsOf, type FlattenedTypePathsToAdaptersOf, type FormFieldsOfFieldAdapters, type FormFieldsOfModel, FormModel, type FormProps, type FromOfFieldAdapter, IntegerToStringConverter, type MergedOfFieldAdaptersWithTwoWayConverter, type MergedOfFieldAdaptersWithValidators, type MergedOfValidator, type MergedOfValidators, NullableToBooleanConverter, type PartialComponent, SelectDiscriminatedUnionConverter, SelectLiteralConverter, SelectStringConverter, type ToOfFieldAdapter, type ToValueOfModelValuePath, TrimmingStringConverter, type TwoWayFieldConverter, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion, UnreliableFieldConversionType, type UnreliableFieldConverter, type UnsafePartialComponent, type ValuePathOfFieldAdapter, type ValuePathsOfModel, type ValuePathsToAdaptersOf, adapter, adapterFromPrototype, adapterFromTwoWayConverter, createPartialComponent, createPartialObserverComponent, createSimplePartialComponent, createUnsafePartialObserverComponent, identityAdapter, listAdapter, mergeAdaptersWithValidators, mergeFieldAdaptersWithTwoWayConverter, mergeValidators, prototypingFieldValueFactory, subFormFieldAdapters, trimmingStringAdapter, useDefaultMobxFormHooks, useMantineFormFields, usePartialComponent, usePartialObserverComponent, validatingConverter };
|
|
453
|
+
export { AbstractSelectValueTypeConverter, type AnnotatedFieldConversion, type AnnotatedFieldConverter, type Annotation, type ContextOf, type ContextOfFieldAdapter, DefaultErrorRenderer, Empty, type ErrorOfField, type ErrorOfFieldAdapter, type ErrorRenderer, type ErrorRendererProps, type Field, type FieldAdapter, type FieldAdaptersOfValues, type FieldValueFactory, type Fields, type FieldsViewProps, type FlattenedAdaptersOfFields, type FlattenedConvertedFieldsOf, type FlattenedTypePathsToAdaptersOf, type FormFieldsOfFieldAdapters, type FormFieldsOfModel, type FormMode, FormModel, type FormProps, type FromOfFieldAdapter, IntegerToStringConverter, type MergedOfFieldAdaptersWithTwoWayConverter, type MergedOfFieldAdaptersWithValidators, type MergedOfValidator, type MergedOfValidators, NullableToBooleanConverter, type PartialComponent, SelectDiscriminatedUnionConverter, SelectLiteralConverter, SelectStringConverter, type ToOfFieldAdapter, type ToValueOfModelValuePath, TrimmingStringConverter, type TwoWayFieldConverter, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion, UnreliableFieldConversionType, type UnreliableFieldConverter, type UnsafePartialComponent, type ValuePathOfFieldAdapter, type ValuePathsOfModel, type ValuePathsToAdaptersOf, adapter, adapterFromPrototype, adapterFromTwoWayConverter, createPartialComponent, createPartialObserverComponent, createSimplePartialComponent, createUnsafePartialObserverComponent, identityAdapter, listAdapter, mergeAdaptersWithValidators, mergeFieldAdaptersWithTwoWayConverter, mergeValidators, prototypingFieldValueFactory, subFormFieldAdapters, trimmingStringAdapter, useDefaultMobxFormHooks, useMantineFormFields, usePartialComponent, usePartialObserverComponent, validatingConverter };
|