@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.cjs CHANGED
@@ -363,11 +363,12 @@ var Validation = /* @__PURE__ */ ((Validation2) => {
363
363
  Validation2[Validation2["Always"] = 2] = "Always";
364
364
  return Validation2;
365
365
  })(Validation || {});
366
- var _dirty_dec, _accessors_dec, _knownFields_dec, _fields_dec, _validation_dec, _errorOverrides_dec, _fieldOverrides_dec, _value_dec, _init, _value, _fieldOverrides, _errorOverrides, _validation;
367
- _value_dec = [import_mobx.observable.ref], _fieldOverrides_dec = [import_mobx.observable.shallow], _errorOverrides_dec = [import_mobx.observable.shallow], _validation_dec = [import_mobx.observable.shallow], _fields_dec = [import_mobx.computed], _knownFields_dec = [import_mobx.computed], _accessors_dec = [import_mobx.computed], _dirty_dec = [import_mobx.computed];
366
+ var _valueChanged_dec, _dirty_dec, _accessors_dec, _knownFields_dec, _fields_dec, _validation_dec, _errorOverrides_dec, _fieldOverrides_dec, _value_dec, _init, _value, _fieldOverrides, _errorOverrides, _validation;
367
+ _value_dec = [import_mobx.observable.ref], _fieldOverrides_dec = [import_mobx.observable.shallow], _errorOverrides_dec = [import_mobx.observable.shallow], _validation_dec = [import_mobx.observable.shallow], _fields_dec = [import_mobx.computed], _knownFields_dec = [import_mobx.computed], _accessors_dec = [import_mobx.computed], _dirty_dec = [import_mobx.computed], _valueChanged_dec = [import_mobx.computed];
368
368
  var FormModel = class {
369
369
  constructor(type, originalValue, adapters, mode) {
370
370
  this.type = type;
371
+ this.originalValue = originalValue;
371
372
  this.adapters = adapters;
372
373
  this.mode = mode;
373
374
  __runInitializers(_init, 5, this);
@@ -379,7 +380,9 @@ var FormModel = class {
379
380
  // cannot be type safe
380
381
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
381
382
  __publicField(this, "originalValues");
382
- this.originalValues = (0, import_define.flattenValuesOfType)(type, originalValue);
383
+ // maintains the value paths of lists when the original order is destroyed by deletes or reordering
384
+ __publicField(this, "listIndicesToKeys", {});
385
+ this.originalValues = (0, import_define.flattenValuesOfType)(type, originalValue, this.listIndicesToKeys);
383
386
  this.value = (0, import_define.mobxCopy)(type, originalValue);
384
387
  this.flattenedTypeDefs = (0, import_define.flattenTypesOfType)(type);
385
388
  const conversions = (0, import_define.flattenValueTo)(
@@ -401,7 +404,8 @@ var FormModel = class {
401
404
  return;
402
405
  }
403
406
  return convert(fieldValue, valuePath, contextValue);
404
- }
407
+ },
408
+ this.listIndicesToKeys
405
409
  );
406
410
  this.fieldOverrides = (0, import_base2.map)(conversions, function(_k, v) {
407
411
  return v && [v.value];
@@ -447,7 +451,8 @@ var FormModel = class {
447
451
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
448
452
  typePath
449
453
  );
450
- }
454
+ },
455
+ this.listIndicesToKeys
451
456
  );
452
457
  }
453
458
  maybeSynthesizeFieldByValuePath(valuePath) {
@@ -556,7 +561,9 @@ var FormModel = class {
556
561
  value: displayedValue,
557
562
  error,
558
563
  readonly: readonly && !this.forceMutableFields,
559
- required
564
+ required,
565
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
566
+ listIndexToKey: this.listIndicesToKeys[valuePath]
560
567
  };
561
568
  }
