@arrai-innovations/reactive-helpers 11.0.0 → 11.0.2

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/README.md CHANGED
@@ -523,7 +523,7 @@ const managedList = useList({
523
523
  },
524
524
  });
525
525
  // the state expected of each are all available on the same state.
526
- console.log(managedList.state.value.objects);
526
+ console.log(managedList.state.objects);
527
527
  // managed instances can also be accessed directly.
528
528
  console.log(managedList.managed);
529
529
  /*
@@ -685,7 +685,7 @@ const managedObject = useObject({
685
685
  },
686
686
  });
687
687
  // the state expected of each are all available on the same state.
688
- console.log(managedObject.state.value.objects);
688
+ console.log(managedObject.state.objects);
689
689
  // managed instances can also be accessed directly.
690
690
  console.log(managedObject.managed);
691
691
  /*
@@ -727,7 +727,7 @@ const source2 = reactive({ b: 5 });
727
727
 
728
728
  const a = toRef(target, "a");
729
729
  const b = toRef(target, "b");
730
- const mySum = computed(() => (a.value || 0) + (b.value || 0));
730
+ const mySum = computed(() => (unref(a) || 0) + (unref(b) || 0));
731
731
 
732
732
  console.log(mySum.value); // 1
733
733
  assignReactiveObject(target, source);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arrai-innovations/reactive-helpers",
3
- "version": "11.0.0",
3
+ "version": "11.0.2",
4
4
  "description": "VueJS 3 utility composition functions to help manipulate objects and lists.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -154,10 +154,8 @@ describe("use/listFilter", () => {
154
154
  obj: filter.state,
155
155
  prop: "running",
156
156
  });
157
- const unrefOrder = deepUnref(filter.state.order);
158
- const unrefObjectsInOrder = deepUnref(filter.state.objectsInOrder);
159
- expect(unrefOrder).toEqual(expectedOrder);
160
- expect(unrefObjectsInOrder).toEqual(orderedObjects);
157
+ expect(filter.state.order).toEqual(expectedOrder);
158
+ expect(filter.state.objectsInOrder).toEqual(orderedObjects);
161
159
  });
162
160
  });
163
161
  describe("useListFilters accepts args and parentInstances", () => {
@@ -356,4 +354,148 @@ describe("use/listFilter", () => {
356
354
  });
357
355
  });
358
356
  });
357
+ it("you can use nested useListFilters", async () => {
358
+ const list = useListInstance({ props: {} });
359
+
360
+ function filter1AllowedFilter(object) {
361
+ return object.has_things && object.has_stuff;
362
+ }
363
+
364
+ function filter2AllowedFilter(object) {
365
+ return object.has_things && object.has_other_stuff;
366
+ }
367
+
368
+ const filter1 = useListFilter({
369
+ parentState: list.state,
370
+ allowedFilter: filter1AllowedFilter,
371
+ });
372
+ const filter2 = useListFilter({
373
+ parentState: filter1.state,
374
+ allowedFilter: filter2AllowedFilter,
375
+ });
376
+ await doAwaitNot({
377
+ obj: filter1.state,
378
+ prop: "running",
379
+ });
380
+ await doAwaitNot({
381
+ obj: filter2.state,
382
+ prop: "running",
383
+ });
384
+ expect(filter1.state.objects).toEqual({});
385
+ expect(filter1.state.order).toEqual([]);
386
+ expect(filter2.state.objects).toEqual({});
387
+ expect(filter2.state.order).toEqual([]);
388
+ list.addListObject({ id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true });
389
+ await doAwaitNot({
390
+ obj: filter1.state,
391
+ prop: "running",
392
+ });
393
+ await doAwaitNot({
394
+ obj: filter2.state,
395
+ prop: "running",
396
+ });
397
+ expect(filter1.state.objects).toEqual({
398
+ 1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
399
+ });
400
+ expect(filter1.state.order).toEqual(["1"]);
401
+ expect(filter2.state.objects).toEqual({
402
+ 1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
403
+ });
404
+ expect(filter2.state.order).toEqual(["1"]);
405
+ list.addListObject({ id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: false });
406
+ await doAwaitNot({
407
+ obj: filter1.state,
408
+ prop: "running",
409
+ });
410
+ await doAwaitNot({
411
+ obj: filter2.state,
412
+ prop: "running",
413
+ });
414
+ expect(filter1.state.objects).toEqual({
415
+ 1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
416
+ 2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: false },
417
+ });
418
+ expect(filter1.state.order).toEqual(["1", "2"]);
419
+ expect(filter2.state.objects).toEqual({
420
+ 1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
421
+ });
422
+ expect(filter2.state.order).toEqual(["1"]);
423
+ list.addListObject({ id: 3, name: "three", has_things: true, has_stuff: false, has_other_stuff: true });
424
+ await doAwaitNot({
425
+ obj: filter1.state,
426
+ prop: "running",
427
+ });
428
+ await doAwaitNot({
429
+ obj: filter2.state,
430
+ prop: "running",
431
+ });
432
+ expect(filter1.state.objects).toEqual({
433
+ 1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
434
+ 2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: false },
435
+ });
436
+ expect(filter1.state.order).toEqual(["1", "2"]);
437
+ expect(filter2.state.objects).toEqual({
438
+ 1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
439
+ });
440
+ expect(filter2.state.order).toEqual(["1"]);
441
+ list.addListObject({ id: 4, name: "four", has_things: true, has_stuff: false, has_other_stuff: false });
442
+ await doAwaitNot({
443
+ obj: filter1.state,
444
+ prop: "running",
445
+ });
446
+ await doAwaitNot({
447
+ obj: filter2.state,
448
+ prop: "running",
449
+ });
450
+ expect(filter1.state.objects).toEqual({
451
+ 1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
452
+ 2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: false },
453
+ });
454
+ expect(filter1.state.order).toEqual(["1", "2"]);
455
+ expect(filter2.state.objects).toEqual({
456
+ 1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
457
+ });
458
+ expect(filter2.state.order).toEqual(["1"]);
459
+ list.state.objects[1].has_stuff = false;
460
+ list.state.objects[2].has_other_stuff = true;
461
+ await doAwaitNot({
462
+ obj: filter1.state,
463
+ prop: "running",
464
+ });
465
+ await doAwaitNot({
466
+ obj: filter2.state,
467
+ prop: "running",
468
+ });
469
+ expect(filter1.state.objects).toEqual({
470
+ 2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: true },
471
+ });
472
+ expect(filter1.state.order).toEqual(["2"]);
473
+ expect(filter2.state.objects).toEqual({
474
+ 2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: true },
475
+ });
476
+ expect(filter2.state.order).toEqual(["2"]);
477
+ list.addListObject({ id: 5, name: "five", has_things: true, has_stuff: false, has_other_stuff: true });
478
+ list.addListObject({ id: 6, name: "six", has_things: true, has_stuff: true, has_other_stuff: false });
479
+ list.addListObject({ id: 7, name: "seven", has_things: false, has_stuff: true, has_other_stuff: true });
480
+ list.addListObject({ id: 8, name: "eight", has_things: true, has_stuff: true, has_other_stuff: true });
481
+ await doAwaitNot({
482
+ obj: filter1.state,
483
+ prop: "running",
484
+ });
485
+ await doAwaitNot({
486
+ obj: filter2.state,
487
+ prop: "running",
488
+ });
489
+ expect(filter1.state.objects).toEqual({
490
+ 2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: true },
491
+ 6: { id: 6, name: "six", has_things: true, has_stuff: true, has_other_stuff: false },
492
+ 8: { id: 8, name: "eight", has_things: true, has_stuff: true, has_other_stuff: true },
493
+ });
494
+ expect(filter1.state.order).toEqual(["2", "6", "8"]);
495
+ expect(filter2.state.objects).toEqual({
496
+ 2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: true },
497
+ 8: { id: 8, name: "eight", has_things: true, has_stuff: true, has_other_stuff: true },
498
+ });
499
+ expect(filter2.state.order).toEqual(["2", "8"]);
500
+ });
359
501
  });
@@ -1,3 +1,4 @@
1
+ import { doAwaitNot } from "../../../utils/index.js";
1
2
  import { expectErrorToBeNull } from "../expectHelpers.js";
2
3
  import flushPromises from "flush-promises";
3
4
  import keyBy from "lodash-es/keyBy.js";
@@ -308,6 +309,7 @@ describe("use/listInstance.spec.js", function () {
308
309
  expect(listInstance.state.errored).toBe(false);
309
310
  expect(listInstance.state.loading).toBe(false);
310
311
  expect({ ...listInstance.state.objects }).toEqual(crudListResolvedObjects2);
312
+ await nextTick();
311
313
  await flushPromises();
312
314
  expect(listInstance.state.order).toEqual(Object.keys(crudListResolvedObjects2));
313
315
  expect(listInstance.state.objectsInOrder).toEqual(Object.values(crudListResolvedObjects2));
@@ -429,7 +431,7 @@ describe("use/listInstance.spec.js", function () {
429
431
  expect(fakeId).toBeTruthy();
430
432
  });
431
433
  });
432
- it("computes objectsInOrder and maintains state", () => {
434
+ it("computes objectsInOrder and maintains state", async () => {
433
435
  const crudListResolvedPage3 = [
434
436
  {
435
437
  id: 3,
@@ -447,6 +449,7 @@ describe("use/listInstance.spec.js", function () {
447
449
  name: "zxcv",
448
450
  },
449
451
  ];
452
+ const crudListResolvedObjects3 = keyBy(crudListResolvedPage3, "id");
450
453
  const addObject = {
451
454
  id: 4,
452
455
  __str__: "yuio",
@@ -467,12 +470,22 @@ describe("use/listInstance.spec.js", function () {
467
470
 
468
471
  passedPageCallback(crudListResolvedPage3);
469
472
  crudListResolve();
473
+ await doAwaitNot({
474
+ obj: listInstance.state,
475
+ prop: "loading",
476
+ });
477
+ expect(listInstance.state.objects).toEqual(crudListResolvedObjects3);
478
+ expect(listInstance.state.order).toEqual(crudListResolvedPage3.map((e) => e.id.toString()));
470
479
  expect(listInstance.state.objectsInOrder).toEqual(crudListResolvedPage3);
471
480
  listInstance.addListObject(addObject);
472
481
  crudListResolvedPage3.push(addObject);
482
+ await nextTick();
483
+ expect(listInstance.state.order).toEqual(crudListResolvedPage3.map((e) => e.id.toString()));
473
484
  expect(listInstance.state.objectsInOrder).toEqual(crudListResolvedPage3);
474
485
  listInstance.deleteListObject(8);
475
486
  crudListResolvedPage3.splice(1, 1);
487
+ await nextTick();
488
+ expect(listInstance.state.order).toEqual(crudListResolvedPage3.map((e) => e.id.toString()));
476
489
  expect(listInstance.state.objectsInOrder).toEqual(crudListResolvedPage3);
477
490
  });
478
491
  });
@@ -191,5 +191,69 @@ describe("use/listRelated", () => {
191
191
  },
192
192
  },
193
193
  });
194
+ intermediateListInstance.state.objects[2].name = "intermediate1a";
195
+ intermediateListInstance.state.objects[2].related_id = "6";
196
+ intermediateListInstance.state.objects[2].related_ids = ["7", "8"];
197
+ intermediateListInstance.state.objects[3].name = "intermediate2a";
198
+ intermediateListInstance.state.objects[3].related_id = "4";
199
+ intermediateListInstance.state.objects[3].related_ids = ["5", "9"];
200
+ relatedListInstance.state.objects[4].name = "related1a";
201
+ relatedListInstance.state.objects[5].name = "related2a";
202
+ relatedListInstance.state.objects[6].name = "related3a";
203
+ relatedListInstance.state.objects[7].name = "related4a";
204
+ relatedListInstance.addListObject({
205
+ id: "8",
206
+ name: "related5",
207
+ });
208
+ relatedListInstance.addListObject({
209
+ id: "9",
210
+ name: "related6",
211
+ });
212
+ expect(deepUnref(listRelated.state.relatedObjects)).toEqual({
213
+ 1: {
214
+ intermediateItems: [
215
+ {
216
+ id: "2",
217
+ name: "intermediate1a",
218
+ related_ids: ["7", "8"],
219
+ related_id: "6",
220
+ },
221
+ {
222
+ id: "3",
223
+ name: "intermediate2a",
224
+ related_ids: ["5", "9"],
225
+ related_id: "4",
226
+ },
227
+ ],
228
+ intermediateItem: {
229
+ id: "2",
230
+ name: "intermediate1a",
231
+ related_ids: ["7", "8"],
232
+ related_id: "6",
233
+ },
234
+ relatedItems: [
235
+ {
236
+ id: "7",
237
+ name: "related4a",
238
+ },
239
+ {
240
+ id: "8",
241
+ name: "related5",
242
+ },
243
+ {
244
+ id: "5",
245
+ name: "related2a",
246
+ },
247
+ {
248
+ id: "9",
249
+ name: "related6",
250
+ },
251
+ ],
252
+ relatedItem: {
253
+ id: "6",
254
+ name: "related3a",
255
+ },
256
+ },
257
+ });
194
258
  });
195
259
  });
@@ -107,13 +107,16 @@ describe("use/useListSort", () => {
107
107
  const listSort = useListSort({ parentState: listInstance.state, orderByRules });
108
108
  // sorts immediately
109
109
  expect(listSort.state.order).toEqual(testOrder1);
110
+ expect(listSort.state.objectsInOrder).toEqual(testOrder1.map((id) => listInstance.state.objects[id]));
110
111
  await waitForListSort(listSort);
111
112
  listInstance.addListObject(addObject);
112
113
  await waitForListSort(listSort);
113
114
  expect(listSort.state.order).toEqual(testOrder2);
115
+ expect(listSort.state.objectsInOrder).toEqual(testOrder2.map((id) => listInstance.state.objects[id]));
114
116
  listInstance.deleteListObject(12);
115
117
  await waitForListSort(listSort);
116
118
  expect(listSort.state.order).toEqual(testOrder3);
119
+ expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
117
120
  });
118
121
  });
119
122
  describe("sortWatch sifts various criteria", () => {
@@ -132,18 +135,22 @@ describe("use/useListSort", () => {
132
135
  listSort.state.orderByRules.pop();
133
136
  listSort.state.orderByRules.push({ key: "lexical_name", desc: false, localeCompare: true });
134
137
  expect(listSort.state.order).toEqual(testOrder1);
138
+ expect(listSort.state.objectsInOrder).toEqual(testOrder1.map((id) => listInstance.state.objects[id]));
135
139
  await waitForListSort(listSort);
136
140
  expect(listSort.state.order).toEqual(testOrder2);
137
141
  listSort.state.orderByRules.pop();
138
142
  listSort.state.orderByRules.push({ key: "organization", desc: true, localeCompare: true });
139
143
  await waitForListSort(listSort);
140
144
  expect(listSort.state.order).toEqual(testOrder3);
145
+ expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
141
146
  listSort.state.orderByRules.pop();
142
147
  await waitForListSort(listSort);
143
148
  expect(listSort.state.order).toEqual(testOrder4);
149
+ expect(listSort.state.objectsInOrder).toEqual(testOrder4.map((id) => listInstance.state.objects[id]));
144
150
  listSort.state.orderByRules.push({ key: "organization", desc: false, localeCompare: false });
145
151
  await waitForListSort(listSort);
146
152
  expect(listSort.state.order).toEqual(testOrder2);
153
+ expect(listSort.state.objectsInOrder).toEqual(testOrder2.map((id) => listInstance.state.objects[id]));
147
154
  });
148
155
  });
149
156
  it("useListSorts & useListInstances", async function () {
@@ -269,13 +276,16 @@ describe("use/useListSort", () => {
269
276
  }
270
277
  await waitForListSort(listSort);
271
278
  expect(listSort.state.order).toEqual(["4", "3", "2", "1"]);
279
+ expect(listSort.state.objectsInOrder.map((obj) => obj.id)).toEqual([4, 3, 2, 1]);
272
280
  orderByRules[0].key = "relatedItemName.name";
273
281
  await waitForListSort(listSort);
274
282
  expect(listSort.state.order).toEqual(["1", "2", "3", "4"]);
283
+ expect(listSort.state.objectsInOrder.map((obj) => obj.id)).toEqual([1, 2, 3, 4]);
275
284
  orderByRules[0].key = "relatedItemName.sameValue";
276
285
  orderByRules[1] = { key: "calculatedItem.calculatedItemName", desc: false, localeCompare: false };
277
286
  await waitForListSort(listSort);
278
287
  expect(listSort.state.order).toEqual(["4", "3", "2", "1"]);
288
+ expect(listSort.state.objectsInOrder.map((obj) => obj.id)).toEqual([4, 3, 2, 1]);
279
289
  });
280
290
  describe("useListSort/sortThrottleWait", () => {
281
291
  it("respects throttle time prior to triggering", async () => {
@@ -301,25 +311,32 @@ describe("use/useListSort", () => {
301
311
 
302
312
  const listSort = useListSort({ parentState: listInstance.state, orderByRules, sortThrottleWait });
303
313
  expect(listSort.state.order).toEqual(testOrder1);
314
+ expect(listSort.state.objectsInOrder).toEqual(testOrder1.map((id) => listInstance.state.objects[id]));
304
315
 
305
316
  // wait for the original throttle to finish
306
317
  await doAwaitTimeout(250);
307
318
 
308
319
  expect(listSort.state.order).toEqual(testOrder2);
320
+ expect(listSort.state.objectsInOrder).toEqual(testOrder2.map((id) => listInstance.state.objects[id]));
309
321
  listInstance.addListObject(addObject);
310
322
  expect(listSort.state.order).toEqual(testOrder2);
323
+ expect(listSort.state.objectsInOrder).toEqual(testOrder2.map((id) => listInstance.state.objects[id]));
311
324
  // trigger the leading edge of the throttle
312
325
  await doAwaitTimeout(10);
313
326
  expect(listSort.state.order).toEqual(testOrder3);
327
+ expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
314
328
  // trigger again before the 200ms throttle
315
329
  listInstance.deleteListObject(12);
316
330
  expect(listSort.state.order).toEqual(testOrder3);
331
+ expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
317
332
  // this should trigger before the 200ms throttle
318
333
  await doAwaitTimeout(100);
319
334
  expect(listSort.state.order).toEqual(testOrder3);
335
+ expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
320
336
  // this should trigger after the 200ms throttle
321
337
  await doAwaitTimeout(200);
322
338
  expect(listSort.state.order).toEqual(testOrder4);
339
+ expect(listSort.state.objectsInOrder).toEqual(testOrder4.map((id) => listInstance.state.objects[id]));
323
340
  });
324
341
  });
325
342
  });
@@ -4,6 +4,7 @@ import {
4
4
  AssignReactiveObjectError,
5
5
  } from "../../../utils/assignReactiveObject.js";
6
6
  import { computed, EffectScope, effectScope, reactive, toRef, unref } from "vue";
7
+ import { deepUnref } from "vue-deepunref";
7
8
 
8
9
  describe("utils/assignReactiveObject", function () {
9
10
  describe("assignReactiveObject", function () {
@@ -183,4 +184,46 @@ describe("utils/assignReactiveObject", function () {
183
184
  });
184
185
  es.stop();
185
186
  });
187
+ describe("should propagate changes when used to chain multiple levels of reactivity", function () {
188
+ it("array", function () {
189
+ // assign reactive object will make lists of refs for each layer, causing refs to refs to refs
190
+ // this isn't great but consumers should use other methods to avoid this
191
+ const target = reactive({
192
+ a: [1, 2, 3],
193
+ });
194
+ const source = reactive({
195
+ a: [4, 5, 6],
196
+ });
197
+ const source2 = reactive({
198
+ a: [7, 8, 9],
199
+ });
200
+ expect(source.a).toEqual([4, 5, 6]);
201
+ assignReactiveObject(target.a, source.a);
202
+ expect(source.a).toEqual([4, 5, 6]);
203
+ expect(deepUnref(target.a)).toEqual([4, 5, 6]);
204
+ assignReactiveObject(source.a, source2.a);
205
+ expect(source2.a).toEqual([7, 8, 9]);
206
+ expect(deepUnref(source.a)).toEqual([7, 8, 9]);
207
+ expect(deepUnref(deepUnref(target.a))).toEqual([7, 8, 9]);
208
+ });
209
+ it("object", function () {
210
+ const target = reactive({
211
+ a: { b: 1, c: 2, d: 3 },
212
+ });
213
+ const source = reactive({
214
+ a: { b: 4, c: 5, d: 6 },
215
+ });
216
+ const source2 = reactive({
217
+ a: { b: 7, c: 8, d: 9 },
218
+ });
219
+ expect(source.a).toEqual({ b: 4, c: 5, d: 6 });
220
+ assignReactiveObject(target.a, source.a);
221
+ expect(target.a).toEqual({ b: 4, c: 5, d: 6 });
222
+ expect(source.a).toEqual({ b: 4, c: 5, d: 6 });
223
+ assignReactiveObject(source.a, source2.a);
224
+ expect(source2.a).toEqual({ b: 7, c: 8, d: 9 });
225
+ expect(source.a).toEqual({ b: 7, c: 8, d: 9 });
226
+ expect(target.a).toEqual({ b: 7, c: 8, d: 9 });
227
+ });
228
+ });
186
229
  });
@@ -66,9 +66,6 @@ export function useListCalculated({ parentState, calculatedObjectsRules }) {
66
66
  function calculatedObjectsWatch() {
67
67
  const calculatedObjectsRulesIsEmpty = !state.calculatedObjectsRules || isEmpty(state.calculatedObjectsRules);
68
68
  for (const objectKey of Object.keys(state.calculatedObjects)) {
69
- if (!calculatedObjectsEffectScopes[objectKey]) {
70
- calculatedObjectsEffectScopes[objectKey] = effectScope();
71
- }
72
69
  const originalObject = toRef(parentState.objects, objectKey);
73
70
  const relatedObject = parentState.relatedObjects
74
71
  ? toRef(parentState.relatedObjects, objectKey)
@@ -91,8 +88,13 @@ export function useListCalculated({ parentState, calculatedObjectsRules }) {
91
88
  addedRuleKeys = [];
92
89
  }
93
90
  for (const removedRuleKey of removedRuleKeys) {
91
+ // this is an unofficial api
92
+ calculatedObjectsObject[removedRuleKey].effect.stop();
94
93
  delete calculatedObjectsObject[removedRuleKey];
95
94
  }
95
+ if (!calculatedObjectsEffectScopes[objectKey]) {
96
+ calculatedObjectsEffectScopes[objectKey] = effectScope();
97
+ }
96
98
  calculatedObjectsEffectScopes[objectKey].run(() => {
97
99
  for (const addedRuleKey of addedRuleKeys) {
98
100
  calculatedObjectsObject[addedRuleKey] = computed(() =>
package/use/listFilter.js CHANGED
@@ -11,8 +11,6 @@ import {
11
11
  } from "./listKeys.js";
12
12
  import { effectScope, reactive, toRef, watch, unref, computed, nextTick } from "vue";
13
13
 
14
- 3;
15
-
16
14
  const parentStateKeys = difference(
17
15
  new Set([
18
16
  ...listInstanceStateKeys,
@@ -37,6 +35,9 @@ const inResults = (state, object, relatedObject, calculatedObject) => {
37
35
  const unrefObject = unref(object);
38
36
  const unrefRelatedObject = unref(relatedObject);
39
37
  const unrefCalculatedObject = unref(calculatedObject);
38
+ if (!unrefObject) {
39
+ return false;
40
+ }
40
41
  return !(
41
42
  (state.allowedFilter && !state.allowedFilter(unrefObject, unrefRelatedObject, unrefCalculatedObject)) ||
42
43
  (state.excludedFilter && state.excludedFilter(unrefObject, unrefRelatedObject, unrefCalculatedObject))
@@ -45,13 +46,14 @@ const inResults = (state, object, relatedObject, calculatedObject) => {
45
46
 
46
47
  export function useListFilter({ parentState, allowedFilter, excludedFilter }) {
47
48
  const state = reactive({
49
+ allowedFilter,
50
+ excludedFilter,
48
51
  inResults: {},
49
52
  objects: {},
50
53
  objectsInOrder: [],
51
- order: [],
52
- allowedFilter,
53
- excludedFilter,
54
+ objectsInOrderRefs: [],
54
55
  objectsWatchRunning: undefined,
56
+ order: [],
55
57
  resultsWatchRunning: undefined,
56
58
  running: undefined,
57
59
  });
@@ -104,11 +106,7 @@ export function useListFilter({ parentState, allowedFilter, excludedFilter }) {
104
106
  };
105
107
 
106
108
  const resultsWatch = async () => {
107
- if (parentState.running) {
108
- return;
109
- }
110
109
  state.resultsWatchRunning = true;
111
- await nextTick();
112
110
  if (state.allowedFilter || state.excludedFilter) {
113
111
  assignReactiveObject(
114
112
  state.objects,
@@ -119,21 +117,37 @@ export function useListFilter({ parentState, allowedFilter, excludedFilter }) {
119
117
  )
120
118
  );
121
119
  }
122
-
123
- nextTick().then(() => {
124
- state.resultsWatchRunning = false;
125
- });
120
+ await nextTick();
121
+ // the watches don't necessarily run in the order we expect, or at all
122
+ orderWatch();
123
+ await nextTick();
124
+ state.resultsWatchRunning = false;
126
125
  };
127
126
 
128
127
  const orderWatch = () => {
129
- let desiredOrder = parentState.order.filter((id) => !!state.objects[id]),
130
- desiredObjectsInOrder = desiredOrder.map((id) => toRef(state.objects, id));
128
+ let desiredOrder = parentState.order.filter((id) => !!state.objects[id]);
131
129
  if (!state.allowedFilter && !state.excludedFilter) {
132
130
  desiredOrder = parentState.order;
133
- desiredObjectsInOrder = parentState.objectsInOrder;
134
131
  }
135
- assignReactiveObject(state.objectsInOrder, desiredObjectsInOrder);
136
- assignReactiveObject(state.order, desiredOrder);
132
+ // order is primitives, references to the parent state order doesn't make sense
133
+ const entries = Object.entries(desiredOrder);
134
+ entries.reverse();
135
+ if (entries.length !== state.order.length) {
136
+ state.order.length = entries.length;
137
+ state.objectsInOrderRefs.length = entries.length;
138
+ }
139
+ for (const [index, id] of entries) {
140
+ if (state.order[index] !== id) {
141
+ state.order[index] = id;
142
+ }
143
+ if (unref(toRef(state.objectsInOrderRefs, index)) !== unref(toRef(state.objects, id))) {
144
+ state.objectsInOrderRefs[index] = toRef(state.objects, id);
145
+ }
146
+ }
147
+ assignReactiveObject(
148
+ state.objectsInOrderRefs,
149
+ desiredOrder.map((id) => toRef(state.objects, id))
150
+ );
137
151
  };
138
152
 
139
153
  es.run(() => {
@@ -148,11 +162,17 @@ export function useListFilter({ parentState, allowedFilter, excludedFilter }) {
148
162
  watch(toRef(state, "inResults"), resultsWatch, { deep: true });
149
163
 
150
164
  watch(toRef(parentState, "order"), orderWatch, { deep: true, immediate: true });
165
+ state.objectsInOrder = computed(() => state.objectsInOrderRefs.map((e) => unref(e)));
151
166
 
152
167
  watch(
153
- [() => Object.keys(parentState.objects), toRef(state, "allowedFilter"), toRef(state, "excludedFilter")],
168
+ [
169
+ toRef(parentState, "objects"),
170
+ toRef(state, "allowedFilter"),
171
+ toRef(state, "excludedFilter"),
172
+ toRef(parentState, "running"),
173
+ ],
154
174
  objectsWatch,
155
- { immediate: true }
175
+ { immediate: true, deep: true }
156
176
  );
157
177
  });
158
178
  return {
@@ -2,7 +2,7 @@ import { getListCrud } from "../config/listCrud.js";
2
2
  import { assignReactiveObject } from "../utils/assignReactiveObject.js";
3
3
  import { getFakeId } from "../utils/getFakeId.js";
4
4
  import inspect from "browser-util-inspect";
5
- import { computed, effectScope, reactive, toRef } from "vue";
5
+ import { effectScope, reactive, toRef, watch, computed, unref } from "vue";
6
6
 
7
7
  export class ListError extends Error {
8
8
  constructor(message, code) {
@@ -32,6 +32,7 @@ export class ListError extends Error {
32
32
  * @param {Object.<string, ListInstanceOptions>} listInstanceArgs - each desired list instance options, keyed by an instance name.
33
33
  * @returns {Object.<string, ListInstance>} - each list instance, keyed by the instance name.
34
34
  */
