@microsoft/live-share-react 1.3.0-preview.0 → 1.3.1-preview.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.
Files changed (38) hide show
  1. package/.nycrc.json +9 -9
  2. package/LICENSE +86 -86
  3. package/README.md +608 -608
  4. package/package.json +50 -50
  5. package/src/index.ts +6 -6
  6. package/src/interfaces/LiveInterfaceExtensions.ts +26 -26
  7. package/src/interfaces/index.ts +1 -1
  8. package/src/internal/errors.ts +57 -57
  9. package/src/internal/index.ts +2 -2
  10. package/src/internal/type-guards.ts +9 -9
  11. package/src/live-hooks/index.ts +7 -7
  12. package/src/live-hooks/useLiveCanvas.ts +191 -191
  13. package/src/live-hooks/useLiveEvent.ts +140 -140
  14. package/src/live-hooks/useLiveFollowMode.ts +316 -316
  15. package/src/live-hooks/useLivePresence.ts +147 -147
  16. package/src/live-hooks/useLiveState.ts +110 -110
  17. package/src/live-hooks/useLiveTimer.ts +213 -213
  18. package/src/live-hooks/useMediaSynchronizer.ts +295 -295
  19. package/src/providers/AzureProvider.tsx +261 -261
  20. package/src/providers/LiveShareProvider.tsx +210 -210
  21. package/src/providers/index.ts +2 -2
  22. package/src/shared-hooks/index.ts +4 -4
  23. package/src/shared-hooks/useDynamicDDS.ts +82 -82
  24. package/src/shared-hooks/useSharedMap.ts +159 -159
  25. package/src/shared-hooks/useSharedState.ts +96 -96
  26. package/src/shared-hooks/useSharedStateRegistry.ts +170 -170
  27. package/src/types/ActionTypes.ts +161 -161
  28. package/src/types/PropTypes.ts +10 -10
  29. package/src/types/ResultTypes.ts +332 -332
  30. package/src/types/index.ts +3 -3
  31. package/src/utils/index.ts +1 -1
  32. package/src/utils/type-check.ts +69 -69
  33. package/tsconfig.build.json +5 -5
  34. package/tsconfig.json +72 -72
  35. package/bin/internal/useSharedStateRegistry.d.ts +0 -31
  36. package/bin/internal/useSharedStateRegistry.d.ts.map +0 -1
  37. package/bin/internal/useSharedStateRegistry.js +0 -102
  38. package/bin/internal/useSharedStateRegistry.js.map +0 -1
