@arrai-innovations/reactive-helpers 2.1.2 → 2.2.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arrai-innovations/reactive-helpers",
3
- "version": "2.1.2",
3
+ "version": "2.2.0",
4
4
  "description": "VueJS 3 utility composition functions to help manipulate objects and lists.",
5
5
  "main": "index.js",
6
6
  "directories": {
package/use/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./listCalculated.js";
1
2
  export * from "./listFilter.js";
2
3
  export * from "./listInstance.js";
3
4
  export * from "./listRelated.js";
@@ -0,0 +1,128 @@
1
+ import { isEmpty } from "lodash";
2
+ import { computed, effectScope, onScopeDispose, reactive, toRef, toRefs, watch } from "vue";
3
+ import { keyDiff } from "../utils";
4
+
5
+ // the simpler sibling of useListRelated
6
+ // rules are just keys to functions that will be called with the object
7
+ // and the result will be added as a computed property
8
+ export function useListCalculated({
9
+ parentState,
10
+ calculatedObjectsRules,
11
+ calculatedObjectsPropertyName = "calculatedObjects", // NOT REACTIVE
12
+ }) {
13
+ const state = reactive({
14
+ calculatedObjectsRules,
15
+ calculatedObjectsObjects: {},
16
+ objects: {},
17
+ });
18
+ const calculatedObjectsEffectScopes = {};
19
+ const combinedEffectScopes = {};
20
+
21
+ // don't change calculatedObjectsPropertyName on us or it will break
22
+ const copn = calculatedObjectsPropertyName + "";
23
+
24
+ function parentStateObjectsWatch() {
25
+ const { addedKeys, removedKeys } = keyDiff(
26
+ Object.keys(parentState.objects),
27
+ Object.keys(state.calculatedObjectsObjects)
28
+ );
29
+ for (const removedKey of removedKeys) {
30
+ delete state.calculatedObjectsObjects[removedKey];
31
+ delete state.objects[removedKey];
32
+ if (calculatedObjectsEffectScopes[removedKey]) {
33
+ calculatedObjectsEffectScopes[removedKey].stop();
34
+ delete calculatedObjectsEffectScopes[removedKey];
35
+ }
36
+ if (combinedEffectScopes[removedKey]) {
37
+ combinedEffectScopes[removedKey].stop();
38
+ delete combinedEffectScopes[removedKey];
39
+ }
40
+ }
41
+ for (const addedKey of addedKeys) {
42
+ state.calculatedObjectsObjects[addedKey] = {};
43
+ combinedEffectScopes[addedKey] = effectScope();
44
+ combinedEffectScopes[addedKey].run(() => {
45
+ state.objects[addedKey] = computed(() =>
46
+ reactive({
47
+ ...toRefs(state.calculatedObjectsObjects[addedKey]),
48
+ ...toRefs(parentState.objects[addedKey]),
49
+ })
50
+ );
51
+ });
52
+ }
53
+ }
54
+
55
+ function calculatedObjectsWatch() {
56
+ if (state.calculatedObjectsRules === false) {
57
+ return;
58
+ }
59
+ const calculatedObjectsRulesIsEmpty = isEmpty(state.calculatedObjectsRules);
60
+ for (const objectKey of Object.keys(state.calculatedObjectsObjects)) {
61
+ const calculatedObjectsEffectScope = effectScope();
62
+ calculatedObjectsEffectScope.run(() => {
63
+ const calculatedObjectsObject = state.calculatedObjectsObjects[objectKey];
64
+ const originalObject = parentState.objects[objectKey];
65
+ if (!calculatedObjectsObject[copn]) {
66
+ calculatedObjectsObject[copn] = {};
67
+ }
68
+ let removedRuleKeys, addedRuleKeys;
69
+ if (!calculatedObjectsRulesIsEmpty) {
70
+ ({ removedKeys: removedRuleKeys, addedKeys: addedRuleKeys } = keyDiff(
71
+ Object.keys(state.calculatedObjectsRules),
72
+ Object.keys(calculatedObjectsObject[copn])
73
+ ));
74
+ } else {
75
+ if (isEmpty(calculatedObjectsObject[copn])) {
76
+ return;
77
+ }
78
+ removedRuleKeys = Object.keys(calculatedObjectsObject[copn]);
79
+ addedRuleKeys = [];
80
+ }
81
+ for (const removedRuleKey of removedRuleKeys) {
82
+ delete calculatedObjectsObject[copn][removedRuleKey];
83
+ }
84
+ for (const addedRuleKey of addedRuleKeys) {
85
+ calculatedObjectsObject[copn][addedRuleKey] = computed(() => {
86
+ return state.calculatedObjectsRules?.[addedRuleKey]?.(originalObject);
87
+ });
88
+ }
89
+ });
90
+ calculatedObjectsEffectScopes[objectKey] = calculatedObjectsEffectScope;
91
+ }
92
+ parentStateObjectsWatch();
93
+ }
94
+
95
+ const es = effectScope();
96
+
97
+ es.run(() => {
98
+ state.order = toRef(parentState, "order");
99
+ state.objectsInOrder = computed(() => state.order.map((id) => state.objects[id]));
100
+
101
+ watch(() => Object.keys(parentState.objects), parentStateObjectsWatch, { immediate: true });
102
+ watch(
103
+ [
104
+ () => Object.keys(state.calculatedObjectsObjects),
105
+ () =>
106
+ state.calculatedObjectsRules
107
+ ? Object.keys(state.calculatedObjectsRules)
108
+ : state.calculatedObjectsRules,
109
+ ],
110
+ calculatedObjectsWatch,
111
+ { immediate: true }
112
+ );
113
+
114
+ onScopeDispose(() => {
115
+ for (const objectKey of Object.keys(calculatedObjectsEffectScopes)) {
116
+ calculatedObjectsEffectScopes[objectKey].stop();
117
+ }
118
+ for (const objectKey of Object.keys(combinedEffectScopes)) {
119
+ combinedEffectScopes[objectKey].stop();
120
+ }
121
+ });
122
+ });
123
+
124
+ return {
125
+ state,
126
+ effectScope: es,
127
+ };
128
+ }