35
+
35
36
  /* eslint-enable jsdoc/check-types */
36
37
  export function useListInstances(listInstanceArgs) {
37
38
  const instances = {};
@@ -119,6 +120,10 @@ export function useListInstance({ props, functions = {}, keepOldPages = false })
119
120
  }
120
121
  : Reflect.getOwnPropertyDescriptor(target, p); // we can't report target properties as non-existent re: proxy invariants
121
122
  },
123
+ // things introspect us thing we are a map, we need to pretend to be a object
124
+ getPrototypeOf() {
125
+ return Object.prototype;
126
+ },
122
127
  });
123
128
  // ### touching the _objectsMap or _objectsProxy directly will not trigger reactivity ###
124
129
  const state = reactive({
@@ -132,6 +137,9 @@ export function useListInstance({ props, functions = {}, keepOldPages = false })
132
137
  loading: undefined,
133
138
  errored: false,
134
139
  error: null,
140
+ order: [],
141
+ objectsInOrder: [],
142
+ objectsInOrderRefs: [],
135
143
  });
136
144
  const es = effectScope();
137
145
 
@@ -249,8 +257,23 @@ export function useListInstance({ props, functions = {}, keepOldPages = false })
249
257
  state.error = null;
250
258
  }
251
259
 
252
- state.objectsInOrder = computed(() => Object.values(state.objects));
253
- state.order = computed(() => Object.keys(state.objects));
260
+ es.run(() => {
261
+ watch(
262
+ toRef(state, "objects"),
263
+ () => {
264
+ assignReactiveObject(
265
+ state.objectsInOrderRefs,
266
+ Object.keys(state.objects).map((id) => toRef(state.objects, id))
267
+ );
268
+ },
269
+ {
270
+ immediate: true,
271
+ deep: true,
272
+ }
273
+ );
274
+ state.objectsInOrder = computed(() => state.objectsInOrderRefs.map((ref) => unref(ref)));
275
+ state.order = computed(() => Object.keys(state.objects));
276
+ });
254
277
 
