@liveblocks/react 0.18.0-beta0 → 0.18.0-beta1
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/.built-by-link-script +1 -1
- package/index.d.ts +101 -3
- package/index.js +152 -49
- package/index.mjs +2 -0
- package/package.json +2 -2
package/.built-by-link-script
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
82a138d642402a9a15f754de8f42105c6724d0b0
|
package/index.d.ts
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactElement, ReactNode } from 'react';
|
|
1
3
|
import { JsonObject, LsonObject, LiveObject, BaseUserMeta, Json, Client, Room, BroadcastOptions, History, Others, User } from '@liveblocks/client';
|
|
2
|
-
export { Json, JsonObject } from '@liveblocks/client';
|
|
4
|
+
export { Json, JsonObject, shallow } from '@liveblocks/client';
|
|
3
5
|
import { ToImmutable, Resolve, RoomInitializers } from '@liveblocks/client/internal';
|
|
4
|
-
|
|
6
|
+
|
|
7
|
+
declare type Props = {
|
|
8
|
+
fallback: NonNullable<ReactNode> | null;
|
|
9
|
+
children: () => ReactNode | undefined;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Almost like a normal <Suspense> component, except that for server-side
|
|
13
|
+
* renders, the fallback will be used.
|
|
14
|
+
*
|
|
15
|
+
* The child props will have to be provided in a function, i.e. change:
|
|
16
|
+
*
|
|
17
|
+
* <Suspense fallback={<Loading />}>
|
|
18
|
+
* <MyRealComponent a={1} />
|
|
19
|
+
* </Suspense>
|
|
20
|
+
*
|
|
21
|
+
* To:
|
|
22
|
+
*
|
|
23
|
+
* <ClientSideSuspense fallback={<Loading />}>
|
|
24
|
+
* {() => <MyRealComponent a={1} />}
|
|
25
|
+
* </ClientSideSuspense>
|
|
26
|
+
*
|
|
27
|
+
*/
|
|
28
|
+
declare function ClientSideSuspense(props: Props): ReactElement;
|
|
5
29
|
|
|
6
30
|
/**
|
|
7
31
|
* For any function type, returns a similar function type, but without the
|
|
@@ -210,6 +234,70 @@ declare type RoomContextBundle<TPresence extends JsonObject, TStorage extends Ls
|
|
|
210
234
|
*
|
|
211
235
|
*/
|
|
212
236
|
useOthers<T>(selector: (others: Others<TPresence, TUserMeta>) => T, isEqual?: (a: T, b: T) => boolean): T;
|
|
237
|
+
/**
|
|
238
|
+
* Related to useOthers(), but optimized for selecting only "subsets" of
|
|
239
|
+
* others. This is useful for performance reasons in particular, because
|
|
240
|
+
* selecting only a subset of users also means limiting the number of
|
|
241
|
+
* re-renders that will be triggered.
|
|
242
|
+
*
|
|
243
|
+
* Note that there are two ways to use this hook, and depending on how you
|
|
244
|
+
* call it, the return value will be slightly different.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* const ids = useOtherIds();
|
|
248
|
+
* // ^^^ number[]
|
|
249
|
+
*/
|
|
250
|
+
useOtherIds(): readonly number[];
|
|
251
|
+
/**
|
|
252
|
+
* Related to useOthers(), but optimized for selecting only "subsets" of
|
|
253
|
+
* others. This is useful for performance reasons in particular, because
|
|
254
|
+
* selecting only a subset of users also means limiting the number of
|
|
255
|
+
* re-renders that will be triggered.
|
|
256
|
+
*
|
|
257
|
+
* Note that there are two ways to use this hook, and depending on how you
|
|
258
|
+
* call it, the return value will be slightly different.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* const avatars = useOtherIds(user => user.info.avatar);
|
|
262
|
+
* // ^^^^^^^
|
|
263
|
+
* // { connectionId: number; data: string }[]
|
|
264
|
+
*
|
|
265
|
+
* The selector function you pass to useOtherIds() is called an "item
|
|
266
|
+
* selector", and operates on a single user at a time. If you provide an
|
|
267
|
+
* (optional) comparison function, it will also work on the _item_ level.
|
|
268
|
+
*
|
|
269
|
+
* For example, to select multiple properties:
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* const avatarsAndCursors = useOtherIds(
|
|
273
|
+
* user => [u.info.avatar, u.presence.cursor],
|
|
274
|
+
* shallow, // ❗️
|
|
275
|
+
* );
|
|
276
|
+
*/
|
|
277
|
+
useOtherIds<T>(itemSelector: (other: User<TPresence, TUserMeta>) => T, isEqual?: (a: T, b: T) => boolean): readonly {
|
|
278
|
+
readonly connectionId: number;
|
|
279
|
+
readonly data: T;
|
|
280
|
+
}[];
|
|
281
|
+
/**
|
|
282
|
+
* Given a connection ID (as obtained by using `useOtherIds()`), you can call
|
|
283
|
+
* this selector deep down in your component stack to only have the component
|
|
284
|
+
* re-render if properties for this particular connection change.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* // Returns full user and re-renders whenever anything on the user changes
|
|
288
|
+
* const secondUser = useOther(2);
|
|
289
|
+
*/
|
|
290
|
+
useOther(connectionId: number): User<TPresence, TUserMeta>;
|
|
291
|
+
/**
|
|
292
|
+
* Given a connection ID (as obtained by using `useOtherIds()`), you can call
|
|
293
|
+
* this selector deep down in your component stack to only have the component
|
|
294
|
+
* re-render if properties for this particular connection change.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* // Returns only the selected values re-renders whenever that selection changes)
|
|
298
|
+
* const { x, y } = useOther(2, user => user.presence.cursor);
|
|
299
|
+
*/
|
|
300
|
+
useOther<T>(connectionId: number, selector: (other: User<TPresence, TUserMeta>) => T, isEqual?: (a: T, b: T) => boolean): T;
|
|
213
301
|
/**
|
|
214
302
|
* Returns the Room of the nearest RoomProvider above in the React component
|
|
215
303
|
* tree.
|
|
@@ -277,8 +365,18 @@ declare type RoomContextBundle<TPresence extends JsonObject, TStorage extends Ls
|
|
|
277
365
|
useSelf<T>(selector: (me: User<TPresence, TUserMeta>) => T, isEqual?: (a: T, b: T) => boolean): T;
|
|
278
366
|
useOthers(): Others<TPresence, TUserMeta>;
|
|
279
367
|
useOthers<T>(selector: (others: Others<TPresence, TUserMeta>) => T, isEqual?: (a: T, b: T) => boolean): T;
|
|
368
|
+
useOtherIds(): readonly number[];
|
|
369
|
+
useOtherIds<T>(itemSelector: (other: User<TPresence, TUserMeta>) => T, isEqual?: (a: T, b: T) => boolean): readonly {
|
|
370
|
+
readonly connectionId: number;
|
|
371
|
+
readonly data: T;
|
|
372
|
+
}[];
|
|
373
|
+
useOther(connectionId: number): User<TPresence, TUserMeta>;
|
|
374
|
+
useOther<T>(connectionId: number, selector: (other: User<TPresence, TUserMeta>) => T, isEqual?: (a: T, b: T) => boolean): T;
|
|
375
|
+
useList<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey];
|
|
376
|
+
useMap<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey];
|
|
377
|
+
useObject<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey];
|
|
280
378
|
};
|
|
281
379
|
};
|
|
282
380
|
declare function createRoomContext<TPresence extends JsonObject, TStorage extends LsonObject = LsonObject, TUserMeta extends BaseUserMeta = BaseUserMeta, TRoomEvent extends Json = never>(client: Client): RoomContextBundle<TPresence, TStorage, TUserMeta, TRoomEvent>;
|
|
283
381
|
|
|
284
|
-
export { MutationContext, createRoomContext };
|
|
382
|
+
export { ClientSideSuspense, MutationContext, createRoomContext };
|
package/index.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }// src/
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }// src/ClientSideSuspense.tsx
|
|
2
|
+
var _react = require('react'); var React = _interopRequireWildcard(_react); var React2 = _interopRequireWildcard(_react);
|
|
3
|
+
function ClientSideSuspense(props) {
|
|
4
|
+
const [mounted, setMounted] = React.useState(false);
|
|
5
|
+
React.useEffect(() => {
|
|
6
|
+
setMounted(true);
|
|
7
|
+
}, []);
|
|
8
|
+
return /* @__PURE__ */ React.createElement(React.Suspense, {
|
|
9
|
+
fallback: props.fallback
|
|
10
|
+
}, mounted ? props.children() : props.fallback);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/factory.tsx
|
|
14
|
+
var _client = require('@liveblocks/client');
|
|
2
15
|
var _internal = require('@liveblocks/client/internal');
|
|
3
|
-
|
|
16
|
+
|
|
4
17
|
var _withselector = require('use-sync-external-store/shim/with-selector');
|
|
5
18
|
|
|
6
19
|
// src/hooks.ts
|
|
@@ -20,21 +33,12 @@ function useInitial(value) {
|
|
|
20
33
|
var noop = () => {
|
|
21
34
|
};
|
|
22
35
|
var identity = (x) => x;
|
|
23
|
-
var EMPTY_OTHERS = [];
|
|
24
|
-
Object.defineProperty(EMPTY_OTHERS, "count", {
|
|
25
|
-
value: 0,
|
|
26
|
-
enumerable: false
|
|
27
|
-
});
|
|
28
|
-
Object.defineProperty(EMPTY_OTHERS, "toArray", {
|
|
29
|
-
value: () => EMPTY_OTHERS,
|
|
30
|
-
enumerable: false
|
|
31
|
-
});
|
|
32
|
-
_internal.freeze.call(void 0, EMPTY_OTHERS);
|
|
36
|
+
var EMPTY_OTHERS = _internal.asArrayWithLegacyMethods.call(void 0, []);
|
|
33
37
|
function getEmptyOthers() {
|
|
34
38
|
return EMPTY_OTHERS;
|
|
35
39
|
}
|
|
36
40
|
function createRoomContext(client) {
|
|
37
|
-
const RoomContext =
|
|
41
|
+
const RoomContext = React2.createContext(null);
|
|
38
42
|
function RoomProvider(props) {
|
|
39
43
|
const { id: roomId, initialPresence, initialStorage } = props;
|
|
40
44
|
if (process.env.NODE_ENV !== "production") {
|
|
@@ -51,14 +55,14 @@ function createRoomContext(client) {
|
|
|
51
55
|
initialPresence,
|
|
52
56
|
initialStorage
|
|
53
57
|
});
|
|
54
|
-
const [room, setRoom] =
|
|
58
|
+
const [room, setRoom] = React2.useState(
|
|
55
59
|
() => client.enter(roomId, {
|
|
56
60
|
initialPresence,
|
|
57
61
|
initialStorage,
|
|
58
62
|
DO_NOT_USE_withoutConnecting: typeof window === "undefined"
|
|
59
63
|
})
|
|
60
64
|
);
|
|
61
|
-
|
|
65
|
+
React2.useEffect(() => {
|
|
62
66
|
setRoom(
|
|
63
67
|
client.enter(roomId, {
|
|
64
68
|
initialPresence: frozen.initialPresence,
|
|
@@ -70,12 +74,15 @@ function createRoomContext(client) {
|
|
|
70
74
|
client.leave(roomId);
|
|
71
75
|
};
|
|
72
76
|
}, [roomId, frozen]);
|
|
73
|
-
return /* @__PURE__ */
|
|
77
|
+
return /* @__PURE__ */ React2.createElement(RoomContext.Provider, {
|
|
74
78
|
value: room
|
|
75
79
|
}, props.children);
|
|
76
80
|
}
|
|
81
|
+
function connectionIdSelector(others) {
|
|
82
|
+
return others.map((user) => user.connectionId);
|
|
83
|
+
}
|
|
77
84
|
function useRoom() {
|
|
78
|
-
const room =
|
|
85
|
+
const room = React2.useContext(RoomContext);
|
|
79
86
|
if (room == null) {
|
|
80
87
|
throw new Error("RoomProvider is missing from the react tree");
|
|
81
88
|
}
|
|
@@ -85,11 +92,8 @@ function createRoomContext(client) {
|
|
|
85
92
|
const room = useRoom();
|
|
86
93
|
const presence = room.getPresence();
|
|
87
94
|
const rerender = useRerender();
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
(patch, options) => room.updatePresence(patch, options),
|
|
91
|
-
[room]
|
|
92
|
-
);
|
|
95
|
+
const setPresence = room.updatePresence;
|
|
96
|
+
React2.useEffect(() => room.events.me.subscribe(rerender), [room, rerender]);
|
|
93
97
|
return [presence, setPresence];
|
|
94
98
|
}
|
|
95
99
|
function useUpdateMyPresence() {
|
|
@@ -98,10 +102,7 @@ function createRoomContext(client) {
|
|
|
98
102
|
function useOthers(selector, isEqual) {
|
|
99
103
|
const room = useRoom();
|
|
100
104
|
const subscribe = room.events.others.subscribe;
|
|
101
|
-
const getSnapshot =
|
|
102
|
-
() => room.getOthers(),
|
|
103
|
-
[room]
|
|
104
|
-
);
|
|
105
|
+
const getSnapshot = room.getOthers;
|
|
105
106
|
const getServerSnapshot = getEmptyOthers;
|
|
106
107
|
return _withselector.useSyncExternalStoreWithSelector.call(void 0,
|
|
107
108
|
subscribe,
|
|
@@ -111,9 +112,80 @@ function createRoomContext(client) {
|
|
|
111
112
|
isEqual
|
|
112
113
|
);
|
|
113
114
|
}
|
|
115
|
+
function useOtherIds(itemSelector, isEqual) {
|
|
116
|
+
const _useCallback = React2.useCallback;
|
|
117
|
+
const _useOthers = useOthers;
|
|
118
|
+
if (itemSelector === void 0) {
|
|
119
|
+
return _useOthers(connectionIdSelector, _client.shallow);
|
|
120
|
+
} else {
|
|
121
|
+
const wrappedSelector = _useCallback(
|
|
122
|
+
(others) => others.map((other) => ({
|
|
123
|
+
connectionId: other.connectionId,
|
|
124
|
+
data: itemSelector(other)
|
|
125
|
+
})),
|
|
126
|
+
[itemSelector]
|
|
127
|
+
);
|
|
128
|
+
const wrappedIsEqual = _useCallback(
|
|
129
|
+
(a, b) => {
|
|
130
|
+
const eq = isEqual != null ? isEqual : Object.is;
|
|
131
|
+
return a.length === b.length && a.every((atuple, index) => {
|
|
132
|
+
const btuple = b[index];
|
|
133
|
+
return atuple.connectionId === btuple.connectionId && eq(atuple.data, btuple.data);
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
[isEqual]
|
|
137
|
+
);
|
|
138
|
+
return _useOthers(wrappedSelector, wrappedIsEqual);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const sentinel = Symbol();
|
|
142
|
+
function useOther(connectionId, selector, isEqual) {
|
|
143
|
+
const _useCallback = React2.useCallback;
|
|
144
|
+
const _useOthers = useOthers;
|
|
145
|
+
if (selector === void 0) {
|
|
146
|
+
const selector2 = _useCallback(
|
|
147
|
+
(others) => others.find((other2) => other2.connectionId === connectionId),
|
|
148
|
+
[connectionId]
|
|
149
|
+
);
|
|
150
|
+
const other = _useOthers(selector2, _client.shallow);
|
|
151
|
+
if (other === void 0) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`No such other user with connection id ${connectionId} exists`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
return other;
|
|
157
|
+
} else {
|
|
158
|
+
const wrappedSelector = _useCallback(
|
|
159
|
+
(others) => {
|
|
160
|
+
const other2 = others.find(
|
|
161
|
+
(other3) => other3.connectionId === connectionId
|
|
162
|
+
);
|
|
163
|
+
return other2 !== void 0 ? selector(other2) : sentinel;
|
|
164
|
+
},
|
|
165
|
+
[connectionId, selector]
|
|
166
|
+
);
|
|
167
|
+
const wrappedIsEqual = _useCallback(
|
|
168
|
+
(a, b) => {
|
|
169
|
+
if (a === sentinel || b === sentinel) {
|
|
170
|
+
return a === b;
|
|
171
|
+
}
|
|
172
|
+
const eq = isEqual != null ? isEqual : Object.is;
|
|
173
|
+
return eq(a, b);
|
|
174
|
+
},
|
|
175
|
+
[isEqual]
|
|
176
|
+
);
|
|
177
|
+
const other = _useOthers(wrappedSelector, wrappedIsEqual);
|
|
178
|
+
if (other === sentinel) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`No such other user with connection id ${connectionId} exists`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return other;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
114
186
|
function useBroadcastEvent() {
|
|
115
187
|
const room = useRoom();
|
|
116
|
-
return
|
|
188
|
+
return React2.useCallback(
|
|
117
189
|
(event, options = { shouldQueueEventIfNotReady: false }) => {
|
|
118
190
|
room.broadcastEvent(event, options);
|
|
119
191
|
},
|
|
@@ -122,22 +194,22 @@ function createRoomContext(client) {
|
|
|
122
194
|
}
|
|
123
195
|
function useErrorListener(callback) {
|
|
124
196
|
const room = useRoom();
|
|
125
|
-
const savedCallback =
|
|
126
|
-
|
|
197
|
+
const savedCallback = React2.useRef(callback);
|
|
198
|
+
React2.useEffect(() => {
|
|
127
199
|
savedCallback.current = callback;
|
|
128
200
|
});
|
|
129
|
-
|
|
201
|
+
React2.useEffect(
|
|
130
202
|
() => room.events.error.subscribe((e) => savedCallback.current(e)),
|
|
131
203
|
[room]
|
|
132
204
|
);
|
|
133
205
|
}
|
|
134
206
|
function useEventListener(callback) {
|
|
135
207
|
const room = useRoom();
|
|
136
|
-
const savedCallback =
|
|
137
|
-
|
|
208
|
+
const savedCallback = React2.useRef(callback);
|
|
209
|
+
React2.useEffect(() => {
|
|
138
210
|
savedCallback.current = callback;
|
|
139
211
|
});
|
|
140
|
-
|
|
212
|
+
React2.useEffect(() => {
|
|
141
213
|
const listener = (eventData) => {
|
|
142
214
|
savedCallback.current(eventData);
|
|
143
215
|
};
|
|
@@ -146,7 +218,7 @@ function createRoomContext(client) {
|
|
|
146
218
|
}
|
|
147
219
|
function useSelf(maybeSelector, isEqual) {
|
|
148
220
|
const room = useRoom();
|
|
149
|
-
const subscribe =
|
|
221
|
+
const subscribe = React2.useCallback(
|
|
150
222
|
(onChange) => {
|
|
151
223
|
const unsub1 = room.events.me.subscribe(onChange);
|
|
152
224
|
const unsub2 = room.events.connection.subscribe(onChange);
|
|
@@ -159,11 +231,11 @@ function createRoomContext(client) {
|
|
|
159
231
|
);
|
|
160
232
|
const getSnapshot = room.getSelf;
|
|
161
233
|
const selector = maybeSelector != null ? maybeSelector : identity;
|
|
162
|
-
const wrappedSelector =
|
|
234
|
+
const wrappedSelector = React2.useCallback(
|
|
163
235
|
(me) => me !== null ? selector(me) : null,
|
|
164
236
|
[selector]
|
|
165
237
|
);
|
|
166
|
-
const getServerSnapshot =
|
|
238
|
+
const getServerSnapshot = React2.useCallback(() => null, []);
|
|
167
239
|
return _withselector.useSyncExternalStoreWithSelector.call(void 0,
|
|
168
240
|
subscribe,
|
|
169
241
|
getSnapshot,
|
|
@@ -176,7 +248,7 @@ function createRoomContext(client) {
|
|
|
176
248
|
const room = useRoom();
|
|
177
249
|
const subscribe = room.events.storageDidLoad.subscribeOnce;
|
|
178
250
|
const getSnapshot = room.getStorageSnapshot;
|
|
179
|
-
const getServerSnapshot =
|
|
251
|
+
const getServerSnapshot = React2.useCallback(() => null, []);
|
|
180
252
|
const selector = identity;
|
|
181
253
|
return _withselector.useSyncExternalStoreWithSelector.call(void 0,
|
|
182
254
|
subscribe,
|
|
@@ -199,8 +271,8 @@ function createRoomContext(client) {
|
|
|
199
271
|
}
|
|
200
272
|
function useCanUndo() {
|
|
201
273
|
const room = useRoom();
|
|
202
|
-
const [canUndo, setCanUndo] =
|
|
203
|
-
|
|
274
|
+
const [canUndo, setCanUndo] = React2.useState(room.history.canUndo);
|
|
275
|
+
React2.useEffect(
|
|
204
276
|
() => room.events.history.subscribe(({ canUndo: canUndo2 }) => setCanUndo(canUndo2)),
|
|
205
277
|
[room]
|
|
206
278
|
);
|
|
@@ -208,8 +280,8 @@ function createRoomContext(client) {
|
|
|
208
280
|
}
|
|
209
281
|
function useCanRedo() {
|
|
210
282
|
const room = useRoom();
|
|
211
|
-
const [canRedo, setCanRedo] =
|
|
212
|
-
|
|
283
|
+
const [canRedo, setCanRedo] = React2.useState(room.history.canRedo);
|
|
284
|
+
React2.useEffect(
|
|
213
285
|
() => room.events.history.subscribe(({ canRedo: canRedo2 }) => setCanRedo(canRedo2)),
|
|
214
286
|
[room]
|
|
215
287
|
);
|
|
@@ -222,7 +294,7 @@ function createRoomContext(client) {
|
|
|
222
294
|
const room = useRoom();
|
|
223
295
|
const root = useMutableStorageRoot();
|
|
224
296
|
const rerender = useRerender();
|
|
225
|
-
|
|
297
|
+
React2.useEffect(() => {
|
|
226
298
|
if (root == null) {
|
|
227
299
|
return;
|
|
228
300
|
}
|
|
@@ -263,15 +335,15 @@ function createRoomContext(client) {
|
|
|
263
335
|
const room = useRoom();
|
|
264
336
|
const rootOrNull = useMutableStorageRoot();
|
|
265
337
|
const selector = maybeSelector != null ? maybeSelector : identity;
|
|
266
|
-
const wrappedSelector =
|
|
338
|
+
const wrappedSelector = React2.useCallback(
|
|
267
339
|
(rootOrNull2) => rootOrNull2 !== null ? selector(rootOrNull2) : null,
|
|
268
340
|
[selector]
|
|
269
341
|
);
|
|
270
|
-
const subscribe =
|
|
342
|
+
const subscribe = React2.useCallback(
|
|
271
343
|
(onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop,
|
|
272
344
|
[room, rootOrNull]
|
|
273
345
|
);
|
|
274
|
-
const getSnapshot =
|
|
346
|
+
const getSnapshot = React2.useCallback(() => {
|
|
275
347
|
if (rootOrNull === null) {
|
|
276
348
|
return null;
|
|
277
349
|
} else {
|
|
@@ -280,7 +352,7 @@ function createRoomContext(client) {
|
|
|
280
352
|
return imm;
|
|
281
353
|
}
|
|
282
354
|
}, [rootOrNull]);
|
|
283
|
-
const getServerSnapshot =
|
|
355
|
+
const getServerSnapshot = React2.useCallback(() => null, []);
|
|
284
356
|
return _withselector.useSyncExternalStoreWithSelector.call(void 0,
|
|
285
357
|
subscribe,
|
|
286
358
|
getSnapshot,
|
|
@@ -320,7 +392,7 @@ function createRoomContext(client) {
|
|
|
320
392
|
const room = useRoom();
|
|
321
393
|
const root = useMutableStorageRoot();
|
|
322
394
|
const setMyPresence = room.updatePresence;
|
|
323
|
-
return
|
|
395
|
+
return React2.useMemo(
|
|
324
396
|
() => {
|
|
325
397
|
if (root !== null) {
|
|
326
398
|
const mutationCtx = {
|
|
@@ -366,6 +438,25 @@ function createRoomContext(client) {
|
|
|
366
438
|
isEqual
|
|
367
439
|
);
|
|
368
440
|
}
|
|
441
|
+
function useOtherIdsSuspense(itemSelector, isEqual) {
|
|
442
|
+
useSuspendUntilPresenceLoaded();
|
|
443
|
+
return useOtherIds(
|
|
444
|
+
itemSelector,
|
|
445
|
+
isEqual
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
function useOtherSuspense(connectionId, selector, isEqual) {
|
|
449
|
+
useSuspendUntilPresenceLoaded();
|
|
450
|
+
return useOther(
|
|
451
|
+
connectionId,
|
|
452
|
+
selector,
|
|
453
|
+
isEqual
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
function useLegacyKeySuspense(key) {
|
|
457
|
+
useSuspendUntilStorageLoaded();
|
|
458
|
+
return useLegacyKey(key);
|
|
459
|
+
}
|
|
369
460
|
return {
|
|
370
461
|
RoomProvider,
|
|
371
462
|
useBatch,
|
|
@@ -377,6 +468,8 @@ function createRoomContext(client) {
|
|
|
377
468
|
useHistory,
|
|
378
469
|
useMyPresence,
|
|
379
470
|
useOthers,
|
|
471
|
+
useOtherIds,
|
|
472
|
+
useOther,
|
|
380
473
|
useRedo,
|
|
381
474
|
useRoom,
|
|
382
475
|
useSelf,
|
|
@@ -392,10 +485,20 @@ function createRoomContext(client) {
|
|
|
392
485
|
suspense: {
|
|
393
486
|
useStorage: useStorageSuspense,
|
|
394
487
|
useSelf: useSelfSuspense,
|
|
395
|
-
useOthers: useOthersSuspense
|
|
488
|
+
useOthers: useOthersSuspense,
|
|
489
|
+
useOtherIds: useOtherIdsSuspense,
|
|
490
|
+
useOther: useOtherSuspense,
|
|
491
|
+
useList: useLegacyKeySuspense,
|
|
492
|
+
useMap: useLegacyKeySuspense,
|
|
493
|
+
useObject: useLegacyKeySuspense
|
|
396
494
|
}
|
|
397
495
|
};
|
|
398
496
|
}
|
|
399
497
|
|
|
498
|
+
// src/index.ts
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
400
503
|
|
|
401
|
-
exports.createRoomContext = createRoomContext;
|
|
504
|
+
exports.ClientSideSuspense = ClientSideSuspense; exports.createRoomContext = createRoomContext; exports.shallow = _client.shallow;
|
package/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/react",
|
|
3
|
-
"version": "0.18.0-
|
|
3
|
+
"version": "0.18.0-beta1",
|
|
4
4
|
"description": "A set of React hooks and providers to use Liveblocks declaratively.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.mjs",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"use-sync-external-store": "^1.2.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@liveblocks/client": "0.18.0-
|
|
30
|
+
"@liveblocks/client": "0.18.0-beta1",
|
|
31
31
|
"react": "^16.14.0 || ^17 || ^18"
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|