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