@strictly/react-form 0.0.26 → 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,110 +630,47 @@ 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
- });
724
- accessor.set(newList);
725
- 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
+ }
726
674
  });
727
675
  });
728
676
  }
@@ -805,7 +753,7 @@ var FormModel = class {
805
753
  });
806
754
  }
807
755
  isValuePathActive(valuePath) {
808
- const values = (0, import_define.flattenValuesOfType)(this.type, this.value);
756
+ const values = (0, import_define.flattenValuesOfType)(this.type, this.value, this.listIndicesToKeys);
809
757
  const keys = new Set(Object.keys(values));
810
758
  return keys.has(valuePath);
811
759
  }
@@ -885,6 +833,7 @@ __decorateElement(_init, 2, "fields", _fields_dec, FormModel);
885
833
  __decorateElement(_init, 2, "knownFields", _knownFields_dec, FormModel);
886
834
  __decorateElement(_init, 2, "accessors", _accessors_dec, FormModel);
887
835
  __decorateElement(_init, 2, "dirty", _dirty_dec, FormModel);
836
+ __decorateElement(_init, 2, "valueChanged", _valueChanged_dec, FormModel);
888
837
  __decoratorMetadata(_init, FormModel);
889
838
 
890
839
  // core/mobx/hooks.tsx
@@ -915,7 +864,7 @@ function useDefaultMobxFormHooks(model, {
915
864
  const onFieldBlur = (0, import_react.useCallback)(
916
865
  function(path) {
917
866
  setTimeout(function() {
918
- if (model.isValuePathActive(path) && model.isFieldDirty(path)) {
867
+ if (model.isValuePathActive(path) && model.isFieldDirty(path) && model.fields[path].error == null) {
919
868
  model.validateField(path, Math.max(1 /* Changed */, model.getValidation(path)));
920
869
  }
921
870
  }, 100);
@@ -1240,7 +1189,7 @@ function DefaultErrorRenderer({
1240
1189
 
1241
1190
  // mantine/hooks.tsx
1242
1191
  var import_core = require("@mantine/core");
1243
- var import_base6 = require("@strictly/base");
1192
+ var import_base7 = require("@strictly/base");
1244
1193
  var import_mobx2 = require("mobx");
1245
1194
  var import_react6 = require("react");
1246
1195
 
@@ -1599,25 +1548,45 @@ function createForm(valuePath, Form, observableProps) {
1599
1548
  }
1600
1549
 
1601
1550
  // mantine/create_list.tsx
1551
+ var import_base6 = require("@strictly/base");
1602
1552
  var import_react5 = require("react");
1603
1553
  var import_jsx_runtime6 = require("react/jsx-runtime");
1604
1554
  function createList(valuePath, List) {
1605
1555
  const propSource = () => {
1606
- const values = [...this.fields[valuePath].value];
1556
+ const field = this.fields[valuePath];
1557
+ const values = [...field.value];
1607
1558
  return {
1608
1559
  values,
1609
- listPath: valuePath
1560
+ listPath: valuePath,
1561
+ indexKeys: (0, import_base6.assertExistsAndReturn)(field.listIndexToKey, "list index to key mapping missing in {}", valuePath)
1610
1562
  };
1611
1563
  };
1612
1564
  return createUnsafePartialObserverComponent(List, propSource);
1613
1565
  }
1614
1566
  function DefaultList({
1615
1567
  values,
1568
+ indexKeys,
1616
1569
  listPath,
1617
1570
  children
1618
1571
  }) {
1619
1572
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: values.map(function(value, index) {
1620
- 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}`;
1621
1590
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react5.Fragment, { children: children(valuePath, value, index) }, valuePath);
1622
1591
  }) });
1623
1592
  }
@@ -1865,34 +1834,34 @@ var _fields_dec2, _init2, _fields;
1865
1834
  _fields_dec2 = [import_mobx2.observable.ref];
1866
1835
  var MantineFormImpl = class {
1867
1836
  constructor(fields) {
1868
- __publicField(this, "textInputCache", new import_base6.Cache(
1837
+ __publicField(this, "textInputCache", new import_base7.Cache(
1869
1838
  createTextInput.bind(this)
1870
1839
  ));
1871
- __publicField(this, "valueInputCache", new import_base6.Cache(
1840
+ __publicField(this, "valueInputCache", new import_base7.Cache(
1872
1841
  createValueInput.bind(this)
1873
1842
  ));
1874
- __publicField(this, "checkboxCache", new import_base6.Cache(
1843
+ __publicField(this, "checkboxCache", new import_base7.Cache(
1875
1844
  createCheckbox.bind(this)
1876
1845
  ));
1877
- __publicField(this, "radioGroupCache", new import_base6.Cache(
1846
+ __publicField(this, "radioGroupCache", new import_base7.Cache(
1878
1847
  createRadioGroup.bind(this)
1879
1848
  ));
1880
- __publicField(this, "radioCache", new import_base6.Cache(
1849
+ __publicField(this, "radioCache", new import_base7.Cache(
1881
1850
  createRadio.bind(this)
1882
1851
  ));
1883
- __publicField(this, "pillCache", new import_base6.Cache(
1852
+ __publicField(this, "pillCache", new import_base7.Cache(
1884
1853
  createPill.bind(this)
1885
1854
  ));
1886
- __publicField(this, "listCache", new import_base6.Cache(
1855
+ __publicField(this, "listCache", new import_base7.Cache(
1887
1856
  createList.bind(this)
1888
1857
  ));
1889
- __publicField(this, "fieldViewCache", new import_base6.Cache(
1858
+ __publicField(this, "fieldViewCache", new import_base7.Cache(
1890
1859
  createFieldView.bind(this)
1891
1860
  ));
1892
- __publicField(this, "fieldsViewCache", new import_base6.Cache(
1861
+ __publicField(this, "fieldsViewCache", new import_base7.Cache(
1893
1862
  createFieldsView.bind(this)
1894
1863
  ));
1895
- __publicField(this, "formCache", new import_base6.Cache(createForm.bind(this)));
1864
+ __publicField(this, "formCache", new import_base7.Cache(createForm.bind(this)));
1896
1865
  __privateAdd(this, _fields, __runInitializers(_init2, 8, this)), __runInitializers(_init2, 11, this);
1897
1866
  __publicField(this, "onFieldValueChange");
1898
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,6 +156,7 @@ 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;
@@ -370,9 +374,10 @@ type FieldsView<ValuePath extends string = string, C extends ComponentType<any>
370
374
 
371
375
  type SuppliedListProps<Value = any, ListPath extends string = string> = {
372
376
  values: readonly Value[];
377
+ indexKeys: number[];
373
378
  listPath: ListPath;
374
379
  };
375
- 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> & {
376
381
  children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
377
382
  }): react_jsx_runtime.JSX.Element;
378
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,6 +156,7 @@ 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;
@@ -370,9 +374,10 @@ type FieldsView<ValuePath extends string = string, C extends ComponentType<any>
370
374
 
371
375
  type SuppliedListProps<Value = any, ListPath extends string = string> = {
372
376
  values: readonly Value[];
377
+ indexKeys: number[];
373
378
  listPath: ListPath;
374
379
  };
375
- 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> & {
376
381
  children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
377
382
  }): react_jsx_runtime.JSX.Element;
378
383