@microsoft/live-share-react 1.0.0-preview.12 → 1.0.0-preview.14
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 +3 -3
- package/bin/index.d.ts +6 -6
- package/bin/index.js +6 -6
- package/bin/interfaces/LiveInterfaceExtensions.d.ts +8 -8
- package/bin/interfaces/LiveInterfaceExtensions.js +5 -5
- package/bin/interfaces/index.d.ts +1 -1
- package/bin/interfaces/index.js +1 -1
- package/bin/internal-hooks/index.d.ts +1 -1
- package/bin/internal-hooks/index.js +1 -1
- package/bin/internal-hooks/useSharedStateRegistry.d.ts +30 -30
- package/bin/internal-hooks/useSharedStateRegistry.d.ts.map +1 -1
- package/bin/internal-hooks/useSharedStateRegistry.js +101 -99
- package/bin/internal-hooks/useSharedStateRegistry.js.map +1 -1
- package/bin/live-hooks/index.d.ts +6 -6
- package/bin/live-hooks/index.js +6 -6
- package/bin/live-hooks/useLiveCanvas.d.ts +27 -27
- package/bin/live-hooks/useLiveCanvas.js +158 -158
- package/bin/live-hooks/useLiveEvent.d.ts +21 -21
- package/bin/live-hooks/useLiveEvent.d.ts.map +1 -1
- package/bin/live-hooks/useLiveEvent.js +92 -85
- package/bin/live-hooks/useLiveEvent.js.map +1 -1
- package/bin/live-hooks/useLivePresence.d.ts +25 -25
- package/bin/live-hooks/useLivePresence.d.ts.map +1 -1
- package/bin/live-hooks/useLivePresence.js +101 -92
- package/bin/live-hooks/useLivePresence.js.map +1 -1
- package/bin/live-hooks/useLiveState.d.ts +19 -18
- package/bin/live-hooks/useLiveState.d.ts.map +1 -1
- package/bin/live-hooks/useLiveState.js +72 -60
- package/bin/live-hooks/useLiveState.js.map +1 -1
- package/bin/live-hooks/useLiveTimer.d.ts +7 -7
- package/bin/live-hooks/useLiveTimer.d.ts.map +1 -1
- package/bin/live-hooks/useLiveTimer.js +144 -131
- package/bin/live-hooks/useLiveTimer.js.map +1 -1
- package/bin/live-hooks/useMediaSynchronizer.d.ts +22 -22
- package/bin/live-hooks/useMediaSynchronizer.d.ts.map +1 -1
- package/bin/live-hooks/useMediaSynchronizer.js +184 -161
- package/bin/live-hooks/useMediaSynchronizer.js.map +1 -1
- package/bin/providers/AzureProvider.d.ts +33 -33
- package/bin/providers/AzureProvider.d.ts.map +1 -1
- package/bin/providers/AzureProvider.js +101 -101
- package/bin/providers/AzureProvider.js.map +1 -1
- package/bin/providers/LiveShareProvider.d.ts +62 -41
- package/bin/providers/LiveShareProvider.d.ts.map +1 -1
- package/bin/providers/LiveShareProvider.js +68 -65
- package/bin/providers/LiveShareProvider.js.map +1 -1
- package/bin/providers/index.d.ts +2 -2
- package/bin/providers/index.js +2 -2
- package/bin/shared-hooks/index.d.ts +3 -3
- package/bin/shared-hooks/index.js +3 -3
- package/bin/shared-hooks/useDynamicDDS.d.ts +18 -18
- package/bin/shared-hooks/useDynamicDDS.d.ts.map +1 -1
- package/bin/shared-hooks/useDynamicDDS.js +67 -67
- package/bin/shared-hooks/useDynamicDDS.js.map +1 -1
- package/bin/shared-hooks/useSharedMap.d.ts +21 -21
- package/bin/shared-hooks/useSharedMap.d.ts.map +1 -1
- package/bin/shared-hooks/useSharedMap.js +105 -105
- package/bin/shared-hooks/useSharedMap.js.map +1 -1
- package/bin/shared-hooks/useSharedState.d.ts +20 -20
- package/bin/shared-hooks/useSharedState.d.ts.map +1 -1
- package/bin/shared-hooks/useSharedState.js +66 -62
- package/bin/shared-hooks/useSharedState.js.map +1 -1
- package/bin/types/ActionTypes.d.ts +105 -29
- package/bin/types/ActionTypes.d.ts.map +1 -1
- package/bin/types/ActionTypes.js +5 -5
- package/bin/types/PropTypes.d.ts +7 -7
- package/bin/types/PropTypes.d.ts.map +1 -1
- package/bin/types/PropTypes.js +5 -5
- package/bin/types/ResultTypes.d.ts +174 -162
- package/bin/types/ResultTypes.d.ts.map +1 -1
- package/bin/types/ResultTypes.js +5 -5
- package/bin/types/index.d.ts +3 -3
- package/bin/types/index.js +3 -3
- package/bin/utils/index.d.ts +1 -1
- package/bin/utils/index.js +1 -1
- package/bin/utils/type-check.d.ts +14 -14
- package/bin/utils/type-check.js +53 -53
- package/package.json +13 -13
- package/src/internal-hooks/useSharedStateRegistry.ts +6 -5
- package/src/live-hooks/useLiveEvent.ts +14 -18
- package/src/live-hooks/useLivePresence.ts +13 -7
- package/src/live-hooks/useLiveState.ts +8 -6
- package/src/live-hooks/useLiveTimer.ts +21 -18
- package/src/live-hooks/useMediaSynchronizer.ts +37 -27
- package/src/providers/AzureProvider.tsx +2 -7
- package/src/providers/LiveShareProvider.tsx +45 -15
- package/src/shared-hooks/useDynamicDDS.ts +15 -8
- package/src/shared-hooks/useSharedMap.ts +17 -10
- package/src/shared-hooks/useSharedState.ts +5 -1
- package/src/types/ActionTypes.ts +89 -11
- package/src/types/ResultTypes.ts +22 -8
package/bin/utils/type-check.js
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
-
* Licensed under the Microsoft Live Share SDK License.
|
|
4
|
-
*/
|
|
5
|
-
export function isRefObject(value) {
|
|
6
|
-
return value.current === null || !!value.current;
|
|
7
|
-
}
|
|
8
|
-
export function isMediaElement(value) {
|
|
9
|
-
if (value) {
|
|
10
|
-
return (value.currentSrc !== undefined &&
|
|
11
|
-
value.currentTime !== undefined &&
|
|
12
|
-
value.duration !== undefined &&
|
|
13
|
-
value.ended !== undefined &&
|
|
14
|
-
value.muted !== undefined &&
|
|
15
|
-
value.paused !== undefined &&
|
|
16
|
-
value.playbackRate !== undefined &&
|
|
17
|
-
value.src !== undefined &&
|
|
18
|
-
value.volume !== undefined &&
|
|
19
|
-
value.load !== undefined &&
|
|
20
|
-
value.pause !== undefined &&
|
|
21
|
-
value.play !== undefined &&
|
|
22
|
-
value.addEventListener !== undefined &&
|
|
23
|
-
value.removeEventListener !== undefined);
|
|
24
|
-
}
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
export function isExtendedMediaMetadata(value) {
|
|
28
|
-
return value === null || !!(value === null || value === void 0 ? void 0 : value.trackIdentifier);
|
|
29
|
-
}
|
|
30
|
-
export function isMap(value) {
|
|
31
|
-
return value instanceof Map;
|
|
32
|
-
}
|
|
33
|
-
export function isEntries(value) {
|
|
34
|
-
try {
|
|
35
|
-
const tryValue = value;
|
|
36
|
-
if (typeof tryValue[0][0] === "string") {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
export function isJSON(value) {
|
|
46
|
-
try {
|
|
47
|
-
const tryValue = value;
|
|
48
|
-
return Object.keys(tryValue).length > 0;
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the Microsoft Live Share SDK License.
|
|
4
|
+
*/
|
|
5
|
+
export function isRefObject(value) {
|
|
6
|
+
return value.current === null || !!value.current;
|
|
7
|
+
}
|
|
8
|
+
export function isMediaElement(value) {
|
|
9
|
+
if (value) {
|
|
10
|
+
return (value.currentSrc !== undefined &&
|
|
11
|
+
value.currentTime !== undefined &&
|
|
12
|
+
value.duration !== undefined &&
|
|
13
|
+
value.ended !== undefined &&
|
|
14
|
+
value.muted !== undefined &&
|
|
15
|
+
value.paused !== undefined &&
|
|
16
|
+
value.playbackRate !== undefined &&
|
|
17
|
+
value.src !== undefined &&
|
|
18
|
+
value.volume !== undefined &&
|
|
19
|
+
value.load !== undefined &&
|
|
20
|
+
value.pause !== undefined &&
|
|
21
|
+
value.play !== undefined &&
|
|
22
|
+
value.addEventListener !== undefined &&
|
|
23
|
+
value.removeEventListener !== undefined);
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
export function isExtendedMediaMetadata(value) {
|
|
28
|
+
return value === null || !!(value === null || value === void 0 ? void 0 : value.trackIdentifier);
|
|
29
|
+
}
|
|
30
|
+
export function isMap(value) {
|
|
31
|
+
return value instanceof Map;
|
|
32
|
+
}
|
|
33
|
+
export function isEntries(value) {
|
|
34
|
+
try {
|
|
35
|
+
const tryValue = value;
|
|
36
|
+
if (typeof tryValue[0][0] === "string") {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function isJSON(value) {
|
|
46
|
+
try {
|
|
47
|
+
const tryValue = value;
|
|
48
|
+
return Object.keys(tryValue).length > 0;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
54
|
//# sourceMappingURL=type-check.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/live-share-react",
|
|
3
|
-
"version": "1.0.0-preview.
|
|
3
|
+
"version": "1.0.0-preview.14",
|
|
4
4
|
"description": "Build collaborative React apps using Microsoft's Fluid & Live Share frameworks with ease.",
|
|
5
5
|
"author": "Microsoft",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -12,29 +12,29 @@
|
|
|
12
12
|
"typecheck": "tsc"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@microsoft/live-share-turbo": "1.0.0-preview.
|
|
15
|
+
"@microsoft/live-share-turbo": "1.0.0-preview.14",
|
|
16
16
|
"url": "^0.11.0",
|
|
17
|
-
"uuid": "^
|
|
17
|
+
"uuid": "^9.0.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@babel/core": "^7.
|
|
20
|
+
"@babel/core": "^7.21.8",
|
|
21
21
|
"@fluidframework/azure-client": "~1.0.3",
|
|
22
22
|
"@fluidframework/test-client-utils": "^1.3.6",
|
|
23
|
-
"@microsoft/live-share": "1.0.0-preview.
|
|
24
|
-
"@microsoft/live-share-canvas": "1.0.0-preview.
|
|
25
|
-
"@microsoft/live-share-media": "1.0.0-preview.
|
|
23
|
+
"@microsoft/live-share": "1.0.0-preview.14",
|
|
24
|
+
"@microsoft/live-share-canvas": "1.0.0-preview.14",
|
|
25
|
+
"@microsoft/live-share-media": "1.0.0-preview.14",
|
|
26
26
|
"@types/react": "^18.0.0",
|
|
27
27
|
"@types/react-dom": "^18.0.0",
|
|
28
|
-
"@types/uuid": "^
|
|
29
|
-
"babel-loader": "^
|
|
28
|
+
"@types/uuid": "^9.0.1",
|
|
29
|
+
"babel-loader": "^9.1.2",
|
|
30
30
|
"fluid-framework": "^1.3.6",
|
|
31
|
-
"typescript": "^
|
|
31
|
+
"typescript": "^5.0.4"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@fluidframework/azure-client": "^1.0.0",
|
|
35
|
-
"@microsoft/live-share": "1.0.0-preview.
|
|
36
|
-
"@microsoft/live-share-canvas": "1.0.0-preview.
|
|
37
|
-
"@microsoft/live-share-media": "1.0.0-preview.
|
|
35
|
+
"@microsoft/live-share": "1.0.0-preview.14",
|
|
36
|
+
"@microsoft/live-share-canvas": "1.0.0-preview.14",
|
|
37
|
+
"@microsoft/live-share-media": "1.0.0-preview.14",
|
|
38
38
|
"fluid-framework": "^1.2.3",
|
|
39
39
|
"react": "^16.8.0 || ^17 || ^18",
|
|
40
40
|
"react-dom": "^16.8.0 || ^17 || ^18"
|
|
@@ -70,9 +70,8 @@ export const useSharedStateRegistry = (
|
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
// Set initial values, if known
|
|
73
|
-
const stateMap = results?.container.initialObjects
|
|
74
|
-
|
|
|
75
|
-
| undefined;
|
|
73
|
+
const stateMap = results?.container.initialObjects
|
|
74
|
+
.TURBO_STATE_MAP as SharedMap | undefined;
|
|
76
75
|
const initialValue = stateMap?.get(uniqueKey);
|
|
77
76
|
if (initialValue) {
|
|
78
77
|
setLocalStateAction(initialValue);
|
|
@@ -102,7 +101,8 @@ export const useSharedStateRegistry = (
|
|
|
102
101
|
(uniqueKey: string, value: any) => {
|
|
103
102
|
if (!results) return;
|
|
104
103
|
const { container } = results;
|
|
105
|
-
const stateMap = container.initialObjects
|
|
104
|
+
const stateMap = container.initialObjects
|
|
105
|
+
.TURBO_STATE_MAP as SharedMap;
|
|
106
106
|
stateMap.set(uniqueKey, value);
|
|
107
107
|
},
|
|
108
108
|
[results]
|
|
@@ -118,7 +118,8 @@ export const useSharedStateRegistry = (
|
|
|
118
118
|
let actionsMap =
|
|
119
119
|
registeredSharedSetStateActionMapRef.current.get(uniqueKey);
|
|
120
120
|
actionsMap?.clear();
|
|
121
|
-
const stateMap = container.initialObjects
|
|
121
|
+
const stateMap = container.initialObjects
|
|
122
|
+
.TURBO_STATE_MAP as SharedMap;
|
|
122
123
|
stateMap.delete(uniqueKey);
|
|
123
124
|
},
|
|
124
125
|
[results]
|
|
@@ -49,40 +49,36 @@ export function useLiveEvent<TEvent extends object = object>(
|
|
|
49
49
|
/**
|
|
50
50
|
* User facing: dynamically load the DDS for the given unique key.
|
|
51
51
|
*/
|
|
52
|
-
const { dds: liveEvent } = useDynamicDDS<LiveEvent
|
|
52
|
+
const { dds: liveEvent } = useDynamicDDS<LiveEvent<TEvent>>(
|
|
53
|
+
uniqueKey,
|
|
54
|
+
LiveEvent<TEvent>
|
|
55
|
+
);
|
|
53
56
|
|
|
54
57
|
/**
|
|
55
58
|
* User facing: callback to send event through `LiveEvent`
|
|
56
59
|
*/
|
|
57
60
|
const sendEvent: SendLiveEventAction<TEvent> = React.useCallback(
|
|
58
|
-
(event: TEvent) => {
|
|
59
|
-
if (liveEvent
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"Cannot call emitEvent when liveEvent is undefined"
|
|
63
|
-
)
|
|
61
|
+
async (event: TEvent) => {
|
|
62
|
+
if (liveEvent === undefined) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"Cannot call emitEvent when liveEvent is undefined"
|
|
64
65
|
);
|
|
65
|
-
return;
|
|
66
66
|
}
|
|
67
67
|
if (!liveEvent.isInitialized) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"Cannot call emitEvent while liveEvent is not started"
|
|
71
|
-
)
|
|
68
|
+
throw new Error(
|
|
69
|
+
"Cannot call emitEvent while liveEvent is not started"
|
|
72
70
|
);
|
|
73
|
-
return;
|
|
74
71
|
}
|
|
75
|
-
liveEvent
|
|
72
|
+
return await liveEvent.send(event);
|
|
76
73
|
},
|
|
77
|
-
[liveEvent
|
|
74
|
+
[liveEvent]
|
|
78
75
|
);
|
|
79
76
|
|
|
80
77
|
/**
|
|
81
78
|
* Setup change listeners and start `LiveEvent` if needed
|
|
82
79
|
*/
|
|
83
80
|
React.useEffect(() => {
|
|
84
|
-
if (liveEvent?.isInitialized === undefined)
|
|
85
|
-
return;
|
|
81
|
+
if (liveEvent?.isInitialized === undefined) return;
|
|
86
82
|
// Register event listener
|
|
87
83
|
const onEventReceived = (event: any, local: boolean) => {
|
|
88
84
|
// If developer passed the optional onReceivedEvent callback, we
|
|
@@ -106,7 +102,7 @@ export function useLiveEvent<TEvent extends object = object>(
|
|
|
106
102
|
// on unmount, remove event listeners
|
|
107
103
|
liveEvent?.off(LiveEventEvents.received, onEventReceived);
|
|
108
104
|
};
|
|
109
|
-
}, [liveEvent
|
|
105
|
+
}, [liveEvent]);
|
|
110
106
|
|
|
111
107
|
return {
|
|
112
108
|
latestEvent,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
LivePresenceUser,
|
|
8
8
|
PresenceState,
|
|
9
9
|
LivePresence,
|
|
10
|
+
UserMeetingRole,
|
|
10
11
|
} from "@microsoft/live-share";
|
|
11
12
|
import React from "react";
|
|
12
13
|
import { IUseLivePresenceResults, OnUpdateLivePresenceAction } from "../types";
|
|
@@ -21,19 +22,20 @@ import { useDynamicDDS } from "../shared-hooks";
|
|
|
21
22
|
* user data. This is useful for rendering a list of users, profile pictures, cursor positions, and more.
|
|
22
23
|
*
|
|
23
24
|
* @template TData Optional typing for the custom user presence data object. Default is `object` type.
|
|
24
|
-
|
|
25
|
+
* @param uniqueKey The unique key for `LivePresence`. If one does not yet exist, a new one
|
|
25
26
|
* @param userId Optional. The unique ID for a user. If none is provided, a random UUID will be generated.
|
|
26
27
|
* @param initialData Optional. Initial presence data object for the user.
|
|
27
28
|
* @param initialPresenceState Optional. Initial status of the user's presence. Default is online.
|
|
28
|
-
* @param
|
|
29
|
+
* @param allowedRoles Optional. the user roles that are allowed to mutate the synchronized state
|
|
29
30
|
* will be created, otherwise it will use the existing one. Default value is ":<dds-default>"
|
|
30
31
|
* @returns stateful `localUser`, `otherUsers` list, and `allUsers` list. Also returns a callback method
|
|
31
32
|
* to update the local user's presence and the `LivePresence` Fluid object.
|
|
32
33
|
*/
|
|
33
34
|
export function useLivePresence<TData extends object = object>(
|
|
35
|
+
uniqueKey: string,
|
|
34
36
|
initialData?: TData | undefined,
|
|
35
37
|
initialPresenceState: PresenceState = PresenceState.online,
|
|
36
|
-
|
|
38
|
+
allowedRoles?: UserMeetingRole[]
|
|
37
39
|
): IUseLivePresenceResults<TData> {
|
|
38
40
|
/**
|
|
39
41
|
* Stateful all user presence list and its non-user-facing setter method.
|
|
@@ -67,7 +69,7 @@ export function useLivePresence<TData extends object = object>(
|
|
|
67
69
|
* User facing: callback to update the local user's presence.
|
|
68
70
|
*/
|
|
69
71
|
const updatePresence: OnUpdateLivePresenceAction<TData> = React.useCallback(
|
|
70
|
-
(data?: TData | undefined, state?: PresenceState | undefined) => {
|
|
72
|
+
async (data?: TData | undefined, state?: PresenceState | undefined) => {
|
|
71
73
|
if (!livePresence) {
|
|
72
74
|
console.error(
|
|
73
75
|
new Error(
|
|
@@ -84,7 +86,7 @@ export function useLivePresence<TData extends object = object>(
|
|
|
84
86
|
);
|
|
85
87
|
return;
|
|
86
88
|
}
|
|
87
|
-
livePresence.update(data, state);
|
|
89
|
+
return await livePresence.update(data, state);
|
|
88
90
|
},
|
|
89
91
|
[livePresence]
|
|
90
92
|
);
|
|
@@ -97,7 +99,7 @@ export function useLivePresence<TData extends object = object>(
|
|
|
97
99
|
|
|
98
100
|
const onPresenceChanged = () => {
|
|
99
101
|
const updatedLocalUsers: LivePresenceUser<TData>[] = [];
|
|
100
|
-
livePresence?.forEach((user) => {
|
|
102
|
+
livePresence?.getUsers().forEach((user) => {
|
|
101
103
|
updatedLocalUsers.push(user);
|
|
102
104
|
});
|
|
103
105
|
setAllUsers(updatedLocalUsers);
|
|
@@ -105,7 +107,11 @@ export function useLivePresence<TData extends object = object>(
|
|
|
105
107
|
livePresence.on("presenceChanged", onPresenceChanged);
|
|
106
108
|
|
|
107
109
|
if (!livePresence.isInitialized) {
|
|
108
|
-
livePresence.initialize(
|
|
110
|
+
livePresence.initialize(
|
|
111
|
+
initialData,
|
|
112
|
+
initialPresenceState,
|
|
113
|
+
allowedRoles
|
|
114
|
+
);
|
|
109
115
|
} else {
|
|
110
116
|
onPresenceChanged();
|
|
111
117
|
}
|
|
@@ -18,15 +18,15 @@ import { useDynamicDDS } from "../shared-hooks";
|
|
|
18
18
|
* @param initialState Optional. the initial state value of type TState
|
|
19
19
|
* @param allowedRoles Optional. the user roles that are allowed to mutate the synchronized state
|
|
20
20
|
* @returns ordered values: first value is the synchronized state value and the second is a setter to change the state value.
|
|
21
|
+
* The setter returns a void promise, which will throw if the user does not have the required roles to set.
|
|
21
22
|
*/
|
|
22
|
-
export function useLiveState<
|
|
23
|
-
TState = any,
|
|
24
|
-
>(
|
|
23
|
+
export function useLiveState<TState = any>(
|
|
25
24
|
uniqueKey: string,
|
|
26
25
|
initialState: TState,
|
|
27
26
|
allowedRoles?: UserMeetingRole[]
|
|
28
27
|
): [TState, SetLiveStateAction<TState>] {
|
|
29
|
-
const [currentState, setCurrentState] =
|
|
28
|
+
const [currentState, setCurrentState] =
|
|
29
|
+
React.useState<TState>(initialState);
|
|
30
30
|
/**
|
|
31
31
|
* User facing: dynamically load the DDS for the given unique key.
|
|
32
32
|
*/
|
|
@@ -37,9 +37,11 @@ export function useLiveState<
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Change state callback that is user facing
|
|
40
|
+
* @param state TState to set
|
|
41
|
+
* @returns void promise, which will throw if the user does not have the required roles
|
|
40
42
|
*/
|
|
41
43
|
const setState = React.useCallback(
|
|
42
|
-
(state: TState) => {
|
|
44
|
+
async (state: TState) => {
|
|
43
45
|
if (!liveState) {
|
|
44
46
|
console.error(
|
|
45
47
|
new Error(
|
|
@@ -56,7 +58,7 @@ export function useLiveState<
|
|
|
56
58
|
);
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
59
|
-
liveState.set(state);
|
|
61
|
+
return await liveState.set(state);
|
|
60
62
|
},
|
|
61
63
|
[liveState]
|
|
62
64
|
);
|
|
@@ -31,7 +31,7 @@ export function useLiveTimer(
|
|
|
31
31
|
onStart?: OnTimerDidStartAction,
|
|
32
32
|
onPause?: OnTimerDidPauseAction,
|
|
33
33
|
onPlay?: OnTimerDidPlayAction,
|
|
34
|
-
onFinish?: OnTimerDidFinishAction
|
|
34
|
+
onFinish?: OnTimerDidFinishAction
|
|
35
35
|
): IUseLiveTimerResults {
|
|
36
36
|
/**
|
|
37
37
|
* User facing: Stateful timer config.
|
|
@@ -47,11 +47,13 @@ export function useLiveTimer(
|
|
|
47
47
|
const { dds: liveTimer } = useDynamicDDS<LiveTimer>(uniqueKey, LiveTimer);
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Callback to send event through `LiveTimer`
|
|
51
|
+
* @param duration the duration for the timer in milliseconds
|
|
52
|
+
* @returns void promise that will throw when user does not have required roles
|
|
51
53
|
*/
|
|
52
54
|
const start: OnStartTimerAction = React.useCallback(
|
|
53
|
-
(duration: number)
|
|
54
|
-
if (liveTimer
|
|
55
|
+
async (duration: number) => {
|
|
56
|
+
if (liveTimer === undefined) {
|
|
55
57
|
console.error(
|
|
56
58
|
new Error("Cannot call start when liveTimer is undefined")
|
|
57
59
|
);
|
|
@@ -65,16 +67,17 @@ export function useLiveTimer(
|
|
|
65
67
|
);
|
|
66
68
|
return;
|
|
67
69
|
}
|
|
68
|
-
liveTimer
|
|
70
|
+
return await liveTimer.start(duration);
|
|
69
71
|
},
|
|
70
|
-
[liveTimer
|
|
72
|
+
[liveTimer]
|
|
71
73
|
);
|
|
72
74
|
|
|
73
75
|
/**
|
|
74
|
-
*
|
|
76
|
+
* Callback to send event through `LiveTimer`
|
|
77
|
+
* @returns void promise that will throw when user does not have required roles
|
|
75
78
|
*/
|
|
76
|
-
const play: OnPlayTimerAction = React.useCallback(()
|
|
77
|
-
if (liveTimer
|
|
79
|
+
const play: OnPlayTimerAction = React.useCallback(async () => {
|
|
80
|
+
if (liveTimer === undefined) {
|
|
78
81
|
console.error(
|
|
79
82
|
new Error("Cannot call play when liveTimer is undefined")
|
|
80
83
|
);
|
|
@@ -86,14 +89,15 @@ export function useLiveTimer(
|
|
|
86
89
|
);
|
|
87
90
|
return;
|
|
88
91
|
}
|
|
89
|
-
liveTimer
|
|
90
|
-
}, [liveTimer
|
|
92
|
+
return await liveTimer.play();
|
|
93
|
+
}, [liveTimer]);
|
|
91
94
|
|
|
92
95
|
/**
|
|
93
|
-
*
|
|
96
|
+
* Callback to send event through `LiveTimer`
|
|
97
|
+
* @returns void promise that will throw when user does not have required roles
|
|
94
98
|
*/
|
|
95
|
-
const pause: OnPauseTimerAction = React.useCallback(()
|
|
96
|
-
if (liveTimer
|
|
99
|
+
const pause: OnPauseTimerAction = React.useCallback(async () => {
|
|
100
|
+
if (liveTimer === undefined) {
|
|
97
101
|
console.error(
|
|
98
102
|
new Error("Cannot call pause when liveTimer is undefined")
|
|
99
103
|
);
|
|
@@ -105,15 +109,14 @@ export function useLiveTimer(
|
|
|
105
109
|
);
|
|
106
110
|
return;
|
|
107
111
|
}
|
|
108
|
-
liveTimer
|
|
109
|
-
}, [liveTimer
|
|
112
|
+
return await liveTimer.pause();
|
|
113
|
+
}, [liveTimer]);
|
|
110
114
|
|
|
111
115
|
/**
|
|
112
116
|
* Setup change listeners and start `LiveTimer` if needed
|
|
113
117
|
*/
|
|
114
118
|
React.useEffect(() => {
|
|
115
|
-
if (liveTimer === undefined)
|
|
116
|
-
return;
|
|
119
|
+
if (liveTimer === undefined) return;
|
|
117
120
|
// Register event listeners
|
|
118
121
|
const onTimerConfigChange = (config: ITimerConfig) => {
|
|
119
122
|
setTimerConfig(config);
|
|
@@ -52,28 +52,34 @@ export function useMediaSynchronizer(
|
|
|
52
52
|
/**
|
|
53
53
|
* User facing: dynamically load the LiveMediaSession DDS for the given unique key.
|
|
54
54
|
*/
|
|
55
|
-
const { dds: mediaSession } = useDynamicDDS<LiveMediaSession>(
|
|
55
|
+
const { dds: mediaSession } = useDynamicDDS<LiveMediaSession>(
|
|
56
|
+
uniqueKey,
|
|
57
|
+
LiveMediaSession
|
|
58
|
+
);
|
|
56
59
|
|
|
57
60
|
/**
|
|
58
|
-
*
|
|
61
|
+
* Play callback
|
|
59
62
|
*/
|
|
60
|
-
const play = React.useCallback(()
|
|
61
|
-
mediaSynchronizer
|
|
63
|
+
const play = React.useCallback(async () => {
|
|
64
|
+
if (!mediaSynchronizer) return;
|
|
65
|
+
return await mediaSynchronizer.play();
|
|
62
66
|
}, [mediaSynchronizer]);
|
|
63
67
|
|
|
64
68
|
/**
|
|
65
|
-
*
|
|
69
|
+
* Pause callback
|
|
66
70
|
*/
|
|
67
|
-
const pause = React.useCallback(()
|
|
68
|
-
mediaSynchronizer
|
|
71
|
+
const pause = React.useCallback(async () => {
|
|
72
|
+
if (!mediaSynchronizer) return;
|
|
73
|
+
return await mediaSynchronizer.pause();
|
|
69
74
|
}, [mediaSynchronizer]);
|
|
70
75
|
|
|
71
76
|
/**
|
|
72
77
|
* User facing: seek callback
|
|
73
78
|
*/
|
|
74
79
|
const seekTo = React.useCallback(
|
|
75
|
-
(time: number)
|
|
76
|
-
mediaSynchronizer
|
|
80
|
+
async (time: number) => {
|
|
81
|
+
if (!mediaSynchronizer) return;
|
|
82
|
+
return await mediaSynchronizer.seekTo(time);
|
|
77
83
|
},
|
|
78
84
|
[mediaSynchronizer]
|
|
79
85
|
);
|
|
@@ -82,12 +88,12 @@ export function useMediaSynchronizer(
|
|
|
82
88
|
* User facing: set track callback
|
|
83
89
|
*/
|
|
84
90
|
const setTrack = React.useCallback(
|
|
85
|
-
(track: Partial<ExtendedMediaMetadata> | string | null)
|
|
86
|
-
|
|
91
|
+
async (track: Partial<ExtendedMediaMetadata> | string | null) => {
|
|
92
|
+
if (!mediaSynchronizer) return;
|
|
87
93
|
if (isExtendedMediaMetadata(track)) {
|
|
88
|
-
mediaSynchronizer
|
|
94
|
+
return await mediaSynchronizer.setTrack(track);
|
|
89
95
|
} else if (typeof track === "string") {
|
|
90
|
-
mediaSynchronizer
|
|
96
|
+
return await mediaSynchronizer.setTrack({
|
|
91
97
|
trackIdentifier: track,
|
|
92
98
|
} as ExtendedMediaMetadata);
|
|
93
99
|
}
|
|
@@ -119,8 +125,8 @@ export function useMediaSynchronizer(
|
|
|
119
125
|
* Setup change listeners and start `LiveMediaSession` if needed
|
|
120
126
|
*/
|
|
121
127
|
React.useEffect(() => {
|
|
122
|
-
if (mediaSession === undefined || !mediaPlayerElementRef)
|
|
123
|
-
|
|
128
|
+
if (mediaSession === undefined || !mediaPlayerElementRef) return;
|
|
129
|
+
let mounted = true;
|
|
124
130
|
// Query the HTML5 media element from the document and set reference
|
|
125
131
|
let mediaPlayer: IMediaPlayer | undefined;
|
|
126
132
|
if (isRefObject<IMediaPlayer>(mediaPlayerElementRef)) {
|
|
@@ -152,25 +158,29 @@ export function useMediaSynchronizer(
|
|
|
152
158
|
// Start synchronizing the media session
|
|
153
159
|
mediaSession.initialize(allowedRoles ?? []);
|
|
154
160
|
} else if (initialTrack) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
|
|
161
|
+
mediaSession.onLocalUserAllowed(async () => {
|
|
162
|
+
if (!mounted) return;
|
|
163
|
+
try {
|
|
164
|
+
if (isExtendedMediaMetadata(initialTrack)) {
|
|
165
|
+
await synchronizer.setTrack(initialTrack);
|
|
166
|
+
} else if (typeof initialTrack === "string") {
|
|
167
|
+
await synchronizer.setTrack({
|
|
168
|
+
trackIdentifier: initialTrack,
|
|
169
|
+
} as ExtendedMediaMetadata);
|
|
170
|
+
}
|
|
171
|
+
} catch (err) {
|
|
172
|
+
console.error(err);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
167
175
|
}
|
|
168
176
|
setMediaSynchronizer(synchronizer);
|
|
169
177
|
|
|
170
178
|
return () => {
|
|
179
|
+
mounted = false;
|
|
171
180
|
synchronizer.removeAllListeners();
|
|
172
181
|
mediaSession.removeAllListeners();
|
|
173
182
|
synchronizer?.end();
|
|
183
|
+
mediaSession?.dispose();
|
|
174
184
|
};
|
|
175
185
|
}, [mediaSession]);
|
|
176
186
|
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
* Licensed under the Microsoft Live Share SDK License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
IFluidContainer,
|
|
8
|
-
LoadableObjectClassRecord,
|
|
9
|
-
} from "fluid-framework";
|
|
6
|
+
import { IFluidContainer, LoadableObjectClassRecord } from "fluid-framework";
|
|
10
7
|
import React from "react";
|
|
11
8
|
import {
|
|
12
9
|
AzureClientProps,
|
|
@@ -58,9 +55,7 @@ interface IAzureProviderProps {
|
|
|
58
55
|
/**
|
|
59
56
|
* React Context provider component for using Fluid data objects & joining/creating a Fluid document `AzureClient`.
|
|
60
57
|
*/
|
|
61
|
-
export const AzureProvider: React.FC<IAzureProviderProps> = (
|
|
62
|
-
props
|
|
63
|
-
) => {
|
|
58
|
+
export const AzureProvider: React.FC<IAzureProviderProps> = (props) => {
|
|
64
59
|
const startedRef = React.useRef<boolean>(false);
|
|
65
60
|
const clientRef = React.useRef<AzureTurboClient>(
|
|
66
61
|
new AzureTurboClient(props.clientOptions)
|