@100mslive/roomkit-react 0.1.4-alpha.1 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/{HLSView-F2K5VSTS.js → HLSView-P57IRMAR.js} +7 -11
- package/dist/{HLSView-F2K5VSTS.js.map → HLSView-P57IRMAR.js.map} +1 -1
- package/dist/PinnedTrackView-4FYJEBTB.js +102 -0
- package/dist/PinnedTrackView-4FYJEBTB.js.map +7 -0
- package/dist/Popover/index.d.ts +1 -0
- package/dist/Prebuilt/App.d.ts +25 -0
- package/dist/Prebuilt/index.d.ts +1 -0
- package/dist/Prebuilt/provider/roomLayoutProvider/index.d.ts +1 -1
- package/dist/Sheet/Sheet.d.ts +3093 -0
- package/dist/Sheet/index.d.ts +1 -0
- package/dist/Theme/ThemeProvider.d.ts +4 -286
- package/dist/Theme/stitches.config.d.ts +1 -1
- package/dist/{VirtualBackground-S3XEPZ2T.js → VirtualBackground-GGCQJ5JM.js} +31 -7
- package/dist/VirtualBackground-GGCQJ5JM.js.map +7 -0
- package/dist/chunk-IVTWKQI3.js +827 -0
- package/dist/chunk-IVTWKQI3.js.map +7 -0
- package/dist/{chunk-42SWPN2C.js → chunk-OSM4QEQG.js} +3020 -2189
- package/dist/chunk-OSM4QEQG.js.map +7 -0
- package/dist/chunk-P5X32KOD.js +67 -0
- package/dist/chunk-P5X32KOD.js.map +7 -0
- package/dist/chunk-RVCZPPTL.js +1100 -0
- package/dist/chunk-RVCZPPTL.js.map +7 -0
- package/dist/{chunk-ESUJK7AT.js → conference-P6I6ESVF.js} +3136 -653
- package/dist/conference-P6I6ESVF.js.map +7 -0
- package/dist/index.cjs.js +15733 -15498
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +4 -8
- package/dist/meta.cjs.json +3355 -3017
- package/dist/meta.esbuild.json +3534 -3329
- package/dist/utils/animations.d.ts +16 -0
- package/package.json +8 -10
- package/src/Button/Button.tsx +4 -4
- package/src/Dropdown/Dropdown.tsx +2 -2
- package/src/IconButton/IconButton.tsx +4 -2
- package/src/Pagination/StyledPagination.tsx +1 -0
- package/src/Popover/index.tsx +2 -1
- package/src/Prebuilt/{App.jsx → App.tsx} +95 -48
- package/src/Prebuilt/Prebuilt.stories.tsx +22 -8
- package/src/Prebuilt/common/constants.js +1 -2
- package/src/Prebuilt/common/hooks.js +8 -0
- package/src/Prebuilt/common/utils.js +15 -0
- package/src/Prebuilt/components/AppData/AppData.jsx +1 -2
- package/src/Prebuilt/components/AppData/useUISettings.js +0 -5
- package/src/Prebuilt/components/AudioVideoToggle.jsx +69 -26
- package/src/Prebuilt/components/AuthToken.jsx +3 -2
- package/src/Prebuilt/components/Chat/ChatSelector.jsx +1 -1
- package/src/Prebuilt/components/Connection/TileConnection.jsx +0 -1
- package/src/Prebuilt/components/EmojiReaction.jsx +23 -73
- package/src/Prebuilt/components/EndSessionContent.jsx +57 -0
- package/src/Prebuilt/components/EqualProminence.jsx +180 -0
- package/src/Prebuilt/components/ErrorBoundary.jsx +4 -10
- package/src/Prebuilt/components/Footer/EmojiCard.jsx +34 -0
- package/src/Prebuilt/components/Footer/Footer.jsx +73 -0
- package/src/Prebuilt/components/{Header → Footer}/ParticipantList.jsx +5 -5
- package/src/Prebuilt/components/Header/ConferencingHeader.jsx +27 -7
- package/src/Prebuilt/components/Header/HeaderComponents.jsx +16 -14
- package/src/Prebuilt/components/Header/StreamActions.jsx +101 -36
- package/src/Prebuilt/components/Header/StreamingHeader.jsx +1 -1
- package/src/Prebuilt/components/Header/common.jsx +164 -0
- package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.jsx +1 -2
- package/src/Prebuilt/components/LeaveCard.jsx +19 -0
- package/src/Prebuilt/components/LeaveRoom.jsx +35 -143
- package/src/Prebuilt/components/LeaveSessionContent.jsx +45 -0
- package/src/Prebuilt/components/MoreSettings/ActionTile.jsx +55 -0
- package/src/Prebuilt/components/MoreSettings/ChangeNameContent.jsx +96 -0
- package/src/Prebuilt/components/MoreSettings/ChangeNameModal.jsx +31 -54
- package/src/Prebuilt/components/MoreSettings/EmbedUrl.jsx +48 -73
- package/src/Prebuilt/components/MoreSettings/MoreSettings.jsx +5 -221
- package/src/Prebuilt/components/MoreSettings/MuteAllContent.jsx +61 -0
- package/src/Prebuilt/components/MoreSettings/MuteAllModal.jsx +32 -49
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopLeaveRoom.jsx +129 -0
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.jsx +219 -0
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebLeaveRoom.jsx +100 -0
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.jsx +259 -0
- package/src/Prebuilt/components/Notifications/Notifications.jsx +0 -2
- package/src/Prebuilt/components/Notifications/ReconnectNotifications.jsx +0 -4
- package/src/Prebuilt/components/PIP/PIPComponent.jsx +30 -26
- package/src/Prebuilt/components/PIP/PIPManager.js +13 -0
- package/src/Prebuilt/components/PIP/index.jsx +2 -7
- package/src/Prebuilt/components/Pagination.jsx +4 -4
- package/src/Prebuilt/components/Preview/PreviewContainer.jsx +5 -13
- package/src/Prebuilt/components/Preview/PreviewForm.jsx +9 -5
- package/src/Prebuilt/components/Preview/PreviewJoin.jsx +20 -27
- package/src/Prebuilt/components/RaiseHand.jsx +27 -0
- package/src/Prebuilt/components/ScreenShare.jsx +1 -1
- package/src/Prebuilt/components/ScreenshareDisplay.jsx +2 -2
- package/src/Prebuilt/components/ScreenshareTile.jsx +2 -2
- package/src/Prebuilt/components/Settings/DeviceSettings.jsx +2 -1
- package/src/Prebuilt/components/Settings/LayoutSettings.jsx +1 -24
- package/src/Prebuilt/components/Settings/SettingsModal.jsx +152 -17
- package/src/Prebuilt/components/ShareMenuIcon.jsx +1 -0
- package/src/Prebuilt/components/TileMenu/TileMenu.jsx +133 -0
- package/src/Prebuilt/components/TileMenu/TileMenuContent.jsx +313 -0
- package/src/Prebuilt/components/VideoList.jsx +5 -33
- package/src/Prebuilt/components/VideoTile.jsx +30 -8
- package/src/Prebuilt/components/conference.jsx +14 -1
- package/src/Prebuilt/components/init/Init.jsx +0 -27
- package/src/Prebuilt/components/init/initUtils.js +0 -23
- package/src/Prebuilt/components/pdfAnnotator/pdfFileOptions.jsx +2 -1
- package/src/Prebuilt/components/pdfAnnotator/pdfInfo.jsx +1 -1
- package/src/Prebuilt/components/pdfAnnotator/shareScreenOptions.jsx +19 -8
- package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +1 -0
- package/src/Prebuilt/images/pdf-share.png +0 -0
- package/src/Prebuilt/images/screen-share.png +0 -0
- package/src/Prebuilt/index.ts +1 -0
- package/src/Prebuilt/layouts/EmbedView.jsx +0 -1
- package/src/Prebuilt/layouts/InsetView.jsx +65 -24
- package/src/Prebuilt/layouts/PDFView.jsx +0 -1
- package/src/Prebuilt/layouts/SidePane.jsx +8 -7
- package/src/Prebuilt/layouts/mainView.jsx +22 -31
- package/src/Prebuilt/layouts/screenShareView.jsx +0 -2
- package/src/Prebuilt/plugins/VirtualBackground/VirtualBackground.jsx +25 -1
- package/src/Prebuilt/primitives/DialogContent.jsx +1 -1
- package/src/Prebuilt/provider/roomLayoutProvider/index.tsx +1 -1
- package/src/Sheet/Sheet.mdx +19 -0
- package/src/Sheet/Sheet.stories.tsx +103 -0
- package/src/Sheet/Sheet.tsx +118 -0
- package/src/Sheet/index.ts +1 -0
- package/src/Theme/ThemeProvider.tsx +10 -13
- package/src/Theme/base.config.ts +1 -1
- package/src/Theme/stitches.config.ts +1 -1
- package/src/TileMenu/StyledMenuTile.tsx +2 -2
- package/src/TileMenu/TileMenu.tsx +2 -0
- package/src/VideoTile/StyledVideoTile.tsx +5 -0
- package/src/utils/animations.ts +18 -0
- package/dist/ActiveSpeakerView-V6O4K3BV.js +0 -39
- package/dist/ActiveSpeakerView-V6O4K3BV.js.map +0 -7
- package/dist/PinnedTrackView-7YQG4QKC.js +0 -70
- package/dist/PinnedTrackView-7YQG4QKC.js.map +0 -7
- package/dist/VirtualBackground-S3XEPZ2T.js.map +0 -7
- package/dist/chunk-42SWPN2C.js.map +0 -7
- package/dist/chunk-4NEZLVVH.js +0 -811
- package/dist/chunk-4NEZLVVH.js.map +0 -7
- package/dist/chunk-4ZBEFSRC.js +0 -58
- package/dist/chunk-4ZBEFSRC.js.map +0 -7
- package/dist/chunk-ESUJK7AT.js.map +0 -7
- package/dist/chunk-R6PDR5WZ.js +0 -243
- package/dist/chunk-R6PDR5WZ.js.map +0 -7
- package/dist/conference-7QKOMJPP.js +0 -3697
- package/dist/conference-7QKOMJPP.js.map +0 -7
- package/dist/transcription-RJA4V6PC.js +0 -356
- package/dist/transcription-RJA4V6PC.js.map +0 -7
- package/src/Prebuilt/common/useSortedPeers.js +0 -28
- package/src/Prebuilt/components/BottomActionSheet/BottomActionSheet.jsx +0 -96
- package/src/Prebuilt/components/BottomActionSheet/BottomActionSheet.stories.tsx +0 -46
- package/src/Prebuilt/components/Footer/ConferencingFooter.jsx +0 -101
- package/src/Prebuilt/components/Footer/StreamingFooter.jsx +0 -71
- package/src/Prebuilt/components/Footer.jsx +0 -8
- package/src/Prebuilt/components/MoreSettings/ChangeSelfRole.jsx +0 -67
- package/src/Prebuilt/components/TileMenu.jsx +0 -268
- package/src/Prebuilt/index.d.ts +0 -20
- package/src/Prebuilt/index.js +0 -2
@@ -2,11 +2,18 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|
2
2
|
import { useMedia } from 'react-use';
|
3
3
|
import { selectLocalPeerRoleName, useHMSStore } from '@100mslive/react-sdk';
|
4
4
|
import { ChevronLeftIcon, CrossIcon } from '@100mslive/react-icons';
|
5
|
-
import {
|
5
|
+
import { HorizontalDivider } from '../../../Divider';
|
6
|
+
import { IconButton } from '../../../IconButton';
|
7
|
+
import { Box, Flex } from '../../../Layout';
|
8
|
+
import { Dialog } from '../../../Modal';
|
9
|
+
import { Sheet } from '../../../Sheet';
|
10
|
+
import { Tabs } from '../../../Tabs';
|
11
|
+
import { Text } from '../../../Text';
|
12
|
+
import { config as cssConfig } from '../../../Theme';
|
6
13
|
import { useHLSViewerRole } from '../AppData/useUISettings';
|
7
14
|
import { settingContent, settingsList } from './common.js';
|
8
15
|
|
9
|
-
const SettingsModal = ({ open, onOpenChange, children }) => {
|
16
|
+
const SettingsModal = ({ open, onOpenChange, children = <></> }) => {
|
10
17
|
const mediaQueryLg = cssConfig.media.md;
|
11
18
|
const isMobile = useMedia(mediaQueryLg);
|
12
19
|
|
@@ -43,6 +50,145 @@ const SettingsModal = ({ open, onOpenChange, children }) => {
|
|
43
50
|
}
|
44
51
|
}, [isMobile, showSetting]);
|
45
52
|
|
53
|
+
return isMobile ? (
|
54
|
+
<MobileSettingModal
|
55
|
+
open={open}
|
56
|
+
onOpenChange={onOpenChange}
|
57
|
+
selection={selection}
|
58
|
+
setSelection={setSelection}
|
59
|
+
showSetting={showSetting}
|
60
|
+
hideSettingByTabName={hideSettingByTabName}
|
61
|
+
resetSelection={resetSelection}
|
62
|
+
children={children}
|
63
|
+
/>
|
64
|
+
) : (
|
65
|
+
<DesktopSettingModal
|
66
|
+
open={open}
|
67
|
+
onOpenChange={onOpenChange}
|
68
|
+
selection={selection}
|
69
|
+
setSelection={setSelection}
|
70
|
+
showSetting={showSetting}
|
71
|
+
hideSettingByTabName={hideSettingByTabName}
|
72
|
+
resetSelection={resetSelection}
|
73
|
+
children={children}
|
74
|
+
/>
|
75
|
+
);
|
76
|
+
};
|
77
|
+
|
78
|
+
const MobileSettingModal = ({
|
79
|
+
open,
|
80
|
+
onOpenChange,
|
81
|
+
selection,
|
82
|
+
setSelection,
|
83
|
+
showSetting,
|
84
|
+
hideSettingByTabName,
|
85
|
+
resetSelection,
|
86
|
+
children = <></>,
|
87
|
+
}) => {
|
88
|
+
return (
|
89
|
+
<Sheet.Root open={open} onOpenChange={onOpenChange}>
|
90
|
+
<Sheet.Trigger asChild>{children}</Sheet.Trigger>
|
91
|
+
<Sheet.Content
|
92
|
+
css={{
|
93
|
+
bg: '$surface_dim',
|
94
|
+
overflowY: 'auto',
|
95
|
+
}}
|
96
|
+
>
|
97
|
+
<Sheet.Title css={{ py: '$10', px: '$8', alignItems: 'center' }}>
|
98
|
+
<Flex direction="row" justify="between" css={{ w: '100%' }}>
|
99
|
+
{!selection ? (
|
100
|
+
<Text variant="h6" css={{ display: 'flex' }}>
|
101
|
+
Settings
|
102
|
+
</Text>
|
103
|
+
) : (
|
104
|
+
<Text variant="h6" css={{ display: 'flex' }}>
|
105
|
+
<Box as="span" css={{ r: '$round', mr: '$2' }} onClick={resetSelection}>
|
106
|
+
<ChevronLeftIcon />
|
107
|
+
</Box>
|
108
|
+
{selection?.charAt(0).toUpperCase() + selection.slice(1)}
|
109
|
+
</Text>
|
110
|
+
)}
|
111
|
+
<Sheet.Close>
|
112
|
+
<IconButton as="div" data-testid="dialog_cross_icon">
|
113
|
+
<CrossIcon />
|
114
|
+
</IconButton>
|
115
|
+
</Sheet.Close>
|
116
|
+
</Flex>
|
117
|
+
</Sheet.Title>
|
118
|
+
<HorizontalDivider />
|
119
|
+
{!selection ? (
|
120
|
+
<Flex
|
121
|
+
direction="column"
|
122
|
+
css={{
|
123
|
+
px: '$8',
|
124
|
+
pb: '$8',
|
125
|
+
overflowY: 'auto',
|
126
|
+
}}
|
127
|
+
>
|
128
|
+
{settingsList
|
129
|
+
.filter(({ tabName }) => showSetting[tabName])
|
130
|
+
.map(({ icon: Icon, tabName, title }) => {
|
131
|
+
return (
|
132
|
+
<Box
|
133
|
+
key={tabName}
|
134
|
+
value={tabName}
|
135
|
+
onClick={() => {
|
136
|
+
setSelection(tabName);
|
137
|
+
}}
|
138
|
+
as="div"
|
139
|
+
css={{
|
140
|
+
all: 'unset',
|
141
|
+
fontFamily: '$sans',
|
142
|
+
py: '$10',
|
143
|
+
display: 'flex',
|
144
|
+
alignItems: 'center',
|
145
|
+
fontSize: '$sm',
|
146
|
+
lineHeight: '$sm',
|
147
|
+
color: '$on_surface_high',
|
148
|
+
userSelect: 'none',
|
149
|
+
gap: '$8',
|
150
|
+
cursor: 'pointer',
|
151
|
+
'&:hover': {
|
152
|
+
bg: '$surface_brighter',
|
153
|
+
r: '$1',
|
154
|
+
gap: '$8',
|
155
|
+
border: 'none',
|
156
|
+
},
|
157
|
+
borderBottom: '1px solid $border_default',
|
158
|
+
}}
|
159
|
+
>
|
160
|
+
<Icon />
|
161
|
+
{title}
|
162
|
+
</Box>
|
163
|
+
);
|
164
|
+
})}
|
165
|
+
</Flex>
|
166
|
+
) : (
|
167
|
+
<Box
|
168
|
+
direction="column"
|
169
|
+
css={{ overflowY: 'scroll', px: '$8', py: '$10', maxHeight: '70vh', overflowX: 'hidden' }}
|
170
|
+
>
|
171
|
+
{settingsList
|
172
|
+
.filter(({ tabName }) => showSetting[tabName] && selection === tabName)
|
173
|
+
.map(({ content: Content, title, tabName }) => {
|
174
|
+
return <Content key={title} setHide={hideSettingByTabName(tabName)} />;
|
175
|
+
})}
|
176
|
+
</Box>
|
177
|
+
)}
|
178
|
+
</Sheet.Content>
|
179
|
+
</Sheet.Root>
|
180
|
+
);
|
181
|
+
};
|
182
|
+
const DesktopSettingModal = ({
|
183
|
+
open,
|
184
|
+
onOpenChange,
|
185
|
+
selection,
|
186
|
+
setSelection,
|
187
|
+
showSetting,
|
188
|
+
hideSettingByTabName,
|
189
|
+
resetSelection,
|
190
|
+
children = <></>,
|
191
|
+
}) => {
|
46
192
|
return (
|
47
193
|
<Dialog.Root open={open} onOpenChange={onOpenChange}>
|
48
194
|
<Dialog.Trigger asChild>{children}</Dialog.Trigger>
|
@@ -58,13 +204,13 @@ const SettingsModal = ({ open, onOpenChange, children }) => {
|
|
58
204
|
>
|
59
205
|
<Tabs.Root
|
60
206
|
value={selection}
|
61
|
-
activationMode=
|
207
|
+
activationMode="automatic"
|
62
208
|
onValueChange={setSelection}
|
63
209
|
css={{ size: '100%', position: 'relative' }}
|
64
210
|
>
|
65
211
|
<Tabs.List
|
66
212
|
css={{
|
67
|
-
w:
|
213
|
+
w: '18.625rem',
|
68
214
|
flexDirection: 'column',
|
69
215
|
bg: '$background_default',
|
70
216
|
p: '$14 $10',
|
@@ -73,7 +219,7 @@ const SettingsModal = ({ open, onOpenChange, children }) => {
|
|
73
219
|
}}
|
74
220
|
>
|
75
221
|
<Text variant="h5">Settings </Text>
|
76
|
-
<Flex direction="column" css={{ mx:
|
222
|
+
<Flex direction="column" css={{ mx: 0, overflowY: 'auto', pt: '$10' }}>
|
77
223
|
{settingsList
|
78
224
|
.filter(({ tabName }) => showSetting[tabName])
|
79
225
|
.map(({ icon: Icon, tabName, title }) => {
|
@@ -93,16 +239,6 @@ const SettingsModal = ({ open, onOpenChange, children }) => {
|
|
93
239
|
flex: '1 1 0',
|
94
240
|
minWidth: 0,
|
95
241
|
mr: '$4',
|
96
|
-
...(isMobile
|
97
|
-
? {
|
98
|
-
position: 'absolute',
|
99
|
-
left: 0,
|
100
|
-
right: 0,
|
101
|
-
bg: '$surface_default',
|
102
|
-
width: '100%',
|
103
|
-
height: '100%',
|
104
|
-
}
|
105
|
-
: {}),
|
106
242
|
}}
|
107
243
|
>
|
108
244
|
{settingsList
|
@@ -110,7 +246,7 @@ const SettingsModal = ({ open, onOpenChange, children }) => {
|
|
110
246
|
.map(({ content: Content, title, tabName }) => {
|
111
247
|
return (
|
112
248
|
<Tabs.Content key={tabName} value={tabName} className={settingContent()}>
|
113
|
-
<SettingsContentHeader onBack={resetSelection} isMobile={
|
249
|
+
<SettingsContentHeader onBack={resetSelection} isMobile={false}>
|
114
250
|
{title}
|
115
251
|
</SettingsContentHeader>
|
116
252
|
<Content setHide={hideSettingByTabName(tabName)} />
|
@@ -130,7 +266,6 @@ const SettingsModal = ({ open, onOpenChange, children }) => {
|
|
130
266
|
</Dialog.Root>
|
131
267
|
);
|
132
268
|
};
|
133
|
-
|
134
269
|
const SettingsContentHeader = ({ children, isMobile, onBack }) => {
|
135
270
|
return (
|
136
271
|
<Text variant="h6" css={{ mb: '$12', display: 'flex', alignItems: 'center' }}>
|
@@ -0,0 +1,133 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { useMedia } from 'react-use';
|
3
|
+
import {
|
4
|
+
selectLocalPeerID,
|
5
|
+
selectPeerByID,
|
6
|
+
selectPermissions,
|
7
|
+
selectTemplateAppData,
|
8
|
+
selectTrackByID,
|
9
|
+
selectVideoTrackByPeerID,
|
10
|
+
useHMSStore,
|
11
|
+
useRemoteAVToggle,
|
12
|
+
} from '@100mslive/react-sdk';
|
13
|
+
import { CrossIcon, VerticalMenuIcon } from '@100mslive/react-icons';
|
14
|
+
import { Box, Flex } from '../../../Layout';
|
15
|
+
import { Sheet } from '../../../Sheet';
|
16
|
+
import { Text } from '../../../Text';
|
17
|
+
import { config as cssConfig, useTheme } from '../../../Theme';
|
18
|
+
import { StyledMenuTile } from '../../../TileMenu';
|
19
|
+
import { ChangeNameModal } from '../MoreSettings/ChangeNameModal';
|
20
|
+
import { TileMenuContent } from './TileMenuContent';
|
21
|
+
import { useDropdownList } from '../hooks/useDropdownList';
|
22
|
+
import { useIsFeatureEnabled } from '../hooks/useFeatures';
|
23
|
+
import { FEATURE_LIST } from '../../common/constants';
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Taking peerID as peer won't necesarilly have tracks
|
27
|
+
*/
|
28
|
+
const TileMenu = ({ audioTrackID, videoTrackID, peerID, isScreenshare = false, canMinimise }) => {
|
29
|
+
const [open, setOpen] = useState(false);
|
30
|
+
const { theme } = useTheme();
|
31
|
+
|
32
|
+
const localPeerID = useHMSStore(selectLocalPeerID);
|
33
|
+
const isLocal = localPeerID === peerID;
|
34
|
+
const { removeOthers, changeRole } = useHMSStore(selectPermissions);
|
35
|
+
const { setVolume, toggleAudio, toggleVideo } = useRemoteAVToggle(audioTrackID, videoTrackID);
|
36
|
+
const showSpotlight = changeRole;
|
37
|
+
|
38
|
+
const isPrimaryVideoTrack = useHMSStore(selectVideoTrackByPeerID(peerID))?.id === videoTrackID;
|
39
|
+
const uiMode = useHMSStore(selectTemplateAppData).uiMode;
|
40
|
+
const isInset = uiMode === 'inset';
|
41
|
+
|
42
|
+
const isPinEnabled = useIsFeatureEnabled(FEATURE_LIST.PIN_TILE);
|
43
|
+
const showPinAction = isPinEnabled && (audioTrackID || (videoTrackID && isPrimaryVideoTrack)) && !isInset;
|
44
|
+
|
45
|
+
const track = useHMSStore(selectTrackByID(videoTrackID));
|
46
|
+
const hideSimulcastLayers = !track?.layerDefinitions?.length || track.degraded || !track.enabled;
|
47
|
+
const isMobile = useMedia(cssConfig.media.md);
|
48
|
+
const peer = useHMSStore(selectPeerByID(peerID));
|
49
|
+
const [showNameChangeModal, setShowNameChangeModal] = useState(false);
|
50
|
+
useDropdownList({ open, name: 'TileMenu' });
|
51
|
+
|
52
|
+
if (!(removeOthers || toggleAudio || toggleVideo || setVolume || showPinAction) && hideSimulcastLayers) {
|
53
|
+
return null;
|
54
|
+
}
|
55
|
+
|
56
|
+
if (isInset && isLocal) {
|
57
|
+
return null;
|
58
|
+
}
|
59
|
+
const openNameChangeModal = () => setShowNameChangeModal(true);
|
60
|
+
|
61
|
+
const props = {
|
62
|
+
isLocal,
|
63
|
+
isScreenshare,
|
64
|
+
audioTrackID,
|
65
|
+
videoTrackID,
|
66
|
+
peerID,
|
67
|
+
isPrimaryVideoTrack,
|
68
|
+
showSpotlight,
|
69
|
+
showPinAction,
|
70
|
+
canMinimise,
|
71
|
+
openNameChangeModal,
|
72
|
+
};
|
73
|
+
|
74
|
+
return (
|
75
|
+
<>
|
76
|
+
<StyledMenuTile.Root open={open} onOpenChange={setOpen}>
|
77
|
+
<StyledMenuTile.Trigger
|
78
|
+
data-testid="participant_menu_btn"
|
79
|
+
css={{ bg: `${theme.colors.background_dim.value}A3` }}
|
80
|
+
onClick={e => e.stopPropagation()}
|
81
|
+
className={isMobile ? '__cancel-drag-event' : ''}
|
82
|
+
>
|
83
|
+
<VerticalMenuIcon width={20} height={20} />
|
84
|
+
</StyledMenuTile.Trigger>
|
85
|
+
|
86
|
+
{isMobile ? (
|
87
|
+
<Sheet.Root open={open} onOpenChange={setOpen}>
|
88
|
+
<Sheet.Content css={{ bg: '$surface_dim', pt: '$8' }}>
|
89
|
+
<Flex
|
90
|
+
css={{
|
91
|
+
color: '$on_surface_high',
|
92
|
+
display: 'flex',
|
93
|
+
w: '100%',
|
94
|
+
justifyContent: 'space-between',
|
95
|
+
alignItems: 'center',
|
96
|
+
px: '$10',
|
97
|
+
pb: '$8',
|
98
|
+
borderBottom: '1px solid $border_default',
|
99
|
+
}}
|
100
|
+
>
|
101
|
+
<Box>
|
102
|
+
<Text css={{ color: '$on_surface_high', fontWeight: '$semiBold' }}>
|
103
|
+
{peer.name}
|
104
|
+
{isLocal ? ` (You)` : null}
|
105
|
+
</Text>
|
106
|
+
{peer?.roleName ? (
|
107
|
+
<Text variant="xs" css={{ color: '$on_surface_low', mt: '$2' }}>
|
108
|
+
{peer.roleName}
|
109
|
+
</Text>
|
110
|
+
) : null}
|
111
|
+
</Box>
|
112
|
+
|
113
|
+
<Sheet.Close css={{ color: 'inherit' }}>
|
114
|
+
<CrossIcon />
|
115
|
+
</Sheet.Close>
|
116
|
+
</Flex>
|
117
|
+
<Box css={{ px: '$8', pb: '$10' }}>
|
118
|
+
<TileMenuContent {...props} closeSheetOnClick={() => setOpen(false)} />
|
119
|
+
</Box>
|
120
|
+
</Sheet.Content>
|
121
|
+
</Sheet.Root>
|
122
|
+
) : (
|
123
|
+
<StyledMenuTile.Content side="top" align="end">
|
124
|
+
<TileMenuContent {...props} />
|
125
|
+
</StyledMenuTile.Content>
|
126
|
+
)}
|
127
|
+
</StyledMenuTile.Root>
|
128
|
+
{showNameChangeModal && <ChangeNameModal onOpenChange={setShowNameChangeModal} />}
|
129
|
+
</>
|
130
|
+
);
|
131
|
+
};
|
132
|
+
|
133
|
+
export default TileMenu;
|
@@ -0,0 +1,313 @@
|
|
1
|
+
import React, { Fragment } from 'react';
|
2
|
+
import {
|
3
|
+
selectPermissions,
|
4
|
+
selectSessionStore,
|
5
|
+
selectTrackByID,
|
6
|
+
useCustomEvent,
|
7
|
+
useHMSActions,
|
8
|
+
useHMSStore,
|
9
|
+
useRemoteAVToggle,
|
10
|
+
} from '@100mslive/react-sdk';
|
11
|
+
import {
|
12
|
+
MicOffIcon,
|
13
|
+
MicOnIcon,
|
14
|
+
PencilIcon,
|
15
|
+
PinIcon,
|
16
|
+
RemoveUserIcon,
|
17
|
+
ShareScreenIcon,
|
18
|
+
ShrinkIcon,
|
19
|
+
SpeakerIcon,
|
20
|
+
StarIcon,
|
21
|
+
VideoOffIcon,
|
22
|
+
VideoOnIcon,
|
23
|
+
} from '@100mslive/react-icons';
|
24
|
+
import { Box, Flex } from '../../../Layout';
|
25
|
+
import { Slider } from '../../../Slider';
|
26
|
+
import { Text } from '../../../Text';
|
27
|
+
import { StyledMenuTile } from '../../../TileMenu';
|
28
|
+
import { ToastManager } from '../Toast/ToastManager';
|
29
|
+
import { useSetAppDataByKey } from '../AppData/useUISettings';
|
30
|
+
import { useDropdownSelection } from '../hooks/useDropdownSelection';
|
31
|
+
import { useIsFeatureEnabled } from '../hooks/useFeatures';
|
32
|
+
import { APP_DATA, FEATURE_LIST, REMOTE_STOP_SCREENSHARE_TYPE, SESSION_STORE_KEY } from '../../common/constants';
|
33
|
+
|
34
|
+
const isSameTile = ({ trackId, videoTrackID, audioTrackID }) =>
|
35
|
+
trackId && ((videoTrackID && videoTrackID === trackId) || (audioTrackID && audioTrackID === trackId));
|
36
|
+
|
37
|
+
const spacingCSS = { '@md': { my: '$8', fontWeight: '$semiBold', fontSize: 'sm' } };
|
38
|
+
|
39
|
+
const SpotlightActions = ({
|
40
|
+
peerId,
|
41
|
+
onSpotLightClick = () => {
|
42
|
+
return;
|
43
|
+
},
|
44
|
+
}) => {
|
45
|
+
const hmsActions = useHMSActions();
|
46
|
+
const spotlightPeerId = useHMSStore(selectSessionStore(SESSION_STORE_KEY.SPOTLIGHT));
|
47
|
+
const isTileSpotlighted = spotlightPeerId === peerId;
|
48
|
+
|
49
|
+
const setSpotlightPeerId = peer =>
|
50
|
+
hmsActions.sessionStore
|
51
|
+
.set(SESSION_STORE_KEY.SPOTLIGHT, peer)
|
52
|
+
.catch(err => ToastManager.addToast({ title: err.description }));
|
53
|
+
|
54
|
+
return (
|
55
|
+
<StyledMenuTile.ItemButton
|
56
|
+
css={spacingCSS}
|
57
|
+
onClick={() => {
|
58
|
+
if (isTileSpotlighted) {
|
59
|
+
setSpotlightPeerId();
|
60
|
+
} else {
|
61
|
+
setSpotlightPeerId(peerId);
|
62
|
+
}
|
63
|
+
onSpotLightClick();
|
64
|
+
}}
|
65
|
+
>
|
66
|
+
<StarIcon />
|
67
|
+
<span>{isTileSpotlighted ? 'Remove from Spotlight' : 'Spotlight Tile for everyone'}</span>
|
68
|
+
</StyledMenuTile.ItemButton>
|
69
|
+
);
|
70
|
+
};
|
71
|
+
|
72
|
+
const PinActions = ({ audioTrackID, videoTrackID }) => {
|
73
|
+
const [pinnedTrackId, setPinnedTrackId] = useSetAppDataByKey(APP_DATA.pinnedTrackId);
|
74
|
+
|
75
|
+
const isTilePinned = isSameTile({
|
76
|
+
trackId: pinnedTrackId,
|
77
|
+
videoTrackID,
|
78
|
+
audioTrackID,
|
79
|
+
});
|
80
|
+
|
81
|
+
return (
|
82
|
+
<>
|
83
|
+
<StyledMenuTile.ItemButton
|
84
|
+
css={spacingCSS}
|
85
|
+
onClick={() => (isTilePinned ? setPinnedTrackId() : setPinnedTrackId(videoTrackID || audioTrackID))}
|
86
|
+
>
|
87
|
+
<PinIcon />
|
88
|
+
<span>{isTilePinned ? 'Unpin' : 'Pin'} Tile for myself</span>
|
89
|
+
</StyledMenuTile.ItemButton>
|
90
|
+
</>
|
91
|
+
);
|
92
|
+
};
|
93
|
+
|
94
|
+
const MinimiseInset = () => {
|
95
|
+
const [minimised, setMinimised] = useSetAppDataByKey(APP_DATA.minimiseInset);
|
96
|
+
|
97
|
+
return (
|
98
|
+
<>
|
99
|
+
<StyledMenuTile.ItemButton css={spacingCSS} onClick={() => setMinimised(!minimised)}>
|
100
|
+
<ShrinkIcon />
|
101
|
+
<span>{minimised ? 'Show' : 'Minimise'} your video</span>
|
102
|
+
</StyledMenuTile.ItemButton>
|
103
|
+
</>
|
104
|
+
);
|
105
|
+
};
|
106
|
+
|
107
|
+
const SimulcastLayers = ({ trackId }) => {
|
108
|
+
const track = useHMSStore(selectTrackByID(trackId));
|
109
|
+
const actions = useHMSActions();
|
110
|
+
const bg = useDropdownSelection();
|
111
|
+
if (!track?.layerDefinitions?.length || track.degraded || !track.enabled) {
|
112
|
+
return null;
|
113
|
+
}
|
114
|
+
const currentLayer = track.layerDefinitions.find(layer => layer.layer === track.layer);
|
115
|
+
return (
|
116
|
+
<Fragment>
|
117
|
+
<StyledMenuTile.ItemButton css={{ color: '$on_surface_medium', cursor: 'default' }}>
|
118
|
+
Select maximum resolution
|
119
|
+
</StyledMenuTile.ItemButton>
|
120
|
+
{track.layerDefinitions.map(layer => {
|
121
|
+
return (
|
122
|
+
<StyledMenuTile.ItemButton
|
123
|
+
key={layer.layer}
|
124
|
+
onClick={async () => {
|
125
|
+
await actions.setPreferredLayer(trackId, layer.layer);
|
126
|
+
}}
|
127
|
+
css={{
|
128
|
+
justifyContent: 'space-between',
|
129
|
+
bg: track.preferredLayer === layer.layer ? bg : undefined,
|
130
|
+
'&:hover': {
|
131
|
+
bg: track.preferredLayer === layer.layer ? bg : undefined,
|
132
|
+
},
|
133
|
+
}}
|
134
|
+
>
|
135
|
+
<Text
|
136
|
+
as="span"
|
137
|
+
css={{
|
138
|
+
textTransform: 'capitalize',
|
139
|
+
mr: '$2',
|
140
|
+
fontWeight: track.preferredLayer === layer.layer ? '$semiBold' : '$regular',
|
141
|
+
}}
|
142
|
+
>
|
143
|
+
{layer.layer}
|
144
|
+
</Text>
|
145
|
+
<Text as="span" variant="xs" css={{ color: '$on_surface_medium' }}>
|
146
|
+
{layer.resolution.width}x{layer.resolution.height}
|
147
|
+
</Text>
|
148
|
+
</StyledMenuTile.ItemButton>
|
149
|
+
);
|
150
|
+
})}
|
151
|
+
<StyledMenuTile.ItemButton>
|
152
|
+
<Text as="span" variant="xs" css={{ color: '$on_surface_medium' }}>
|
153
|
+
Currently streaming:
|
154
|
+
<Text
|
155
|
+
as="span"
|
156
|
+
variant="xs"
|
157
|
+
css={{
|
158
|
+
fontWeight: '$semiBold',
|
159
|
+
textTransform: 'capitalize',
|
160
|
+
color: '$on_surface_medium',
|
161
|
+
ml: '$2',
|
162
|
+
}}
|
163
|
+
>
|
164
|
+
{currentLayer ? (
|
165
|
+
<>
|
166
|
+
{track.layer} ({currentLayer.resolution.width}x{currentLayer.resolution.height})
|
167
|
+
</>
|
168
|
+
) : (
|
169
|
+
'-'
|
170
|
+
)}
|
171
|
+
</Text>
|
172
|
+
</Text>
|
173
|
+
</StyledMenuTile.ItemButton>
|
174
|
+
</Fragment>
|
175
|
+
);
|
176
|
+
};
|
177
|
+
|
178
|
+
export const TileMenuContent = props => {
|
179
|
+
const actions = useHMSActions();
|
180
|
+
const { removeOthers } = useHMSStore(selectPermissions);
|
181
|
+
const {
|
182
|
+
videoTrackID,
|
183
|
+
audioTrackID,
|
184
|
+
isLocal,
|
185
|
+
isScreenshare,
|
186
|
+
showSpotlight,
|
187
|
+
showPinAction,
|
188
|
+
peerID,
|
189
|
+
canMinimise,
|
190
|
+
closeSheetOnClick = () => {
|
191
|
+
return;
|
192
|
+
},
|
193
|
+
openNameChangeModal = () => {
|
194
|
+
return;
|
195
|
+
},
|
196
|
+
} = props;
|
197
|
+
|
198
|
+
const { isAudioEnabled, isVideoEnabled, setVolume, toggleAudio, toggleVideo, volume } = useRemoteAVToggle(
|
199
|
+
audioTrackID,
|
200
|
+
videoTrackID,
|
201
|
+
);
|
202
|
+
|
203
|
+
const { sendEvent } = useCustomEvent({
|
204
|
+
type: REMOTE_STOP_SCREENSHARE_TYPE,
|
205
|
+
});
|
206
|
+
|
207
|
+
const isChangeNameEnabled = useIsFeatureEnabled(FEATURE_LIST.CHANGE_NAME);
|
208
|
+
|
209
|
+
return isLocal ? (
|
210
|
+
(showPinAction || canMinimise) && (
|
211
|
+
<>
|
212
|
+
{showPinAction && <PinActions audioTrackID={audioTrackID} videoTrackID={videoTrackID} />}
|
213
|
+
{showSpotlight && <SpotlightActions peerId={peerID} onSpotLightClick={() => closeSheetOnClick()} />}
|
214
|
+
{canMinimise && <MinimiseInset />}
|
215
|
+
{isChangeNameEnabled ? (
|
216
|
+
<StyledMenuTile.ItemButton
|
217
|
+
onClick={() => {
|
218
|
+
openNameChangeModal();
|
219
|
+
closeSheetOnClick();
|
220
|
+
}}
|
221
|
+
>
|
222
|
+
<PencilIcon />
|
223
|
+
<Text variant="sm" css={{ fontWeight: '$semiBold' }}>
|
224
|
+
Change Name
|
225
|
+
</Text>
|
226
|
+
</StyledMenuTile.ItemButton>
|
227
|
+
) : null}
|
228
|
+
</>
|
229
|
+
)
|
230
|
+
) : (
|
231
|
+
<>
|
232
|
+
{toggleVideo ? (
|
233
|
+
<StyledMenuTile.ItemButton
|
234
|
+
css={spacingCSS}
|
235
|
+
onClick={() => {
|
236
|
+
toggleVideo();
|
237
|
+
closeSheetOnClick();
|
238
|
+
}}
|
239
|
+
data-testid={isVideoEnabled ? 'mute_video_participant_btn' : 'unmute_video_participant_btn'}
|
240
|
+
>
|
241
|
+
{isVideoEnabled ? <VideoOnIcon /> : <VideoOffIcon />}
|
242
|
+
<span>{isVideoEnabled ? 'Mute' : 'Request Unmute'}</span>
|
243
|
+
</StyledMenuTile.ItemButton>
|
244
|
+
) : null}
|
245
|
+
|
246
|
+
{toggleAudio ? (
|
247
|
+
<StyledMenuTile.ItemButton
|
248
|
+
css={spacingCSS}
|
249
|
+
onClick={() => {
|
250
|
+
toggleAudio();
|
251
|
+
closeSheetOnClick();
|
252
|
+
}}
|
253
|
+
data-testid={isVideoEnabled ? 'mute_audio_participant_btn' : 'unmute_audio_participant_btn'}
|
254
|
+
>
|
255
|
+
{isAudioEnabled ? <MicOnIcon /> : <MicOffIcon />}
|
256
|
+
<span>{isAudioEnabled ? 'Mute' : 'Request Unmute'}</span>
|
257
|
+
</StyledMenuTile.ItemButton>
|
258
|
+
) : null}
|
259
|
+
|
260
|
+
{audioTrackID ? (
|
261
|
+
<StyledMenuTile.VolumeItem data-testid="participant_volume_slider" css={{ ...spacingCSS, mb: '$0' }}>
|
262
|
+
<Flex align="center" gap={1}>
|
263
|
+
<SpeakerIcon />
|
264
|
+
<Box as="span" css={{ ml: '$4' }}>
|
265
|
+
Volume ({volume})
|
266
|
+
</Box>
|
267
|
+
</Flex>
|
268
|
+
<Slider css={{ my: '0.5rem' }} step={5} value={[volume]} onValueChange={e => setVolume(e[0])} />
|
269
|
+
</StyledMenuTile.VolumeItem>
|
270
|
+
) : null}
|
271
|
+
|
272
|
+
{showPinAction && (
|
273
|
+
<>
|
274
|
+
<PinActions audioTrackID={audioTrackID} videoTrackID={videoTrackID} />
|
275
|
+
{showSpotlight && <SpotlightActions peerId={peerID} onSpotLightClick={() => closeSheetOnClick()} />}
|
276
|
+
</>
|
277
|
+
)}
|
278
|
+
|
279
|
+
<SimulcastLayers trackId={videoTrackID} />
|
280
|
+
|
281
|
+
{removeOthers ? (
|
282
|
+
<StyledMenuTile.RemoveItem
|
283
|
+
css={{ ...spacingCSS, borderTop: 'none' }}
|
284
|
+
onClick={async () => {
|
285
|
+
try {
|
286
|
+
await actions.removePeer(peerID, '');
|
287
|
+
} catch (error) {
|
288
|
+
// TODO: Toast here
|
289
|
+
}
|
290
|
+
closeSheetOnClick();
|
291
|
+
}}
|
292
|
+
data-testid="remove_participant_btn"
|
293
|
+
>
|
294
|
+
<RemoveUserIcon />
|
295
|
+
<span>Remove Participant</span>
|
296
|
+
</StyledMenuTile.RemoveItem>
|
297
|
+
) : null}
|
298
|
+
|
299
|
+
{removeOthers && isScreenshare ? (
|
300
|
+
<StyledMenuTile.RemoveItem
|
301
|
+
onClick={() => {
|
302
|
+
sendEvent({});
|
303
|
+
closeSheetOnClick();
|
304
|
+
}}
|
305
|
+
css={spacingCSS}
|
306
|
+
>
|
307
|
+
<ShareScreenIcon />
|
308
|
+
<span>Stop Screenshare</span>
|
309
|
+
</StyledMenuTile.RemoveItem>
|
310
|
+
) : null}
|
311
|
+
</>
|
312
|
+
);
|
313
|
+
};
|