@verdant-web/react 23.0.3-next.0 → 23.0.4
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/dist/cjs/hooks.d.ts +2 -2
- package/dist/cjs/hooks.js +390 -390
- package/dist/cjs/hooks.test.d.ts +1 -1
- package/dist/cjs/hooks.test.js +51 -51
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +17 -17
- package/dist/esm/hooks.d.ts +2 -2
- package/dist/esm/hooks.js +386 -386
- package/dist/esm/hooks.test.d.ts +1 -1
- package/dist/esm/hooks.test.js +49 -49
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/tsconfig-cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
package/dist/cjs/hooks.js
CHANGED
|
@@ -1,391 +1,391 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
-
var t = {};
|
|
4
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
-
t[p] = s[p];
|
|
6
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
-
t[p[i]] = s[p[i]];
|
|
10
|
-
}
|
|
11
|
-
return t;
|
|
12
|
-
};
|
|
13
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.createHooks = void 0;
|
|
15
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
16
|
-
const store_1 = require("@verdant-web/store");
|
|
17
|
-
const react_1 = require("react");
|
|
18
|
-
const suspend_react_1 = require("suspend-react");
|
|
19
|
-
const with_selector_js_1 = require("use-sync-external-store/with-selector.js");
|
|
20
|
-
function isQueryCurrentValid(query) {
|
|
21
|
-
return !(query.status === 'initial' || query.status === 'initializing');
|
|
22
|
-
}
|
|
23
|
-
function useLiveQuery(liveQuery, disableSuspense = false) {
|
|
24
|
-
// suspend if the query doesn't have a valid result set yet.
|
|
25
|
-
if (!disableSuspense && liveQuery && !isQueryCurrentValid(liveQuery)) {
|
|
26
|
-
(0, suspend_react_1.suspend)(() => liveQuery.resolved, [liveQuery]);
|
|
27
|
-
}
|
|
28
|
-
return (0, react_1.useSyncExternalStore)((callback) => {
|
|
29
|
-
if (liveQuery) {
|
|
30
|
-
return liveQuery.subscribe('change', callback);
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
return () => { };
|
|
34
|
-
}
|
|
35
|
-
}, () => {
|
|
36
|
-
return liveQuery ? liveQuery.current : null;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function useLiveQueryStatus(liveQuery) {
|
|
40
|
-
return (0, react_1.useSyncExternalStore)((callback) => {
|
|
41
|
-
if (liveQuery) {
|
|
42
|
-
return liveQuery.subscribe('statusChange', callback);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
return () => { };
|
|
46
|
-
}
|
|
47
|
-
}, () => {
|
|
48
|
-
var _a;
|
|
49
|
-
return (_a = liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.status) !== null && _a !== void 0 ? _a : 'initial';
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
function capitalize(str) {
|
|
53
|
-
return (str.charAt(0).toUpperCase() + str.slice(1));
|
|
54
|
-
}
|
|
55
|
-
function createHooks(schema) {
|
|
56
|
-
const Context = (0, react_1.createContext)(null);
|
|
57
|
-
function useStorage() {
|
|
58
|
-
const ctx = (0, react_1.useContext)(Context);
|
|
59
|
-
if (!ctx) {
|
|
60
|
-
throw new Error('No verdant provider was found');
|
|
61
|
-
}
|
|
62
|
-
return (0, suspend_react_1.suspend)(() => ctx.readyPromise, ['lofi_' + ctx.namespace]);
|
|
63
|
-
}
|
|
64
|
-
function useWatch(liveObject, prop) {
|
|
65
|
-
return (0, react_1.useSyncExternalStore)((handler) => {
|
|
66
|
-
if (liveObject) {
|
|
67
|
-
return liveObject.subscribe('change', handler);
|
|
68
|
-
}
|
|
69
|
-
return () => { };
|
|
70
|
-
}, () => {
|
|
71
|
-
if (liveObject) {
|
|
72
|
-
if (liveObject instanceof store_1.EntityFile) {
|
|
73
|
-
return liveObject.url;
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
if (prop) {
|
|
77
|
-
return liveObject.get(prop);
|
|
78
|
-
}
|
|
79
|
-
return liveObject.getAll();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return undefined;
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
function useSelf() {
|
|
86
|
-
const storage = useStorage();
|
|
87
|
-
return (0, react_1.useSyncExternalStore)((callback) => storage.sync.presence.subscribe('selfChanged', callback), () => storage.sync.presence.self);
|
|
88
|
-
}
|
|
89
|
-
function usePeerIds() {
|
|
90
|
-
const storage = useStorage();
|
|
91
|
-
return (0, react_1.useSyncExternalStore)((callback) => storage.sync.presence.subscribe('peersChanged', callback), () => storage.sync.presence.peerIds);
|
|
92
|
-
}
|
|
93
|
-
function usePeer(peerId) {
|
|
94
|
-
const storage = useStorage();
|
|
95
|
-
return (0, react_1.useSyncExternalStore)((callback) => {
|
|
96
|
-
const unsubs = [];
|
|
97
|
-
unsubs.push(storage.sync.presence.subscribe('peerChanged', (id, user) => {
|
|
98
|
-
if (id === peerId) {
|
|
99
|
-
callback();
|
|
100
|
-
}
|
|
101
|
-
}));
|
|
102
|
-
unsubs.push(storage.sync.presence.subscribe('peerLeft', (id) => {
|
|
103
|
-
if (id === peerId) {
|
|
104
|
-
callback();
|
|
105
|
-
}
|
|
106
|
-
}));
|
|
107
|
-
return () => {
|
|
108
|
-
unsubs.forEach((unsub) => unsub());
|
|
109
|
-
};
|
|
110
|
-
}, () => { var _a; return (peerId ? (_a = storage.sync.presence.peers[peerId]) !== null && _a !== void 0 ? _a : null : null); });
|
|
111
|
-
}
|
|
112
|
-
function useFindPeer(query, options) {
|
|
113
|
-
const storage = useStorage();
|
|
114
|
-
return (0, react_1.useSyncExternalStore)((callback) => {
|
|
115
|
-
const unsubs = [];
|
|
116
|
-
unsubs.push(storage.sync.presence.subscribe('peerChanged', (id, user) => {
|
|
117
|
-
if (query(user)) {
|
|
118
|
-
callback();
|
|
119
|
-
}
|
|
120
|
-
}));
|
|
121
|
-
unsubs.push(storage.sync.presence.subscribe('peerLeft', (id) => {
|
|
122
|
-
if (query(storage.sync.presence.peers[id])) {
|
|
123
|
-
callback();
|
|
124
|
-
}
|
|
125
|
-
}));
|
|
126
|
-
if (options === null || options === void 0 ? void 0 : options.includeSelf) {
|
|
127
|
-
unsubs.push(storage.sync.presence.subscribe('selfChanged', (user) => {
|
|
128
|
-
if (query(user)) {
|
|
129
|
-
callback();
|
|
130
|
-
}
|
|
131
|
-
}));
|
|
132
|
-
}
|
|
133
|
-
return () => {
|
|
134
|
-
unsubs.forEach((unsub) => unsub());
|
|
135
|
-
};
|
|
136
|
-
}, () => {
|
|
137
|
-
const peers = Object.values(storage.sync.presence.peers);
|
|
138
|
-
if (options === null || options === void 0 ? void 0 : options.includeSelf) {
|
|
139
|
-
peers.push(storage.sync.presence.self);
|
|
140
|
-
}
|
|
141
|
-
return peers.find(query) || null;
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
function useFindPeers(query, options) {
|
|
145
|
-
const storage = useStorage();
|
|
146
|
-
return (0, with_selector_js_1.useSyncExternalStoreWithSelector)((callback) => {
|
|
147
|
-
const unsubs = [];
|
|
148
|
-
unsubs.push(storage.sync.presence.subscribe('peerChanged', (id, user) => {
|
|
149
|
-
if (user && query(user)) {
|
|
150
|
-
callback();
|
|
151
|
-
}
|
|
152
|
-
}));
|
|
153
|
-
unsubs.push(storage.sync.presence.subscribe('peerLeft', (id) => {
|
|
154
|
-
callback();
|
|
155
|
-
}));
|
|
156
|
-
if (options === null || options === void 0 ? void 0 : options.includeSelf) {
|
|
157
|
-
unsubs.push(storage.sync.presence.subscribe('selfChanged', (user) => {
|
|
158
|
-
if (query(user)) {
|
|
159
|
-
callback();
|
|
160
|
-
}
|
|
161
|
-
}));
|
|
162
|
-
}
|
|
163
|
-
return () => {
|
|
164
|
-
unsubs.forEach((unsub) => unsub());
|
|
165
|
-
};
|
|
166
|
-
}, () => {
|
|
167
|
-
const peers = Object.values(storage.sync.presence.peers).filter(Boolean);
|
|
168
|
-
if (options === null || options === void 0 ? void 0 : options.includeSelf) {
|
|
169
|
-
peers.push(storage.sync.presence.self);
|
|
170
|
-
}
|
|
171
|
-
return peers.filter((p) => !!p).filter(query);
|
|
172
|
-
}, () => [], (peers) => peers, (a, b) => a.length === b.length && a.every((peer, i) => peer === b[i]));
|
|
173
|
-
}
|
|
174
|
-
function useSyncStatus() {
|
|
175
|
-
const storage = useStorage();
|
|
176
|
-
return (0, react_1.useSyncExternalStore)((callback) => storage.sync.subscribe('onlineChange', callback), () => storage.sync.isConnected);
|
|
177
|
-
}
|
|
178
|
-
function useUndo() {
|
|
179
|
-
const storage = useStorage();
|
|
180
|
-
return (0, react_1.useCallback)(() => storage.undoHistory.undo(), [storage]);
|
|
181
|
-
}
|
|
182
|
-
function useRedo() {
|
|
183
|
-
const storage = useStorage();
|
|
184
|
-
return (0, react_1.useCallback)(() => storage.undoHistory.redo(), [storage]);
|
|
185
|
-
}
|
|
186
|
-
function useCanUndo() {
|
|
187
|
-
const storage = useStorage();
|
|
188
|
-
return (0, react_1.useSyncExternalStore)((callback) => storage.undoHistory.subscribe('change', callback), () => storage.undoHistory.canUndo);
|
|
189
|
-
}
|
|
190
|
-
function useCanRedo() {
|
|
191
|
-
const storage = useStorage();
|
|
192
|
-
return (0, react_1.useSyncExternalStore)((callback) => storage.undoHistory.subscribe('change', callback), () => storage.undoHistory.canRedo);
|
|
193
|
-
}
|
|
194
|
-
function useUnsuspendedClient() {
|
|
195
|
-
const desc = (0, react_1.useContext)(Context);
|
|
196
|
-
const client = desc === null || desc === void 0 ? void 0 : desc.current;
|
|
197
|
-
const [_, forceUpdate] = (0, react_1.useState)(0);
|
|
198
|
-
(0, react_1.useEffect)(() => {
|
|
199
|
-
if (desc && !client) {
|
|
200
|
-
desc.readyPromise.then(() => forceUpdate((n) => n + 1));
|
|
201
|
-
}
|
|
202
|
-
}, [desc, client]);
|
|
203
|
-
return client || null;
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Non-suspending hook which allows declarative sync start/stop
|
|
207
|
-
* control.
|
|
208
|
-
*
|
|
209
|
-
* You can optionally configure parameters as part of this as well.
|
|
210
|
-
*/
|
|
211
|
-
function useSync(isOn, config = {}) {
|
|
212
|
-
const client = useUnsuspendedClient();
|
|
213
|
-
(0, react_1.useEffect)(() => {
|
|
214
|
-
if (client) {
|
|
215
|
-
if (isOn) {
|
|
216
|
-
client.sync.start();
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
client.sync.stop();
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}, [client, isOn]);
|
|
223
|
-
(0, react_1.useEffect)(() => {
|
|
224
|
-
if (client) {
|
|
225
|
-
if (config.mode !== undefined) {
|
|
226
|
-
client.sync.setMode(config.mode);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}, [client, config.mode]);
|
|
230
|
-
(0, react_1.useEffect)(() => {
|
|
231
|
-
if (client) {
|
|
232
|
-
if (config.pullInterval !== undefined) {
|
|
233
|
-
client.sync.setPullInterval(config.pullInterval);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}, [client, config.pullInterval]);
|
|
237
|
-
}
|
|
238
|
-
function SyncController({ isOn }) {
|
|
239
|
-
useSync(isOn);
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
const hooks = {
|
|
243
|
-
useStorage,
|
|
244
|
-
useClient: useStorage,
|
|
245
|
-
useUnsuspendedClient,
|
|
246
|
-
useWatch,
|
|
247
|
-
useSelf,
|
|
248
|
-
usePeerIds,
|
|
249
|
-
usePeer,
|
|
250
|
-
useFindPeer,
|
|
251
|
-
useFindPeers,
|
|
252
|
-
useSyncStatus,
|
|
253
|
-
useUndo,
|
|
254
|
-
useRedo,
|
|
255
|
-
useCanUndo,
|
|
256
|
-
useCanRedo,
|
|
257
|
-
useSync,
|
|
258
|
-
Context,
|
|
259
|
-
Provider: (_a) => {
|
|
260
|
-
var { value, children, sync } = _a, rest = __rest(_a, ["value", "children", "sync"]);
|
|
261
|
-
// auto-open storage when used in provider
|
|
262
|
-
(0, react_1.useMemo)(() => {
|
|
263
|
-
value.open();
|
|
264
|
-
}, [value]);
|
|
265
|
-
return ((0, jsx_runtime_1.jsxs)(Context.Provider, Object.assign({ value: value }, rest, { children: [children, sync !== undefined && (0, jsx_runtime_1.jsx)(SyncController, { isOn: sync })] })));
|
|
266
|
-
},
|
|
267
|
-
};
|
|
268
|
-
const collectionNames = Object.keys(schema.collections);
|
|
269
|
-
for (const pluralName of collectionNames) {
|
|
270
|
-
const collection = schema.collections[pluralName];
|
|
271
|
-
const getOneHookName = `use${capitalize(collection.name)}`;
|
|
272
|
-
hooks[getOneHookName] = function useIndividual(id, { skip } = {}) {
|
|
273
|
-
const storage = useStorage();
|
|
274
|
-
const liveQuery = (0, react_1.useMemo)(() => {
|
|
275
|
-
return skip ? null : storage[pluralName].get(id);
|
|
276
|
-
}, [id, skip]);
|
|
277
|
-
const data = useLiveQuery(liveQuery);
|
|
278
|
-
return data;
|
|
279
|
-
};
|
|
280
|
-
hooks[getOneHookName + 'Unsuspended'] = function useIndividualUnsuspended(id, { skip } = {}) {
|
|
281
|
-
const storage = useStorage();
|
|
282
|
-
const liveQuery = (0, react_1.useMemo)(() => {
|
|
283
|
-
return skip ? null : storage[pluralName].get(id);
|
|
284
|
-
}, [id, skip]);
|
|
285
|
-
const data = useLiveQuery(liveQuery, true);
|
|
286
|
-
const status = useLiveQueryStatus(liveQuery);
|
|
287
|
-
return { data, status };
|
|
288
|
-
};
|
|
289
|
-
const findOneHookName = `useOne${capitalize(collection.name)}`;
|
|
290
|
-
hooks[findOneHookName] = function useOne({ skip, index, key, } = {}) {
|
|
291
|
-
const storage = useStorage();
|
|
292
|
-
const liveQuery = (0, react_1.useMemo)(() => {
|
|
293
|
-
return skip ? null : storage[pluralName].findOne({ index, key });
|
|
294
|
-
}, [index, skip]);
|
|
295
|
-
const data = useLiveQuery(liveQuery);
|
|
296
|
-
return data;
|
|
297
|
-
};
|
|
298
|
-
hooks[findOneHookName + 'Unsuspended'] = function useOneUnsuspended({ skip, index, key, } = {}) {
|
|
299
|
-
const storage = useStorage();
|
|
300
|
-
const liveQuery = (0, react_1.useMemo)(() => {
|
|
301
|
-
return skip ? null : storage[pluralName].findOne({ index, key });
|
|
302
|
-
}, [index, skip]);
|
|
303
|
-
const data = useLiveQuery(liveQuery, true);
|
|
304
|
-
const status = useLiveQueryStatus(liveQuery);
|
|
305
|
-
return { data, status };
|
|
306
|
-
};
|
|
307
|
-
const getAllHookName = `useAll${capitalize(pluralName)}`;
|
|
308
|
-
hooks[getAllHookName] = function useAll({ index, skip, key, } = {}) {
|
|
309
|
-
const storage = useStorage();
|
|
310
|
-
// assumptions: this query getter is fast and returns the same
|
|
311
|
-
// query identity for subsequent calls.
|
|
312
|
-
const liveQuery = (0, react_1.useMemo)(() => (skip ? null : storage[pluralName].findAll({ index, key })), [index, skip]);
|
|
313
|
-
const data = useLiveQuery(liveQuery);
|
|
314
|
-
return data || [];
|
|
315
|
-
};
|
|
316
|
-
hooks[getAllHookName + 'Unsuspended'] = function useAllUnsuspended({ index, skip, key, } = {}) {
|
|
317
|
-
const storage = useStorage();
|
|
318
|
-
// assumptions: this query getter is fast and returns the same
|
|
319
|
-
// query identity for subsequent calls.
|
|
320
|
-
const liveQuery = (0, react_1.useMemo)(() => (skip ? null : storage[pluralName].findAll({ index, key })), [index, skip]);
|
|
321
|
-
const data = useLiveQuery(liveQuery, true) || [];
|
|
322
|
-
const status = useLiveQueryStatus(liveQuery);
|
|
323
|
-
return { data, status };
|
|
324
|
-
};
|
|
325
|
-
const getAllPaginatedHookName = `useAll${capitalize(pluralName)}Paginated`;
|
|
326
|
-
hooks[getAllPaginatedHookName] = function useAllPaginated({ index, skip, pageSize = 10, key, suspend, } = {}) {
|
|
327
|
-
const storage = useStorage();
|
|
328
|
-
// assumptions: this query getter is fast and returns the same
|
|
329
|
-
// query identity for subsequent calls.
|
|
330
|
-
const liveQuery = (0, react_1.useMemo)(() => skip
|
|
331
|
-
? null
|
|
332
|
-
: storage[pluralName].findPage({
|
|
333
|
-
index,
|
|
334
|
-
pageSize,
|
|
335
|
-
page: 0,
|
|
336
|
-
key: key || getAllPaginatedHookName,
|
|
337
|
-
}), [index, skip, pageSize]);
|
|
338
|
-
const data = useLiveQuery(liveQuery, suspend === false);
|
|
339
|
-
const status = useLiveQueryStatus(liveQuery);
|
|
340
|
-
const tools = (0, react_1.useMemo)(() => ({
|
|
341
|
-
next: () => liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.nextPage(),
|
|
342
|
-
previous: () => liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.previousPage(),
|
|
343
|
-
setPage: (page) => liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.setPage(page),
|
|
344
|
-
get hasPrevious() {
|
|
345
|
-
return liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.hasPreviousPage;
|
|
346
|
-
},
|
|
347
|
-
get hasNext() {
|
|
348
|
-
return liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.hasNextPage;
|
|
349
|
-
},
|
|
350
|
-
status,
|
|
351
|
-
}), [liveQuery, status]);
|
|
352
|
-
return [data, tools];
|
|
353
|
-
};
|
|
354
|
-
const getAllInfiniteHookName = `useAll${capitalize(pluralName)}Infinite`;
|
|
355
|
-
hooks[getAllInfiniteHookName] = function useAllInfinite({ index, skip, pageSize = 10, key, suspend, } = {}) {
|
|
356
|
-
const storage = useStorage();
|
|
357
|
-
// assumptions: this query getter is fast and returns the same
|
|
358
|
-
// query identity for subsequent calls.
|
|
359
|
-
const liveQuery = (0, react_1.useMemo)(() => skip
|
|
360
|
-
? null
|
|
361
|
-
: storage[pluralName].findAllInfinite({
|
|
362
|
-
index,
|
|
363
|
-
pageSize,
|
|
364
|
-
key: key || getAllInfiniteHookName,
|
|
365
|
-
}), [index, skip, pageSize]);
|
|
366
|
-
const data = useLiveQuery(liveQuery, suspend === false);
|
|
367
|
-
const status = useLiveQueryStatus(liveQuery);
|
|
368
|
-
const tools = (0, react_1.useMemo)(() => ({
|
|
369
|
-
loadMore: () => liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.loadMore(),
|
|
370
|
-
get hasMore() {
|
|
371
|
-
return liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.hasMore;
|
|
372
|
-
},
|
|
373
|
-
status,
|
|
374
|
-
}), [liveQuery, status]);
|
|
375
|
-
return [data, tools];
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
hooks.withMutations = (mutations) => {
|
|
379
|
-
const augmentedHooks = Object.assign({}, hooks);
|
|
380
|
-
for (const [name, subHook] of Object.entries(mutations)) {
|
|
381
|
-
augmentedHooks[name] = (...args) => {
|
|
382
|
-
const client = hooks.useClient();
|
|
383
|
-
return subHook(client, ...args);
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
return augmentedHooks;
|
|
387
|
-
};
|
|
388
|
-
return hooks;
|
|
389
|
-
}
|
|
390
|
-
exports.createHooks = createHooks;
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.createHooks = void 0;
|
|
15
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
16
|
+
const store_1 = require("@verdant-web/store");
|
|
17
|
+
const react_1 = require("react");
|
|
18
|
+
const suspend_react_1 = require("suspend-react");
|
|
19
|
+
const with_selector_js_1 = require("use-sync-external-store/with-selector.js");
|
|
20
|
+
function isQueryCurrentValid(query) {
|
|
21
|
+
return !(query.status === 'initial' || query.status === 'initializing');
|
|
22
|
+
}
|
|
23
|
+
function useLiveQuery(liveQuery, disableSuspense = false) {
|
|
24
|
+
// suspend if the query doesn't have a valid result set yet.
|
|
25
|
+
if (!disableSuspense && liveQuery && !isQueryCurrentValid(liveQuery)) {
|
|
26
|
+
(0, suspend_react_1.suspend)(() => liveQuery.resolved, [liveQuery]);
|
|
27
|
+
}
|
|
28
|
+
return (0, react_1.useSyncExternalStore)((callback) => {
|
|
29
|
+
if (liveQuery) {
|
|
30
|
+
return liveQuery.subscribe('change', callback);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return () => { };
|
|
34
|
+
}
|
|
35
|
+
}, () => {
|
|
36
|
+
return liveQuery ? liveQuery.current : null;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function useLiveQueryStatus(liveQuery) {
|
|
40
|
+
return (0, react_1.useSyncExternalStore)((callback) => {
|
|
41
|
+
if (liveQuery) {
|
|
42
|
+
return liveQuery.subscribe('statusChange', callback);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
return () => { };
|
|
46
|
+
}
|
|
47
|
+
}, () => {
|
|
48
|
+
var _a;
|
|
49
|
+
return (_a = liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.status) !== null && _a !== void 0 ? _a : 'initial';
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function capitalize(str) {
|
|
53
|
+
return (str.charAt(0).toUpperCase() + str.slice(1));
|
|
54
|
+
}
|
|
55
|
+
function createHooks(schema) {
|
|
56
|
+
const Context = (0, react_1.createContext)(null);
|
|
57
|
+
function useStorage() {
|
|
58
|
+
const ctx = (0, react_1.useContext)(Context);
|
|
59
|
+
if (!ctx) {
|
|
60
|
+
throw new Error('No verdant provider was found');
|
|
61
|
+
}
|
|
62
|
+
return (0, suspend_react_1.suspend)(() => ctx.readyPromise, ['lofi_' + ctx.namespace]);
|
|
63
|
+
}
|
|
64
|
+
function useWatch(liveObject, prop) {
|
|
65
|
+
return (0, react_1.useSyncExternalStore)((handler) => {
|
|
66
|
+
if (liveObject) {
|
|
67
|
+
return liveObject.subscribe('change', handler);
|
|
68
|
+
}
|
|
69
|
+
return () => { };
|
|
70
|
+
}, () => {
|
|
71
|
+
if (liveObject) {
|
|
72
|
+
if (liveObject instanceof store_1.EntityFile) {
|
|
73
|
+
return liveObject.url;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
if (prop) {
|
|
77
|
+
return liveObject.get(prop);
|
|
78
|
+
}
|
|
79
|
+
return liveObject.getAll();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function useSelf() {
|
|
86
|
+
const storage = useStorage();
|
|
87
|
+
return (0, react_1.useSyncExternalStore)((callback) => storage.sync.presence.subscribe('selfChanged', callback), () => storage.sync.presence.self);
|
|
88
|
+
}
|
|
89
|
+
function usePeerIds() {
|
|
90
|
+
const storage = useStorage();
|
|
91
|
+
return (0, react_1.useSyncExternalStore)((callback) => storage.sync.presence.subscribe('peersChanged', callback), () => storage.sync.presence.peerIds);
|
|
92
|
+
}
|
|
93
|
+
function usePeer(peerId) {
|
|
94
|
+
const storage = useStorage();
|
|
95
|
+
return (0, react_1.useSyncExternalStore)((callback) => {
|
|
96
|
+
const unsubs = [];
|
|
97
|
+
unsubs.push(storage.sync.presence.subscribe('peerChanged', (id, user) => {
|
|
98
|
+
if (id === peerId) {
|
|
99
|
+
callback();
|
|
100
|
+
}
|
|
101
|
+
}));
|
|
102
|
+
unsubs.push(storage.sync.presence.subscribe('peerLeft', (id) => {
|
|
103
|
+
if (id === peerId) {
|
|
104
|
+
callback();
|
|
105
|
+
}
|
|
106
|
+
}));
|
|
107
|
+
return () => {
|
|
108
|
+
unsubs.forEach((unsub) => unsub());
|
|
109
|
+
};
|
|
110
|
+
}, () => { var _a; return (peerId ? (_a = storage.sync.presence.peers[peerId]) !== null && _a !== void 0 ? _a : null : null); });
|
|
111
|
+
}
|
|
112
|
+
function useFindPeer(query, options) {
|
|
113
|
+
const storage = useStorage();
|
|
114
|
+
return (0, react_1.useSyncExternalStore)((callback) => {
|
|
115
|
+
const unsubs = [];
|
|
116
|
+
unsubs.push(storage.sync.presence.subscribe('peerChanged', (id, user) => {
|
|
117
|
+
if (query(user)) {
|
|
118
|
+
callback();
|
|
119
|
+
}
|
|
120
|
+
}));
|
|
121
|
+
unsubs.push(storage.sync.presence.subscribe('peerLeft', (id) => {
|
|
122
|
+
if (query(storage.sync.presence.peers[id])) {
|
|
123
|
+
callback();
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
if (options === null || options === void 0 ? void 0 : options.includeSelf) {
|
|
127
|
+
unsubs.push(storage.sync.presence.subscribe('selfChanged', (user) => {
|
|
128
|
+
if (query(user)) {
|
|
129
|
+
callback();
|
|
130
|
+
}
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
return () => {
|
|
134
|
+
unsubs.forEach((unsub) => unsub());
|
|
135
|
+
};
|
|
136
|
+
}, () => {
|
|
137
|
+
const peers = Object.values(storage.sync.presence.peers);
|
|
138
|
+
if (options === null || options === void 0 ? void 0 : options.includeSelf) {
|
|
139
|
+
peers.push(storage.sync.presence.self);
|
|
140
|
+
}
|
|
141
|
+
return peers.find(query) || null;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function useFindPeers(query, options) {
|
|
145
|
+
const storage = useStorage();
|
|
146
|
+
return (0, with_selector_js_1.useSyncExternalStoreWithSelector)((callback) => {
|
|
147
|
+
const unsubs = [];
|
|
148
|
+
unsubs.push(storage.sync.presence.subscribe('peerChanged', (id, user) => {
|
|
149
|
+
if (user && query(user)) {
|
|
150
|
+
callback();
|
|
151
|
+
}
|
|
152
|
+
}));
|
|
153
|
+
unsubs.push(storage.sync.presence.subscribe('peerLeft', (id) => {
|
|
154
|
+
callback();
|
|
155
|
+
}));
|
|
156
|
+
if (options === null || options === void 0 ? void 0 : options.includeSelf) {
|
|
157
|
+
unsubs.push(storage.sync.presence.subscribe('selfChanged', (user) => {
|
|
158
|
+
if (query(user)) {
|
|
159
|
+
callback();
|
|
160
|
+
}
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
return () => {
|
|
164
|
+
unsubs.forEach((unsub) => unsub());
|
|
165
|
+
};
|
|
166
|
+
}, () => {
|
|
167
|
+
const peers = Object.values(storage.sync.presence.peers).filter(Boolean);
|
|
168
|
+
if (options === null || options === void 0 ? void 0 : options.includeSelf) {
|
|
169
|
+
peers.push(storage.sync.presence.self);
|
|
170
|
+
}
|
|
171
|
+
return peers.filter((p) => !!p).filter(query);
|
|
172
|
+
}, () => [], (peers) => peers, (a, b) => a.length === b.length && a.every((peer, i) => peer === b[i]));
|
|
173
|
+
}
|
|
174
|
+
function useSyncStatus() {
|
|
175
|
+
const storage = useStorage();
|
|
176
|
+
return (0, react_1.useSyncExternalStore)((callback) => storage.sync.subscribe('onlineChange', callback), () => storage.sync.isConnected);
|
|
177
|
+
}
|
|
178
|
+
function useUndo() {
|
|
179
|
+
const storage = useStorage();
|
|
180
|
+
return (0, react_1.useCallback)(() => storage.undoHistory.undo(), [storage]);
|
|
181
|
+
}
|
|
182
|
+
function useRedo() {
|
|
183
|
+
const storage = useStorage();
|
|
184
|
+
return (0, react_1.useCallback)(() => storage.undoHistory.redo(), [storage]);
|
|
185
|
+
}
|
|
186
|
+
function useCanUndo() {
|
|
187
|
+
const storage = useStorage();
|
|
188
|
+
return (0, react_1.useSyncExternalStore)((callback) => storage.undoHistory.subscribe('change', callback), () => storage.undoHistory.canUndo);
|
|
189
|
+
}
|
|
190
|
+
function useCanRedo() {
|
|
191
|
+
const storage = useStorage();
|
|
192
|
+
return (0, react_1.useSyncExternalStore)((callback) => storage.undoHistory.subscribe('change', callback), () => storage.undoHistory.canRedo);
|
|
193
|
+
}
|
|
194
|
+
function useUnsuspendedClient() {
|
|
195
|
+
const desc = (0, react_1.useContext)(Context);
|
|
196
|
+
const client = desc === null || desc === void 0 ? void 0 : desc.current;
|
|
197
|
+
const [_, forceUpdate] = (0, react_1.useState)(0);
|
|
198
|
+
(0, react_1.useEffect)(() => {
|
|
199
|
+
if (desc && !client) {
|
|
200
|
+
desc.readyPromise.then(() => forceUpdate((n) => n + 1));
|
|
201
|
+
}
|
|
202
|
+
}, [desc, client]);
|
|
203
|
+
return client || null;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Non-suspending hook which allows declarative sync start/stop
|
|
207
|
+
* control.
|
|
208
|
+
*
|
|
209
|
+
* You can optionally configure parameters as part of this as well.
|
|
210
|
+
*/
|
|
211
|
+
function useSync(isOn, config = {}) {
|
|
212
|
+
const client = useUnsuspendedClient();
|
|
213
|
+
(0, react_1.useEffect)(() => {
|
|
214
|
+
if (client) {
|
|
215
|
+
if (isOn) {
|
|
216
|
+
client.sync.start();
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
client.sync.stop();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}, [client, isOn]);
|
|
223
|
+
(0, react_1.useEffect)(() => {
|
|
224
|
+
if (client) {
|
|
225
|
+
if (config.mode !== undefined) {
|
|
226
|
+
client.sync.setMode(config.mode);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}, [client, config.mode]);
|
|
230
|
+
(0, react_1.useEffect)(() => {
|
|
231
|
+
if (client) {
|
|
232
|
+
if (config.pullInterval !== undefined) {
|
|
233
|
+
client.sync.setPullInterval(config.pullInterval);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}, [client, config.pullInterval]);
|
|
237
|
+
}
|
|
238
|
+
function SyncController({ isOn }) {
|
|
239
|
+
useSync(isOn);
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
const hooks = {
|
|
243
|
+
useStorage,
|
|
244
|
+
useClient: useStorage,
|
|
245
|
+
useUnsuspendedClient,
|
|
246
|
+
useWatch,
|
|
247
|
+
useSelf,
|
|
248
|
+
usePeerIds,
|
|
249
|
+
usePeer,
|
|
250
|
+
useFindPeer,
|
|
251
|
+
useFindPeers,
|
|
252
|
+
useSyncStatus,
|
|
253
|
+
useUndo,
|
|
254
|
+
useRedo,
|
|
255
|
+
useCanUndo,
|
|
256
|
+
useCanRedo,
|
|
257
|
+
useSync,
|
|
258
|
+
Context,
|
|
259
|
+
Provider: (_a) => {
|
|
260
|
+
var { value, children, sync } = _a, rest = __rest(_a, ["value", "children", "sync"]);
|
|
261
|
+
// auto-open storage when used in provider
|
|
262
|
+
(0, react_1.useMemo)(() => {
|
|
263
|
+
value.open();
|
|
264
|
+
}, [value]);
|
|
265
|
+
return ((0, jsx_runtime_1.jsxs)(Context.Provider, Object.assign({ value: value }, rest, { children: [children, sync !== undefined && (0, jsx_runtime_1.jsx)(SyncController, { isOn: sync })] })));
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
const collectionNames = Object.keys(schema.collections);
|
|
269
|
+
for (const pluralName of collectionNames) {
|
|
270
|
+
const collection = schema.collections[pluralName];
|
|
271
|
+
const getOneHookName = `use${capitalize(collection.name)}`;
|
|
272
|
+
hooks[getOneHookName] = function useIndividual(id, { skip } = {}) {
|
|
273
|
+
const storage = useStorage();
|
|
274
|
+
const liveQuery = (0, react_1.useMemo)(() => {
|
|
275
|
+
return skip ? null : storage[pluralName].get(id);
|
|
276
|
+
}, [id, skip]);
|
|
277
|
+
const data = useLiveQuery(liveQuery);
|
|
278
|
+
return data;
|
|
279
|
+
};
|
|
280
|
+
hooks[getOneHookName + 'Unsuspended'] = function useIndividualUnsuspended(id, { skip } = {}) {
|
|
281
|
+
const storage = useStorage();
|
|
282
|
+
const liveQuery = (0, react_1.useMemo)(() => {
|
|
283
|
+
return skip ? null : storage[pluralName].get(id);
|
|
284
|
+
}, [id, skip]);
|
|
285
|
+
const data = useLiveQuery(liveQuery, true);
|
|
286
|
+
const status = useLiveQueryStatus(liveQuery);
|
|
287
|
+
return { data, status };
|
|
288
|
+
};
|
|
289
|
+
const findOneHookName = `useOne${capitalize(collection.name)}`;
|
|
290
|
+
hooks[findOneHookName] = function useOne({ skip, index, key, } = {}) {
|
|
291
|
+
const storage = useStorage();
|
|
292
|
+
const liveQuery = (0, react_1.useMemo)(() => {
|
|
293
|
+
return skip ? null : storage[pluralName].findOne({ index, key });
|
|
294
|
+
}, [index, skip]);
|
|
295
|
+
const data = useLiveQuery(liveQuery);
|
|
296
|
+
return data;
|
|
297
|
+
};
|
|
298
|
+
hooks[findOneHookName + 'Unsuspended'] = function useOneUnsuspended({ skip, index, key, } = {}) {
|
|
299
|
+
const storage = useStorage();
|
|
300
|
+
const liveQuery = (0, react_1.useMemo)(() => {
|
|
301
|
+
return skip ? null : storage[pluralName].findOne({ index, key });
|
|
302
|
+
}, [index, skip]);
|
|
303
|
+
const data = useLiveQuery(liveQuery, true);
|
|
304
|
+
const status = useLiveQueryStatus(liveQuery);
|
|
305
|
+
return { data, status };
|
|
306
|
+
};
|
|
307
|
+
const getAllHookName = `useAll${capitalize(pluralName)}`;
|
|
308
|
+
hooks[getAllHookName] = function useAll({ index, skip, key, } = {}) {
|
|
309
|
+
const storage = useStorage();
|
|
310
|
+
// assumptions: this query getter is fast and returns the same
|
|
311
|
+
// query identity for subsequent calls.
|
|
312
|
+
const liveQuery = (0, react_1.useMemo)(() => (skip ? null : storage[pluralName].findAll({ index, key })), [index, skip]);
|
|
313
|
+
const data = useLiveQuery(liveQuery);
|
|
314
|
+
return data || [];
|
|
315
|
+
};
|
|
316
|
+
hooks[getAllHookName + 'Unsuspended'] = function useAllUnsuspended({ index, skip, key, } = {}) {
|
|
317
|
+
const storage = useStorage();
|
|
318
|
+
// assumptions: this query getter is fast and returns the same
|
|
319
|
+
// query identity for subsequent calls.
|
|
320
|
+
const liveQuery = (0, react_1.useMemo)(() => (skip ? null : storage[pluralName].findAll({ index, key })), [index, skip]);
|
|
321
|
+
const data = useLiveQuery(liveQuery, true) || [];
|
|
322
|
+
const status = useLiveQueryStatus(liveQuery);
|
|
323
|
+
return { data, status };
|
|
324
|
+
};
|
|
325
|
+
const getAllPaginatedHookName = `useAll${capitalize(pluralName)}Paginated`;
|
|
326
|
+
hooks[getAllPaginatedHookName] = function useAllPaginated({ index, skip, pageSize = 10, key, suspend, } = {}) {
|
|
327
|
+
const storage = useStorage();
|
|
328
|
+
// assumptions: this query getter is fast and returns the same
|
|
329
|
+
// query identity for subsequent calls.
|
|
330
|
+
const liveQuery = (0, react_1.useMemo)(() => skip
|
|
331
|
+
? null
|
|
332
|
+
: storage[pluralName].findPage({
|
|
333
|
+
index,
|
|
334
|
+
pageSize,
|
|
335
|
+
page: 0,
|
|
336
|
+
key: key || getAllPaginatedHookName,
|
|
337
|
+
}), [index, skip, pageSize]);
|
|
338
|
+
const data = useLiveQuery(liveQuery, suspend === false);
|
|
339
|
+
const status = useLiveQueryStatus(liveQuery);
|
|
340
|
+
const tools = (0, react_1.useMemo)(() => ({
|
|
341
|
+
next: () => liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.nextPage(),
|
|
342
|
+
previous: () => liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.previousPage(),
|
|
343
|
+
setPage: (page) => liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.setPage(page),
|
|
344
|
+
get hasPrevious() {
|
|
345
|
+
return liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.hasPreviousPage;
|
|
346
|
+
},
|
|
347
|
+
get hasNext() {
|
|
348
|
+
return liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.hasNextPage;
|
|
349
|
+
},
|
|
350
|
+
status,
|
|
351
|
+
}), [liveQuery, status]);
|
|
352
|
+
return [data, tools];
|
|
353
|
+
};
|
|
354
|
+
const getAllInfiniteHookName = `useAll${capitalize(pluralName)}Infinite`;
|
|
355
|
+
hooks[getAllInfiniteHookName] = function useAllInfinite({ index, skip, pageSize = 10, key, suspend, } = {}) {
|
|
356
|
+
const storage = useStorage();
|
|
357
|
+
// assumptions: this query getter is fast and returns the same
|
|
358
|
+
// query identity for subsequent calls.
|
|
359
|
+
const liveQuery = (0, react_1.useMemo)(() => skip
|
|
360
|
+
? null
|
|
361
|
+
: storage[pluralName].findAllInfinite({
|
|
362
|
+
index,
|
|
363
|
+
pageSize,
|
|
364
|
+
key: key || getAllInfiniteHookName,
|
|
365
|
+
}), [index, skip, pageSize]);
|
|
366
|
+
const data = useLiveQuery(liveQuery, suspend === false);
|
|
367
|
+
const status = useLiveQueryStatus(liveQuery);
|
|
368
|
+
const tools = (0, react_1.useMemo)(() => ({
|
|
369
|
+
loadMore: () => liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.loadMore(),
|
|
370
|
+
get hasMore() {
|
|
371
|
+
return liveQuery === null || liveQuery === void 0 ? void 0 : liveQuery.hasMore;
|
|
372
|
+
},
|
|
373
|
+
status,
|
|
374
|
+
}), [liveQuery, status]);
|
|
375
|
+
return [data, tools];
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
hooks.withMutations = (mutations) => {
|
|
379
|
+
const augmentedHooks = Object.assign({}, hooks);
|
|
380
|
+
for (const [name, subHook] of Object.entries(mutations)) {
|
|
381
|
+
augmentedHooks[name] = (...args) => {
|
|
382
|
+
const client = hooks.useClient();
|
|
383
|
+
return subHook(client, ...args);
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
return augmentedHooks;
|
|
387
|
+
};
|
|
388
|
+
return hooks;
|
|
389
|
+
}
|
|
390
|
+
exports.createHooks = createHooks;
|
|
391
391
|
//# sourceMappingURL=hooks.js.map
|