mobx-formkit 1.1.1 → 1.1.3

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.
@@ -129,6 +129,8 @@
129
129
  class ArrayMap {
130
130
  /** Duck-typing marker for utility code */
131
131
  _isArrayMap = true;
132
+ /** Called after a successful `move()` — used to flag the change as dirty */
133
+ onMove;
132
134
  /** Internal observable array: entries stored as [key, value] pairs */
133
135
  _entries = mobx.observable.array([]);
134
136
  constructor(entries) {
@@ -246,6 +248,7 @@
246
248
  return;
247
249
  const [entry] = this._entries.splice(fromIndex, 1);
248
250
  this._entries.splice(toIndex, 0, entry);
251
+ this.onMove?.();
249
252
  });
250
253
  }
251
254
  /**
@@ -963,7 +966,14 @@
963
966
  set: mobx.action,
964
967
  add: mobx.action,
965
968
  del: mobx.action,
969
+ move: mobx.action,
966
970
  });
971
+ // Any reorder of the fields (also when `fields.move()` is called
972
+ // directly) flags the field and the form as changed. (#657)
973
+ this.fields.onMove = () => {
974
+ this.$changed++;
975
+ this.state.form.$changed++;
976
+ };
967
977
  }
968
978
  execHook = (name, fallback = {}, ...args) => $try(fallback[name], this.$hooks[name], this.noop).apply(this, [this, ...args]);
969
979
  execHandler = (name, args, fallback = undefined, hook = null, execHook = true) => [
@@ -1204,7 +1214,21 @@
1204
1214
  deepCheck(type, prop, fields) {
1205
1215
  const $fields = getObservableMapValues(fields);
1206
1216
  return lodash.transform($fields, (check, field) => {
1207
- if (!field.fields.size || !Array.isArray(field.initial)) {
1217
+ // Array containers are skipped because most of their props are
1218
+ // computed recursively on their nested fields. Some props are not
1219
+ // recursive (isDirty/isPristine compare the container value with
1220
+ // its initial value) or must aggregate the container itself
1221
+ // (isValid/hasError), so they are taken into account for array
1222
+ // containers too. (#656, #657)
1223
+ const isContainerProp = [
1224
+ FieldPropsEnum.isValid,
1225
+ FieldPropsEnum.hasError,
1226
+ FieldPropsEnum.isDirty,
1227
+ FieldPropsEnum.isPristine,
1228
+ ].includes(prop);
1229
+ if (isContainerProp ||
1230
+ !field.fields.size ||
1231
+ !Array.isArray(field.initial)) {
1208
1232
  check.push(field[prop]);
1209
1233
  }
1210
1234
  check.push(checkPropOccurrence({
@@ -1471,17 +1495,41 @@
1471
1495
  return this;
1472
1496
  }
1473
1497
  let key;
1498
+ const tree = pathToFieldsTree(this.state.struct(), this.path ?? "", 0, true);
1499
+ const nestedFields = tree[0]?.fields ?? null;
1500
+ // An object without field-definition props, whose keys match the
1501
+ // nested fields of the container, holds the values of the new item
1502
+ // (e.g. add({ name: 'John', qty: 1 })). The 'name' prop is ambiguous:
1503
+ // it is treated as a value only when the container defines a nested
1504
+ // field called 'name'. (#657)
1505
+ const payloadKeys = lodash.isPlainObject(obj)
1506
+ ? Object.keys(obj).filter((k) => k !== FieldPropsEnum.key)
1507
+ : [];
1508
+ const isValuesPayload = !!nestedFields &&
1509
+ lodash.isPlainObject(obj) &&
1510
+ !lodash.has(obj, FieldPropsEnum.value) &&
1511
+ !lodash.has(obj, FieldPropsEnum.fields) &&
1512
+ payloadKeys.length > 0 &&
1513
+ (!lodash.has(obj, FieldPropsEnum.name) ||
1514
+ Object.prototype.hasOwnProperty.call(nestedFields, FieldPropsEnum.name));
1474
1515
  if (lodash.has(obj, FieldPropsEnum.key))
1475
1516
  key = obj.key;
1476
- if (lodash.has(obj, FieldPropsEnum.name))
1517
+ if (!isValuesPayload && lodash.has(obj, FieldPropsEnum.name))
1477
1518
  key = obj.name;
1478
1519
  if (!key)
1479
1520
  key = maxKey(this.fields);
1480
1521
  const $path = ($key) => [this.path, $key].join(".").replace(/^\.+/, "");
1481
- const tree = pathToFieldsTree(this.state.struct(), this.path ?? "", 0, true);
1482
- const field = this.initField(key, $path(key), lodash.merge(tree[0], obj));
1522
+ const field = this.initField(key, $path(key), isValuesPayload ? tree[0] : lodash.merge(tree[0], obj));
1483
1523
  const hasValues = lodash.has(obj, FieldPropsEnum.value) || lodash.has(obj, FieldPropsEnum.fields);
1484
- if (!hasValues) {
1524
+ if (isValuesPayload) {
1525
+ lodash.each(payloadKeys, (fieldName) => {
1526
+ const nestedField = field.select(fieldName);
1527
+ if (nestedField && !nestedField.hasNestedFields) {
1528
+ nestedField.set(FieldPropsEnum.value, obj[fieldName]);
1529
+ }
1530
+ });
1531
+ }
1532
+ else if (!hasValues) {
1485
1533
  // When the struct defines nested fields and obj is a plain object
1486
1534
  // without field-definition props (key, name), treat obj properties
1487
1535
  // directly as nested field values (e.g. add({ firstname: 'John' }))
@@ -2523,11 +2571,12 @@
2523
2571
  }
2524
2572
  get isDirty() {
2525
2573
  const value = this.changed ? this.value : this.initial;
2526
- return !lodash.isEqual(this.initial, value);
2574
+ // a soft deleted field differs from its initial state
2575
+ return !lodash.isEqual(this.initial, value) || this.deleted;
2527
2576
  }
2528
2577
  get isPristine() {
2529
2578
  const value = this.changed ? this.value : this.initial;
2530
- return lodash.isEqual(this.initial, value);
2579
+ return lodash.isEqual(this.initial, value) && !this.deleted;
2531
2580
  }
2532
2581
  get isEmpty() {
2533
2582
  if (this.hasNestedFields)
@@ -2558,9 +2607,10 @@
2558
2607
  : this.$touched;
2559
2608
  }
2560
2609
  get deleted() {
2561
- return this.hasNestedFields
2562
- ? this.check(FieldPropsEnum.deleted, true)
2563
- : this.$deleted;
2610
+ // an explicit flag on the field itself always wins
2611
+ if (this.$deleted)
2612
+ return true;
2613
+ return this.hasNestedFields ? this.check(FieldPropsEnum.deleted, true) : false;
2564
2614
  }
2565
2615
  /* ------------------------------------------------------------------ */
2566
2616
  /* EVENTS HANDLERS */