@stream-io/video-react-sdk 1.20.2 → 1.21.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/index.cjs.js +47 -31
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +47 -31
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/CallControls/ScreenShareButton.d.ts +2 -1
- package/dist/src/components/CallControls/ToggleAudioButton.d.ts +3 -2
- package/dist/src/components/CallControls/ToggleVideoButton.d.ts +3 -2
- package/package.json +3 -3
- package/src/components/CallControls/ScreenShareButton.tsx +15 -8
- package/src/components/CallControls/ToggleAudioButton.tsx +29 -14
- package/src/components/CallControls/ToggleVideoButton.tsx +24 -14
- package/src/components/Notification/PermissionNotification.tsx +4 -2
- package/src/core/components/CallLayout/LivestreamLayout.tsx +14 -5
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { UseInputMediaDeviceOptions } from '@stream-io/video-react-bindings';
|
|
1
2
|
import { PropsWithErrorHandler } from '../../utilities/callControlHandler';
|
|
2
3
|
export type ScreenShareButtonProps = PropsWithErrorHandler<{
|
|
3
4
|
caption?: string;
|
|
4
|
-
}>;
|
|
5
|
+
} & UseInputMediaDeviceOptions>;
|
|
5
6
|
export declare const ScreenShareButton: (props: ScreenShareButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { type UseInputMediaDeviceOptions } from '@stream-io/video-react-bindings';
|
|
1
2
|
import { IconButtonWithMenuProps } from '../Button';
|
|
2
3
|
import { PropsWithErrorHandler } from '../../utilities/callControlHandler';
|
|
3
|
-
export type ToggleAudioPreviewButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
4
|
+
export type ToggleAudioPreviewButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'> & UseInputMediaDeviceOptions>;
|
|
4
5
|
export declare const ToggleAudioPreviewButton: (props: ToggleAudioPreviewButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
5
|
-
export type ToggleAudioPublishingButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
6
|
+
export type ToggleAudioPublishingButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'> & UseInputMediaDeviceOptions>;
|
|
6
7
|
export declare const ToggleAudioPublishingButton: (props: ToggleAudioPublishingButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { UseInputMediaDeviceOptions } from '@stream-io/video-react-bindings';
|
|
1
2
|
import { IconButtonWithMenuProps } from '../Button/';
|
|
2
3
|
import { PropsWithErrorHandler } from '../../utilities/callControlHandler';
|
|
3
|
-
export type ToggleVideoPreviewButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
4
|
+
export type ToggleVideoPreviewButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'> & UseInputMediaDeviceOptions>;
|
|
4
5
|
export declare const ToggleVideoPreviewButton: (props: ToggleVideoPreviewButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
5
|
-
type ToggleVideoPublishingButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
6
|
+
type ToggleVideoPublishingButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'> & UseInputMediaDeviceOptions>;
|
|
6
7
|
export declare const ToggleVideoPublishingButton: (props: ToggleVideoPublishingButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
8
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/video-react-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.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.29.0",
|
|
34
34
|
"@stream-io/video-filters-web": "0.2.1",
|
|
35
|
-
"@stream-io/video-react-bindings": "1.
|
|
35
|
+
"@stream-io/video-react-bindings": "1.8.0",
|
|
36
36
|
"chart.js": "^4.4.4",
|
|
37
37
|
"clsx": "^2.0.0",
|
|
38
38
|
"react-chartjs-2": "^5.3.0"
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
Restricted,
|
|
4
4
|
useCallStateHooks,
|
|
5
5
|
useI18n,
|
|
6
|
+
UseInputMediaDeviceOptions,
|
|
6
7
|
} from '@stream-io/video-react-bindings';
|
|
7
8
|
import { CompositeButton } from '../Button/';
|
|
8
9
|
import { PermissionNotification } from '../Notification';
|
|
@@ -14,13 +15,15 @@ import {
|
|
|
14
15
|
createCallControlHandler,
|
|
15
16
|
} from '../../utilities/callControlHandler';
|
|
16
17
|
|
|
17
|
-
export type ScreenShareButtonProps = PropsWithErrorHandler<
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
export type ScreenShareButtonProps = PropsWithErrorHandler<
|
|
19
|
+
{
|
|
20
|
+
caption?: string;
|
|
21
|
+
} & UseInputMediaDeviceOptions
|
|
22
|
+
>;
|
|
20
23
|
|
|
21
24
|
export const ScreenShareButton = (props: ScreenShareButtonProps) => {
|
|
22
25
|
const { t } = useI18n();
|
|
23
|
-
const { caption } = props;
|
|
26
|
+
const { caption, optimisticUpdates } = props;
|
|
24
27
|
|
|
25
28
|
const { useHasOngoingScreenShare, useScreenShareState, useCallSettings } =
|
|
26
29
|
useCallStateHooks();
|
|
@@ -31,11 +34,15 @@ export const ScreenShareButton = (props: ScreenShareButtonProps) => {
|
|
|
31
34
|
const callSettings = useCallSettings();
|
|
32
35
|
const isScreenSharingAllowed = callSettings?.screensharing.enabled;
|
|
33
36
|
|
|
34
|
-
const { screenShare,
|
|
35
|
-
|
|
37
|
+
const { screenShare, optionsAwareIsMute, isTogglePending } =
|
|
38
|
+
useScreenShareState({
|
|
39
|
+
optimisticUpdates,
|
|
40
|
+
});
|
|
41
|
+
const amIScreenSharing = !optionsAwareIsMute;
|
|
36
42
|
const disableScreenShareButton =
|
|
37
|
-
!amIScreenSharing &&
|
|
38
|
-
|
|
43
|
+
(!amIScreenSharing &&
|
|
44
|
+
(isSomeoneScreenSharing || isScreenSharingAllowed === false)) ||
|
|
45
|
+
(!optimisticUpdates && isTogglePending);
|
|
39
46
|
const handleClick = createCallControlHandler(props, async () => {
|
|
40
47
|
if (!hasPermission) {
|
|
41
48
|
await requestPermission();
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
Restricted,
|
|
4
4
|
useCallStateHooks,
|
|
5
5
|
useI18n,
|
|
6
|
+
type UseInputMediaDeviceOptions,
|
|
6
7
|
} from '@stream-io/video-react-bindings';
|
|
7
8
|
import clsx from 'clsx';
|
|
8
9
|
import { CompositeButton, IconButtonWithMenuProps } from '../Button';
|
|
@@ -21,7 +22,8 @@ export type ToggleAudioPreviewButtonProps = PropsWithErrorHandler<
|
|
|
21
22
|
Pick<
|
|
22
23
|
IconButtonWithMenuProps,
|
|
23
24
|
'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
24
|
-
>
|
|
25
|
+
> &
|
|
26
|
+
UseInputMediaDeviceOptions
|
|
25
27
|
>;
|
|
26
28
|
|
|
27
29
|
export const ToggleAudioPreviewButton = (
|
|
@@ -32,16 +34,18 @@ export const ToggleAudioPreviewButton = (
|
|
|
32
34
|
Menu = DeviceSelectorAudioInput,
|
|
33
35
|
menuPlacement = 'top',
|
|
34
36
|
onMenuToggle,
|
|
37
|
+
optimisticUpdates,
|
|
35
38
|
...restCompositeButtonProps
|
|
36
39
|
} = props;
|
|
37
40
|
const { t } = useI18n();
|
|
38
41
|
const { useMicrophoneState } = useCallStateHooks();
|
|
39
42
|
const {
|
|
40
43
|
microphone,
|
|
41
|
-
optimisticIsMute,
|
|
42
44
|
hasBrowserPermission,
|
|
43
45
|
isPromptingPermission,
|
|
44
|
-
|
|
46
|
+
optionsAwareIsMute,
|
|
47
|
+
isTogglePending,
|
|
48
|
+
} = useMicrophoneState({ optimisticUpdates });
|
|
45
49
|
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
46
50
|
const handleClick = createCallControlHandler(props, () =>
|
|
47
51
|
microphone.toggle(),
|
|
@@ -57,15 +61,17 @@ export const ToggleAudioPreviewButton = (
|
|
|
57
61
|
tooltipDisabled={tooltipDisabled}
|
|
58
62
|
>
|
|
59
63
|
<CompositeButton
|
|
60
|
-
active={
|
|
64
|
+
active={optionsAwareIsMute}
|
|
61
65
|
caption={caption}
|
|
62
66
|
className={clsx(
|
|
63
67
|
!hasBrowserPermission && 'str-video__device-unavailable',
|
|
64
68
|
)}
|
|
65
69
|
variant="secondary"
|
|
66
|
-
disabled={
|
|
70
|
+
disabled={
|
|
71
|
+
!hasBrowserPermission || (!optimisticUpdates && isTogglePending)
|
|
72
|
+
}
|
|
67
73
|
data-testid={
|
|
68
|
-
|
|
74
|
+
optionsAwareIsMute
|
|
69
75
|
? 'preview-audio-unmute-button'
|
|
70
76
|
: 'preview-audio-mute-button'
|
|
71
77
|
}
|
|
@@ -78,7 +84,7 @@ export const ToggleAudioPreviewButton = (
|
|
|
78
84
|
onMenuToggle?.(shown);
|
|
79
85
|
}}
|
|
80
86
|
>
|
|
81
|
-
<Icon icon={!
|
|
87
|
+
<Icon icon={!optionsAwareIsMute ? 'mic' : 'mic-off'} />
|
|
82
88
|
{!hasBrowserPermission && (
|
|
83
89
|
<span
|
|
84
90
|
className="str-video__no-media-permission"
|
|
@@ -102,7 +108,8 @@ export type ToggleAudioPublishingButtonProps = PropsWithErrorHandler<
|
|
|
102
108
|
Pick<
|
|
103
109
|
IconButtonWithMenuProps,
|
|
104
110
|
'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
105
|
-
>
|
|
111
|
+
> &
|
|
112
|
+
UseInputMediaDeviceOptions
|
|
106
113
|
>;
|
|
107
114
|
|
|
108
115
|
export const ToggleAudioPublishingButton = (
|
|
@@ -114,6 +121,7 @@ export const ToggleAudioPublishingButton = (
|
|
|
114
121
|
Menu = <DeviceSelectorAudioInput visualType="list" />,
|
|
115
122
|
menuPlacement = 'top',
|
|
116
123
|
onMenuToggle,
|
|
124
|
+
optimisticUpdates,
|
|
117
125
|
...restCompositeButtonProps
|
|
118
126
|
} = props;
|
|
119
127
|
|
|
@@ -123,10 +131,12 @@ export const ToggleAudioPublishingButton = (
|
|
|
123
131
|
const { useMicrophoneState } = useCallStateHooks();
|
|
124
132
|
const {
|
|
125
133
|
microphone,
|
|
126
|
-
optimisticIsMute,
|
|
127
134
|
hasBrowserPermission,
|
|
128
135
|
isPromptingPermission,
|
|
129
|
-
|
|
136
|
+
isTogglePending,
|
|
137
|
+
optionsAwareIsMute,
|
|
138
|
+
} = useMicrophoneState({ optimisticUpdates });
|
|
139
|
+
|
|
130
140
|
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
131
141
|
const handleClick = createCallControlHandler(props, async () => {
|
|
132
142
|
if (!hasPermission) {
|
|
@@ -156,12 +166,17 @@ export const ToggleAudioPublishingButton = (
|
|
|
156
166
|
tooltipDisabled={tooltipDisabled}
|
|
157
167
|
>
|
|
158
168
|
<CompositeButton
|
|
159
|
-
active={
|
|
169
|
+
active={optionsAwareIsMute}
|
|
160
170
|
caption={caption}
|
|
161
171
|
variant="secondary"
|
|
162
|
-
disabled={
|
|
172
|
+
disabled={
|
|
173
|
+
!hasBrowserPermission ||
|
|
174
|
+
!hasPermission ||
|
|
175
|
+
// disable button while the toggle action is pending when not using optimistic updates
|
|
176
|
+
(!optimisticUpdates && isTogglePending)
|
|
177
|
+
}
|
|
163
178
|
data-testid={
|
|
164
|
-
|
|
179
|
+
optionsAwareIsMute ? 'audio-unmute-button' : 'audio-mute-button'
|
|
165
180
|
}
|
|
166
181
|
onClick={handleClick}
|
|
167
182
|
Menu={Menu}
|
|
@@ -173,7 +188,7 @@ export const ToggleAudioPublishingButton = (
|
|
|
173
188
|
onMenuToggle?.(shown);
|
|
174
189
|
}}
|
|
175
190
|
>
|
|
176
|
-
<Icon icon={
|
|
191
|
+
<Icon icon={optionsAwareIsMute ? 'mic-off' : 'mic'} />
|
|
177
192
|
{(!hasBrowserPermission || !hasPermission) && (
|
|
178
193
|
<span className="str-video__no-media-permission">!</span>
|
|
179
194
|
)}
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
Restricted,
|
|
3
3
|
useCallStateHooks,
|
|
4
4
|
useI18n,
|
|
5
|
+
UseInputMediaDeviceOptions,
|
|
5
6
|
} from '@stream-io/video-react-bindings';
|
|
6
7
|
import clsx from 'clsx';
|
|
7
8
|
import { OwnCapability } from '@stream-io/video-client';
|
|
@@ -21,7 +22,8 @@ export type ToggleVideoPreviewButtonProps = PropsWithErrorHandler<
|
|
|
21
22
|
Pick<
|
|
22
23
|
IconButtonWithMenuProps,
|
|
23
24
|
'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
24
|
-
>
|
|
25
|
+
> &
|
|
26
|
+
UseInputMediaDeviceOptions
|
|
25
27
|
>;
|
|
26
28
|
|
|
27
29
|
export const ToggleVideoPreviewButton = (
|
|
@@ -32,16 +34,18 @@ export const ToggleVideoPreviewButton = (
|
|
|
32
34
|
Menu = DeviceSelectorVideo,
|
|
33
35
|
menuPlacement = 'top',
|
|
34
36
|
onMenuToggle,
|
|
37
|
+
optimisticUpdates,
|
|
35
38
|
...restCompositeButtonProps
|
|
36
39
|
} = props;
|
|
37
40
|
const { t } = useI18n();
|
|
38
41
|
const { useCameraState } = useCallStateHooks();
|
|
39
42
|
const {
|
|
40
43
|
camera,
|
|
41
|
-
optimisticIsMute,
|
|
42
44
|
hasBrowserPermission,
|
|
43
45
|
isPromptingPermission,
|
|
44
|
-
|
|
46
|
+
isTogglePending,
|
|
47
|
+
optionsAwareIsMute,
|
|
48
|
+
} = useCameraState({ optimisticUpdates });
|
|
45
49
|
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
46
50
|
const handleClick = createCallControlHandler(props, () => camera.toggle());
|
|
47
51
|
|
|
@@ -55,19 +59,21 @@ export const ToggleVideoPreviewButton = (
|
|
|
55
59
|
tooltipDisabled={tooltipDisabled}
|
|
56
60
|
>
|
|
57
61
|
<CompositeButton
|
|
58
|
-
active={
|
|
62
|
+
active={optionsAwareIsMute}
|
|
59
63
|
caption={caption}
|
|
60
64
|
className={clsx(
|
|
61
65
|
!hasBrowserPermission && 'str-video__device-unavailable',
|
|
62
66
|
)}
|
|
63
67
|
variant="secondary"
|
|
64
68
|
data-testid={
|
|
65
|
-
|
|
69
|
+
optionsAwareIsMute
|
|
66
70
|
? 'preview-video-unmute-button'
|
|
67
71
|
: 'preview-video-mute-button'
|
|
68
72
|
}
|
|
69
73
|
onClick={handleClick}
|
|
70
|
-
disabled={
|
|
74
|
+
disabled={
|
|
75
|
+
!hasBrowserPermission || (!optimisticUpdates && isTogglePending)
|
|
76
|
+
}
|
|
71
77
|
Menu={Menu}
|
|
72
78
|
menuPlacement={menuPlacement}
|
|
73
79
|
{...restCompositeButtonProps}
|
|
@@ -76,7 +82,7 @@ export const ToggleVideoPreviewButton = (
|
|
|
76
82
|
onMenuToggle?.(shown);
|
|
77
83
|
}}
|
|
78
84
|
>
|
|
79
|
-
<Icon icon={!
|
|
85
|
+
<Icon icon={!optionsAwareIsMute ? 'camera' : 'camera-off'} />
|
|
80
86
|
{!hasBrowserPermission && (
|
|
81
87
|
<span
|
|
82
88
|
className="str-video__no-media-permission"
|
|
@@ -100,7 +106,8 @@ type ToggleVideoPublishingButtonProps = PropsWithErrorHandler<
|
|
|
100
106
|
Pick<
|
|
101
107
|
IconButtonWithMenuProps,
|
|
102
108
|
'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
103
|
-
>
|
|
109
|
+
> &
|
|
110
|
+
UseInputMediaDeviceOptions
|
|
104
111
|
>;
|
|
105
112
|
|
|
106
113
|
export const ToggleVideoPublishingButton = (
|
|
@@ -112,6 +119,7 @@ export const ToggleVideoPublishingButton = (
|
|
|
112
119
|
Menu = <DeviceSelectorVideo visualType="list" />,
|
|
113
120
|
menuPlacement = 'top',
|
|
114
121
|
onMenuToggle,
|
|
122
|
+
optimisticUpdates,
|
|
115
123
|
...restCompositeButtonProps
|
|
116
124
|
} = props;
|
|
117
125
|
|
|
@@ -121,10 +129,11 @@ export const ToggleVideoPublishingButton = (
|
|
|
121
129
|
const { useCameraState, useCallSettings } = useCallStateHooks();
|
|
122
130
|
const {
|
|
123
131
|
camera,
|
|
124
|
-
|
|
132
|
+
optionsAwareIsMute,
|
|
125
133
|
hasBrowserPermission,
|
|
126
134
|
isPromptingPermission,
|
|
127
|
-
|
|
135
|
+
isTogglePending,
|
|
136
|
+
} = useCameraState({ optimisticUpdates });
|
|
128
137
|
const callSettings = useCallSettings();
|
|
129
138
|
const isPublishingVideoAllowed = callSettings?.video.enabled;
|
|
130
139
|
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
@@ -160,16 +169,17 @@ export const ToggleVideoPublishingButton = (
|
|
|
160
169
|
tooltipDisabled={tooltipDisabled}
|
|
161
170
|
>
|
|
162
171
|
<CompositeButton
|
|
163
|
-
active={
|
|
172
|
+
active={optionsAwareIsMute}
|
|
164
173
|
caption={caption}
|
|
165
174
|
variant="secondary"
|
|
166
175
|
disabled={
|
|
167
176
|
!hasBrowserPermission ||
|
|
168
177
|
!hasPermission ||
|
|
169
|
-
!isPublishingVideoAllowed
|
|
178
|
+
!isPublishingVideoAllowed ||
|
|
179
|
+
(!optimisticUpdates && isTogglePending)
|
|
170
180
|
}
|
|
171
181
|
data-testid={
|
|
172
|
-
|
|
182
|
+
optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button'
|
|
173
183
|
}
|
|
174
184
|
onClick={handleClick}
|
|
175
185
|
Menu={Menu}
|
|
@@ -181,7 +191,7 @@ export const ToggleVideoPublishingButton = (
|
|
|
181
191
|
onMenuToggle?.(shown);
|
|
182
192
|
}}
|
|
183
193
|
>
|
|
184
|
-
<Icon icon={
|
|
194
|
+
<Icon icon={optionsAwareIsMute ? 'camera-off' : 'camera'} />
|
|
185
195
|
{(!hasBrowserPermission ||
|
|
186
196
|
!hasPermission ||
|
|
187
197
|
!isPublishingVideoAllowed) && (
|
|
@@ -62,10 +62,12 @@ export const PermissionNotification = (props: PermissionNotificationProps) => {
|
|
|
62
62
|
'granted' | 'revoked'
|
|
63
63
|
>();
|
|
64
64
|
useEffect(() => {
|
|
65
|
-
if (
|
|
65
|
+
if (prevHasPermission.current === hasPermission) return;
|
|
66
|
+
|
|
67
|
+
if (hasPermission) {
|
|
66
68
|
setShowNotification('granted');
|
|
67
69
|
prevHasPermission.current = true;
|
|
68
|
-
} else
|
|
70
|
+
} else {
|
|
69
71
|
setShowNotification('revoked');
|
|
70
72
|
prevHasPermission.current = false;
|
|
71
73
|
}
|
|
@@ -261,15 +261,24 @@ const useUpdateCallDuration = () => {
|
|
|
261
261
|
|
|
262
262
|
const useToggleFullScreen = () => {
|
|
263
263
|
const { participantViewElement } = useParticipantViewContext();
|
|
264
|
-
const [isFullscreen, setIsFullscreen] = useState(
|
|
264
|
+
const [isFullscreen, setIsFullscreen] = useState(
|
|
265
|
+
!!document.fullscreenElement,
|
|
266
|
+
);
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
const handler = () => setIsFullscreen(!!document.fullscreenElement);
|
|
269
|
+
document.addEventListener('fullscreenchange', handler);
|
|
270
|
+
return () => {
|
|
271
|
+
document.removeEventListener('fullscreenchange', handler);
|
|
272
|
+
};
|
|
273
|
+
}, []);
|
|
265
274
|
return useCallback(() => {
|
|
266
275
|
if (isFullscreen) {
|
|
267
|
-
document.exitFullscreen().
|
|
268
|
-
|
|
276
|
+
document.exitFullscreen().catch((err) => {
|
|
277
|
+
console.error('Failed to exit fullscreen', err);
|
|
269
278
|
});
|
|
270
279
|
} else {
|
|
271
|
-
participantViewElement?.requestFullscreen().
|
|
272
|
-
|
|
280
|
+
participantViewElement?.requestFullscreen().catch((err) => {
|
|
281
|
+
console.error('Failed to enter fullscreen', err);
|
|
273
282
|
});
|
|
274
283
|
}
|
|
275
284
|
}, [isFullscreen, participantViewElement]);
|