@stream-io/video-react-sdk 0.0.92 → 0.1.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 (48) hide show
  1. package/CHANGELOG.md +26 -15
  2. package/dist/src/components/CallControls/ReactionsButton.js +3 -2
  3. package/dist/src/components/CallControls/ReactionsButton.js.map +1 -1
  4. package/dist/src/components/CallControls/RecordCallButton.js +7 -40
  5. package/dist/src/components/CallControls/RecordCallButton.js.map +1 -1
  6. package/dist/src/components/CallControls/ScreenShareButton.js +6 -46
  7. package/dist/src/components/CallControls/ScreenShareButton.js.map +1 -1
  8. package/dist/src/components/CallControls/ToggleAudioButton.js +2 -2
  9. package/dist/src/components/CallControls/ToggleAudioButton.js.map +1 -1
  10. package/dist/src/components/CallControls/ToggleVideoButton.js +2 -2
  11. package/dist/src/components/CallControls/ToggleVideoButton.js.map +1 -1
  12. package/dist/src/components/Permissions/PermissionRequests.d.ts +3 -1
  13. package/dist/src/components/Permissions/PermissionRequests.js +25 -13
  14. package/dist/src/components/Permissions/PermissionRequests.js.map +1 -1
  15. package/dist/src/hooks/index.d.ts +3 -0
  16. package/dist/src/hooks/index.js +3 -0
  17. package/dist/src/hooks/index.js.map +1 -1
  18. package/dist/src/hooks/useRequestPermission.d.ts +7 -0
  19. package/dist/src/hooks/useRequestPermission.js +52 -0
  20. package/dist/src/hooks/useRequestPermission.js.map +1 -0
  21. package/dist/src/hooks/useToggleAudioMuteState.d.ts +1 -1
  22. package/dist/src/hooks/useToggleAudioMuteState.js +14 -41
  23. package/dist/src/hooks/useToggleAudioMuteState.js.map +1 -1
  24. package/dist/src/hooks/useToggleCallRecording.d.ts +5 -0
  25. package/dist/src/hooks/useToggleCallRecording.js +43 -0
  26. package/dist/src/hooks/useToggleCallRecording.js.map +1 -0
  27. package/dist/src/hooks/useToggleScreenShare.d.ts +5 -0
  28. package/dist/src/hooks/useToggleScreenShare.js +37 -0
  29. package/dist/src/hooks/useToggleScreenShare.js.map +1 -0
  30. package/dist/src/hooks/useToggleVideoMuteState.d.ts +1 -1
  31. package/dist/src/hooks/useToggleVideoMuteState.js +14 -41
  32. package/dist/src/hooks/useToggleVideoMuteState.js.map +1 -1
  33. package/dist/version.d.ts +1 -1
  34. package/dist/version.js +1 -1
  35. package/dist/version.js.map +1 -1
  36. package/package.json +3 -3
  37. package/src/components/CallControls/ReactionsButton.tsx +5 -3
  38. package/src/components/CallControls/RecordCallButton.tsx +9 -33
  39. package/src/components/CallControls/ScreenShareButton.tsx +13 -51
  40. package/src/components/CallControls/ToggleAudioButton.tsx +5 -5
  41. package/src/components/CallControls/ToggleVideoButton.tsx +7 -5
  42. package/src/components/Permissions/PermissionRequests.tsx +49 -22
  43. package/src/hooks/index.ts +3 -0
  44. package/src/hooks/useRequestPermission.ts +48 -0
  45. package/src/hooks/useToggleAudioMuteState.ts +19 -48
  46. package/src/hooks/useToggleCallRecording.ts +39 -0
  47. package/src/hooks/useToggleScreenShare.ts +42 -0
  48. package/src/hooks/useToggleVideoMuteState.ts +19 -48
