@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/dist/index.js CHANGED
@@ -306,7 +306,6 @@ function listAdapter() {
306
306
  import {
307
307
  assertExists,
308
308
  assertExistsAndReturn,
309
- assertState,
310
309
  checkValidNumber,
311
310
  map,
312
311
  toArray,
@@ -333,11 +332,12 @@ var Validation = /* @__PURE__ */ ((Validation2) => {
333
332
  Validation2[Validation2["Always"] = 2] = "Always";
334
333
  return Validation2;
335
334
  })(Validation || {});
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];
335
+ var _valueChanged_dec, _dirty_dec, _accessors_dec, _knownFields_dec, _fields_dec, _validation_dec, _errorOverrides_dec, _fieldOverrides_dec, _value_dec, _init, _value, _fieldOverrides, _errorOverrides, _validation;
336
+ _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], _valueChanged_dec = [computed];
338
337
  var FormModel = class {
339
338
  constructor(type, originalValue, adapters, mode) {
340
339
  this.type = type;
340
+ this.originalValue = originalValue;
341
341
  this.adapters = adapters;
342
342
  this.mode = mode;
343
343
  __runInitializers(_init, 5, this);
@@ -349,7 +349,9 @@ var FormModel = class {
349
349
  // cannot be type safe
350
350
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
351
351
  __publicField(this, "originalValues");
352
- this.originalValues = flattenValuesOfType(type, originalValue);
352
+ // maintains the value paths of lists when the original order is destroyed by deletes or reordering
353
+ __publicField(this, "listIndicesToKeys", {});
354
+ this.originalValues = flattenValuesOfType(type, originalValue, this.listIndicesToKeys);
353
355
  this.value = mobxCopy(type, originalValue);
354
356
  this.flattenedTypeDefs = flattenTypesOfType(type);
355
357
  const conversions = flattenValueTo(
@@ -371,7 +373,8 @@ var FormModel = class {
371
373
  return;
372
374
  }
373
375
  return convert(fieldValue, valuePath, contextValue);
374
- }
376
+ },
377
+ this.listIndicesToKeys
375
378
  );
376
379
  this.fieldOverrides = map(conversions, function(_k, v) {
377
380
  return v && [v.value];
@@ -417,7 +420,8 @@ var FormModel = class {
417
420
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
418
421
  typePath
419
422
  );
420
- }
423
+ },
424
+ this.listIndicesToKeys
421
425
  );
422
426
  }
423
427
  maybeSynthesizeFieldByValuePath(valuePath) {
@@ -526,7 +530,9 @@ var FormModel = class {
526
530
  value: displayedValue,
527
531
  error,
528
532
  readonly: readonly && !this.forceMutableFields,
529
- required
533
+ required,
534
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
535
+ listIndexToKey: this.listIndicesToKeys[valuePath]
530
536
  };
531
537
  }
532
538
  getAccessorForValuePath(valuePath) {
@@ -539,7 +545,8 @@ var FormModel = class {
539
545
  this.value,
540
546
  (value) => {
541
547
  this.value = mobxCopy(this.type, value);
542
- }
548
+ },
549
+ this.listIndicesToKeys
543
550
  );
544
551
  }
545
552
  maybeGetAdapterForValuePath(valuePath) {
@@ -558,6 +565,9 @@ var FormModel = class {
558
565
  return this.isFieldDirty(valuePath);
559
566
  });
560
567
  }
568
+ get valueChanged() {
569
+ return !equals(this.type, this.value, this.originalValue);
570
+ }
561
571
  typePath(valuePath) {
562
572
  return valuePathToTypePath(this.type, valuePath, true);
563
573
  }
@@ -589,118 +599,50 @@ var FormModel = class {
589
599
  element,
590
600
  ...originalList.slice(definedIndex)
591
601
  ];