562
569
  getAccessorForValuePath(valuePath) {
@@ -569,7 +576,8 @@ var FormModel = class {
569
576
  this.value,
570
577
  (value) => {
571
578
  this.value = (0, import_define.mobxCopy)(this.type, value);
572
- }
579
+ },
580
+ this.listIndicesToKeys
573
581
  );
574
582
  }
575
583
  maybeGetAdapterForValuePath(valuePath) {
@@ -588,6 +596,9 @@ var FormModel = class {
588
596
  return this.isFieldDirty(valuePath);
589
597
  });
590
598
  }
599
+ get valueChanged() {
600
+ return !(0, import_define.equals)(this.type, this.value, this.originalValue);
601
+ }
591
602
  typePath(valuePath) {
592
603
  return (0, import_define.valuePathToTypePath)(this.type, valuePath, true);
593
604
  }
@@ -619,118 +630,50 @@ var FormModel = class {
619
630
  element,
620
631
  ...originalList.slice(definedIndex)
621
632
  ];
622
- const targetPaths = Object.keys(this.fieldOverrides).filter(function(v) {
623
- return v.startsWith(`${listValuePath}.`);
624
- }).map(function(v) {
625
- const parts = v.substring(listValuePath.length + 1).split(".");
626
- const index2 = parseInt(parts[0]);
627
- return [
628
- index2,
629
- parts.slice(1)
630
- ];
631
- }).filter(function([index2]) {
632
- return index2 >= definedIndex;
633
- }).sort(function([a], [b]) {
634
- return b - a;
635
- });
636
633
  (0, import_mobx.runInAction)(() => {
637
- targetPaths.forEach(([
638
- index2,
639
- postfix
640
- ]) => {
641
- const fromJsonPath = [
642
- listValuePath,
643
- `${index2}`,
644
- ...postfix
645
- ].join(".");
646
- const toJsonPath = [
647
- listValuePath,
648
- `${index2 + 1}`,
649
- ...postfix
650
- ].join(".");
651
- const fieldOverride = this.fieldOverrides[fromJsonPath];
652
- delete this.fieldOverrides[fromJsonPath];
653
- this.fieldOverrides[toJsonPath] = fieldOverride;
654
- const validation = this.validation[fromJsonPath];
655
- delete this.validation[fromJsonPath];
656
- this.validation[toJsonPath] = validation;
657
- });
658
634
  accessor.set(newList);
659
635
  delete this.fieldOverrides[listValuePath];
636
+ const indicesToKeys = (0, import_base2.assertExistsAndReturn)(
637
+ this.listIndicesToKeys[listValuePath],
638
+ "no index to key mapping for list {}",
639
+ listValuePath
640
+ );
641
+ const nextKey = indicesToKeys[indicesToKeys.length - 1];
642
+ indicesToKeys.splice(definedIndex, 0, nextKey);
643
+ indicesToKeys[indicesToKeys.length - 1] = nextKey + 1;
660
644
  });
661
645
  }