@@ -1,316 +1,316 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the Microsoft Live Share SDK License.
4
- */
5
-
6
- import {
7
- LivePresenceUser,
8
- UserMeetingRole,
9
- LiveDataObjectInitializeState,
10
- LiveFollowMode,
11
- IFollowModePresenceUserData,
12
- IFollowModeState,
13
- } from "@microsoft/live-share";
14
- import React from "react";
15
- import { useDynamicDDS } from "../shared-hooks";
16
- import { useFluidObjectsContext } from "../providers";
17
- import {
18
- ActionContainerNotJoinedError,
19
- ActionLiveDataObjectInitializedError,
20
- ActionLiveDataObjectUndefinedError,
21
- } from "../internal";
22
- import { IUseLiveFollowModeResults } from "../types";
23
-
24
- /**
25
- * React hook for using a Live Share `LiveFollowMode`.
26
- *
27
- * @remarks
28
- * Use this hook if you want to add the ability to follow specific users or let a user present to everyone in the session.
29
- * Each user has their own `stateValue`, which is the value other users will reference when that user is presenting or being followed.
30
- * The `state` response includes the user's `value` that the local user is "following", whether it be their own or someone else's.
31
- * This hook can only be used in a child component of `<LiveShareProvider>` or `<AzureProvider>`.
32
- *
33
- * @template TData Optional typing for the custom user presence data object. Default is `object` type.
34
- *
35
- * @param uniqueKey The unique key for `LiveFollowMode`. If one does not yet exist, a new one will be created.
36
- * @param initialData The initial value for the local user's `stateValue`.
37
- * @param allowedRoles Optional. The user roles that are allowed to present to use `startPresenting()` or `stopPresenting()`.
38
- * @returns `IUseLiveFollowModeResults` results, which contains React stateful objects and callbacks.
39
- */
40
- export function useLiveFollowMode<TData = any>(
41
- uniqueKey: string,
42
- initialData: TData | (() => TData),
43
- allowedRoles?: UserMeetingRole[]
44
- ): IUseLiveFollowModeResults<TData> {
45
- /**
46
- * Stateful follow state.
47
- */
48
- const [state, setState] = React.useState<IFollowModeState<TData>>();
49
- /**
50
- * Stateful all user presence list and its non-user-facing setter method.
51
- */
52
- const [allUsers, setAllUsers] = React.useState<
53
- LivePresenceUser<IFollowModePresenceUserData<TData>>[]
54
- >([]);
55
- /**
56
- * User facing: dynamically load the DDS for the given unique key.
57
- */
58
- const { dds: liveFollowMode } = useDynamicDDS<LiveFollowMode<TData>>(
59
- uniqueKey,
60
- LiveFollowMode<TData>
61
- );
62
-
63
- /**
64
- * User facing: list of non-local user's presence objects.
65
- */
66
- const otherUsers = allUsers.filter((user) => !user.isLocalUser);
67
-
68
- /**
69
- * User facing: local user's presence object.
70
- */
71
- const localUser = allUsers.find((user) => user.isLocalUser);
72
-
73
- const { container } = useFluidObjectsContext();
74
-
75
- /**
76
- * User facing: callback to update the local user's custom data for their follow state.
77
- */
78
- const update = React.useCallback(
79
- async (stateValue: TData) => {
80
- if (!container) {
81
- throw new ActionContainerNotJoinedError(
82
- "liveFollowMode",
83
- "update"
84
- );
85
- }
86
- if (liveFollowMode === undefined) {
87
- throw new ActionLiveDataObjectUndefinedError(
88
- "liveFollowMode",
89
- "update"
90
- );
91
- }
92
- if (!liveFollowMode.isInitialized) {
93
- throw new ActionLiveDataObjectInitializedError(
94
- "liveFollowMode",
95
- "update"
96
- );
97
- }
98
- return await liveFollowMode.update(stateValue);
99
- },
100
- [container, liveFollowMode]
101
- );
102
-
103
- /**
104
- * User facing: callback to start presenting.
105
- */
106
- const startPresenting = React.useCallback(async () => {
107
- if (!container) {
108
- throw new ActionContainerNotJoinedError(
109
- "liveFollowMode",
110
- "startPresenting"
111
- );
112
- }
113
- if (liveFollowMode === undefined) {
114
- throw new ActionLiveDataObjectUndefinedError(
115
- "liveFollowMode",
116
- "startPresenting"
117
- );
118
- }
119
- if (!liveFollowMode.isInitialized) {
120
- throw new ActionLiveDataObjectInitializedError(
121
- "liveFollowMode",
122
- "startPresenting"
123
- );
124
- }
125
- return await liveFollowMode.startPresenting();
126
- }, [container, liveFollowMode]);
127
-
128
- /**
129
- * User facing: callback to stop presenting.
130
- */
131
- const stopPresenting = React.useCallback(async () => {
132
- if (!container) {
133
- throw new ActionContainerNotJoinedError(
134
- "liveFollowMode",
135
- "stopPresenting"
136
- );
137
- }
138
- if (liveFollowMode === undefined) {
139
- throw new ActionLiveDataObjectUndefinedError(
140
- "liveFollowMode",
141
- "stopPresenting"
142
- );
143
- }
144
- if (!liveFollowMode.isInitialized) {
145
- throw new ActionLiveDataObjectInitializedError(
146
- "liveFollowMode",
147
- "stopPresenting"
148
- );
149
- }
150
- return await liveFollowMode.stopPresenting();
151
- }, [container, liveFollowMode]);
152
-
153
- /**
154
- * User facing: callback to suspend sync.
155
- */
156
- const beginSuspension = React.useCallback(async () => {
157
- if (!container) {
158
- throw new ActionContainerNotJoinedError(
159
- "liveFollowMode",
160
- "syncToPresenter"
161
- );
162
- }
163
- if (liveFollowMode === undefined) {
164
- throw new ActionLiveDataObjectUndefinedError(
165
- "liveFollowMode",
166
- "syncToPresenter"
167
- );
168
- }
169
- if (!liveFollowMode.isInitialized) {
170
- throw new ActionLiveDataObjectInitializedError(
171
- "liveFollowMode",
172
- "syncToPresenter"
173
- );
174
- }
175
- return await liveFollowMode.beginSuspension();
176
- }, [container, liveFollowMode]);
177
-
178
- /**
179
- * User facing: callback to end current suspension.
180
- */
181
- const endSuspension = React.useCallback(async () => {
182
- if (!container) {
183
- throw new ActionContainerNotJoinedError(
184
- "liveFollowMode",
185
- "syncToPresenter"
186
- );
187
- }
188
- if (liveFollowMode === undefined) {
189
- throw new ActionLiveDataObjectUndefinedError(
190
- "liveFollowMode",
191
- "syncToPresenter"
192
- );
193
- }
194
- if (!liveFollowMode.isInitialized) {
195
- throw new ActionLiveDataObjectInitializedError(
196
- "liveFollowMode",
197
- "syncToPresenter"
198
- );
199
- }
200
- return await liveFollowMode.endSuspension();
201
- }, [container, liveFollowMode]);
202
-
203
- /**
204
- * User facing: callback to follow a specific user.
205
- */
206
- const followUser = React.useCallback(
207
- async (userId: string) => {
208
- if (!container) {
209
- throw new ActionContainerNotJoinedError(
210
- "liveFollowMode",
211
- "followUser"
212
- );
213
- }
214
- if (liveFollowMode === undefined) {
215
- throw new ActionLiveDataObjectUndefinedError(
216
- "liveFollowMode",
217
- "followUser"
218
- );
219
- }
220
- if (!liveFollowMode.isInitialized) {
221
- throw new ActionLiveDataObjectInitializedError(
222
- "liveFollowMode",
223
- "followUser"
224
- );
225
- }
226
- return await liveFollowMode.followUser(userId);
227
- },
228
- [container, liveFollowMode]
229
- );
230
-
231
- /**
232
- * User facing: callback to stop following a user.
233
- */
234
- const stopFollowing = React.useCallback(async () => {
235
- if (!container) {
236
- throw new ActionContainerNotJoinedError(
237
- "liveFollowMode",
238
- "stopFollowing"
239
- );
240
- }
241
- if (liveFollowMode === undefined) {
242
- throw new ActionLiveDataObjectUndefinedError(
243
- "liveFollowMode",
244
- "stopFollowing"
245
- );
246
- }
247
- if (!liveFollowMode.isInitialized) {
248
- throw new ActionLiveDataObjectInitializedError(
249
- "liveFollowMode",
250
- "stopFollowing"
251
- );
252
- }
253
- return await liveFollowMode.stopFollowing();
254
- }, [container, liveFollowMode]);
255
-
256
- /**
257
- * Setup change listeners and start `LiveFollowMode` if needed
258
- */
259
- React.useEffect(() => {
260
- if (liveFollowMode === undefined) return;
261
-
262
- const onPresenceChanged = () => {
263
- const updatedLocalUsers: LivePresenceUser<
264
- IFollowModePresenceUserData<TData>
265
- >[] = [];
266
- liveFollowMode?.getUsers().forEach((user) => {
267
- updatedLocalUsers.push(user);
268
- });
269
- setAllUsers(updatedLocalUsers);
270
- };
271
- liveFollowMode.on("presenceChanged", onPresenceChanged);
272
- const onStateChanged = () => {
273
- setState(liveFollowMode?.state);
274
- };
275
- liveFollowMode.on("stateChanged", onStateChanged);
276
-
277
- if (
278
- liveFollowMode.initializeState ===
279
- LiveDataObjectInitializeState.needed
280
- ) {
281
- liveFollowMode.initialize(
282
- isInitialDataCallback<TData>(initialData)
283
- ? initialData()
284
- : initialData,
285
- allowedRoles
286
- );
287
- } else {
288
- onPresenceChanged();
289
- onStateChanged();
290
- }
291
-
292
- return () => {
293
- liveFollowMode?.off("presenceChanged", onPresenceChanged);
294
- liveFollowMode?.off("stateChanged", onStateChanged);
295
- };
296
- }, [liveFollowMode]);
297
-
298
- return {
299
- state,
300
- localUser,
301
- otherUsers,
302
- allUsers,
303
- liveFollowMode,
304
- update,
305
- startPresenting,
306
- stopPresenting,
307
- beginSuspension,
308
- endSuspension,
309
- followUser,
310
- stopFollowing,
311
- };
312
- }
313
-
314
- function isInitialDataCallback<TData>(value: any): value is () => TData {
315
- return typeof value === "function";
316
- }
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
+ */
5
+
6
+ import {
7
+ LivePresenceUser,
8
+ UserMeetingRole,
9
+ LiveDataObjectInitializeState,
10
+ LiveFollowMode,
11
+ IFollowModePresenceUserData,
12
+ IFollowModeState,
13
+ } from "@microsoft/live-share";
14
+ import React from "react";
15
+ import { useDynamicDDS } from "../shared-hooks";
16
+ import { useFluidObjectsContext } from "../providers";
17
+ import {
18
+ ActionContainerNotJoinedError,
19
+ ActionLiveDataObjectInitializedError,
20
+ ActionLiveDataObjectUndefinedError,
21
+ } from "../internal";
22
+ import { IUseLiveFollowModeResults } from "../types";
23
+
24
+ /**
25
+ * React hook for using a Live Share `LiveFollowMode`.
26
+ *
27
+ * @remarks
28
+ * Use this hook if you want to add the ability to follow specific users or let a user present to everyone in the session.
29
+ * Each user has their own `stateValue`, which is the value other users will reference when that user is presenting or being followed.
30
+ * The `state` response includes the user's `value` that the local user is "following", whether it be their own or someone else's.
31
+ * This hook can only be used in a child component of `<LiveShareProvider>` or `<AzureProvider>`.
32
+ *
33
+ * @template TData Optional typing for the custom user presence data object. Default is `object` type.
34
+ *
35
+ * @param uniqueKey The unique key for `LiveFollowMode`. If one does not yet exist, a new one will be created.
36
+ * @param initialData The initial value for the local user's `stateValue`.
37
+ * @param allowedRoles Optional. The user roles that are allowed to present to use `startPresenting()` or `stopPresenting()`.
38
+ * @returns `IUseLiveFollowModeResults` results, which contains React stateful objects and callbacks.
39
+ */
40
+ export function useLiveFollowMode<TData = any>(
41
+ uniqueKey: string,
42
+ initialData: TData | (() => TData),
43
+ allowedRoles?: UserMeetingRole[]
44
+ ): IUseLiveFollowModeResults<TData> {
45
+ /**
46
+ * Stateful follow state.
47
+ */
48
+ const [state, setState] = React.useState<IFollowModeState<TData>>();
49
+ /**
50
+ * Stateful all user presence list and its non-user-facing setter method.
51
+ */
52
+ const [allUsers, setAllUsers] = React.useState<
53
+ LivePresenceUser<IFollowModePresenceUserData<TData>>[]
54
+ >([]);
55
+ /**
56
+ * User facing: dynamically load the DDS for the given unique key.
57
+ */
58
+ const { dds: liveFollowMode } = useDynamicDDS<LiveFollowMode<TData>>(
59
+ uniqueKey,
60
+ LiveFollowMode<TData>
61
+ );
62
+
63
+ /**
64
+ * User facing: list of non-local user's presence objects.
65
+ */
66
+ const otherUsers = allUsers.filter((user) => !user.isLocalUser);
67
+
68
+ /**
69
+ * User facing: local user's presence object.
70
+ */
71
+ const localUser = allUsers.find((user) => user.isLocalUser);
72
+
73
+ const { container } = useFluidObjectsContext();
74
+
75
+ /**
76
+ * User facing: callback to update the local user's custom data for their follow state.
77
+ */
78
+ const update = React.useCallback(
79
+ async (stateValue: TData) => {
80
+ if (!container) {
81
+ throw new ActionContainerNotJoinedError(
82
+ "liveFollowMode",
83
+ "update"
84
+ );
85
+ }
86
+ if (liveFollowMode === undefined) {
87
+ throw new ActionLiveDataObjectUndefinedError(
88
+ "liveFollowMode",
89
+ "update"
90
+ );
91
+ }
92
+ if (!liveFollowMode.isInitialized) {
93
+ throw new ActionLiveDataObjectInitializedError(
94
+ "liveFollowMode",
95
+ "update"
96
+ );
97
+ }
98
+ return await liveFollowMode.update(stateValue);
99
+ },
100
+ [container, liveFollowMode]
101
+ );
102
+
103
+ /**
104
+ * User facing: callback to start presenting.
105
+ */
106
+ const startPresenting = React.useCallback(async () => {
107
+ if (!container) {
108
+ throw new ActionContainerNotJoinedError(
109
+ "liveFollowMode",
110
+ "startPresenting"
111
+ );
112
+ }
113
+ if (liveFollowMode === undefined) {
114
+ throw new ActionLiveDataObjectUndefinedError(
115
+ "liveFollowMode",
116
+ "startPresenting"
117
+ );
118
+ }
119
+ if (!liveFollowMode.isInitialized) {
120
+ throw new ActionLiveDataObjectInitializedError(
121
+ "liveFollowMode",
122
+ "startPresenting"
123
+ );
124
+ }
125
+ return await liveFollowMode.startPresenting();
126
+ }, [container, liveFollowMode]);
127
+
128
+ /**
129
+ * User facing: callback to stop presenting.
130
+ */
131
+ const stopPresenting = React.useCallback(async () => {
132
+ if (!container) {
133
+ throw new ActionContainerNotJoinedError(
134
+ "liveFollowMode",
135
+ "stopPresenting"
136
+ );
137
+ }
138
+ if (liveFollowMode === undefined) {
139
+ throw new ActionLiveDataObjectUndefinedError(
140
+ "liveFollowMode",
141
+ "stopPresenting"
142
+ );
143
+ }
144
+ if (!liveFollowMode.isInitialized) {
145
+ throw new ActionLiveDataObjectInitializedError(
146
+ "liveFollowMode",
147
+ "stopPresenting"
148
+ );
149
+ }
150
+ return await liveFollowMode.stopPresenting();
151
+ }, [container, liveFollowMode]);
152
+
153
+ /**
154
+ * User facing: callback to suspend sync.
155
+ */
156
+ const beginSuspension = React.useCallback(async () => {
157
+ if (!container) {
158
+ throw new ActionContainerNotJoinedError(
159
+ "liveFollowMode",
160
+ "syncToPresenter"
161
+ );
162
+ }
163
+ if (liveFollowMode === undefined) {
164
+ throw new ActionLiveDataObjectUndefinedError(
165
+ "liveFollowMode",
166
+ "syncToPresenter"
167
+ );
168
+ }
169
+ if (!liveFollowMode.isInitialized) {
170
+ throw new ActionLiveDataObjectInitializedError(
171
+ "liveFollowMode",
172
+ "syncToPresenter"
173
+ );
174
+ }
175
+ return await liveFollowMode.beginSuspension();
176
+ }, [container, liveFollowMode]);
177
+
178
+ /**
179
+ * User facing: callback to end current suspension.
180
+ */
181
+ const endSuspension = React.useCallback(async () => {
182
+ if (!container) {
183
+ throw new ActionContainerNotJoinedError(
184
+ "liveFollowMode",
185
+ "syncToPresenter"
186
+ );
187
+ }
188
+ if (liveFollowMode === undefined) {
189
+ throw new ActionLiveDataObjectUndefinedError(
190
+ "liveFollowMode",
191
+ "syncToPresenter"
192
+ );
193
+ }
194
+ if (!liveFollowMode.isInitialized) {
195
+ throw new ActionLiveDataObjectInitializedError(
196
+ "liveFollowMode",
197
+ "syncToPresenter"
198
+ );
199
+ }
200
+ return await liveFollowMode.endSuspension();
201
+ }, [container, liveFollowMode]);
202
+
203
+ /**
204
+ * User facing: callback to follow a specific user.
205
+ */
206
+ const followUser = React.useCallback(
207
+ async (userId: string) => {
208
+ if (!container) {
209
+ throw new ActionContainerNotJoinedError(
210
+ "liveFollowMode",
211
+ "followUser"
212
+ );
213
+ }
214
+ if (liveFollowMode === undefined) {
215
+ throw new ActionLiveDataObjectUndefinedError(
216
+ "liveFollowMode",
217
+ "followUser"
218
+ );
219
+ }
220
+ if (!liveFollowMode.isInitialized) {
221
+ throw new ActionLiveDataObjectInitializedError(
222
+ "liveFollowMode",
223
+ "followUser"
224
+ );
225
+ }
226
+ return await liveFollowMode.followUser(userId);
227
+ },
228
+ [container, liveFollowMode]
229
+ );
230
+
231
+ /**
232
+ * User facing: callback to stop following a user.
233
+ */
234
+ const stopFollowing = React.useCallback(async () => {
235
+ if (!container) {
236
+ throw new ActionContainerNotJoinedError(
237
+ "liveFollowMode",
238
+ "stopFollowing"
239
+ );
240
+ }
241
+ if (liveFollowMode === undefined) {
242
+ throw new ActionLiveDataObjectUndefinedError(
243
+ "liveFollowMode",
244
+ "stopFollowing"
245
+ );
246
+ }
247
+ if (!liveFollowMode.isInitialized) {
248
+ throw new ActionLiveDataObjectInitializedError(
249
+ "liveFollowMode",
250
+ "stopFollowing"
251
+ );
252
+ }
253
+ return await liveFollowMode.stopFollowing();
254
+ }, [container, liveFollowMode]);
255
+
256
+ /**
257
+ * Setup change listeners and start `LiveFollowMode` if needed
258
+ */
259
+ React.useEffect(() => {
260
+ if (liveFollowMode === undefined) return;
261
+
262
+ const onPresenceChanged = () => {
263
+ const updatedLocalUsers: LivePresenceUser<
264
+ IFollowModePresenceUserData<TData>
265
+ >[] = [];
266
+ liveFollowMode?.getUsers().forEach((user) => {
267
+ updatedLocalUsers.push(user);
268
+ });
269
+ setAllUsers(updatedLocalUsers);
270
+ };
271
+ liveFollowMode.on("presenceChanged", onPresenceChanged);
272
+ const onStateChanged = () => {
273
+ setState(liveFollowMode?.state);
274
+ };
275
+ liveFollowMode.on("stateChanged", onStateChanged);
276
+
277
+ if (
278
+ liveFollowMode.initializeState ===
279
+ LiveDataObjectInitializeState.needed
280
+ ) {
281
+ liveFollowMode.initialize(
282
+ isInitialDataCallback<TData>(initialData)
283
+ ? initialData()
284
+ : initialData,
285
+ allowedRoles
286
+ );
287
+ } else {
288
+ onPresenceChanged();
289
+ onStateChanged();
290
+ }
291
+
292
+ return () => {
293
+ liveFollowMode?.off("presenceChanged", onPresenceChanged);
294
+ liveFollowMode?.off("stateChanged", onStateChanged);
295
+ };
296
+ }, [liveFollowMode]);
297
+
298
+ return {
299
+ state,
300
+ localUser,
301
+ otherUsers,
302
+ allUsers,
303
+ liveFollowMode,
304
+ update,
305
+ startPresenting,
306
+ stopPresenting,
307
+ beginSuspension,
308
+ endSuspension,
309
+ followUser,
310
+ stopFollowing,
311
+ };
312
+ }
313
+
314
+ function isInitialDataCallback<TData>(value: any): value is () => TData {
315
+ return typeof value === "function";
316
+ }