@stream-io/video-react-sdk 1.43.3 → 1.44.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 +23 -1
- package/dist/css/embedded.css +11 -0
- package/dist/css/embedded.css.map +1 -1
- package/dist/css/styles.css +11 -0
- package/dist/css/styles.css.map +1 -1
- package/dist/embedded.cjs.js +54 -30
- package/dist/embedded.cjs.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/src/components/CallControls/ToggleVideoButton.js +30 -29
- package/dist/esm/src/components/CallControls/ToggleVideoButton.js.map +1 -1
- package/dist/esm/src/components/DeviceSettings/SpeakerTest.js +1 -1
- package/dist/esm/src/components/Notification/CameraUnavailableNotification.js +30 -0
- package/dist/esm/src/components/Notification/CameraUnavailableNotification.js.map +1 -0
- package/dist/esm/src/translations/en.json.js +2 -0
- package/dist/esm/src/translations/en.json.js.map +1 -1
- package/dist/index.cjs.js +56 -31
- package/dist/index.cjs.js.map +1 -1
- package/dist/src/components/Notification/CameraUnavailableNotification.d.ts +15 -0
- package/dist/src/components/Notification/index.d.ts +1 -0
- package/dist/src/translations/index.d.ts +2 -0
- package/package.json +4 -4
- package/src/components/CallControls/ToggleVideoButton.tsx +122 -115
- package/src/components/Notification/CameraUnavailableNotification.tsx +61 -0
- package/src/components/Notification/index.ts +1 -0
- package/src/translations/en.json +2 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { Placement } from '@floating-ui/react';
|
|
3
|
+
export type CameraUnavailableNotificationProps = {
|
|
4
|
+
placement?: Placement;
|
|
5
|
+
className?: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Shows when the last attempt to start the camera failed (e.g. the camera is
|
|
9
|
+
* in use by another app). Reads the error from the camera state, so it shows
|
|
10
|
+
* failures that happened before it was mounted.
|
|
11
|
+
*
|
|
12
|
+
* For error-specific copy, build your own notification on top of
|
|
13
|
+
* `useCameraState().error`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const CameraUnavailableNotification: ({ children, placement, className, }: PropsWithChildren<CameraUnavailableNotificationProps>) => import("react").JSX.Element;
|
|
@@ -62,6 +62,8 @@ export declare const translations: {
|
|
|
62
62
|
"Camera on": string;
|
|
63
63
|
"Camera off": string;
|
|
64
64
|
"Camera is paused by your system": string;
|
|
65
|
+
"Camera unavailable": string;
|
|
66
|
+
"Close other apps that might be using your camera and try again.": string;
|
|
65
67
|
"No camera found": string;
|
|
66
68
|
"Video is disabled": string;
|
|
67
69
|
Pinned: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/video-react-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.44.0",
|
|
4
4
|
"main": "./dist/index.cjs.js",
|
|
5
5
|
"module": "./dist/esm/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@floating-ui/react": "^0.27.20",
|
|
52
|
-
"@stream-io/video-client": "1.
|
|
52
|
+
"@stream-io/video-client": "1.62.0",
|
|
53
53
|
"@stream-io/video-filters-web": "0.10.0",
|
|
54
|
-
"@stream-io/video-react-bindings": "1.
|
|
54
|
+
"@stream-io/video-react-bindings": "1.21.0",
|
|
55
55
|
"chart.js": "^4.5.1",
|
|
56
56
|
"clsx": "^2.1.1",
|
|
57
57
|
"react-chartjs-2": "^5.3.1"
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
67
67
|
"@stream-io/audio-filters-web": "^0.10.4",
|
|
68
68
|
"@stream-io/typescript-config": "^0.0.0",
|
|
69
|
-
"@stream-io/video-styling": "^1.
|
|
69
|
+
"@stream-io/video-styling": "^1.16.0",
|
|
70
70
|
"@types/node": "^25.9.5",
|
|
71
71
|
"@types/react": "~19.2.18",
|
|
72
72
|
"@types/react-dom": "~19.2.4",
|
|
@@ -12,7 +12,10 @@ import {
|
|
|
12
12
|
} from '@stream-io/video-client';
|
|
13
13
|
import { CompositeButton, IconButtonWithMenuProps } from '../Button/';
|
|
14
14
|
import { DeviceSelectorVideo } from '../DeviceSettings';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
CameraUnavailableNotification,
|
|
17
|
+
PermissionNotification,
|
|
18
|
+
} from '../Notification';
|
|
16
19
|
import { useRequestPermission } from '../../hooks';
|
|
17
20
|
import { Icon } from '../Icon';
|
|
18
21
|
import { WithTooltip } from '../Tooltip';
|
|
@@ -58,64 +61,66 @@ export const ToggleVideoPreviewButton = (
|
|
|
58
61
|
const handleClick = createCallControlHandler(props, () => camera.toggle());
|
|
59
62
|
|
|
60
63
|
return (
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
tooltipDisabled={tooltipDisabled}
|
|
70
|
-
>
|
|
71
|
-
<CompositeButton
|
|
72
|
-
active={optionsAwareIsMute}
|
|
73
|
-
caption={caption}
|
|
74
|
-
className={clsx(
|
|
75
|
-
!hasBrowserPermission && 'str-video__device-unavailable',
|
|
76
|
-
)}
|
|
77
|
-
variant="secondary"
|
|
78
|
-
data-testid={
|
|
79
|
-
optionsAwareIsMute
|
|
80
|
-
? 'preview-video-unmute-button'
|
|
81
|
-
: 'preview-video-mute-button'
|
|
64
|
+
<CameraUnavailableNotification>
|
|
65
|
+
<WithTooltip
|
|
66
|
+
title={
|
|
67
|
+
!hasBrowserPermission
|
|
68
|
+
? t('Check your browser video permissions')
|
|
69
|
+
: isSystemMuted
|
|
70
|
+
? t('Camera is paused by your system')
|
|
71
|
+
: (caption ?? t('Video'))
|
|
82
72
|
}
|
|
83
|
-
|
|
84
|
-
disabled={
|
|
85
|
-
!hasBrowserPermission || (!optimisticUpdates && isTogglePending)
|
|
86
|
-
}
|
|
87
|
-
Menu={Menu}
|
|
88
|
-
menuPlacement={menuPlacement}
|
|
89
|
-
{...restCompositeButtonProps}
|
|
90
|
-
onMenuToggle={(shown) => {
|
|
91
|
-
setTooltipDisabled(shown);
|
|
92
|
-
onMenuToggle?.(shown);
|
|
93
|
-
}}
|
|
73
|
+
tooltipDisabled={tooltipDisabled}
|
|
94
74
|
>
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
75
|
+
<CompositeButton
|
|
76
|
+
active={optionsAwareIsMute}
|
|
77
|
+
caption={caption}
|
|
78
|
+
className={clsx(
|
|
79
|
+
!hasBrowserPermission && 'str-video__device-unavailable',
|
|
80
|
+
)}
|
|
81
|
+
variant="secondary"
|
|
82
|
+
data-testid={
|
|
83
|
+
optionsAwareIsMute
|
|
84
|
+
? 'preview-video-unmute-button'
|
|
85
|
+
: 'preview-video-mute-button'
|
|
86
|
+
}
|
|
87
|
+
onClick={handleClick}
|
|
88
|
+
disabled={
|
|
89
|
+
!hasBrowserPermission || (!optimisticUpdates && isTogglePending)
|
|
90
|
+
}
|
|
91
|
+
Menu={Menu}
|
|
92
|
+
menuPlacement={menuPlacement}
|
|
93
|
+
{...restCompositeButtonProps}
|
|
94
|
+
onMenuToggle={(shown) => {
|
|
95
|
+
setTooltipDisabled(shown);
|
|
96
|
+
onMenuToggle?.(shown);
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
<Icon icon={!optionsAwareIsMute ? 'camera' : 'camera-off'} />
|
|
100
|
+
{!hasBrowserPermission && (
|
|
101
|
+
<span
|
|
102
|
+
className="str-video__no-media-permission"
|
|
103
|
+
title={t('Check your browser video permissions')}
|
|
104
|
+
children="!"
|
|
105
|
+
/>
|
|
106
|
+
)}
|
|
107
|
+
{isPromptingPermission && (
|
|
108
|
+
<span
|
|
109
|
+
className="str-video__pending-permission"
|
|
110
|
+
title={t('Waiting for permission')}
|
|
111
|
+
children="?"
|
|
112
|
+
/>
|
|
113
|
+
)}
|
|
114
|
+
{isSystemMuted && hasBrowserPermission && (
|
|
115
|
+
<span
|
|
116
|
+
className="str-video__system-muted"
|
|
117
|
+
title={t('Camera is paused by your system')}
|
|
118
|
+
children="!"
|
|
119
|
+
/>
|
|
120
|
+
)}
|
|
121
|
+
</CompositeButton>
|
|
122
|
+
</WithTooltip>
|
|
123
|
+
</CameraUnavailableNotification>
|
|
119
124
|
);
|
|
120
125
|
};
|
|
121
126
|
|
|
@@ -178,70 +183,72 @@ export const ToggleVideoPublishingButton = (
|
|
|
178
183
|
)}
|
|
179
184
|
messageRevoked={t('You can no longer share your video.')}
|
|
180
185
|
>
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
tooltipDisabled={tooltipDisabled}
|
|
194
|
-
>
|
|
195
|
-
<CompositeButton
|
|
196
|
-
active={optionsAwareIsMute}
|
|
197
|
-
caption={caption}
|
|
198
|
-
variant="secondary"
|
|
199
|
-
disabled={
|
|
200
|
-
!hasBrowserPermission ||
|
|
201
|
-
!hasPermission ||
|
|
202
|
-
!isPublishingVideoAllowed ||
|
|
203
|
-
(!optimisticUpdates && isTogglePending)
|
|
204
|
-
}
|
|
205
|
-
data-testid={
|
|
206
|
-
optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button'
|
|
186
|
+
<CameraUnavailableNotification>
|
|
187
|
+
<WithTooltip
|
|
188
|
+
title={
|
|
189
|
+
!hasPermission
|
|
190
|
+
? t('You have no permission to share your video')
|
|
191
|
+
: !hasBrowserPermission
|
|
192
|
+
? t('Check your browser video permissions')
|
|
193
|
+
: !isPublishingVideoAllowed
|
|
194
|
+
? t('Video publishing is disabled by the system')
|
|
195
|
+
: isSystemMuted
|
|
196
|
+
? t('Camera is paused by your system')
|
|
197
|
+
: caption || t('Video')
|
|
207
198
|
}
|
|
208
|
-
|
|
209
|
-
Menu={Menu}
|
|
210
|
-
menuPlacement={menuPlacement}
|
|
211
|
-
menuOffset={16}
|
|
212
|
-
{...restCompositeButtonProps}
|
|
213
|
-
onMenuToggle={(shown) => {
|
|
214
|
-
setTooltipDisabled(shown);
|
|
215
|
-
onMenuToggle?.(shown);
|
|
216
|
-
}}
|
|
199
|
+
tooltipDisabled={tooltipDisabled}
|
|
217
200
|
>
|
|
218
|
-
<
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
?
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
201
|
+
<CompositeButton
|
|
202
|
+
active={optionsAwareIsMute}
|
|
203
|
+
caption={caption}
|
|
204
|
+
variant="secondary"
|
|
205
|
+
disabled={
|
|
206
|
+
!hasBrowserPermission ||
|
|
207
|
+
!hasPermission ||
|
|
208
|
+
!isPublishingVideoAllowed ||
|
|
209
|
+
(!optimisticUpdates && isTogglePending)
|
|
210
|
+
}
|
|
211
|
+
data-testid={
|
|
212
|
+
optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button'
|
|
213
|
+
}
|
|
214
|
+
onClick={handleClick}
|
|
215
|
+
Menu={Menu}
|
|
216
|
+
menuPlacement={menuPlacement}
|
|
217
|
+
menuOffset={16}
|
|
218
|
+
{...restCompositeButtonProps}
|
|
219
|
+
onMenuToggle={(shown) => {
|
|
220
|
+
setTooltipDisabled(shown);
|
|
221
|
+
onMenuToggle?.(shown);
|
|
222
|
+
}}
|
|
223
|
+
>
|
|
224
|
+
<Icon icon={optionsAwareIsMute ? 'camera-off' : 'camera'} />
|
|
225
|
+
{(!hasBrowserPermission ||
|
|
226
|
+
!hasPermission ||
|
|
227
|
+
!isPublishingVideoAllowed) && (
|
|
228
|
+
<span className="str-video__no-media-permission">!</span>
|
|
229
|
+
)}
|
|
230
|
+
{isPromptingPermission && (
|
|
236
231
|
<span
|
|
237
|
-
className="str-
|
|
238
|
-
title={t('
|
|
232
|
+
className="str-video__pending-permission"
|
|
233
|
+
title={t('Waiting for permission')}
|
|
239
234
|
>
|
|
240
|
-
|
|
235
|
+
?
|
|
241
236
|
</span>
|
|
242
237
|
)}
|
|
243
|
-
|
|
244
|
-
|
|
238
|
+
{isSystemMuted &&
|
|
239
|
+
hasBrowserPermission &&
|
|
240
|
+
hasPermission &&
|
|
241
|
+
isPublishingVideoAllowed && (
|
|
242
|
+
<span
|
|
243
|
+
className="str-video__system-muted"
|
|
244
|
+
title={t('Camera is paused by your system')}
|
|
245
|
+
>
|
|
246
|
+
!
|
|
247
|
+
</span>
|
|
248
|
+
)}
|
|
249
|
+
</CompositeButton>
|
|
250
|
+
</WithTooltip>
|
|
251
|
+
</CameraUnavailableNotification>
|
|
245
252
|
</PermissionNotification>
|
|
246
253
|
</Restricted>
|
|
247
254
|
);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { PropsWithChildren, useEffect, useState } from 'react';
|
|
2
|
+
import { Placement } from '@floating-ui/react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { useCallStateHooks, useI18n } from '@stream-io/video-react-bindings';
|
|
5
|
+
import { Notification } from './Notification';
|
|
6
|
+
|
|
7
|
+
export type CameraUnavailableNotificationProps = {
|
|
8
|
+
placement?: Placement;
|
|
9
|
+
className?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const UNAVAILABLE_ERRORS = ['NotReadableError', 'AbortError'];
|
|
13
|
+
|
|
14
|
+
const isCameraUnavailable = (error: Error | undefined) =>
|
|
15
|
+
!!error?.name && UNAVAILABLE_ERRORS.includes(error.name);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Shows when the last attempt to start the camera failed (e.g. the camera is
|
|
19
|
+
* in use by another app). Reads the error from the camera state, so it shows
|
|
20
|
+
* failures that happened before it was mounted.
|
|
21
|
+
*
|
|
22
|
+
* For error-specific copy, build your own notification on top of
|
|
23
|
+
* `useCameraState().error`.
|
|
24
|
+
*/
|
|
25
|
+
export const CameraUnavailableNotification = ({
|
|
26
|
+
children,
|
|
27
|
+
placement,
|
|
28
|
+
className,
|
|
29
|
+
}: PropsWithChildren<CameraUnavailableNotificationProps>) => {
|
|
30
|
+
const { useCameraState } = useCallStateHooks();
|
|
31
|
+
const { error } = useCameraState();
|
|
32
|
+
const { t } = useI18n();
|
|
33
|
+
const [isVisible, setIsVisible] = useState(() => isCameraUnavailable(error));
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
setIsVisible(isCameraUnavailable(error));
|
|
37
|
+
}, [error]);
|
|
38
|
+
|
|
39
|
+
const message = (
|
|
40
|
+
<>
|
|
41
|
+
<span className="str-video__notification__line str-video__notification__title">
|
|
42
|
+
{t('Camera unavailable')}
|
|
43
|
+
</span>
|
|
44
|
+
<span className="str-video__notification__line">
|
|
45
|
+
{t('Close other apps that might be using your camera and try again.')}
|
|
46
|
+
</span>
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Notification
|
|
52
|
+
message={message}
|
|
53
|
+
isVisible={isVisible}
|
|
54
|
+
placement={placement}
|
|
55
|
+
className={clsx('str-video__camera-unavailable-notification', className)}
|
|
56
|
+
close={() => setIsVisible(false)}
|
|
57
|
+
>
|
|
58
|
+
{children}
|
|
59
|
+
</Notification>
|
|
60
|
+
);
|
|
61
|
+
};
|
package/src/translations/en.json
CHANGED
|
@@ -67,6 +67,8 @@
|
|
|
67
67
|
"Camera on": "Camera on",
|
|
68
68
|
"Camera off": "Camera off",
|
|
69
69
|
"Camera is paused by your system": "Camera is paused by your system",
|
|
70
|
+
"Camera unavailable": "Camera unavailable",
|
|
71
|
+
"Close other apps that might be using your camera and try again.": "Close other apps that might be using your camera and try again.",
|
|
70
72
|
"No camera found": "No camera found",
|
|
71
73
|
"Video is disabled": "Video is disabled",
|
|
72
74
|
"Pinned": "Pinned",
|