@liveblocks/react 0.16.3 → 0.16.4
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/index.d.ts +29 -27
- package/index.js +68 -20
- package/index.mjs +507 -0
- package/package.json +10 -14
- package/esm/index.js +0 -216
- package/esm/index.mjs +0 -216
package/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Client, Room, Presence, Others, BroadcastOptions, Json, User, LiveObject, Lson, LiveMap, LiveList, LsonObject, History } from '@liveblocks/client';
|
|
3
3
|
export { Json, JsonObject } from '@liveblocks/client';
|
|
4
|
+
import { Resolve, RoomInitializers } from '@liveblocks/client/internal';
|
|
4
5
|
|
|
5
6
|
declare type LiveblocksProviderProps = {
|
|
6
7
|
children: React.ReactNode;
|
|
@@ -16,25 +17,19 @@ declare function LiveblocksProvider(props: LiveblocksProviderProps): JSX.Element
|
|
|
16
17
|
*/
|
|
17
18
|
declare function useClient(): Client;
|
|
18
19
|
|
|
19
|
-
declare type RoomProviderProps<
|
|
20
|
+
declare type RoomProviderProps<TStorage> = Resolve<{
|
|
20
21
|
/**
|
|
21
22
|
* The id of the room you want to connect to
|
|
22
23
|
*/
|
|
23
24
|
id: string;
|
|
24
|
-
/**
|
|
25
|
-
* A callback that let you initialize the default presence when entering the room.
|
|
26
|
-
* If ommited, the default presence will be an empty object
|
|
27
|
-
*/
|
|
28
|
-
defaultPresence?: () => Presence;
|
|
29
|
-
defaultStorageRoot?: TStorageRoot;
|
|
30
25
|
children: React.ReactNode;
|
|
31
|
-
}
|
|
26
|
+
} & RoomInitializers<Presence, TStorage>>;
|
|
32
27
|
/**
|
|
33
28
|
* Makes a Room available in the component hierarchy below.
|
|
34
29
|
* When this component is unmounted, the current user leave the room.
|
|
35
30
|
* That means that you can't have 2 RoomProvider with the same room id in your react tree.
|
|
36
31
|
*/
|
|
37
|
-
declare function RoomProvider<
|
|
32
|
+
declare function RoomProvider<TStorage>(props: RoomProviderProps<TStorage>): JSX.Element;
|
|
38
33
|
/**
|
|
39
34
|
* Returns the Room of the nearest RoomProvider above in the React component
|
|
40
35
|
* tree.
|
|
@@ -142,50 +137,57 @@ declare function useEventListener<TEvent extends Json>(callback: ({ connectionId
|
|
|
142
137
|
* const user = useSelf();
|
|
143
138
|
*/
|
|
144
139
|
declare function useSelf<TPresence extends Presence = Presence>(): User<TPresence> | null;
|
|
145
|
-
declare function useStorage<
|
|
146
|
-
root: LiveObject<
|
|
140
|
+
declare function useStorage<TStorage extends Record<string, any>>(): [
|
|
141
|
+
root: LiveObject<TStorage> | null
|
|
147
142
|
];
|
|
148
143
|
/**
|
|
149
144
|
* Returns the LiveMap associated with the provided key. If the LiveMap does not exist, a new empty LiveMap will be created.
|
|
150
145
|
* 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.
|
|
151
146
|
*
|
|
152
147
|
* @param key The storage key associated with the LiveMap
|
|
153
|
-
* @param entries Optional entries that are used to create the LiveMap for the first time
|
|
154
148
|
* @returns null while the storage is loading, otherwise, returns the LiveMap associated to the storage
|
|
155
149
|
*
|
|
156
150
|
* @example
|
|
157
|
-
* const
|
|
158
|
-
|
|
151
|
+
* const shapesById = useMap<string, Shape>("shapes");
|
|
152
|
+
*/
|
|
153
|
+
declare function useMap<TKey extends string, TValue extends Lson>(key: string): LiveMap<TKey, TValue> | null;
|
|
154
|
+
/**
|
|
155
|
+
* @deprecated We no longer recommend initializing the
|
|
156
|
+
* entries from the useMap() hook. For details, see https://bit.ly/3Niy5aP.
|
|
159
157
|
*/
|
|
160
|
-
declare function useMap<TKey extends string, TValue extends Lson>(key: string, entries
|
|
158
|
+
declare function useMap<TKey extends string, TValue extends Lson>(key: string, entries: readonly (readonly [TKey, TValue])[] | null): LiveMap<TKey, TValue> | null;
|
|
161
159
|
/**
|
|
162
|
-
* Returns the LiveList associated with the provided key.
|
|
160
|
+
* Returns the LiveList associated with the provided key.
|
|
163
161
|
* 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.
|
|
164
162
|
*
|
|
165
163
|
* @param key The storage key associated with the LiveList
|
|
166
|
-
* @param items Optional items that are used to create the LiveList for the first time
|
|
167
164
|
* @returns null while the storage is loading, otherwise, returns the LiveList associated to the storage
|
|
168
165
|
*
|
|
169
166
|
* @example
|
|
170
|
-
* const
|
|
171
|
-
* const listWithItems = useList("listB", ["a", "b", "c"]);
|
|
167
|
+
* const animals = useList("animals"); // e.g. [] or ["🦁", "🐍", "🦍"]
|
|
172
168
|
*/
|
|
173
|
-
declare function useList<TValue extends Lson>(key: string
|
|
169
|
+
declare function useList<TValue extends Lson>(key: string): LiveList<TValue> | null;
|
|
174
170
|
/**
|
|
175
|
-
*
|
|
171
|
+
* @deprecated We no longer recommend initializing the
|
|
172
|
+
* items from the useList() hook. For details, see https://bit.ly/3Niy5aP.
|
|
173
|
+
*/
|
|
174
|
+
declare function useList<TValue extends Lson>(key: string, items: TValue[]): LiveList<TValue> | null;
|
|
175
|
+
/**
|
|
176
|
+
* Returns the LiveObject associated with the provided key.
|
|
176
177
|
* 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.
|
|
177
178
|
*
|
|
178
179
|
* @param key The storage key associated with the LiveObject
|
|
179
|
-
* @param initialData Optional data that is used to create the LiveObject for the first time
|
|
180
180
|
* @returns null while the storage is loading, otherwise, returns the LveObject associated to the storage
|
|
181
181
|
*
|
|
182
182
|
* @example
|
|
183
|
-
* const object = useObject("obj"
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
183
|
+
* const object = useObject("obj");
|
|
184
|
+
*/
|
|
185
|
+
declare function useObject<TData extends LsonObject>(key: string): LiveObject<TData> | null;
|
|
186
|
+
/**
|
|
187
|
+
* @deprecated We no longer recommend initializing the fields from the
|
|
188
|
+
* useObject() hook. For details, see https://bit.ly/3Niy5aP.
|
|
187
189
|
*/
|
|
188
|
-
declare function useObject<TData extends LsonObject>(key: string, initialData
|
|
190
|
+
declare function useObject<TData extends LsonObject>(key: string, initialData: TData): LiveObject<TData> | null;
|
|
189
191
|
/**
|
|
190
192
|
* Returns a function that undoes the last operation executed by the current client.
|
|
191
193
|
* It does not impact operations made by other clients.
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var React = require('react');
|
|
6
6
|
var client = require('@liveblocks/client');
|
|
7
|
+
var internal = require('@liveblocks/client/internal');
|
|
7
8
|
|
|
8
9
|
function _interopNamespace(e) {
|
|
9
10
|
if (e && e.__esModule) return e;
|
|
@@ -87,27 +88,32 @@ function useRerender() {
|
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
var RoomContext = React__namespace.createContext(null);
|
|
90
|
-
function RoomProvider(
|
|
91
|
-
var
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
function RoomProvider(props) {
|
|
92
|
+
var roomId = props.id,
|
|
93
|
+
initialPresence = props.initialPresence,
|
|
94
|
+
initialStorage = props.initialStorage,
|
|
95
|
+
defaultPresence = props.defaultPresence,
|
|
96
|
+
defaultStorageRoot = props.defaultStorageRoot;
|
|
95
97
|
|
|
96
98
|
if (process.env.NODE_ENV !== "production") {
|
|
97
|
-
if (
|
|
99
|
+
if (roomId == null) {
|
|
98
100
|
throw new Error("RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required");
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
if (typeof
|
|
103
|
+
if (typeof roomId !== "string") {
|
|
102
104
|
throw new Error("RoomProvider id property should be a string.");
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
internal.deprecateIf(defaultPresence, "RoomProvider's `defaultPresence` prop will be removed in @liveblocks/react 0.18. Please use `initialPresence` instead. For more info, see https://bit.ly/3Niy5aP", "defaultPresence");
|
|
109
|
+
internal.deprecateIf(defaultStorageRoot, "RoomProvider's `defaultStorageRoot` prop will be removed in @liveblocks/react 0.18. Please use `initialStorage` instead. For more info, see https://bit.ly/3Niy5aP", "defaultStorageRoot");
|
|
106
110
|
var client = useClient();
|
|
107
111
|
|
|
108
112
|
var _React$useState = React__namespace.useState(function () {
|
|
109
|
-
return client.enter(
|
|
110
|
-
|
|
113
|
+
return client.enter(roomId, {
|
|
114
|
+
initialPresence: initialPresence,
|
|
115
|
+
initialStorage: initialStorage,
|
|
116
|
+
defaultPresence: defaultPresence,
|
|
111
117
|
defaultStorageRoot: defaultStorageRoot,
|
|
112
118
|
DO_NOT_USE_withoutConnecting: typeof window === "undefined"
|
|
113
119
|
});
|
|
@@ -116,18 +122,20 @@ function RoomProvider(_ref) {
|
|
|
116
122
|
setRoom = _React$useState[1];
|
|
117
123
|
|
|
118
124
|
React__namespace.useEffect(function () {
|
|
119
|
-
setRoom(client.enter(
|
|
120
|
-
|
|
125
|
+
setRoom(client.enter(roomId, {
|
|
126
|
+
initialPresence: initialPresence,
|
|
127
|
+
initialStorage: initialStorage,
|
|
128
|
+
defaultPresence: defaultPresence,
|
|
121
129
|
defaultStorageRoot: defaultStorageRoot,
|
|
122
130
|
DO_NOT_USE_withoutConnecting: typeof window === "undefined"
|
|
123
131
|
}));
|
|
124
132
|
return function () {
|
|
125
|
-
client.leave(
|
|
133
|
+
client.leave(roomId);
|
|
126
134
|
};
|
|
127
|
-
}, [client,
|
|
135
|
+
}, [client, roomId]);
|
|
128
136
|
return React__namespace.createElement(RoomContext.Provider, {
|
|
129
137
|
value: room
|
|
130
|
-
}, children);
|
|
138
|
+
}, props.children);
|
|
131
139
|
}
|
|
132
140
|
function useRoom() {
|
|
133
141
|
var room = React__namespace.useContext(RoomContext);
|
|
@@ -278,13 +286,37 @@ function useStorage() {
|
|
|
278
286
|
return [root];
|
|
279
287
|
}
|
|
280
288
|
function useMap(key, entries) {
|
|
281
|
-
|
|
289
|
+
internal.deprecateIf(entries, "Support for initializing entries in useMap() directly will be removed in @liveblocks/react 0.18.\n\nInstead, please initialize this data where you set up your RoomProvider:\n\n const initialStorage = () => {\n " + JSON.stringify(key) + ": new LiveMap(...),\n ...\n };\n\n <RoomProvider initialStorage={initialStorage}>\n ...\n </RoomProvider>\n\nPlease see https://bit.ly/3Niy5aP for details.");
|
|
290
|
+
var value = useCrdt(key, new client.LiveMap(entries));
|
|
291
|
+
|
|
292
|
+
if (value.status === "ok") {
|
|
293
|
+
return value.value;
|
|
294
|
+
} else {
|
|
295
|
+
internal.deprecateIf(value.status === "notfound", "Key " + JSON.stringify(key) + " was not found in Storage. Starting with 0.18, useMap() will no longer automatically create this key.\n\nInstead, please initialize your storage where you set up your RoomProvider:\n\n import { LiveMap } from \"@liveblocks/client\";\n\n const initialStorage = () => {\n " + JSON.stringify(key) + ": new LiveMap(...),\n ...\n };\n\n <RoomProvider initialStorage={initialStorage}>\n ...\n </RoomProvider>\n\nPlease see https://bit.ly/3Niy5aP for details.");
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
282
298
|
}
|
|
283
299
|
function useList(key, items) {
|
|
284
|
-
|
|
300
|
+
internal.deprecateIf(items, "Support for initializing items in useList() directly will be removed in @liveblocks/react 0.18.\n\nInstead, please initialize this data where you set up your RoomProvider:\n\n import { LiveList } from \"@liveblocks/client\";\n\n const initialStorage = () => {\n " + JSON.stringify(key) + ": new LiveList(...),\n ...\n };\n\n <RoomProvider initialStorage={initialStorage}>\n ...\n </RoomProvider>\n\nPlease see https://bit.ly/3Niy5aP for details.");
|
|
301
|
+
var value = useCrdt(key, new client.LiveList(items));
|
|
302
|
+
|
|
303
|
+
if (value.status === "ok") {
|
|
304
|
+
return value.value;
|
|
305
|
+
} else {
|
|
306
|
+
internal.deprecateIf(value.status === "notfound", "Key " + JSON.stringify(key) + " was not found in Storage. Starting with 0.18, useList() will no longer automatically create this key.\n\nInstead, please initialize your storage where you set up your RoomProvider:\n\n import { LiveList } from \"@liveblocks/client\";\n\n const initialStorage = () => {\n " + JSON.stringify(key) + ": new LiveList(...),\n ...\n };\n\n <RoomProvider initialStorage={initialStorage}>\n ...\n </RoomProvider>\n\nPlease see https://bit.ly/3Niy5aP for details.");
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
285
309
|
}
|
|
286
310
|
function useObject(key, initialData) {
|
|
287
|
-
|
|
311
|
+
internal.deprecateIf(initialData, "Support for initializing data in useObject() directly will be removed in @liveblocks/react 0.18.\n\nInstead, please initialize this data where you set up your RoomProvider:\n\n import { LiveObject } from \"@liveblocks/client\";\n\n const initialStorage = () => {\n " + JSON.stringify(key) + ": new LiveObject(...),\n ...\n };\n\n <RoomProvider initialStorage={initialStorage}>\n ...\n </RoomProvider>\n\nPlease see https://bit.ly/3Niy5aP for details.");
|
|
312
|
+
var value = useCrdt(key, new client.LiveObject(initialData));
|
|
313
|
+
|
|
314
|
+
if (value.status === "ok") {
|
|
315
|
+
return value.value;
|
|
316
|
+
} else {
|
|
317
|
+
internal.deprecateIf(value.status === "notfound", "Key " + JSON.stringify(key) + " was not found in Storage. Starting with 0.18, useObject() will no longer automatically create this key.\n\nInstead, please initialize your storage where you set up your RoomProvider:\n\n import { LiveObject } from \"@liveblocks/client\";\n\n const initialStorage = () => {\n " + JSON.stringify(key) + ": new LiveObject(...),\n ...\n };\n\n <RoomProvider initialStorage={initialStorage}>\n ...\n </RoomProvider>\n\nPlease see https://bit.ly/3Niy5aP for details.");
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
288
320
|
}
|
|
289
321
|
function useUndo() {
|
|
290
322
|
return useRoom().history.undo;
|
|
@@ -300,8 +332,6 @@ function useHistory() {
|
|
|
300
332
|
}
|
|
301
333
|
|
|
302
334
|
function useCrdt(key, initialCrdt) {
|
|
303
|
-
var _root$get;
|
|
304
|
-
|
|
305
335
|
var room = useRoom();
|
|
306
336
|
|
|
307
337
|
var _useStorage = useStorage(),
|
|
@@ -339,7 +369,25 @@ function useCrdt(key, initialCrdt) {
|
|
|
339
369
|
unsubscribeCrdt();
|
|
340
370
|
};
|
|
341
371
|
}, [root, room]);
|
|
342
|
-
|
|
372
|
+
|
|
373
|
+
if (root == null) {
|
|
374
|
+
return {
|
|
375
|
+
status: "loading"
|
|
376
|
+
};
|
|
377
|
+
} else {
|
|
378
|
+
var value = root.get(key);
|
|
379
|
+
|
|
380
|
+
if (value == null) {
|
|
381
|
+
return {
|
|
382
|
+
status: "notfound"
|
|
383
|
+
};
|
|
384
|
+
} else {
|
|
385
|
+
return {
|
|
386
|
+
status: "ok",
|
|
387
|
+
value: value
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
}
|
|
343
391
|
}
|
|
344
392
|
|
|
345
393
|
exports.LiveblocksProvider = LiveblocksProvider;
|
package/index.mjs
ADDED
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useReducer } from 'react';
|
|
3
|
+
import { LiveMap, LiveList, LiveObject } from '@liveblocks/client';
|
|
4
|
+
import { deprecateIf } from '@liveblocks/client/internal';
|
|
5
|
+
|
|
6
|
+
const ClientContext = React.createContext(null);
|
|
7
|
+
/**
|
|
8
|
+
* Makes the Liveblocks client available in the component hierarchy below.
|
|
9
|
+
*/
|
|
10
|
+
function LiveblocksProvider(props) {
|
|
11
|
+
return (React.createElement(ClientContext.Provider, { value: props.client }, props.children));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns the Client of the nearest LiveblocksProvider above in the React
|
|
15
|
+
* component tree.
|
|
16
|
+
*/
|
|
17
|
+
function useClient() {
|
|
18
|
+
const client = React.useContext(ClientContext);
|
|
19
|
+
if (client == null) {
|
|
20
|
+
throw new Error("LiveblocksProvider is missing from the react tree");
|
|
21
|
+
}
|
|
22
|
+
return client;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/*! *****************************************************************************
|
|
26
|
+
Copyright (c) Microsoft Corporation.
|
|
27
|
+
|
|
28
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
29
|
+
purpose with or without fee is hereby granted.
|
|
30
|
+
|
|
31
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
32
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
33
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
34
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
35
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
36
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
37
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
38
|
+
***************************************************************************** */
|
|
39
|
+
|
|
40
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
41
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
42
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
43
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
44
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
45
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
46
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Trigger a re-render programmatically, without changing the component's
|
|
52
|
+
* state.
|
|
53
|
+
*
|
|
54
|
+
* Usage:
|
|
55
|
+
*
|
|
56
|
+
* const rerender = useRerender();
|
|
57
|
+
* return (
|
|
58
|
+
* <button onClick={rerender}>
|
|
59
|
+
* {Math.random()}
|
|
60
|
+
* </button>
|
|
61
|
+
* )
|
|
62
|
+
*
|
|
63
|
+
*/
|
|
64
|
+
function useRerender() {
|
|
65
|
+
const [, update] = useReducer(
|
|
66
|
+
// This implementation works by incrementing a hidden counter value that is
|
|
67
|
+
// never consumed. Simply incrementing the counter changes the component's
|
|
68
|
+
// state and, thus, trigger a re-render.
|
|
69
|
+
(x) => x + 1, 0);
|
|
70
|
+
return update;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const RoomContext = React.createContext(null);
|
|
74
|
+
/**
|
|
75
|
+
* Makes a Room available in the component hierarchy below.
|
|
76
|
+
* When this component is unmounted, the current user leave the room.
|
|
77
|
+
* That means that you can't have 2 RoomProvider with the same room id in your react tree.
|
|
78
|
+
*/
|
|
79
|
+
function RoomProvider(props) {
|
|
80
|
+
const { id: roomId, initialPresence, initialStorage, defaultPresence, // Will get removed in 0.18
|
|
81
|
+
defaultStorageRoot, } = props;
|
|
82
|
+
if (process.env.NODE_ENV !== "production") {
|
|
83
|
+
if (roomId == null) {
|
|
84
|
+
throw new Error("RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required");
|
|
85
|
+
}
|
|
86
|
+
if (typeof roomId !== "string") {
|
|
87
|
+
throw new Error("RoomProvider id property should be a string.");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
deprecateIf(defaultPresence, "RoomProvider's `defaultPresence` prop will be removed in @liveblocks/react 0.18. Please use `initialPresence` instead. For more info, see https://bit.ly/3Niy5aP", "defaultPresence");
|
|
91
|
+
deprecateIf(defaultStorageRoot, "RoomProvider's `defaultStorageRoot` prop will be removed in @liveblocks/react 0.18. Please use `initialStorage` instead. For more info, see https://bit.ly/3Niy5aP", "defaultStorageRoot");
|
|
92
|
+
const client = useClient();
|
|
93
|
+
const [room, setRoom] = React.useState(() => client.enter(roomId, {
|
|
94
|
+
initialPresence,
|
|
95
|
+
initialStorage,
|
|
96
|
+
defaultPresence,
|
|
97
|
+
defaultStorageRoot,
|
|
98
|
+
DO_NOT_USE_withoutConnecting: typeof window === "undefined",
|
|
99
|
+
}));
|
|
100
|
+
React.useEffect(() => {
|
|
101
|
+
setRoom(client.enter(roomId, {
|
|
102
|
+
initialPresence,
|
|
103
|
+
initialStorage,
|
|
104
|
+
defaultPresence,
|
|
105
|
+
defaultStorageRoot,
|
|
106
|
+
DO_NOT_USE_withoutConnecting: typeof window === "undefined",
|
|
107
|
+
}));
|
|
108
|
+
return () => {
|
|
109
|
+
client.leave(roomId);
|
|
110
|
+
};
|
|
111
|
+
}, [client, roomId]);
|
|
112
|
+
return (React.createElement(RoomContext.Provider, { value: room }, props.children));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Returns the Room of the nearest RoomProvider above in the React component
|
|
116
|
+
* tree.
|
|
117
|
+
*/
|
|
118
|
+
function useRoom() {
|
|
119
|
+
const room = React.useContext(RoomContext);
|
|
120
|
+
if (room == null) {
|
|
121
|
+
throw new Error("RoomProvider is missing from the react tree");
|
|
122
|
+
}
|
|
123
|
+
return room;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Returns the presence of the current user of the current room, and a function to update it.
|
|
127
|
+
* It is different from the setState function returned by the useState hook from React.
|
|
128
|
+
* You don't need to pass the full presence object to update it.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* import { useMyPresence } from "@liveblocks/react";
|
|
132
|
+
*
|
|
133
|
+
* const [myPresence, updateMyPresence] = useMyPresence();
|
|
134
|
+
* updateMyPresence({ x: 0 });
|
|
135
|
+
* updateMyPresence({ y: 0 });
|
|
136
|
+
*
|
|
137
|
+
* // At the next render, "myPresence" will be equal to "{ x: 0, y: 0 }"
|
|
138
|
+
*/
|
|
139
|
+
function useMyPresence() {
|
|
140
|
+
const room = useRoom();
|
|
141
|
+
const presence = room.getPresence();
|
|
142
|
+
const rerender = useRerender();
|
|
143
|
+
React.useEffect(() => {
|
|
144
|
+
const unsubscribe = room.subscribe("my-presence", rerender);
|
|
145
|
+
return () => {
|
|
146
|
+
unsubscribe();
|
|
147
|
+
};
|
|
148
|
+
}, [room]);
|
|
149
|
+
const setPresence = React.useCallback((overrides, options) => room.updatePresence(overrides, options), [room]);
|
|
150
|
+
return [presence, setPresence];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.
|
|
154
|
+
* 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.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* import { useUpdateMyPresence } from "@liveblocks/react";
|
|
158
|
+
*
|
|
159
|
+
* const updateMyPresence = useUpdateMyPresence();
|
|
160
|
+
* updateMyPresence({ x: 0 });
|
|
161
|
+
* updateMyPresence({ y: 0 });
|
|
162
|
+
*
|
|
163
|
+
* // At the next render, the presence of the current user will be equal to "{ x: 0, y: 0 }"
|
|
164
|
+
*/
|
|
165
|
+
function useUpdateMyPresence() {
|
|
166
|
+
const room = useRoom();
|
|
167
|
+
return React.useCallback((overrides, options) => {
|
|
168
|
+
room.updatePresence(overrides, options);
|
|
169
|
+
}, [room]);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Returns an object that lets you get information about all the the users currently connected in the room.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* import { useOthers } from "@liveblocks/react";
|
|
176
|
+
*
|
|
177
|
+
* const others = useOthers();
|
|
178
|
+
*
|
|
179
|
+
* // Example to map all cursors in jsx
|
|
180
|
+
* {
|
|
181
|
+
* others.map(({ connectionId, presence }) => {
|
|
182
|
+
* if(presence == null || presence.cursor == null) {
|
|
183
|
+
* return null;
|
|
184
|
+
* }
|
|
185
|
+
* return <Cursor key={connectionId} cursor={presence.cursor} />
|
|
186
|
+
* })
|
|
187
|
+
* }
|
|
188
|
+
*/
|
|
189
|
+
function useOthers() {
|
|
190
|
+
const room = useRoom();
|
|
191
|
+
const rerender = useRerender();
|
|
192
|
+
React.useEffect(() => {
|
|
193
|
+
const unsubscribe = room.subscribe("others", rerender);
|
|
194
|
+
return () => {
|
|
195
|
+
unsubscribe();
|
|
196
|
+
};
|
|
197
|
+
}, [room]);
|
|
198
|
+
return room.getOthers();
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Returns a callback that lets you broadcast custom events to other users in the room
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* import { useBroadcastEvent } from "@liveblocks/react";
|
|
205
|
+
*
|
|
206
|
+
* const broadcast = useBroadcastEvent();
|
|
207
|
+
*
|
|
208
|
+
* broadcast({ type: "CUSTOM_EVENT", data: { x: 0, y: 0 } });
|
|
209
|
+
*/
|
|
210
|
+
function useBroadcastEvent() {
|
|
211
|
+
const room = useRoom();
|
|
212
|
+
return React.useCallback((event, options = { shouldQueueEventIfNotReady: false }) => {
|
|
213
|
+
room.broadcastEvent(event, options);
|
|
214
|
+
}, [room]);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* useErrorListener is a react hook that lets you react to potential room connection errors.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* import { useErrorListener } from "@liveblocks/react";
|
|
221
|
+
*
|
|
222
|
+
* useErrorListener(er => {
|
|
223
|
+
* console.error(er);
|
|
224
|
+
* })
|
|
225
|
+
*/
|
|
226
|
+
function useErrorListener(callback) {
|
|
227
|
+
const room = useRoom();
|
|
228
|
+
const savedCallback = React.useRef(callback);
|
|
229
|
+
React.useEffect(() => {
|
|
230
|
+
savedCallback.current = callback;
|
|
231
|
+
});
|
|
232
|
+
React.useEffect(() => {
|
|
233
|
+
const listener = (e) => savedCallback.current(e);
|
|
234
|
+
const unsubscribe = room.subscribe("error", listener);
|
|
235
|
+
return () => {
|
|
236
|
+
unsubscribe();
|
|
237
|
+
};
|
|
238
|
+
}, [room]);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* useEventListener is a react hook that lets you react to event broadcasted by other users in the room.
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* import { useEventListener } from "@liveblocks/react";
|
|
245
|
+
*
|
|
246
|
+
* useEventListener(({ connectionId, event }) => {
|
|
247
|
+
* if (event.type === "CUSTOM_EVENT") {
|
|
248
|
+
* // Do something
|
|
249
|
+
* }
|
|
250
|
+
* });
|
|
251
|
+
*/
|
|
252
|
+
function useEventListener(callback) {
|
|
253
|
+
const room = useRoom();
|
|
254
|
+
const savedCallback = React.useRef(callback);
|
|
255
|
+
React.useEffect(() => {
|
|
256
|
+
savedCallback.current = callback;
|
|
257
|
+
});
|
|
258
|
+
React.useEffect(() => {
|
|
259
|
+
const listener = (e) => savedCallback.current(e);
|
|
260
|
+
const unsubscribe = room.subscribe("event", listener);
|
|
261
|
+
return () => {
|
|
262
|
+
unsubscribe();
|
|
263
|
+
};
|
|
264
|
+
}, [room]);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Gets the current user once it is connected to the room.
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* import { useSelf } from "@liveblocks/react";
|
|
271
|
+
*
|
|
272
|
+
* const user = useSelf();
|
|
273
|
+
*/
|
|
274
|
+
function useSelf() {
|
|
275
|
+
const room = useRoom();
|
|
276
|
+
const rerender = useRerender();
|
|
277
|
+
React.useEffect(() => {
|
|
278
|
+
const unsubscribePresence = room.subscribe("my-presence", rerender);
|
|
279
|
+
const unsubscribeConnection = room.subscribe("connection", rerender);
|
|
280
|
+
return () => {
|
|
281
|
+
unsubscribePresence();
|
|
282
|
+
unsubscribeConnection();
|
|
283
|
+
};
|
|
284
|
+
}, [room]);
|
|
285
|
+
return room.getSelf();
|
|
286
|
+
}
|
|
287
|
+
function useStorage() {
|
|
288
|
+
const room = useRoom();
|
|
289
|
+
const [root, setState] = React.useState(null);
|
|
290
|
+
React.useEffect(() => {
|
|
291
|
+
let didCancel = false;
|
|
292
|
+
function fetchStorage() {
|
|
293
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
294
|
+
const storage = yield room.getStorage();
|
|
295
|
+
if (!didCancel) {
|
|
296
|
+
setState(storage.root);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
fetchStorage();
|
|
301
|
+
return () => {
|
|
302
|
+
didCancel = true;
|
|
303
|
+
};
|
|
304
|
+
}, [room]);
|
|
305
|
+
return [root];
|
|
306
|
+
}
|
|
307
|
+
function useMap(key, entries) {
|
|
308
|
+
deprecateIf(entries, `Support for initializing entries in useMap() directly will be removed in @liveblocks/react 0.18.
|
|
309
|
+
|
|
310
|
+
Instead, please initialize this data where you set up your RoomProvider:
|
|
311
|
+
|
|
312
|
+
const initialStorage = () => {
|
|
313
|
+
${JSON.stringify(key)}: new LiveMap(...),
|
|
314
|
+
...
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
<RoomProvider initialStorage={initialStorage}>
|
|
318
|
+
...
|
|
319
|
+
</RoomProvider>
|
|
320
|
+
|
|
321
|
+
Please see https://bit.ly/3Niy5aP for details.`);
|
|
322
|
+
const value = useCrdt(key, new LiveMap(entries));
|
|
323
|
+
// ^^^^^^^^^^^^^^^^^^^^
|
|
324
|
+
// NOTE: This param is scheduled for removal in 0.18
|
|
325
|
+
if (value.status === "ok") {
|
|
326
|
+
return value.value;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
deprecateIf(value.status === "notfound", `Key ${JSON.stringify(key)} was not found in Storage. Starting with 0.18, useMap() will no longer automatically create this key.
|
|
330
|
+
|
|
331
|
+
Instead, please initialize your storage where you set up your RoomProvider:
|
|
332
|
+
|
|
333
|
+
import { LiveMap } from "@liveblocks/client";
|
|
334
|
+
|
|
335
|
+
const initialStorage = () => {
|
|
336
|
+
${JSON.stringify(key)}: new LiveMap(...),
|
|
337
|
+
...
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
<RoomProvider initialStorage={initialStorage}>
|
|
341
|
+
...
|
|
342
|
+
</RoomProvider>
|
|
343
|
+
|
|
344
|
+
Please see https://bit.ly/3Niy5aP for details.`);
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function useList(key, items) {
|
|
349
|
+
deprecateIf(items, `Support for initializing items in useList() directly will be removed in @liveblocks/react 0.18.
|
|
350
|
+
|
|
351
|
+
Instead, please initialize this data where you set up your RoomProvider:
|
|
352
|
+
|
|
353
|
+
import { LiveList } from "@liveblocks/client";
|
|
354
|
+
|
|
355
|
+
const initialStorage = () => {
|
|
356
|
+
${JSON.stringify(key)}: new LiveList(...),
|
|
357
|
+
...
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
<RoomProvider initialStorage={initialStorage}>
|
|
361
|
+
...
|
|
362
|
+
</RoomProvider>
|
|
363
|
+
|
|
364
|
+
Please see https://bit.ly/3Niy5aP for details.`);
|
|
365
|
+
const value = useCrdt(key, new LiveList(items));
|
|
366
|
+
// ^^^^^^^^^^^^^^^^^^^
|
|
367
|
+
// NOTE: This param is scheduled for removal in 0.18
|
|
368
|
+
if (value.status === "ok") {
|
|
369
|
+
return value.value;
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
deprecateIf(value.status === "notfound", `Key ${JSON.stringify(key)} was not found in Storage. Starting with 0.18, useList() will no longer automatically create this key.
|
|
373
|
+
|
|
374
|
+
Instead, please initialize your storage where you set up your RoomProvider:
|
|
375
|
+
|
|
376
|
+
import { LiveList } from "@liveblocks/client";
|
|
377
|
+
|
|
378
|
+
const initialStorage = () => {
|
|
379
|
+
${JSON.stringify(key)}: new LiveList(...),
|
|
380
|
+
...
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
<RoomProvider initialStorage={initialStorage}>
|
|
384
|
+
...
|
|
385
|
+
</RoomProvider>
|
|
386
|
+
|
|
387
|
+
Please see https://bit.ly/3Niy5aP for details.`);
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function useObject(key, initialData) {
|
|
392
|
+
deprecateIf(initialData, `Support for initializing data in useObject() directly will be removed in @liveblocks/react 0.18.
|
|
393
|
+
|
|
394
|
+
Instead, please initialize this data where you set up your RoomProvider:
|
|
395
|
+
|
|
396
|
+
import { LiveObject } from "@liveblocks/client";
|
|
397
|
+
|
|
398
|
+
const initialStorage = () => {
|
|
399
|
+
${JSON.stringify(key)}: new LiveObject(...),
|
|
400
|
+
...
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
<RoomProvider initialStorage={initialStorage}>
|
|
404
|
+
...
|
|
405
|
+
</RoomProvider>
|
|
406
|
+
|
|
407
|
+
Please see https://bit.ly/3Niy5aP for details.`);
|
|
408
|
+
const value = useCrdt(key, new LiveObject(initialData));
|
|
409
|
+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
410
|
+
// NOTE: This param is scheduled for removal in 0.18
|
|
411
|
+
if (value.status === "ok") {
|
|
412
|
+
return value.value;
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
deprecateIf(value.status === "notfound", `Key ${JSON.stringify(key)} was not found in Storage. Starting with 0.18, useObject() will no longer automatically create this key.
|
|
416
|
+
|
|
417
|
+
Instead, please initialize your storage where you set up your RoomProvider:
|
|
418
|
+
|
|
419
|
+
import { LiveObject } from "@liveblocks/client";
|
|
420
|
+
|
|
421
|
+
const initialStorage = () => {
|
|
422
|
+
${JSON.stringify(key)}: new LiveObject(...),
|
|
423
|
+
...
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
<RoomProvider initialStorage={initialStorage}>
|
|
427
|
+
...
|
|
428
|
+
</RoomProvider>
|
|
429
|
+
|
|
430
|
+
Please see https://bit.ly/3Niy5aP for details.`);
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Returns a function that undoes the last operation executed by the current client.
|
|
436
|
+
* It does not impact operations made by other clients.
|
|
437
|
+
*/
|
|
438
|
+
function useUndo() {
|
|
439
|
+
return useRoom().history.undo;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Returns a function that redoes the last operation executed by the current client.
|
|
443
|
+
* It does not impact operations made by other clients.
|
|
444
|
+
*/
|
|
445
|
+
function useRedo() {
|
|
446
|
+
return useRoom().history.redo;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Returns a function that batches modifications made during the given function.
|
|
450
|
+
* All the modifications are sent to other clients in a single message.
|
|
451
|
+
* All the modifications are merged in a single history item (undo/redo).
|
|
452
|
+
* All the subscribers are called only after the batch is over.
|
|
453
|
+
*/
|
|
454
|
+
function useBatch() {
|
|
455
|
+
return useRoom().batch;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Returns the room.history
|
|
459
|
+
*/
|
|
460
|
+
function useHistory() {
|
|
461
|
+
return useRoom().history;
|
|
462
|
+
}
|
|
463
|
+
function useCrdt(key, initialCrdt) {
|
|
464
|
+
const room = useRoom();
|
|
465
|
+
const [root] = useStorage();
|
|
466
|
+
const rerender = useRerender();
|
|
467
|
+
React.useEffect(() => {
|
|
468
|
+
if (root == null) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
let crdt = root.get(key);
|
|
472
|
+
if (crdt == null) {
|
|
473
|
+
crdt = initialCrdt;
|
|
474
|
+
root.set(key, crdt);
|
|
475
|
+
}
|
|
476
|
+
function onRootChange() {
|
|
477
|
+
const newCrdt = root.get(key);
|
|
478
|
+
if (newCrdt !== crdt) {
|
|
479
|
+
unsubscribeCrdt();
|
|
480
|
+
crdt = newCrdt;
|
|
481
|
+
unsubscribeCrdt = room.subscribe(crdt /* AbstractCrdt */, rerender);
|
|
482
|
+
rerender();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
let unsubscribeCrdt = room.subscribe(crdt /* AbstractCrdt */, rerender);
|
|
486
|
+
const unsubscribeRoot = room.subscribe(root /* AbstractCrdt */, onRootChange);
|
|
487
|
+
rerender();
|
|
488
|
+
return () => {
|
|
489
|
+
unsubscribeRoot();
|
|
490
|
+
unsubscribeCrdt();
|
|
491
|
+
};
|
|
492
|
+
}, [root, room]);
|
|
493
|
+
if (root == null) {
|
|
494
|
+
return { status: "loading" };
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
const value = root.get(key);
|
|
498
|
+
if (value == null) {
|
|
499
|
+
return { status: "notfound" };
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
return { status: "ok", value };
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export { LiveblocksProvider, RoomProvider, useBatch, useBroadcastEvent, useClient, useErrorListener, useEventListener, useHistory, useList, useMap, useMyPresence, useObject, useOthers, useRedo, useRoom, useSelf, useStorage, useUndo, useUpdateMyPresence };
|
package/package.json
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/react",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "A set of React hooks and providers to use Liveblocks declaratively.",
|
|
5
5
|
"main": "./index.js",
|
|
6
|
+
"module": "./index.mjs",
|
|
6
7
|
"types": "./index.d.ts",
|
|
7
8
|
"files": [
|
|
8
9
|
"**"
|
|
9
10
|
],
|
|
10
|
-
"exports": {
|
|
11
|
-
"./package.json": "./package.json",
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./index.d.ts",
|
|
14
|
-
"module": "./esm/index.js",
|
|
15
|
-
"import": "./esm/index.mjs",
|
|
16
|
-
"default": "./index.js"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
11
|
"keywords": [
|
|
20
12
|
"react",
|
|
21
13
|
"liveblocks",
|
|
@@ -29,11 +21,13 @@
|
|
|
29
21
|
"scripts": {
|
|
30
22
|
"build": "rollup -c && cp ./package.json ./README.md ./lib",
|
|
31
23
|
"start": "rollup -c -w",
|
|
32
|
-
"
|
|
24
|
+
"lint": "eslint src/",
|
|
25
|
+
"test": "jest --watch",
|
|
26
|
+
"test-ci": "jest"
|
|
33
27
|
},
|
|
34
28
|
"license": "Apache-2.0",
|
|
35
29
|
"peerDependencies": {
|
|
36
|
-
"@liveblocks/client": "0.16.
|
|
30
|
+
"@liveblocks/client": "0.16.4",
|
|
37
31
|
"react": "^16.14.0 || ^17 || ^18"
|
|
38
32
|
},
|
|
39
33
|
"devDependencies": {
|
|
@@ -43,6 +37,7 @@
|
|
|
43
37
|
"@babel/preset-typescript": "^7.12.16",
|
|
44
38
|
"@rollup/plugin-babel": "^5.3.1",
|
|
45
39
|
"@rollup/plugin-node-resolve": "^11.2.1",
|
|
40
|
+
"@rollup/plugin-replace": "^4.0.0",
|
|
46
41
|
"@rollup/plugin-typescript": "^8.3.1",
|
|
47
42
|
"@testing-library/jest-dom": "^5.11.9",
|
|
48
43
|
"@testing-library/react": "^13.1.1",
|
|
@@ -59,8 +54,8 @@
|
|
|
59
54
|
"msw": "^0.27.1",
|
|
60
55
|
"react-error-boundary": "^3.1.1",
|
|
61
56
|
"rollup": "^2.39.0",
|
|
57
|
+
"rollup-plugin-command": "^1.1.3",
|
|
62
58
|
"rollup-plugin-dts": "^4.2.0",
|
|
63
|
-
"rollup-plugin-esbuild": "^4.8.2",
|
|
64
59
|
"typescript": "^4.1.5",
|
|
65
60
|
"whatwg-fetch": "^3.6.2"
|
|
66
61
|
},
|
|
@@ -68,5 +63,6 @@
|
|
|
68
63
|
"type": "git",
|
|
69
64
|
"url": "https://github.com/liveblocks/liveblocks.git",
|
|
70
65
|
"directory": "packages/liveblocks-react"
|
|
71
|
-
}
|
|
66
|
+
},
|
|
67
|
+
"sideEffects": false
|
|
72
68
|
}
|
package/esm/index.js
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { useReducer } from 'react';
|
|
3
|
-
import { LiveMap, LiveList, LiveObject } from '@liveblocks/client';
|
|
4
|
-
|
|
5
|
-
const ClientContext = React.createContext(null);
|
|
6
|
-
function LiveblocksProvider(props) {
|
|
7
|
-
return /* @__PURE__ */ React.createElement(ClientContext.Provider, {
|
|
8
|
-
value: props.client
|
|
9
|
-
}, props.children);
|
|
10
|
-
}
|
|
11
|
-
function useClient() {
|
|
12
|
-
const client = React.useContext(ClientContext);
|
|
13
|
-
if (client == null) {
|
|
14
|
-
throw new Error("LiveblocksProvider is missing from the react tree");
|
|
15
|
-
}
|
|
16
|
-
return client;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function useRerender() {
|
|
20
|
-
const [, update] = useReducer((x) => x + 1, 0);
|
|
21
|
-
return update;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const RoomContext = React.createContext(null);
|
|
25
|
-
function RoomProvider({
|
|
26
|
-
id,
|
|
27
|
-
children,
|
|
28
|
-
defaultPresence,
|
|
29
|
-
defaultStorageRoot
|
|
30
|
-
}) {
|
|
31
|
-
if (process.env.NODE_ENV !== "production") {
|
|
32
|
-
if (id == null) {
|
|
33
|
-
throw new Error("RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required");
|
|
34
|
-
}
|
|
35
|
-
if (typeof id !== "string") {
|
|
36
|
-
throw new Error("RoomProvider id property should be a string.");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
const client = useClient();
|
|
40
|
-
const [room, setRoom] = React.useState(() => client.enter(id, {
|
|
41
|
-
defaultPresence: defaultPresence ? defaultPresence() : void 0,
|
|
42
|
-
defaultStorageRoot,
|
|
43
|
-
DO_NOT_USE_withoutConnecting: typeof window === "undefined"
|
|
44
|
-
}));
|
|
45
|
-
React.useEffect(() => {
|
|
46
|
-
setRoom(client.enter(id, {
|
|
47
|
-
defaultPresence: defaultPresence ? defaultPresence() : void 0,
|
|
48
|
-
defaultStorageRoot,
|
|
49
|
-
DO_NOT_USE_withoutConnecting: typeof window === "undefined"
|
|
50
|
-
}));
|
|
51
|
-
return () => {
|
|
52
|
-
client.leave(id);
|
|
53
|
-
};
|
|
54
|
-
}, [client, id]);
|
|
55
|
-
return /* @__PURE__ */ React.createElement(RoomContext.Provider, {
|
|
56
|
-
value: room
|
|
57
|
-
}, children);
|
|
58
|
-
}
|
|
59
|
-
function useRoom() {
|
|
60
|
-
const room = React.useContext(RoomContext);
|
|
61
|
-
if (room == null) {
|
|
62
|
-
throw new Error("RoomProvider is missing from the react tree");
|
|
63
|
-
}
|
|
64
|
-
return room;
|
|
65
|
-
}
|
|
66
|
-
function useMyPresence() {
|
|
67
|
-
const room = useRoom();
|
|
68
|
-
const presence = room.getPresence();
|
|
69
|
-
const rerender = useRerender();
|
|
70
|
-
React.useEffect(() => {
|
|
71
|
-
const unsubscribe = room.subscribe("my-presence", rerender);
|
|
72
|
-
return () => {
|
|
73
|
-
unsubscribe();
|
|
74
|
-
};
|
|
75
|
-
}, [room]);
|
|
76
|
-
const setPresence = React.useCallback((overrides, options) => room.updatePresence(overrides, options), [room]);
|
|
77
|
-
return [presence, setPresence];
|
|
78
|
-
}
|
|
79
|
-
function useUpdateMyPresence() {
|
|
80
|
-
const room = useRoom();
|
|
81
|
-
return React.useCallback((overrides, options) => {
|
|
82
|
-
room.updatePresence(overrides, options);
|
|
83
|
-
}, [room]);
|
|
84
|
-
}
|
|
85
|
-
function useOthers() {
|
|
86
|
-
const room = useRoom();
|
|
87
|
-
const rerender = useRerender();
|
|
88
|
-
React.useEffect(() => {
|
|
89
|
-
const unsubscribe = room.subscribe("others", rerender);
|
|
90
|
-
return () => {
|
|
91
|
-
unsubscribe();
|
|
92
|
-
};
|
|
93
|
-
}, [room]);
|
|
94
|
-
return room.getOthers();
|
|
95
|
-
}
|
|
96
|
-
function useBroadcastEvent() {
|
|
97
|
-
const room = useRoom();
|
|
98
|
-
return React.useCallback((event, options = { shouldQueueEventIfNotReady: false }) => {
|
|
99
|
-
room.broadcastEvent(event, options);
|
|
100
|
-
}, [room]);
|
|
101
|
-
}
|
|
102
|
-
function useErrorListener(callback) {
|
|
103
|
-
const room = useRoom();
|
|
104
|
-
const savedCallback = React.useRef(callback);
|
|
105
|
-
React.useEffect(() => {
|
|
106
|
-
savedCallback.current = callback;
|
|
107
|
-
});
|
|
108
|
-
React.useEffect(() => {
|
|
109
|
-
const listener = (e) => savedCallback.current(e);
|
|
110
|
-
const unsubscribe = room.subscribe("error", listener);
|
|
111
|
-
return () => {
|
|
112
|
-
unsubscribe();
|
|
113
|
-
};
|
|
114
|
-
}, [room]);
|
|
115
|
-
}
|
|
116
|
-
function useEventListener(callback) {
|
|
117
|
-
const room = useRoom();
|
|
118
|
-
const savedCallback = React.useRef(callback);
|
|
119
|
-
React.useEffect(() => {
|
|
120
|
-
savedCallback.current = callback;
|
|
121
|
-
});
|
|
122
|
-
React.useEffect(() => {
|
|
123
|
-
const listener = (e) => savedCallback.current(e);
|
|
124
|
-
const unsubscribe = room.subscribe("event", listener);
|
|
125
|
-
return () => {
|
|
126
|
-
unsubscribe();
|
|
127
|
-
};
|
|
128
|
-
}, [room]);
|
|
129
|
-
}
|
|
130
|
-
function useSelf() {
|
|
131
|
-
const room = useRoom();
|
|
132
|
-
const rerender = useRerender();
|
|
133
|
-
React.useEffect(() => {
|
|
134
|
-
const unsubscribePresence = room.subscribe("my-presence", rerender);
|
|
135
|
-
const unsubscribeConnection = room.subscribe("connection", rerender);
|
|
136
|
-
return () => {
|
|
137
|
-
unsubscribePresence();
|
|
138
|
-
unsubscribeConnection();
|
|
139
|
-
};
|
|
140
|
-
}, [room]);
|
|
141
|
-
return room.getSelf();
|
|
142
|
-
}
|
|
143
|
-
function useStorage() {
|
|
144
|
-
const room = useRoom();
|
|
145
|
-
const [root, setState] = React.useState(null);
|
|
146
|
-
React.useEffect(() => {
|
|
147
|
-
let didCancel = false;
|
|
148
|
-
async function fetchStorage() {
|
|
149
|
-
const storage = await room.getStorage();
|
|
150
|
-
if (!didCancel) {
|
|
151
|
-
setState(storage.root);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
fetchStorage();
|
|
155
|
-
return () => {
|
|
156
|
-
didCancel = true;
|
|
157
|
-
};
|
|
158
|
-
}, [room]);
|
|
159
|
-
return [root];
|
|
160
|
-
}
|
|
161
|
-
function useMap(key, entries) {
|
|
162
|
-
return useCrdt(key, new LiveMap(entries));
|
|
163
|
-
}
|
|
164
|
-
function useList(key, items) {
|
|
165
|
-
return useCrdt(key, new LiveList(items));
|
|
166
|
-
}
|
|
167
|
-
function useObject(key, initialData) {
|
|
168
|
-
return useCrdt(key, new LiveObject(initialData));
|
|
169
|
-
}
|
|
170
|
-
function useUndo() {
|
|
171
|
-
return useRoom().history.undo;
|
|
172
|
-
}
|
|
173
|
-
function useRedo() {
|
|
174
|
-
return useRoom().history.redo;
|
|
175
|
-
}
|
|
176
|
-
function useBatch() {
|
|
177
|
-
return useRoom().batch;
|
|
178
|
-
}
|
|
179
|
-
function useHistory() {
|
|
180
|
-
return useRoom().history;
|
|
181
|
-
}
|
|
182
|
-
function useCrdt(key, initialCrdt) {
|
|
183
|
-
var _a;
|
|
184
|
-
const room = useRoom();
|
|
185
|
-
const [root] = useStorage();
|
|
186
|
-
const rerender = useRerender();
|
|
187
|
-
React.useEffect(() => {
|
|
188
|
-
if (root == null) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
let crdt = root.get(key);
|
|
192
|
-
if (crdt == null) {
|
|
193
|
-
crdt = initialCrdt;
|
|
194
|
-
root.set(key, crdt);
|
|
195
|
-
}
|
|
196
|
-
function onRootChange() {
|
|
197
|
-
const newCrdt = root.get(key);
|
|
198
|
-
if (newCrdt !== crdt) {
|
|
199
|
-
unsubscribeCrdt();
|
|
200
|
-
crdt = newCrdt;
|
|
201
|
-
unsubscribeCrdt = room.subscribe(crdt, rerender);
|
|
202
|
-
rerender();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
let unsubscribeCrdt = room.subscribe(crdt, rerender);
|
|
206
|
-
const unsubscribeRoot = room.subscribe(root, onRootChange);
|
|
207
|
-
rerender();
|
|
208
|
-
return () => {
|
|
209
|
-
unsubscribeRoot();
|
|
210
|
-
unsubscribeCrdt();
|
|
211
|
-
};
|
|
212
|
-
}, [root, room]);
|
|
213
|
-
return (_a = root == null ? void 0 : root.get(key)) != null ? _a : null;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export { LiveblocksProvider, RoomProvider, useBatch, useBroadcastEvent, useClient, useErrorListener, useEventListener, useHistory, useList, useMap, useMyPresence, useObject, useOthers, useRedo, useRoom, useSelf, useStorage, useUndo, useUpdateMyPresence };
|
package/esm/index.mjs
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { useReducer } from 'react';
|
|
3
|
-
import { LiveMap, LiveList, LiveObject } from '@liveblocks/client';
|
|
4
|
-
|
|
5
|
-
const ClientContext = React.createContext(null);
|
|
6
|
-
function LiveblocksProvider(props) {
|
|
7
|
-
return /* @__PURE__ */ React.createElement(ClientContext.Provider, {
|
|
8
|
-
value: props.client
|
|
9
|
-
}, props.children);
|
|
10
|
-
}
|
|
11
|
-
function useClient() {
|
|
12
|
-
const client = React.useContext(ClientContext);
|
|
13
|
-
if (client == null) {
|
|
14
|
-
throw new Error("LiveblocksProvider is missing from the react tree");
|
|
15
|
-
}
|
|
16
|
-
return client;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function useRerender() {
|
|
20
|
-
const [, update] = useReducer((x) => x + 1, 0);
|
|
21
|
-
return update;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const RoomContext = React.createContext(null);
|
|
25
|
-
function RoomProvider({
|
|
26
|
-
id,
|
|
27
|
-
children,
|
|
28
|
-
defaultPresence,
|
|
29
|
-
defaultStorageRoot
|
|
30
|
-
}) {
|
|
31
|
-
if (process.env.NODE_ENV !== "production") {
|
|
32
|
-
if (id == null) {
|
|
33
|
-
throw new Error("RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required");
|
|
34
|
-
}
|
|
35
|
-
if (typeof id !== "string") {
|
|
36
|
-
throw new Error("RoomProvider id property should be a string.");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
const client = useClient();
|
|
40
|
-
const [room, setRoom] = React.useState(() => client.enter(id, {
|
|
41
|
-
defaultPresence: defaultPresence ? defaultPresence() : void 0,
|
|
42
|
-
defaultStorageRoot,
|
|
43
|
-
DO_NOT_USE_withoutConnecting: typeof window === "undefined"
|
|
44
|
-
}));
|
|
45
|
-
React.useEffect(() => {
|
|
46
|
-
setRoom(client.enter(id, {
|
|
47
|
-
defaultPresence: defaultPresence ? defaultPresence() : void 0,
|
|
48
|
-
defaultStorageRoot,
|
|
49
|
-
DO_NOT_USE_withoutConnecting: typeof window === "undefined"
|
|
50
|
-
}));
|
|
51
|
-
return () => {
|
|
52
|
-
client.leave(id);
|
|
53
|
-
};
|
|
54
|
-
}, [client, id]);
|
|
55
|
-
return /* @__PURE__ */ React.createElement(RoomContext.Provider, {
|
|
56
|
-
value: room
|
|
57
|
-
}, children);
|
|
58
|
-
}
|
|
59
|
-
function useRoom() {
|
|
60
|
-
const room = React.useContext(RoomContext);
|
|
61
|
-
if (room == null) {
|
|
62
|
-
throw new Error("RoomProvider is missing from the react tree");
|
|
63
|
-
}
|
|
64
|
-
return room;
|
|
65
|
-
}
|
|
66
|
-
function useMyPresence() {
|
|
67
|
-
const room = useRoom();
|
|
68
|
-
const presence = room.getPresence();
|
|
69
|
-
const rerender = useRerender();
|
|
70
|
-
React.useEffect(() => {
|
|
71
|
-
const unsubscribe = room.subscribe("my-presence", rerender);
|
|
72
|
-
return () => {
|
|
73
|
-
unsubscribe();
|
|
74
|
-
};
|
|
75
|
-
}, [room]);
|
|
76
|
-
const setPresence = React.useCallback((overrides, options) => room.updatePresence(overrides, options), [room]);
|
|
77
|
-
return [presence, setPresence];
|
|
78
|
-
}
|
|
79
|
-
function useUpdateMyPresence() {
|
|
80
|
-
const room = useRoom();
|
|
81
|
-
return React.useCallback((overrides, options) => {
|
|
82
|
-
room.updatePresence(overrides, options);
|
|
83
|
-
}, [room]);
|
|
84
|
-
}
|
|
85
|
-
function useOthers() {
|
|
86
|
-
const room = useRoom();
|
|
87
|
-
const rerender = useRerender();
|
|
88
|
-
React.useEffect(() => {
|
|
89
|
-
const unsubscribe = room.subscribe("others", rerender);
|
|
90
|
-
return () => {
|
|
91
|
-
unsubscribe();
|
|
92
|
-
};
|
|
93
|
-
}, [room]);
|
|
94
|
-
return room.getOthers();
|
|
95
|
-
}
|
|
96
|
-
function useBroadcastEvent() {
|
|
97
|
-
const room = useRoom();
|
|
98
|
-
return React.useCallback((event, options = { shouldQueueEventIfNotReady: false }) => {
|
|
99
|
-
room.broadcastEvent(event, options);
|
|
100
|
-
}, [room]);
|
|
101
|
-
}
|
|
102
|
-
function useErrorListener(callback) {
|
|
103
|
-
const room = useRoom();
|
|
104
|
-
const savedCallback = React.useRef(callback);
|
|
105
|
-
React.useEffect(() => {
|
|
106
|
-
savedCallback.current = callback;
|
|
107
|
-
});
|
|
108
|
-
React.useEffect(() => {
|
|
109
|
-
const listener = (e) => savedCallback.current(e);
|
|
110
|
-
const unsubscribe = room.subscribe("error", listener);
|
|
111
|
-
return () => {
|
|
112
|
-
unsubscribe();
|
|
113
|
-
};
|
|
114
|
-
}, [room]);
|
|
115
|
-
}
|
|
116
|
-
function useEventListener(callback) {
|
|
117
|
-
const room = useRoom();
|
|
118
|
-
const savedCallback = React.useRef(callback);
|
|
119
|
-
React.useEffect(() => {
|
|
120
|
-
savedCallback.current = callback;
|
|
121
|
-
});
|
|
122
|
-
React.useEffect(() => {
|
|
123
|
-
const listener = (e) => savedCallback.current(e);
|
|
124
|
-
const unsubscribe = room.subscribe("event", listener);
|
|
125
|
-
return () => {
|
|
126
|
-
unsubscribe();
|
|
127
|
-
};
|
|
128
|
-
}, [room]);
|
|
129
|
-
}
|
|
130
|
-
function useSelf() {
|
|
131
|
-
const room = useRoom();
|
|
132
|
-
const rerender = useRerender();
|
|
133
|
-
React.useEffect(() => {
|
|
134
|
-
const unsubscribePresence = room.subscribe("my-presence", rerender);
|
|
135
|
-
const unsubscribeConnection = room.subscribe("connection", rerender);
|
|
136
|
-
return () => {
|
|
137
|
-
unsubscribePresence();
|
|
138
|
-
unsubscribeConnection();
|
|
139
|
-
};
|
|
140
|
-
}, [room]);
|
|
141
|
-
return room.getSelf();
|
|
142
|
-
}
|
|
143
|
-
function useStorage() {
|
|
144
|
-
const room = useRoom();
|
|
145
|
-
const [root, setState] = React.useState(null);
|
|
146
|
-
React.useEffect(() => {
|
|
147
|
-
let didCancel = false;
|
|
148
|
-
async function fetchStorage() {
|
|
149
|
-
const storage = await room.getStorage();
|
|
150
|
-
if (!didCancel) {
|
|
151
|
-
setState(storage.root);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
fetchStorage();
|
|
155
|
-
return () => {
|
|
156
|
-
didCancel = true;
|
|
157
|
-
};
|
|
158
|
-
}, [room]);
|
|
159
|
-
return [root];
|
|
160
|
-
}
|
|
161
|
-
function useMap(key, entries) {
|
|
162
|
-
return useCrdt(key, new LiveMap(entries));
|
|
163
|
-
}
|
|
164
|
-
function useList(key, items) {
|
|
165
|
-
return useCrdt(key, new LiveList(items));
|
|
166
|
-
}
|
|
167
|
-
function useObject(key, initialData) {
|
|
168
|
-
return useCrdt(key, new LiveObject(initialData));
|
|
169
|
-
}
|
|
170
|
-
function useUndo() {
|
|
171
|
-
return useRoom().history.undo;
|
|
172
|
-
}
|
|
173
|
-
function useRedo() {
|
|
174
|
-
return useRoom().history.redo;
|
|
175
|
-
}
|
|
176
|
-
function useBatch() {
|
|
177
|
-
return useRoom().batch;
|
|
178
|
-
}
|
|
179
|
-
function useHistory() {
|
|
180
|
-
return useRoom().history;
|
|
181
|
-
}
|
|
182
|
-
function useCrdt(key, initialCrdt) {
|
|
183
|
-
var _a;
|
|
184
|
-
const room = useRoom();
|
|
185
|
-
const [root] = useStorage();
|
|
186
|
-
const rerender = useRerender();
|
|
187
|
-
React.useEffect(() => {
|
|
188
|
-
if (root == null) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
let crdt = root.get(key);
|
|
192
|
-
if (crdt == null) {
|
|
193
|
-
crdt = initialCrdt;
|
|
194
|
-
root.set(key, crdt);
|
|
195
|
-
}
|
|
196
|
-
function onRootChange() {
|
|
197
|
-
const newCrdt = root.get(key);
|
|
198
|
-
if (newCrdt !== crdt) {
|
|
199
|
-
unsubscribeCrdt();
|
|
200
|
-
crdt = newCrdt;
|
|
201
|
-
unsubscribeCrdt = room.subscribe(crdt, rerender);
|
|
202
|
-
rerender();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
let unsubscribeCrdt = room.subscribe(crdt, rerender);
|
|
206
|
-
const unsubscribeRoot = room.subscribe(root, onRootChange);
|
|
207
|
-
rerender();
|
|
208
|
-
return () => {
|
|
209
|
-
unsubscribeRoot();
|
|
210
|
-
unsubscribeCrdt();
|
|
211
|
-
};
|
|
212
|
-
}, [root, room]);
|
|
213
|
-
return (_a = root == null ? void 0 : root.get(key)) != null ? _a : null;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export { LiveblocksProvider, RoomProvider, useBatch, useBroadcastEvent, useClient, useErrorListener, useEventListener, useHistory, useList, useMap, useMyPresence, useObject, useOthers, useRedo, useRoom, useSelf, useStorage, useUndo, useUpdateMyPresence };
|