@pluv/react 0.17.3 → 0.19.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/.turbo/turbo-build.log +15 -15
- package/CHANGELOG.md +173 -0
- package/README.md +12 -2
- package/dist/index.d.mts +15 -9
- package/dist/index.d.ts +15 -9
- package/dist/index.js +118 -101
- package/dist/index.mjs +102 -92
- package/package.json +11 -12
- package/src/createBundle.tsx +4 -14
- package/src/createRoomBundle.tsx +111 -183
- package/src/index.ts +1 -6
- package/src/internal/hooks/index.ts +1 -1
- package/src/internal/hooks/useNoSsr.ts +18 -0
- package/src/internal/hooks/useSyncExternalStoreWithSelector.ts +44 -1
- package/src/internal/index.ts +1 -5
- package/src/internal/utils/index.ts +1 -0
- package/src/internal/utils/shallowArrayEqual.ts +1 -4
- package/src/internal/utils/shallowEqual.ts +1 -0
- package/tsconfig.json +4 -1
- package/src/internal/hooks/useSyncExternalStore.ts +0 -15
package/dist/index.js
CHANGED
|
@@ -38,25 +38,39 @@ module.exports = __toCommonJS(src_exports);
|
|
|
38
38
|
var import_client2 = require("@pluv/client");
|
|
39
39
|
|
|
40
40
|
// src/createBundle.tsx
|
|
41
|
-
var
|
|
41
|
+
var import_react5 = require("react");
|
|
42
42
|
|
|
43
43
|
// src/createRoomBundle.tsx
|
|
44
44
|
var import_client = require("@pluv/client");
|
|
45
45
|
var import_crdt = require("@pluv/crdt");
|
|
46
46
|
var import_fast_deep_equal = __toESM(require("fast-deep-equal"));
|
|
47
|
-
var
|
|
47
|
+
var import_react4 = require("react");
|
|
48
48
|
|
|
49
|
-
// src/internal/hooks/
|
|
49
|
+
// src/internal/hooks/useNoSsr.ts
|
|
50
50
|
var import_react = require("react");
|
|
51
|
+
var useNoSsr = () => {
|
|
52
|
+
const [didMount, setDidMount] = (0, import_react.useState)(false);
|
|
53
|
+
(0, import_react.useEffect)(() => setDidMount(typeof window !== "undefined"), []);
|
|
54
|
+
const noSsr = (0, import_react.useCallback)(
|
|
55
|
+
(value, fallback = null) => {
|
|
56
|
+
return didMount ? typeof value !== "function" ? value : value() : fallback;
|
|
57
|
+
},
|
|
58
|
+
[didMount]
|
|
59
|
+
);
|
|
60
|
+
return noSsr;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// src/internal/hooks/useRerender.ts
|
|
64
|
+
var import_react2 = require("react");
|
|
51
65
|
var useRerender = () => {
|
|
52
|
-
const [, setCount] = (0,
|
|
53
|
-
return (0,
|
|
66
|
+
const [, setCount] = (0, import_react2.useState)(0);
|
|
67
|
+
return (0, import_react2.useCallback)(() => {
|
|
54
68
|
setCount((oldCount) => (oldCount + 1) % Number.MAX_SAFE_INTEGER);
|
|
55
69
|
}, []);
|
|
56
70
|
};
|
|
57
71
|
|
|
58
72
|
// src/internal/hooks/useSyncExternalStoreWithSelector.ts
|
|
59
|
-
var
|
|
73
|
+
var import_react3 = require("react");
|
|
60
74
|
|
|
61
75
|
// src/internal/utils/identity.ts
|
|
62
76
|
var identity = (x) => x;
|
|
@@ -66,22 +80,40 @@ var shallowArrayEqual = (a, b) => {
|
|
|
66
80
|
return a.length === b.length && a.every((item, i) => item === b[i]);
|
|
67
81
|
};
|
|
68
82
|
|
|
83
|
+
// src/internal/utils/shallowEqual.ts
|
|
84
|
+
var shallowEqual = (a, b) => a === b;
|
|
85
|
+
|
|
86
|
+
// src/internal/hooks/useSyncExternalStoreWithSelector.ts
|
|
87
|
+
var useSyncExternalStoreWithSelector = (subscribe, getClientSnapshot, getServerSnapshot, selector, isEqual) => {
|
|
88
|
+
const noSsr = useNoSsr();
|
|
89
|
+
const cacheRef = (0, import_react3.useRef)(null);
|
|
90
|
+
const _getServerSnapshot = getServerSnapshot ? () => {
|
|
91
|
+
const data = getServerSnapshot();
|
|
92
|
+
return selector(data);
|
|
93
|
+
} : void 0;
|
|
94
|
+
const _getClientSnapshot = () => {
|
|
95
|
+
const data = getClientSnapshot();
|
|
96
|
+
const snapshot = selector(data);
|
|
97
|
+
const compare = isEqual != null ? isEqual : shallowEqual;
|
|
98
|
+
const cached = cacheRef.current;
|
|
99
|
+
const isUnchanged = cached === null ? snapshot === null : compare(cached, snapshot);
|
|
100
|
+
cacheRef.current = isUnchanged ? cached != null ? cached : snapshot : snapshot;
|
|
101
|
+
return cacheRef.current;
|
|
102
|
+
};
|
|
103
|
+
const result = (0, import_react3.useSyncExternalStore)(subscribe, _getClientSnapshot, _getServerSnapshot);
|
|
104
|
+
return typeof window !== "undefined" ? noSsr(result, _getServerSnapshot == null ? void 0 : _getServerSnapshot()) : result;
|
|
105
|
+
};
|
|
106
|
+
|
|
69
107
|
// src/createRoomBundle.tsx
|
|
70
108
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
71
109
|
var createRoomBundle = (client, options) => {
|
|
72
110
|
var _a;
|
|
73
111
|
const _initialStorage = (_a = options.initialStorage) != null ? _a : import_crdt.noop.doc();
|
|
74
|
-
const PluvRoomContext = (0,
|
|
75
|
-
const MockedRoomContext = (0,
|
|
76
|
-
const MockedRoomProvider = (0,
|
|
77
|
-
const {
|
|
78
|
-
|
|
79
|
-
events,
|
|
80
|
-
initialPresence,
|
|
81
|
-
initialStorage,
|
|
82
|
-
room: _room
|
|
83
|
-
} = props;
|
|
84
|
-
const [room] = (0, import_react2.useState)(() => {
|
|
112
|
+
const PluvRoomContext = (0, import_react4.createContext)(null);
|
|
113
|
+
const MockedRoomContext = (0, import_react4.createContext)({ room: null });
|
|
114
|
+
const MockedRoomProvider = (0, import_react4.memo)((props) => {
|
|
115
|
+
const { children, events, initialPresence, initialStorage, room: _room } = props;
|
|
116
|
+
const [room] = (0, import_react4.useState)(() => {
|
|
85
117
|
return new import_client.MockedRoom(_room, {
|
|
86
118
|
events,
|
|
87
119
|
initialPresence,
|
|
@@ -92,18 +124,11 @@ var createRoomBundle = (client, options) => {
|
|
|
92
124
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MockedRoomContext.Provider, { value: { room }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PluvRoomContext.Provider, { value: room, children }) });
|
|
93
125
|
});
|
|
94
126
|
MockedRoomProvider.displayName = "MockedRoomProvider";
|
|
95
|
-
const PluvRoomProvider = (0,
|
|
96
|
-
const {
|
|
97
|
-
children,
|
|
98
|
-
debug,
|
|
99
|
-
initialPresence,
|
|
100
|
-
initialStorage,
|
|
101
|
-
onAuthorizationFail,
|
|
102
|
-
room: _room
|
|
103
|
-
} = props;
|
|
127
|
+
const PluvRoomProvider = (0, import_react4.memo)((props) => {
|
|
128
|
+
const { children, debug, initialPresence, initialStorage, onAuthorizationFail, room: _room } = props;
|
|
104
129
|
const rerender = useRerender();
|
|
105
|
-
const { room: mockedRoom } = (0,
|
|
106
|
-
const [room] = (0,
|
|
130
|
+
const { room: mockedRoom } = (0, import_react4.useContext)(MockedRoomContext);
|
|
131
|
+
const [room] = (0, import_react4.useState)(() => {
|
|
107
132
|
return client.createRoom(_room, {
|
|
108
133
|
addons: options.addons,
|
|
109
134
|
debug,
|
|
@@ -113,7 +138,7 @@ var createRoomBundle = (client, options) => {
|
|
|
113
138
|
onAuthorizationFail
|
|
114
139
|
});
|
|
115
140
|
});
|
|
116
|
-
(0,
|
|
141
|
+
(0, import_react4.useEffect)(() => {
|
|
117
142
|
const unsubscribe = room.subscribe("connection", () => {
|
|
118
143
|
rerender();
|
|
119
144
|
});
|
|
@@ -121,7 +146,7 @@ var createRoomBundle = (client, options) => {
|
|
|
121
146
|
unsubscribe();
|
|
122
147
|
};
|
|
123
148
|
}, [rerender, room]);
|
|
124
|
-
(0,
|
|
149
|
+
(0, import_react4.useEffect)(() => {
|
|
125
150
|
client.enter(room);
|
|
126
151
|
return () => {
|
|
127
152
|
client.leave(room);
|
|
@@ -130,61 +155,51 @@ var createRoomBundle = (client, options) => {
|
|
|
130
155
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PluvRoomContext.Provider, { value: mockedRoom != null ? mockedRoom : room, children });
|
|
131
156
|
});
|
|
132
157
|
PluvRoomProvider.displayName = "PluvRoomProvider";
|
|
133
|
-
const useRoom = () => (0,
|
|
158
|
+
const useRoom = () => (0, import_react4.useContext)(PluvRoomContext);
|
|
134
159
|
const useBroadcast = () => {
|
|
135
160
|
const room = useRoom();
|
|
136
|
-
|
|
137
|
-
(
|
|
138
|
-
room.broadcast(
|
|
161
|
+
const broadcast = (0, import_react4.useCallback)(
|
|
162
|
+
(event2, data) => {
|
|
163
|
+
room.broadcast(event2, data);
|
|
139
164
|
},
|
|
140
165
|
[room]
|
|
141
166
|
);
|
|
167
|
+
return (0, import_react4.useMemo)(() => {
|
|
168
|
+
return new Proxy(broadcast, {
|
|
169
|
+
get(fn, prop) {
|
|
170
|
+
return (data) => {
|
|
171
|
+
return fn(prop, data);
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}, [broadcast]);
|
|
142
176
|
};
|
|
143
177
|
const useCanRedo = () => {
|
|
144
178
|
const room = useRoom();
|
|
145
|
-
const subscribe = (0,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
);
|
|
149
|
-
const getSnapshot = (0, import_react2.useCallback)(() => room.canRedo(), [room]);
|
|
150
|
-
const canRedo = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
151
|
-
subscribe,
|
|
152
|
-
getSnapshot,
|
|
153
|
-
getSnapshot,
|
|
154
|
-
identity
|
|
155
|
-
);
|
|
179
|
+
const subscribe = (0, import_react4.useCallback)((onStoreChange) => room.storageRoot(onStoreChange), [room]);
|
|
180
|
+
const getSnapshot = (0, import_react4.useCallback)(() => room.canRedo(), [room]);
|
|
181
|
+
const canRedo = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity);
|
|
156
182
|
return canRedo;
|
|
157
183
|
};
|
|
158
184
|
const useCanUndo = () => {
|
|
159
185
|
const room = useRoom();
|
|
160
|
-
const subscribe = (0,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const getSnapshot = (0, import_react2.useCallback)(() => room.canUndo(), [room]);
|
|
165
|
-
const canRedo = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
166
|
-
subscribe,
|
|
167
|
-
getSnapshot,
|
|
168
|
-
getSnapshot,
|
|
169
|
-
identity
|
|
170
|
-
);
|
|
171
|
-
return canRedo;
|
|
186
|
+
const subscribe = (0, import_react4.useCallback)((onStoreChange) => room.storageRoot(onStoreChange), [room]);
|
|
187
|
+
const getSnapshot = (0, import_react4.useCallback)(() => room.canUndo(), [room]);
|
|
188
|
+
const canUndo = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity);
|
|
189
|
+
return canUndo;
|
|
172
190
|
};
|
|
173
191
|
const useConnection = (selector = identity, options2) => {
|
|
174
192
|
var _a2;
|
|
175
193
|
const room = useRoom();
|
|
176
|
-
const subscribe = (0,
|
|
194
|
+
const subscribe = (0, import_react4.useCallback)(
|
|
177
195
|
(onStoreChange) => {
|
|
178
196
|
return room.subscribe("connection", onStoreChange);
|
|
179
197
|
},
|
|
180
198
|
[room]
|
|
181
199
|
);
|
|
182
200
|
const getSnapshot = room.getConnection;
|
|
183
|
-
const _selector = (0,
|
|
184
|
-
|
|
185
|
-
[selector]
|
|
186
|
-
);
|
|
187
|
-
return (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
201
|
+
const _selector = (0, import_react4.useCallback)((snapshot) => selector(snapshot), [selector]);
|
|
202
|
+
return useSyncExternalStoreWithSelector(
|
|
188
203
|
subscribe,
|
|
189
204
|
getSnapshot,
|
|
190
205
|
getSnapshot,
|
|
@@ -198,60 +213,61 @@ var createRoomBundle = (client, options) => {
|
|
|
198
213
|
};
|
|
199
214
|
const useEvent = (type, callback) => {
|
|
200
215
|
const room = useRoom();
|
|
201
|
-
(0,
|
|
216
|
+
(0, import_react4.useEffect)(() => {
|
|
202
217
|
const unsubscribe = room.event(type, callback);
|
|
203
218
|
return () => {
|
|
204
219
|
unsubscribe();
|
|
205
220
|
};
|
|
206
221
|
}, [callback, room, type]);
|
|
207
222
|
};
|
|
223
|
+
const event = new Proxy(
|
|
224
|
+
{},
|
|
225
|
+
{
|
|
226
|
+
get(_, prop) {
|
|
227
|
+
const useProxyEvent = (callback) => {
|
|
228
|
+
return useEvent(prop, callback);
|
|
229
|
+
};
|
|
230
|
+
return { useEvent: useProxyEvent };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
);
|
|
208
234
|
const useMyPresence = (selector = identity, options2) => {
|
|
209
235
|
var _a2;
|
|
210
236
|
const room = useRoom();
|
|
211
|
-
const subscribe = (0,
|
|
237
|
+
const subscribe = (0, import_react4.useCallback)(
|
|
212
238
|
(onStoreChange) => {
|
|
213
239
|
return room.subscribe("my-presence", onStoreChange);
|
|
214
240
|
},
|
|
215
241
|
[room]
|
|
216
242
|
);
|
|
217
243
|
const getSnapshot = room.getMyPresence;
|
|
218
|
-
const _selector = (0,
|
|
219
|
-
|
|
220
|
-
[selector]
|
|
221
|
-
);
|
|
222
|
-
const myPresence = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
244
|
+
const _selector = (0, import_react4.useCallback)((snapshot) => selector(snapshot), [selector]);
|
|
245
|
+
const myPresence = useSyncExternalStoreWithSelector(
|
|
223
246
|
subscribe,
|
|
224
247
|
getSnapshot,
|
|
225
248
|
getSnapshot,
|
|
226
249
|
_selector,
|
|
227
250
|
(_a2 = options2 == null ? void 0 : options2.isEqual) != null ? _a2 : import_fast_deep_equal.default
|
|
228
251
|
);
|
|
229
|
-
|
|
230
|
-
(value) => {
|
|
231
|
-
const presence = typeof value === "function" ? value(room.getMyPresence()) : value;
|
|
232
|
-
room.updateMyPresence(presence);
|
|
233
|
-
},
|
|
234
|
-
[room]
|
|
235
|
-
);
|
|
236
|
-
return [myPresence, updateMyPresence];
|
|
252
|
+
return [myPresence, room.updateMyPresence];
|
|
237
253
|
};
|
|
238
254
|
const useMyself = (selector = identity, options2) => {
|
|
239
255
|
var _a2;
|
|
240
256
|
const room = useRoom();
|
|
241
|
-
const subscribe = (0,
|
|
257
|
+
const subscribe = (0, import_react4.useCallback)(
|
|
242
258
|
(onStoreChange) => {
|
|
243
259
|
return room.subscribe("myself", onStoreChange);
|
|
244
260
|
},
|
|
245
261
|
[room]
|
|
246
262
|
);
|
|
247
263
|
const getSnapshot = room.getMyself;
|
|
248
|
-
const _selector = (0,
|
|
264
|
+
const _selector = (0, import_react4.useCallback)(
|
|
249
265
|
(snapshot) => {
|
|
250
266
|
return !snapshot ? null : selector(snapshot);
|
|
251
267
|
},
|
|
252
268
|
[selector]
|
|
253
269
|
);
|
|
254
|
-
return
|
|
270
|
+
return useSyncExternalStoreWithSelector(
|
|
255
271
|
subscribe,
|
|
256
272
|
getSnapshot,
|
|
257
273
|
getSnapshot,
|
|
@@ -262,23 +278,20 @@ var createRoomBundle = (client, options) => {
|
|
|
262
278
|
const useOther = (connectionId, selector = identity, options2) => {
|
|
263
279
|
var _a2;
|
|
264
280
|
const room = useRoom();
|
|
265
|
-
const subscribe = (0,
|
|
281
|
+
const subscribe = (0, import_react4.useCallback)(
|
|
266
282
|
(onStoreChange) => {
|
|
267
283
|
return room.other(connectionId, onStoreChange);
|
|
268
284
|
},
|
|
269
285
|
[room, connectionId]
|
|
270
286
|
);
|
|
271
|
-
const getSnapshot = (0,
|
|
272
|
-
|
|
273
|
-
[room, connectionId]
|
|
274
|
-
);
|
|
275
|
-
const _selector = (0, import_react2.useCallback)(
|
|
287
|
+
const getSnapshot = (0, import_react4.useCallback)(() => room.getOther(connectionId), [room, connectionId]);
|
|
288
|
+
const _selector = (0, import_react4.useCallback)(
|
|
276
289
|
(snapshot) => {
|
|
277
290
|
return !snapshot ? null : selector(snapshot);
|
|
278
291
|
},
|
|
279
292
|
[selector]
|
|
280
293
|
);
|
|
281
|
-
return
|
|
294
|
+
return useSyncExternalStoreWithSelector(
|
|
282
295
|
subscribe,
|
|
283
296
|
getSnapshot,
|
|
284
297
|
getSnapshot,
|
|
@@ -289,19 +302,24 @@ var createRoomBundle = (client, options) => {
|
|
|
289
302
|
const useOthers = (selector = identity, options2) => {
|
|
290
303
|
var _a2;
|
|
291
304
|
const room = useRoom();
|
|
292
|
-
const subscribe = (0,
|
|
305
|
+
const subscribe = (0, import_react4.useCallback)(
|
|
293
306
|
(onStoreChange) => {
|
|
294
307
|
return room.subscribe("others", onStoreChange);
|
|
295
308
|
},
|
|
296
309
|
[room]
|
|
297
310
|
);
|
|
298
311
|
const getSnapshot = room.getOthers;
|
|
299
|
-
return
|
|
312
|
+
return useSyncExternalStoreWithSelector(
|
|
300
313
|
subscribe,
|
|
301
314
|
getSnapshot,
|
|
302
315
|
getSnapshot,
|
|
303
316
|
selector,
|
|
304
|
-
(_a2 = options2 == null ? void 0 : options2.isEqual) != null ? _a2 :
|
|
317
|
+
(_a2 = options2 == null ? void 0 : options2.isEqual) != null ? _a2 : (a, b) => {
|
|
318
|
+
if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {
|
|
319
|
+
return shallowArrayEqual(a, b);
|
|
320
|
+
}
|
|
321
|
+
return (0, import_fast_deep_equal.default)(a, b);
|
|
322
|
+
}
|
|
305
323
|
);
|
|
306
324
|
};
|
|
307
325
|
const useRedo = () => {
|
|
@@ -315,21 +333,18 @@ var createRoomBundle = (client, options) => {
|
|
|
315
333
|
room.subscribe("storage-loaded", () => {
|
|
316
334
|
rerender();
|
|
317
335
|
});
|
|
318
|
-
const subscribe = (0,
|
|
319
|
-
|
|
320
|
-
[key, room]
|
|
321
|
-
);
|
|
322
|
-
const getSnapshot = (0, import_react2.useCallback)(() => {
|
|
336
|
+
const subscribe = (0, import_react4.useCallback)((onStoreChange) => room.storage(key, onStoreChange), [key, room]);
|
|
337
|
+
const getSnapshot = (0, import_react4.useCallback)(() => {
|
|
323
338
|
var _a3;
|
|
324
339
|
return (_a3 = room.getStorage(key)) == null ? void 0 : _a3.toJson();
|
|
325
340
|
}, [key, room]);
|
|
326
|
-
const _selector = (0,
|
|
341
|
+
const _selector = (0, import_react4.useCallback)(
|
|
327
342
|
(snapshot) => {
|
|
328
343
|
return snapshot === null ? null : selector(snapshot);
|
|
329
344
|
},
|
|
330
345
|
[selector]
|
|
331
346
|
);
|
|
332
|
-
const data =
|
|
347
|
+
const data = useSyncExternalStoreWithSelector(
|
|
333
348
|
subscribe,
|
|
334
349
|
getSnapshot,
|
|
335
350
|
getSnapshot,
|
|
@@ -351,6 +366,8 @@ var createRoomBundle = (client, options) => {
|
|
|
351
366
|
// components
|
|
352
367
|
MockedRoomProvider,
|
|
353
368
|
PluvRoomProvider,
|
|
369
|
+
// proxies
|
|
370
|
+
event,
|
|
354
371
|
// hooks
|
|
355
372
|
useBroadcast,
|
|
356
373
|
useCanRedo,
|
|
@@ -373,13 +390,13 @@ var createRoomBundle = (client, options) => {
|
|
|
373
390
|
// src/createBundle.tsx
|
|
374
391
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
375
392
|
var createBundle = (client) => {
|
|
376
|
-
const PluvContext = (0,
|
|
377
|
-
const PluvProvider = (0,
|
|
393
|
+
const PluvContext = (0, import_react5.createContext)(null);
|
|
394
|
+
const PluvProvider = (0, import_react5.memo)((props) => {
|
|
378
395
|
const { children } = props;
|
|
379
396
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PluvContext.Provider, { value: client, children });
|
|
380
397
|
});
|
|
381
398
|
PluvProvider.displayName = "PluvProvider";
|
|
382
|
-
const useClient = () => (0,
|
|
399
|
+
const useClient = () => (0, import_react5.useContext)(PluvContext);
|
|
383
400
|
const createRoomBundle2 = (options) => createRoomBundle(client, options);
|
|
384
401
|
return {
|
|
385
402
|
createRoomBundle: createRoomBundle2,
|