@liveblocks/react 0.12.1 → 0.13.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 CHANGED
@@ -1,17 +1,45 @@
1
1
  <p align="center">
2
2
  <a href="https://liveblocks.io">
3
- <img src="https://liveblocks.io/icon-192x192.png" height="96">
3
+ <img src="https://liveblocks.io/images/blog/introducing-liveblocks.png">
4
4
  </a>
5
5
  </p>
6
6
 
7
- # [Liveblocks](https://liveblocks.io) · [![Twitter Follow](https://shields.io/twitter/follow/liveblocks?label=Follow)](https://twitter.com/liveblocks)
7
+ # Liveblocks · [![Twitter Follow](https://shields.io/twitter/follow/liveblocks?label=Follow)](https://twitter.com/liveblocks)
8
8
 
9
- Liveblocks helps you create performant and reliable collaborative experiences.
9
+ **At [Liveblocks](https://liveblocks.io), we’re building tools to help companies create world-class collaborative products that attract, engage and retain users.** This repository is a set of open-source packages for building performant and reliable multiplayer experiences.
10
10
 
11
- ## [Documentation](https://liveblocks.io/docs)
11
+ ## Installation
12
+
13
+ ```
14
+ npm install @liveblocks/react
15
+ ```
12
16
 
13
17
  ## Examples
14
18
 
15
- Try it live on [liveblocks.io](https://liveblocks.io/examples).
19
+ - Browse our gallery of collaborative UI patterns. [View examples gallery](https://liveblocks.io/examples)
20
+ - Explore and clone any of our open-source examples. [View code examples](https://github.com/liveblocks/liveblocks/tree/main/examples)
21
+
22
+ ## Documentation
23
+
24
+ [Read the documentation](https://liveblocks.io/docs) to start using Liveblocks.
25
+
26
+ ## Releases
27
+
28
+ For changelog, visit [https://github.com/liveblocks/liveblocks/releases](https://github.com/liveblocks/liveblocks/releases).
29
+
30
+ ## Authors
31
+
32
+ - Guillaume Salles ([@guillaume_slls](https://twitter.com/guillaume_slls)) - [Liveblocks](https://liveblocks.io)
33
+ - Olivier Foucherot ([@ofoucherot](https://twitter.com/ofoucherot)) - [Liveblocks](https://liveblocks.io)
34
+ - Steven Fabre ([@stevenfabre](https://twitter.com/stevenfabre)) - [Liveblocks](https://liveblocks.io)
35
+
36
+ ## Community
37
+
38
+ - [Discord](https://discord.gg/X4YWJuH9VY) - To get involved with the Liveblocks community, ask questions and share tips.
39
+ - [Twitter](https://twitter.com/liveblocks) - To receive updates, announcements, blog posts, and general Liveblocks tips.
40
+
41
+ ## License
42
+
43
+ Licensed under the Apache License 2.0, Copyright © 2021-present [Liveblocks](https://liveblocks.io).
16
44
 
17
- Clone one of our [examples](https://github.com/liveblocks/liveblocks/tree/main/examples).
45
+ See [LICENSE](../../LICENSE) for more information.
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Client, Others, Presence, LiveObject, LiveMap, User, LiveList } from "@liveblocks/client";
1
+ import { Client, Others, Presence, LiveObject, LiveMap, Room, User, LiveList } from "@liveblocks/client";
2
2
  import * as React from "react";
3
3
  declare type LiveblocksProviderProps = {
4
4
  children: React.ReactNode;
@@ -27,6 +27,10 @@ declare type RoomProviderProps<TStorageRoot> = {
27
27
  * That means that you can't have 2 RoomProvider with the same room id in your react tree.
28
28
  */
29
29
  export declare function RoomProvider<TStorageRoot>({ id, children, defaultPresence, defaultStorageRoot, }: RoomProviderProps<TStorageRoot>): JSX.Element;
30
+ /**
31
+ * Returns the room of the nearest RoomProvider above in the react component tree
32
+ */
33
+ export declare function useRoom(): Room;
30
34
  /**
31
35
  * Returns the presence of the current user of the current room, and a function to update it.
32
36
  * It is different from the setState function returned by the useState hook from React.
@@ -43,7 +47,9 @@ export declare function RoomProvider<TStorageRoot>({ id, children, defaultPresen
43
47
  */
44
48
  export declare function useMyPresence<T extends Presence>(): [
45
49
  T,
46
- (overrides: Partial<T>) => void
50
+ (overrides: Partial<T>, options?: {
51
+ addToHistory: boolean;
52
+ }) => void
47
53
  ];
48
54
  /**
49
55
  * useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.
@@ -58,7 +64,9 @@ export declare function useMyPresence<T extends Presence>(): [
58
64
  *
59
65
  * // At the next render, the presence of the current user will be equal to "{ x: 0, y: 0 }"
60
66
  */
61
- export declare function useUpdateMyPresence<T extends Presence>(): (overrides: Partial<T>) => void;
67
+ export declare function useUpdateMyPresence<T extends Presence>(): (overrides: Partial<T>, options?: {
68
+ addToHistory: boolean;
69
+ }) => void;
62
70
  /**
63
71
  * Returns an object that lets you get information about all the the users currently connected in the room.
64
72
  *
@@ -170,13 +178,26 @@ export declare function useList<TValue>(key: string, items?: TValue[] | undefine
170
178
  */
171
179
  export declare function useObject<TData>(key: string, initialData?: TData): LiveObject<TData> | null;
172
180
  /**
173
- * Returns a function that undo the last operation executed by the current client.
174
- * Undo does not impact operations made by other clients.
181
+ * Returns a function that undoes the last operation executed by the current client.
182
+ * It does not impact operations made by other clients.
175
183
  */
176
184
  export declare function useUndo(): () => void;
177
185
  /**
178
- * Returns a function that redo the last operation executed by the current client.
179
- * Redo does not impact operations made by other clients.
186
+ * Returns a function that redoes the last operation executed by the current client.
187
+ * It does not impact operations made by other clients.
180
188
  */
181
189
  export declare function useRedo(): () => void;
190
+ /**
191
+ * Returns a function that batches modifications made during the given function.
192
+ * All the modifications are sent to other clients in a single message.
193
+ * All the modifications are merged in a single history item (undo/redo).
194
+ * All the subscribers are called only after the batch is over.
195
+ */
196
+ export declare function useBatch(): (fn: () => void) => void;
197
+ export declare function useHistory(): {
198
+ undo: () => void;
199
+ redo: () => void;
200
+ pause: () => void;
201
+ resume: () => void;
202
+ };
182
203
  export {};
package/lib/index.js CHANGED
@@ -126,12 +126,14 @@ function useMyPresence() {
126
126
  function onMyPresenceChange() {
127
127
  update(function (x) { return x + 1; });
128
128
  }
129
- room.subscribe("my-presence", onMyPresenceChange);
129
+ var unsubscribe = room.subscribe("my-presence", onMyPresenceChange);
130
130
  return function () {
131
- room.unsubscribe("my-presence", onMyPresenceChange);
131
+ unsubscribe();
132
132
  };
133
133
  }, [room]);
134
- var setPresence = React.useCallback(function (overrides) { return room.updatePresence(overrides); }, [room]);
134
+ var setPresence = React.useCallback(function (overrides, options) {
135
+ return room.updatePresence(overrides, options);
136
+ }, [room]);
135
137
  return [presence, setPresence];
136
138
  }
137
139
  /**
@@ -149,8 +151,8 @@ function useMyPresence() {
149
151
  */
150
152
  function useUpdateMyPresence() {
151
153
  var room = useRoom();
152
- return React.useCallback(function (overrides) {
153
- room.updatePresence(overrides);
154
+ return React.useCallback(function (overrides, options) {
155
+ room.updatePresence(overrides, options);
154
156
  }, [room]);
155
157
  }
156
158
  /**
@@ -178,9 +180,9 @@ function useOthers() {
178
180
  function onOthersChange() {
179
181
  update(function (x) { return x + 1; });
180
182
  }
181
- room.subscribe("others", onOthersChange);
183
+ var unsubscribe = room.subscribe("others", onOthersChange);
182
184
  return function () {
183
- room.subscribe("others", onOthersChange);
185
+ unsubscribe();
184
186
  };
185
187
  }, [room]);
186
188
  return room.getOthers();
@@ -219,9 +221,9 @@ function useErrorListener(callback) {
219
221
  });
220
222
  React.useEffect(function () {
221
223
  var listener = function (e) { return savedCallback.current(e); };
222
- room.subscribe("error", listener);
224
+ var unsubscribe = room.subscribe("error", listener);
223
225
  return function () {
224
- room.unsubscribe("error", listener);
226
+ unsubscribe();
225
227
  };
226
228
  }, [room]);
227
229
  }
@@ -247,9 +249,9 @@ function useEventListener(callback) {
247
249
  var listener = function (e) {
248
250
  return savedCallback.current(e);
249
251
  };
250
- room.subscribe("event", listener);
252
+ var unsubscribe = room.subscribe("event", listener);
251
253
  return function () {
252
- room.unsubscribe("event", listener);
254
+ unsubscribe();
253
255
  };
254
256
  }, [room]);
255
257
  }
@@ -268,11 +270,11 @@ function useSelf() {
268
270
  function onChange() {
269
271
  update(function (x) { return x + 1; });
270
272
  }
271
- room.subscribe("my-presence", onChange);
272
- room.subscribe("connection", onChange);
273
+ var unsubscribePresence = room.subscribe("my-presence", onChange);
274
+ var unsubscribeConnection = room.subscribe("connection", onChange);
273
275
  return function () {
274
- room.unsubscribe("my-presence", onChange);
275
- room.unsubscribe("connection", onChange);
276
+ unsubscribePresence();
277
+ unsubscribeConnection();
276
278
  };
277
279
  }, [room]);
278
280
  return room.getSelf();
@@ -281,6 +283,7 @@ function useStorage() {
281
283
  var room = useRoom();
282
284
  var _a = React.useState(null), root = _a[0], setState = _a[1];
283
285
  React.useEffect(function () {
286
+ var didCancel = false;
284
287
  function fetchStorage() {
285
288
  return __awaiter(this, void 0, void 0, function () {
286
289
  var storage;
@@ -289,14 +292,18 @@ function useStorage() {
289
292
  case 0: return [4 /*yield*/, room.getStorage()];
290
293
  case 1:
291
294
  storage = _a.sent();
292
- setState(storage.root);
295
+ if (!didCancel) {
296
+ setState(storage.root);
297
+ }
293
298
  return [2 /*return*/];
294
299
  }
295
300
  });
296
301
  });
297
302
  }
298
303
  fetchStorage();
299
- return function () { };
304
+ return function () {
305
+ didCancel = true;
306
+ };
300
307
  }, [room]);
301
308
  return [root];
302
309
  }
@@ -348,21 +355,34 @@ function useObject(key, initialData) {
348
355
  return useCrdt(key, new client.LiveObject(initialData));
349
356
  }
350
357
  /**
351
- * Returns a function that undo the last operation executed by the current client.
352
- * Undo does not impact operations made by other clients.
358
+ * Returns a function that undoes the last operation executed by the current client.
359
+ * It does not impact operations made by other clients.
353
360
  */
354
361
  function useUndo() {
355
- return useRoom().undo;
362
+ return useRoom().history.undo;
356
363
  }
357
364
  /**
358
- * Returns a function that redo the last operation executed by the current client.
359
- * Redo does not impact operations made by other clients.
365
+ * Returns a function that redoes the last operation executed by the current client.
366
+ * It does not impact operations made by other clients.
360
367
  */
361
368
  function useRedo() {
362
- return useRoom().redo;
369
+ return useRoom().history.redo;
370
+ }
371
+ /**
372
+ * Returns a function that batches modifications made during the given function.
373
+ * All the modifications are sent to other clients in a single message.
374
+ * All the modifications are merged in a single history item (undo/redo).
375
+ * All the subscribers are called only after the batch is over.
376
+ */
377
+ function useBatch() {
378
+ return useRoom().batch;
379
+ }
380
+ function useHistory() {
381
+ return useRoom().history;
363
382
  }
364
383
  function useCrdt(key, initialCrdt) {
365
384
  var _a;
385
+ var room = useRoom();
366
386
  var root = useStorage()[0];
367
387
  var _b = React.useState(0), setCount = _b[1];
368
388
  React.useEffect(function () {
@@ -380,34 +400,37 @@ function useCrdt(key, initialCrdt) {
380
400
  function onRootChange() {
381
401
  var newCrdt = root.get(key);
382
402
  if (newCrdt !== crdt) {
383
- crdt.unsubscribe(onChange);
403
+ unsubscribeCrdt();
384
404
  crdt = newCrdt;
385
- crdt.subscribe(onChange);
405
+ unsubscribeCrdt = room.subscribe(crdt /* AbstractCrdt */, onChange);
386
406
  setCount(function (x) { return x + 1; });
387
407
  }
388
408
  }
389
- crdt.subscribe(onChange);
390
- root.subscribe(onRootChange);
409
+ var unsubscribeCrdt = room.subscribe(crdt /* AbstractCrdt */, onChange);
410
+ var unsubscribeRoot = room.subscribe(root /* AbstractCrdt */, onRootChange);
391
411
  setCount(function (x) { return x + 1; });
392
412
  return function () {
393
- root.unsubscribe(onRootChange);
394
- crdt.unsubscribe(onChange);
413
+ unsubscribeRoot();
414
+ unsubscribeCrdt();
395
415
  };
396
- }, [root]);
416
+ }, [root, room]);
397
417
  return (_a = root === null || root === void 0 ? void 0 : root.get(key)) !== null && _a !== void 0 ? _a : null;
398
418
  }
399
419
 
400
420
  exports.LiveblocksProvider = LiveblocksProvider;
401
421
  exports.RoomProvider = RoomProvider;
422
+ exports.useBatch = useBatch;
402
423
  exports.useBroadcastEvent = useBroadcastEvent;
403
424
  exports.useErrorListener = useErrorListener;
404
425
  exports.useEventListener = useEventListener;
426
+ exports.useHistory = useHistory;
405
427
  exports.useList = useList;
406
428
  exports.useMap = useMap;
407
429
  exports.useMyPresence = useMyPresence;
408
430
  exports.useObject = useObject;
409
431
  exports.useOthers = useOthers;
410
432
  exports.useRedo = useRedo;
433
+ exports.useRoom = useRoom;
411
434
  exports.useSelf = useSelf;
412
435
  exports.useStorage = useStorage;
413
436
  exports.useUndo = useUndo;
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["import {\n Client,\n Others,\n Presence,\n LiveObject,\n LiveMap,\n Room,\n User,\n LiveList,\n} from \"@liveblocks/client\";\nimport * as React from \"react\";\n\ntype LiveblocksProviderProps = {\n children: React.ReactNode;\n client: Client;\n};\n\nconst ClientContext = React.createContext<Client | null>(null);\nconst RoomContext = React.createContext<Room | null>(null);\n\n/**\n * Makes the Liveblocks client available in the component hierarchy below.\n */\nexport function LiveblocksProvider(props: LiveblocksProviderProps) {\n return (\n <ClientContext.Provider value={props.client}>\n {props.children}\n </ClientContext.Provider>\n );\n}\n\n/**\n * Returns the client of the nearest LiveblocksProvider above in the react component tree\n */\nfunction useClient(): Client {\n const client = React.useContext(ClientContext);\n if (client == null) {\n throw new Error(\"LiveblocksProvider is missing from the react tree\");\n }\n\n return client;\n}\n\ntype RoomProviderProps<TStorageRoot> = {\n /**\n * The id of the room you want to connect to\n */\n id: string;\n /**\n * A callback that let you initialize the default presence when entering the room.\n * If ommited, the default presence will be an empty object\n */\n defaultPresence?: () => Presence;\n\n defaultStorageRoot?: TStorageRoot;\n\n children: React.ReactNode;\n};\n\n/**\n * Makes a Room available in the component hierarchy below.\n * When this component is unmounted, the current user leave the room.\n * That means that you can't have 2 RoomProvider with the same room id in your react tree.\n */\nexport function RoomProvider<TStorageRoot>({\n id,\n children,\n defaultPresence,\n defaultStorageRoot,\n}: RoomProviderProps<TStorageRoot>) {\n const client = useClient();\n\n React.useEffect(() => {\n return () => {\n client.leave(id);\n };\n }, [client, id]);\n\n const room =\n client.getRoom(id) ||\n client.enter(id, {\n defaultPresence: defaultPresence ? defaultPresence() : undefined,\n defaultStorageRoot,\n });\n\n return <RoomContext.Provider value={room}>{children}</RoomContext.Provider>;\n}\n\n/**\n * Returns the room of the nearest RoomProvider above in the react component tree\n */\nfunction useRoom() {\n const room = React.useContext(RoomContext);\n\n if (room == null) {\n throw new Error(\"RoomProvider is missing from the react tree\");\n }\n\n return room;\n}\n\n/**\n * Returns the presence of the current user of the current room, and a function to update it.\n * It is different from the setState function returned by the useState hook from React.\n * You don't need to pass the full presence object to update it.\n *\n * @example\n * import { useMyPresence } from \"@liveblocks/react\";\n *\n * const [myPresence, updateMyPresence] = useMyPresence();\n * updateMyPresence({ x: 0 });\n * updateMyPresence({ y: 0 });\n *\n * // At the next render, \"myPresence\" will be equal to \"{ x: 0, y: 0 }\"\n */\nexport function useMyPresence<T extends Presence>(): [\n T,\n (overrides: Partial<T>) => void\n] {\n const room = useRoom();\n const presence = room.getPresence<T>();\n const [, update] = React.useState(0);\n\n React.useEffect(() => {\n function onMyPresenceChange() {\n update((x) => x + 1);\n }\n\n room.subscribe(\"my-presence\", onMyPresenceChange);\n\n return () => {\n room.unsubscribe(\"my-presence\", onMyPresenceChange);\n };\n }, [room]);\n\n const setPresence = React.useCallback(\n (overrides: Partial<T>) => room.updatePresence(overrides),\n [room]\n );\n\n return [presence, setPresence];\n}\n\n/**\n * useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.\n * 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.\n *\n * @example\n * import { useUpdateMyPresence } from \"@liveblocks/react\";\n *\n * const updateMyPresence = useUpdateMyPresence();\n * updateMyPresence({ x: 0 });\n * updateMyPresence({ y: 0 });\n *\n * // At the next render, the presence of the current user will be equal to \"{ x: 0, y: 0 }\"\n */\nexport function useUpdateMyPresence<T extends Presence>(): (\n overrides: Partial<T>\n) => void {\n const room = useRoom();\n\n return React.useCallback(\n (overrides: Partial<T>) => {\n room.updatePresence(overrides);\n },\n [room]\n );\n}\n\n/**\n * Returns an object that lets you get information about all the the users currently connected in the room.\n *\n * @example\n * import { useOthers } from \"@liveblocks/react\";\n *\n * const others = useOthers();\n *\n * // Example to map all cursors in jsx\n * {\n * others.map(({ connectionId, presence }) => {\n * if(presence == null || presence.cursor == null) {\n * return null;\n * }\n * return <Cursor key={connectionId} cursor={presence.cursor} />\n * })\n * }\n */\nexport function useOthers<T extends Presence>(): Others<T> {\n const room = useRoom();\n\n const [, update] = React.useState(0);\n\n React.useEffect(() => {\n function onOthersChange() {\n update((x) => x + 1);\n }\n\n room.subscribe(\"others\", onOthersChange);\n\n return () => {\n room.subscribe(\"others\", onOthersChange);\n };\n }, [room]);\n\n return room.getOthers();\n}\n\n/**\n * Returns a callback that lets you broadcast custom events to other users in the room\n *\n * @example\n * import { useBroadcastEvent } from \"@liveblocks/react\";\n *\n * const broadcast = useBroadcastEvent();\n *\n * broadcast({ type: \"CUSTOM_EVENT\", data: { x: 0, y: 0 } });\n */\nexport function useBroadcastEvent() {\n const room = useRoom();\n\n return React.useCallback(\n (event: any) => {\n room.broadcastEvent(event);\n },\n [room]\n );\n}\n\n/**\n * useErrorListener is a react hook that lets you react to potential room connection errors.\n *\n * @example\n * import { useErrorListener } from \"@liveblocks/react\";\n *\n * useErrorListener(er => {\n * console.error(er);\n * })\n */\nexport function useErrorListener(callback: (er: Error) => void) {\n const room = useRoom();\n const savedCallback = React.useRef(callback);\n\n React.useEffect(() => {\n savedCallback.current = callback;\n });\n\n React.useEffect(() => {\n const listener = (e: Error) => savedCallback.current(e);\n\n room.subscribe(\"error\", listener);\n\n return () => {\n room.unsubscribe(\"error\", listener);\n };\n }, [room]);\n}\n\n/**\n * useEventListener is a react hook that lets you react to event broadcasted by other users in the room.\n *\n * @example\n * import { useEventListener } from \"@liveblocks/react\";\n *\n * useEventListener(({ connectionId, event }) => {\n * if (event.type === \"CUSTOM_EVENT\") {\n * // Do something\n * }\n * });\n */\nexport function useEventListener<TEvent>(\n callback: ({\n connectionId,\n event,\n }: {\n connectionId: number;\n event: TEvent;\n }) => void\n) {\n const room = useRoom();\n const savedCallback = React.useRef(callback);\n\n React.useEffect(() => {\n savedCallback.current = callback;\n });\n\n React.useEffect(() => {\n const listener = (e: { connectionId: number; event: TEvent }) =>\n savedCallback.current(e);\n\n room.subscribe(\"event\", listener);\n\n return () => {\n room.unsubscribe(\"event\", listener);\n };\n }, [room]);\n}\n\n/**\n * Gets the current user once it is connected to the room.\n *\n * @example\n * import { useSelf } from \"@liveblocks/react\";\n *\n * const user = useSelf();\n */\nexport function useSelf<\n TPresence extends Presence = Presence\n>(): User<TPresence> | null {\n const room = useRoom();\n const [, update] = React.useState(0);\n\n React.useEffect(() => {\n function onChange() {\n update((x) => x + 1);\n }\n\n room.subscribe(\"my-presence\", onChange);\n room.subscribe(\"connection\", onChange);\n\n return () => {\n room.unsubscribe(\"my-presence\", onChange);\n room.unsubscribe(\"connection\", onChange);\n };\n }, [room]);\n\n return room.getSelf<TPresence>();\n}\n\nexport function useStorage<TRoot extends Record<string, any>>(): [\n root: LiveObject<TRoot> | null\n] {\n const room = useRoom();\n const [root, setState] = React.useState<LiveObject<TRoot> | null>(null);\n\n React.useEffect(() => {\n async function fetchStorage() {\n const storage = await room.getStorage<TRoot>();\n setState(storage.root);\n }\n\n fetchStorage();\n\n return () => {};\n }, [room]);\n\n return [root];\n}\n\n/**\n * Returns the LiveMap associated with the provided key. If the LiveMap does not exist, a new empty LiveMap will be created.\n * 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.\n *\n * @param key The storage key associated with the LiveMap\n * @param entries Optional entries that are used to create the LiveMap for the first time\n * @returns null while the storage is loading, otherwise, returns the LiveMap associated to the storage\n *\n * @example\n * const emptyMap = useMap(\"mapA\");\n * const mapWithItems = useMap(\"mapB\", [[\"keyA\", \"valueA\"], [\"keyB\", \"valueB\"]]);\n */\nexport function useMap<TKey extends string, TValue>(\n key: string,\n entries?: readonly (readonly [TKey, TValue])[] | null | undefined\n): LiveMap<TKey, TValue> | null {\n return useCrdt(key, new LiveMap(entries));\n}\n\n/**\n * Returns the LiveList associated with the provided key. If the LiveList does not exist, a new LiveList will be created.\n * 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.\n *\n * @param key The storage key associated with the LiveList\n * @param items Optional items that are used to create the LiveList for the first time\n * @returns null while the storage is loading, otherwise, returns the LiveList associated to the storage\n *\n * @example\n * const emptyList = useList(\"listA\");\n * const listWithItems = useList(\"listB\", [\"a\", \"b\", \"c\"]);\n */\nexport function useList<TValue>(\n key: string,\n items?: TValue[] | undefined\n): LiveList<TValue> | null {\n return useCrdt<LiveList<TValue>>(key, new LiveList(items));\n}\n\n/**\n * Returns the LiveObject associated with the provided key. If the LiveObject does not exist, it will be created with the initialData parameter.\n * 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.\n *\n * @param key The storage key associated with the LiveObject\n * @param initialData Optional data that is used to create the LiveObject for the first time\n * @returns null while the storage is loading, otherwise, returns the LveObject associated to the storage\n *\n * @example\n * const object = useObject(\"obj\", {\n * company: \"Liveblocks\",\n * website: \"https://liveblocks.io\"\n * });\n */\nexport function useObject<TData>(\n key: string,\n initialData?: TData\n): LiveObject<TData> | null {\n return useCrdt(key, new LiveObject(initialData));\n}\n\n/**\n * Returns a function that undo the last operation executed by the current client.\n * Undo does not impact operations made by other clients.\n */\nexport function useUndo() {\n return useRoom().undo;\n}\n\n/**\n * Returns a function that redo the last operation executed by the current client.\n * Redo does not impact operations made by other clients.\n */\nexport function useRedo() {\n return useRoom().redo;\n}\n\nfunction useCrdt<\n T extends {\n subscribe: (callback: () => void) => void;\n unsubscribe: (callback: () => void) => void;\n }\n>(key: string, initialCrdt: T): T | null {\n const [root] = useStorage();\n const [, setCount] = React.useState(0);\n\n React.useEffect(() => {\n if (root == null) {\n return;\n }\n\n let crdt: null | T = root.get(key);\n\n if (crdt == null) {\n crdt = initialCrdt;\n root.set(key, crdt);\n }\n\n function onChange() {\n setCount((x) => x + 1);\n }\n\n function onRootChange() {\n const newCrdt = root!.get(key);\n if (newCrdt !== crdt) {\n crdt!.unsubscribe(onChange);\n crdt = newCrdt;\n crdt!.subscribe(onChange);\n setCount((x) => x + 1);\n }\n }\n\n crdt.subscribe(onChange);\n root.subscribe(onRootChange);\n\n setCount((x) => x + 1);\n\n return () => {\n root.unsubscribe(onRootChange);\n crdt!.unsubscribe(onChange);\n };\n }, [root]);\n\n return root?.get(key) ?? null;\n}\n"],"names":["React.createContext","React.createElement","React.useContext","React.useEffect","React.useState","React.useCallback","React.useRef","LiveMap","LiveList","LiveObject"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["import {\n Client,\n Others,\n Presence,\n LiveObject,\n LiveMap,\n Room,\n User,\n LiveList,\n} from \"@liveblocks/client\";\nimport * as React from \"react\";\n\ntype LiveblocksProviderProps = {\n children: React.ReactNode;\n client: Client;\n};\n\nconst ClientContext = React.createContext<Client | null>(null);\nconst RoomContext = React.createContext<Room | null>(null);\n\n/**\n * Makes the Liveblocks client available in the component hierarchy below.\n */\nexport function LiveblocksProvider(props: LiveblocksProviderProps) {\n return (\n <ClientContext.Provider value={props.client}>\n {props.children}\n </ClientContext.Provider>\n );\n}\n\n/**\n * Returns the client of the nearest LiveblocksProvider above in the react component tree\n */\nfunction useClient(): Client {\n const client = React.useContext(ClientContext);\n if (client == null) {\n throw new Error(\"LiveblocksProvider is missing from the react tree\");\n }\n\n return client;\n}\n\ntype RoomProviderProps<TStorageRoot> = {\n /**\n * The id of the room you want to connect to\n */\n id: string;\n /**\n * A callback that let you initialize the default presence when entering the room.\n * If ommited, the default presence will be an empty object\n */\n defaultPresence?: () => Presence;\n\n defaultStorageRoot?: TStorageRoot;\n\n children: React.ReactNode;\n};\n\n/**\n * Makes a Room available in the component hierarchy below.\n * When this component is unmounted, the current user leave the room.\n * That means that you can't have 2 RoomProvider with the same room id in your react tree.\n */\nexport function RoomProvider<TStorageRoot>({\n id,\n children,\n defaultPresence,\n defaultStorageRoot,\n}: RoomProviderProps<TStorageRoot>) {\n const client = useClient();\n\n React.useEffect(() => {\n return () => {\n client.leave(id);\n };\n }, [client, id]);\n\n const room =\n client.getRoom(id) ||\n client.enter(id, {\n defaultPresence: defaultPresence ? defaultPresence() : undefined,\n defaultStorageRoot,\n });\n\n return <RoomContext.Provider value={room}>{children}</RoomContext.Provider>;\n}\n\n/**\n * Returns the room of the nearest RoomProvider above in the react component tree\n */\nexport function useRoom() {\n const room = React.useContext(RoomContext);\n\n if (room == null) {\n throw new Error(\"RoomProvider is missing from the react tree\");\n }\n\n return room;\n}\n\n/**\n * Returns the presence of the current user of the current room, and a function to update it.\n * It is different from the setState function returned by the useState hook from React.\n * You don't need to pass the full presence object to update it.\n *\n * @example\n * import { useMyPresence } from \"@liveblocks/react\";\n *\n * const [myPresence, updateMyPresence] = useMyPresence();\n * updateMyPresence({ x: 0 });\n * updateMyPresence({ y: 0 });\n *\n * // At the next render, \"myPresence\" will be equal to \"{ x: 0, y: 0 }\"\n */\nexport function useMyPresence<T extends Presence>(): [\n T,\n (overrides: Partial<T>, options?: { addToHistory: boolean }) => void\n] {\n const room = useRoom();\n const presence = room.getPresence<T>();\n const [, update] = React.useState(0);\n\n React.useEffect(() => {\n function onMyPresenceChange() {\n update((x) => x + 1);\n }\n\n const unsubscribe = room.subscribe(\"my-presence\", onMyPresenceChange);\n\n return () => {\n unsubscribe();\n };\n }, [room]);\n\n const setPresence = React.useCallback(\n (overrides: Partial<T>, options?: { addToHistory: boolean }) =>\n room.updatePresence(overrides, options),\n [room]\n );\n\n return [presence, setPresence];\n}\n\n/**\n * useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.\n * 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.\n *\n * @example\n * import { useUpdateMyPresence } from \"@liveblocks/react\";\n *\n * const updateMyPresence = useUpdateMyPresence();\n * updateMyPresence({ x: 0 });\n * updateMyPresence({ y: 0 });\n *\n * // At the next render, the presence of the current user will be equal to \"{ x: 0, y: 0 }\"\n */\nexport function useUpdateMyPresence<T extends Presence>(): (\n overrides: Partial<T>,\n options?: { addToHistory: boolean }\n) => void {\n const room = useRoom();\n\n return React.useCallback(\n (overrides: Partial<T>, options?: { addToHistory: boolean }) => {\n room.updatePresence(overrides, options);\n },\n [room]\n );\n}\n\n/**\n * Returns an object that lets you get information about all the the users currently connected in the room.\n *\n * @example\n * import { useOthers } from \"@liveblocks/react\";\n *\n * const others = useOthers();\n *\n * // Example to map all cursors in jsx\n * {\n * others.map(({ connectionId, presence }) => {\n * if(presence == null || presence.cursor == null) {\n * return null;\n * }\n * return <Cursor key={connectionId} cursor={presence.cursor} />\n * })\n * }\n */\nexport function useOthers<T extends Presence>(): Others<T> {\n const room = useRoom();\n\n const [, update] = React.useState(0);\n\n React.useEffect(() => {\n function onOthersChange() {\n update((x) => x + 1);\n }\n\n const unsubscribe = room.subscribe(\"others\", onOthersChange);\n\n return () => {\n unsubscribe();\n };\n }, [room]);\n\n return room.getOthers();\n}\n\n/**\n * Returns a callback that lets you broadcast custom events to other users in the room\n *\n * @example\n * import { useBroadcastEvent } from \"@liveblocks/react\";\n *\n * const broadcast = useBroadcastEvent();\n *\n * broadcast({ type: \"CUSTOM_EVENT\", data: { x: 0, y: 0 } });\n */\nexport function useBroadcastEvent() {\n const room = useRoom();\n\n return React.useCallback(\n (event: any) => {\n room.broadcastEvent(event);\n },\n [room]\n );\n}\n\n/**\n * useErrorListener is a react hook that lets you react to potential room connection errors.\n *\n * @example\n * import { useErrorListener } from \"@liveblocks/react\";\n *\n * useErrorListener(er => {\n * console.error(er);\n * })\n */\nexport function useErrorListener(callback: (er: Error) => void) {\n const room = useRoom();\n const savedCallback = React.useRef(callback);\n\n React.useEffect(() => {\n savedCallback.current = callback;\n });\n\n React.useEffect(() => {\n const listener = (e: Error) => savedCallback.current(e);\n\n const unsubscribe = room.subscribe(\"error\", listener);\n\n return () => {\n unsubscribe();\n };\n }, [room]);\n}\n\n/**\n * useEventListener is a react hook that lets you react to event broadcasted by other users in the room.\n *\n * @example\n * import { useEventListener } from \"@liveblocks/react\";\n *\n * useEventListener(({ connectionId, event }) => {\n * if (event.type === \"CUSTOM_EVENT\") {\n * // Do something\n * }\n * });\n */\nexport function useEventListener<TEvent>(\n callback: ({\n connectionId,\n event,\n }: {\n connectionId: number;\n event: TEvent;\n }) => void\n) {\n const room = useRoom();\n const savedCallback = React.useRef(callback);\n\n React.useEffect(() => {\n savedCallback.current = callback;\n });\n\n React.useEffect(() => {\n const listener = (e: { connectionId: number; event: TEvent }) =>\n savedCallback.current(e);\n\n const unsubscribe = room.subscribe(\"event\", listener);\n\n return () => {\n unsubscribe();\n };\n }, [room]);\n}\n\n/**\n * Gets the current user once it is connected to the room.\n *\n * @example\n * import { useSelf } from \"@liveblocks/react\";\n *\n * const user = useSelf();\n */\nexport function useSelf<\n TPresence extends Presence = Presence\n>(): User<TPresence> | null {\n const room = useRoom();\n const [, update] = React.useState(0);\n\n React.useEffect(() => {\n function onChange() {\n update((x) => x + 1);\n }\n\n const unsubscribePresence = room.subscribe(\"my-presence\", onChange);\n const unsubscribeConnection = room.subscribe(\"connection\", onChange);\n\n return () => {\n unsubscribePresence();\n unsubscribeConnection();\n };\n }, [room]);\n\n return room.getSelf<TPresence>();\n}\n\nexport function useStorage<TRoot extends Record<string, any>>(): [\n root: LiveObject<TRoot> | null\n] {\n const room = useRoom();\n const [root, setState] = React.useState<LiveObject<TRoot> | null>(null);\n\n React.useEffect(() => {\n let didCancel = false;\n\n async function fetchStorage() {\n const storage = await room.getStorage<TRoot>();\n if (!didCancel) {\n setState(storage.root);\n }\n }\n\n fetchStorage();\n\n return () => {\n didCancel = true;\n };\n }, [room]);\n\n return [root];\n}\n\n/**\n * Returns the LiveMap associated with the provided key. If the LiveMap does not exist, a new empty LiveMap will be created.\n * 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.\n *\n * @param key The storage key associated with the LiveMap\n * @param entries Optional entries that are used to create the LiveMap for the first time\n * @returns null while the storage is loading, otherwise, returns the LiveMap associated to the storage\n *\n * @example\n * const emptyMap = useMap(\"mapA\");\n * const mapWithItems = useMap(\"mapB\", [[\"keyA\", \"valueA\"], [\"keyB\", \"valueB\"]]);\n */\nexport function useMap<TKey extends string, TValue>(\n key: string,\n entries?: readonly (readonly [TKey, TValue])[] | null | undefined\n): LiveMap<TKey, TValue> | null {\n return useCrdt(key, new LiveMap(entries));\n}\n\n/**\n * Returns the LiveList associated with the provided key. If the LiveList does not exist, a new LiveList will be created.\n * 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.\n *\n * @param key The storage key associated with the LiveList\n * @param items Optional items that are used to create the LiveList for the first time\n * @returns null while the storage is loading, otherwise, returns the LiveList associated to the storage\n *\n * @example\n * const emptyList = useList(\"listA\");\n * const listWithItems = useList(\"listB\", [\"a\", \"b\", \"c\"]);\n */\nexport function useList<TValue>(\n key: string,\n items?: TValue[] | undefined\n): LiveList<TValue> | null {\n return useCrdt<LiveList<TValue>>(key, new LiveList(items));\n}\n\n/**\n * Returns the LiveObject associated with the provided key. If the LiveObject does not exist, it will be created with the initialData parameter.\n * 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.\n *\n * @param key The storage key associated with the LiveObject\n * @param initialData Optional data that is used to create the LiveObject for the first time\n * @returns null while the storage is loading, otherwise, returns the LveObject associated to the storage\n *\n * @example\n * const object = useObject(\"obj\", {\n * company: \"Liveblocks\",\n * website: \"https://liveblocks.io\"\n * });\n */\nexport function useObject<TData>(\n key: string,\n initialData?: TData\n): LiveObject<TData> | null {\n return useCrdt(key, new LiveObject(initialData));\n}\n\n/**\n * Returns a function that undoes the last operation executed by the current client.\n * It does not impact operations made by other clients.\n */\nexport function useUndo() {\n return useRoom().history.undo;\n}\n\n/**\n * Returns a function that redoes the last operation executed by the current client.\n * It does not impact operations made by other clients.\n */\nexport function useRedo() {\n return useRoom().history.redo;\n}\n\n/**\n * Returns a function that batches modifications made during the given function.\n * All the modifications are sent to other clients in a single message.\n * All the modifications are merged in a single history item (undo/redo).\n * All the subscribers are called only after the batch is over.\n */\nexport function useBatch() {\n return useRoom().batch;\n}\n\nexport function useHistory() {\n return useRoom().history;\n}\n\nfunction useCrdt<T>(key: string, initialCrdt: T): T | null {\n const room = useRoom();\n const [root] = useStorage();\n const [, setCount] = React.useState(0);\n\n React.useEffect(() => {\n if (root == null) {\n return;\n }\n\n let crdt: null | T = root.get(key);\n\n if (crdt == null) {\n crdt = initialCrdt;\n root.set(key, crdt);\n }\n\n function onChange() {\n setCount((x) => x + 1);\n }\n\n function onRootChange() {\n const newCrdt = root!.get(key);\n if (newCrdt !== crdt) {\n unsubscribeCrdt();\n crdt = newCrdt;\n unsubscribeCrdt = room.subscribe(\n crdt as any /* AbstractCrdt */,\n onChange\n );\n setCount((x) => x + 1);\n }\n }\n\n let unsubscribeCrdt = room.subscribe(\n crdt as any /* AbstractCrdt */,\n onChange\n );\n const unsubscribeRoot = room.subscribe(\n root as any /* AbstractCrdt */,\n onRootChange\n );\n\n setCount((x) => x + 1);\n\n return () => {\n unsubscribeRoot();\n unsubscribeCrdt();\n };\n }, [root, room]);\n\n return root?.get(key) ?? null;\n}\n"],"names":["React.createContext","React.createElement","React.useContext","React.useEffect","React.useState","React.useCallback","React.useRef","LiveMap","LiveList","LiveObject"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/react",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "",
5
5
  "main": "./lib/index.js",
6
6
  "files": [
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "license": "Apache-2.0",
25
25
  "peerDependencies": {
26
- "@liveblocks/client": "0.12.1",
26
+ "@liveblocks/client": "0.13.0",
27
27
  "react": "^16.14.0 || ^17"
28
28
  },
29
29
  "devDependencies": {