592
- const targetPaths = Object.keys(this.fieldOverrides).filter(function(v) {
593
- return v.startsWith(`${listValuePath}.`);
594
- }).map(function(v) {
595
- const parts = v.substring(listValuePath.length + 1).split(".");
596
- const index2 = parseInt(parts[0]);
597
- return [
598
- index2,
599
- parts.slice(1)
600
- ];
601
- }).filter(function([index2]) {
602
- return index2 >= definedIndex;
603
- }).sort(function([a], [b]) {
604
- return b - a;
605
- });
606
602
  runInAction(() => {
607
- targetPaths.forEach(([
608
- index2,
609
- postfix
610
- ]) => {
611
- const fromJsonPath = [
612
- listValuePath,
613
- `${index2}`,
614
- ...postfix
615
- ].join(".");
616
- const toJsonPath = [
617
- listValuePath,
618
- `${index2 + 1}`,
619
- ...postfix
620
- ].join(".");
621
- const fieldOverride = this.fieldOverrides[fromJsonPath];
622
- delete this.fieldOverrides[fromJsonPath];
623
- this.fieldOverrides[toJsonPath] = fieldOverride;
624
- const validation = this.validation[fromJsonPath];
625
- delete this.validation[fromJsonPath];
626
- this.validation[toJsonPath] = validation;
627
- });
628
603
  accessor.set(newList);
629
604
  delete this.fieldOverrides[listValuePath];
605
+ const indicesToKeys = assertExistsAndReturn(
606
+ this.listIndicesToKeys[listValuePath],
607
+ "no index to key mapping for list {}",
608
+ listValuePath
609
+ );
610
+ const nextKey = indicesToKeys[indicesToKeys.length - 1];
611
+ indicesToKeys.splice(definedIndex, 0, nextKey);
612
+ indicesToKeys[indicesToKeys.length - 1] = nextKey + 1;
630
613
  });
631
614
  }