@@ -0,0 +1,5 @@
1
+ export declare const useToggleCallRecording: () => {
2
+ toggleCallRecording: () => Promise<void>;
3
+ isAwaitingResponse: boolean;
4
+ isCallRecordingInProgress: boolean;
5
+ };
@@ -0,0 +1,43 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { useCallback, useEffect, useState } from 'react';
11
+ import { useCall, useIsCallRecordingInProgress, } from '@stream-io/video-react-bindings';
12
+ export const useToggleCallRecording = () => {
13
+ const call = useCall();
14
+ const isCallRecordingInProgress = useIsCallRecordingInProgress();
15
+ const [isAwaitingResponse, setIsAwaitingResponse] = useState(false);
16
+ // TODO: add permissions
17
+ useEffect(() => {
18
+ // we wait until call.recording_started/stopped event to flips the
19
+ // `isCallRecordingInProgress` state variable.
20
+ // Once the flip happens, we remove the loading indicator
21
+ setIsAwaitingResponse((isAwaiting) => {
22
+ if (isAwaiting)
23
+ return false;
24
+ return isAwaiting;
25
+ });
26
+ }, [isCallRecordingInProgress]);
27
+ const toggleCallRecording = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
28
+ try {
29
+ setIsAwaitingResponse(true);
30
+ if (isCallRecordingInProgress) {
31
+ yield (call === null || call === void 0 ? void 0 : call.stopRecording());
32
+ }
33
+ else {
34
+ yield (call === null || call === void 0 ? void 0 : call.startRecording());
35
+ }
36
+ }
37
+ catch (e) {
38
+ console.error(`Failed start recording`, e);
39
+ }
40
+ }), [call, isCallRecordingInProgress]);
41
+ return { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress };
42
+ };
43
+ //# sourceMappingURL=useToggleCallRecording.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useToggleCallRecording.js","sourceRoot":"","sources":["../../../src/hooks/useToggleCallRecording.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EACL,OAAO,EACP,4BAA4B,GAC7B,MAAM,iCAAiC,CAAC;AAEzC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,EAAE;IACzC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,yBAAyB,GAAG,4BAA4B,EAAE,CAAC;IACjE,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpE,wBAAwB;IAExB,SAAS,CAAC,GAAG,EAAE;QACb,kEAAkE;QAClE,8CAA8C;QAC9C,yDAAyD;QACzD,qBAAqB,CAAC,CAAC,UAAU,EAAE,EAAE;YACnC,IAAI,UAAU;gBAAE,OAAO,KAAK,CAAC;YAC7B,OAAO,UAAU,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,CAAC;IAEhC,MAAM,mBAAmB,GAAG,WAAW,CAAC,GAAS,EAAE;QACjD,IAAI;YACF,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAC5B,IAAI,yBAAyB,EAAE;gBAC7B,MAAM,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,aAAa,EAAE,CAAA,CAAC;aAC7B;iBAAM;gBACL,MAAM,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,cAAc,EAAE,CAAA,CAAC;aAC9B;SACF;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC;SAC5C;IACH,CAAC,CAAA,EAAE,CAAC,IAAI,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAEtC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,CAAC;AAChF,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare const useToggleScreenShare: () => {
2
+ toggleScreenShare: () => Promise<void>;
3
+ isAwaitingPermission: boolean;
4
+ isScreenSharing: boolean;
5
+ };
@@ -0,0 +1,37 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { useCallback, useRef } from 'react';
11
+ import { useCall, useLocalParticipant } from '@stream-io/video-react-bindings';
12
+ import { OwnCapability, SfuModels, getScreenShareStream, } from '@stream-io/video-client';
13
+ import { useRequestPermission } from './useRequestPermission';
14
+ export const useToggleScreenShare = () => {
15
+ const localParticipant = useLocalParticipant();
16
+ const call = useCall();
17
+ const isScreenSharingReference = useRef(false);
18
+ const { isAwaitingPermission, requestPermission } = useRequestPermission(OwnCapability.SCREENSHARE);
19
+ const isScreenSharing = !!(localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.publishedTracks.includes(SfuModels.TrackType.SCREEN_SHARE));
20
+ isScreenSharingReference.current = isScreenSharing;
21
+ const toggleScreenShare = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
22
+ if (!isScreenSharingReference.current) {
23
+ const canPublish = yield requestPermission();
24
+ if (!canPublish)
25
+ return;
26
+ const stream = yield getScreenShareStream().catch((e) => {
27
+ console.log(`Can't share screen: ${e}`);
28
+ });
29
+ if (stream) {
30
+ return call === null || call === void 0 ? void 0 : call.publishScreenShareStream(stream);
31
+ }
32
+ }
33
+ call === null || call === void 0 ? void 0 : call.stopPublish(SfuModels.TrackType.SCREEN_SHARE);
34
+ }), [call, requestPermission]);
35
+ return { toggleScreenShare, isAwaitingPermission, isScreenSharing };
36
+ };
37
+ //# sourceMappingURL=useToggleScreenShare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useToggleScreenShare.js","sourceRoot":"","sources":["../../../src/hooks/useToggleScreenShare.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EACL,aAAa,EACb,SAAS,EACT,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,EAAE;IACvC,MAAM,gBAAgB,GAAG,mBAAmB,EAAE,CAAC;IAC/C,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,wBAAwB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,GAAG,oBAAoB,CACtE,aAAa,CAAC,WAAW,CAC1B,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,CAAC,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,eAAe,CAAC,QAAQ,CAClE,SAAS,CAAC,SAAS,CAAC,YAAY,CACjC,CAAA,CAAC;IAEF,wBAAwB,CAAC,OAAO,GAAG,eAAe,CAAC;IAEnD,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAS,EAAE;QAC/C,IAAI,CAAC,wBAAwB,CAAC,OAAO,EAAE;YACrC,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAC;YAC7C,IAAI,CAAC,UAAU;gBAAE,OAAO;YAExB,MAAM,MAAM,GAAG,MAAM,oBAAoB,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBACtD,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC;YAC1C,CAAC,CAAC,CAAC;YAEH,IAAI,MAAM,EAAE;gBACV,OAAO,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,wBAAwB,CAAC,MAAM,CAAC,CAAC;aAC/C;SACF;QAED,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACtD,CAAC,CAAA,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAE9B,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC;AACtE,CAAC,CAAC"}
@@ -1,4 +1,4 @@
1
1
  export declare const useToggleVideoMuteState: () => {
2
2
  toggleVideoMuteState: () => Promise<void>;
3
- isAwaitingApproval: boolean;
3
+ isAwaitingPermission: boolean;
4
4
  };
