@stream-io/video-react-sdk 1.0.7 → 1.0.8
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 +10 -0
- package/dist/css/styles.css +3 -3
- package/dist/index.cjs.js +139 -87
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +140 -88
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/Button/CompositeButton.d.ts +1 -0
- package/dist/src/components/CallControls/CancelCallButton.d.ts +2 -1
- package/dist/src/components/CallControls/ScreenShareButton.d.ts +3 -2
- package/dist/src/components/CallControls/ToggleAudioButton.d.ts +3 -2
- package/dist/src/components/CallControls/ToggleVideoButton.d.ts +3 -2
- package/dist/src/components/Menu/MenuToggle.d.ts +2 -1
- package/dist/src/components/Tooltip/WithTooltip.d.ts +4 -2
- package/dist/src/utilities/callControlHandler.d.ts +16 -0
- package/package.json +2 -2
- package/src/components/Button/CompositeButton.tsx +3 -0
- package/src/components/CallControls/CallControls.tsx +3 -3
- package/src/components/CallControls/CancelCallButton.tsx +12 -8
- package/src/components/CallControls/ReactionsButton.tsx +14 -9
- package/src/components/CallControls/RecordCallButton.tsx +21 -15
- package/src/components/CallControls/ScreenShareButton.tsx +34 -26
- package/src/components/CallControls/ToggleAudioButton.tsx +84 -56
- package/src/components/CallControls/ToggleVideoButton.tsx +87 -59
- package/src/components/DeviceSettings/DeviceSelector.tsx +4 -0
- package/src/components/Menu/MenuToggle.tsx +9 -0
- package/src/components/Tooltip/WithTooltip.tsx +7 -2
- package/src/utilities/callControlHandler.ts +43 -0
|
@@ -10,5 +10,6 @@ export type IconButtonWithMenuProps<E extends HTMLElement = HTMLButtonElement> =
|
|
|
10
10
|
menuOffset?: number;
|
|
11
11
|
ToggleMenuButton?: ComponentType<ToggleMenuButtonProps<E>>;
|
|
12
12
|
variant?: 'primary' | 'secondary';
|
|
13
|
+
onMenuToggle?: (menuShown: boolean) => void;
|
|
13
14
|
}> & ComponentProps<'button'>;
|
|
14
15
|
export declare const CompositeButton: import("react").ForwardRefExoticComponent<Omit<IconButtonWithMenuProps<HTMLButtonElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { MouseEventHandler } from 'react';
|
|
2
2
|
export type CancelCallButtonProps = {
|
|
3
3
|
disabled?: boolean;
|
|
4
|
+
caption?: string;
|
|
4
5
|
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
5
6
|
onLeave?: () => void;
|
|
6
7
|
};
|
|
7
8
|
export declare const CancelCallConfirmButton: ({ onClick, onLeave, }: CancelCallButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
export declare const CancelCallButton: ({ disabled, onClick, onLeave, }: CancelCallButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare const CancelCallButton: ({ disabled, caption, onClick, onLeave, }: CancelCallButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { PropsWithErrorHandler } from '../../utilities/callControlHandler';
|
|
2
|
+
export type ScreenShareButtonProps = PropsWithErrorHandler<{
|
|
2
3
|
caption?: string;
|
|
3
|
-
}
|
|
4
|
+
}>;
|
|
4
5
|
export declare const ScreenShareButton: (props: ScreenShareButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IconButtonWithMenuProps } from '../Button';
|
|
2
|
-
|
|
2
|
+
import { PropsWithErrorHandler } from '../../utilities/callControlHandler';
|
|
3
|
+
export type ToggleAudioPreviewButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'>>;
|
|
3
4
|
export declare const ToggleAudioPreviewButton: (props: ToggleAudioPreviewButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
4
|
-
export type ToggleAudioPublishingButtonProps = Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement'
|
|
5
|
+
export type ToggleAudioPublishingButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'>>;
|
|
5
6
|
export declare const ToggleAudioPublishingButton: (props: ToggleAudioPublishingButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IconButtonWithMenuProps } from '../Button/';
|
|
2
|
-
|
|
2
|
+
import { PropsWithErrorHandler } from '../../utilities/callControlHandler';
|
|
3
|
+
export type ToggleVideoPreviewButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'>>;
|
|
3
4
|
export declare const ToggleVideoPreviewButton: (props: ToggleVideoPreviewButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
4
|
-
type ToggleVideoPublishingButtonProps = Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement'
|
|
5
|
+
type ToggleVideoPublishingButtonProps = PropsWithErrorHandler<Pick<IconButtonWithMenuProps, 'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'>>;
|
|
5
6
|
export declare const ToggleVideoPublishingButton: (props: ToggleVideoPublishingButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
7
|
export {};
|
|
@@ -14,6 +14,7 @@ export type MenuToggleProps<E extends HTMLElement> = PropsWithChildren<{
|
|
|
14
14
|
strategy?: Strategy;
|
|
15
15
|
offset?: number;
|
|
16
16
|
visualType?: MenuVisualType;
|
|
17
|
+
onToggle?: (menuShown: boolean) => void;
|
|
17
18
|
}>;
|
|
18
19
|
export type MenuContextValue = {
|
|
19
20
|
close?: () => void;
|
|
@@ -22,4 +23,4 @@ export type MenuContextValue = {
|
|
|
22
23
|
* Access to the closes MenuContext.
|
|
23
24
|
*/
|
|
24
25
|
export declare const useMenuContext: () => MenuContextValue;
|
|
25
|
-
export declare const MenuToggle: <E extends HTMLElement>({ ToggleButton, placement, strategy, offset, visualType, children, }: MenuToggleProps<E>) => import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export declare const MenuToggle: <E extends HTMLElement>({ ToggleButton, placement, strategy, offset, visualType, children, onToggle, }: MenuToggleProps<E>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ComponentProps } from 'react';
|
|
2
2
|
import { TooltipProps } from './Tooltip';
|
|
3
|
-
type WithPopupProps = ComponentProps<'div'> & Omit<TooltipProps<HTMLDivElement>, 'referenceElement'
|
|
4
|
-
|
|
3
|
+
type WithPopupProps = ComponentProps<'div'> & Omit<TooltipProps<HTMLDivElement>, 'referenceElement' | 'children'> & {
|
|
4
|
+
tooltipDisabled?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare const WithTooltip: ({ title, tooltipClassName, tooltipPlacement, tooltipDisabled, ...props }: WithPopupProps) => import("react/jsx-runtime").JSX.Element;
|
|
5
7
|
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type PropsWithErrorHandler<T = unknown> = T & {
|
|
2
|
+
/**
|
|
3
|
+
* Will be called if the call control action failed with an error (e.g. user didn't grant a
|
|
4
|
+
* browser permission to enable a media device). If no callback is provided, just logs the error.
|
|
5
|
+
* @param error Exception which caused call control action to fail
|
|
6
|
+
*/
|
|
7
|
+
onError?: (error: unknown) => void;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Wraps an event handler, silencing and logging exceptions (excluding the NotAllowedError
|
|
11
|
+
* DOMException, which is a normal situation handled by the SDK)
|
|
12
|
+
*
|
|
13
|
+
* @param props component props, including the onError callback
|
|
14
|
+
* @param handler event handler to wrap
|
|
15
|
+
*/
|
|
16
|
+
export declare const createCallControlHandler: (props: PropsWithErrorHandler, handler: () => Promise<void>) => (() => Promise<void>);
|
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.8",
|
|
4
4
|
"packageManager": "yarn@3.2.4",
|
|
5
5
|
"main": "./dist/index.cjs.js",
|
|
6
6
|
"module": "./dist/index.es.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@rollup/plugin-replace": "^5.0.5",
|
|
46
46
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
47
47
|
"@stream-io/audio-filters-web": "^0.1.0",
|
|
48
|
-
"@stream-io/video-styling": "^1.0.
|
|
48
|
+
"@stream-io/video-styling": "^1.0.3",
|
|
49
49
|
"react": "^18.2.0",
|
|
50
50
|
"react-dom": "^18.2.0",
|
|
51
51
|
"rimraf": "^5.0.5",
|
|
@@ -22,6 +22,7 @@ export type IconButtonWithMenuProps<E extends HTMLElement = HTMLButtonElement> =
|
|
|
22
22
|
menuOffset?: number;
|
|
23
23
|
ToggleMenuButton?: ComponentType<ToggleMenuButtonProps<E>>;
|
|
24
24
|
variant?: 'primary' | 'secondary';
|
|
25
|
+
onMenuToggle?: (menuShown: boolean) => void;
|
|
25
26
|
}> &
|
|
26
27
|
ComponentProps<'button'>;
|
|
27
28
|
|
|
@@ -41,6 +42,7 @@ export const CompositeButton = forwardRef<
|
|
|
41
42
|
ToggleMenuButton = DefaultToggleMenuButton,
|
|
42
43
|
variant,
|
|
43
44
|
onClick,
|
|
45
|
+
onMenuToggle,
|
|
44
46
|
...restButtonProps
|
|
45
47
|
},
|
|
46
48
|
ref,
|
|
@@ -79,6 +81,7 @@ export const CompositeButton = forwardRef<
|
|
|
79
81
|
offset={menuOffset}
|
|
80
82
|
placement={menuPlacement}
|
|
81
83
|
ToggleButton={ToggleMenuButton}
|
|
84
|
+
onToggle={onMenuToggle}
|
|
82
85
|
>
|
|
83
86
|
{isComponentType(Menu) ? <Menu /> : Menu}
|
|
84
87
|
</MenuToggle>
|
|
@@ -12,13 +12,13 @@ export type CallControlsProps = {
|
|
|
12
12
|
|
|
13
13
|
export const CallControls = ({ onLeave }: CallControlsProps) => (
|
|
14
14
|
<div className="str-video__call-controls">
|
|
15
|
-
<RecordCallButton />
|
|
16
|
-
<ReactionsButton />
|
|
17
|
-
<ScreenShareButton />
|
|
18
15
|
<SpeakingWhileMutedNotification>
|
|
19
16
|
<ToggleAudioPublishingButton />
|
|
20
17
|
</SpeakingWhileMutedNotification>
|
|
21
18
|
<ToggleVideoPublishingButton />
|
|
19
|
+
<ReactionsButton />
|
|
20
|
+
<ScreenShareButton />
|
|
21
|
+
<RecordCallButton />
|
|
22
22
|
<CancelCallButton onLeave={onLeave} />
|
|
23
23
|
</div>
|
|
24
24
|
);
|
|
@@ -6,6 +6,7 @@ import { MenuToggle, ToggleMenuButtonProps } from '../Menu';
|
|
|
6
6
|
|
|
7
7
|
import { IconButton } from '../Button';
|
|
8
8
|
import { Icon } from '../Icon';
|
|
9
|
+
import { WithTooltip } from '../Tooltip';
|
|
9
10
|
|
|
10
11
|
const EndCallMenu = (props: {
|
|
11
12
|
onLeave: MouseEventHandler<HTMLButtonElement>;
|
|
@@ -51,18 +52,20 @@ const CancelCallToggleMenuButton = forwardRef<
|
|
|
51
52
|
>(function CancelCallToggleMenuButton(props, ref) {
|
|
52
53
|
const { t } = useI18n();
|
|
53
54
|
return (
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
<WithTooltip title={t('Leave call')}>
|
|
56
|
+
<IconButton
|
|
57
|
+
icon="call-end"
|
|
58
|
+
variant="danger"
|
|
59
|
+
data-testid="leave-call-button"
|
|
60
|
+
ref={ref}
|
|
61
|
+
/>
|
|
62
|
+
</WithTooltip>
|
|
61
63
|
);
|
|
62
64
|
});
|
|
63
65
|
|
|
64
66
|
export type CancelCallButtonProps = {
|
|
65
67
|
disabled?: boolean;
|
|
68
|
+
caption?: string;
|
|
66
69
|
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
67
70
|
onLeave?: () => void;
|
|
68
71
|
};
|
|
@@ -106,6 +109,7 @@ export const CancelCallConfirmButton = ({
|
|
|
106
109
|
|
|
107
110
|
export const CancelCallButton = ({
|
|
108
111
|
disabled,
|
|
112
|
+
caption,
|
|
109
113
|
onClick,
|
|
110
114
|
onLeave,
|
|
111
115
|
}: CancelCallButtonProps) => {
|
|
@@ -127,7 +131,7 @@ export const CancelCallButton = ({
|
|
|
127
131
|
disabled={disabled}
|
|
128
132
|
icon="call-end"
|
|
129
133
|
variant="danger"
|
|
130
|
-
title={t('Leave call')}
|
|
134
|
+
title={caption ?? t('Leave call')}
|
|
131
135
|
data-testid="cancel-call-button"
|
|
132
136
|
onClick={handleClick}
|
|
133
137
|
/>
|
|
@@ -4,10 +4,16 @@ import clsx from 'clsx';
|
|
|
4
4
|
import { OwnCapability, StreamReaction } from '@stream-io/video-client';
|
|
5
5
|
import { Restricted, useCall, useI18n } from '@stream-io/video-react-bindings';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
MenuToggle,
|
|
9
|
+
MenuVisualType,
|
|
10
|
+
ToggleMenuButtonProps,
|
|
11
|
+
useMenuContext,
|
|
12
|
+
} from '../Menu';
|
|
8
13
|
import { CompositeButton } from '../Button';
|
|
9
14
|
import { defaultEmojiReactionMap } from '../Reaction';
|
|
10
15
|
import { Icon } from '../Icon';
|
|
16
|
+
import { WithTooltip } from '../Tooltip';
|
|
11
17
|
|
|
12
18
|
export const defaultReactions: StreamReaction[] = [
|
|
13
19
|
{
|
|
@@ -63,14 +69,11 @@ const ToggleReactionsMenuButton = forwardRef<
|
|
|
63
69
|
>(function ToggleReactionsMenuButton({ menuShown }, ref) {
|
|
64
70
|
const { t } = useI18n();
|
|
65
71
|
return (
|
|
66
|
-
<
|
|
67
|
-
ref={ref}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
>
|
|
72
|
-
<Icon icon="reactions" />
|
|
73
|
-
</CompositeButton>
|
|
72
|
+
<WithTooltip title={t('Reactions')} tooltipDisabled={menuShown}>
|
|
73
|
+
<CompositeButton ref={ref} active={menuShown} variant="primary">
|
|
74
|
+
<Icon icon="reactions" />
|
|
75
|
+
</CompositeButton>
|
|
76
|
+
</WithTooltip>
|
|
74
77
|
);
|
|
75
78
|
});
|
|
76
79
|
|
|
@@ -84,6 +87,7 @@ export const DefaultReactionsMenu = ({
|
|
|
84
87
|
layout = 'horizontal',
|
|
85
88
|
}: DefaultReactionsMenuProps) => {
|
|
86
89
|
const call = useCall();
|
|
90
|
+
const { close } = useMenuContext();
|
|
87
91
|
return (
|
|
88
92
|
<div
|
|
89
93
|
className={clsx('str-video__reactions-menu', {
|
|
@@ -98,6 +102,7 @@ export const DefaultReactionsMenu = ({
|
|
|
98
102
|
className="str-video__reactions-menu__button"
|
|
99
103
|
onClick={() => {
|
|
100
104
|
call?.sendReaction(reaction);
|
|
105
|
+
close?.();
|
|
101
106
|
}}
|
|
102
107
|
>
|
|
103
108
|
{reaction.emoji_code && defaultEmojiReactionMap[reaction.emoji_code]}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from '../Menu';
|
|
13
13
|
import { LoadingIndicator } from '../LoadingIndicator';
|
|
14
14
|
import { useToggleCallRecording } from '../../hooks';
|
|
15
|
+
import { WithTooltip } from '../Tooltip';
|
|
15
16
|
|
|
16
17
|
export type RecordCallButtonProps = {
|
|
17
18
|
caption?: string;
|
|
@@ -89,6 +90,10 @@ export const RecordCallConfirmationButton = ({
|
|
|
89
90
|
);
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
const title = isAwaitingResponse
|
|
94
|
+
? t('Waiting for recording to start...')
|
|
95
|
+
: caption ?? t('Record call');
|
|
96
|
+
|
|
92
97
|
return (
|
|
93
98
|
<Restricted
|
|
94
99
|
requiredGrants={[
|
|
@@ -96,20 +101,21 @@ export const RecordCallConfirmationButton = ({
|
|
|
96
101
|
OwnCapability.STOP_RECORD_CALL,
|
|
97
102
|
]}
|
|
98
103
|
>
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
<WithTooltip title={title}>
|
|
105
|
+
<CompositeButton
|
|
106
|
+
active={isCallRecordingInProgress}
|
|
107
|
+
caption={caption}
|
|
108
|
+
variant="secondary"
|
|
109
|
+
data-testid="recording-start-button"
|
|
110
|
+
onClick={isAwaitingResponse ? undefined : toggleCallRecording}
|
|
111
|
+
>
|
|
112
|
+
{isAwaitingResponse ? (
|
|
113
|
+
<LoadingIndicator />
|
|
114
|
+
) : (
|
|
115
|
+
<Icon icon="recording-off" />
|
|
116
|
+
)}
|
|
117
|
+
</CompositeButton>
|
|
118
|
+
</WithTooltip>
|
|
113
119
|
</Restricted>
|
|
114
120
|
);
|
|
115
121
|
};
|
|
@@ -119,7 +125,7 @@ export const RecordCallButton = ({ caption }: RecordCallButtonProps) => {
|
|
|
119
125
|
const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } =
|
|
120
126
|
useToggleCallRecording();
|
|
121
127
|
|
|
122
|
-
let title = caption
|
|
128
|
+
let title = caption ?? t('Record call');
|
|
123
129
|
|
|
124
130
|
if (isAwaitingResponse) {
|
|
125
131
|
title = isCallRecordingInProgress
|
|
@@ -8,10 +8,15 @@ import { CompositeButton } from '../Button/';
|
|
|
8
8
|
import { PermissionNotification } from '../Notification';
|
|
9
9
|
import { useRequestPermission } from '../../hooks';
|
|
10
10
|
import { Icon } from '../Icon';
|
|
11
|
+
import { WithTooltip } from '../Tooltip';
|
|
12
|
+
import {
|
|
13
|
+
PropsWithErrorHandler,
|
|
14
|
+
createCallControlHandler,
|
|
15
|
+
} from '../../utilities/callControlHandler';
|
|
11
16
|
|
|
12
|
-
export type ScreenShareButtonProps = {
|
|
17
|
+
export type ScreenShareButtonProps = PropsWithErrorHandler<{
|
|
13
18
|
caption?: string;
|
|
14
|
-
}
|
|
19
|
+
}>;
|
|
15
20
|
|
|
16
21
|
export const ScreenShareButton = (props: ScreenShareButtonProps) => {
|
|
17
22
|
const { t } = useI18n();
|
|
@@ -31,6 +36,14 @@ export const ScreenShareButton = (props: ScreenShareButtonProps) => {
|
|
|
31
36
|
const disableScreenShareButton =
|
|
32
37
|
!amIScreenSharing &&
|
|
33
38
|
(isSomeoneScreenSharing || isScreenSharingAllowed === false);
|
|
39
|
+
const handleClick = createCallControlHandler(props, async () => {
|
|
40
|
+
if (!hasPermission) {
|
|
41
|
+
await requestPermission();
|
|
42
|
+
} else {
|
|
43
|
+
await screenShare.toggle();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
34
47
|
return (
|
|
35
48
|
<Restricted requiredGrants={[OwnCapability.SCREENSHARE]}>
|
|
36
49
|
<PermissionNotification
|
|
@@ -40,31 +53,26 @@ export const ScreenShareButton = (props: ScreenShareButtonProps) => {
|
|
|
40
53
|
messageAwaitingApproval={t('Awaiting for an approval to share screen.')}
|
|
41
54
|
messageRevoked={t('You can no longer share your screen.')}
|
|
42
55
|
>
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
disabled={disableScreenShareButton}
|
|
54
|
-
onClick={async () => {
|
|
55
|
-
if (!hasPermission) {
|
|
56
|
-
await requestPermission();
|
|
57
|
-
} else {
|
|
58
|
-
await screenShare.toggle();
|
|
59
|
-
}
|
|
60
|
-
}}
|
|
61
|
-
>
|
|
62
|
-
<Icon
|
|
63
|
-
icon={
|
|
64
|
-
isSomeoneScreenSharing ? 'screen-share-on' : 'screen-share-off'
|
|
56
|
+
<WithTooltip title={caption ?? t('Share screen')}>
|
|
57
|
+
<CompositeButton
|
|
58
|
+
active={isSomeoneScreenSharing || amIScreenSharing}
|
|
59
|
+
caption={caption}
|
|
60
|
+
variant="primary"
|
|
61
|
+
data-testid={
|
|
62
|
+
isSomeoneScreenSharing
|
|
63
|
+
? 'screen-share-stop-button'
|
|
64
|
+
: 'screen-share-start-button'
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
disabled={disableScreenShareButton}
|
|
67
|
+
onClick={handleClick}
|
|
68
|
+
>
|
|
69
|
+
<Icon
|
|
70
|
+
icon={
|
|
71
|
+
isSomeoneScreenSharing ? 'screen-share-on' : 'screen-share-off'
|
|
72
|
+
}
|
|
73
|
+
/>
|
|
74
|
+
</CompositeButton>
|
|
75
|
+
</WithTooltip>
|
|
68
76
|
</PermissionNotification>
|
|
69
77
|
</Restricted>
|
|
70
78
|
);
|
|
@@ -10,10 +10,18 @@ import { DeviceSelectorAudioInput } from '../DeviceSettings';
|
|
|
10
10
|
import { PermissionNotification } from '../Notification';
|
|
11
11
|
import { useRequestPermission } from '../../hooks';
|
|
12
12
|
import { Icon } from '../Icon';
|
|
13
|
+
import { WithTooltip } from '../Tooltip';
|
|
14
|
+
import { useState } from 'react';
|
|
15
|
+
import {
|
|
16
|
+
PropsWithErrorHandler,
|
|
17
|
+
createCallControlHandler,
|
|
18
|
+
} from '../../utilities/callControlHandler';
|
|
13
19
|
|
|
14
|
-
export type ToggleAudioPreviewButtonProps =
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
export type ToggleAudioPreviewButtonProps = PropsWithErrorHandler<
|
|
21
|
+
Pick<
|
|
22
|
+
IconButtonWithMenuProps,
|
|
23
|
+
'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
24
|
+
>
|
|
17
25
|
>;
|
|
18
26
|
|
|
19
27
|
export const ToggleAudioPreviewButton = (
|
|
@@ -24,44 +32,57 @@ export const ToggleAudioPreviewButton = (
|
|
|
24
32
|
const { useMicrophoneState } = useCallStateHooks();
|
|
25
33
|
const { microphone, optimisticIsMute, hasBrowserPermission } =
|
|
26
34
|
useMicrophoneState();
|
|
35
|
+
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
36
|
+
const handleClick = createCallControlHandler(props, () =>
|
|
37
|
+
microphone.toggle(),
|
|
38
|
+
);
|
|
27
39
|
|
|
28
40
|
return (
|
|
29
|
-
<
|
|
30
|
-
active={optimisticIsMute}
|
|
31
|
-
caption={caption}
|
|
32
|
-
className={clsx(!hasBrowserPermission && 'str-video__device-unavailable')}
|
|
33
|
-
variant="secondary"
|
|
41
|
+
<WithTooltip
|
|
34
42
|
title={
|
|
35
43
|
!hasBrowserPermission
|
|
36
44
|
? t('Check your browser audio permissions')
|
|
37
|
-
: caption
|
|
45
|
+
: caption ?? t('Mic')
|
|
38
46
|
}
|
|
39
|
-
|
|
40
|
-
data-testid={
|
|
41
|
-
optimisticIsMute
|
|
42
|
-
? 'preview-audio-unmute-button'
|
|
43
|
-
: 'preview-audio-mute-button'
|
|
44
|
-
}
|
|
45
|
-
onClick={() => microphone.toggle()}
|
|
46
|
-
Menu={Menu}
|
|
47
|
-
menuPlacement={menuPlacement}
|
|
48
|
-
{...restCompositeButtonProps}
|
|
47
|
+
tooltipDisabled={tooltipDisabled}
|
|
49
48
|
>
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
<CompositeButton
|
|
50
|
+
active={optimisticIsMute}
|
|
51
|
+
caption={caption}
|
|
52
|
+
className={clsx(
|
|
53
|
+
!hasBrowserPermission && 'str-video__device-unavailable',
|
|
54
|
+
)}
|
|
55
|
+
variant="secondary"
|
|
56
|
+
disabled={!hasBrowserPermission}
|
|
57
|
+
data-testid={
|
|
58
|
+
optimisticIsMute
|
|
59
|
+
? 'preview-audio-unmute-button'
|
|
60
|
+
: 'preview-audio-mute-button'
|
|
61
|
+
}
|
|
62
|
+
onClick={handleClick}
|
|
63
|
+
Menu={Menu}
|
|
64
|
+
menuPlacement={menuPlacement}
|
|
65
|
+
onMenuToggle={(shown) => setTooltipDisabled(shown)}
|
|
66
|
+
{...restCompositeButtonProps}
|
|
67
|
+
>
|
|
68
|
+
<Icon icon={!optimisticIsMute ? 'mic' : 'mic-off'} />
|
|
69
|
+
{!hasBrowserPermission && (
|
|
70
|
+
<span
|
|
71
|
+
className="str-video__no-media-permission"
|
|
72
|
+
title={t('Check your browser audio permissions')}
|
|
73
|
+
children="!"
|
|
74
|
+
/>
|
|
75
|
+
)}
|
|
76
|
+
</CompositeButton>
|
|
77
|
+
</WithTooltip>
|
|
59
78
|
);
|
|
60
79
|
};
|
|
61
80
|
|
|
62
|
-
export type ToggleAudioPublishingButtonProps =
|
|
63
|
-
|
|
64
|
-
|
|
81
|
+
export type ToggleAudioPublishingButtonProps = PropsWithErrorHandler<
|
|
82
|
+
Pick<
|
|
83
|
+
IconButtonWithMenuProps,
|
|
84
|
+
'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
|
|
85
|
+
>
|
|
65
86
|
>;
|
|
66
87
|
|
|
67
88
|
export const ToggleAudioPublishingButton = (
|
|
@@ -81,6 +102,14 @@ export const ToggleAudioPublishingButton = (
|
|
|
81
102
|
const { useMicrophoneState } = useCallStateHooks();
|
|
82
103
|
const { microphone, optimisticIsMute, hasBrowserPermission } =
|
|
83
104
|
useMicrophoneState();
|
|
105
|
+
const [tooltipDisabled, setTooltipDisabled] = useState(false);
|
|
106
|
+
const handleClick = createCallControlHandler(props, async () => {
|
|
107
|
+
if (!hasPermission) {
|
|
108
|
+
await requestPermission();
|
|
109
|
+
} else {
|
|
110
|
+
await microphone.toggle();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
84
113
|
|
|
85
114
|
return (
|
|
86
115
|
<Restricted requiredGrants={[OwnCapability.SEND_AUDIO]}>
|
|
@@ -91,38 +120,37 @@ export const ToggleAudioPublishingButton = (
|
|
|
91
120
|
messageAwaitingApproval={t('Awaiting for an approval to speak.')}
|
|
92
121
|
messageRevoked={t('You can no longer speak.')}
|
|
93
122
|
>
|
|
94
|
-
<
|
|
95
|
-
active={optimisticIsMute}
|
|
96
|
-
caption={caption}
|
|
123
|
+
<WithTooltip
|
|
97
124
|
title={
|
|
98
125
|
!hasPermission
|
|
99
126
|
? t('You have no permission to share your audio')
|
|
100
127
|
: !hasBrowserPermission
|
|
101
128
|
? t('Check your browser mic permissions')
|
|
102
|
-
: caption
|
|
129
|
+
: caption ?? t('Mic')
|
|
103
130
|
}
|
|
104
|
-
|
|
105
|
-
disabled={!hasBrowserPermission || !hasPermission}
|
|
106
|
-
data-testid={
|
|
107
|
-
optimisticIsMute ? 'audio-unmute-button' : 'audio-mute-button'
|
|
108
|
-
}
|
|
109
|
-
onClick={async () => {
|
|
110
|
-
if (!hasPermission) {
|
|
111
|
-
await requestPermission();
|
|
112
|
-
} else {
|
|
113
|
-
await microphone.toggle();
|
|
114
|
-
}
|
|
115
|
-
}}
|
|
116
|
-
Menu={Menu}
|
|
117
|
-
menuPlacement={menuPlacement}
|
|
118
|
-
menuOffset={16}
|
|
119
|
-
{...restCompositeButtonProps}
|
|
131
|
+
tooltipDisabled={tooltipDisabled}
|
|
120
132
|
>
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
<CompositeButton
|
|
134
|
+
active={optimisticIsMute}
|
|
135
|
+
caption={caption}
|
|
136
|
+
variant="secondary"
|
|
137
|
+
disabled={!hasBrowserPermission || !hasPermission}
|
|
138
|
+
data-testid={
|
|
139
|
+
optimisticIsMute ? 'audio-unmute-button' : 'audio-mute-button'
|
|
140
|
+
}
|
|
141
|
+
onClick={handleClick}
|
|
142
|
+
Menu={Menu}
|
|
143
|
+
menuPlacement={menuPlacement}
|
|
144
|
+
menuOffset={16}
|
|
145
|
+
onMenuToggle={(shown) => setTooltipDisabled(shown)}
|
|
146
|
+
{...restCompositeButtonProps}
|
|
147
|
+
>
|
|
148
|
+
<Icon icon={optimisticIsMute ? 'mic-off' : 'mic'} />
|
|
149
|
+
{(!hasBrowserPermission || !hasPermission) && (
|
|
150
|
+
<span className="str-video__no-media-permission">!</span>
|
|
151
|
+
)}
|
|
152
|
+
</CompositeButton>
|
|
153
|
+
</WithTooltip>
|
|
126
154
|
</PermissionNotification>
|
|
127
155
|
</Restricted>
|
|
128
156
|
);
|