use-everywhere 0.7.0 → 0.9.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 +2 -2
- package/dist/{chunk-LNJEF4DI.js → chunk-R7PBPLF7.js} +83 -18
- package/dist/devtools/index.cjs +153 -9
- package/dist/devtools/index.js +140 -5
- package/dist/index.cjs +275 -73
- package/dist/index.d.cts +242 -10
- package/dist/index.d.ts +242 -10
- package/dist/index.js +164 -26
- package/package.json +23 -11
package/dist/index.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_NAME,
|
|
4
|
+
configureChannel,
|
|
4
5
|
configureStore,
|
|
5
6
|
getChannel,
|
|
6
7
|
getLeader,
|
|
8
|
+
getReducer,
|
|
7
9
|
getSharedStore,
|
|
8
10
|
getStore,
|
|
9
11
|
useClientId,
|
|
10
12
|
usePeers,
|
|
13
|
+
usePresenceMetadata,
|
|
11
14
|
warnOnInitialMismatch
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-R7PBPLF7.js";
|
|
13
16
|
|
|
14
17
|
// src/use-shared-state.ts
|
|
15
18
|
import { useCallback, useSyncExternalStore } from "react";
|
|
@@ -17,7 +20,9 @@ function useSharedState(key, initial, options) {
|
|
|
17
20
|
const storeName = options?.store ?? DEFAULT_NAME;
|
|
18
21
|
const store = getStore(storeName, options?.scope ?? "everywhere");
|
|
19
22
|
store.registerKey(key, initial);
|
|
20
|
-
|
|
23
|
+
if (process.env.NODE_ENV !== "production") {
|
|
24
|
+
warnOnInitialMismatch(storeName, key, initial);
|
|
25
|
+
}
|
|
21
26
|
const value = useSyncExternalStore(
|
|
22
27
|
useCallback((onChange) => store.subscribeKey(key, onChange), [store, key]),
|
|
23
28
|
() => store.getSnapshot()[key],
|
|
@@ -30,27 +35,98 @@ function useSharedState(key, initial, options) {
|
|
|
30
35
|
return [value, setValue];
|
|
31
36
|
}
|
|
32
37
|
|
|
38
|
+
// src/use-shared-reducer.ts
|
|
39
|
+
import { useCallback as useCallback2, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
40
|
+
function useSharedReducer(reducer, initial, options) {
|
|
41
|
+
const engine = getReducer(
|
|
42
|
+
options?.name ?? DEFAULT_NAME,
|
|
43
|
+
options?.key ?? "default",
|
|
44
|
+
reducer,
|
|
45
|
+
initial
|
|
46
|
+
);
|
|
47
|
+
const value = useSyncExternalStore2(
|
|
48
|
+
useCallback2((onChange) => engine.subscribe(onChange), [engine]),
|
|
49
|
+
() => engine.getSnapshot(),
|
|
50
|
+
() => initial
|
|
51
|
+
);
|
|
52
|
+
const dispatch = useCallback2((action) => engine.dispatch(action), [engine]);
|
|
53
|
+
return [value, dispatch];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/use-shared-selector.ts
|
|
57
|
+
import { useCallback as useCallback3, useRef, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
58
|
+
function useSharedStore(selector, options) {
|
|
59
|
+
const store = getStore(options?.store ?? DEFAULT_NAME, options?.scope ?? "everywhere");
|
|
60
|
+
const equal = options?.equal ?? Object.is;
|
|
61
|
+
const selectorRef = useRef(selector);
|
|
62
|
+
selectorRef.current = selector;
|
|
63
|
+
const equalRef = useRef(equal);
|
|
64
|
+
equalRef.current = equal;
|
|
65
|
+
const cache = useRef(null);
|
|
66
|
+
const getSelection = useCallback3(() => {
|
|
67
|
+
const source = store.getSnapshot();
|
|
68
|
+
const select = selectorRef.current;
|
|
69
|
+
const previous = cache.current;
|
|
70
|
+
if (previous && previous.source === source && previous.select === select) return previous.value;
|
|
71
|
+
const next = select(source);
|
|
72
|
+
const value = previous && equalRef.current(previous.value, next) ? previous.value : next;
|
|
73
|
+
cache.current = { source, select, value };
|
|
74
|
+
return value;
|
|
75
|
+
}, [store]);
|
|
76
|
+
return useSyncExternalStore3(
|
|
77
|
+
useCallback3((onChange) => store.subscribe(onChange), [store]),
|
|
78
|
+
getSelection,
|
|
79
|
+
getSelection
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
function shallowEqual(a, b) {
|
|
83
|
+
if (Object.is(a, b)) return true;
|
|
84
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
|
|
85
|
+
const left = a;
|
|
86
|
+
const right = b;
|
|
87
|
+
const keys = Object.keys(left);
|
|
88
|
+
if (keys.length !== Object.keys(right).length) return false;
|
|
89
|
+
return keys.every((key) => Object.is(left[key], right[key]));
|
|
90
|
+
}
|
|
91
|
+
|
|
33
92
|
// src/use-message.ts
|
|
34
|
-
import { useEffect, useRef } from "react";
|
|
93
|
+
import { useEffect, useRef as useRef2 } from "react";
|
|
35
94
|
function useChannel(name) {
|
|
36
95
|
return getChannel(name);
|
|
37
96
|
}
|
|
38
|
-
function useMessage(channel, type, handler) {
|
|
39
|
-
const handlerRef =
|
|
97
|
+
function useMessage(channel, type, handler, options) {
|
|
98
|
+
const handlerRef = useRef2(handler);
|
|
40
99
|
useEffect(() => {
|
|
41
100
|
handlerRef.current = handler;
|
|
42
101
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
102
|
+
const enabled = options?.enabled ?? true;
|
|
103
|
+
const once = options?.once ?? false;
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!enabled) return;
|
|
106
|
+
return channel.on(type, (payload, meta) => handlerRef.current(payload, meta), { once });
|
|
107
|
+
}, [channel, type, enabled, once]);
|
|
108
|
+
}
|
|
109
|
+
function useAnswer(channel, type, responder, options) {
|
|
110
|
+
const responderRef = useRef2(responder);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
responderRef.current = responder;
|
|
113
|
+
});
|
|
114
|
+
const enabled = options?.enabled ?? true;
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (!enabled) return;
|
|
117
|
+
return channel.answer(type, (payload, meta) => responderRef.current(payload, meta));
|
|
118
|
+
}, [channel, type, enabled]);
|
|
47
119
|
}
|
|
48
120
|
function useSend(channel) {
|
|
49
121
|
return channel.post;
|
|
50
122
|
}
|
|
123
|
+
function useAsk(channel) {
|
|
124
|
+
return channel.ask;
|
|
125
|
+
}
|
|
51
126
|
|
|
52
127
|
// src/define-channel.ts
|
|
53
|
-
function defineChannel(name) {
|
|
128
|
+
function defineChannel(name, options) {
|
|
129
|
+
if (options) configureChannel(name, options);
|
|
54
130
|
const useBoundSend = () => useSend(useChannel(name));
|
|
55
131
|
const useBoundMessage = (type, handler) => useMessage(useChannel(name), type, handler);
|
|
56
132
|
return {
|
|
@@ -68,7 +144,10 @@ function defineStore(name, options = {}) {
|
|
|
68
144
|
persist: {
|
|
69
145
|
adapter: options.persist,
|
|
70
146
|
...options.persistKeys ? { keys: options.persistKeys } : {},
|
|
71
|
-
...options.persistDebounceMs === void 0 ? {} : { debounceMs: options.persistDebounceMs }
|
|
147
|
+
...options.persistDebounceMs === void 0 ? {} : { debounceMs: options.persistDebounceMs },
|
|
148
|
+
...options.persistVersion === void 0 ? {} : { version: options.persistVersion },
|
|
149
|
+
...options.migrate ? { migrate: options.migrate } : {},
|
|
150
|
+
...options.onRestoreError ? { onRestoreError: options.onRestoreError } : {}
|
|
72
151
|
}
|
|
73
152
|
});
|
|
74
153
|
}
|
|
@@ -78,18 +157,35 @@ function defineStore(name, options = {}) {
|
|
|
78
157
|
};
|
|
79
158
|
}
|
|
80
159
|
|
|
160
|
+
// src/use-hydrated.ts
|
|
161
|
+
import { useEffect as useEffect2, useState } from "react";
|
|
162
|
+
function useHydrated(options) {
|
|
163
|
+
const store = getStore(options?.store ?? DEFAULT_NAME, options?.scope ?? "everywhere");
|
|
164
|
+
const [ready, setReady] = useState(false);
|
|
165
|
+
useEffect2(() => {
|
|
166
|
+
let cancelled = false;
|
|
167
|
+
void store.hydrated.then(() => {
|
|
168
|
+
if (!cancelled) setReady(true);
|
|
169
|
+
});
|
|
170
|
+
return () => {
|
|
171
|
+
cancelled = true;
|
|
172
|
+
};
|
|
173
|
+
}, [store]);
|
|
174
|
+
return ready;
|
|
175
|
+
}
|
|
176
|
+
|
|
81
177
|
// src/use-leader.ts
|
|
82
|
-
import { useCallback as
|
|
178
|
+
import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef3, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
83
179
|
var NO_LEADER = Object.freeze({ leaderId: null, isLeader: false });
|
|
84
180
|
function useLeader(options) {
|
|
85
181
|
const leader = getLeader(options?.name ?? DEFAULT_NAME, options);
|
|
86
182
|
const eligible = options?.eligible;
|
|
87
|
-
|
|
183
|
+
useEffect3(() => {
|
|
88
184
|
if (eligible === void 0) return;
|
|
89
185
|
leader.setEligible(eligible);
|
|
90
186
|
}, [leader, eligible]);
|
|
91
|
-
return
|
|
92
|
-
|
|
187
|
+
return useSyncExternalStore4(
|
|
188
|
+
useCallback4((onChange) => leader.subscribe(onChange), [leader]),
|
|
93
189
|
() => leader.getSnapshot(),
|
|
94
190
|
() => NO_LEADER
|
|
95
191
|
);
|
|
@@ -99,18 +195,42 @@ function useIsLeader(options) {
|
|
|
99
195
|
}
|
|
100
196
|
function useLeaderEffect(effect, options) {
|
|
101
197
|
const { isLeader } = useLeader(options);
|
|
102
|
-
const effectRef =
|
|
103
|
-
|
|
198
|
+
const effectRef = useRef3(effect);
|
|
199
|
+
useEffect3(() => {
|
|
104
200
|
effectRef.current = effect;
|
|
105
201
|
});
|
|
106
|
-
|
|
202
|
+
useEffect3(() => {
|
|
107
203
|
if (!isLeader) return;
|
|
108
204
|
return effectRef.current();
|
|
109
205
|
}, [isLeader]);
|
|
110
206
|
}
|
|
111
207
|
|
|
208
|
+
// src/namespace.ts
|
|
209
|
+
import {
|
|
210
|
+
createNamespace as createCoreNamespace
|
|
211
|
+
} from "@use-everywhere/core";
|
|
212
|
+
function createNamespace(namespace) {
|
|
213
|
+
const core = createCoreNamespace(namespace);
|
|
214
|
+
const { busName } = core;
|
|
215
|
+
return {
|
|
216
|
+
...core,
|
|
217
|
+
defineStore: (name, options) => defineStore(busName(name), options),
|
|
218
|
+
defineChannel: (name, options) => defineChannel(busName(name), options),
|
|
219
|
+
getSharedStore: (name, scope) => getSharedStore(busName(name), scope),
|
|
220
|
+
useSharedState: (key, initial, options) => useSharedState(key, initial, { ...options, store: busName(options?.store) }),
|
|
221
|
+
useSharedStore: (selector, options) => useSharedStore(selector, { ...options, store: busName(options?.store) }),
|
|
222
|
+
usePeers: (options) => usePeers({ ...options, name: busName(options?.name) }),
|
|
223
|
+
usePresenceMetadata: (metadata, options) => usePresenceMetadata(metadata, { ...options, name: busName(options?.name) }),
|
|
224
|
+
useHydrated: (options) => useHydrated({ ...options, store: busName(options?.store) }),
|
|
225
|
+
useClientId: (options) => useClientId({ name: busName(options?.name) }),
|
|
226
|
+
useLeader: (options) => useLeader({ ...options, name: busName(options?.name) }),
|
|
227
|
+
useIsLeader: (options) => useIsLeader({ ...options, name: busName(options?.name) }),
|
|
228
|
+
useLeaderEffect: (effect, options) => useLeaderEffect(effect, { ...options, name: busName(options?.name) })
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
112
232
|
// src/use-opened-window.ts
|
|
113
|
-
import { useCallback as
|
|
233
|
+
import { useCallback as useCallback5, useEffect as useEffect4, useRef as useRef4, useState as useState2 } from "react";
|
|
114
234
|
import { WindowClosedError } from "@use-everywhere/core";
|
|
115
235
|
var IDLE = Object.freeze({
|
|
116
236
|
status: "idle",
|
|
@@ -118,13 +238,13 @@ var IDLE = Object.freeze({
|
|
|
118
238
|
error: void 0
|
|
119
239
|
});
|
|
120
240
|
function useOpenedWindow(factory) {
|
|
121
|
-
const [state, setState] =
|
|
122
|
-
const current =
|
|
123
|
-
const factoryRef =
|
|
124
|
-
|
|
241
|
+
const [state, setState] = useState2(IDLE);
|
|
242
|
+
const current = useRef4(null);
|
|
243
|
+
const factoryRef = useRef4(factory);
|
|
244
|
+
useEffect4(() => {
|
|
125
245
|
factoryRef.current = factory;
|
|
126
246
|
});
|
|
127
|
-
const open =
|
|
247
|
+
const open = useCallback5(() => {
|
|
128
248
|
current.current?.close();
|
|
129
249
|
let opened;
|
|
130
250
|
try {
|
|
@@ -159,10 +279,10 @@ function useOpenedWindow(factory) {
|
|
|
159
279
|
}
|
|
160
280
|
);
|
|
161
281
|
}, []);
|
|
162
|
-
const post =
|
|
282
|
+
const post = useCallback5((type, payload) => {
|
|
163
283
|
current.current?.post(type, payload);
|
|
164
284
|
}, []);
|
|
165
|
-
const close =
|
|
285
|
+
const close = useCallback5(() => current.current?.close(), []);
|
|
166
286
|
return { ...state, open, post, close };
|
|
167
287
|
}
|
|
168
288
|
|
|
@@ -170,11 +290,14 @@ function useOpenedWindow(factory) {
|
|
|
170
290
|
import {
|
|
171
291
|
createChannel,
|
|
172
292
|
createSharedStore,
|
|
293
|
+
createSharedReducer,
|
|
173
294
|
createPresence,
|
|
174
295
|
createLeader,
|
|
175
296
|
webStorageAdapter,
|
|
176
297
|
localStorageAdapter,
|
|
177
298
|
sessionStorageAdapter,
|
|
299
|
+
indexedDbAdapter,
|
|
300
|
+
jsonSerializer,
|
|
178
301
|
openWindow,
|
|
179
302
|
connectToOpener,
|
|
180
303
|
CID_PARAM,
|
|
@@ -185,6 +308,8 @@ import {
|
|
|
185
308
|
enableDebug,
|
|
186
309
|
getBusNames,
|
|
187
310
|
getTransportKind,
|
|
311
|
+
getWireSkew,
|
|
312
|
+
WIRE_VERSION,
|
|
188
313
|
BroadcastChannelTransport,
|
|
189
314
|
NoopTransport,
|
|
190
315
|
StorageTransport,
|
|
@@ -199,11 +324,14 @@ export {
|
|
|
199
324
|
HandshakeTimeoutError,
|
|
200
325
|
NoopTransport,
|
|
201
326
|
StorageTransport,
|
|
327
|
+
WIRE_VERSION,
|
|
202
328
|
WindowClosedError2 as WindowClosedError,
|
|
203
329
|
connectToOpener,
|
|
204
330
|
createChannel,
|
|
205
331
|
createLeader,
|
|
332
|
+
createNamespace,
|
|
206
333
|
createPresence,
|
|
334
|
+
createSharedReducer,
|
|
207
335
|
createSharedStore,
|
|
208
336
|
defaultTransport,
|
|
209
337
|
defineChannel,
|
|
@@ -213,22 +341,32 @@ export {
|
|
|
213
341
|
getLeader,
|
|
214
342
|
getSharedStore,
|
|
215
343
|
getTransportKind,
|
|
344
|
+
getWireSkew,
|
|
345
|
+
indexedDbAdapter,
|
|
216
346
|
isBroadcastChannelAvailable,
|
|
217
347
|
isStorageEventAvailable,
|
|
348
|
+
jsonSerializer,
|
|
218
349
|
localStorageAdapter,
|
|
219
350
|
newer,
|
|
220
351
|
observeBus,
|
|
221
352
|
openWindow,
|
|
222
353
|
sessionStorageAdapter,
|
|
354
|
+
shallowEqual,
|
|
355
|
+
useAnswer,
|
|
356
|
+
useAsk,
|
|
223
357
|
useChannel,
|
|
224
358
|
useClientId,
|
|
359
|
+
useHydrated,
|
|
225
360
|
useIsLeader,
|
|
226
361
|
useLeader,
|
|
227
362
|
useLeaderEffect,
|
|
228
363
|
useMessage,
|
|
229
364
|
useOpenedWindow,
|
|
230
365
|
usePeers,
|
|
366
|
+
usePresenceMetadata,
|
|
231
367
|
useSend,
|
|
368
|
+
useSharedReducer,
|
|
232
369
|
useSharedState,
|
|
370
|
+
useSharedStore,
|
|
233
371
|
webStorageAdapter
|
|
234
372
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "use-everywhere",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "React hooks for state and messages shared across tabs, windows, and workers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jonatan Kruszewski <jonakrusze@gmail.com>",
|
|
@@ -69,59 +69,71 @@
|
|
|
69
69
|
"name": "everything (import *)",
|
|
70
70
|
"path": "dist/index.js",
|
|
71
71
|
"import": "*",
|
|
72
|
-
"limit": "
|
|
72
|
+
"limit": "10.89 kB"
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
"name": "useSharedState",
|
|
76
76
|
"path": "dist/index.js",
|
|
77
77
|
"import": "{ useSharedState }",
|
|
78
|
-
"limit": "
|
|
78
|
+
"limit": "4.24 kB"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "useSharedStore (selector)",
|
|
82
|
+
"path": "dist/index.js",
|
|
83
|
+
"import": "{ useSharedStore, shallowEqual }",
|
|
84
|
+
"limit": "4.40 kB"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "useSharedReducer",
|
|
88
|
+
"path": "dist/index.js",
|
|
89
|
+
"import": "{ useSharedReducer }",
|
|
90
|
+
"limit": "4.21 kB"
|
|
79
91
|
},
|
|
80
92
|
{
|
|
81
93
|
"name": "useChannel + useMessage + useSend",
|
|
82
94
|
"path": "dist/index.js",
|
|
83
95
|
"import": "{ useChannel, useMessage, useSend }",
|
|
84
|
-
"limit": "
|
|
96
|
+
"limit": "3.07 kB"
|
|
85
97
|
},
|
|
86
98
|
{
|
|
87
99
|
"name": "usePeers + useClientId",
|
|
88
100
|
"path": "dist/index.js",
|
|
89
101
|
"import": "{ usePeers, useClientId }",
|
|
90
|
-
"limit": "2.
|
|
102
|
+
"limit": "2.77 kB"
|
|
91
103
|
},
|
|
92
104
|
{
|
|
93
105
|
"name": "useOpenedWindow + openWindow",
|
|
94
106
|
"path": "dist/index.js",
|
|
95
107
|
"import": "{ useOpenedWindow, openWindow }",
|
|
96
|
-
"limit": "1.
|
|
108
|
+
"limit": "1.47 kB"
|
|
97
109
|
},
|
|
98
110
|
{
|
|
99
111
|
"name": "useLeader + useLeaderEffect",
|
|
100
112
|
"path": "dist/index.js",
|
|
101
113
|
"import": "{ useLeader, useLeaderEffect }",
|
|
102
|
-
"limit": "3.
|
|
114
|
+
"limit": "3.65 kB"
|
|
103
115
|
},
|
|
104
116
|
{
|
|
105
117
|
"name": "defineStore (persisted)",
|
|
106
118
|
"path": "dist/index.js",
|
|
107
119
|
"import": "{ defineStore, localStorageAdapter }",
|
|
108
|
-
"limit": "4.
|
|
120
|
+
"limit": "4.67 kB"
|
|
109
121
|
},
|
|
110
122
|
{
|
|
111
123
|
"name": "Inspector (devtools subpath)",
|
|
112
124
|
"path": "dist/devtools/index.js",
|
|
113
125
|
"import": "{ Inspector }",
|
|
114
|
-
"limit": "
|
|
126
|
+
"limit": "6.70 kB"
|
|
115
127
|
},
|
|
116
128
|
{
|
|
117
129
|
"name": "MemoryHub (testing subpath)",
|
|
118
130
|
"path": "dist/testing.js",
|
|
119
131
|
"import": "{ MemoryHub }",
|
|
120
|
-
"limit": "
|
|
132
|
+
"limit": "264 B"
|
|
121
133
|
}
|
|
122
134
|
],
|
|
123
135
|
"dependencies": {
|
|
124
|
-
"@use-everywhere/core": "0.
|
|
136
|
+
"@use-everywhere/core": "0.9.0"
|
|
125
137
|
},
|
|
126
138
|
"peerDependencies": {
|
|
127
139
|
"react": ">=18"
|