@@ -7,54 +7,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { useCallback, useEffect, useState } from 'react';
11
- import { useCall, useHasPermissions, useLocalParticipant, } from '@stream-io/video-react-bindings';
10
+ import { useCallback, useRef } from 'react';
11
+ import { useLocalParticipant } from '@stream-io/video-react-bindings';
12
12
  import { OwnCapability, SfuModels } from '@stream-io/video-client';
13
13
  import { useMediaDevices } from '../core';
14
+ import { useRequestPermission } from './useRequestPermission';
14
15
  export const useToggleVideoMuteState = () => {
15
16
  const { publishVideoStream, stopPublishingVideo } = useMediaDevices();
16
17
  const localParticipant = useLocalParticipant();
17
- const call = useCall();
18
- const hasPermission = useHasPermissions(OwnCapability.SEND_VIDEO);
19
- const [isAwaitingApproval, setIsAwaitingApproval] = useState(false);
20
- const isVideoMute = !(localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.publishedTracks.includes(SfuModels.TrackType.VIDEO));
21
- useEffect(() => {
22
- if (hasPermission) {
23
- setIsAwaitingApproval(false);
24
- }
25
- }, [hasPermission]);
18
+ const { isAwaitingPermission, requestPermission } = useRequestPermission(OwnCapability.SEND_VIDEO);
19
+ // to keep the toggle function as stable as possible
20
+ const isVideoMutedReference = useRef(false);
21
+ isVideoMutedReference.current = !(localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.publishedTracks.includes(SfuModels.TrackType.VIDEO));
26
22
  const toggleVideoMuteState = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
27
- if (!hasPermission &&
28
- call &&
29
- call.permissionsContext.canRequest(OwnCapability.SEND_VIDEO)) {
30
- setIsAwaitingApproval(true);
31
- yield call
32
- .requestPermissions({
33
- permissions: [OwnCapability.SEND_VIDEO],
34
- })
35
- .catch((reason) => {
36
- console.log('RequestPermissions failed', reason);
37
- });
38
- return;
39
- }
40
- if (isVideoMute) {
41
- if (hasPermission) {
42
- yield publishVideoStream();
43
- }
44
- else {
45
- console.log('Cannot publish video. Insufficient permissions.');
46
- }
23
+ if (isVideoMutedReference.current) {
24
+ const canPublish = yield requestPermission();
25
+ if (canPublish)
26
+ return publishVideoStream();
47
27
  }
48
- else {
28
+ if (!isVideoMutedReference.current)
49
29
  stopPublishingVideo();
50
- }
51
- }), [
52
- call,
53
- hasPermission,
54
- isVideoMute,
55
- publishVideoStream,
56
- stopPublishingVideo,
57
- ]);
58
- return { toggleVideoMuteState, isAwaitingApproval };
30
+ }), [publishVideoStream, requestPermission, stopPublishingVideo]);
31
+ return { toggleVideoMuteState, isAwaitingPermission };
59
32
  };