662
646
  removeListItem(...elementValuePaths) {
663
- const orderedElementValuePaths = elementValuePaths.toSorted().reverse();
664
647
  (0, import_mobx.runInAction)(() => {
665
- orderedElementValuePaths.forEach((elementValuePath) => {
648
+ elementValuePaths.forEach((elementValuePath) => {
649
+ var _a;
666
650
  const [
667
651
  listValuePath,
668
- elementIndexString
652
+ elementKeyString
669
653
  ] = (0, import_base2.assertExistsAndReturn)(
670
654
  (0, import_define.jsonPathPop)(elementValuePath),
671
655
  "expected a path with two or more segments {}",
672
656
  elementValuePath
673
657
  );
674
658
  const accessor = this.accessors[listValuePath];
675
- const elementIndex = (0, import_base2.checkValidNumber)(
676
- parseInt(elementIndexString),
677
- "unexpected index {} ({})",
678
- elementIndexString,
679
- elementValuePath
680
- );
681
- const newList = [...accessor.value];
682
- (0, import_base2.assertState)(
683
- elementIndex >= 0 && elementIndex < newList.length,
684
- "invalid index from path {} ({})",
685
- elementIndex,
659
+ const elementKey = (0, import_base2.checkValidNumber)(
660
+ parseInt(elementKeyString),
661
+ "unexpected id {} ({})",
662
+ elementKeyString,
686
663
  elementValuePath
687
664
  );
688
- newList.splice(elementIndex, 1);
689
- const targetPaths = Object.keys(this.fieldOverrides).filter(function(v) {
690
- return v.startsWith(`${listValuePath}.`);
691
- }).map(function(v) {
692
- const parts = v.substring(listValuePath.length + 1).split(".");
693
- const index = parseInt(parts[0]);
694
- return [
695
- index,
696
- parts.slice(1)
697
- ];
698
- }).filter(function([index]) {
699
- return index > elementIndex;
700
- }).sort(function([a], [b]) {
701
- return a - b;
702
- });
703
- targetPaths.forEach(([
704
- index,
705
- postfix
706
- ]) => {
707
- const fromJsonPath = [
708
- listValuePath,
709
- `${index}`,
710
- ...postfix
711
- ].join(".");
712
- const toJsonPath = [
713
- listValuePath,
714
- `${index - 1}`,
715
- ...postfix
716
- ].join(".");
717
- const fieldOverride = this.fieldOverrides[fromJsonPath];
718
- delete this.fieldOverrides[fromJsonPath];
719
- this.fieldOverrides[toJsonPath] = fieldOverride;
720
- const validation = this.validation[fromJsonPath];
721
- delete this.validation[fromJsonPath];
722
- this.validation[toJsonPath] = validation;
723
- this.moveListItem(fromJsonPath, toJsonPath);
724
- });
725
- accessor.set(newList);
726
- delete this.fieldOverrides[listValuePath];
665
+ const indicesToKeys = this.listIndicesToKeys[listValuePath];
666
+ const elementIndex = (_a = indicesToKeys == null ? void 0 : indicesToKeys.indexOf(elementKey)) != null ? _a : -1;
667
+ if (elementIndex >= 0) {
668
+ const newList = [...accessor.value];
669
+ newList.splice(elementIndex, 1);
670
+ accessor.set(newList);
671
+ delete this.fieldOverrides[listValuePath];
672
+ indicesToKeys.splice(elementIndex, 1);
673
+ }
727
674
  });
728
675
  });
729
676
  }
730
- moveListItem(fromValuePath, toValuePath) {
731
- fromValuePath;
732
- toValuePath;
733
- }
734
677
  internalSetFieldValue(valuePath, value, validation) {
735
678
  const { revert } = this.getAdapterForValuePath(valuePath);
736
679
  (0, import_base2.assertExists)(revert, "setting value not supported {}", valuePath);
@@ -810,7 +753,7 @@ var FormModel = class {
810
753
  });
811
754
  }
812
755
  isValuePathActive(valuePath) {
813
- const values = (0, import_define.flattenValuesOfType)(this.type, this.value);
756
+ const values = (0, import_define.flattenValuesOfType)(this.type, this.value, this.listIndicesToKeys);
814
757
  const keys = new Set(Object.keys(values));
815
758
  return keys.has(valuePath);
816
759
  }
@@ -890,6 +833,7 @@ __decorateElement(_init, 2, "fields", _fields_dec, FormModel);
890
833
  __decorateElement(_init, 2, "knownFields", _knownFields_dec, FormModel);
891
834
  __decorateElement(_init, 2, "accessors", _accessors_dec, FormModel);
892
835
  __decorateElement(_init, 2, "dirty", _dirty_dec, FormModel);
836
+ __decorateElement(_init, 2, "valueChanged", _valueChanged_dec, FormModel);
893
837
  __decoratorMetadata(_init, FormModel);
894
838
 
895
839
  // core/mobx/hooks.tsx
@@ -1245,7 +1189,7 @@ function DefaultErrorRenderer({
1245
1189
 
1246
1190
  // mantine/hooks.tsx
1247
1191
  var import_core = require("@mantine/core");
1248
- var import_base6 = require("@strictly/base");
1192
+ var import_base7 = require("@strictly/base");
1249
1193
  var import_mobx2 = require("mobx");
1250
1194
  var import_react6 = require("react");
1251
1195
 
@@ -1604,25 +1548,45 @@ function createForm(valuePath, Form, observableProps) {
1604
1548
  }
1605
1549
 
1606
1550
  // mantine/create_list.tsx
1551
+ var import_base6 = require("@strictly/base");
1607
1552
  var import_react5 = require("react");
1608
1553
  var import_jsx_runtime6 = require("react/jsx-runtime");
1609
1554
  function createList(valuePath, List) {
1610
1555
  const propSource = () => {
1611
- const values = [...this.fields[valuePath].value];
1556
+ const field = this.fields[valuePath];
1557
+ const values = [...field.value];
1612
1558
  return {
1613
1559
  values,
1614
- listPath: valuePath
1560
+ listPath: valuePath,
1561
+ indexKeys: (0, import_base6.assertExistsAndReturn)(field.listIndexToKey, "list index to key mapping missing in {}", valuePath)
1615
1562
  };
1616
1563
  };
1617
1564
  return createUnsafePartialObserverComponent(List, propSource);
1618
1565
  }
1619
1566
  function DefaultList({
1620
1567
  values,
1568
+ indexKeys,
1621
1569
  listPath,
1622
1570
  children
1623
1571
  }) {
1624
1572
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: values.map(function(value, index) {
1625
- const valuePath = `${listPath}.${index}`;
1573
+ return [
1574
+ value,
1575
+ index,
1576
+ indexKeys[index]
1577
+ ];
1578
+ }).filter(function([
1579
+ _value2,
1580
+ _index,
1581
+ key
1582
+ ]) {
1583
+ return key != null;
1584
+ }).map(function([
1585
+ value,
1586
+ index,
1587
+ key
1588
+ ]) {
1589
+ const valuePath = `${listPath}.${key}`;
1626
1590
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react5.Fragment, { children: children(valuePath, value, index) }, valuePath);
1627
1591
  }) });
1628
1592
  }
@@ -1870,34 +1834,34 @@ var _fields_dec2, _init2, _fields;
1870
1834
  _fields_dec2 = [import_mobx2.observable.ref];
1871
1835
  var MantineFormImpl = class {
1872
1836
  constructor(fields) {
1873
- __publicField(this, "textInputCache", new import_base6.Cache(
1837
+ __publicField(this, "textInputCache", new import_base7.Cache(
1874
1838
  createTextInput.bind(this)
1875
1839
  ));
1876
- __publicField(this, "valueInputCache", new import_base6.Cache(
1840
+ __publicField(this, "valueInputCache", new import_base7.Cache(
1877
1841
  createValueInput.bind(this)
1878
1842
  ));
1879
- __publicField(this, "checkboxCache", new import_base6.Cache(
1843
+ __publicField(this, "checkboxCache", new import_base7.Cache(
1880
1844
  createCheckbox.bind(this)
1881
1845
  ));
1882
- __publicField(this, "radioGroupCache", new import_base6.Cache(
1846
+ __publicField(this, "radioGroupCache", new import_base7.Cache(
1883
1847
  createRadioGroup.bind(this)
1884
1848
  ));
1885
- __publicField(this, "radioCache", new import_base6.Cache(
1849
+ __publicField(this, "radioCache", new import_base7.Cache(
1886
1850
  createRadio.bind(this)
1887
1851
  ));
1888
- __publicField(this, "pillCache", new import_base6.Cache(
1852
+ __publicField(this, "pillCache", new import_base7.Cache(
1889
1853
  createPill.bind(this)
1890
1854
  ));
1891
- __publicField(this, "listCache", new import_base6.Cache(
1855
+ __publicField(this, "listCache", new import_base7.Cache(
1892
1856
  createList.bind(this)
1893
1857
  ));
1894
- __publicField(this, "fieldViewCache", new import_base6.Cache(
1858
+ __publicField(this, "fieldViewCache", new import_base7.Cache(
1895
1859
  createFieldView.bind(this)
1896
1860
  ));
1897
- __publicField(this, "fieldsViewCache", new import_base6.Cache(
1861
+ __publicField(this, "fieldsViewCache", new import_base7.Cache(
1898
1862
  createFieldsView.bind(this)
1899
1863
  ));
1900
- __publicField(this, "formCache", new import_base6.Cache(createForm.bind(this)));
1864
+ __publicField(this, "formCache", new import_base7.Cache(createForm.bind(this)));
1901
1865
  __privateAdd(this, _fields, __runInitializers(_init2, 8, this)), __runInitializers(_init2, 11, this);
1902
1866
  __publicField(this, "onFieldValueChange");
1903
1867
  __publicField(this, "onFieldFocus");
package/dist/index.d.cts CHANGED
@@ -84,6 +84,7 @@ type Field<V = any, E = any> = {
84
84
  readonly error?: E | undefined;
85
85
  readonly readonly: boolean;
86
86
  readonly required: boolean;
87
+ readonly listIndexToKey?: number[];
87
88
  };
88
89
  type Fields = Readonly<Record<string, Field>>;
89
90
 
@@ -132,6 +133,7 @@ type ContextOf<TypePathsToAdapters extends Partial<Readonly<Record<string, Field
132
133
  type FormMode = 'edit' | 'create';
133
134
  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>> {
134
135
  readonly type: T;
136
+ private readonly originalValue;
135
137
  protected readonly adapters: TypePathsToAdapters;
136
138
  protected readonly mode: FormMode;
137
139
  accessor value: MobxValueOfType<T>;
@@ -140,6 +142,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
140
142
  accessor validation: FlattenedValidation<ValuePathsToAdapters>;
141
143
  private readonly flattenedTypeDefs;
142
144
  private readonly originalValues;
145
+ private readonly listIndicesToKeys;
143
146
  constructor(type: T, originalValue: ValueOfType<ReadonlyTypeOfType<T>>, adapters: TypePathsToAdapters, mode: FormMode);
144
147
  protected abstract toContext(value: ValueOfType<ReadonlyTypeOfType<T>>, valuePath: keyof ValuePathsToAdapters): ContextType;
145
148
  get forceMutableFields(): boolean;
@@ -153,11 +156,11 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
153
156
  private maybeGetAdapterForValuePath;
154
157
  private getAdapterForValuePath;
155
158
  get dirty(): boolean;
159
+ get valueChanged(): boolean;
156
160
  typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K];
157
161
  setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation): boolean;
158
162
  addListItem<K extends keyof FlattenedListTypesOfType<T>>(valuePath: K, elementValue?: Maybe<ElementOfArray<FlattenedValuesOfType<T>[K]>>, index?: number): void;
159
163
  removeListItem<K extends keyof FlattenedListTypesOfType<T>>(...elementValuePaths: readonly `${K}.${number}`[]): void;
160
- protected moveListItem<K extends keyof FlattenedListTypesOfType<T>>(fromValuePath: K, toValuePath: K): void;
161
164
  private internalSetFieldValue;
162
165
  /**
163
166
  * Forces an error onto a field. Error will be removed if the field value changes
@@ -371,9 +374,10 @@ type FieldsView<ValuePath extends string = string, C extends ComponentType<any>
371
374
 
372
375
  type SuppliedListProps<Value = any, ListPath extends string = string> = {
373
376
  values: readonly Value[];
377
+ indexKeys: number[];
374
378
  listPath: ListPath;
375
379
  };
376
- declare function DefaultList<Value, ListPath extends string>({ values, listPath, children, }: SuppliedListProps<Value, ListPath> & {
380
+ declare function DefaultList<Value, ListPath extends string>({ values, indexKeys, listPath, children, }: SuppliedListProps<Value, ListPath> & {
377
381
  children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
378
382
  }): react_jsx_runtime.JSX.Element;
379
383
 
package/dist/index.d.ts CHANGED
@@ -84,6 +84,7 @@ type Field<V = any, E = any> = {
84
84
  readonly error?: E | undefined;
85
85
  readonly readonly: boolean;
86
86
  readonly required: boolean;
87
+ readonly listIndexToKey?: number[];
87
88
  };
88
89
  type Fields = Readonly<Record<string, Field>>;
89
90
 
@@ -132,6 +133,7 @@ type ContextOf<TypePathsToAdapters extends Partial<Readonly<Record<string, Field
132
133
  type FormMode = 'edit' | 'create';
133
134
  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>> {
134
135
  readonly type: T;
136
+ private readonly originalValue;
135
137
  protected readonly adapters: TypePathsToAdapters;
136
138
  protected readonly mode: FormMode;
137
139
  accessor value: MobxValueOfType<T>;
@@ -140,6 +142,7 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
140
142
  accessor validation: FlattenedValidation<ValuePathsToAdapters>;
141
143
  private readonly flattenedTypeDefs;
142
144
  private readonly originalValues;
145
+ private readonly listIndicesToKeys;
143
146
  constructor(type: T, originalValue: ValueOfType<ReadonlyTypeOfType<T>>, adapters: TypePathsToAdapters, mode: FormMode);
144
147
  protected abstract toContext(value: ValueOfType<ReadonlyTypeOfType<T>>, valuePath: keyof ValuePathsToAdapters): ContextType;
145
148
  get forceMutableFields(): boolean;
@@ -153,11 +156,11 @@ declare abstract class FormModel<T extends Type, ValueToTypePaths extends Readon
153
156
  private maybeGetAdapterForValuePath;
154
157
  private getAdapterForValuePath;
155
158
  get dirty(): boolean;
159
+ get valueChanged(): boolean;
156
160
  typePath<K extends keyof ValueToTypePaths>(valuePath: K): ValueToTypePaths[K];
157
161
  setFieldValue<K extends keyof ValuePathsToAdapters>(valuePath: K, value: ToOfFieldAdapter<ValuePathsToAdapters[K]>, validation?: Validation): boolean;
158
162
  addListItem<K extends keyof FlattenedListTypesOfType<T>>(valuePath: K, elementValue?: Maybe<ElementOfArray<FlattenedValuesOfType<T>[K]>>, index?: number): void;
159
163
  removeListItem<K extends keyof FlattenedListTypesOfType<T>>(...elementValuePaths: readonly `${K}.${number}`[]): void;
160
- protected moveListItem<K extends keyof FlattenedListTypesOfType<T>>(fromValuePath: K, toValuePath: K): void;
161
164
  private internalSetFieldValue;
162
165
  /**
163
166
  * Forces an error onto a field. Error will be removed if the field value changes
@@ -371,9 +374,10 @@ type FieldsView<ValuePath extends string = string, C extends ComponentType<any>
371
374
 
372
375
  type SuppliedListProps<Value = any, ListPath extends string = string> = {
373
376
  values: readonly Value[];
377
+ indexKeys: number[];
374
378
  listPath: ListPath;
375
379
  };
376
- declare function DefaultList<Value, ListPath extends string>({ values, listPath, children, }: SuppliedListProps<Value, ListPath> & {
380
+ declare function DefaultList<Value, ListPath extends string>({ values, indexKeys, listPath, children, }: SuppliedListProps<Value, ListPath> & {
377
381
  children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
378
382
  }): react_jsx_runtime.JSX.Element;
379
383