255
278
  const returnedObject = {
256
279
  state,
package/use/listKeys.js CHANGED
@@ -7,6 +7,7 @@ export const listInstanceStateKeys = [
7
7
  "errored",
8
8
  "error",
9
9
  "objectsInOrder",
10
+ "objectsInOrderRefs",
10
11
  "order",
11
12
  // when paged
12
13
  "totalRecords",
@@ -41,6 +42,8 @@ export const listRelatedStateKeys = [
41
42
  "relatedObjectsWatchRunning",
42
43
  "relatedObjectsParentStateObjectsWatchRunning",
43
44
  "running",
45
+ "objAndKeyForIdAndRule",
46
+ "fkForIdAndRule",
44
47
  ];
45
48
  export const listRelatedFunctions = [];
46
49
 
@@ -54,14 +57,16 @@ export const listCalculatedStateKeys = [
54
57
  export const listCalculatedFunctions = [];
55
58
 
56
59
  export const listFilterStateKeys = [
57
- "objects",
58
- "order",
59
- "objectsInOrder",
60
60
  "allowedFilter",
61
61
  "excludedFilter",
62
- "running",
62
+ "inResults",
63
+ "objects",
64
+ "objectsInOrder",
65
+ "objectsInOrderRefs",
63
66
  "objectsWatchRunning",
67
+ "order",
64
68
  "resultsWatchRunning",
69
+ "running",
65
70
  ];
66
71
  export const listFilterFunctions = [];
67
72
 
@@ -70,6 +75,7 @@ export const listSearchStateKeys = [
70
75
  "objects",
71
76
  "order",
72
77
  "objectsInOrder",
78
+ "objectsInOrderRefs",
73
79
  "textSearchRules",
74
80
  "textSearchValue",
75
81
  "searched",
@@ -84,6 +90,7 @@ export const listSortStateKeys = [
84
90
  "orderByRules",
85
91
  "order",
86
92
  "objectsInOrder",
93
+ "objectsInOrderRefs",
87
94
  "sortCriteria",
88
95
  "orderByDesc",
89
96
  "sortCriteriaWatchRunning",
@@ -1,6 +1,7 @@
1
- import { difference } from "../utils/index.js";
2
1
  import { keyDiff } from "../utils/keyDiff.js";
3
2
  import { loadingCombine } from "../utils/loadingCombine.js";
3
+ import { getObjectRelatedByKey } from "../utils/relatedCalculatedHelpers.js";
4
+ import { difference } from "../utils/set.js";
4
5
  import {
5
6
  listSubscriptionStateKeys,
6
7
  listInstanceStateKeys,
@@ -15,7 +16,6 @@ import get from "lodash-es/get.js";
15
16
  import identity from "lodash-es/identity.js";
16
17
  import isArray from "lodash-es/isArray.js";
17
18
  import isEmpty from "lodash-es/isEmpty.js";
18
- import isEqual from "lodash-es/isEqual.js";
19
19
  import isUndefined from "lodash-es/isUndefined.js";
20
20
  import { computed, effectScope, onScopeDispose, reactive, toRef, unref, watch } from "vue";
21
21
 
@@ -43,23 +43,47 @@ export function useListRelateds(instances, args) {
43
43
  export function useListRelated({ parentState, relatedObjectsRules }) {
44
44
  const state = reactive({
45
45
  relatedObjectsRules: relatedObjectsRules,
46
- relatedObjects: {},
46
+ relatedObjects: {
47
+ // id: {
48
+ // rule: list of objects or single object,
49
+ // },
50
+ },
51
+ objAndKeyForIdAndRule: {
52
+ // id: {
53
+ // rule: {
54
+ // obj: object,
55
+ // key: string,
56
+ // },
57
+ // },
58
+ },
59
+ fkForIdAndRule: {
60
+ // id: {
61
+ // rule: list of ids or single id,
62
+ // },
63
+ },
47
64
  relatedObjectsParentStateObjectsWatchRunning: false,
48
65
  relatedObjectsWatchRunning: false,
49
66
  });
50
67
  const relatedObjectsEffectScopes = {};
51
68
 
52
69
  function parentStateObjectsWatch() {
53
- const { addedKeys, removedKeys } = keyDiff(Object.keys(parentState.objects), Object.keys(state.relatedObjects));
54
- for (const removedKey of removedKeys) {
55
- delete state.relatedObjects[removedKey];
56
- if (relatedObjectsEffectScopes[removedKey]) {
57
- relatedObjectsEffectScopes[removedKey].stop();
58
- delete relatedObjectsEffectScopes[removedKey];
70
+ const { addedKeys: addedIds, removedKeys: removedIds } = keyDiff(
71
+ Object.keys(parentState.objects),
72
+ Object.keys(state.relatedObjects)
73
+ );
74
+ for (const removedId of removedIds) {
75
+ delete state.relatedObjects[removedId];
76
+ delete state.objAndKeyForIdAndRule[removedId];
77
+ delete state.fkForIdAndRule[removedId];
78
+ if (relatedObjectsEffectScopes[removedId]) {
79
+ relatedObjectsEffectScopes[removedId].stop();
80
+ delete relatedObjectsEffectScopes[removedId];
59
81
  }
60
82
  }
61
- for (const addedKey of addedKeys) {
62
- state.relatedObjects[addedKey] = {};
83
+ for (const addedId of addedIds) {
84
+ state.relatedObjects[addedId] = {};
85
+ state.objAndKeyForIdAndRule[addedId] = {};
86
+ state.fkForIdAndRule[addedId] = {};
63
87
  }
64
88
  state.relatedObjectsParentStateObjectsWatchRunning = false;
65
89
  }
@@ -67,66 +91,58 @@ export function useListRelated({ parentState, relatedObjectsRules }) {
67
91
  function relatedObjectsWatch() {
68
92
  const relatedObjectsRulesIsEmpty = !state.relatedObjectsRules || isEmpty(state.relatedObjectsRules);
69
93
  for (const objectKey of Object.keys(state.relatedObjects)) {
70
- const relatedObjectsObject = state.relatedObjects[objectKey];
71
94
  const originalObjectRef = toRef(parentState.objects, objectKey);
72
95
  const relatedObjectRef = toRef(state.relatedObjects, objectKey);
73
96
  let removedRuleKeys, addedRuleKeys;
74
97
  if (!relatedObjectsRulesIsEmpty) {
75
98
  ({ removedKeys: removedRuleKeys, addedKeys: addedRuleKeys } = keyDiff(
76
99
  Object.keys(state.relatedObjectsRules),
77
- Object.keys(relatedObjectsObject)
100
+ Object.keys(state.relatedObjects[objectKey])
78
101
  ));
79
102
  } else {
80
- if (isEmpty(relatedObjectsObject)) {
103
+ if (isEmpty(state.relatedObjects[objectKey])) {
81
104
  return;
82
105
  }
83
- removedRuleKeys = Object.keys(relatedObjectsObject);
84
- addedRuleKeys = [];
106
+ removedRuleKeys = new Set(Object.keys(state.relatedObjects[objectKey]));
107
+ addedRuleKeys = new Set();
85
108
  }
86
109
  for (const removedRuleKey of removedRuleKeys) {
87
- delete relatedObjectsObject[removedRuleKey];
88
- }
89
- if (!relatedObjectsEffectScopes[objectKey]) {
90
- relatedObjectsEffectScopes[objectKey] = effectScope();
110
+ state.relatedObjects[objectKey][removedRuleKey]?.effect?.stop();
111
+ delete state.relatedObjects[objectKey][removedRuleKey];
112
+ state.objAndKeyForIdAndRule[objectKey][removedRuleKey]?.effect?.stop();
113
+ delete state.objAndKeyForIdAndRule[objectKey][removedRuleKey];
114
+ state.fkForIdAndRule[objectKey][removedRuleKey]?.effect?.stop();
115
+ delete state.fkForIdAndRule[objectKey][removedRuleKey];
91
116
  }
92
- relatedObjectsEffectScopes[objectKey].run(() => {
93
- for (const addedRuleKey of addedRuleKeys) {
94
- relatedObjectsObject[addedRuleKey] = undefined;
95
- const relatedObjectsObjectWatchFn = () => {
96
- // deal with computed objects being passed.
97
- const ruleObjects = unref(state.relatedObjectsRules?.[addedRuleKey]?.objects);
98
- const rulePkKey = state.relatedObjectsRules?.[addedRuleKey]?.pkKey || addedRuleKey;
99
- const ruleOrder = unref(state.relatedObjectsRules?.[addedRuleKey]?.order);
100
- if (!ruleObjects || !rulePkKey) {
101
- if (!isUndefined(relatedObjectsObject[addedRuleKey])) {
102
- relatedObjectsObject[addedRuleKey] = undefined;
103
- }
104
- return;
105
- }
106
- let value;
107
- if (rulePkKey.startsWith("relatedItem.")) {
108
- value = get(unref(relatedObjectRef), rulePkKey.slice(12));
109
- if (isUndefined(value)) {
117
+ if (addedRuleKeys.size) {
118
+ if (!relatedObjectsEffectScopes[objectKey]) {
119
+ relatedObjectsEffectScopes[objectKey] = effectScope();
120
+ }
121
+ relatedObjectsEffectScopes[objectKey].run(() => {
122
+ for (const addedRuleKey of addedRuleKeys) {
123
+ const rules = toRef(state.relatedObjectsRules, addedRuleKey);
124
+ state.objAndKeyForIdAndRule[objectKey][addedRuleKey] = computed(() => {
125
+ const rulePkKey = unref(rules).pkKey || addedRuleKey;
126
+ const object = unref(originalObjectRef);
127
+ const relatedObject = unref(relatedObjectRef);
128
+ return getObjectRelatedByKey(object, relatedObject, rulePkKey);
129
+ });
130
+
131
+ state.fkForIdAndRule[objectKey][addedRuleKey] = computed(() => {
132
+ const ruleOrder = unref(rules).order;
133
+ const relatedObject = unref(relatedObjectRef);
134
+ const [objectForGet, key] = unref(state.objAndKeyForIdAndRule[objectKey][addedRuleKey]);
135
+ let value = get(objectForGet, key);
136
+ if (objectForGet === relatedObject && isUndefined(value)) {
110
137
  // is the first level an array?
111
- const firstLevelKey = rulePkKey.slice(12).split(".")[0];
112
- const firstLevelItem = get(unref(relatedObjectRef), firstLevelKey);
138
+ const firstLevelKey = key.split(".")[0];
139
+ const firstLevelItem = get(relatedObject, firstLevelKey);
113
140
  if (isArray(firstLevelItem)) {
114
- const restOfKey = rulePkKey.slice(12 + firstLevelKey.length + 1);
141
+ const restOfKey = key.slice(firstLevelKey.length + 1);
115
142
  value = firstLevelItem.map((e) => get(e, restOfKey)).flat();
116
143
  }
117
144
  }
118
- } else {
119
- value = get(unref(originalObjectRef), rulePkKey);
120
- }
121
- if (isUndefined(value)) {
122
- if (!isUndefined(relatedObjectsObject[addedRuleKey])) {
123
- relatedObjectsObject[addedRuleKey] = undefined;
124
- }
125
- return;
126
- }
127
- if (isArray(value)) {
128
- // the related list could be sorted differently than the original list.
129
- if (ruleOrder?.length) {
145
+ if (isArray(value) && ruleOrder?.length) {
130
146
  value = value.filter(identity);
131
147
  const indexById = Object.fromEntries(ruleOrder.map((e, i) => [e, i]));
132
148
  value.sort((a, b) => {
@@ -135,24 +151,20 @@ export function useListRelated({ parentState, relatedObjectsRules }) {
135
151
  return aIndex - bIndex;
136
152
  });
137
153
  }
138
- value = value.map((e) => ruleObjects[e]).filter(identity);
139
- } else {
140
- value = ruleObjects[value];
141
- }
142
- if (!isEqual(value, relatedObjectsObject[addedRuleKey])) {
143
- relatedObjectsObject[addedRuleKey] = value;
144
- }
145
- };
146
- watch(
147
- [toRef(state.relatedObjectsRules, addedRuleKey), originalObjectRef, relatedObjectRef],
148
- relatedObjectsObjectWatchFn,
149
- {
150
- deep: true,
151
- immediate: true,
152
- }
153
- );
154
- }
155
- });
154
+ return value;
155
+ });
156
+
157
+ state.relatedObjects[objectKey][addedRuleKey] = computed(() => {
158
+ const value = unref(state.fkForIdAndRule[objectKey][addedRuleKey]);
159
+ const objects = unref(rules).objects;
160
+ if (isArray(value)) {
161
+ return value.map((e) => objects[e]).filter(identity);
162
+ }
163
+ return objects[value];
164
+ });
165
+ }
166
+ });
167
+ }
156
168
  }
157
169
  state.relatedObjectsWatchRunning = false;
158
170
  }
@@ -168,10 +180,7 @@ export function useListRelated({ parentState, relatedObjectsRules }) {
168
180
 
169
181
  watch(() => Object.keys(parentState.objects), parentStateObjectsWatch, { immediate: true });
170
182
  watch(
171
- [
172
- () => Object.keys(state.relatedObjects),
173
- () => (state.relatedObjectsRules ? Object.keys(state.relatedObjectsRules) : state.relatedObjectsRules),
174
- ],
183
+ [() => Object.keys(state.relatedObjects), () => Object.keys(state.relatedObjectsRules || {})],
175
184
  relatedObjectsWatch,
176
185
  { immediate: true }
177
186
  );
package/use/listSearch.js CHANGED
@@ -81,6 +81,7 @@ export function useListSearch({ parentState, props, throttle = 500, showAllWhenE
81
81
  const state = reactive({
82
82
  objects: {},
83
83
  objectsInOrder: [],
84
+ objectsInOrderRefs: [],
84
85
  order: [],
85
86
  textSearchRules: toRef(props, "textSearchRules"),
86
87
  textSearchValue: toRef(props, "textSearchValue"),
@@ -270,14 +271,11 @@ export function useListSearch({ parentState, props, throttle = 500, showAllWhenE
270
271
  };
271
272
 
272
273
  const updateOrder = () => {
274
+ state.order = parentState.order.filter((id) => !!state.objects[id]);
273
275
  assignReactiveObject(
274
- state.objectsInOrder,
276
+ state.objectsInOrderRefs,
275
277
  parentState.order.filter((id) => !!state.objects[id]).map((id) => toRef(state.objects, id))
276
278
  );
277
- assignReactiveObject(
278
- state.order,
279
- parentState.order.filter((id) => !!state.objects[id])
280
- );
281
279
  };
282
280
 
283
281
  let firstIndexWasCleared = false;
@@ -309,6 +307,7 @@ export function useListSearch({ parentState, props, throttle = 500, showAllWhenE
309
307
  state.running = computed(() => {
310
308
  return loadingCombine(parentState.running, state.newSearchComputeds, textSearchIndex.state.running);
311
309
  });
310
+ state.objectsInOrder = computed(() => state.objectsInOrderRefs.map((ref) => unref(ref)));
312
311
 
313
312
  watch([() => Object.keys(parentState.objects), toRef(state.textSearchRules)], makeComputeds, {
314
313
  immediate: true,
package/use/listSort.js CHANGED
@@ -9,7 +9,6 @@ import {
9
9
  listSearchStateKeys,
10
10
  } from "./listKeys.js";
11
11
  import { useWatchesRunning } from "./watchesRunning.js";
12
- import cloneDeep from "lodash-es/cloneDeep.js";
13
12
  import get from "lodash-es/get.js";
14
13
  import identity from "lodash-es/identity.js";
15
14
  import isEmpty from "lodash-es/isEmpty.js";
@@ -19,6 +18,7 @@ import isUndefined from "lodash-es/isUndefined.js";
19
18
  import throttle from "lodash-es/throttle.js";
20
19
  import zip from "lodash-es/zip.js";
21
20
  import { effectScope, reactive, toRef, unref, watch, computed } from "vue";
21
+ import { deepUnref } from "vue-deepunref";
22
22
 
23
23
  const collator = new Intl.Collator(undefined, { numeric: true });
24
24
 
@@ -62,6 +62,7 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
62
62
  const state = reactive({
63
63
  orderByRules,
64
64
  order: [],
65
+ objectsInOrderRefs: [],
65
66
  objectsInOrder: [],
66
67
  sortCriteria: {},
67
68
  orderByDesc: [],
@@ -137,8 +138,8 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
137
138
  removeSortCriteria(removedKey);
138
139
  }
139
140
  }
140
- assignReactiveObject(state.order, cloneDeep(parentState.order));
141
- assignReactiveObject(state.objectsInOrder, cloneDeep(parentState.objectsInOrder));
141
+ assignReactiveObject(state.order, deepUnref(parentState.order));
142
+ assignReactiveObject(state.objectsInOrder, deepUnref(parentState.objectsInOrder));
142
143
  return;
143
144
  }
144
145
  const { removedKeys, addedKeys } = keyDiff(
@@ -169,8 +170,12 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
169
170
  function sortWatch() {
170
171
  try {
171
172
  if (!state.orderByRules || !state.orderByRules.length) {
172
- assignReactiveObject(state.order, cloneDeep(parentState.order));
173
- assignReactiveObject(state.objectsInOrder, cloneDeep(parentState.objectsInOrder));
173
+ state.order = [...parentState.order];
174
+ assignReactiveObject(
175
+ state.objectsInOrderRefs,
176
+ state.order.map((e) => toRef(parentState.objects, e))
177
+ );
178
+ 3;
174
179
  return;
175
180
  }
176
181
 
@@ -210,8 +215,11 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
210
215
  }
211
216
  return 0;
212
217
  });
213
- assignReactiveObject(state.order, idList);
214
- assignReactiveObject(state.objectsInOrder, idList.map((e) => parentState.objects[e]).filter(identity));
218
+ state.order = idList;
219
+ assignReactiveObject(
220
+ state.objectsInOrderRefs,
221
+ idList.map((e) => toRef(parentState.objects, e))
222
+ );
215
223
  } finally {
216
224
  state.sortWatchRunning = false;
217
225
  state.outstandingEffects = false;
@@ -243,6 +251,7 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
243
251
  watchSentinelRefs: [toRef(state, "sortCriteriaWatchRunning"), toRef(state, "sortWatchRunning")],
244
252
  });
245
253
 
254
+ state.objectsInOrder = computed(() => state.objectsInOrderRefs.map((e) => unref(e)));
246
255
  state.sortRunning = computed(() => loadingCombine(watchesRunning.state.running, state.outstandingEffects));
247
256
  state.running = computed(() =>
248
257
  loadingCombine(watchesRunning.state.running, state.outstandingEffects, parentState.running)
@@ -22,7 +22,7 @@ export function useWatchesRunning({ triggerRefs, watchSentinelRefs }) {
22
22
  }
23
23
  );
24
24
  state.running = computed(() => {
25
- const values = watchSentinelRefs.map((ref) => ref.value);
25
+ const values = watchSentinelRefs.map((ref) => unref(ref));
26
26
  return loadingCombine(values);
27
27
  });
28
28
  });
@@ -221,7 +221,7 @@ export function trimReactiveObject(target, source, exclude, removedKeys = null)
221
221
  }
222
222
 
223
223
  function checkIfReversed(target, source) {
224
- if (target.length !== source.length) {
224
+ if (target.length !== source.length || target.length === 0) {
225
225
  return false;
226
226
  }
227
227
  let t = target.length - 1,
@@ -15,3 +15,12 @@ export const getObjectRelatedCalculatedByKey = (obj, relatedObj, calculatedObj,
15
15
  }
16
16
  return [getObj, getKey];
17
17
  };
18
+
19
+ export const getObjectRelatedByKey = (obj, relatedObj, key) => {
20
+ let getObj = obj,
21
+ getKey = key.replace(relatedItemRegex, () => {
22
+ getObj = relatedObj;
23
+ return "";
24
+ });
25
+ return [getObj, getKey];
26
+ };