60
33
  //# sourceMappingURL=useToggleVideoMuteState.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useToggleVideoMuteState.js","sourceRoot":"","sources":["../../../src/hooks/useToggleVideoMuteState.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EACL,OAAO,EACP,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,EAAE;IAC1C,MAAM,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,GAAG,eAAe,EAAE,CAAC;IACtE,MAAM,gBAAgB,GAAG,mBAAmB,EAAE,CAAC;IAC/C,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,aAAa,GAAG,iBAAiB,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAClE,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpE,MAAM,WAAW,GAAG,CAAC,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,eAAe,CAAC,QAAQ,CAC7D,SAAS,CAAC,SAAS,CAAC,KAAK,CAC1B,CAAA,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,aAAa,EAAE;YACjB,qBAAqB,CAAC,KAAK,CAAC,CAAC;SAC9B;IACH,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;IAEpB,MAAM,oBAAoB,GAAG,WAAW,CAAC,GAAS,EAAE;QAClD,IACE,CAAC,aAAa;YACd,IAAI;YACJ,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,EAC5D;YACA,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAC5B,MAAM,IAAI;iBACP,kBAAkB,CAAC;gBAClB,WAAW,EAAE,CAAC,aAAa,CAAC,UAAU,CAAC;aACxC,CAAC;iBACD,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE;gBAChB,OAAO,CAAC,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC,CAAC,CAAC;YACL,OAAO;SACR;QACD,IAAI,WAAW,EAAE;YACf,IAAI,aAAa,EAAE;gBACjB,MAAM,kBAAkB,EAAE,CAAC;aAC5B;iBAAM;gBACL,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;aAChE;SACF;aAAM;YACL,mBAAmB,EAAE,CAAC;SACvB;IACH,CAAC,CAAA,EAAE;QACD,IAAI;QACJ,aAAa;QACb,WAAW;QACX,kBAAkB;QAClB,mBAAmB;KACpB,CAAC,CAAC;IAEH,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,CAAC;AACtD,CAAC,CAAC"}
