@arrai-innovations/reactive-helpers 20.1.3 → 21.0.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/README.md +22 -893
- package/config/listCrud.js +30 -27
- package/config/objectCrud.js +20 -13
- package/index.js +4 -3
- package/package.json +5 -3
- package/types/config/commonCrud.d.ts +0 -1
- package/types/config/listCrud.d.ts +28 -41
- package/types/config/objectCrud.d.ts +14 -29
- package/types/index.d.ts +4 -4
- package/types/tests/unit/config/listCrud.spec.d.ts +0 -1
- package/types/tests/unit/config/objectCrud.spec.d.ts +0 -1
- package/types/tests/unit/crudPromise.d.ts +42 -15
- package/types/tests/unit/mockOnUnmounted.d.ts +0 -1
- package/types/tests/unit/poll.d.ts +0 -1
- package/types/tests/unit/scopedIt.d.ts +15 -0
- package/types/tests/unit/setup.d.ts +2 -0
- package/types/tests/unit/use/cancellableIntent.spec.d.ts +0 -1
- package/types/tests/unit/use/combineClasses.spec.d.ts +1 -0
- package/types/tests/unit/use/list.spec.d.ts +1 -0
- package/types/tests/unit/use/listCalculated.spec.d.ts +0 -1
- package/types/tests/unit/use/listFilter.spec.d.ts +0 -1
- package/types/tests/unit/use/listInstance.spec.d.ts +0 -1
- package/types/tests/unit/use/listRelated.spec.d.ts +0 -1
- package/types/tests/unit/use/listSearch.spec.d.ts +0 -1
- package/types/tests/unit/use/listSort.spec.d.ts +0 -1
- package/types/tests/unit/use/listSubscription.spec.d.ts +0 -1
- package/types/tests/unit/use/loadingError.spec.d.ts +0 -1
- package/types/tests/unit/use/object.spec.d.ts +1 -0
- package/types/tests/unit/use/objectCalculated.spec.d.ts +1 -0
- package/types/tests/unit/use/objectInstance.spec.d.ts +0 -1
- package/types/tests/unit/use/objectRelated.spec.d.ts +1 -0
- package/types/tests/unit/use/objectSubscription.spec.d.ts +0 -1
- package/types/tests/unit/use/proxyLoadingError.spec.d.ts +0 -1
- package/types/tests/unit/use/search.error.spec.d.ts +1 -0
- package/types/tests/unit/use/search.spec.d.ts +0 -1
- package/types/tests/unit/utils/assignReactiveObject.extra.spec.d.ts +1 -0
- package/types/tests/unit/utils/assignReactiveObject.refs.spec.d.ts +1 -0
- package/types/tests/unit/utils/assignReactiveObject.spec.d.ts +0 -1
- package/types/tests/unit/utils/cancellableFetch.spec.d.ts +1 -0
- package/types/tests/unit/utils/classes.spec.d.ts +0 -1
- package/types/tests/unit/utils/compact.spec.d.ts +1 -0
- package/types/tests/unit/utils/deepUnref.spec.d.ts +1 -0
- package/types/tests/unit/utils/deleteKey.spec.d.ts +0 -1
- package/types/tests/unit/utils/flattenPaths.spec.d.ts +0 -1
- package/types/tests/unit/utils/flattenPathsWithValues.spec.d.ts +1 -0
- package/types/tests/unit/utils/getFakePk.spec.d.ts +1 -0
- package/types/tests/unit/utils/keepAliveTry.spec.d.ts +1 -0
- package/types/tests/unit/utils/keyDiff.spec.d.ts +0 -1
- package/types/tests/unit/utils/set.spec.d.ts +0 -1
- package/types/tests/unit/utils/transformWalk.spec.d.ts +1 -0
- package/types/tests/unit/utils/unwrapNested.spec.d.ts +1 -0
- package/types/tests/unit/utils/watches.spec.d.ts +0 -1
- package/types/use/cancellableIntent.d.ts +121 -48
- package/types/use/combineClasses.d.ts +0 -1
- package/types/use/error.d.ts +48 -0
- package/types/use/list.d.ts +9 -32
- package/types/use/listCalculated.d.ts +107 -49
- package/types/use/listFilter.d.ts +13 -31
- package/types/use/listInstance.d.ts +137 -71
- package/types/use/listRelated.d.ts +106 -43
- package/types/use/listSearch.d.ts +24 -12
- package/types/use/listSort.d.ts +3 -34
- package/types/use/listSubscription.d.ts +40 -57
- package/types/use/loading.d.ts +37 -0
- package/types/use/loadingError.d.ts +5 -100
- package/types/use/object.d.ts +3 -12
- package/types/use/objectCalculated.d.ts +3 -9
- package/types/use/objectInstance.d.ts +59 -47
- package/types/use/objectRelated.d.ts +3 -9
- package/types/use/objectSubscription.d.ts +33 -51
- package/types/use/proxyError.d.ts +27 -0
- package/types/use/proxyLoading.d.ts +15 -0
- package/types/use/proxyLoadingError.d.ts +8 -16
- package/types/use/search.d.ts +2 -3
- package/types/utils/assignReactiveObject.d.ts +0 -1
- package/types/utils/cancellableFetch.d.ts +0 -1
- package/types/utils/cancellablePromise.d.ts +0 -1
- package/types/utils/classes.d.ts +2 -8
- package/types/utils/compact.d.ts +0 -1
- package/types/utils/deepUnref.d.ts +0 -1
- package/types/utils/deleteKey.d.ts +5 -6
- package/types/utils/flattenPaths.d.ts +0 -1
- package/types/utils/flattenPathsWithValues.d.ts +0 -1
- package/types/utils/getFakePk.d.ts +0 -1
- package/types/utils/keepAliveTry.d.ts +0 -1
- package/types/utils/keyDiff.d.ts +0 -1
- package/types/utils/loadingCombine.d.ts +0 -1
- package/types/utils/proxyRunning.d.ts +2 -3
- package/types/utils/refIfReactive.d.ts +0 -1
- package/types/utils/relatedCalculatedHelpers.d.ts +0 -1
- package/types/utils/set.d.ts +0 -1
- package/types/utils/transformWalk.d.ts +0 -1
- package/types/utils/unwrapNested.d.ts +0 -1
- package/types/utils/watches.d.ts +0 -1
- package/use/cancellableIntent.js +185 -100
- package/use/error.js +44 -0
- package/use/list.js +51 -111
- package/use/listCalculated.js +75 -98
- package/use/listFilter.js +91 -186
- package/use/listInstance.js +357 -282
- package/use/listRelated.js +52 -72
- package/use/listSearch.js +49 -86
- package/use/listSort.js +121 -237
- package/use/listSubscription.js +181 -274
- package/use/loading.js +35 -0
- package/use/loadingError.js +7 -81
- package/use/object.js +47 -67
- package/use/objectCalculated.js +103 -65
- package/use/objectInstance.js +253 -241
- package/use/objectRelated.js +48 -30
- package/use/objectSubscription.js +110 -175
- package/use/proxyError.js +48 -0
- package/use/proxyLoading.js +22 -0
- package/use/proxyLoadingError.js +9 -35
- package/use/search.js +4 -2
- package/utils/assignReactiveObject.js +8 -8
- package/utils/classes.js +7 -28
- package/utils/deleteKey.js +9 -3
- package/utils/proxyRunning.js +16 -10
- package/types/config/commonCrud.d.ts.map +0 -1
- package/types/config/listCrud.d.ts.map +0 -1
- package/types/config/objectCrud.d.ts.map +0 -1
- package/types/index.d.ts.map +0 -1
- package/types/tests/unit/config/listCrud.spec.d.ts.map +0 -1
- package/types/tests/unit/config/objectCrud.spec.d.ts.map +0 -1
- package/types/tests/unit/crudPromise.d.ts.map +0 -1
- package/types/tests/unit/expectHelpers.d.ts +0 -2
- package/types/tests/unit/expectHelpers.d.ts.map +0 -1
- package/types/tests/unit/mockOnUnmounted.d.ts.map +0 -1
- package/types/tests/unit/poll.d.ts.map +0 -1
- package/types/tests/unit/use/cancellableIntent.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listCalculated.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listFilter.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listInstance.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listRelated.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listSearch.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listSort.spec.d.ts.map +0 -1
- package/types/tests/unit/use/listSubscription.spec.d.ts.map +0 -1
- package/types/tests/unit/use/loadingError.spec.d.ts.map +0 -1
- package/types/tests/unit/use/objectInstance.spec.d.ts.map +0 -1
- package/types/tests/unit/use/objectSubscription.spec.d.ts.map +0 -1
- package/types/tests/unit/use/proxyLoadingError.spec.d.ts.map +0 -1
- package/types/tests/unit/use/search.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/assignReactiveObject.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/classes.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/deleteKey.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/flattenPaths.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/keyDiff.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/set.spec.d.ts.map +0 -1
- package/types/tests/unit/utils/watches.spec.d.ts.map +0 -1
- package/types/use/cancellableIntent.d.ts.map +0 -1
- package/types/use/combineClasses.d.ts.map +0 -1
- package/types/use/list.d.ts.map +0 -1
- package/types/use/listCalculated.d.ts.map +0 -1
- package/types/use/listFilter.d.ts.map +0 -1
- package/types/use/listInstance.d.ts.map +0 -1
- package/types/use/listKeys.d.ts +0 -15
- package/types/use/listKeys.d.ts.map +0 -1
- package/types/use/listRelated.d.ts.map +0 -1
- package/types/use/listSearch.d.ts.map +0 -1
- package/types/use/listSort.d.ts.map +0 -1
- package/types/use/listSubscription.d.ts.map +0 -1
- package/types/use/loadingError.d.ts.map +0 -1
- package/types/use/object.d.ts.map +0 -1
- package/types/use/objectCalculated.d.ts.map +0 -1
- package/types/use/objectInstance.d.ts.map +0 -1
- package/types/use/objectRelated.d.ts.map +0 -1
- package/types/use/objectSubscription.d.ts.map +0 -1
- package/types/use/paginatedListInstance.d.ts +0 -60
- package/types/use/paginatedListInstance.d.ts.map +0 -1
- package/types/use/proxyLoadingError.d.ts.map +0 -1
- package/types/use/search.d.ts.map +0 -1
- package/types/use/watchesRunning.d.ts +0 -63
- package/types/use/watchesRunning.d.ts.map +0 -1
- package/types/utils/assignReactiveObject.d.ts.map +0 -1
- package/types/utils/cancellableFetch.d.ts.map +0 -1
- package/types/utils/cancellablePromise.d.ts.map +0 -1
- package/types/utils/classes.d.ts.map +0 -1
- package/types/utils/compact.d.ts.map +0 -1
- package/types/utils/deepUnref.d.ts.map +0 -1
- package/types/utils/deleteKey.d.ts.map +0 -1
- package/types/utils/flattenPaths.d.ts.map +0 -1
- package/types/utils/flattenPathsWithValues.d.ts.map +0 -1
- package/types/utils/getFakePk.d.ts.map +0 -1
- package/types/utils/keepAliveTry.d.ts.map +0 -1
- package/types/utils/keyDiff.d.ts.map +0 -1
- package/types/utils/loadingCombine.d.ts.map +0 -1
- package/types/utils/proxyRunning.d.ts.map +0 -1
- package/types/utils/refIfReactive.d.ts.map +0 -1
- package/types/utils/relatedCalculatedHelpers.d.ts.map +0 -1
- package/types/utils/set.d.ts.map +0 -1
- package/types/utils/transformWalk.d.ts.map +0 -1
- package/types/utils/unwrapNested.d.ts.map +0 -1
- package/types/utils/watches.d.ts.map +0 -1
- package/use/listKeys.js +0 -105
- package/use/paginatedListInstance.js +0 -126
- package/use/watchesRunning.js +0 -69
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|
|
|
8
|
-
Vue.js 3
|
|
8
|
+
Vue.js 3 composition utilities to manage reactive lists, objects and other helpers.
|
|
9
9
|
|
|
10
10
|
<!-- prettier-ignore-start -->
|
|
11
11
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
@@ -13,24 +13,7 @@ Vue.js 3 utility composition functions to help manipulate objects and lists.
|
|
|
13
13
|
|
|
14
14
|
- [Install](#install)
|
|
15
15
|
- [Usage](#usage)
|
|
16
|
-
|
|
17
|
-
- [Documentation](#documentation)
|
|
18
|
-
- [List](#list)
|
|
19
|
-
- [Instance](#instance)
|
|
20
|
-
- [Subscription](#subscription)
|
|
21
|
-
- [Related](#related)
|
|
22
|
-
- [Calculated](#calculated)
|
|
23
|
-
- [Filter](#filter)
|
|
24
|
-
- [Search](#search)
|
|
25
|
-
- [Sort](#sort)
|
|
26
|
-
- [All](#all)
|
|
27
|
-
- [Object](#object)
|
|
28
|
-
- [Search](#search-1)
|
|
29
|
-
- [Utils](#utils)
|
|
30
|
-
- [addOrUpdateReactiveObject & assignReactiveObject](#addorupdatereactiveobject--assignreactiveobject)
|
|
31
|
-
- [keyDiff](#keydiff)
|
|
32
|
-
- [set](#set)
|
|
33
|
-
- [watches](#watches)
|
|
16
|
+
- [Changelog](#changelog)
|
|
34
17
|
- [Development](#development)
|
|
35
18
|
|
|
36
19
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
|
@@ -38,911 +21,56 @@ Vue.js 3 utility composition functions to help manipulate objects and lists.
|
|
|
38
21
|
|
|
39
22
|
## Install
|
|
40
23
|
|
|
41
|
-
```
|
|
24
|
+
```bash
|
|
42
25
|
$ npm install @arrai-innovations/reactive-helpers
|
|
43
26
|
```
|
|
44
27
|
|
|
45
28
|
## Usage
|
|
46
29
|
|
|
47
|
-
|
|
30
|
+
The package exposes many composables and helper utilities. A minimal example of using a list instance is shown below.
|
|
48
31
|
|
|
49
|
-
```
|
|
50
|
-
// base import contains all exports
|
|
51
|
-
import { useListInstance, useObjectInstance } from "@arrai-innovations/reactive-helpers";
|
|
52
|
-
// you can also import individual modules
|
|
53
|
-
import { useListInstance } from "@arrai-innovations/reactive-helpers/use/listInstance";
|
|
54
|
-
// or the module categories
|
|
55
|
-
import { useObjectInstance } from "@arrai-innovations/reactive-helpers/use";
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Documentation
|
|
59
|
-
|
|
60
|
-
See the [generated documentation](./docs/README.md) for list of available modules and imports.
|
|
61
|
-
|
|
62
|
-
### List
|
|
63
|
-
|
|
64
|
-
#### Instance
|
|
65
|
-
|
|
66
|
-
The container for your list of objects, providing loading or error status.
|
|
67
|
-
|
|
68
|
-
```js
|
|
69
|
-
// do this in your main.js
|
|
70
|
-
import { setListCrud } from "@arrai-innovations/reactive-helpers";
|
|
71
|
-
|
|
72
|
-
setListCrud({
|
|
73
|
-
list: async function listCrudAdaptor({ target, params, pageCallback }) {
|
|
74
|
-
// todo: your implemenation here.
|
|
75
|
-
const listOfObjects = await talkToServer(target, params);
|
|
76
|
-
pageCallback(listOfObjects);
|
|
77
|
-
const nextListOfObjects = await talkToServerAgain(target, params);
|
|
78
|
-
pageCallback(nextListOfObjects);
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
```js
|
|
84
|
-
// then use in your component
|
|
32
|
+
```javascript
|
|
85
33
|
import { useListInstance } from "@arrai-innovations/reactive-helpers";
|
|
86
34
|
import { reactive } from "vue";
|
|
87
35
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
target: {
|
|
91
|
-
stream: "contacts",
|
|
92
|
-
},
|
|
36
|
+
const props = reactive({
|
|
37
|
+
target: { stream: "contacts" },
|
|
93
38
|
pkKey: "id",
|
|
94
|
-
params,
|
|
95
|
-
});
|
|
96
|
-
const contacts = useListInstance({
|
|
97
|
-
props: listProps,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
await contacts.list();
|
|
101
|
-
console.log(contacts.loading);
|
|
102
|
-
// False
|
|
103
|
-
console.log(contacts.errored);
|
|
104
|
-
// False
|
|
105
|
-
console.log(contacts.error);
|
|
106
|
-
// null
|
|
107
|
-
console.log(contacts.objects);
|
|
108
|
-
// { contacts keyed by 'id' }
|
|
109
|
-
// change list or retrieve args directly
|
|
110
|
-
contacts.state.params.fields.push("message_count");
|
|
111
|
-
await contacts.list();
|
|
112
|
-
console.log(contacts.objects);
|
|
113
|
-
// { contacts keyed by 'id' with message_count }
|
|
114
|
-
// change list or retrieve args indirectly
|
|
115
|
-
listProps.params.has_organization = false;
|
|
116
|
-
await contacts.list();
|
|
117
|
-
console.log(contacts.objects);
|
|
118
|
-
// { contacts keyed by 'id' with organizationless contacts }
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
#### Subscription
|
|
122
|
-
|
|
123
|
-
Adds functionality to a list instance to receive updates from the server.
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
// do this in your main.js
|
|
127
|
-
import { setListCrud } from "@arrai-innovations/reactive-helpers";
|
|
128
|
-
setListCrud({
|
|
129
|
-
..., // in addition to the list crud adaptor above
|
|
130
|
-
subscribe: function subscribeCrudAdaptor({ target, params, eventCallback }) {
|
|
131
|
-
// todo: your implemenation here.
|
|
132
|
-
const subscription = talkToServer(function (data, action) {
|
|
133
|
-
eventCallback(data, action);
|
|
134
|
-
});
|
|
135
|
-
// return a promise with a cancel action
|
|
136
|
-
subscription.cancel = async () => {
|
|
137
|
-
await cancelSubOnServer();
|
|
138
|
-
};
|
|
139
|
-
return subscription;
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
```js
|
|
145
|
-
// then use in your component
|
|
146
|
-
import { useListInstance, useListSubscription } from "@arrai-innovations/reactive-helpers";
|
|
147
|
-
import { reactive } from "vue";
|
|
148
|
-
|
|
149
|
-
const listProps = reactive({
|
|
150
|
-
// target are implementation specific to your crud handlers.
|
|
151
|
-
target: {
|
|
152
|
-
stream: "contacts",
|
|
153
|
-
includeCreateEvents: true,
|
|
154
|
-
subscribeAction: "subscribe_contacts",
|
|
155
|
-
unsubscribeAction: "unsubscribe_contacts",
|
|
156
|
-
},
|
|
157
|
-
pkKey: "id",
|
|
158
|
-
params: {
|
|
159
|
-
has_organization: true,
|
|
160
|
-
fields: ["id", "has_name", "lexical_name", "organization", "phone"],
|
|
161
|
-
},
|
|
162
|
-
});
|
|
163
|
-
const contacts = useListInstance({
|
|
164
|
-
props: listProps,
|
|
165
|
-
});
|
|
166
|
-
const contactsSubscription = useListSubscription({
|
|
167
|
-
listInstance: contacts,
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// only get new or updated contacts, not existing.
|
|
171
|
-
contactsSubscription.subscribe();
|
|
172
|
-
// or, subscribe and get the existing list.
|
|
173
|
-
contactsSubscription.subscribe();
|
|
174
|
-
// stop getting updates.
|
|
175
|
-
contactsSubscription.unsubscribe();
|
|
176
|
-
// re-retreive the list of existing contacts including another field.
|
|
177
|
-
contacts.params.fields.push("message_count");
|
|
178
|
-
// re-retreive the list of all existing contacts.
|
|
179
|
-
delete contacts.params.has_organization;
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
```js
|
|
183
|
-
// or you can have listSubscription create the listInstance for you.
|
|
184
|
-
import { useListSubscription } from "@arrai-innovations/reactive-helpers";
|
|
185
|
-
import { reactive } from "vue";
|
|
186
|
-
|
|
187
|
-
const listProps = reactive({
|
|
188
|
-
// target are implementation specific to your crud handlers.
|
|
189
|
-
target: {
|
|
190
|
-
stream: "contacts",
|
|
191
|
-
includeCreateEvents: true,
|
|
192
|
-
subscribeAction: "subscribe_contacts",
|
|
193
|
-
unsubscribeAction: "unsubscribe_contacts",
|
|
194
|
-
},
|
|
195
|
-
params: {
|
|
196
|
-
fields: ["id", "has_name", "lexical_name", "organization", "phone"],
|
|
197
|
-
has_organization: true,
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
const contactsSubscription = useListSubscription({
|
|
201
|
-
props: listProps,
|
|
202
|
-
});
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
#### Related
|
|
206
|
-
|
|
207
|
-
Lookup foreign keys between list instances via watch, for using dot notation in templates to cross object relations.
|
|
208
|
-
|
|
209
|
-
```js
|
|
210
|
-
// no main.js setup required.
|
|
211
|
-
// used in example below.
|
|
212
|
-
import { useListInstance, useListRelated, doAwaitNot } from "@arrai-innovations/reactive-helpers";
|
|
213
|
-
import { reactive, toRef } from "vue";
|
|
214
|
-
|
|
215
|
-
const organizationsProps = reactive({
|
|
216
|
-
pkKey: "id",
|
|
217
|
-
params: {
|
|
218
|
-
fields: ["id", "name"],
|
|
219
|
-
},
|
|
220
|
-
});
|
|
221
|
-
const organizations = useListInstance({
|
|
222
|
-
props: organizationsProps,
|
|
223
|
-
});
|
|
224
|
-
const contactsProps = reactive({
|
|
225
|
-
pkKey: "id",
|
|
226
|
-
params: {
|
|
227
|
-
fields: ["id", "lexical_name", "organization"],
|
|
228
|
-
},
|
|
229
|
-
});
|
|
230
|
-
const contacts = useListInstance({
|
|
231
|
-
props: contactsProps,
|
|
232
|
-
});
|
|
233
|
-
const contactsRelatedRules = reactive({
|
|
234
|
-
organization: {
|
|
235
|
-
// desired key on relatedObjects
|
|
236
|
-
objects: toRef(organizations.state, "objects"), // organizations by id
|
|
237
|
-
pkKey: "organization", // reference key on contact for org id.
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
const contactsRelated = useListRelated({
|
|
241
|
-
parentState: contacts.state,
|
|
242
|
-
relatedObjectsRules: contactsRelatedRules,
|
|
243
|
-
});
|
|
244
|
-
await organizations.list();
|
|
245
|
-
await contacts.list();
|
|
246
|
-
console.log(organizations.objects);
|
|
247
|
-
/*
|
|
248
|
-
{
|
|
249
|
-
"24": { "id": 24, "name": "org 24" },
|
|
250
|
-
"42": { "id": 42, "name": "org 42" },
|
|
251
|
-
}
|
|
252
|
-
*/
|
|
253
|
-
console.log(contacts.objects);
|
|
254
|
-
/*
|
|
255
|
-
{
|
|
256
|
-
"15": {
|
|
257
|
-
"id": 15,
|
|
258
|
-
"lexical_name": "one, contact",
|
|
259
|
-
"organization": 42,
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
*/
|
|
263
|
-
console.log(contacts.relatedObjects);
|
|
264
|
-
/*
|
|
265
|
-
{
|
|
266
|
-
"15": {
|
|
267
|
-
"organization": { "id": 42, "name": "org 42" }
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
*/
|
|
271
|
-
contacts.objects["15"].organization = 24;
|
|
272
|
-
await doAwaitNot({
|
|
273
|
-
obj: contactsRelated.state,
|
|
274
|
-
prop: "running",
|
|
275
|
-
});
|
|
276
|
-
console.log(contacts.relatedObjects["15"]);
|
|
277
|
-
/*
|
|
278
|
-
{
|
|
279
|
-
"organization": { "id": 24, "name": "org 24" }
|
|
280
|
-
}
|
|
281
|
-
*/
|
|
282
|
-
delete contactsRelated.relatedObjectRules.organization;
|
|
283
|
-
await doAwaitNot({
|
|
284
|
-
obj: contactsRelated.state,
|
|
285
|
-
prop: "running",
|
|
286
|
-
});
|
|
287
|
-
await nextTick();
|
|
288
|
-
console.log(contacts.relatedObjects["15"]);
|
|
289
|
-
/* {} */
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
#### Calculated
|
|
293
|
-
|
|
294
|
-
```js
|
|
295
|
-
// no main.js setup required.
|
|
296
|
-
// used in example below.
|
|
297
|
-
import { useListInstance, useListCalculated } from "@arrai-innovations/reactive-helpers";
|
|
298
|
-
import { nextTick, reactive } from "vue";
|
|
299
|
-
|
|
300
|
-
const contactsProps = reactive({
|
|
301
|
-
pkKey: "id",
|
|
302
|
-
params: {
|
|
303
|
-
fields: ["id", "has_name", "has_billing", "lexical_name", "organization"],
|
|
304
|
-
},
|
|
305
|
-
});
|
|
306
|
-
const contacts = useListInstance({
|
|
307
|
-
props: contactsProps,
|
|
308
|
-
});
|
|
309
|
-
const contactsCalculatedRules = reactive({
|
|
310
|
-
first_letter_of_name: (object) => {
|
|
311
|
-
return object.lexical_name[0];
|
|
312
|
-
},
|
|
313
|
-
});
|
|
314
|
-
const contactsCalculated = useListCalculated({
|
|
315
|
-
parentState: contacts.state,
|
|
316
|
-
calculatedObjectsRules: contactsCalculatedRules,
|
|
317
|
-
});
|
|
318
|
-
await contacts.list();
|
|
319
|
-
console.log(contacts.objects);
|
|
320
|
-
/*
|
|
321
|
-
{
|
|
322
|
-
"15": {
|
|
323
|
-
"id": 15,
|
|
324
|
-
"lexical_name": "one, contact",
|
|
325
|
-
"organization": 42,
|
|
326
|
-
},
|
|
327
|
-
"16": {
|
|
328
|
-
"id": 16,
|
|
329
|
-
"lexical_name": "two, contact",
|
|
330
|
-
"organization": 42,
|
|
331
|
-
},
|
|
332
|
-
}
|
|
333
|
-
*/
|
|
334
|
-
console.log(contacts.calculatedObjects);
|
|
335
|
-
/*
|
|
336
|
-
{
|
|
337
|
-
"15": {
|
|
338
|
-
"first_letter_of_name": "o"
|
|
339
|
-
},
|
|
340
|
-
"16": {
|
|
341
|
-
"first_letter_of_name": "t"
|
|
342
|
-
},
|
|
343
|
-
}
|
|
344
|
-
*/
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
#### Filter
|
|
348
|
-
|
|
349
|
-
```js
|
|
350
|
-
// no main.js setup required.
|
|
351
|
-
// used in example below.
|
|
352
|
-
import { useListInstance, useListFilter, doAwaitNot } from "@arrai-innovations/reactive-helpers";
|
|
353
|
-
import { reactive, ref } from "vue";
|
|
354
|
-
|
|
355
|
-
const contactsProps = reactive({
|
|
356
|
-
pkKey: "id",
|
|
357
|
-
params: {
|
|
358
|
-
fields: ["id", "has_name", "has_billing", "lexical_name", "organization"],
|
|
359
|
-
},
|
|
360
|
-
});
|
|
361
|
-
const contacts = useListInstance({
|
|
362
|
-
props: contactsProps,
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
const allowedFilter = ref((object) => {
|
|
366
|
-
return object.has_name === true;
|
|
367
|
-
});
|
|
368
|
-
const excludedFilter = ref((object) => {
|
|
369
|
-
return object.has_billing === true;
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
// conditions are all optional but anded together if present.
|
|
373
|
-
const contactsFilter = useListFilter({
|
|
374
|
-
parentState: contacts.state,
|
|
375
|
-
allowedFilter,
|
|
376
|
-
excludedFilter,
|
|
377
|
-
});
|
|
378
|
-
await contacts.list();
|
|
379
|
-
console.log(contactsFilter.state.objects);
|
|
380
|
-
console.log(contactsFilter.state.objectsInOrder);
|
|
381
|
-
console.log(contactsFilter.state.order);
|
|
382
|
-
contacts.objects["15"].has_name = false;
|
|
383
|
-
await doAwaitNot({
|
|
384
|
-
obj: contactsFilter.state,
|
|
385
|
-
prop: "running",
|
|
386
|
-
});
|
|
387
|
-
console.log(contactsFilter.state.objects);
|
|
388
|
-
console.log(contactsFilter.state.objectsInOrder);
|
|
389
|
-
console.log(contactsFilter.state.order);
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
#### Search
|
|
393
|
-
|
|
394
|
-
```js
|
|
395
|
-
// no main.js setup required.
|
|
396
|
-
// used in example below.
|
|
397
|
-
import { useListInstance, useListSearch, doAwaitNot } from "@arrai-innovations/reactive-helpers";
|
|
398
|
-
import { reactive } from "vue";
|
|
399
|
-
|
|
400
|
-
const contactsProps = reactive({
|
|
401
|
-
pkKey: "id",
|
|
402
|
-
params: {
|
|
403
|
-
fields: ["id", "has_name", "has_billing", "lexical_name", "organization"],
|
|
404
|
-
},
|
|
405
|
-
});
|
|
406
|
-
const contacts = useListInstance({
|
|
407
|
-
props: contactsProps,
|
|
408
|
-
});
|
|
409
|
-
const searchProps = reactive({
|
|
410
|
-
textSearchRules: ["lexical_name"],
|
|
411
|
-
textSearchValue: "",
|
|
412
|
-
});
|
|
413
|
-
const search = useListSearch({
|
|
414
|
-
parentState: contacts.state,
|
|
415
|
-
props: searchProps,
|
|
416
|
-
});
|
|
417
|
-
await contacts.list();
|
|
418
|
-
await doAwaitNot({
|
|
419
|
-
obj: search.state,
|
|
420
|
-
prop: "running",
|
|
421
|
-
});
|
|
422
|
-
// all values show when search is empty.
|
|
423
|
-
console.log(search.state.objects);
|
|
424
|
-
console.log(search.state.objectsInOrder);
|
|
425
|
-
console.log(search.state.order);
|
|
426
|
-
searchProps.textSearchValue = "one";
|
|
427
|
-
await doAwaitNot({
|
|
428
|
-
obj: search.state,
|
|
429
|
-
prop: "running",
|
|
39
|
+
params: { fields: ["id", "name"] },
|
|
430
40
|
});
|
|
431
|
-
// only values that match the search show.
|
|
432
|
-
console.log(search.state.objects);
|
|
433
|
-
console.log(search.state.objectsInOrder);
|
|
434
|
-
console.log(search.state.order);
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
#### Sort
|
|
438
|
-
|
|
439
|
-
```js
|
|
440
|
-
// no main.js setup required.
|
|
441
|
-
// used in example below.
|
|
442
|
-
import { useListInstance, useListSort, doAwaitNot } from "@arrai-innovations/reactive-helpers";
|
|
443
|
-
import { reactive } from "vue";
|
|
444
41
|
|
|
445
|
-
const
|
|
446
|
-
pkKey: "id",
|
|
447
|
-
params: {
|
|
448
|
-
fields: ["id", "has_name", "lexical_name", "organization"],
|
|
449
|
-
},
|
|
450
|
-
});
|
|
451
|
-
const contacts = useListInstance({
|
|
452
|
-
props: contactsProps,
|
|
453
|
-
});
|
|
454
|
-
const contactsSort = useListSort({
|
|
455
|
-
parentState: contacts.state,
|
|
456
|
-
orderByRules: [
|
|
457
|
-
{ key: "has_name", desc: true, localeCompare: false },
|
|
458
|
-
{ key: "lexical_name", desc: false, localeCompare: true },
|
|
459
|
-
],
|
|
460
|
-
sortThrottleWait: 100, // default, ms to wait before sorting after a change.
|
|
461
|
-
});
|
|
42
|
+
const contacts = useListInstance({ props });
|
|
462
43
|
await contacts.list();
|
|
463
|
-
console.log(
|
|
464
|
-
// array of ids in order, based on the specified rules.
|
|
465
|
-
console.log(contactsSort.state.objectsInOrder);
|
|
466
|
-
// computed array of the previous that also looks up the object ids in .objects
|
|
467
|
-
contactsSort.state.orderByRules[0].desc = false;
|
|
468
|
-
await doAwaitNot({
|
|
469
|
-
obj: contactsSort.state,
|
|
470
|
-
prop: "running",
|
|
471
|
-
});
|
|
472
|
-
console.log(contactsSort.state.order);
|
|
473
|
-
// array of ids in order, based on updated rules.
|
|
44
|
+
console.log(contacts.state.objects);
|
|
474
45
|
```
|
|
475
46
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
```js
|
|
479
|
-
// you can also let the library manage a full stack for you.
|
|
480
|
-
import { useList } from "@arrai-innovations/reactive-helpers";
|
|
481
|
-
import { reactive, toRef } from "vue";
|
|
482
|
-
|
|
483
|
-
const managedListProps = reactive({
|
|
484
|
-
// target are implementation specific to your crud handlers.
|
|
485
|
-
target: {
|
|
486
|
-
stream: "contacts",
|
|
487
|
-
includeCreateEvents: true,
|
|
488
|
-
subscribeAction: "subscribe_contacts",
|
|
489
|
-
unsubscribeAction: "unsubscribe_contacts",
|
|
490
|
-
},
|
|
491
|
-
pkKey: "id",
|
|
492
|
-
params: {
|
|
493
|
-
has_organization: true,
|
|
494
|
-
fields: ["id", "has_name", "lexical_name", "organization", "phone"],
|
|
495
|
-
},
|
|
496
|
-
relatedObjectsRules: {
|
|
497
|
-
organization: {
|
|
498
|
-
// desired key on relatedObjects
|
|
499
|
-
objects: toRef(organizations.state, "objects"), // organizations by id
|
|
500
|
-
pkKey: "organization", // reference key on contact for org id.
|
|
501
|
-
},
|
|
502
|
-
},
|
|
503
|
-
calculatedObjectsRules: {
|
|
504
|
-
first_letter_of_name: (object) => {
|
|
505
|
-
return object.lexical_name[0];
|
|
506
|
-
},
|
|
507
|
-
},
|
|
508
|
-
orderByRules: [
|
|
509
|
-
{ key: "relatedObjects.organization.name", desc: false, localeCompare: true },
|
|
510
|
-
{ key: "lexical_name", desc: false, localeCompare: true },
|
|
511
|
-
],
|
|
512
|
-
textSearchRules: ["relatedObjects.organization.name"],
|
|
513
|
-
textSearchValue: organizationNameSearch,
|
|
514
|
-
sortThrottleWait: 100, // default, ms to wait before sorting after a change.
|
|
515
|
-
});
|
|
516
|
-
const managedList = useList({
|
|
517
|
-
props: managedListProps,
|
|
518
|
-
handlers: {
|
|
519
|
-
list: customListFunction,
|
|
520
|
-
subscribe: customSubscribeFunction,
|
|
521
|
-
},
|
|
522
|
-
});
|
|
523
|
-
// the state expected of each are all available on the same state.
|
|
524
|
-
console.log(managedList.state.objects);
|
|
525
|
-
// managed instances can also be accessed directly.
|
|
526
|
-
console.log(managedList.managed);
|
|
527
|
-
/*
|
|
528
|
-
{
|
|
529
|
-
listInstance: {...},
|
|
530
|
-
listSubscription: {...},
|
|
531
|
-
listRelated: {...},
|
|
532
|
-
listCalculated: {...},
|
|
533
|
-
listFilter: {...},
|
|
534
|
-
listSort: {...},
|
|
535
|
-
}
|
|
536
|
-
*/
|
|
537
|
-
// the stack is applied in the order of the keys as by managedList.managed.
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
### Object
|
|
541
|
-
|
|
542
|
-
```js
|
|
543
|
-
// do this in your main.js
|
|
544
|
-
import { setObjectCrud } from "@arrai-innovations/reactive-helpers";
|
|
545
|
-
|
|
546
|
-
setObjectCrud({
|
|
547
|
-
create: async function createCrudAdaptor({ target, params, object }) {
|
|
548
|
-
// todo: your implemenation here.
|
|
549
|
-
const newObject = await talkToServer(object);
|
|
550
|
-
return newObject;
|
|
551
|
-
},
|
|
552
|
-
retrieve: async function retrieveCrudAdaptor({ target, params, id }) {
|
|
553
|
-
// todo: your implemenation here.
|
|
554
|
-
const retrievedObject = await talkToServer(id);
|
|
555
|
-
return retrievedObject;
|
|
556
|
-
},
|
|
557
|
-
update: async function updateCrudAdaptor({ target, params, object }) {
|
|
558
|
-
// todo: your implemenation here.
|
|
559
|
-
const updatedObject = await talkToServer(object);
|
|
560
|
-
return updatedObject;
|
|
561
|
-
},
|
|
562
|
-
delete: async function deleteCrudAdaptor({ target, id }) {
|
|
563
|
-
// todo: your implemenation here.
|
|
564
|
-
await talkToServer(id);
|
|
565
|
-
},
|
|
566
|
-
patch: async function patchCrudAdaptor({ target, params, id, partialObject }) {
|
|
567
|
-
// todo: your implemenation here.
|
|
568
|
-
const patchedObject = await talkToServer(object);
|
|
569
|
-
return patchedObject; // still return the full object.
|
|
570
|
-
},
|
|
571
|
-
subscribe: function subscribeCrudAdaptor({ target, params, params, eventCallback }) {
|
|
572
|
-
// todo: your implemenation here.
|
|
573
|
-
const subscription = talkToServer(function (data, action) {
|
|
574
|
-
eventCallback(data, action);
|
|
575
|
-
});
|
|
576
|
-
// return a promise with a cancel action
|
|
577
|
-
subscription.cancel = async () => {
|
|
578
|
-
await cancelSubOnServer();
|
|
579
|
-
};
|
|
580
|
-
return subscription;
|
|
581
|
-
},
|
|
582
|
-
});
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
```js
|
|
586
|
-
// similar to list, but for a single object.
|
|
587
|
-
import {
|
|
588
|
-
useObjectInstance,
|
|
589
|
-
useObjectSubscription,
|
|
590
|
-
useObjectRelated,
|
|
591
|
-
useObjectCalculated,
|
|
592
|
-
} from "@arrai-innovations/reactive-helpers";
|
|
593
|
-
|
|
594
|
-
const contactObject = useObjectInstance({
|
|
595
|
-
props: {
|
|
596
|
-
target: {
|
|
597
|
-
stream: "contacts",
|
|
598
|
-
},
|
|
599
|
-
params: {
|
|
600
|
-
fields: ["id", "has_name", "lexical_name", "organization", "phone"],
|
|
601
|
-
},
|
|
602
|
-
id: contactId,
|
|
603
|
-
},
|
|
604
|
-
});
|
|
605
|
-
console.log(contactObject.state.object);
|
|
606
|
-
const contactSubscription = useObjectSubscription({
|
|
607
|
-
objectInstance: contactObject,
|
|
608
|
-
});
|
|
609
|
-
// or
|
|
610
|
-
const contactSubscription = useObjectSubscription({
|
|
611
|
-
props: {
|
|
612
|
-
target: {
|
|
613
|
-
stream: "contacts",
|
|
614
|
-
},
|
|
615
|
-
params: {
|
|
616
|
-
fields: ["id", "has_name", "lexical_name", "organization", "phone"],
|
|
617
|
-
},
|
|
618
|
-
id: contactId,
|
|
619
|
-
},
|
|
620
|
-
});
|
|
621
|
-
console.log(contactSubscription.state.object);
|
|
622
|
-
const organizations = useList({
|
|
623
|
-
props: {
|
|
624
|
-
target: {
|
|
625
|
-
stream: "organizations",
|
|
626
|
-
},
|
|
627
|
-
params: {
|
|
628
|
-
fields: ["id", "name"],
|
|
629
|
-
},
|
|
630
|
-
},
|
|
631
|
-
});
|
|
632
|
-
await organizations.list();
|
|
633
|
-
const contactRelated = useObjectRelated({
|
|
634
|
-
parentState: contactSubscription.state,
|
|
635
|
-
relatedObjectRules: {
|
|
636
|
-
organization: {
|
|
637
|
-
// desired key on relatedObjects
|
|
638
|
-
objects: toRef(organizations.state, "objects"), // organizations by id
|
|
639
|
-
pkKey: "organization", // reference key on contact for org id.
|
|
640
|
-
},
|
|
641
|
-
},
|
|
642
|
-
});
|
|
643
|
-
console.log(contactRelated.state.object.relatedObject.organization.name);
|
|
644
|
-
const contactCalculated = useObjectCalculated({
|
|
645
|
-
parentState: contactSubscription.state,
|
|
646
|
-
calculatedObjectRules: {
|
|
647
|
-
first_letter_of_name: (object) => {
|
|
648
|
-
return object.lexical_name[0];
|
|
649
|
-
},
|
|
650
|
-
},
|
|
651
|
-
});
|
|
652
|
-
console.log(contactCalculated.state.object.calculatedObject.first_letter_of_name);
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
```js
|
|
656
|
-
// you can also let the library managed a full stack for you.
|
|
657
|
-
import { useObject } from "@arrai-innovations/reactive-helpers";
|
|
658
|
-
import { reactive } from "vue";
|
|
659
|
-
|
|
660
|
-
const managedObjectProps = reactive({
|
|
661
|
-
target: {
|
|
662
|
-
stream: "contacts",
|
|
663
|
-
},
|
|
664
|
-
params: {
|
|
665
|
-
fields: ["id", "has_name", "lexical_name", "organization", "phone"],
|
|
666
|
-
},
|
|
667
|
-
pk: contactId,
|
|
668
|
-
pkKey: "id",
|
|
669
|
-
relatedObjectRules: {
|
|
670
|
-
organization: {
|
|
671
|
-
// desired key on relatedObjects
|
|
672
|
-
objects: toRef(organizations.state, "objects"), // organizations by id
|
|
673
|
-
pkKey: "organization", // reference key on contact for org id.
|
|
674
|
-
},
|
|
675
|
-
},
|
|
676
|
-
calculatedObjectRules: {
|
|
677
|
-
first_letter_of_name: (object) => {
|
|
678
|
-
return object.lexical_name[0];
|
|
679
|
-
},
|
|
680
|
-
},
|
|
681
|
-
});
|
|
682
|
-
const managedObject = useObject({
|
|
683
|
-
props: managedObjectProps,
|
|
684
|
-
handlers: {
|
|
685
|
-
retrieve: customRetrieveFunction,
|
|
686
|
-
subscribe: customSubscribeFunction,
|
|
687
|
-
},
|
|
688
|
-
});
|
|
689
|
-
// the state expected of each are all available on the same state.
|
|
690
|
-
console.log(managedObject.state.objects);
|
|
691
|
-
// managed instances can also be accessed directly.
|
|
692
|
-
console.log(managedObject.managed);
|
|
693
|
-
/*
|
|
694
|
-
{
|
|
695
|
-
objectInstance: {...},
|
|
696
|
-
objectSubscription: {...},
|
|
697
|
-
objectRelated: {...},
|
|
698
|
-
objectCalculated: {...},\
|
|
699
|
-
}
|
|
700
|
-
*/
|
|
701
|
-
// the stack is applied in the order of the keys as by managedObject.managed.
|
|
702
|
-
```
|
|
703
|
-
|
|
704
|
-
### Search
|
|
705
|
-
|
|
706
|
-
```js
|
|
707
|
-
// no main.js setup required.
|
|
708
|
-
import { useSearch } from "@arrai-innovations/reactive-helpers";
|
|
709
|
-
|
|
710
|
-
const search = useSearch({});
|
|
711
|
-
```
|
|
712
|
-
|
|
713
|
-
### Utils
|
|
714
|
-
|
|
715
|
-
#### addOrUpdateReactiveObject & assignReactiveObject
|
|
716
|
-
|
|
717
|
-
`addOrUpdateReactiveObject` - Assigns properties of a source object onto a target object, using refs if both source and
|
|
718
|
-
target are reactive.
|
|
719
|
-
|
|
720
|
-
`assignReactiveObject` - same as `addOrUpdateReactiveObject`, but deletes keys from target that are not in source.
|
|
721
|
-
|
|
722
|
-
```js
|
|
723
|
-
import { assignReactiveObject, addOrUpdateReactiveObject } from "@arrai-innovations/reactive-helpers";
|
|
724
|
-
import { reactive, toRef, computed } from "vue";
|
|
47
|
+
See [docs/README.md](./docs/README.md) for a full list of modules, composables, utilities, as well as, their arguments
|
|
48
|
+
and properties.
|
|
725
49
|
|
|
726
|
-
|
|
727
|
-
const source = { a: 3, b: 4 };
|
|
728
|
-
const source2 = reactive({ b: 5 });
|
|
50
|
+
## Changelog
|
|
729
51
|
|
|
730
|
-
|
|
731
|
-
const b = toRef(target, "b");
|
|
732
|
-
const mySum = computed(() => (unref(a) || 0) + (unref(b) || 0));
|
|
733
|
-
|
|
734
|
-
console.log(mySum.value); // 1
|
|
735
|
-
assignReactiveObject(target, source);
|
|
736
|
-
console.log(mySum.value); // 7
|
|
737
|
-
addOrUpdateReactiveObject(target, source2);
|
|
738
|
-
console.log({ ...target }); // { a: 3, b: 5 }
|
|
739
|
-
console.log(mySum.value); // 8
|
|
740
|
-
source2.b = 6;
|
|
741
|
-
console.log(mySum.value); // 9
|
|
742
|
-
assignReactiveObject(target, source2);
|
|
743
|
-
console.log({ ...target }); // { b: 6 }
|
|
744
|
-
console.log(mySum.value); // 6
|
|
745
|
-
source2.b = 10;
|
|
746
|
-
console.log(mySum.value); // 10
|
|
747
|
-
```
|
|
748
|
-
|
|
749
|
-
#### keyDiff
|
|
750
|
-
|
|
751
|
-
`keyDiff` - returns the various set results related to figuring out the changes in keys over time on an object or related objects. Returns the intersection as sameKeys, the difference of old and new as removedKeys, and the difference of new and old as addedKeys.
|
|
752
|
-
|
|
753
|
-
```js
|
|
754
|
-
import { keyDiff } from "@arrai-innovations/reactive-helpers";
|
|
755
|
-
|
|
756
|
-
const newKeys = Object.keys({ a: 1, b: 2 });
|
|
757
|
-
const oldKeys = Object.keys({ a: 1, c: 3 });
|
|
758
|
-
const { addedKeys, removedKeys, sameKeys } = keyDiff(newKeys, oldKeys);
|
|
759
|
-
console.log({ addedKeys, removedKeys, sameKeys });
|
|
760
|
-
// { addedKeys: Set(1) { 'b' }, removedKeys: Set(1) { 'c' }, sameKeys: Set(1) { 'a' } }
|
|
761
|
-
```
|
|
762
|
-
|
|
763
|
-
#### set
|
|
764
|
-
|
|
765
|
-
We make use of the basic set operations provided as example on mdn:
|
|
766
|
-
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#implementing_basic_set_operations
|
|
767
|
-
|
|
768
|
-
```js
|
|
769
|
-
import {
|
|
770
|
-
isSuperset,
|
|
771
|
-
union,
|
|
772
|
-
intersection,
|
|
773
|
-
symmetricDifference,
|
|
774
|
-
difference,
|
|
775
|
-
equals,
|
|
776
|
-
} from "@arrai-innovations/reactive-helpers";
|
|
777
|
-
|
|
778
|
-
isSuperset(new Set([1, 2, 3, 4]), new Set([1, 2, 3])); // true
|
|
779
|
-
union(new Set([1, 2, 3, 4]), new Set([1, 2, 3])); // Set { 1, 2, 3, 4 }
|
|
780
|
-
intersection(new Set([1, 2, 3, 4]), new Set([1, 2, 3])); // Set { 1, 2, 3 }
|
|
781
|
-
symmetricDifference(new Set([1, 2, 3, 4]), new Set([1, 2, 3, 5])); // Set { 4, 5 }
|
|
782
|
-
difference(new Set([1, 2, 3, 4]), new Set([1, 2, 3, 5])); // Set { 4 }
|
|
783
|
-
difference(new Set([1, 2, 3, 5]), new Set([1, 2, 3, 4])); // Set { 5 }
|
|
784
|
-
equals(new Set([1, 2, 3, 4]), new Set([1, 2, 3, 5])); // false
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
#### watches
|
|
788
|
-
|
|
789
|
-
`ImmediateStopWatch` - a vue.js watch that can be stopped in the first iteration
|
|
790
|
-
|
|
791
|
-
```js
|
|
792
|
-
import { ImmediateStopWatch } from "@arrai-innovations/reactive-helpers";
|
|
793
|
-
|
|
794
|
-
const reactiveObject = reactive({ a: 1 });
|
|
795
|
-
const watch = new ImmediateStopWatch();
|
|
796
|
-
const watch2 = new ImmediateStopWatch();
|
|
797
|
-
watch.start(
|
|
798
|
-
() => reactiveObject.a,
|
|
799
|
-
(newA) => {
|
|
800
|
-
if (newA === 2) {
|
|
801
|
-
console.log("a is now 2!");
|
|
802
|
-
watch.stop();
|
|
803
|
-
}
|
|
804
|
-
},
|
|
805
|
-
[reactiveObject.a]
|
|
806
|
-
);
|
|
807
|
-
watch2.start(
|
|
808
|
-
() => reactiveObject.a,
|
|
809
|
-
(newA) => {
|
|
810
|
-
if (newA === 1) {
|
|
811
|
-
console.log("a is now 1!");
|
|
812
|
-
watch2.stop();
|
|
813
|
-
}
|
|
814
|
-
},
|
|
815
|
-
[reactiveObject.a]
|
|
816
|
-
);
|
|
817
|
-
// a is now 1!
|
|
818
|
-
await nextTick();
|
|
819
|
-
reactiveObject.a = 2;
|
|
820
|
-
await nextTick();
|
|
821
|
-
// a is now 2!
|
|
822
|
-
await nextTick();
|
|
823
|
-
reactiveObject.a = 1;
|
|
824
|
-
await nextTick();
|
|
825
|
-
// no output;
|
|
826
|
-
reactiveObject.a = 2;
|
|
827
|
-
await nextTick();
|
|
828
|
-
// no output;
|
|
829
|
-
```
|
|
830
|
-
|
|
831
|
-
`AwaitTimeout` - a class that provides a promise that resolves after a timeout.
|
|
832
|
-
|
|
833
|
-
```js
|
|
834
|
-
import { AwaitTimeout } from "@arrai-innovations/reactive-helpers";
|
|
835
|
-
|
|
836
|
-
const awaitTimeout = new AwaitTimeout({ timeout: 1000 });
|
|
837
|
-
awaitTimeout.start();
|
|
838
|
-
await awaitTimeout.promise; // waits 1 second
|
|
839
|
-
const awaitTimeout2 = new AwaitTimeout({ timeout: 1000 });
|
|
840
|
-
awaitTimeout2.start();
|
|
841
|
-
setTimeout(() => awaitTimeout2.stop(), 500);
|
|
842
|
-
await awaitTimeout2.promise; // waits 500 ms then rejects with new AwaitTimeoutError("Cancelled", "timeout_cancelled")
|
|
843
|
-
```
|
|
844
|
-
|
|
845
|
-
`doAwaitTimeout` - a function that returns a promise that resolves after a timeout.
|
|
846
|
-
|
|
847
|
-
```js
|
|
848
|
-
import { doAwaitTimeout } from "@arrai-innovations/reactive-helpers";
|
|
849
|
-
|
|
850
|
-
// non cancellable AwaitTimeout helper
|
|
851
|
-
await doAwaitTimeout(1000); // waits 1 second
|
|
852
|
-
```
|
|
853
|
-
|
|
854
|
-
`AwaitNot` - a class that provides a promise that resolves when a watched prop switches to true then to false.
|
|
855
|
-
|
|
856
|
-
```mermaid
|
|
857
|
-
flowchart TD
|
|
858
|
-
A["new AwaitNot"] --> B["AwaitNot.start()"];
|
|
859
|
-
B -- timeout --> G["AwaitNot.promise is rejected"]
|
|
860
|
-
B --> C{"prop is false"};
|
|
861
|
-
C -- false --> D["AwaitNot.waitForTrue()"];
|
|
862
|
-
C -- true --> H{"canAlreadyBeFalse"}
|
|
863
|
-
H -- true --> D;
|
|
864
|
-
H -- false --> E["AwaitNot.waitForFalse()"];
|
|
865
|
-
|
|
866
|
-
D -- timeout --> G
|
|
867
|
-
E -- timeout --> G
|
|
868
|
-
E -- prop is false --> F["AwaitNot.promise is resolved"]
|
|
869
|
-
D -- prop is true --> E
|
|
870
|
-
```
|
|
871
|
-
|
|
872
|
-
```js
|
|
873
|
-
import { AwaitNot } from "@arrai-innovations/reactive-helpers";
|
|
874
|
-
import { reactive } from "vue";
|
|
875
|
-
|
|
876
|
-
const reactiveObject = reactive({});
|
|
877
|
-
|
|
878
|
-
const awaitNot = new AwaitNot({
|
|
879
|
-
obj: reactiveObject,
|
|
880
|
-
prop: "prop",
|
|
881
|
-
couldAlreadyBeFalse: true, // default
|
|
882
|
-
timeout: 1000, // default
|
|
883
|
-
});
|
|
884
|
-
awaitNot.promise
|
|
885
|
-
.then(() => {
|
|
886
|
-
console.log("resolved");
|
|
887
|
-
})
|
|
888
|
-
.catch(() => {
|
|
889
|
-
console.log("rejected");
|
|
890
|
-
});
|
|
891
|
-
awaitNot.start();
|
|
892
|
-
await nextTick();
|
|
893
|
-
reactiveObject.prop = true;
|
|
894
|
-
await nextTick();
|
|
895
|
-
reactiveObject.prop = false;
|
|
896
|
-
await nextTick();
|
|
897
|
-
// resolved
|
|
898
|
-
const awaitNot2 = new AwaitNot({
|
|
899
|
-
obj: reactiveObject,
|
|
900
|
-
prop: "prop",
|
|
901
|
-
couldAlreadyBeFalse: true, // default
|
|
902
|
-
timeout: 500,
|
|
903
|
-
});
|
|
904
|
-
awaitNot2.promise
|
|
905
|
-
.then(() => {
|
|
906
|
-
console.log("resolved");
|
|
907
|
-
})
|
|
908
|
-
.catch(() => {
|
|
909
|
-
console.log("rejected");
|
|
910
|
-
});
|
|
911
|
-
awaitNot2.start();
|
|
912
|
-
await awaitNot2.promise;
|
|
913
|
-
// rejected
|
|
914
|
-
const awaitNot3 = new AwaitNot({
|
|
915
|
-
obj: reactiveObject,
|
|
916
|
-
prop: "prop",
|
|
917
|
-
couldAlreadyBeFalse: false,
|
|
918
|
-
timeout: 1000, // default
|
|
919
|
-
});
|
|
920
|
-
awaitNot3.promise
|
|
921
|
-
.then(() => {
|
|
922
|
-
console.log("resolved");
|
|
923
|
-
})
|
|
924
|
-
.catch(() => {
|
|
925
|
-
console.log("rejected");
|
|
926
|
-
});
|
|
927
|
-
awaitNot3.start();
|
|
928
|
-
await awaitNot3.promise;
|
|
929
|
-
// resolved
|
|
930
|
-
```
|
|
52
|
+
Since v21.0.0, the changelog is available in the [CHANGELOG.md](./CHANGELOG.md) file.
|
|
931
53
|
|
|
932
54
|
## Development
|
|
933
55
|
|
|
934
56
|
1. Checkout this repo:
|
|
57
|
+
|
|
935
58
|
```bash
|
|
936
59
|
$ git clone git@github.com:arrai-innovations/reactive-helpers.git
|
|
937
60
|
```
|
|
61
|
+
|
|
938
62
|
2. Install dependencies:
|
|
63
|
+
|
|
939
64
|
```bash
|
|
940
|
-
$ npm
|
|
65
|
+
$ npm install --dev
|
|
941
66
|
```
|
|
67
|
+
|
|
942
68
|
3. Run tests via vitest:
|
|
69
|
+
|
|
943
70
|
```bash
|
|
944
71
|
$ npm test
|
|
945
72
|
```
|
|
73
|
+
|
|
946
74
|
4. Run tests with coverage output:
|
|
947
75
|
|
|
948
76
|
```bash
|
|
@@ -950,6 +78,7 @@ await awaitNot3.promise;
|
|
|
950
78
|
```
|
|
951
79
|
|
|
952
80
|
5. Generate types and typedocs:
|
|
81
|
+
|
|
953
82
|
```bash
|
|
954
83
|
$ npm run docs
|
|
955
84
|
```
|