@stream-io/video-react-sdk 1.0.5 → 1.0.7
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/CHANGELOG.md +17 -0
- package/dist/index.cjs.js +35 -37
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +36 -38
- package/dist/index.es.js.map +1 -1
- package/package.json +3 -3
- package/src/components/CallParticipantsList/CallParticipantListingItem.tsx +10 -9
- package/src/core/components/Audio/ParticipantsAudio.tsx +10 -13
- package/src/core/components/CallLayout/LivestreamLayout.tsx +5 -7
- package/src/core/components/CallLayout/SpeakerLayout.tsx +3 -5
- package/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +12 -12
- package/src/core/components/ParticipantView/ParticipantActionsContextMenu.tsx +16 -14
- package/src/core/components/ParticipantView/ParticipantView.tsx +12 -17
- package/src/core/components/Video/Video.tsx +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/video-react-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"packageManager": "yarn@3.2.4",
|
|
5
5
|
"main": "./dist/index.cjs.js",
|
|
6
6
|
"module": "./dist/index.es.js",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@floating-ui/react": "^0.26.5",
|
|
32
|
-
"@stream-io/video-client": "1.0.
|
|
32
|
+
"@stream-io/video-client": "1.0.6",
|
|
33
33
|
"@stream-io/video-filters-web": "0.1.0",
|
|
34
|
-
"@stream-io/video-react-bindings": "0.4.
|
|
34
|
+
"@stream-io/video-react-bindings": "0.4.32",
|
|
35
35
|
"chart.js": "^4.4.1",
|
|
36
36
|
"clsx": "^2.0.0",
|
|
37
37
|
"react-chartjs-2": "^5.2.0"
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import { ComponentProps, ComponentType, forwardRef } from 'react';
|
|
3
3
|
import { useConnectedUser, useI18n } from '@stream-io/video-react-bindings';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
hasAudio,
|
|
6
|
+
hasVideo,
|
|
7
|
+
isPinned,
|
|
8
|
+
StreamVideoParticipant,
|
|
9
|
+
} from '@stream-io/video-client';
|
|
5
10
|
import { IconButton } from '../Button';
|
|
6
11
|
import { MenuToggle, ToggleMenuButtonProps } from '../Menu';
|
|
7
12
|
import { WithTooltip } from '../Tooltip';
|
|
@@ -21,13 +26,9 @@ export const CallParticipantListingItem = ({
|
|
|
21
26
|
participant,
|
|
22
27
|
DisplayName = DefaultDisplayName,
|
|
23
28
|
}: CallParticipantListingItemProps) => {
|
|
24
|
-
const isAudioOn = participant
|
|
25
|
-
|
|
26
|
-
);
|
|
27
|
-
const isVideoOn = participant.publishedTracks.includes(
|
|
28
|
-
SfuModels.TrackType.VIDEO,
|
|
29
|
-
);
|
|
30
|
-
const isPinned = !!participant.pin;
|
|
29
|
+
const isAudioOn = hasAudio(participant);
|
|
30
|
+
const isVideoOn = hasVideo(participant);
|
|
31
|
+
const isPinnedOn = isPinned(participant);
|
|
31
32
|
|
|
32
33
|
const { t } = useI18n();
|
|
33
34
|
|
|
@@ -54,7 +55,7 @@ export const CallParticipantListingItem = ({
|
|
|
54
55
|
}`,
|
|
55
56
|
)}
|
|
56
57
|
/>
|
|
57
|
-
{
|
|
58
|
+
{isPinnedOn && (
|
|
58
59
|
<MediaIndicator
|
|
59
60
|
title={t('Pinned')}
|
|
60
61
|
className={clsx(
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { ComponentProps, Fragment } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
hasAudio,
|
|
4
|
+
hasScreenShareAudio,
|
|
5
|
+
StreamVideoParticipant,
|
|
6
|
+
} from '@stream-io/video-client';
|
|
3
7
|
import { Audio } from './Audio';
|
|
4
8
|
|
|
5
9
|
export type ParticipantsAudioProps = {
|
|
@@ -20,15 +24,10 @@ export const ParticipantsAudio = (props: ParticipantsAudioProps) => {
|
|
|
20
24
|
<>
|
|
21
25
|
{participants.map((participant) => {
|
|
22
26
|
if (participant.isLocalParticipant) return null;
|
|
23
|
-
const {
|
|
24
|
-
publishedTracks,
|
|
25
|
-
audioStream,
|
|
26
|
-
screenShareAudioStream,
|
|
27
|
-
sessionId,
|
|
28
|
-
} = participant;
|
|
27
|
+
const { audioStream, screenShareAudioStream, sessionId } = participant;
|
|
29
28
|
|
|
30
|
-
const
|
|
31
|
-
const audioTrackElement =
|
|
29
|
+
const hasAudioTrack = hasAudio(participant);
|
|
30
|
+
const audioTrackElement = hasAudioTrack && audioStream && (
|
|
32
31
|
<Audio
|
|
33
32
|
{...audioProps}
|
|
34
33
|
trackType="audioTrack"
|
|
@@ -36,10 +35,8 @@ export const ParticipantsAudio = (props: ParticipantsAudioProps) => {
|
|
|
36
35
|
/>
|
|
37
36
|
);
|
|
38
37
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
);
|
|
42
|
-
const screenShareAudioTrackElement = hasScreenShareAudio &&
|
|
38
|
+
const hasScreenShareAudioTrack = hasScreenShareAudio(participant);
|
|
39
|
+
const screenShareAudioTrackElement = hasScreenShareAudioTrack &&
|
|
43
40
|
screenShareAudioStream && (
|
|
44
41
|
<Audio
|
|
45
42
|
{...audioProps}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
useCallStateHooks,
|
|
6
6
|
useI18n,
|
|
7
7
|
} from '@stream-io/video-react-bindings';
|
|
8
|
-
import {
|
|
8
|
+
import { hasScreenShare } from '@stream-io/video-client';
|
|
9
9
|
import { ParticipantView, useParticipantViewContext } from '../ParticipantView';
|
|
10
10
|
import { ParticipantsAudio } from '../Audio';
|
|
11
11
|
import { usePaginatedLayoutSortPreset } from './hooks';
|
|
@@ -59,12 +59,13 @@ export const LivestreamLayout = (props: LivestreamLayoutProps) => {
|
|
|
59
59
|
const { useParticipants, useRemoteParticipants, useHasOngoingScreenShare } =
|
|
60
60
|
useCallStateHooks();
|
|
61
61
|
const call = useCall();
|
|
62
|
-
const
|
|
62
|
+
const participants = useParticipants();
|
|
63
|
+
const [currentSpeaker] = participants;
|
|
63
64
|
const remoteParticipants = useRemoteParticipants();
|
|
64
65
|
const hasOngoingScreenShare = useHasOngoingScreenShare();
|
|
65
66
|
const presenter = hasOngoingScreenShare
|
|
66
|
-
? hasScreenShare
|
|
67
|
-
:
|
|
67
|
+
? participants.find(hasScreenShare)
|
|
68
|
+
: undefined;
|
|
68
69
|
|
|
69
70
|
usePaginatedLayoutSortPreset(call);
|
|
70
71
|
|
|
@@ -122,9 +123,6 @@ export const LivestreamLayout = (props: LivestreamLayoutProps) => {
|
|
|
122
123
|
);
|
|
123
124
|
};
|
|
124
125
|
|
|
125
|
-
const hasScreenShare = (p?: StreamVideoParticipant) =>
|
|
126
|
-
!!p?.publishedTracks.includes(SfuModels.TrackType.SCREEN_SHARE);
|
|
127
|
-
|
|
128
126
|
const ParticipantOverlay = (props: {
|
|
129
127
|
enableFullScreen?: boolean;
|
|
130
128
|
showParticipantCount?: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
|
-
import {
|
|
3
|
+
import { hasScreenShare } from '@stream-io/video-client';
|
|
4
4
|
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
5
5
|
|
|
6
6
|
import {
|
|
@@ -56,7 +56,8 @@ export const SpeakerLayout = ({
|
|
|
56
56
|
const [buttonsWrapperElement, setButtonsWrapperElement] =
|
|
57
57
|
useState<HTMLDivElement | null>(null);
|
|
58
58
|
|
|
59
|
-
const isSpeakerScreenSharing =
|
|
59
|
+
const isSpeakerScreenSharing =
|
|
60
|
+
participantInSpotlight && hasScreenShare(participantInSpotlight);
|
|
60
61
|
const hardLimit = useCalculateHardLimit(
|
|
61
62
|
buttonsWrapperElement,
|
|
62
63
|
participantsBarElement,
|
|
@@ -247,6 +248,3 @@ const VerticalScrollButtons = <T extends HTMLElement>({
|
|
|
247
248
|
</>
|
|
248
249
|
);
|
|
249
250
|
};
|
|
250
|
-
|
|
251
|
-
const hasScreenShare = (p?: StreamVideoParticipant) =>
|
|
252
|
-
!!p?.publishedTracks.includes(SfuModels.TrackType.SCREEN_SHARE);
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ComponentType, forwardRef } from 'react';
|
|
2
2
|
import { Placement } from '@floating-ui/react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
hasAudio,
|
|
5
|
+
hasScreenShare,
|
|
6
|
+
hasVideo,
|
|
7
|
+
SfuModels,
|
|
8
|
+
} from '@stream-io/video-client';
|
|
4
9
|
import { useCall, useI18n } from '@stream-io/video-react-bindings';
|
|
5
10
|
import clsx from 'clsx';
|
|
6
11
|
|
|
@@ -71,15 +76,11 @@ export const DefaultParticipantViewUI = ({
|
|
|
71
76
|
ParticipantActionsContextMenu = DefaultParticipantActionsContextMenu,
|
|
72
77
|
}: DefaultParticipantViewUIProps) => {
|
|
73
78
|
const { participant, trackType } = useParticipantViewContext();
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
const hasScreenShare = publishedTracks.includes(
|
|
77
|
-
SfuModels.TrackType.SCREEN_SHARE,
|
|
78
|
-
);
|
|
79
|
+
const isScreenSharing = hasScreenShare(participant);
|
|
79
80
|
|
|
80
81
|
if (
|
|
81
82
|
participant.isLocalParticipant &&
|
|
82
|
-
|
|
83
|
+
isScreenSharing &&
|
|
83
84
|
trackType === 'screenShareTrack'
|
|
84
85
|
) {
|
|
85
86
|
return (
|
|
@@ -114,7 +115,6 @@ export const ParticipantDetails = ({
|
|
|
114
115
|
const {
|
|
115
116
|
isLocalParticipant,
|
|
116
117
|
connectionQuality,
|
|
117
|
-
publishedTracks,
|
|
118
118
|
pin,
|
|
119
119
|
sessionId,
|
|
120
120
|
name,
|
|
@@ -127,8 +127,8 @@ export const ParticipantDetails = ({
|
|
|
127
127
|
!!connectionQuality &&
|
|
128
128
|
SfuModels.ConnectionQuality[connectionQuality].toLowerCase();
|
|
129
129
|
|
|
130
|
-
const
|
|
131
|
-
const
|
|
130
|
+
const hasAudioTrack = hasAudio(participant);
|
|
131
|
+
const hasVideoTrack = hasVideo(participant);
|
|
132
132
|
const canUnpin = !!pin && pin.isLocalPin;
|
|
133
133
|
|
|
134
134
|
return (
|
|
@@ -137,10 +137,10 @@ export const ParticipantDetails = ({
|
|
|
137
137
|
<span className="str-video__participant-details__name">
|
|
138
138
|
{name || userId}
|
|
139
139
|
|
|
140
|
-
{indicatorsVisible && !
|
|
140
|
+
{indicatorsVisible && !hasAudioTrack && (
|
|
141
141
|
<span className="str-video__participant-details__name--audio-muted" />
|
|
142
142
|
)}
|
|
143
|
-
{indicatorsVisible && !
|
|
143
|
+
{indicatorsVisible && !hasVideoTrack && (
|
|
144
144
|
<span className="str-video__participant-details__name--video-muted" />
|
|
145
145
|
)}
|
|
146
146
|
{indicatorsVisible && canUnpin && (
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import { Restricted, useCall, useI18n } from '@stream-io/video-react-bindings';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
hasAudio,
|
|
5
|
+
hasScreenShare,
|
|
6
|
+
hasScreenShareAudio,
|
|
7
|
+
hasVideo,
|
|
8
|
+
OwnCapability,
|
|
9
|
+
} from '@stream-io/video-client';
|
|
4
10
|
import { useParticipantViewContext } from './ParticipantViewContext';
|
|
5
11
|
import {
|
|
6
12
|
GenericMenu,
|
|
@@ -21,16 +27,12 @@ export const ParticipantActionsContextMenu = () => {
|
|
|
21
27
|
const call = useCall();
|
|
22
28
|
const { t } = useI18n();
|
|
23
29
|
|
|
24
|
-
const { pin,
|
|
30
|
+
const { pin, sessionId, userId } = participant;
|
|
25
31
|
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
);
|
|
31
|
-
const hasScreenShareAudio = publishedTracks.includes(
|
|
32
|
-
SfuModels.TrackType.SCREEN_SHARE_AUDIO,
|
|
33
|
-
);
|
|
32
|
+
const hasAudioTrack = hasAudio(participant);
|
|
33
|
+
const hasVideoTrack = hasVideo(participant);
|
|
34
|
+
const hasScreenShareTrack = hasScreenShare(participant);
|
|
35
|
+
const hasScreenShareAudioTrack = hasScreenShareAudio(participant);
|
|
34
36
|
|
|
35
37
|
const blockUser = () => call?.blockUser(userId);
|
|
36
38
|
const muteAudio = () => call?.muteUser(userId, 'audio');
|
|
@@ -161,25 +163,25 @@ export const ParticipantActionsContextMenu = () => {
|
|
|
161
163
|
</GenericMenuButtonItem>
|
|
162
164
|
</Restricted>
|
|
163
165
|
<Restricted requiredGrants={[OwnCapability.MUTE_USERS]}>
|
|
164
|
-
{
|
|
166
|
+
{hasVideoTrack && (
|
|
165
167
|
<GenericMenuButtonItem onClick={muteVideo}>
|
|
166
168
|
<Icon icon="camera-off-outline" />
|
|
167
169
|
{t('Turn off video')}
|
|
168
170
|
</GenericMenuButtonItem>
|
|
169
171
|
)}
|
|
170
|
-
{
|
|
172
|
+
{hasScreenShareTrack && (
|
|
171
173
|
<GenericMenuButtonItem onClick={muteScreenShare}>
|
|
172
174
|
<Icon icon="screen-share-off" />
|
|
173
175
|
{t('Turn off screen share')}
|
|
174
176
|
</GenericMenuButtonItem>
|
|
175
177
|
)}
|
|
176
|
-
{
|
|
178
|
+
{hasAudioTrack && (
|
|
177
179
|
<GenericMenuButtonItem onClick={muteAudio}>
|
|
178
180
|
<Icon icon="no-audio" />
|
|
179
181
|
{t('Mute audio')}
|
|
180
182
|
</GenericMenuButtonItem>
|
|
181
183
|
)}
|
|
182
|
-
{
|
|
184
|
+
{hasScreenShareAudioTrack && (
|
|
183
185
|
<GenericMenuButtonItem onClick={muteScreenShareAudio}>
|
|
184
186
|
<Icon icon="no-audio" />
|
|
185
187
|
{t('Mute screen share audio')}
|
|
@@ -7,7 +7,9 @@ import {
|
|
|
7
7
|
} from 'react';
|
|
8
8
|
import clsx from 'clsx';
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
hasAudio,
|
|
11
|
+
hasScreenShareAudio,
|
|
12
|
+
hasVideo,
|
|
11
13
|
StreamVideoParticipant,
|
|
12
14
|
VideoTrackType,
|
|
13
15
|
} from '@stream-io/video-client';
|
|
@@ -74,19 +76,12 @@ export const ParticipantView = forwardRef<HTMLDivElement, ParticipantViewProps>(
|
|
|
74
76
|
},
|
|
75
77
|
ref,
|
|
76
78
|
) {
|
|
77
|
-
const {
|
|
78
|
-
|
|
79
|
-
isSpeaking,
|
|
80
|
-
isDominantSpeaker,
|
|
81
|
-
publishedTracks,
|
|
82
|
-
sessionId,
|
|
83
|
-
} = participant;
|
|
79
|
+
const { isLocalParticipant, isSpeaking, isDominantSpeaker, sessionId } =
|
|
80
|
+
participant;
|
|
84
81
|
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
SfuModels.TrackType.SCREEN_SHARE_AUDIO,
|
|
89
|
-
);
|
|
82
|
+
const hasAudioTrack = hasAudio(participant);
|
|
83
|
+
const hasVideoTrack = hasVideo(participant);
|
|
84
|
+
const hasScreenShareAudioTrack = hasScreenShareAudio(participant);
|
|
90
85
|
|
|
91
86
|
const [trackedElement, setTrackedElement] = useState<HTMLDivElement | null>(
|
|
92
87
|
null,
|
|
@@ -147,8 +142,8 @@ export const ParticipantView = forwardRef<HTMLDivElement, ParticipantViewProps>(
|
|
|
147
142
|
'str-video__participant-view',
|
|
148
143
|
isDominantSpeaker && 'str-video__participant-view--dominant-speaker',
|
|
149
144
|
isSpeaking && 'str-video__participant-view--speaking',
|
|
150
|
-
!
|
|
151
|
-
!
|
|
145
|
+
!hasVideoTrack && 'str-video__participant-view--no-video',
|
|
146
|
+
!hasAudioTrack && 'str-video__participant-view--no-audio',
|
|
152
147
|
className,
|
|
153
148
|
)}
|
|
154
149
|
>
|
|
@@ -156,10 +151,10 @@ export const ParticipantView = forwardRef<HTMLDivElement, ParticipantViewProps>(
|
|
|
156
151
|
{/* mute the local participant, as we don't want to hear ourselves */}
|
|
157
152
|
{!isLocalParticipant && !muteAudio && (
|
|
158
153
|
<>
|
|
159
|
-
{
|
|
154
|
+
{hasAudioTrack && (
|
|
160
155
|
<Audio participant={participant} trackType="audioTrack" />
|
|
161
156
|
)}
|
|
162
|
-
{
|
|
157
|
+
{hasScreenShareAudioTrack && (
|
|
163
158
|
<Audio
|
|
164
159
|
participant={participant}
|
|
165
160
|
trackType="screenShareAudioTrack"
|
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
hasScreenShare,
|
|
10
|
+
hasVideo,
|
|
10
11
|
StreamVideoParticipant,
|
|
11
12
|
VideoTrackType,
|
|
12
13
|
VisibilityState,
|
|
@@ -64,7 +65,6 @@ export const Video = ({
|
|
|
64
65
|
sessionId,
|
|
65
66
|
videoStream,
|
|
66
67
|
screenShareStream,
|
|
67
|
-
publishedTracks,
|
|
68
68
|
viewportVisibilityState,
|
|
69
69
|
isLocalParticipant,
|
|
70
70
|
userId,
|
|
@@ -130,9 +130,9 @@ export const Video = ({
|
|
|
130
130
|
|
|
131
131
|
const isPublishingTrack =
|
|
132
132
|
trackType === 'videoTrack'
|
|
133
|
-
?
|
|
133
|
+
? hasVideo(participant)
|
|
134
134
|
: trackType === 'screenShareTrack'
|
|
135
|
-
?
|
|
135
|
+
? hasScreenShare(participant)
|
|
136
136
|
: false;
|
|
137
137
|
|
|
138
138
|
const isInvisible =
|