@strictly/react-form 0.0.27 → 0.0.28
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 +3 -1
- package/.out/core/mobx/form_model.js +48 -99
- package/.out/core/mobx/specs/form_model.tests.js +14 -12
- package/.out/mantine/create_list.d.ts +2 -1
- package/.out/mantine/create_list.js +15 -3
- package/.out/mantine/specs/list_hooks.stories.js +8 -0
- package/.out/tsconfig.tsbuildinfo +1 -1
- package/.out/types/field.d.ts +1 -0
- package/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-check-types.log +1 -1
- package/core/mobx/form_model.ts +47 -115
- package/core/mobx/specs/form_model.tests.ts +14 -12
- package/dist/index.cjs +78 -114
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +69 -104
- package/mantine/create_list.tsx +27 -3
- package/mantine/specs/__snapshots__/list_hooks.tests.tsx.snap +3 -3
- package/mantine/specs/list_hooks.stories.tsx +8 -0
- package/package.json +1 -1
- package/types/field.ts +1 -0
|
@@ -34,6 +34,7 @@ export type ContextOf<TypePathsToAdapters extends Partial<Readonly<Record<string
|
|
|
34
34
|
export type FormMode = 'edit' | 'create';
|
|
35
35
|
export 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>> {
|
|
36
36
|
readonly type: T;
|
|
37
|
+
private readonly originalValue;
|
|
37
38
|
protected readonly adapters: TypePathsToAdapters;
|
|
38
39
|
protected readonly mode: FormMode;
|
|
39
40
|
accessor value: MobxValueOfType<T>;
|
|
@@ -42,6 +43,7 @@ export declare abstract class FormModel<T extends Type, ValueToTypePaths extends
|
|
|
42
43
|
accessor validation: FlattenedValidation<ValuePathsToAdapters>;
|
|
43
44
|
private readonly flattenedTypeDefs;
|
|
44
45
|
private readonly originalValues;
|
|
46
|
+
private readonly listIndicesToKeys;
|
|
45
47
|
constructor(type: T, originalValue: ValueOfType<ReadonlyTypeOfType<T>>, adapters: TypePathsToAdapters, mode: FormMode);
|
|
46
48
|
protected abstract toContext(value: ValueOfType<ReadonlyTypeOfType<T>>, valuePath: keyof ValuePathsToAdapters): ContextType;
|
|
47
49
|
get forceMutableFields(): boolean;
|
|
@@ -55,11 +57,11 @@ export declare abstract class FormModel<T extends Type, ValueToTypePaths extends
|
|
|
55
57
|
private maybeGetAdapterForValuePath;
|
|
56
58
|
private getAdapterForValuePath;
|
|
57
59
|
get dirty(): boolean;
|
|
60
|
+
get valueChanged(): boolean;
|
|
58
61
|
typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K];
|
|
59
62
|
setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation): boolean;
|
|
60
63
|
addListItem<K extends keyof FlattenedListTypesOfType<T>>(valuePath: K, elementValue?: Maybe<ElementOfArray<FlattenedValuesOfType<T>[K]>>, index?: number): void;
|
|
61
64
|
removeListItem<K extends keyof FlattenedListTypesOfType<T>>(...elementValuePaths: readonly `${K}.${number}`[]): void;
|
|
62
|
-
protected moveListItem<K extends keyof FlattenedListTypesOfType<T>>(fromValuePath: K, toValuePath: K): void;
|
|
63
65
|
private internalSetFieldValue;
|
|
64
66
|
/**
|
|
65
67
|
* Forces an error onto a field. Error will be removed if the field value changes
|
|
@@ -43,7 +43,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
43
43
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
44
44
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
45
45
|
};
|
|
46
|
-
import { assertExists, assertExistsAndReturn,
|
|
46
|
+
import { assertExists, assertExistsAndReturn, checkValidNumber, map, toArray, UnreachableError, } from '@strictly/base';
|
|
47
47
|
import { equals, flattenAccessorsOfType, flattenTypesOfType, flattenValuesOfType, flattenValueTo, jsonPathPop, mobxCopy, valuePathToTypePath, } from '@strictly/define';
|
|
48
48
|
import { computed, observable, runInAction, } from 'mobx';
|
|
49
49
|
import { UnreliableFieldConversionType, } from 'types/field_converters';
|
|
@@ -73,6 +73,7 @@ let FormModel = (() => {
|
|
|
73
73
|
let _get_knownFields_decorators;
|
|
74
74
|
let _get_accessors_decorators;
|
|
75
75
|
let _get_dirty_decorators;
|
|
76
|
+
let _get_valueChanged_decorators;
|
|
76
77
|
return _a = class FormModel {
|
|
77
78
|
get value() { return __classPrivateFieldGet(this, _FormModel_value_accessor_storage, "f"); }
|
|
78
79
|
set value(value) { __classPrivateFieldSet(this, _FormModel_value_accessor_storage, value, "f"); }
|
|
@@ -89,6 +90,12 @@ let FormModel = (() => {
|
|
|
89
90
|
writable: true,
|
|
90
91
|
value: (__runInitializers(this, _instanceExtraInitializers), type)
|
|
91
92
|
});
|
|
93
|
+
Object.defineProperty(this, "originalValue", {
|
|
94
|
+
enumerable: true,
|
|
95
|
+
configurable: true,
|
|
96
|
+
writable: true,
|
|
97
|
+
value: originalValue
|
|
98
|
+
});
|
|
92
99
|
Object.defineProperty(this, "adapters", {
|
|
93
100
|
enumerable: true,
|
|
94
101
|
configurable: true,
|
|
@@ -119,7 +126,14 @@ let FormModel = (() => {
|
|
|
119
126
|
writable: true,
|
|
120
127
|
value: void 0
|
|
121
128
|
});
|
|
122
|
-
|
|
129
|
+
// maintains the value paths of lists when the original order is destroyed by deletes or reordering
|
|
130
|
+
Object.defineProperty(this, "listIndicesToKeys", {
|
|
131
|
+
enumerable: true,
|
|
132
|
+
configurable: true,
|
|
133
|
+
writable: true,
|
|
134
|
+
value: {}
|
|
135
|
+
});
|
|
136
|
+
this.originalValues = flattenValuesOfType(type, originalValue, this.listIndicesToKeys);
|
|
123
137
|
this.value = mobxCopy(type, originalValue);
|
|
124
138
|
this.flattenedTypeDefs = flattenTypesOfType(type);
|
|
125
139
|
// pre-populate field overrides for consistent behavior when default information is overwritten
|
|
@@ -139,7 +153,7 @@ let FormModel = (() => {
|
|
|
139
153
|
}
|
|
140
154
|
// cannot call this.context yet as the "this" pointer has not been fully created
|
|
141
155
|
return convert(fieldValue, valuePath, contextValue);
|
|
142
|
-
});
|
|
156
|
+
}, this.listIndicesToKeys);
|
|
143
157
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
144
158
|
this.fieldOverrides = map(conversions, function (_k, v) {
|
|
145
159
|
return v && [v.value];
|
|
@@ -179,7 +193,7 @@ let FormModel = (() => {
|
|
|
179
193
|
valuePath,
|
|
180
194
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
181
195
|
typePath);
|
|
182
|
-
});
|
|
196
|
+
}, this.listIndicesToKeys);
|
|
183
197
|
}
|
|
184
198
|
maybeSynthesizeFieldByValuePath(valuePath) {
|
|
185
199
|
let typePath;
|
|
@@ -282,6 +296,8 @@ let FormModel = (() => {
|
|
|
282
296
|
error,
|
|
283
297
|
readonly: readonly && !this.forceMutableFields,
|
|
284
298
|
required,
|
|
299
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
300
|
+
listIndexToKey: this.listIndicesToKeys[valuePath],
|
|
285
301
|
};
|
|
286
302
|
}
|
|
287
303
|
getAccessorForValuePath(valuePath) {
|
|
@@ -291,7 +307,7 @@ let FormModel = (() => {
|
|
|
291
307
|
get accessors() {
|
|
292
308
|
return flattenAccessorsOfType(this.type, this.value, (value) => {
|
|
293
309
|
this.value = mobxCopy(this.type, value);
|
|
294
|
-
});
|
|
310
|
+
}, this.listIndicesToKeys);
|
|
295
311
|
}
|
|
296
312
|
maybeGetAdapterForValuePath(valuePath) {
|
|
297
313
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
@@ -308,6 +324,10 @@ let FormModel = (() => {
|
|
|
308
324
|
return this.isFieldDirty(valuePath);
|
|
309
325
|
});
|
|
310
326
|
}
|
|
327
|
+
get valueChanged() {
|
|
328
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
329
|
+
return !equals(this.type, this.value, this.originalValue);
|
|
330
|
+
}
|
|
311
331
|
typePath(valuePath) {
|
|
312
332
|
return valuePathToTypePath(this.type, valuePath, true);
|
|
313
333
|
}
|
|
@@ -341,113 +361,40 @@ let FormModel = (() => {
|
|
|
341
361
|
element,
|
|
342
362
|
...originalList.slice(definedIndex),
|
|
343
363
|
];
|
|
344
|
-
// shuffle the overrides around to account for new indices
|
|
345
|
-
// to so this we need to sort the array indices in descending order
|
|
346
|
-
const targetPaths = Object.keys(this.fieldOverrides).filter(function (v) {
|
|
347
|
-
return v.startsWith(`${listValuePath}.`);
|
|
348
|
-
}).map(function (v) {
|
|
349
|
-
const parts = v.substring(listValuePath.length + 1).split('.');
|
|
350
|
-
const index = parseInt(parts[0]);
|
|
351
|
-
return [
|
|
352
|
-
index,
|
|
353
|
-
parts.slice(1),
|
|
354
|
-
];
|
|
355
|
-
}).filter(function ([index]) {
|
|
356
|
-
return index >= definedIndex;
|
|
357
|
-
}).sort(function ([a], [b]) {
|
|
358
|
-
// descending
|
|
359
|
-
return b - a;
|
|
360
|
-
});
|
|
361
364
|
runInAction(() => {
|
|
362
|
-
targetPaths.forEach(([index, postfix,]) => {
|
|
363
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
364
|
-
const fromJsonPath = [
|
|
365
|
-
listValuePath,
|
|
366
|
-
`${index}`,
|
|
367
|
-
...postfix,
|
|
368
|
-
].join('.');
|
|
369
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
370
|
-
const toJsonPath = [
|
|
371
|
-
listValuePath,
|
|
372
|
-
`${index + 1}`,
|
|
373
|
-
...postfix,
|
|
374
|
-
].join('.');
|
|
375
|
-
const fieldOverride = this.fieldOverrides[fromJsonPath];
|
|
376
|
-
delete this.fieldOverrides[fromJsonPath];
|
|
377
|
-
this.fieldOverrides[toJsonPath] = fieldOverride;
|
|
378
|
-
const validation = this.validation[fromJsonPath];
|
|
379
|
-
delete this.validation[fromJsonPath];
|
|
380
|
-
this.validation[toJsonPath] = validation;
|
|
381
|
-
});
|
|
382
365
|
accessor.set(newList);
|
|
383
366
|
// delete any value overrides so the new list isn't shadowed
|
|
384
367
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
385
368
|
delete this.fieldOverrides[listValuePath];
|
|
369
|
+
const indicesToKeys = assertExistsAndReturn(this.listIndicesToKeys[listValuePath], 'no index to key mapping for list {}', listValuePath);
|
|
370
|
+
const nextKey = indicesToKeys[indicesToKeys.length - 1];
|
|
371
|
+
// insert the next key
|
|
372
|
+
indicesToKeys.splice(definedIndex, 0, nextKey);
|
|
373
|
+
// create the new next key
|
|
374
|
+
indicesToKeys[indicesToKeys.length - 1] = nextKey + 1;
|
|
386
375
|
});
|
|
387
376
|
}
|
|
388
377
|
removeListItem(...elementValuePaths) {
|
|
389
|
-
// sort and reverse so we delete last to first so indices of sequential deletions are preserved
|
|
390
|
-
const orderedElementValuePaths = elementValuePaths.toSorted().reverse();
|
|
391
378
|
runInAction(() => {
|
|
392
|
-
|
|
393
|
-
|
|
379
|
+
elementValuePaths.forEach(elementValuePath => {
|
|
380
|
+
var _b;
|
|
381
|
+
const [listValuePath, elementKeyString,] = assertExistsAndReturn(jsonPathPop(elementValuePath), 'expected a path with two or more segments {}', elementValuePath);
|
|
394
382
|
const accessor = this.accessors[listValuePath];
|
|
395
|
-
const
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}).map(function (v) {
|
|
404
|
-
const parts = v.substring(listValuePath.length + 1).split('.');
|
|
405
|
-
const index = parseInt(parts[0]);
|
|
406
|
-
return [
|
|
407
|
-
index,
|
|
408
|
-
parts.slice(1),
|
|
409
|
-
];
|
|
410
|
-
}).filter(function ([index]) {
|
|
411
|
-
return index > elementIndex;
|
|
412
|
-
}).sort(function ([a], [b]) {
|
|
413
|
-
// descending
|
|
414
|
-
return a - b;
|
|
415
|
-
});
|
|
416
|
-
targetPaths.forEach(([index, postfix,]) => {
|
|
417
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
418
|
-
const fromJsonPath = [
|
|
419
|
-
listValuePath,
|
|
420
|
-
`${index}`,
|
|
421
|
-
...postfix,
|
|
422
|
-
].join('.');
|
|
383
|
+
const elementKey = checkValidNumber(parseInt(elementKeyString), 'unexpected id {} ({})', elementKeyString, elementValuePath);
|
|
384
|
+
const indicesToKeys = this.listIndicesToKeys[listValuePath];
|
|
385
|
+
const elementIndex = (_b = indicesToKeys === null || indicesToKeys === void 0 ? void 0 : indicesToKeys.indexOf(elementKey)) !== null && _b !== void 0 ? _b : -1;
|
|
386
|
+
if (elementIndex >= 0) {
|
|
387
|
+
const newList = [...accessor.value];
|
|
388
|
+
newList.splice(elementIndex, 1);
|
|
389
|
+
accessor.set(newList);
|
|
390
|
+
// delete any value overrides so the new list isn't shadowed
|
|
423
391
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
...postfix,
|
|
428
|
-
].join('.');
|
|
429
|
-
const fieldOverride = this.fieldOverrides[fromJsonPath];
|
|
430
|
-
delete this.fieldOverrides[fromJsonPath];
|
|
431
|
-
this.fieldOverrides[toJsonPath] = fieldOverride;
|
|
432
|
-
const validation = this.validation[fromJsonPath];
|
|
433
|
-
delete this.validation[fromJsonPath];
|
|
434
|
-
this.validation[toJsonPath] = validation;
|
|
435
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
|
|
436
|
-
this.moveListItem(fromJsonPath, toJsonPath);
|
|
437
|
-
});
|
|
438
|
-
accessor.set(newList);
|
|
439
|
-
// delete any value overrides so the new list isn't shadowed
|
|
440
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
441
|
-
delete this.fieldOverrides[listValuePath];
|
|
392
|
+
delete this.fieldOverrides[listValuePath];
|
|
393
|
+
indicesToKeys.splice(elementIndex, 1);
|
|
394
|
+
}
|
|
442
395
|
});
|
|
443
396
|
});
|
|
444
397
|
}
|
|
445
|
-
moveListItem(fromValuePath, toValuePath) {
|
|
446
|
-
// do nothing, this is for subclasses to override
|
|
447
|
-
// put in some nonsense so TS doesn't complain about the parameters not being used
|
|
448
|
-
fromValuePath;
|
|
449
|
-
toValuePath;
|
|
450
|
-
}
|
|
451
398
|
internalSetFieldValue(valuePath, value, validation) {
|
|
452
399
|
const { revert } = this.getAdapterForValuePath(valuePath);
|
|
453
400
|
assertExists(revert, 'setting value not supported {}', valuePath);
|
|
@@ -528,7 +475,7 @@ let FormModel = (() => {
|
|
|
528
475
|
});
|
|
529
476
|
}
|
|
530
477
|
isValuePathActive(valuePath) {
|
|
531
|
-
const values = flattenValuesOfType(this.type, this.value);
|
|
478
|
+
const values = flattenValuesOfType(this.type, this.value, this.listIndicesToKeys);
|
|
532
479
|
const keys = new Set(Object.keys(values));
|
|
533
480
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
534
481
|
return keys.has(valuePath);
|
|
@@ -606,6 +553,7 @@ let FormModel = (() => {
|
|
|
606
553
|
_get_knownFields_decorators = [computed];
|
|
607
554
|
_get_accessors_decorators = [computed];
|
|
608
555
|
_get_dirty_decorators = [computed];
|
|
556
|
+
_get_valueChanged_decorators = [computed];
|
|
609
557
|
__esDecorate(_a, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
|
|
610
558
|
__esDecorate(_a, null, _fieldOverrides_decorators, { kind: "accessor", name: "fieldOverrides", static: false, private: false, access: { has: obj => "fieldOverrides" in obj, get: obj => obj.fieldOverrides, set: (obj, value) => { obj.fieldOverrides = value; } }, metadata: _metadata }, _fieldOverrides_initializers, _fieldOverrides_extraInitializers);
|
|
611
559
|
__esDecorate(_a, null, _errorOverrides_decorators, { kind: "accessor", name: "errorOverrides", static: false, private: false, access: { has: obj => "errorOverrides" in obj, get: obj => obj.errorOverrides, set: (obj, value) => { obj.errorOverrides = value; } }, metadata: _metadata }, _errorOverrides_initializers, _errorOverrides_extraInitializers);
|
|
@@ -614,6 +562,7 @@ let FormModel = (() => {
|
|
|
614
562
|
__esDecorate(_a, null, _get_knownFields_decorators, { kind: "getter", name: "knownFields", static: false, private: false, access: { has: obj => "knownFields" in obj, get: obj => obj.knownFields }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
615
563
|
__esDecorate(_a, null, _get_accessors_decorators, { kind: "getter", name: "accessors", static: false, private: false, access: { has: obj => "accessors" in obj, get: obj => obj.accessors }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
616
564
|
__esDecorate(_a, null, _get_dirty_decorators, { kind: "getter", name: "dirty", static: false, private: false, access: { has: obj => "dirty" in obj, get: obj => obj.dirty }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
565
|
+
__esDecorate(_a, null, _get_valueChanged_decorators, { kind: "getter", name: "valueChanged", static: false, private: false, access: { has: obj => "valueChanged" in obj, get: obj => obj.valueChanged }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
617
566
|
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
618
567
|
})(),
|
|
619
568
|
_a;
|
|
@@ -546,19 +546,20 @@ describe('all', function () {
|
|
|
546
546
|
});
|
|
547
547
|
it.each([
|
|
548
548
|
[
|
|
549
|
-
|
|
549
|
+
// new
|
|
550
|
+
'$.3',
|
|
550
551
|
'0',
|
|
551
552
|
],
|
|
552
553
|
[
|
|
553
|
-
'$.
|
|
554
|
+
'$.0',
|
|
554
555
|
'x',
|
|
555
556
|
],
|
|
556
557
|
[
|
|
557
|
-
'$.
|
|
558
|
+
'$.1',
|
|
558
559
|
'3',
|
|
559
560
|
],
|
|
560
561
|
[
|
|
561
|
-
'$.
|
|
562
|
+
'$.2',
|
|
562
563
|
'z',
|
|
563
564
|
],
|
|
564
565
|
])('it reports the value of field %s as %s', function (path, fieldValue) {
|
|
@@ -567,19 +568,20 @@ describe('all', function () {
|
|
|
567
568
|
});
|
|
568
569
|
it.each([
|
|
569
570
|
[
|
|
570
|
-
|
|
571
|
+
// new
|
|
572
|
+
'$.3',
|
|
571
573
|
undefined,
|
|
572
574
|
],
|
|
573
575
|
[
|
|
574
|
-
'$.
|
|
576
|
+
'$.0',
|
|
575
577
|
IS_NAN_ERROR,
|
|
576
578
|
],
|
|
577
579
|
[
|
|
578
|
-
'$.
|
|
580
|
+
'$.1',
|
|
579
581
|
undefined,
|
|
580
582
|
],
|
|
581
583
|
[
|
|
582
|
-
'$.
|
|
584
|
+
'$.2',
|
|
583
585
|
IS_NAN_ERROR,
|
|
584
586
|
],
|
|
585
587
|
])('it reports the error of field %s', function (path, error) {
|
|
@@ -636,11 +638,11 @@ describe('all', function () {
|
|
|
636
638
|
});
|
|
637
639
|
it('updates the field values and errors', function () {
|
|
638
640
|
expect(model.fields).toEqual({
|
|
639
|
-
'$.
|
|
641
|
+
'$.1': expect.objectContaining({
|
|
640
642
|
value: '3',
|
|
641
643
|
error: undefined,
|
|
642
644
|
}),
|
|
643
|
-
'$.
|
|
645
|
+
'$.2': expect.objectContaining({
|
|
644
646
|
value: 'z',
|
|
645
647
|
error: IS_NAN_ERROR,
|
|
646
648
|
}),
|
|
@@ -663,7 +665,7 @@ describe('all', function () {
|
|
|
663
665
|
value: 'x',
|
|
664
666
|
error: IS_NAN_ERROR,
|
|
665
667
|
}),
|
|
666
|
-
'$.
|
|
668
|
+
'$.2': expect.objectContaining({
|
|
667
669
|
value: 'z',
|
|
668
670
|
error: IS_NAN_ERROR,
|
|
669
671
|
}),
|
|
@@ -679,7 +681,7 @@ describe('all', function () {
|
|
|
679
681
|
});
|
|
680
682
|
it('updates the field values and errors', function () {
|
|
681
683
|
expect(model.fields).toEqual({
|
|
682
|
-
'$.
|
|
684
|
+
'$.2': expect.objectContaining({
|
|
683
685
|
value: 'z',
|
|
684
686
|
error: IS_NAN_ERROR,
|
|
685
687
|
}),
|
|
@@ -6,11 +6,12 @@ import { type ValueTypeOfField } from 'types/value_type_of_field';
|
|
|
6
6
|
import { type MantineFieldComponent, type MantineForm } from './types';
|
|
7
7
|
export type SuppliedListProps<Value = any, ListPath extends string = string> = {
|
|
8
8
|
values: readonly Value[];
|
|
9
|
+
indexKeys: number[];
|
|
9
10
|
listPath: ListPath;
|
|
10
11
|
};
|
|
11
12
|
export declare function createList<F extends Fields, K extends keyof ListFieldsOfFields<F>, Props extends SuppliedListProps<ElementOfArray<ValueTypeOfField<F[K]>>> & {
|
|
12
13
|
children: (valuePath: `${K}.${number}`, value: ElementOfArray<ValueTypeOfField<F[K]>>, index: number) => React.ReactNode;
|
|
13
14
|
}>(this: MantineForm<F>, valuePath: K, List: ComponentType<Props>): MantineFieldComponent<SuppliedListProps<ElementOfArray<ValueTypeOfField<F[K]>>>, Props, never>;
|
|
14
|
-
export declare function DefaultList<Value, ListPath extends string>({ values, listPath, children, }: SuppliedListProps<Value, ListPath> & {
|
|
15
|
+
export declare function DefaultList<Value, ListPath extends string>({ values, indexKeys, listPath, children, }: SuppliedListProps<Value, ListPath> & {
|
|
15
16
|
children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
|
|
16
17
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { assertExistsAndReturn, } from '@strictly/base';
|
|
2
3
|
import { Fragment, } from 'react';
|
|
3
4
|
import { createUnsafePartialObserverComponent } from 'util/partial';
|
|
4
5
|
export function createList(valuePath, List) {
|
|
5
6
|
const propSource = () => {
|
|
6
|
-
const
|
|
7
|
+
const field = this.fields[valuePath];
|
|
8
|
+
const values = [...field.value];
|
|
7
9
|
return {
|
|
8
10
|
values,
|
|
9
11
|
listPath: valuePath,
|
|
12
|
+
indexKeys: assertExistsAndReturn(field.listIndexToKey, 'list index to key mapping missing in {}', valuePath),
|
|
10
13
|
};
|
|
11
14
|
};
|
|
12
15
|
return createUnsafePartialObserverComponent(List, propSource);
|
|
13
16
|
}
|
|
14
|
-
export function DefaultList({ values, listPath, children, }) {
|
|
17
|
+
export function DefaultList({ values, indexKeys, listPath, children, }) {
|
|
15
18
|
return (_jsx(_Fragment, { children: values.map(function (value, index) {
|
|
16
|
-
|
|
19
|
+
return [
|
|
20
|
+
value,
|
|
21
|
+
index,
|
|
22
|
+
indexKeys[index],
|
|
23
|
+
];
|
|
24
|
+
}).filter(function ([_value, _index, key,]) {
|
|
25
|
+
// omit entries without keys
|
|
26
|
+
return key != null;
|
|
27
|
+
}).map(function ([value, index, key,]) {
|
|
28
|
+
const valuePath = `${listPath}.${key}`;
|
|
17
29
|
return (_jsx(Fragment, { children: children(valuePath, value, index) }, valuePath));
|
|
18
30
|
}) }));
|
|
19
31
|
}
|
|
@@ -26,6 +26,7 @@ export const Empty = {
|
|
|
26
26
|
readonly: false,
|
|
27
27
|
required: false,
|
|
28
28
|
value: [],
|
|
29
|
+
listIndexToKey: [0],
|
|
29
30
|
},
|
|
30
31
|
},
|
|
31
32
|
},
|
|
@@ -42,6 +43,13 @@ export const Populated = {
|
|
|
42
43
|
'C',
|
|
43
44
|
'D',
|
|
44
45
|
],
|
|
46
|
+
listIndexToKey: [
|
|
47
|
+
100,
|
|
48
|
+
1,
|
|
49
|
+
33,
|
|
50
|
+
5,
|
|
51
|
+
101,
|
|
52
|
+
],
|
|
45
53
|
},
|
|
46
54
|
},
|
|
47
55
|
},
|