@homebound/form-state 2.2.6 → 2.2.7
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/formState.js +17 -4
- package/dist/formState.test.js +34 -15
- package/package.json +1 -1
package/dist/formState.js
CHANGED
|
@@ -329,7 +329,7 @@ function newValueFieldState(parentInstance, parentState, key, rules, isIdKey, is
|
|
|
329
329
|
if (this.readOnly && !opts.resetting && !opts.refreshing) {
|
|
330
330
|
throw new Error(`${key} is currently readOnly`);
|
|
331
331
|
}
|
|
332
|
-
if (opts.refreshing && this.dirty) {
|
|
332
|
+
if (opts.refreshing && this.dirty && value !== this.value) {
|
|
333
333
|
// Ignore refreshed values if we're already dirty
|
|
334
334
|
return;
|
|
335
335
|
}
|
|
@@ -411,9 +411,18 @@ function newListFieldState(parentInstance, parentState, key, rules, listConfig,
|
|
|
411
411
|
},
|
|
412
412
|
// private
|
|
413
413
|
hasNewItems() {
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
414
|
+
const [current, original] = [this.value || [], originalCopy || []];
|
|
415
|
+
// Instead of relying on just object identities, we look up each child's state
|
|
416
|
+
// in rowMap, because we already dedup/check object identity (i.e. look for id fields)
|
|
417
|
+
// when create object states.
|
|
418
|
+
const a = current.every((e) => {
|
|
419
|
+
const state = rowMap.get(e);
|
|
420
|
+
return original.some((e) => rowMap.get(e) === state);
|
|
421
|
+
});
|
|
422
|
+
const b = original.every((e) => {
|
|
423
|
+
const state = rowMap.get(e);
|
|
424
|
+
return current.some((e) => rowMap.get(e) === state);
|
|
425
|
+
});
|
|
417
426
|
const isSame = a && b;
|
|
418
427
|
return !isSame;
|
|
419
428
|
},
|
|
@@ -496,6 +505,10 @@ function newListFieldState(parentInstance, parentState, key, rules, listConfig,
|
|
|
496
505
|
// Return the already-observable'd value so that our `parent.value[key] = values` doesn't re-proxy things
|
|
497
506
|
return childState.value;
|
|
498
507
|
});
|
|
508
|
+
// Reset originalCopy so that our dirty checks have the right # of rows.
|
|
509
|
+
if (opts.refreshing) {
|
|
510
|
+
originalCopy = [...(parentInstance[key] || [])];
|
|
511
|
+
}
|
|
499
512
|
_tick.value++;
|
|
500
513
|
},
|
|
501
514
|
add(value, spliceIndex) {
|
package/dist/formState.test.js
CHANGED
|
@@ -1197,6 +1197,18 @@ describe("formState", () => {
|
|
|
1197
1197
|
{ id: "b:3", title: "b3" },
|
|
1198
1198
|
],
|
|
1199
1199
|
};
|
|
1200
|
+
// Eventually our local values are saved
|
|
1201
|
+
const data3 = {
|
|
1202
|
+
id: "a:1",
|
|
1203
|
+
firstName: "local",
|
|
1204
|
+
lastName: "l2",
|
|
1205
|
+
address: { id: "address:1", street: "local", city: "c2" },
|
|
1206
|
+
books: [
|
|
1207
|
+
{ id: "b:1", title: "local" },
|
|
1208
|
+
{ id: "b:2", title: "b2" },
|
|
1209
|
+
{ id: "b:3", title: "b3" },
|
|
1210
|
+
],
|
|
1211
|
+
};
|
|
1200
1212
|
// And we start out with data1
|
|
1201
1213
|
const [data, setData] = react_1.useState(data1);
|
|
1202
1214
|
const form = formState_1.useFormState({ config, init: { input: data, map: (d) => d } });
|
|
@@ -1205,9 +1217,6 @@ describe("formState", () => {
|
|
|
1205
1217
|
form.address.street.value = "local";
|
|
1206
1218
|
form.books.rows[0].title.value = "local";
|
|
1207
1219
|
}
|
|
1208
|
-
function refreshData() {
|
|
1209
|
-
setData(data2);
|
|
1210
|
-
}
|
|
1211
1220
|
return (jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName" }, { children: form.firstName.value }), void 0),
|
|
1212
1221
|
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "lastName" }, { children: form.lastName.value }), void 0),
|
|
1213
1222
|
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "street" }, { children: form.address.street.value }), void 0),
|
|
@@ -1216,7 +1225,8 @@ describe("formState", () => {
|
|
|
1216
1225
|
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "title2" }, { children: form.books.rows[1].title.value }), void 0),
|
|
1217
1226
|
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "booksLength" }, { children: form.books.rows.length }), void 0),
|
|
1218
1227
|
jsx_runtime_1.jsx("button", { "data-testid": "makeLocalChanges", onClick: makeLocalChanges }, void 0),
|
|
1219
|
-
jsx_runtime_1.jsx("button", { "data-testid": "refreshData", onClick:
|
|
1228
|
+
jsx_runtime_1.jsx("button", { "data-testid": "refreshData", onClick: () => setData(data2) }, void 0),
|
|
1229
|
+
jsx_runtime_1.jsx("button", { "data-testid": "saveData", onClick: () => setData(data3) }, void 0),
|
|
1220
1230
|
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "changedValue" }, { children: JSON.stringify(form.changedValue) }), void 0)] }, void 0)) }, void 0));
|
|
1221
1231
|
}
|
|
1222
1232
|
// And we start out with the initial query data
|
|
@@ -1253,6 +1263,12 @@ describe("formState", () => {
|
|
|
1253
1263
|
books: [{ id: "b:1", title: "local" }, { id: "b:2" }, { id: "b:3" }],
|
|
1254
1264
|
firstName: "local",
|
|
1255
1265
|
});
|
|
1266
|
+
// And then when our mutation results come back
|
|
1267
|
+
rtl_utils_1.click(r.saveData);
|
|
1268
|
+
// Then changedValue doesn't show our local changes anymore
|
|
1269
|
+
expect(JSON.parse(r.changedValue().textContent)).toEqual({
|
|
1270
|
+
id: "a:1",
|
|
1271
|
+
});
|
|
1256
1272
|
});
|
|
1257
1273
|
it("useFormState can accept new data while read only", async () => {
|
|
1258
1274
|
// Given a component
|
|
@@ -1332,8 +1348,8 @@ describe("formState", () => {
|
|
|
1332
1348
|
expect(r.firstName().textContent).toEqual("f2");
|
|
1333
1349
|
expect(r.fullName().textContent).toEqual("f2 l2");
|
|
1334
1350
|
});
|
|
1335
|
-
it("can trigger
|
|
1336
|
-
const
|
|
1351
|
+
it("can trigger auto save for fields in list that were initially undefined", async () => {
|
|
1352
|
+
const autoSave = jest.fn();
|
|
1337
1353
|
// Given a component
|
|
1338
1354
|
function TestComponent() {
|
|
1339
1355
|
// When the data is initially undefined
|
|
@@ -1342,27 +1358,30 @@ describe("formState", () => {
|
|
|
1342
1358
|
const form = formState_1.useFormState({
|
|
1343
1359
|
config: authorWithBooksConfig,
|
|
1344
1360
|
init: { input: data, map: (d) => d, ifUndefined: { books: [] } },
|
|
1345
|
-
autoSave
|
|
1361
|
+
autoSave,
|
|
1346
1362
|
});
|
|
1347
1363
|
return (jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("button", { "data-testid": "refreshData", onClick: () => setData(data2) }, void 0),
|
|
1348
1364
|
jsx_runtime_1.jsx("button", { "data-testid": "add", onClick: () => form.books.add({ title: "New Book" }) }, void 0),
|
|
1349
|
-
jsx_runtime_1.jsx("button", { "data-testid": "
|
|
1350
|
-
jsx_runtime_1.jsx("button", { "data-testid": "
|
|
1365
|
+
jsx_runtime_1.jsx("button", { "data-testid": "blurBookOne", onClick: () => form.books.rows[0].title.blur() }, void 0),
|
|
1366
|
+
jsx_runtime_1.jsx("button", { "data-testid": "blurBookTwo", onClick: () => form.books.rows[1].title.blur() }, void 0)] }, void 0)) }, void 0));
|
|
1351
1367
|
}
|
|
1352
1368
|
// Given a formState with `onBlur` set
|
|
1353
1369
|
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}, void 0));
|
|
1354
1370
|
// When the data/child is now available
|
|
1355
1371
|
rtl_utils_1.click(r.refreshData);
|
|
1356
1372
|
// And the field is blurred
|
|
1357
|
-
rtl_utils_1.click(r.
|
|
1358
|
-
// Then
|
|
1359
|
-
expect(
|
|
1373
|
+
rtl_utils_1.click(r.blurBookOne);
|
|
1374
|
+
// Then we don't auto-save because nothing has changed
|
|
1375
|
+
expect(autoSave).toBeCalledTimes(0);
|
|
1360
1376
|
// And when adding a new book
|
|
1361
1377
|
rtl_utils_1.click(r.add);
|
|
1378
|
+
// We autoSave the new row right away (because we don't have any validation rules
|
|
1379
|
+
// that say the new row can't be empty)
|
|
1380
|
+
expect(autoSave).toBeCalledTimes(1);
|
|
1362
1381
|
// And the new book is blurred
|
|
1363
|
-
rtl_utils_1.click(r.
|
|
1364
|
-
// Then
|
|
1365
|
-
expect(
|
|
1382
|
+
rtl_utils_1.click(r.blurBookTwo);
|
|
1383
|
+
// Then we auto save again
|
|
1384
|
+
expect(autoSave).toBeCalledTimes(2);
|
|
1366
1385
|
});
|
|
1367
1386
|
});
|
|
1368
1387
|
class ObservableObject {
|