@liveblocks/react 1.1.5-test3 → 1.1.5-test4
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/index.d.mts +815 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +584 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +16 -3
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { JsonObject, LsonObject, BaseUserMeta, LiveObject, User, Others, Json, Room, Status, BroadcastOptions, LostConnectionEvent, History, Client } from '@liveblocks/client';
|
|
3
|
+
export { Json, JsonObject, shallow } from '@liveblocks/client';
|
|
4
|
+
import { ToImmutable, Resolve, RoomInitializers } from '@liveblocks/core';
|
|
5
|
+
|
|
6
|
+
declare type Props = {
|
|
7
|
+
fallback: NonNullable<ReactNode> | null;
|
|
8
|
+
children: () => ReactNode | undefined;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Almost like a normal <Suspense> component, except that for server-side
|
|
12
|
+
* renders, the fallback will be used.
|
|
13
|
+
*
|
|
14
|
+
* The child props will have to be provided in a function, i.e. change:
|
|
15
|
+
*
|
|
16
|
+
* <Suspense fallback={<Loading />}>
|
|
17
|
+
* <MyRealComponent a={1} />
|
|
18
|
+
* </Suspense>
|
|
19
|
+
*
|
|
20
|
+
* To:
|
|
21
|
+
*
|
|
22
|
+
* <ClientSideSuspense fallback={<Loading />}>
|
|
23
|
+
* {() => <MyRealComponent a={1} />}
|
|
24
|
+
* </ClientSideSuspense>
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
declare function ClientSideSuspense(props: Props): ReactElement;
|
|
28
|
+
|
|
29
|
+
declare type RoomProviderProps<TPresence extends JsonObject, TStorage extends LsonObject> = Resolve<{
|
|
30
|
+
/**
|
|
31
|
+
* The id of the room you want to connect to
|
|
32
|
+
*/
|
|
33
|
+
id: string;
|
|
34
|
+
children: React.ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* Whether or not the room should connect to Liveblocks servers
|
|
37
|
+
* when the RoomProvider is rendered.
|
|
38
|
+
*
|
|
39
|
+
* By default equals to `typeof window !== "undefined"`,
|
|
40
|
+
* meaning the RoomProvider tries to connect to Liveblocks servers
|
|
41
|
+
* only on the client side.
|
|
42
|
+
*/
|
|
43
|
+
shouldInitiallyConnect?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* If you're on React 17 or lower, pass in a reference to
|
|
46
|
+
* `ReactDOM.unstable_batchedUpdates` or
|
|
47
|
+
* `ReactNative.unstable_batchedUpdates` here.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* import { unstable_batchedUpdates } from "react-dom";
|
|
51
|
+
*
|
|
52
|
+
* <RoomProvider ... unstable_batchedUpdates={unstable_batchedUpdates} />
|
|
53
|
+
*
|
|
54
|
+
* This will prevent you from running into the so-called "stale props"
|
|
55
|
+
* and/or "zombie child" problem that React 17 and lower can suffer from.
|
|
56
|
+
* Not necessary when you're on React v18 or later.
|
|
57
|
+
*/
|
|
58
|
+
unstable_batchedUpdates?: (cb: () => void) => void;
|
|
59
|
+
} & RoomInitializers<TPresence, TStorage>>;
|
|
60
|
+
/**
|
|
61
|
+
* For any function type, returns a similar function type, but without the
|
|
62
|
+
* first argument.
|
|
63
|
+
*/
|
|
64
|
+
declare type OmitFirstArg<F> = F extends (first: any, ...rest: infer A) => infer R ? (...args: A) => R : never;
|
|
65
|
+
declare type MutationContext<TPresence extends JsonObject, TStorage extends LsonObject, TUserMeta extends BaseUserMeta> = {
|
|
66
|
+
storage: LiveObject<TStorage>;
|
|
67
|
+
self: User<TPresence, TUserMeta>;
|
|
68
|
+
others: Others<TPresence, TUserMeta>;
|
|
69
|
+
setMyPresence: (patch: Partial<TPresence>, options?: {
|
|
70
|
+
addToHistory: boolean;
|
|
71
|
+
}) => void;
|
|
72
|
+
};
|
|
73
|
+
declare type RoomContextBundle<TPresence extends JsonObject, TStorage extends LsonObject, TUserMeta extends BaseUserMeta, TRoomEvent extends Json> = {
|
|
74
|
+
/**
|
|
75
|
+
* You normally don't need to directly interact with the RoomContext, but
|
|
76
|
+
* it can be necessary if you're building an advanced app where you need to
|
|
77
|
+
* set up a context bridge between two React renderers.
|
|
78
|
+
*/
|
|
79
|
+
RoomContext: React.Context<Room<TPresence, TStorage, TUserMeta, TRoomEvent> | null>;
|
|
80
|
+
/**
|
|
81
|
+
* Makes a Room available in the component hierarchy below.
|
|
82
|
+
* When this component is unmounted, the current user leave the room.
|
|
83
|
+
* That means that you can't have 2 RoomProvider with the same room id in your react tree.
|
|
84
|
+
*/
|
|
85
|
+
RoomProvider(props: RoomProviderProps<TPresence, TStorage>): JSX.Element;
|
|
86
|
+
/**
|
|
87
|
+
* Returns the Room of the nearest RoomProvider above in the React component
|
|
88
|
+
* tree.
|
|
89
|
+
*/
|
|
90
|
+
useRoom(): Room<TPresence, TStorage, TUserMeta, TRoomEvent>;
|
|
91
|
+
/**
|
|
92
|
+
* Returns the current connection status for the Room, and triggers
|
|
93
|
+
* a re-render whenever it changes. Can be used to render a status badge.
|
|
94
|
+
*/
|
|
95
|
+
useStatus(): Status;
|
|
96
|
+
/**
|
|
97
|
+
* Returns a function that batches modifications made during the given function.
|
|
98
|
+
* All the modifications are sent to other clients in a single message.
|
|
99
|
+
* All the modifications are merged in a single history item (undo/redo).
|
|
100
|
+
* All the subscribers are called only after the batch is over.
|
|
101
|
+
*/
|
|
102
|
+
useBatch<T>(): (callback: () => T) => T;
|
|
103
|
+
/**
|
|
104
|
+
* Returns a callback that lets you broadcast custom events to other users in the room
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* const broadcast = useBroadcastEvent();
|
|
108
|
+
*
|
|
109
|
+
* broadcast({ type: "CUSTOM_EVENT", data: { x: 0, y: 0 } });
|
|
110
|
+
*/
|
|
111
|
+
useBroadcastEvent(): (event: TRoomEvent, options?: BroadcastOptions) => void;
|
|
112
|
+
/**
|
|
113
|
+
* Get informed when reconnecting to the Liveblocks servers is taking
|
|
114
|
+
* longer than usual. This typically is a sign of a client that has lost
|
|
115
|
+
* internet connectivity.
|
|
116
|
+
*
|
|
117
|
+
* This isn't problematic (because the Liveblocks client is still trying to
|
|
118
|
+
* reconnect), but it's typically a good idea to inform users about it if
|
|
119
|
+
* the connection takes too long to recover.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* useLostConnectionListener(event => {
|
|
123
|
+
* if (event === 'lost') {
|
|
124
|
+
* toast.warn('Reconnecting to the Liveblocks servers is taking longer than usual...')
|
|
125
|
+
* } else if (event === 'failed') {
|
|
126
|
+
* toast.warn('Reconnecting to the Liveblocks servers failed.')
|
|
127
|
+
* } else if (event === 'restored') {
|
|
128
|
+
* toast.clear();
|
|
129
|
+
* }
|
|
130
|
+
* })
|
|
131
|
+
*/
|
|
132
|
+
useLostConnectionListener(callback: (event: LostConnectionEvent) => void): void;
|
|
133
|
+
/**
|
|
134
|
+
* useErrorListener is a react hook that lets you react to potential room connection errors.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* useErrorListener(er => {
|
|
138
|
+
* console.error(er);
|
|
139
|
+
* })
|
|
140
|
+
*/
|
|
141
|
+
useErrorListener(callback: (err: Error) => void): void;
|
|
142
|
+
/**
|
|
143
|
+
* useEventListener is a react hook that lets you react to event broadcasted by other users in the room.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* useEventListener(({ connectionId, event }) => {
|
|
147
|
+
* if (event.type === "CUSTOM_EVENT") {
|
|
148
|
+
* // Do something
|
|
149
|
+
* }
|
|
150
|
+
* });
|
|
151
|
+
*/
|
|
152
|
+
useEventListener(callback: (eventData: {
|
|
153
|
+
connectionId: number;
|
|
154
|
+
event: TRoomEvent;
|
|
155
|
+
}) => void): void;
|
|
156
|
+
/**
|
|
157
|
+
* Returns the room.history
|
|
158
|
+
*/
|
|
159
|
+
useHistory(): History;
|
|
160
|
+
/**
|
|
161
|
+
* Returns a function that undoes the last operation executed by the current client.
|
|
162
|
+
* It does not impact operations made by other clients.
|
|
163
|
+
*/
|
|
164
|
+
useUndo(): () => void;
|
|
165
|
+
/**
|
|
166
|
+
* Returns a function that redoes the last operation executed by the current client.
|
|
167
|
+
* It does not impact operations made by other clients.
|
|
168
|
+
*/
|
|
169
|
+
useRedo(): () => void;
|
|
170
|
+
/**
|
|
171
|
+
* Returns whether there are any operations to undo.
|
|
172
|
+
*/
|
|
173
|
+
useCanUndo(): boolean;
|
|
174
|
+
/**
|
|
175
|
+
* Returns whether there are any operations to redo.
|
|
176
|
+
*/
|
|
177
|
+
useCanRedo(): boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Returns the LiveList associated with the provided key.
|
|
180
|
+
* The hook triggers a re-render if the LiveList is updated, however it does not triggers a re-render if a nested CRDT is updated.
|
|
181
|
+
*
|
|
182
|
+
* @param key The storage key associated with the LiveList
|
|
183
|
+
* @returns null while the storage is loading, otherwise, returns the LiveList associated to the storage
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* const animals = useList("animals"); // e.g. [] or ["🦁", "🐍", "🦍"]
|
|
187
|
+
*/
|
|
188
|
+
useList<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey] | null;
|
|
189
|
+
/**
|
|
190
|
+
* Returns the LiveMap associated with the provided key. If the LiveMap does not exist, a new empty LiveMap will be created.
|
|
191
|
+
* The hook triggers a re-render if the LiveMap is updated, however it does not triggers a re-render if a nested CRDT is updated.
|
|
192
|
+
*
|
|
193
|
+
* @param key The storage key associated with the LiveMap
|
|
194
|
+
* @returns null while the storage is loading, otherwise, returns the LiveMap associated to the storage
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* const shapesById = useMap("shapes");
|
|
198
|
+
*/
|
|
199
|
+
useMap<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey] | null;
|
|
200
|
+
/**
|
|
201
|
+
* Returns the LiveObject associated with the provided key.
|
|
202
|
+
* The hook triggers a re-render if the LiveObject is updated, however it does not triggers a re-render if a nested CRDT is updated.
|
|
203
|
+
*
|
|
204
|
+
* @param key The storage key associated with the LiveObject
|
|
205
|
+
* @returns null while the storage is loading, otherwise, returns the LveObject associated to the storage
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* const object = useObject("obj");
|
|
209
|
+
*/
|
|
210
|
+
useObject<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey] | null;
|
|
211
|
+
/**
|
|
212
|
+
* Returns the mutable (!) Storage root. This hook exists for
|
|
213
|
+
* backward-compatible reasons.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* const [root] = useStorageRoot();
|
|
217
|
+
*/
|
|
218
|
+
useStorageRoot(): [root: LiveObject<TStorage> | null];
|
|
219
|
+
/**
|
|
220
|
+
* Extract arbitrary data from the Liveblocks Storage state, using an
|
|
221
|
+
* arbitrary selector function.
|
|
222
|
+
*
|
|
223
|
+
* The selector function will get re-evaluated any time something changes in
|
|
224
|
+
* Storage. The value returned by your selector function will also be the
|
|
225
|
+
* value returned by the hook.
|
|
226
|
+
*
|
|
227
|
+
* The `root` value that gets passed to your selector function is
|
|
228
|
+
* a immutable/readonly version of your Liveblocks storage root.
|
|
229
|
+
*
|
|
230
|
+
* The component that uses this hook will automatically re-render if the
|
|
231
|
+
* returned value changes.
|
|
232
|
+
*
|
|
233
|
+
* By default `useStorage()` uses strict `===` to check for equality. Take
|
|
234
|
+
* extra care when returning a computed object or list, for example when you
|
|
235
|
+
* return the result of a .map() or .filter() call from the selector. In
|
|
236
|
+
* those cases, you'll probably want to use a `shallow` comparison check.
|
|
237
|
+
*/
|
|
238
|
+
useStorage<T>(selector: (root: ToImmutable<TStorage>) => T, isEqual?: (prev: T | null, curr: T | null) => boolean): T | null;
|
|
239
|
+
/**
|
|
240
|
+
* Gets the current user once it is connected to the room.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* const me = useSelf();
|
|
244
|
+
* const { x, y } = me.presence.cursor;
|
|
245
|
+
*/
|
|
246
|
+
useSelf(): User<TPresence, TUserMeta> | null;
|
|
247
|
+
/**
|
|
248
|
+
* Extract arbitrary data based on the current user.
|
|
249
|
+
*
|
|
250
|
+
* The selector function will get re-evaluated any time your presence data
|
|
251
|
+
* changes.
|
|
252
|
+
*
|
|
253
|
+
* The component that uses this hook will automatically re-render if your
|
|
254
|
+
* selector function returns a different value from its previous run.
|
|
255
|
+
*
|
|
256
|
+
* By default `useSelf()` uses strict `===` to check for equality. Take extra
|
|
257
|
+
* care when returning a computed object or list, for example when you return
|
|
258
|
+
* the result of a .map() or .filter() call from the selector. In those
|
|
259
|
+
* cases, you'll probably want to use a `shallow` comparison check.
|
|
260
|
+
*
|
|
261
|
+
* Will return `null` while Liveblocks isn't connected to a room yet.
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* const cursor = useSelf(me => me.presence.cursor);
|
|
265
|
+
* if (cursor !== null) {
|
|
266
|
+
* const { x, y } = cursor;
|
|
267
|
+
* }
|
|
268
|
+
*
|
|
269
|
+
*/
|
|
270
|
+
useSelf<T>(selector: (me: User<TPresence, TUserMeta>) => T, isEqual?: (prev: T, curr: T) => boolean): T | null;
|
|
271
|
+
/**
|
|
272
|
+
* Returns the presence of the current user of the current room, and a function to update it.
|
|
273
|
+
* It is different from the setState function returned by the useState hook from React.
|
|
274
|
+
* You don't need to pass the full presence object to update it.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* const [myPresence, updateMyPresence] = useMyPresence();
|
|
278
|
+
* updateMyPresence({ x: 0 });
|
|
279
|
+
* updateMyPresence({ y: 0 });
|
|
280
|
+
*
|
|
281
|
+
* // At the next render, "myPresence" will be equal to "{ x: 0, y: 0 }"
|
|
282
|
+
*/
|
|
283
|
+
useMyPresence(): [
|
|
284
|
+
TPresence,
|
|
285
|
+
(patch: Partial<TPresence>, options?: {
|
|
286
|
+
addToHistory: boolean;
|
|
287
|
+
}) => void
|
|
288
|
+
];
|
|
289
|
+
/**
|
|
290
|
+
* Returns an object that lets you get information about all the users
|
|
291
|
+
* currently connected in the room.
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* const others = useOthers();
|
|
295
|
+
*
|
|
296
|
+
* // Example to map all cursors in JSX
|
|
297
|
+
* return (
|
|
298
|
+
* <>
|
|
299
|
+
* {others.map((user) => {
|
|
300
|
+
* if (user.presence.cursor == null) {
|
|
301
|
+
* return null;
|
|
302
|
+
* }
|
|
303
|
+
* return <Cursor key={user.connectionId} cursor={user.presence.cursor} />
|
|
304
|
+
* })}
|
|
305
|
+
* </>
|
|
306
|
+
* )
|
|
307
|
+
*/
|
|
308
|
+
useOthers(): Others<TPresence, TUserMeta>;
|
|
309
|
+
/**
|
|
310
|
+
* Extract arbitrary data based on all the users currently connected in the
|
|
311
|
+
* room (except yourself).
|
|
312
|
+
*
|
|
313
|
+
* The selector function will get re-evaluated any time a user enters or
|
|
314
|
+
* leaves the room, as well as whenever their presence data changes.
|
|
315
|
+
*
|
|
316
|
+
* The component that uses this hook will automatically re-render if your
|
|
317
|
+
* selector function returns a different value from its previous run.
|
|
318
|
+
*
|
|
319
|
+
* By default `useOthers()` uses strict `===` to check for equality. Take
|
|
320
|
+
* extra care when returning a computed object or list, for example when you
|
|
321
|
+
* return the result of a .map() or .filter() call from the selector. In
|
|
322
|
+
* those cases, you'll probably want to use a `shallow` comparison check.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* const avatars = useOthers(users => users.map(u => u.info.avatar), shallow);
|
|
326
|
+
* const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow);
|
|
327
|
+
* const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping));
|
|
328
|
+
*
|
|
329
|
+
*/
|
|
330
|
+
useOthers<T>(selector: (others: Others<TPresence, TUserMeta>) => T, isEqual?: (prev: T, curr: T) => boolean): T;
|
|
331
|
+
/**
|
|
332
|
+
* Returns an array of connection IDs. This matches the values you'll get by
|
|
333
|
+
* using the `useOthers()` hook.
|
|
334
|
+
*
|
|
335
|
+
* Roughly equivalent to:
|
|
336
|
+
* useOthers((others) => others.map(other => other.connectionId), shallow)
|
|
337
|
+
*
|
|
338
|
+
* This is useful in particular to implement efficiently rendering components
|
|
339
|
+
* for each user in the room, e.g. cursors.
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* const ids = useOthersConnectionIds();
|
|
343
|
+
* // [2, 4, 7]
|
|
344
|
+
*/
|
|
345
|
+
useOthersConnectionIds(): readonly number[];
|
|
346
|
+
/**
|
|
347
|
+
* Related to useOthers(), but optimized for selecting only "subsets" of
|
|
348
|
+
* others. This is useful for performance reasons in particular, because
|
|
349
|
+
* selecting only a subset of users also means limiting the number of
|
|
350
|
+
* re-renders that will be triggered.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* const avatars = useOthersMapped(user => user.info.avatar);
|
|
354
|
+
* // ^^^^^^^
|
|
355
|
+
* // { connectionId: number; data: string }[]
|
|
356
|
+
*
|
|
357
|
+
* The selector function you pass to useOthersMapped() is called an "item
|
|
358
|
+
* selector", and operates on a single user at a time. If you provide an
|
|
359
|
+
* (optional) "item comparison" function, it will be used to compare each
|
|
360
|
+
* item pairwise.
|
|
361
|
+
*
|
|
362
|
+
* For example, to select multiple properties:
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* const avatarsAndCursors = useOthersMapped(
|
|
366
|
+
* user => [u.info.avatar, u.presence.cursor],
|
|
367
|
+
* shallow, // 👈
|
|
368
|
+
* );
|
|
369
|
+
*/
|
|
370
|
+
useOthersMapped<T>(itemSelector: (other: User<TPresence, TUserMeta>) => T, itemIsEqual?: (prev: T, curr: T) => boolean): ReadonlyArray<readonly [connectionId: number, data: T]>;
|
|
371
|
+
/**
|
|
372
|
+
* Given a connection ID (as obtained by using `useOthersConnectionIds`), you
|
|
373
|
+
* can call this selector deep down in your component stack to only have the
|
|
374
|
+
* component re-render if properties for this particular user change.
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* // Returns only the selected values re-renders whenever that selection changes)
|
|
378
|
+
* const { x, y } = useOther(2, user => user.presence.cursor);
|
|
379
|
+
*/
|
|
380
|
+
useOther<T>(connectionId: number, selector: (other: User<TPresence, TUserMeta>) => T, isEqual?: (prev: T, curr: T) => boolean): T;
|
|
381
|
+
/**
|
|
382
|
+
* useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.
|
|
383
|
+
* If you don't use the current user presence in your component, but you need to update it (e.g. live cursor), it's better to use useUpdateMyPresence to avoid unnecessary renders.
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* const updateMyPresence = useUpdateMyPresence();
|
|
387
|
+
* updateMyPresence({ x: 0 });
|
|
388
|
+
* updateMyPresence({ y: 0 });
|
|
389
|
+
*
|
|
390
|
+
* // At the next render, the presence of the current user will be equal to "{ x: 0, y: 0 }"
|
|
391
|
+
*/
|
|
392
|
+
useUpdateMyPresence(): (patch: Partial<TPresence>, options?: {
|
|
393
|
+
addToHistory: boolean;
|
|
394
|
+
}) => void;
|
|
395
|
+
/**
|
|
396
|
+
* Create a callback function that lets you mutate Liveblocks state.
|
|
397
|
+
*
|
|
398
|
+
* The first argument that gets passed into your callback will be a "mutation
|
|
399
|
+
* context", which exposes the following:
|
|
400
|
+
*
|
|
401
|
+
* - `root` - The mutable Storage root.
|
|
402
|
+
* You can normal mutation on Live structures with this, for
|
|
403
|
+
* example: root.get('layers').get('layer1').set('fill', 'red')
|
|
404
|
+
*
|
|
405
|
+
* - `setMyPresence` - Call this with a new (partial) Presence value.
|
|
406
|
+
*
|
|
407
|
+
* - `self` - A read-only version of the latest self, if you need it to
|
|
408
|
+
* compute the next state.
|
|
409
|
+
*
|
|
410
|
+
* - `others` - A read-only version of the latest others list, if you need
|
|
411
|
+
* it to compute the next state.
|
|
412
|
+
*
|
|
413
|
+
* useMutation is like React's useCallback, except that the first argument
|
|
414
|
+
* that gets passed into your callback will be a "mutation context".
|
|
415
|
+
*
|
|
416
|
+
* If you want get access to the immutable root somewhere in your mutation,
|
|
417
|
+
* you can use `root.ToImmutable()`.
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* const fillLayers = useMutation(
|
|
421
|
+
* ({ root }, color: Color) => {
|
|
422
|
+
* ...
|
|
423
|
+
* },
|
|
424
|
+
* [],
|
|
425
|
+
* );
|
|
426
|
+
*
|
|
427
|
+
* fillLayers('red');
|
|
428
|
+
*
|
|
429
|
+
* const deleteLayers = useMutation(
|
|
430
|
+
* ({ root }) => {
|
|
431
|
+
* ...
|
|
432
|
+
* },
|
|
433
|
+
* [],
|
|
434
|
+
* );
|
|
435
|
+
*
|
|
436
|
+
* deleteLayers();
|
|
437
|
+
*/
|
|
438
|
+
useMutation<F extends (context: MutationContext<TPresence, TStorage, TUserMeta>, ...args: any[]) => any>(callback: F, deps: readonly unknown[]): OmitFirstArg<F>;
|
|
439
|
+
suspense: {
|
|
440
|
+
/**
|
|
441
|
+
* You normally don't need to directly interact with the RoomContext, but
|
|
442
|
+
* it can be necessary if you're building an advanced app where you need to
|
|
443
|
+
* set up a context bridge between two React renderers.
|
|
444
|
+
*/
|
|
445
|
+
RoomContext: React.Context<Room<TPresence, TStorage, TUserMeta, TRoomEvent> | null>;
|
|
446
|
+
/**
|
|
447
|
+
* Makes a Room available in the component hierarchy below.
|
|
448
|
+
* When this component is unmounted, the current user leave the room.
|
|
449
|
+
* That means that you can't have 2 RoomProvider with the same room id in your react tree.
|
|
450
|
+
*/
|
|
451
|
+
RoomProvider(props: RoomProviderProps<TPresence, TStorage>): JSX.Element;
|
|
452
|
+
/**
|
|
453
|
+
* Returns the Room of the nearest RoomProvider above in the React component
|
|
454
|
+
* tree.
|
|
455
|
+
*/
|
|
456
|
+
useRoom(): Room<TPresence, TStorage, TUserMeta, TRoomEvent>;
|
|
457
|
+
/**
|
|
458
|
+
* Returns the current connection status for the Room, and triggers
|
|
459
|
+
* a re-render whenever it changes. Can be used to render a status badge.
|
|
460
|
+
*/
|
|
461
|
+
useStatus(): Status;
|
|
462
|
+
/**
|
|
463
|
+
* Returns a function that batches modifications made during the given function.
|
|
464
|
+
* All the modifications are sent to other clients in a single message.
|
|
465
|
+
* All the modifications are merged in a single history item (undo/redo).
|
|
466
|
+
* All the subscribers are called only after the batch is over.
|
|
467
|
+
*/
|
|
468
|
+
useBatch<T>(): (callback: () => T) => T;
|
|
469
|
+
/**
|
|
470
|
+
* Returns a callback that lets you broadcast custom events to other users in the room
|
|
471
|
+
*
|
|
472
|
+
* @example
|
|
473
|
+
* const broadcast = useBroadcastEvent();
|
|
474
|
+
*
|
|
475
|
+
* broadcast({ type: "CUSTOM_EVENT", data: { x: 0, y: 0 } });
|
|
476
|
+
*/
|
|
477
|
+
useBroadcastEvent(): (event: TRoomEvent, options?: BroadcastOptions) => void;
|
|
478
|
+
/**
|
|
479
|
+
* Get informed when reconnecting to the Liveblocks servers is taking
|
|
480
|
+
* longer than usual. This typically is a sign of a client that has lost
|
|
481
|
+
* internet connectivity.
|
|
482
|
+
*
|
|
483
|
+
* This isn't problematic (because the Liveblocks client is still trying to
|
|
484
|
+
* reconnect), but it's typically a good idea to inform users about it if
|
|
485
|
+
* the connection takes too long to recover.
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* useLostConnectionListener(event => {
|
|
489
|
+
* if (event === 'lost') {
|
|
490
|
+
* toast.warn('Reconnecting to the Liveblocks servers is taking longer than usual...')
|
|
491
|
+
* } else if (event === 'failed') {
|
|
492
|
+
* toast.warn('Reconnecting to the Liveblocks servers failed.')
|
|
493
|
+
* } else if (event === 'restored') {
|
|
494
|
+
* toast.clear();
|
|
495
|
+
* }
|
|
496
|
+
* })
|
|
497
|
+
*/
|
|
498
|
+
useLostConnectionListener(callback: (event: LostConnectionEvent) => void): void;
|
|
499
|
+
/**
|
|
500
|
+
* useErrorListener is a react hook that lets you react to potential room connection errors.
|
|
501
|
+
*
|
|
502
|
+
* @example
|
|
503
|
+
* useErrorListener(er => {
|
|
504
|
+
* console.error(er);
|
|
505
|
+
* })
|
|
506
|
+
*/
|
|
507
|
+
useErrorListener(callback: (err: Error) => void): void;
|
|
508
|
+
/**
|
|
509
|
+
* useEventListener is a react hook that lets you react to event broadcasted by other users in the room.
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* useEventListener(({ connectionId, event }) => {
|
|
513
|
+
* if (event.type === "CUSTOM_EVENT") {
|
|
514
|
+
* // Do something
|
|
515
|
+
* }
|
|
516
|
+
* });
|
|
517
|
+
*/
|
|
518
|
+
useEventListener(callback: (eventData: {
|
|
519
|
+
connectionId: number;
|
|
520
|
+
event: TRoomEvent;
|
|
521
|
+
}) => void): void;
|
|
522
|
+
/**
|
|
523
|
+
* Returns the room.history
|
|
524
|
+
*/
|
|
525
|
+
useHistory(): History;
|
|
526
|
+
/**
|
|
527
|
+
* Returns a function that undoes the last operation executed by the current client.
|
|
528
|
+
* It does not impact operations made by other clients.
|
|
529
|
+
*/
|
|
530
|
+
useUndo(): () => void;
|
|
531
|
+
/**
|
|
532
|
+
* Returns a function that redoes the last operation executed by the current client.
|
|
533
|
+
* It does not impact operations made by other clients.
|
|
534
|
+
*/
|
|
535
|
+
useRedo(): () => void;
|
|
536
|
+
/**
|
|
537
|
+
* Returns whether there are any operations to undo.
|
|
538
|
+
*/
|
|
539
|
+
useCanUndo(): boolean;
|
|
540
|
+
/**
|
|
541
|
+
* Returns whether there are any operations to redo.
|
|
542
|
+
*/
|
|
543
|
+
useCanRedo(): boolean;
|
|
544
|
+
/**
|
|
545
|
+
* Returns the mutable (!) Storage root. This hook exists for
|
|
546
|
+
* backward-compatible reasons.
|
|
547
|
+
*
|
|
548
|
+
* @example
|
|
549
|
+
* const [root] = useStorageRoot();
|
|
550
|
+
*/
|
|
551
|
+
useStorageRoot(): [root: LiveObject<TStorage> | null];
|
|
552
|
+
/**
|
|
553
|
+
* Extract arbitrary data from the Liveblocks Storage state, using an
|
|
554
|
+
* arbitrary selector function.
|
|
555
|
+
*
|
|
556
|
+
* The selector function will get re-evaluated any time something changes in
|
|
557
|
+
* Storage. The value returned by your selector function will also be the
|
|
558
|
+
* value returned by the hook.
|
|
559
|
+
*
|
|
560
|
+
* The `root` value that gets passed to your selector function is
|
|
561
|
+
* a immutable/readonly version of your Liveblocks storage root.
|
|
562
|
+
*
|
|
563
|
+
* The component that uses this hook will automatically re-render if the
|
|
564
|
+
* returned value changes.
|
|
565
|
+
*
|
|
566
|
+
* By default `useStorage()` uses strict `===` to check for equality. Take
|
|
567
|
+
* extra care when returning a computed object or list, for example when you
|
|
568
|
+
* return the result of a .map() or .filter() call from the selector. In
|
|
569
|
+
* those cases, you'll probably want to use a `shallow` comparison check.
|
|
570
|
+
*/
|
|
571
|
+
useStorage<T>(selector: (root: ToImmutable<TStorage>) => T, isEqual?: (prev: T, curr: T) => boolean): T;
|
|
572
|
+
/**
|
|
573
|
+
* Gets the current user once it is connected to the room.
|
|
574
|
+
*
|
|
575
|
+
* @example
|
|
576
|
+
* const me = useSelf();
|
|
577
|
+
* const { x, y } = me.presence.cursor;
|
|
578
|
+
*/
|
|
579
|
+
useSelf(): User<TPresence, TUserMeta>;
|
|
580
|
+
/**
|
|
581
|
+
* Extract arbitrary data based on the current user.
|
|
582
|
+
*
|
|
583
|
+
* The selector function will get re-evaluated any time your presence data
|
|
584
|
+
* changes.
|
|
585
|
+
*
|
|
586
|
+
* The component that uses this hook will automatically re-render if your
|
|
587
|
+
* selector function returns a different value from its previous run.
|
|
588
|
+
*
|
|
589
|
+
* By default `useSelf()` uses strict `===` to check for equality. Take extra
|
|
590
|
+
* care when returning a computed object or list, for example when you return
|
|
591
|
+
* the result of a .map() or .filter() call from the selector. In those
|
|
592
|
+
* cases, you'll probably want to use a `shallow` comparison check.
|
|
593
|
+
*
|
|
594
|
+
* Will return `null` while Liveblocks isn't connected to a room yet.
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* const cursor = useSelf(me => me.presence.cursor);
|
|
598
|
+
* if (cursor !== null) {
|
|
599
|
+
* const { x, y } = cursor;
|
|
600
|
+
* }
|
|
601
|
+
*
|
|
602
|
+
*/
|
|
603
|
+
useSelf<T>(selector: (me: User<TPresence, TUserMeta>) => T, isEqual?: (prev: T, curr: T) => boolean): T;
|
|
604
|
+
/**
|
|
605
|
+
* Returns the presence of the current user of the current room, and a function to update it.
|
|
606
|
+
* It is different from the setState function returned by the useState hook from React.
|
|
607
|
+
* You don't need to pass the full presence object to update it.
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* const [myPresence, updateMyPresence] = useMyPresence();
|
|
611
|
+
* updateMyPresence({ x: 0 });
|
|
612
|
+
* updateMyPresence({ y: 0 });
|
|
613
|
+
*
|
|
614
|
+
* // At the next render, "myPresence" will be equal to "{ x: 0, y: 0 }"
|
|
615
|
+
*/
|
|
616
|
+
useMyPresence(): [
|
|
617
|
+
TPresence,
|
|
618
|
+
(patch: Partial<TPresence>, options?: {
|
|
619
|
+
addToHistory: boolean;
|
|
620
|
+
}) => void
|
|
621
|
+
];
|
|
622
|
+
/**
|
|
623
|
+
* Returns an object that lets you get information about all the users
|
|
624
|
+
* currently connected in the room.
|
|
625
|
+
*
|
|
626
|
+
* @example
|
|
627
|
+
* const others = useOthers();
|
|
628
|
+
*
|
|
629
|
+
* // Example to map all cursors in JSX
|
|
630
|
+
* return (
|
|
631
|
+
* <>
|
|
632
|
+
* {others.map((user) => {
|
|
633
|
+
* if (user.presence.cursor == null) {
|
|
634
|
+
* return null;
|
|
635
|
+
* }
|
|
636
|
+
* return <Cursor key={user.connectionId} cursor={user.presence.cursor} />
|
|
637
|
+
* })}
|
|
638
|
+
* </>
|
|
639
|
+
* )
|
|
640
|
+
*/
|
|
641
|
+
useOthers(): Others<TPresence, TUserMeta>;
|
|
642
|
+
/**
|
|
643
|
+
* Extract arbitrary data based on all the users currently connected in the
|
|
644
|
+
* room (except yourself).
|
|
645
|
+
*
|
|
646
|
+
* The selector function will get re-evaluated any time a user enters or
|
|
647
|
+
* leaves the room, as well as whenever their presence data changes.
|
|
648
|
+
*
|
|
649
|
+
* The component that uses this hook will automatically re-render if your
|
|
650
|
+
* selector function returns a different value from its previous run.
|
|
651
|
+
*
|
|
652
|
+
* By default `useOthers()` uses strict `===` to check for equality. Take
|
|
653
|
+
* extra care when returning a computed object or list, for example when you
|
|
654
|
+
* return the result of a .map() or .filter() call from the selector. In
|
|
655
|
+
* those cases, you'll probably want to use a `shallow` comparison check.
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* const avatars = useOthers(users => users.map(u => u.info.avatar), shallow);
|
|
659
|
+
* const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow);
|
|
660
|
+
* const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping));
|
|
661
|
+
*
|
|
662
|
+
*/
|
|
663
|
+
useOthers<T>(selector: (others: Others<TPresence, TUserMeta>) => T, isEqual?: (prev: T, curr: T) => boolean): T;
|
|
664
|
+
/**
|
|
665
|
+
* Returns an array of connection IDs. This matches the values you'll get by
|
|
666
|
+
* using the `useOthers()` hook.
|
|
667
|
+
*
|
|
668
|
+
* Roughly equivalent to:
|
|
669
|
+
* useOthers((others) => others.map(other => other.connectionId), shallow)
|
|
670
|
+
*
|
|
671
|
+
* This is useful in particular to implement efficiently rendering components
|
|
672
|
+
* for each user in the room, e.g. cursors.
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* const ids = useOthersConnectionIds();
|
|
676
|
+
* // [2, 4, 7]
|
|
677
|
+
*/
|
|
678
|
+
useOthersConnectionIds(): readonly number[];
|
|
679
|
+
/**
|
|
680
|
+
* Related to useOthers(), but optimized for selecting only "subsets" of
|
|
681
|
+
* others. This is useful for performance reasons in particular, because
|
|
682
|
+
* selecting only a subset of users also means limiting the number of
|
|
683
|
+
* re-renders that will be triggered.
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* const avatars = useOthersMapped(user => user.info.avatar);
|
|
687
|
+
* // ^^^^^^^
|
|
688
|
+
* // { connectionId: number; data: string }[]
|
|
689
|
+
*
|
|
690
|
+
* The selector function you pass to useOthersMapped() is called an "item
|
|
691
|
+
* selector", and operates on a single user at a time. If you provide an
|
|
692
|
+
* (optional) "item comparison" function, it will be used to compare each
|
|
693
|
+
* item pairwise.
|
|
694
|
+
*
|
|
695
|
+
* For example, to select multiple properties:
|
|
696
|
+
*
|
|
697
|
+
* @example
|
|
698
|
+
* const avatarsAndCursors = useOthersMapped(
|
|
699
|
+
* user => [u.info.avatar, u.presence.cursor],
|
|
700
|
+
* shallow, // 👈
|
|
701
|
+
* );
|
|
702
|
+
*/
|
|
703
|
+
useOthersMapped<T>(itemSelector: (other: User<TPresence, TUserMeta>) => T, itemIsEqual?: (prev: T, curr: T) => boolean): ReadonlyArray<readonly [connectionId: number, data: T]>;
|
|
704
|
+
/**
|
|
705
|
+
* Given a connection ID (as obtained by using `useOthersConnectionIds`),
|
|
706
|
+
* you can call this selector deep down in your component stack to only
|
|
707
|
+
* have the component re-render if properties for this particular user
|
|
708
|
+
* change.
|
|
709
|
+
*
|
|
710
|
+
* @example
|
|
711
|
+
* // Returns only the selected values re-renders whenever that selection changes)
|
|
712
|
+
* const { x, y } = useOther(2, user => user.presence.cursor);
|
|
713
|
+
*/
|
|
714
|
+
useOther<T>(connectionId: number, selector: (other: User<TPresence, TUserMeta>) => T, isEqual?: (prev: T, curr: T) => boolean): T;
|
|
715
|
+
/**
|
|
716
|
+
* useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.
|
|
717
|
+
* If you don't use the current user presence in your component, but you need to update it (e.g. live cursor), it's better to use useUpdateMyPresence to avoid unnecessary renders.
|
|
718
|
+
*
|
|
719
|
+
* @example
|
|
720
|
+
* const updateMyPresence = useUpdateMyPresence();
|
|
721
|
+
* updateMyPresence({ x: 0 });
|
|
722
|
+
* updateMyPresence({ y: 0 });
|
|
723
|
+
*
|
|
724
|
+
* // At the next render, the presence of the current user will be equal to "{ x: 0, y: 0 }"
|
|
725
|
+
*/
|
|
726
|
+
useUpdateMyPresence(): (patch: Partial<TPresence>, options?: {
|
|
727
|
+
addToHistory: boolean;
|
|
728
|
+
}) => void;
|
|
729
|
+
/**
|
|
730
|
+
* Create a callback function that lets you mutate Liveblocks state.
|
|
731
|
+
*
|
|
732
|
+
* The first argument that gets passed into your callback will be
|
|
733
|
+
* a "mutation context", which exposes the following:
|
|
734
|
+
*
|
|
735
|
+
* - `root` - The mutable Storage root.
|
|
736
|
+
* You can normal mutation on Live structures with this, for
|
|
737
|
+
* example: root.get('layers').get('layer1').set('fill',
|
|
738
|
+
* 'red')
|
|
739
|
+
*
|
|
740
|
+
* - `setMyPresence` - Call this with a new (partial) Presence value.
|
|
741
|
+
*
|
|
742
|
+
* - `self` - A read-only version of the latest self, if you need it to
|
|
743
|
+
* compute the next state.
|
|
744
|
+
*
|
|
745
|
+
* - `others` - A read-only version of the latest others list, if you
|
|
746
|
+
* need it to compute the next state.
|
|
747
|
+
*
|
|
748
|
+
* useMutation is like React's useCallback, except that the first argument
|
|
749
|
+
* that gets passed into your callback will be a "mutation context".
|
|
750
|
+
*
|
|
751
|
+
* If you want get access to the immutable root somewhere in your mutation,
|
|
752
|
+
* you can use `root.ToImmutable()`.
|
|
753
|
+
*
|
|
754
|
+
* @example
|
|
755
|
+
* const fillLayers = useMutation(
|
|
756
|
+
* ({ root }, color: Color) => {
|
|
757
|
+
* ...
|
|
758
|
+
* },
|
|
759
|
+
* [],
|
|
760
|
+
* );
|
|
761
|
+
*
|
|
762
|
+
* fillLayers('red');
|
|
763
|
+
*
|
|
764
|
+
* const deleteLayers = useMutation(
|
|
765
|
+
* ({ root }) => {
|
|
766
|
+
* ...
|
|
767
|
+
* },
|
|
768
|
+
* [],
|
|
769
|
+
* );
|
|
770
|
+
*
|
|
771
|
+
* deleteLayers();
|
|
772
|
+
*/
|
|
773
|
+
useMutation<F extends (context: MutationContext<TPresence, TStorage, TUserMeta>, ...args: any[]) => any>(callback: F, deps: readonly unknown[]): OmitFirstArg<F>;
|
|
774
|
+
/**
|
|
775
|
+
* Returns the LiveList associated with the provided key. The hook triggers
|
|
776
|
+
* a re-render if the LiveList is updated, however it does not triggers
|
|
777
|
+
* a re-render if a nested CRDT is updated.
|
|
778
|
+
*
|
|
779
|
+
* @param key The storage key associated with the LiveList
|
|
780
|
+
* @returns null while the storage is loading, otherwise, returns the LiveList associated to the storage
|
|
781
|
+
*
|
|
782
|
+
* @example
|
|
783
|
+
* const animals = useList("animals"); // e.g. [] or ["🦁", "🐍", "🦍"]
|
|
784
|
+
*/
|
|
785
|
+
useList<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey];
|
|
786
|
+
/**
|
|
787
|
+
* Returns the LiveMap associated with the provided key. If the LiveMap
|
|
788
|
+
* does not exist, a new empty LiveMap will be created. The hook triggers
|
|
789
|
+
* a re-render if the LiveMap is updated, however it does not triggers
|
|
790
|
+
* a re-render if a nested CRDT is updated.
|
|
791
|
+
*
|
|
792
|
+
* @param key The storage key associated with the LiveMap
|
|
793
|
+
* @returns null while the storage is loading, otherwise, returns the LiveMap associated to the storage
|
|
794
|
+
*
|
|
795
|
+
* @example
|
|
796
|
+
* const shapesById = useMap("shapes");
|
|
797
|
+
*/
|
|
798
|
+
useMap<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey];
|
|
799
|
+
/**
|
|
800
|
+
* Returns the LiveObject associated with the provided key.
|
|
801
|
+
* The hook triggers a re-render if the LiveObject is updated, however it does not triggers a re-render if a nested CRDT is updated.
|
|
802
|
+
*
|
|
803
|
+
* @param key The storage key associated with the LiveObject
|
|
804
|
+
* @returns null while the storage is loading, otherwise, returns the LveObject associated to the storage
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* const object = useObject("obj");
|
|
808
|
+
*/
|
|
809
|
+
useObject<TKey extends Extract<keyof TStorage, string>>(key: TKey): TStorage[TKey];
|
|
810
|
+
};
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
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>;
|
|
814
|
+
|
|
815
|
+
export { ClientSideSuspense, MutationContext, createRoomContext };
|