1
+ {"version":3,"file":"useToggleVideoMuteState.js","sourceRoot":"","sources":["../../../src/hooks/useToggleVideoMuteState.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,EAAE;IAC1C,MAAM,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,GAAG,eAAe,EAAE,CAAC;IACtE,MAAM,gBAAgB,GAAG,mBAAmB,EAAE,CAAC;IAE/C,MAAM,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,GAAG,oBAAoB,CACtE,aAAa,CAAC,UAAU,CACzB,CAAC;IAEF,oDAAoD;IACpD,MAAM,qBAAqB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE5C,qBAAqB,CAAC,OAAO,GAAG,CAAC,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,eAAe,CAAC,QAAQ,CACzE,SAAS,CAAC,SAAS,CAAC,KAAK,CAC1B,CAAA,CAAC;IAEF,MAAM,oBAAoB,GAAG,WAAW,CAAC,GAAS,EAAE;QAClD,IAAI,qBAAqB,CAAC,OAAO,EAAE;YACjC,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAC;YAC7C,IAAI,UAAU;gBAAE,OAAO,kBAAkB,EAAE,CAAC;SAC7C;QAED,IAAI,CAAC,qBAAqB,CAAC,OAAO;YAAE,mBAAmB,EAAE,CAAC;IAC5D,CAAC,CAAA,EAAE,CAAC,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAEjE,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,CAAC;AACxD,CAAC,CAAC"}
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "0.0.92";
1
+ export declare const version = "0.1.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const version = '0.0.92';
1
+ export const version = '0.1.0';
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-react-sdk",
3
- "version": "0.0.92",
3
+ "version": "0.1.0",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -32,9 +32,9 @@
32
32
  "@floating-ui/react": "^0.22.0",
33
33
  "@nivo/core": "^0.80.0",
34
34
  "@nivo/line": "^0.80.0",
35
- "@stream-io/i18n": "^0.1.0",
35
+ "@stream-io/i18n": "^0.1.1",
36
36
  "@stream-io/video-client": "^0.0.51",
37
- "@stream-io/video-react-bindings": "^0.0.54",
37
+ "@stream-io/video-react-bindings": "^0.1.0",
38
38
  "clsx": "^1.2.1",
39
39
  "prop-types": "^15.8.1",
40
40
  "rxjs": "~7.8.1"
@@ -1,5 +1,5 @@
1
1
  import { OwnCapability, StreamReaction } from '@stream-io/video-client';
2
- import { Restricted, useCall } from '@stream-io/video-react-bindings';
2
+ import { Restricted, useCall, useI18n } from '@stream-io/video-react-bindings';
3
3
 
4
4
  import { CompositeButton, IconButton } from '../Button';
5
5
  import { defaultEmojiReactionMap } from '../Reaction';
@@ -27,17 +27,19 @@ export interface ReactionsButtonProps {
27
27
  export const ReactionsButton = ({
28
28
  reactions = defaultReactions,
29
29
  }: ReactionsButtonProps) => {
30
+ const { t } = useI18n();
31
+
30
32
  return (
31
33
  <Restricted requiredGrants={[OwnCapability.CREATE_REACTION]}>
32
34
  <CompositeButton
33
35
  active={false}
34
- caption="Reactions"
36
+ caption={t('Reactions')}
35
37
  menuPlacement="top-start"
36
38
  Menu={<DefaultReactionsMenu reactions={reactions} />}
37
39
  >
38
40
  <IconButton
39
41
  icon="reactions"
40
- title="Reactions"
42
+ title={t('Reactions')}
41
43
  onClick={() => {
42
44
  console.log('Reactions');
43
45
  }}
@@ -1,12 +1,8 @@
1
- import { useCallback, useEffect, useState } from 'react';
2
1
  import { OwnCapability } from '@stream-io/video-client';
3
- import {
4
- Restricted,
5
- useCall,
6
- useIsCallRecordingInProgress,
7
- } from '@stream-io/video-react-bindings';
2
+ import { Restricted, useCall, useI18n } from '@stream-io/video-react-bindings';
8
3
  import { CompositeButton, IconButton } from '../Button/';
9
4
  import { LoadingIndicator } from '../LoadingIndicator';
5
+ import { useToggleCallRecording } from '../../hooks/useToggleCallRecording';
10
6
 
11
7
  export type RecordCallButtonProps = {
12
8
  caption?: string;
@@ -16,30 +12,10 @@ export const RecordCallButton = ({
16
12
  caption = 'Record',
17
13
  }: RecordCallButtonProps) => {
18
14
  const call = useCall();
19
- const isCallRecordingInProgress = useIsCallRecordingInProgress();
20
- const [isAwaitingResponse, setIsAwaitingResponse] = useState(false);
21
- useEffect(() => {
22
- // we wait until call.recording_started/stopped event to flips the
23
- // `isCallRecordingInProgress` state variable.
24
- // Once the flip happens, we remove the loading indicator
25
- setIsAwaitingResponse((isAwaiting) => {
26
- if (isAwaiting) return false;
27
- return isAwaiting;
28
- });
29
- }, [isCallRecordingInProgress]);
30
15
 
31
- const toggleRecording = useCallback(async () => {
32
- try {
33
- setIsAwaitingResponse(true);
34
- if (isCallRecordingInProgress) {
35
- await call?.stopRecording();
36
- } else {
37
- await call?.startRecording();
38
- }
39
- } catch (e) {
40
- console.error(`Failed start recording`, e);
41
- }
42
- }, [call, isCallRecordingInProgress]);
16
+ const { t } = useI18n();
17
+ const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } =
18
+ useToggleCallRecording();
43
19
 
44
20
  return (
45
21
  <Restricted
@@ -53,8 +29,8 @@ export const RecordCallButton = ({
53
29
  <LoadingIndicator
54
30
  tooltip={
55
31
  isCallRecordingInProgress
56
- ? 'Waiting for recording to stop... '
57
- : 'Waiting for recording to start...'
32
+ ? t('Waiting for recording to stop...')
33
+ : t('Waiting for recording to start...')
58
34
  }
59
35
  />
60
36
  ) : (
@@ -63,8 +39,8 @@ export const RecordCallButton = ({
63
39
  enabled={!!call}
64
40
  disabled={!call}
65
41
  icon={isCallRecordingInProgress ? 'recording-on' : 'recording-off'}
66
- title="Record call"
67
- onClick={toggleRecording}
42
+ title={t('Record call')}
43
+ onClick={toggleCallRecording}
68
44
  />
69
45
  )}
70
46
  </CompositeButton>
@@ -1,18 +1,13 @@
1
- import { useEffect, useState } from 'react';
2
- import {
3
- getScreenShareStream,
4
- OwnCapability,
5
- SfuModels,
6
- } from '@stream-io/video-client';
1
+ import { OwnCapability } from '@stream-io/video-client';
7
2
  import {
8
3
  Restricted,
9
4
  useCall,
10
5
  useHasOngoingScreenShare,
11
- useHasPermissions,
12
- useLocalParticipant,
6
+ useI18n,
13
7
  } from '@stream-io/video-react-bindings';
14
8
  import { CompositeButton, IconButton } from '../Button/';
15
9
  import { PermissionNotification } from '../Notification';
10
+ import { useToggleScreenShare } from '../../hooks';
16
11
 
17
12
  export type ScreenShareButtonProps = {
18
13
  caption?: string;
@@ -22,60 +17,27 @@ export const ScreenShareButton = ({
22
17
  caption = 'Screen Share',
23
18
  }: ScreenShareButtonProps) => {
24
19
  const call = useCall();
25
- const localParticipant = useLocalParticipant();
26
20
  const isSomeoneScreenSharing = useHasOngoingScreenShare();
27
- const isScreenSharing = localParticipant?.publishedTracks.includes(
28
- SfuModels.TrackType.SCREEN_SHARE,
29
- );
30
21
 
31
- const [isAwaitingApproval, setIsAwaitingApproval] = useState(false);
32
- const hasPermission = useHasPermissions(OwnCapability.SCREENSHARE);
33
- useEffect(() => {
34
- if (hasPermission) {
35
- setIsAwaitingApproval(false);
36
- }
37
- }, [hasPermission]);
22
+ const { t } = useI18n();
23
+ const { toggleScreenShare, isAwaitingPermission, isScreenSharing } =
24
+ useToggleScreenShare();
25
+
38
26
  return (
39
27
  <Restricted requiredGrants={[OwnCapability.SCREENSHARE]}>
40
28
  <PermissionNotification
41
29
  permission={OwnCapability.SCREENSHARE}
42
- isAwaitingApproval={isAwaitingApproval}
43
- messageApproved="You can now share your screen."
44
- messageAwaitingApproval="Awaiting for an approval to share screen."
45
- messageRevoked="You can no longer share your screen."
30
+ isAwaitingApproval={isAwaitingPermission}
31
+ messageApproved={t('You can now share your screen.')}
32
+ messageAwaitingApproval={t('Awaiting for an approval to share screen.')}
33
+ messageRevoked={t('You can no longer share your screen.')}
46
34
  >
47
35
  <CompositeButton active={isSomeoneScreenSharing} caption={caption}>
48
36
  <IconButton
49
37
  icon={isScreenSharing ? 'screen-share-on' : 'screen-share-off'}
50
- title="Share screen"
38
+ title={t('Share screen')}
51
39
  disabled={(!isScreenSharing && isSomeoneScreenSharing) || !call}
52
- onClick={async () => {
53
- if (
54
- !hasPermission &&
55
- call?.permissionsContext.canRequest(OwnCapability.SCREENSHARE)
56
- ) {
57
- setIsAwaitingApproval(true);
58
- await call
59
- .requestPermissions({
60
- permissions: [OwnCapability.SCREENSHARE],
61
- })
62
- .catch((reason) => {
63
- console.log('RequestPermissions failed', reason);
64
- });
65
- return;
66
- }
67
-
68
- if (!isScreenSharing && hasPermission) {
69
- const stream = await getScreenShareStream().catch((e) => {
70
- console.log(`Can't share screen: ${e}`);
71
- });
72
- if (stream) {
73
- await call?.publishScreenShareStream(stream);
74
- }
75
- } else {
76
- await call?.stopPublish(SfuModels.TrackType.SCREEN_SHARE);
77
- }
78
- }}
40
+ onClick={toggleScreenShare}
79
41
  />
80
42
  </CompositeButton>
81
43
  </PermissionNotification>
@@ -56,17 +56,17 @@ export const ToggleAudioPublishingButton = (
56
56
  SfuModels.TrackType.AUDIO,
57
57
  );
58
58
 
59
- const { toggleAudioMuteState: handleClick, isAwaitingApproval } =
59
+ const { toggleAudioMuteState: handleClick, isAwaitingPermission } =
60
60
  useToggleAudioMuteState();
61
61
 
62
62
  return (
63
63
  <Restricted requiredGrants={[OwnCapability.SEND_AUDIO]}>
64
64
  <PermissionNotification
65
65
  permission={OwnCapability.SEND_AUDIO}
66
- isAwaitingApproval={isAwaitingApproval}
67
- messageApproved="You can now speak."
68
- messageAwaitingApproval="Awaiting for an approval to speak."
69
- messageRevoked="You can no longer speak."
66
+ isAwaitingApproval={isAwaitingPermission}
67
+ messageApproved={t('You can now speak.')}
68
+ messageAwaitingApproval={t('Awaiting for an approval to speak.')}
69
+ messageRevoked={t('You can no longer speak.')}
70
70
  >
71
71
  <CompositeButton Menu={Menu} active={isAudioMute} caption={caption}>
72
72
  <IconButton
@@ -55,17 +55,19 @@ export const ToggleVideoPublishingButton = (
55
55
  SfuModels.TrackType.VIDEO,
56
56
  );
57
57
 
58
- const { toggleVideoMuteState: handleClick, isAwaitingApproval } =
58
+ const { toggleVideoMuteState: handleClick, isAwaitingPermission } =
59
59
  useToggleVideoMuteState();
60
60
 
61
61
  return (
62
62
  <Restricted requiredGrants={[OwnCapability.SEND_VIDEO]}>
63
63
  <PermissionNotification
64
64
  permission={OwnCapability.SEND_VIDEO}
65
- isAwaitingApproval={isAwaitingApproval}
66
- messageApproved="You can now share your video."
67
- messageAwaitingApproval="Awaiting for an approval to share your video."
68
- messageRevoked="You can no longer share your video."
65
+ isAwaitingApproval={isAwaitingPermission}
66
+ messageApproved={t('You can now share your video.')}
67
+ messageAwaitingApproval={t(
68
+ 'Awaiting for an approval to share your video.',
69
+ )}
70
+ messageRevoked={t('You can no longer share your video.')}
69
71
  >
70
72
  <CompositeButton Menu={Menu} active={isVideoMute} caption={caption}>
71
73
  <IconButton
@@ -16,11 +16,13 @@ import {
16
16
  import {
17
17
  useCall,
18
18
  useHasPermissions,
19
+ useI18n,
19
20
  useLocalParticipant,
20
21
  } from '@stream-io/video-react-bindings';
21
22
  import clsx from 'clsx';
22
23
 
23
24
  import { useFloatingUIPreset } from '../../hooks';
25
+ import { TranslatorFunction } from '@stream-io/i18n';
24
26
 
25
27
  const byNameOrId = (a: UserResponse, b: UserResponse) => {
26
28
  if (a.name && b.name && a.name < b.name) return -1;
@@ -30,6 +32,11 @@ const byNameOrId = (a: UserResponse, b: UserResponse) => {
30
32
  return 0;
31
33
  };
32
34
 
35
+ type HandleUpdatePermission = (
36
+ request: PermissionRequestEvent,
37
+ type: 'grant' | 'revoke' | 'dismiss',
38
+ ) => () => Promise<void>;
39
+
33
40
  export const PermissionRequests = () => {
34
41
  const call = useCall();
35
42
  const localParticipant = useLocalParticipant();
@@ -63,16 +70,18 @@ export const PermissionRequests = () => {
63
70
  };
64
71
  }, [call, canUpdateCallPermissions, localParticipant]);
65
72
 
66
- const handleUpdatePermission = (
67
- request: PermissionRequestEvent,
68
- allow: boolean,
69
- ) => {
73
+ const handleUpdatePermission: HandleUpdatePermission = (request, type) => {
70
74
  return async () => {
71
75
  const { user, permissions } = request;
72
- if (allow) {
73
- await call?.grantPermissions(user.id, permissions);
74
- } else {
75
- await call?.revokePermissions(user.id, permissions);
76
+ switch (type) {
77
+ case 'grant':
78
+ await call?.grantPermissions(user.id, permissions);
79
+ break;
80
+ case 'revoke':
81
+ await call?.revokePermissions(user.id, permissions);
82
+ break;
83
+ default:
84
+ break;
76
85
  }
77
86
  setPermissionRequests((requests) =>
78
87
  requests.filter((r) => r !== request),
@@ -122,10 +131,7 @@ export const PermissionRequests = () => {
122
131
 
123
132
  export type PermissionRequestListProps = ComponentProps<'div'> & {
124
133
  permissionRequests: PermissionRequestEvent[];
125
- handleUpdatePermission: (
126
- request: PermissionRequestEvent,
127
- allow: boolean,
128
- ) => () => Promise<void>;
134
+ handleUpdatePermission: HandleUpdatePermission;
129
135
  };
130
136
 
131
137
  export const PermissionRequestList = forwardRef<
@@ -133,6 +139,9 @@ export const PermissionRequestList = forwardRef<
133
139
  PermissionRequestListProps
134
140
  >((props, ref) => {
135
141
  const { permissionRequests, handleUpdatePermission, ...rest } = props;
142
+
143
+ const { t } = useI18n();
144
+
136
145
  return (
137
146
  <div className="str-video__permission-requests-list" ref={ref} {...rest}>
138
147
  {permissionRequests.map((request, reqIndex) => {
@@ -142,21 +151,28 @@ export const PermissionRequestList = forwardRef<
142
151
  {permissions.map((permission) => (
143
152
  <div className="str-video__permission-request" key={permission}>
144
153
  <div className="str-video__permission-request__message">
145
- {messageForPermission(user.name || user.id, permission)}
154
+ {messageForPermission(user.name || user.id, permission, t)}
146
155
  </div>
147
156
  <Button
148
157
  className="str-video__permission-request__button--allow"
149
158
  type="button"
150
- onClick={handleUpdatePermission(request, true)}
159
+ onClick={handleUpdatePermission(request, 'grant')}
151
160
  >
152
- Allow
161
+ {t('Allow')}
153
162
  </Button>
154
163
  <Button
155
164
  className="str-video__permission-request__button--reject"
156
165
  type="button"
157
- onClick={handleUpdatePermission(request, false)}
166
+ onClick={handleUpdatePermission(request, 'revoke')}
158
167
  >
159
- Reject
168
+ {t('Revoke')}
169
+ </Button>
170
+ <Button
171
+ className="str-video__permission-request__button--reject"
172
+ type="button"
173
+ onClick={handleUpdatePermission(request, 'dismiss')}
174
+ >
175
+ {t('Dismiss')}
160
176
  </Button>
161
177
  </div>
162
178
  ))}
@@ -179,15 +195,26 @@ const Button = (
179
195
  );
180
196
  };
181
197
 
182
- const messageForPermission = (userName: string, permission: string) => {
198
+ const messageForPermission = (
199
+ userName: string,
200
+ permission: string,
201
+ t: TranslatorFunction,
202
+ ) => {
183
203
  switch (permission) {
184
204
  case OwnCapability.SEND_AUDIO:
185
- return `${userName} is requesting to speak`;
205
+ return t('{{ userName }} is requesting to speak', { userName });
186
206
  case OwnCapability.SEND_VIDEO:
187
- return `${userName} is requesting to share their camera`;
207
+ return t('{{ userName }} is requesting to share their camera', {
208
+ userName,
209
+ });
188
210
  case OwnCapability.SCREENSHARE:
189
- return `${userName} is requesting to present their screen`;
211
+ return t('{{ userName }} is requesting to present their screen', {
212
+ userName,
213
+ });
190
214
  default:
191
- return `${userName} is requesting permission: ${permission}`;
215
+ return t('{{ userName }} is requesting permission: {{ permission }}', {
216
+ userName,
217
+ permission,
218
+ });
192
219
  }
193
220
  };
@@ -2,3 +2,6 @@ export * from './useFloatingUIPreset';
2
2
  export * from './useScrollPosition';
3
3
  export * from './useToggleAudioMuteState';
4
4
  export * from './useToggleVideoMuteState';
5
+ export * from './useToggleScreenShare';
6
+ export * from './useToggleCallRecording';
7
+ export * from './useRequestPermission';