@homebound/form-state 2.26.10 → 2.26.11

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.
@@ -208,6 +208,8 @@ parentInstance, parentState, key, rules, listConfig, config, strictOrder, maybeA
208
208
  //
209
209
  // Only do this if one of our client-side objects is missing an id
210
210
  const incomingByHash = idKey && currentItems.some((item) => !item[idKey]) && (0, utils_1.groupBy)(incomingItems, hashWithoutId);
211
+ // Watch for deletions
212
+ const hasOpKey = Object.keys(listConfig.config).includes("op");
211
213
  // First, process all current items
212
214
  for (const currentItem of currentItems) {
213
215
  const childState = rowMap.get(currentItem); // We'll always have a child state for `currentItems`
@@ -222,8 +224,13 @@ parentInstance, parentState, key, rules, listConfig, config, strictOrder, maybeA
222
224
  addedRows.delete(currentItem);
223
225
  }
224
226
  else if (childState.dirty || addedRows.has(currentItem)) {
225
- // If no incoming, but we're dirty, keep the WIP change
226
- mergedItems.push(currentItem);
227
+ // If no incoming, but we're dirty (...and not deleted), keep the WIP change
228
+ if (hasOpKey && currentItem.op === "delete") {
229
+ // delete
230
+ }
231
+ else {
232
+ mergedItems.push(currentItem);
233
+ }
227
234
  }
228
235
  else {
229
236
  // Local is not dirty, and it's not upstream, so remove it
@@ -205,6 +205,59 @@ describe("formState", () => {
205
205
  // And we're not longer dirty
206
206
  expect(state.books.dirty).toBe(false);
207
207
  });
208
+ it("list value can refresh and not drop new children that are just data", () => {
209
+ const config = configBuilders_1.f.config({
210
+ firstName: configBuilders_1.f.value(),
211
+ tags: configBuilders_1.f.list({ combo: configBuilders_1.f.value() }),
212
+ });
213
+ const state = (0, objectField_1.createObjectState)(config, { firstName: "a1", tags: [] });
214
+ // And we add a new child on the client-side (and it doesn't have an id)
215
+ state.tags.add({ combo: ["b1", "b2"] });
216
+ // When we refresh it with the original list undefined
217
+ state.set({ tags: [] }, { refreshing: true });
218
+ // Then it keeps the new child
219
+ expect(state.tags.value).toEqual([{ combo: ["b1", "b2"] }]);
220
+ // And it's still considered changed
221
+ expect(state.tags.dirty).toBe(true);
222
+ expect(state.tags.originalValue).toEqual([]);
223
+ // And we add an additional child
224
+ state.tags.add({ combo: ["c1", "c2"] });
225
+ // And a refresh brings back the 1st child acked from the server
226
+ state.set({ tags: [{ combo: ["b1", "b2"] }] }, { refreshing: true });
227
+ // Then we still have 2 children
228
+ expect(state.tags.value).toEqual([{ combo: ["b1", "b2"] }, { combo: ["c1", "c2"] }]);
229
+ // And we're still dirty
230
+ expect(state.tags.dirty).toBe(true);
231
+ // When the server finally acks both children
232
+ state.set({ tags: [{ combo: ["b1", "b2"] }, { combo: ["c1", "c2"] }] }, { refreshing: true });
233
+ // Then we're finally clean
234
+ expect(state.tags.dirty).toBe(false);
235
+ });
236
+ it("list value can refresh and drop children that were deleted", () => {
237
+ // Given a list field that is currently populated
238
+ const a1 = {
239
+ id: "a:1",
240
+ firstName: "a1",
241
+ books: [
242
+ { id: "b:1", title: "b1", op: "include" },
243
+ { id: "b:2", title: "b2", op: "include" },
244
+ ],
245
+ };
246
+ // And incremental deletion is enabled
247
+ const config = configBuilders_1.f.config({
248
+ id: configBuilders_1.f.value(),
249
+ books: configBuilders_1.f.list({ id: configBuilders_1.f.value(), title: configBuilders_1.f.value(), op: configBuilders_1.f.value() }),
250
+ });
251
+ const state = (0, objectField_1.createObjectState)(config, a1);
252
+ // When we delete the 1st book
253
+ state.books.rows[0].op.set("delete");
254
+ // When we refresh it only the 2nd book
255
+ state.set({ books: [{ id: "b:2", title: "b2" }] }, { refreshing: true });
256
+ // Then we only have 1 book
257
+ expect(state.books.value).toEqual([{ id: "b:2", title: "b2", op: "include" }]);
258
+ // And we're not dirty
259
+ expect(state.books.dirty).toBe(false);
260
+ });
208
261
  it("list value can observe changes", () => {
209
262
  const b1 = { title: "t1" };
210
263
  const a1 = { firstName: "a1", books: [b1] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/form-state",
3
- "version": "2.26.10",
3
+ "version": "2.26.11",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",