632
615
  removeListItem(...elementValuePaths) {
633
- const orderedElementValuePaths = elementValuePaths.toSorted().reverse();
634
616
  runInAction(() => {
635
- orderedElementValuePaths.forEach((elementValuePath) => {
617
+ elementValuePaths.forEach((elementValuePath) => {
618
+ var _a;
636
619
  const [
637
620
  listValuePath,
638
- elementIndexString
621
+ elementKeyString
639
622
  ] = assertExistsAndReturn(
640
623
  jsonPathPop(elementValuePath),
641
624
  "expected a path with two or more segments {}",
642
625
  elementValuePath
643
626
  );
644
627
  const accessor = this.accessors[listValuePath];
645
- const elementIndex = checkValidNumber(
646
- parseInt(elementIndexString),
647
- "unexpected index {} ({})",
648
- elementIndexString,
649
- elementValuePath
650
- );
651
- const newList = [...accessor.value];
652
- assertState(
653
- elementIndex >= 0 && elementIndex < newList.length,
654
- "invalid index from path {} ({})",
655
- elementIndex,
628
+ const elementKey = checkValidNumber(
629
+ parseInt(elementKeyString),
630
+ "unexpected id {} ({})",
631
+ elementKeyString,
656
632
  elementValuePath
657
633
  );
658
- newList.splice(elementIndex, 1);
659
- const targetPaths = Object.keys(this.fieldOverrides).filter(function(v) {
660
- return v.startsWith(`${listValuePath}.`);
661
- }).map(function(v) {
662
- const parts = v.substring(listValuePath.length + 1).split(".");
663
- const index = parseInt(parts[0]);
664
- return [
665
- index,
666
- parts.slice(1)
667
- ];
668
- }).filter(function([index]) {
669
- return index > elementIndex;
670
- }).sort(function([a], [b]) {
671
- return a - b;
672
- });
673
- targetPaths.forEach(([
674
- index,
675
- postfix
676
- ]) => {
677
- const fromJsonPath = [
678
- listValuePath,
679
- `${index}`,
680
- ...postfix
681
- ].join(".");
682
- const toJsonPath = [
683
- listValuePath,
684
- `${index - 1}`,
685
- ...postfix
686
- ].join(".");
687
- const fieldOverride = this.fieldOverrides[fromJsonPath];
688
- delete this.fieldOverrides[fromJsonPath];
689
- this.fieldOverrides[toJsonPath] = fieldOverride;
690
- const validation = this.validation[fromJsonPath];
691
- delete this.validation[fromJsonPath];
692
- this.validation[toJsonPath] = validation;
693
- this.moveListItem(fromJsonPath, toJsonPath);
694
- });
695
- accessor.set(newList);
696
- delete this.fieldOverrides[listValuePath];
634
+ const indicesToKeys = this.listIndicesToKeys[listValuePath];
635
+ const elementIndex = (_a = indicesToKeys == null ? void 0 : indicesToKeys.indexOf(elementKey)) != null ? _a : -1;
636
+ if (elementIndex >= 0) {
637
+ const newList = [...accessor.value];
638
+ newList.splice(elementIndex, 1);
639
+ accessor.set(newList);
640
+ delete this.fieldOverrides[listValuePath];
641
+ indicesToKeys.splice(elementIndex, 1);
642
+ }
697
643
  });
698
644
  });
699
645
  }
700
- moveListItem(fromValuePath, toValuePath) {
701
- fromValuePath;
702
- toValuePath;
703
- }
704
646
  internalSetFieldValue(valuePath, value, validation) {
705
647
  const { revert } = this.getAdapterForValuePath(valuePath);
706
648
  assertExists(revert, "setting value not supported {}", valuePath);
@@ -780,7 +722,7 @@ var FormModel = class {
780
722
  });
781
723
  }
782
724
  isValuePathActive(valuePath) {
783
- const values = flattenValuesOfType(this.type, this.value);
725
+ const values = flattenValuesOfType(this.type, this.value, this.listIndicesToKeys);
784
726
  const keys = new Set(Object.keys(values));
785
727
  return keys.has(valuePath);
786
728
  }
@@ -860,6 +802,7 @@ __decorateElement(_init, 2, "fields", _fields_dec, FormModel);
860
802
  __decorateElement(_init, 2, "knownFields", _knownFields_dec, FormModel);
861
803
  __decorateElement(_init, 2, "accessors", _accessors_dec, FormModel);
862
804
  __decorateElement(_init, 2, "dirty", _dirty_dec, FormModel);
805
+ __decorateElement(_init, 2, "valueChanged", _valueChanged_dec, FormModel);
863
806
  __decoratorMetadata(_init, FormModel);
864
807
 
865
808
  // core/mobx/hooks.tsx
@@ -1611,27 +1554,49 @@ function createForm(valuePath, Form, observableProps) {
1611
1554
  }
1612
1555
 
1613
1556
  // mantine/create_list.tsx
1557
+ import {
1558
+ assertExistsAndReturn as assertExistsAndReturn2
1559
+ } from "@strictly/base";
1614
1560
  import {
1615
1561
  Fragment
1616
1562
  } from "react";
1617
1563
  import { Fragment as Fragment2, jsx as jsx6 } from "react/jsx-runtime";
1618
1564
  function createList(valuePath, List) {
1619
1565
  const propSource = () => {
1620
- const values = [...this.fields[valuePath].value];
1566
+ const field = this.fields[valuePath];
1567
+ const values = [...field.value];
1621
1568
  return {
1622
1569
  values,
1623
- listPath: valuePath
1570
+ listPath: valuePath,
1571
+ indexKeys: assertExistsAndReturn2(field.listIndexToKey, "list index to key mapping missing in {}", valuePath)
1624
1572
  };
1625
1573
  };
1626
1574
  return createUnsafePartialObserverComponent(List, propSource);
1627
1575
  }
1628
1576
  function DefaultList({
1629
1577
  values,
1578
+ indexKeys,
1630
1579
  listPath,
1631
1580
  children
1632
1581
  }) {
1633
1582
  return /* @__PURE__ */ jsx6(Fragment2, { children: values.map(function(value, index) {
1634
- const valuePath = `${listPath}.${index}`;
1583
+ return [
1584
+ value,
1585
+ index,
1586
+ indexKeys[index]
1587
+ ];
1588
+ }).filter(function([
1589
+ _value2,
1590
+ _index,
1591
+ key
1592
+ ]) {
1593
+ return key != null;
1594
+ }).map(function([
1595
+ value,
1596
+ index,
1597
+ key
1598
+ ]) {
1599
+ const valuePath = `${listPath}.${key}`;
1635
1600
  return /* @__PURE__ */ jsx6(Fragment, { children: children(valuePath, value, index) }, valuePath);
1636
1601
  }) });
1637
1602
  }
@@ -1,4 +1,7 @@
1
- import { type ElementOfArray } from '@strictly/base'
1
+ import {
2
+ assertExistsAndReturn,
3
+ type ElementOfArray,
4
+ } from '@strictly/base'
2
5
  import {
3
6
  type ComponentType,
4
7
  Fragment,
@@ -15,6 +18,7 @@ import {
15
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
19
  export type SuppliedListProps<Value = any, ListPath extends string = string> = {
17
20
  values: readonly Value[],
21
+ indexKeys: number[],
18
22
  listPath: ListPath,
19
23
  }
20
24
 
@@ -34,10 +38,12 @@ export function createList<
34
38
  List: ComponentType<Props>,
35
39
  ): MantineFieldComponent<SuppliedListProps<ElementOfArray<ValueTypeOfField<F[K]>>>, Props, never> {
36
40
  const propSource = () => {
37
- const values = [...this.fields[valuePath].value]
41
+ const field = this.fields[valuePath]
42
+ const values = [...field.value]
38
43
  return {
39
44
  values,
40
45
  listPath: valuePath,
46
+ indexKeys: assertExistsAndReturn(field.listIndexToKey, 'list index to key mapping missing in {}', valuePath),
41
47
  }
42
48
  }
43
49
  return createUnsafePartialObserverComponent(List, propSource)
@@ -48,6 +54,7 @@ export function DefaultList<
48
54
  ListPath extends string,
49
55
  >({
50
56
  values,
57
+ indexKeys,
51
58
  listPath,
52
59
  children,
53
60
  }: SuppliedListProps<Value, ListPath> & {
@@ -56,7 +63,24 @@ export function DefaultList<
56
63
  return (
57
64
  <>
58
65
  {values.map(function (value, index) {
59
- const valuePath: `${ListPath}.${number}` = `${listPath}.${index}`
66
+ return [
67
+ value,
68
+ index,
69
+ indexKeys[index],
70
+ ] as const
71
+ }).filter(function ([
72
+ _value,
73
+ _index,
74
+ key,
75
+ ]) {
76
+ // omit entries without keys
77
+ return key != null
78
+ }).map(function ([
79
+ value,
80
+ index,
81
+ key,
82
+ ]) {
83
+ const valuePath: `${ListPath}.${number}` = `${listPath}.${key}`
60
84
  return (
61
85
  <Fragment key={valuePath}>
62
86
  {children(valuePath, value, index)}
@@ -40,7 +40,7 @@ exports[`mantine list hooks > renders Populated 1`] = `
40
40
  >
41
41
  <span>
42
42
  ValuePath:
43
- $.0
43
+ $.100
44
44
  </span>
45
45
  <br />
46
46
  <span>
@@ -78,7 +78,7 @@ exports[`mantine list hooks > renders Populated 1`] = `
78
78
  >
79
79
  <span>
80
80
  ValuePath:
81
- $.2
81
+ $.33
82
82
  </span>
83
83
  <br />
84
84
  <span>
@@ -97,7 +97,7 @@ exports[`mantine list hooks > renders Populated 1`] = `
97
97
  >
98
98
  <span>
99
99
  ValuePath:
100
- $.3
100
+ $.5
101
101
  </span>
102
102
  <br />
103
103
  <span>
@@ -70,6 +70,7 @@ export const Empty: Story = {
70
70
  readonly: false,
71
71
  required: false,
72
72
  value: [],
73
+ listIndexToKey: [0],
73
74
  },
74
75
  },
75
76
  },
@@ -87,6 +88,13 @@ export const Populated: Story = {
87
88
  'C',
88
89
  'D',
89
90
  ],
91
+ listIndexToKey: [
92
+ 100,
93
+ 1,
94
+ 33,
95
+ 5,
96
+ 101,
97
+ ],
90
98
  },
91
99
  },
92
100
  },
package/package.json CHANGED
@@ -72,7 +72,7 @@
72
72
  "test:watch": "vitest"
73
73
  },
74
74
  "type": "module",
75
- "version": "0.0.27",
75
+ "version": "0.0.28",
76
76
  "exports": {
77
77
  ".": {
78
78
  "import": {
package/types/field.ts CHANGED
@@ -4,6 +4,7 @@ export type Field<V = any, E = any> = {
4
4
  readonly error?: E | undefined,
5
5
  readonly readonly: boolean,
6
6
  readonly required: boolean,
7
+ readonly listIndexToKey?: number[],
7
8
  }
8
9
 
9
10
  export type Fields = Readonly<Record<string, Field>>