@stream-io/video-react-sdk 1.19.8 → 1.20.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.
- package/CHANGELOG.md +16 -0
- package/dist/css/styles.css +5 -0
- package/dist/css/styles.css.map +1 -1
- package/dist/index.cjs.js +20 -26
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +20 -26
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/Search/hooks/useSearch.d.ts +1 -1
- package/dist/src/translations/index.d.ts +1 -0
- package/package.json +4 -4
- package/src/components/CallParticipantsList/CallParticipantsList.tsx +14 -25
- package/src/components/Search/hooks/useSearch.ts +8 -5
- package/src/core/components/ParticipantView/ParticipantActionsContextMenu.tsx +9 -8
- package/src/translations/en.json +1 -0
|
@@ -8,7 +8,7 @@ export type UseSearchParams<T> = {
|
|
|
8
8
|
/** Search function performing the search request */
|
|
9
9
|
searchFn: (searchQuery: string) => Promise<T[]>;
|
|
10
10
|
/** Debounce interval applied to the search function */
|
|
11
|
-
debounceInterval
|
|
11
|
+
debounceInterval?: number;
|
|
12
12
|
/** Search query string */
|
|
13
13
|
searchQuery?: string;
|
|
14
14
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/video-react-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"main": "./dist/index.cjs.js",
|
|
5
5
|
"module": "./dist/index.es.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@floating-ui/react": "^0.27.6",
|
|
33
|
-
"@stream-io/video-client": "1.
|
|
33
|
+
"@stream-io/video-client": "1.28.0",
|
|
34
34
|
"@stream-io/video-filters-web": "0.2.1",
|
|
35
|
-
"@stream-io/video-react-bindings": "1.7.
|
|
35
|
+
"@stream-io/video-react-bindings": "1.7.15",
|
|
36
36
|
"chart.js": "^4.4.4",
|
|
37
37
|
"clsx": "^2.0.0",
|
|
38
38
|
"react-chartjs-2": "^5.3.0"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@rollup/plugin-replace": "^6.0.2",
|
|
47
47
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
48
48
|
"@stream-io/audio-filters-web": "^0.4.3",
|
|
49
|
-
"@stream-io/video-styling": "^1.
|
|
49
|
+
"@stream-io/video-styling": "^1.5.0",
|
|
50
50
|
"@types/react": "^19.1.3",
|
|
51
51
|
"@types/react-dom": "^19.1.3",
|
|
52
52
|
"react": "19.0.0",
|
|
@@ -47,8 +47,6 @@ const UserListTypes = {
|
|
|
47
47
|
blocked: 'Blocked users',
|
|
48
48
|
} as const;
|
|
49
49
|
|
|
50
|
-
const DEFAULT_DEBOUNCE_SEARCH_INTERVAL = 200 as const;
|
|
51
|
-
|
|
52
50
|
export const CallParticipantsList = ({
|
|
53
51
|
onClose,
|
|
54
52
|
activeUsersSearchFn,
|
|
@@ -103,9 +101,9 @@ const CallParticipantListContentHeader = ({
|
|
|
103
101
|
}) => {
|
|
104
102
|
const call = useCall();
|
|
105
103
|
|
|
106
|
-
const muteAll = () => {
|
|
104
|
+
const muteAll = useCallback(() => {
|
|
107
105
|
call?.muteAllUsers('audio');
|
|
108
|
-
};
|
|
106
|
+
}, [call]);
|
|
109
107
|
|
|
110
108
|
return (
|
|
111
109
|
<div className="str-video__participant-list__content-header">
|
|
@@ -141,7 +139,7 @@ const CallParticipantListContentHeader = ({
|
|
|
141
139
|
const ActiveUsersSearchResults = ({
|
|
142
140
|
searchQuery,
|
|
143
141
|
activeUsersSearchFn: activeUsersSearchFnFromProps,
|
|
144
|
-
debounceSearchInterval
|
|
142
|
+
debounceSearchInterval,
|
|
145
143
|
}: Pick<
|
|
146
144
|
CallParticipantListProps,
|
|
147
145
|
'activeUsersSearchFn' | 'debounceSearchInterval'
|
|
@@ -150,23 +148,18 @@ const ActiveUsersSearchResults = ({
|
|
|
150
148
|
const participants = useParticipants({ sortBy: name });
|
|
151
149
|
|
|
152
150
|
const activeUsersSearchFn = useCallback(
|
|
153
|
-
(queryString: string) => {
|
|
151
|
+
async (queryString: string) => {
|
|
154
152
|
const queryRegExp = new RegExp(queryString, 'i');
|
|
155
|
-
return
|
|
156
|
-
participants.filter((participant) => {
|
|
157
|
-
return participant.name.match(queryRegExp);
|
|
158
|
-
}),
|
|
159
|
-
);
|
|
153
|
+
return participants.filter((p) => p.name.match(queryRegExp));
|
|
160
154
|
},
|
|
161
155
|
[participants],
|
|
162
156
|
);
|
|
163
157
|
|
|
164
|
-
const { searchQueryInProgress, searchResults } =
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
158
|
+
const { searchQueryInProgress, searchResults } = useSearch({
|
|
159
|
+
searchFn: activeUsersSearchFnFromProps ?? activeUsersSearchFn,
|
|
160
|
+
debounceInterval: debounceSearchInterval,
|
|
161
|
+
searchQuery,
|
|
162
|
+
});
|
|
170
163
|
|
|
171
164
|
return (
|
|
172
165
|
<SearchResults<StreamVideoParticipant>
|
|
@@ -181,7 +174,7 @@ const ActiveUsersSearchResults = ({
|
|
|
181
174
|
|
|
182
175
|
const BlockedUsersSearchResults = ({
|
|
183
176
|
blockedUsersSearchFn: blockedUsersSearchFnFromProps,
|
|
184
|
-
debounceSearchInterval
|
|
177
|
+
debounceSearchInterval,
|
|
185
178
|
searchQuery,
|
|
186
179
|
}: Pick<
|
|
187
180
|
CallParticipantListProps,
|
|
@@ -191,18 +184,14 @@ const BlockedUsersSearchResults = ({
|
|
|
191
184
|
const blockedUsers = useCallBlockedUserIds();
|
|
192
185
|
|
|
193
186
|
const blockedUsersSearchFn = useCallback(
|
|
194
|
-
(queryString: string) => {
|
|
187
|
+
async (queryString: string) => {
|
|
195
188
|
const queryRegExp = new RegExp(queryString, 'i');
|
|
196
|
-
return
|
|
197
|
-
blockedUsers.filter((blockedUser) => {
|
|
198
|
-
return blockedUser.match(queryRegExp);
|
|
199
|
-
}),
|
|
200
|
-
);
|
|
189
|
+
return blockedUsers.filter((userId) => userId.match(queryRegExp));
|
|
201
190
|
},
|
|
202
191
|
[blockedUsers],
|
|
203
192
|
);
|
|
204
193
|
|
|
205
|
-
const { searchQueryInProgress, searchResults } = useSearch
|
|
194
|
+
const { searchQueryInProgress, searchResults } = useSearch({
|
|
206
195
|
searchFn: blockedUsersSearchFnFromProps ?? blockedUsersSearchFn,
|
|
207
196
|
debounceInterval: debounceSearchInterval,
|
|
208
197
|
searchQuery,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
export type SearchController<T> = {
|
|
4
4
|
/** Flag signals that the search request is flight await the response */
|
|
@@ -11,19 +11,22 @@ export type UseSearchParams<T> = {
|
|
|
11
11
|
/** Search function performing the search request */
|
|
12
12
|
searchFn: (searchQuery: string) => Promise<T[]>;
|
|
13
13
|
/** Debounce interval applied to the search function */
|
|
14
|
-
debounceInterval
|
|
14
|
+
debounceInterval?: number;
|
|
15
15
|
/** Search query string */
|
|
16
16
|
searchQuery?: string;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export const useSearch = <T>({
|
|
20
|
-
debounceInterval,
|
|
20
|
+
debounceInterval = 200,
|
|
21
21
|
searchFn,
|
|
22
22
|
searchQuery = '',
|
|
23
23
|
}: UseSearchParams<T>): SearchController<T> => {
|
|
24
24
|
const [searchResults, setSearchResults] = useState<T[]>([]);
|
|
25
25
|
const [searchQueryInProgress, setSearchQueryInProgress] = useState(false);
|
|
26
26
|
|
|
27
|
+
const searchFnRef = useRef(searchFn);
|
|
28
|
+
searchFnRef.current = searchFn;
|
|
29
|
+
|
|
27
30
|
useEffect(() => {
|
|
28
31
|
if (!searchQuery.length) {
|
|
29
32
|
setSearchQueryInProgress(false);
|
|
@@ -35,7 +38,7 @@ export const useSearch = <T>({
|
|
|
35
38
|
|
|
36
39
|
const timeout = setTimeout(async () => {
|
|
37
40
|
try {
|
|
38
|
-
const results = await
|
|
41
|
+
const results = await searchFnRef.current(searchQuery);
|
|
39
42
|
setSearchResults(results);
|
|
40
43
|
} catch (error) {
|
|
41
44
|
console.error(error);
|
|
@@ -47,7 +50,7 @@ export const useSearch = <T>({
|
|
|
47
50
|
return () => {
|
|
48
51
|
clearTimeout(timeout);
|
|
49
52
|
};
|
|
50
|
-
}, [debounceInterval,
|
|
53
|
+
}, [debounceInterval, searchQuery]);
|
|
51
54
|
|
|
52
55
|
return {
|
|
53
56
|
searchQueryInProgress,
|
|
@@ -34,6 +34,7 @@ export const ParticipantActionsContextMenu = () => {
|
|
|
34
34
|
const hasScreenShareAudioTrack = hasScreenShareAudio(participant);
|
|
35
35
|
|
|
36
36
|
const blockUser = () => call?.blockUser(userId);
|
|
37
|
+
const kickUser = () => call?.kickUser({ user_id: userId });
|
|
37
38
|
const muteAudio = () => call?.muteUser(userId, 'audio');
|
|
38
39
|
const muteVideo = () => call?.muteUser(userId, 'video');
|
|
39
40
|
const muteScreenShare = () => call?.muteUser(userId, 'screenshare');
|
|
@@ -64,10 +65,7 @@ export const ParticipantActionsContextMenu = () => {
|
|
|
64
65
|
|
|
65
66
|
const pinForEveryone = () => {
|
|
66
67
|
call
|
|
67
|
-
?.pinForEveryone({
|
|
68
|
-
user_id: userId,
|
|
69
|
-
session_id: sessionId,
|
|
70
|
-
})
|
|
68
|
+
?.pinForEveryone({ user_id: userId, session_id: sessionId })
|
|
71
69
|
.catch((err) => {
|
|
72
70
|
console.error(`Failed to pin participant ${userId}`, err);
|
|
73
71
|
});
|
|
@@ -75,10 +73,7 @@ export const ParticipantActionsContextMenu = () => {
|
|
|
75
73
|
|
|
76
74
|
const unpinForEveryone = () => {
|
|
77
75
|
call
|
|
78
|
-
?.unpinForEveryone({
|
|
79
|
-
user_id: userId,
|
|
80
|
-
session_id: sessionId,
|
|
81
|
-
})
|
|
76
|
+
?.unpinForEveryone({ user_id: userId, session_id: sessionId })
|
|
82
77
|
.catch((err) => {
|
|
83
78
|
console.error(`Failed to unpin participant ${userId}`, err);
|
|
84
79
|
});
|
|
@@ -145,6 +140,12 @@ export const ParticipantActionsContextMenu = () => {
|
|
|
145
140
|
{t('Block')}
|
|
146
141
|
</GenericMenuButtonItem>
|
|
147
142
|
</Restricted>
|
|
143
|
+
<Restricted requiredGrants={[OwnCapability.KICK_USER]}>
|
|
144
|
+
<GenericMenuButtonItem onClick={kickUser}>
|
|
145
|
+
<Icon icon="kick-user" />
|
|
146
|
+
{t('Kick')}
|
|
147
|
+
</GenericMenuButtonItem>
|
|
148
|
+
</Restricted>
|
|
148
149
|
<Restricted requiredGrants={[OwnCapability.MUTE_USERS]}>
|
|
149
150
|
{hasVideoTrack && (
|
|
150
151
|
<GenericMenuButtonItem onClick={muteVideo}>
|
package/src/translations/en.json
CHANGED