@100mslive/roomkit-react 0.1.6-alpha.0 → 0.1.6-alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/{HLSView-PY2FKWX3.js → HLSView-HNVYG5VE.js} +208 -118
- package/dist/HLSView-HNVYG5VE.js.map +7 -0
- package/dist/Prebuilt/AppContext.d.ts +1 -1
- package/dist/Prebuilt/components/Chat/ChatFooter.d.ts +7 -0
- package/dist/Prebuilt/components/Connection/ConnectionIndicator.d.ts +6 -0
- package/dist/Prebuilt/components/Connection/TileConnection.d.ts +10 -0
- package/dist/Prebuilt/components/Footer/ChatToggle.d.ts +4 -0
- package/dist/Prebuilt/components/Footer/RoleAccordion.d.ts +14 -0
- package/dist/Prebuilt/components/Footer/RoleOptions.d.ts +6 -0
- package/dist/Prebuilt/components/Header/StreamActions.d.ts +11 -0
- package/dist/Prebuilt/components/Leave/DesktopLeaveRoom.d.ts +4 -3
- package/dist/Prebuilt/components/Leave/EndSessionContent.d.ts +4 -3
- package/dist/Prebuilt/components/Leave/LeaveCard.d.ts +1 -2
- package/dist/Prebuilt/components/Leave/LeaveSessionContent.d.ts +3 -1
- package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +4 -3
- package/dist/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.d.ts +6 -0
- package/dist/Prebuilt/components/Preview/PreviewContainer.d.ts +3 -0
- package/dist/Prebuilt/components/Preview/PreviewJoin.d.ts +16 -0
- package/dist/Prebuilt/components/RoleChangeRequestModal.d.ts +2 -0
- package/dist/Prebuilt/components/SecondaryTiles.d.ts +1 -1
- package/dist/Prebuilt/components/VideoLayouts/EqualProminence.d.ts +1 -1
- package/dist/Prebuilt/components/VideoLayouts/Grid.d.ts +1 -0
- package/dist/Prebuilt/components/VideoLayouts/GridLayout.d.ts +5 -3
- package/dist/Prebuilt/components/VideoLayouts/ProminenceLayout.d.ts +6 -3
- package/dist/Prebuilt/components/VideoLayouts/RoleProminence.d.ts +1 -1
- package/dist/Prebuilt/components/VideoLayouts/ScreenshareLayout.d.ts +1 -1
- package/dist/Prebuilt/components/VideoLayouts/interface.d.ts +1 -0
- package/dist/Prebuilt/components/hooks/useAutoStartStreaming.d.ts +1 -0
- package/dist/Prebuilt/components/hooks/useRedirectToLeave.d.ts +3 -0
- package/dist/Prebuilt/components/hooks/useTileLayout.d.ts +2 -1
- package/dist/Prebuilt/components/hooks/useVideoTileLayout.d.ts +2 -0
- package/dist/Prebuilt/layouts/SidePane.d.ts +4 -1
- package/dist/Prebuilt/layouts/VideoStreamingSection.d.ts +2 -1
- package/dist/{VirtualBackground-AYDHYLIZ.js → VirtualBackground-UM2FOUHQ.js} +3 -3
- package/dist/{chunk-E2M2ZSOL.js → chunk-364HP22I.js} +2 -2
- package/dist/{chunk-RXTHJUMZ.js → chunk-LYSAET4G.js} +946 -390
- package/dist/chunk-LYSAET4G.js.map +7 -0
- package/dist/{chunk-GQD2AGWW.js → chunk-POE7H4IE.js} +12 -2
- package/dist/{chunk-GQD2AGWW.js.map → chunk-POE7H4IE.js.map} +2 -2
- package/dist/{conference-V2XZGTKU.js → conference-UWLJHMB2.js} +1116 -1316
- package/dist/conference-UWLJHMB2.js.map +7 -0
- package/dist/index.cjs.js +6080 -5631
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.js +2 -2
- package/dist/meta.cjs.json +741 -493
- package/dist/meta.esbuild.json +782 -529
- package/package.json +8 -7
- package/src/Prebuilt/App.tsx +10 -21
- package/src/Prebuilt/AppContext.tsx +1 -1
- package/src/Prebuilt/IconButton.jsx +10 -0
- package/src/Prebuilt/common/PeersSorter.ts +1 -1
- package/src/Prebuilt/common/constants.js +1 -2
- package/src/Prebuilt/common/utils.js +1 -1
- package/src/Prebuilt/components/AppData/AppData.jsx +8 -2
- package/src/Prebuilt/components/AppData/useUISettings.js +6 -6
- package/src/Prebuilt/components/AudioVideoToggle.jsx +8 -6
- package/src/Prebuilt/components/Chat/Chat.jsx +23 -6
- package/src/Prebuilt/components/Chat/ChatBody.jsx +20 -21
- package/src/Prebuilt/components/Chat/{ChatFooter.jsx → ChatFooter.tsx} +38 -13
- package/src/Prebuilt/components/Chat/ChatParticipantHeader.jsx +38 -27
- package/src/Prebuilt/components/Chat/useEmojiPickerStyles.js +5 -4
- package/src/Prebuilt/components/Connection/{ConnectionIndicator.jsx → ConnectionIndicator.tsx} +12 -4
- package/src/Prebuilt/components/Connection/{TileConnection.jsx → TileConnection.tsx} +20 -6
- package/src/Prebuilt/components/EmojiReaction.jsx +2 -6
- package/src/Prebuilt/components/Footer/{ChatToggle.jsx → ChatToggle.tsx} +13 -3
- package/src/Prebuilt/components/Footer/Footer.tsx +15 -6
- package/src/Prebuilt/components/Footer/ParticipantList.jsx +15 -47
- package/src/Prebuilt/components/Footer/{RoleAccordion.jsx → RoleAccordion.tsx} +33 -17
- package/src/Prebuilt/components/Footer/RoleOptions.tsx +155 -0
- package/src/Prebuilt/components/FullPageProgress.jsx +3 -3
- package/src/Prebuilt/components/HMSVideo/Controls.jsx +1 -0
- package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx +39 -17
- package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +2 -2
- package/src/Prebuilt/components/HMSVideo/VideoProgress.jsx +5 -6
- package/src/Prebuilt/components/HMSVideo/VolumeControl.jsx +1 -1
- package/src/Prebuilt/components/Header/{StreamActions.jsx → StreamActions.tsx} +23 -9
- package/src/Prebuilt/components/Header/common.jsx +5 -2
- package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.jsx +6 -1
- package/src/Prebuilt/components/InsetTile.tsx +14 -8
- package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +21 -11
- package/src/Prebuilt/components/Leave/EndSessionContent.tsx +2 -5
- package/src/Prebuilt/components/Leave/LeaveCard.tsx +1 -3
- package/src/Prebuilt/components/Leave/LeaveRoom.tsx +28 -25
- package/src/Prebuilt/components/Leave/LeaveSessionContent.tsx +8 -2
- package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +8 -8
- package/src/Prebuilt/components/MoreSettings/ChangeNameContent.jsx +4 -0
- package/src/Prebuilt/components/MoreSettings/MoreSettings.tsx +1 -1
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +9 -23
- package/src/Prebuilt/components/MoreSettings/SplitComponents/{MwebOptions.jsx → MwebOptions.tsx} +88 -27
- package/src/Prebuilt/components/Notifications/Notifications.jsx +30 -21
- package/src/Prebuilt/components/Notifications/ReconnectNotifications.jsx +5 -11
- package/src/Prebuilt/components/Pagination.tsx +14 -12
- package/src/Prebuilt/components/Preview/{PreviewContainer.jsx → PreviewContainer.tsx} +11 -2
- package/src/Prebuilt/components/Preview/PreviewForm.tsx +6 -8
- package/src/Prebuilt/components/Preview/{PreviewJoin.jsx → PreviewJoin.tsx} +43 -19
- package/src/Prebuilt/components/{RoleChangeRequestModal.jsx → RoleChangeRequestModal.tsx} +32 -15
- package/src/Prebuilt/components/ScreenshareTile.jsx +6 -7
- package/src/Prebuilt/components/SecondaryTiles.tsx +12 -10
- package/src/Prebuilt/components/TileMenu/TileMenu.jsx +1 -1
- package/src/Prebuilt/components/TileMenu/TileMenuContent.jsx +14 -10
- package/src/Prebuilt/components/Toast/ToastConfig.jsx +5 -4
- package/src/Prebuilt/components/VideoLayouts/EqualProminence.tsx +13 -10
- package/src/Prebuilt/components/VideoLayouts/Grid.tsx +36 -34
- package/src/Prebuilt/components/VideoLayouts/GridLayout.tsx +33 -15
- package/src/Prebuilt/components/VideoLayouts/ProminenceLayout.tsx +45 -31
- package/src/Prebuilt/components/VideoLayouts/RoleProminence.tsx +12 -9
- package/src/Prebuilt/components/VideoLayouts/ScreenshareLayout.tsx +25 -9
- package/src/Prebuilt/components/VideoLayouts/interface.ts +1 -0
- package/src/Prebuilt/components/VideoTile.jsx +45 -53
- package/src/Prebuilt/components/conference.jsx +71 -74
- package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +57 -0
- package/src/Prebuilt/components/hooks/useMetadata.jsx +12 -3
- package/src/Prebuilt/components/hooks/useRedirectToLeave.tsx +34 -0
- package/src/Prebuilt/components/hooks/useRoleProminencePeers.tsx +1 -1
- package/src/Prebuilt/components/hooks/useTileLayout.tsx +24 -18
- package/src/Prebuilt/components/hooks/useVideoTileLayout.ts +4 -0
- package/src/Prebuilt/layouts/EmbedView.jsx +1 -11
- package/src/Prebuilt/layouts/HLSView.jsx +152 -82
- package/src/Prebuilt/layouts/SidePane.tsx +15 -3
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +11 -47
- package/src/Prebuilt/plugins/FlyingEmoji.jsx +14 -2
- package/src/Prebuilt/services/FeatureFlags.jsx +0 -1
- package/src/VideoTile/StyledVideoTile.tsx +1 -0
- package/dist/HLSView-PY2FKWX3.js.map +0 -7
- package/dist/chunk-RXTHJUMZ.js.map +0 -7
- package/dist/conference-V2XZGTKU.js.map +0 -7
- package/src/Prebuilt/components/AudioLevel/BeamSpeakerLabelsLogging.jsx +0 -16
- package/src/Prebuilt/components/VideoList.jsx +0 -73
- /package/dist/{VirtualBackground-AYDHYLIZ.js.map → VirtualBackground-UM2FOUHQ.js.map} +0 -0
- /package/dist/{chunk-E2M2ZSOL.js.map → chunk-364HP22I.js.map} +0 -0
@@ -1,53 +1,61 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { useMeasure } from 'react-use';
|
3
3
|
import { FixedSizeList } from 'react-window';
|
4
|
+
import { HMSPeer } from '@100mslive/react-sdk';
|
4
5
|
import { Accordion } from '../../../Accordion';
|
5
6
|
import { Box, Flex } from '../../../Layout';
|
7
|
+
import { Text } from '../../../Text';
|
8
|
+
// @ts-ignore: No implicit Any
|
6
9
|
import { Participant } from './ParticipantList';
|
10
|
+
import { RoleOptions } from './RoleOptions';
|
11
|
+
// @ts-ignore: No implicit Any
|
7
12
|
import { getFormattedCount } from '../../common/utils';
|
8
13
|
|
9
14
|
const ROW_HEIGHT = 50;
|
10
15
|
|
11
|
-
|
16
|
+
interface ItemData {
|
17
|
+
peerList: HMSPeer[];
|
18
|
+
isConnected: boolean;
|
19
|
+
}
|
20
|
+
|
21
|
+
function itemKey(index: number, data: ItemData) {
|
12
22
|
return data.peerList[index].id;
|
13
23
|
}
|
14
24
|
|
15
|
-
const VirtualizedParticipantItem = React.memo(({ index, data }) => {
|
16
|
-
return
|
17
|
-
<Participant
|
18
|
-
key={data.peerList[index].id}
|
19
|
-
peer={data.peerList[index]}
|
20
|
-
isConnected={data.isConnected}
|
21
|
-
setSelectedPeerId={data.setSelectedPeerId}
|
22
|
-
/>
|
23
|
-
);
|
25
|
+
const VirtualizedParticipantItem = React.memo(({ index, data }: { index: number; data: ItemData }) => {
|
26
|
+
return <Participant key={data.peerList[index].id} peer={data.peerList[index]} isConnected={data.isConnected} />;
|
24
27
|
});
|
25
28
|
|
26
29
|
export const RoleAccordion = ({
|
27
30
|
peerList = [],
|
28
31
|
roleName,
|
29
|
-
setSelectedPeerId,
|
30
32
|
isConnected,
|
31
33
|
filter,
|
32
34
|
isHandRaisedAccordion = false,
|
35
|
+
}: ItemData & {
|
36
|
+
roleName: string;
|
37
|
+
isHandRaisedAccordion?: boolean;
|
38
|
+
filter?: { search: string };
|
33
39
|
}) => {
|
34
|
-
const [ref, { width }] = useMeasure();
|
35
|
-
const height = ROW_HEIGHT * peerList.length;
|
40
|
+
const [ref, { width }] = useMeasure<HTMLDivElement>();
|
36
41
|
const showAcordion = filter?.search ? peerList.some(peer => peer.name.toLowerCase().includes(filter.search)) : true;
|
42
|
+
|
37
43
|
if (!showAcordion || (isHandRaisedAccordion && filter?.search) || peerList.length === 0) {
|
38
44
|
return null;
|
39
45
|
}
|
46
|
+
const height = ROW_HEIGHT * peerList.length;
|
40
47
|
|
41
48
|
return (
|
42
|
-
<Flex direction="column" css={{ flexGrow: 1 }} ref={ref}>
|
49
|
+
<Flex direction="column" css={{ flexGrow: 1, '&:hover .role_actions': { visibility: 'visible' } }} ref={ref}>
|
43
50
|
<Accordion.Root
|
44
51
|
type="single"
|
45
52
|
collapsible
|
46
53
|
defaultValue={roleName}
|
47
|
-
css={{ borderRadius: '$
|
54
|
+
css={{ borderRadius: '$1', border: '1px solid $border_bright' }}
|
48
55
|
>
|
49
56
|
<Accordion.Item value={roleName}>
|
50
57
|
<Accordion.Header
|
58
|
+
iconStyles={{ c: '$on_surface_high' }}
|
51
59
|
css={{
|
52
60
|
textTransform: 'capitalize',
|
53
61
|
p: '$6 $8',
|
@@ -56,13 +64,21 @@ export const RoleAccordion = ({
|
|
56
64
|
c: '$on_surface_medium',
|
57
65
|
}}
|
58
66
|
>
|
59
|
-
{
|
67
|
+
<Flex justify="between" css={{ flexGrow: 1, pr: '$6' }}>
|
68
|
+
<Text
|
69
|
+
variant="sm"
|
70
|
+
css={{ fontWeight: '$semiBold', textTransform: 'capitalize', color: '$on_surface_medium' }}
|
71
|
+
>
|
72
|
+
{roleName} {`(${getFormattedCount(peerList.length)})`}
|
73
|
+
</Text>
|
74
|
+
<RoleOptions roleName={roleName} peerList={peerList} />
|
75
|
+
</Flex>
|
60
76
|
</Accordion.Header>
|
61
77
|
<Accordion.Content>
|
62
78
|
<Box css={{ borderTop: '1px solid $border_default' }} />
|
63
79
|
<FixedSizeList
|
64
80
|
itemSize={ROW_HEIGHT}
|
65
|
-
itemData={{ peerList, isConnected
|
81
|
+
itemData={{ peerList, isConnected }}
|
66
82
|
itemKey={itemKey}
|
67
83
|
itemCount={peerList.length}
|
68
84
|
width={width}
|
@@ -0,0 +1,155 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
|
3
|
+
import { HMSPeer, selectPermissions, useHMSActions, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
|
4
|
+
import {
|
5
|
+
MicOffIcon,
|
6
|
+
MicOnIcon,
|
7
|
+
PersonRectangleIcon,
|
8
|
+
RemoveUserIcon,
|
9
|
+
VerticalMenuIcon,
|
10
|
+
VideoOffIcon,
|
11
|
+
VideoOnIcon,
|
12
|
+
} from '@100mslive/react-icons';
|
13
|
+
import { Dropdown } from '../../../Dropdown';
|
14
|
+
import { Flex } from '../../../Layout';
|
15
|
+
import { Text } from '../../../Text';
|
16
|
+
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
|
17
|
+
// @ts-ignore: No implicit Any
|
18
|
+
import { getMetadata } from '../../common/utils';
|
19
|
+
|
20
|
+
const dropdownItemCSS = { backgroundColor: '$surface_default', gap: '$4', p: '$8' };
|
21
|
+
const optionTextCSS = { fontWeight: '$semiBold', color: '$on_surface_high', textTransform: 'none' };
|
22
|
+
|
23
|
+
export const RoleOptions = ({ roleName, peerList }: { roleName: string; peerList: HMSPeer[] }) => {
|
24
|
+
const [openOptions, setOpenOptions] = useState(false);
|
25
|
+
const permissions = useHMSStore(selectPermissions);
|
26
|
+
const hmsActions = useHMSActions();
|
27
|
+
const { elements } = useRoomLayoutConferencingScreen();
|
28
|
+
const { on_stage_role, off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {};
|
29
|
+
|
30
|
+
const vanillaStore = useHMSVanillaStore();
|
31
|
+
const store = vanillaStore.getState();
|
32
|
+
|
33
|
+
let allPeersHaveVideoOn = true;
|
34
|
+
let allPeersHaveAudioOn = true;
|
35
|
+
|
36
|
+
peerList.forEach(peer => {
|
37
|
+
const isAudioOn = !!peer.audioTrack && store.tracks[peer.audioTrack]?.enabled;
|
38
|
+
const isVideoOn = !!peer.videoTrack && store.tracks[peer.videoTrack]?.enabled;
|
39
|
+
allPeersHaveAudioOn = allPeersHaveAudioOn && isAudioOn;
|
40
|
+
allPeersHaveVideoOn = allPeersHaveVideoOn && isVideoOn;
|
41
|
+
});
|
42
|
+
|
43
|
+
const canMuteRole = permissions?.mute && roleName === on_stage_role;
|
44
|
+
const canRemoveRoleFromStage = permissions?.changeRole && roleName === on_stage_role;
|
45
|
+
// on stage and off stage roles
|
46
|
+
const canRemoveRoleFromRoom =
|
47
|
+
permissions?.removeOthers && (on_stage_role === roleName || off_stage_roles?.includes(roleName));
|
48
|
+
|
49
|
+
if (!(canMuteRole || canRemoveRoleFromStage || canRemoveRoleFromRoom)) {
|
50
|
+
return null;
|
51
|
+
}
|
52
|
+
|
53
|
+
const removeAllFromStage = () => {
|
54
|
+
peerList.forEach(peer => {
|
55
|
+
const prevRole = getMetadata(peer.metadata).prevRole;
|
56
|
+
if (prevRole) {
|
57
|
+
hmsActions.changeRoleOfPeer(peer.id, prevRole, true);
|
58
|
+
}
|
59
|
+
});
|
60
|
+
};
|
61
|
+
|
62
|
+
const setTrackEnabled = async (type: 'audio' | 'video', enabled = false) => {
|
63
|
+
try {
|
64
|
+
await hmsActions.setRemoteTracksEnabled({ roles: [roleName], source: 'regular', type, enabled });
|
65
|
+
} catch (e) {
|
66
|
+
console.error(e);
|
67
|
+
}
|
68
|
+
};
|
69
|
+
|
70
|
+
const removePeersFromRoom = async () => {
|
71
|
+
try {
|
72
|
+
peerList.forEach(async peer => {
|
73
|
+
await hmsActions.removePeer(peer.id, '');
|
74
|
+
});
|
75
|
+
} catch (e) {
|
76
|
+
console.error(e);
|
77
|
+
}
|
78
|
+
};
|
79
|
+
|
80
|
+
return (
|
81
|
+
<Dropdown.Root open={openOptions} onOpenChange={setOpenOptions}>
|
82
|
+
<Dropdown.Trigger
|
83
|
+
onClick={e => e.stopPropagation()}
|
84
|
+
className="role_actions"
|
85
|
+
asChild
|
86
|
+
css={{
|
87
|
+
p: '$1',
|
88
|
+
r: '$0',
|
89
|
+
c: '$on_surface_high',
|
90
|
+
visibility: openOptions ? 'visible' : 'hidden',
|
91
|
+
'&:hover': {
|
92
|
+
c: '$on_surface_medium',
|
93
|
+
},
|
94
|
+
'@md': {
|
95
|
+
visibility: 'visible',
|
96
|
+
},
|
97
|
+
}}
|
98
|
+
>
|
99
|
+
<Flex>
|
100
|
+
<VerticalMenuIcon />
|
101
|
+
</Flex>
|
102
|
+
</Dropdown.Trigger>
|
103
|
+
<Dropdown.Content
|
104
|
+
onClick={e => e.stopPropagation()}
|
105
|
+
css={{ w: 'max-content', maxWidth: '$64', bg: '$surface_default', py: 0 }}
|
106
|
+
align="end"
|
107
|
+
>
|
108
|
+
{canRemoveRoleFromStage && (
|
109
|
+
<Dropdown.Item
|
110
|
+
css={{ ...dropdownItemCSS, borderBottom: '1px solid $border_bright' }}
|
111
|
+
onClick={removeAllFromStage}
|
112
|
+
>
|
113
|
+
<PersonRectangleIcon />
|
114
|
+
<Text variant="sm" css={optionTextCSS}>
|
115
|
+
Remove all from Stage
|
116
|
+
</Text>
|
117
|
+
</Dropdown.Item>
|
118
|
+
)}
|
119
|
+
|
120
|
+
{canMuteRole && (
|
121
|
+
<>
|
122
|
+
<Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('audio', !allPeersHaveAudioOn)}>
|
123
|
+
{allPeersHaveAudioOn ? <MicOffIcon /> : <MicOnIcon />}
|
124
|
+
<Text variant="sm" css={optionTextCSS}>
|
125
|
+
{allPeersHaveAudioOn ? 'Mute' : 'Unmute'} Audio
|
126
|
+
</Text>
|
127
|
+
</Dropdown.Item>
|
128
|
+
|
129
|
+
<Dropdown.Item
|
130
|
+
css={{ ...dropdownItemCSS, borderTop: '1px solid $border_bright' }}
|
131
|
+
onClick={() => setTrackEnabled('video', !allPeersHaveVideoOn)}
|
132
|
+
>
|
133
|
+
{allPeersHaveVideoOn ? <VideoOffIcon /> : <VideoOnIcon />}
|
134
|
+
<Text variant="sm" css={optionTextCSS}>
|
135
|
+
{allPeersHaveVideoOn ? 'Mute' : 'Unmute'} Video
|
136
|
+
</Text>
|
137
|
+
</Dropdown.Item>
|
138
|
+
</>
|
139
|
+
)}
|
140
|
+
|
141
|
+
{canRemoveRoleFromRoom && (
|
142
|
+
<Dropdown.Item
|
143
|
+
css={{ ...dropdownItemCSS, borderTop: '1px solid $border_bright', color: '$alert_error_default' }}
|
144
|
+
onClick={removePeersFromRoom}
|
145
|
+
>
|
146
|
+
<RemoveUserIcon />
|
147
|
+
<Text variant="sm" css={{ ...optionTextCSS, color: 'inherit' }}>
|
148
|
+
Remove all from Room
|
149
|
+
</Text>
|
150
|
+
</Dropdown.Item>
|
151
|
+
)}
|
152
|
+
</Dropdown.Content>
|
153
|
+
</Dropdown.Root>
|
154
|
+
);
|
155
|
+
};
|
@@ -3,10 +3,10 @@ import { Flex } from '../../Layout';
|
|
3
3
|
import { Loading } from '../../Loading';
|
4
4
|
import { Text } from '../../Text';
|
5
5
|
|
6
|
-
const FullPageProgress = ({ loaderColor = '$primary_default',
|
7
|
-
<Flex direction="column" justify="center" align="center" css={{ size: '100%', color: loaderColor }}>
|
6
|
+
const FullPageProgress = ({ loaderColor = '$primary_default', text = '', css = {} }) => (
|
7
|
+
<Flex direction="column" justify="center" align="center" css={{ size: '100%', color: loaderColor, ...css }}>
|
8
8
|
<Loading color="currentColor" size={100} />
|
9
|
-
{
|
9
|
+
{text ? <Text css={{ mt: '$10', color: '$on_surface_high' }}>{text}</Text> : null}
|
10
10
|
</Flex>
|
11
11
|
);
|
12
12
|
|
@@ -1,12 +1,10 @@
|
|
1
|
-
import React
|
2
|
-
import {
|
1
|
+
import React from 'react';
|
2
|
+
import { CheckIcon, SettingsIcon } from '@100mslive/react-icons';
|
3
3
|
import { Box, Dropdown, Flex, Text, Tooltip } from '../../../';
|
4
4
|
|
5
|
-
export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto }) {
|
6
|
-
const [qualityDropDownOpen, setQualityDropDownOpen] = useState(false);
|
7
|
-
|
5
|
+
export function HLSQualitySelector({ open, onOpen, layers, onQualityChange, selection, isAuto }) {
|
8
6
|
return (
|
9
|
-
<Dropdown.Root open={
|
7
|
+
<Dropdown.Root open={open} onOpenChange={value => onOpen(value)}>
|
10
8
|
<Dropdown.Trigger asChild data-testid="quality_selector">
|
11
9
|
<Flex
|
12
10
|
css={{
|
@@ -24,6 +22,7 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
24
22
|
h: '$9',
|
25
23
|
display: 'inline-flex',
|
26
24
|
alignItems: 'center',
|
25
|
+
c: '$on_surface_high',
|
27
26
|
}}
|
28
27
|
>
|
29
28
|
<SettingsIcon />
|
@@ -44,7 +43,7 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
44
43
|
mx: '$2',
|
45
44
|
w: '$2',
|
46
45
|
h: '$2',
|
47
|
-
background: '$
|
46
|
+
background: '$on_surface_medium',
|
48
47
|
r: '$1',
|
49
48
|
}}
|
50
49
|
/>
|
@@ -60,7 +59,15 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
60
59
|
<Dropdown.Content
|
61
60
|
sideOffset={5}
|
62
61
|
align="end"
|
63
|
-
css={{
|
62
|
+
css={{
|
63
|
+
height: 'auto',
|
64
|
+
maxHeight: '$52',
|
65
|
+
w: '$40',
|
66
|
+
bg: '$surface_bright',
|
67
|
+
py: '$4',
|
68
|
+
gap: '$4',
|
69
|
+
display: 'grid',
|
70
|
+
}}
|
64
71
|
>
|
65
72
|
{layers.map(layer => {
|
66
73
|
return (
|
@@ -68,16 +75,26 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
68
75
|
onClick={() => onQualityChange(layer)}
|
69
76
|
key={layer.width}
|
70
77
|
css={{
|
71
|
-
bg:
|
78
|
+
bg:
|
79
|
+
!isAuto && layer.width === selection?.width && layer.height === selection?.height
|
80
|
+
? '$surface_default'
|
81
|
+
: '$surface_bright',
|
72
82
|
'&:hover': {
|
73
|
-
bg: '$
|
83
|
+
bg: '$surface_brighter',
|
74
84
|
},
|
85
|
+
p: '$2 $4 $2 $8',
|
86
|
+
h: '$12',
|
87
|
+
gap: '$2',
|
75
88
|
}}
|
76
89
|
>
|
77
|
-
<Text
|
78
|
-
|
90
|
+
<Text variant="caption" css={{ fontWeight: '$semiBold' }}>
|
91
|
+
{getQualityText(layer)}
|
92
|
+
</Text>
|
93
|
+
<Text variant="caption" css={{ flex: '1 1 0', c: '$on_surface_low', pl: '$2' }}>
|
94
|
+
{getBitrateText(layer)}
|
95
|
+
</Text>
|
79
96
|
{!isAuto && layer.width === selection?.width && layer.height === selection?.height && (
|
80
|
-
<
|
97
|
+
<CheckIcon width="16px" height="16px" />
|
81
98
|
)}
|
82
99
|
</Dropdown.Item>
|
83
100
|
);
|
@@ -86,14 +103,19 @@ export function HLSQualitySelector({ layers, onQualityChange, selection, isAuto
|
|
86
103
|
onClick={() => onQualityChange({ height: 'auto' })}
|
87
104
|
key="auto"
|
88
105
|
css={{
|
89
|
-
bg: '$surface_bright',
|
106
|
+
bg: !isAuto ? '$surface_bright' : '$surface_default',
|
90
107
|
'&:hover': {
|
91
|
-
bg: '$
|
108
|
+
bg: '$surface_brighter',
|
92
109
|
},
|
110
|
+
p: '$2 $4 $2 $8',
|
111
|
+
h: '$12',
|
112
|
+
gap: '$2',
|
93
113
|
}}
|
94
114
|
>
|
95
|
-
<Text css={{ flex: '1 1 0' }}>
|
96
|
-
|
115
|
+
<Text variant="caption" css={{ fontWeight: '$semiBold', flex: '1 1 0' }}>
|
116
|
+
Auto
|
117
|
+
</Text>
|
118
|
+
{isAuto && <CheckIcon width="16px" height="16px" />}
|
97
119
|
</Dropdown.Item>
|
98
120
|
</Dropdown.Content>
|
99
121
|
)}
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import React, { forwardRef } from 'react';
|
2
2
|
import { Flex } from '../../../';
|
3
3
|
|
4
|
-
export const HMSVideo = forwardRef(({ children }, videoRef) => {
|
4
|
+
export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
|
5
5
|
return (
|
6
|
-
<Flex data-testid="hms-video" css={{ size: '100%' }} direction="column">
|
6
|
+
<Flex data-testid="hms-video" css={{ size: '100%', position: 'relative' }} direction="column" {...props}>
|
7
7
|
<video style={{ flex: '1 1 0', margin: '0 auto', minHeight: '0' }} ref={videoRef} playsInline />
|
8
8
|
{children}
|
9
9
|
</Flex>
|
@@ -44,7 +44,7 @@ export const VideoProgress = ({ onValueChange, hlsPlayer }) => {
|
|
44
44
|
return hlsPlayer.getVideoElement() ? (
|
45
45
|
<Flex
|
46
46
|
ref={progressRootRef}
|
47
|
-
css={{
|
47
|
+
css={{ cursor: 'pointer', h: '$4', alignSelf: 'stretch' }}
|
48
48
|
onClick={onProgressChangeHandler}
|
49
49
|
>
|
50
50
|
<Box
|
@@ -53,23 +53,22 @@ export const VideoProgress = ({ onValueChange, hlsPlayer }) => {
|
|
53
53
|
display: 'inline',
|
54
54
|
width: `${videoProgress}%`,
|
55
55
|
background: '$primary_default',
|
56
|
-
height: '0.3rem',
|
57
56
|
}}
|
58
57
|
/>
|
59
58
|
<Box
|
60
59
|
id="video-buffer"
|
61
60
|
css={{
|
62
61
|
width: `${bufferProgress - videoProgress}%`,
|
63
|
-
background: '$
|
64
|
-
|
62
|
+
background: '$on_surface_high',
|
63
|
+
opacity: '25%',
|
65
64
|
}}
|
66
65
|
/>
|
67
66
|
<Box
|
68
67
|
id="video-rest"
|
69
68
|
css={{
|
70
69
|
width: `${100 - bufferProgress}%`,
|
71
|
-
background: '$
|
72
|
-
|
70
|
+
background: '$on_surface_high',
|
71
|
+
opacity: '10%',
|
73
72
|
}}
|
74
73
|
/>
|
75
74
|
</Flex>
|
@@ -11,26 +11,31 @@ import {
|
|
11
11
|
useRecordingStreaming,
|
12
12
|
} from '@100mslive/react-sdk';
|
13
13
|
import { AlertTriangleIcon, CrossIcon, RecordIcon } from '@100mslive/react-icons';
|
14
|
-
import { Box, Button, config as cssConfig, Flex, HorizontalDivider, Loading, Popover, Text, Tooltip } from '
|
14
|
+
import { Box, Button, config as cssConfig, Flex, HorizontalDivider, Loading, Popover, Text, Tooltip } from '../../..';
|
15
15
|
import { Sheet } from '../../../Sheet';
|
16
|
+
// @ts-ignore
|
16
17
|
import { ToastManager } from '../Toast/ToastManager';
|
18
|
+
// @ts-ignore
|
17
19
|
import { AdditionalRoomState, getRecordingText } from './AdditionalRoomState';
|
20
|
+
// @ts-ignore
|
18
21
|
import { useSetAppDataByKey } from '../AppData/useUISettings';
|
22
|
+
// @ts-ignore
|
19
23
|
import { formatTime } from '../../common/utils';
|
24
|
+
// @ts-ignore
|
20
25
|
import { APP_DATA } from '../../common/constants';
|
21
26
|
|
22
27
|
export const LiveStatus = () => {
|
23
28
|
const { isHLSRunning, isRTMPRunning } = useRecordingStreaming();
|
24
29
|
const hlsState = useHMSStore(selectHLSState);
|
25
30
|
const isMobile = useMedia(cssConfig.media.md);
|
26
|
-
const intervalRef = useRef(null);
|
31
|
+
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
27
32
|
|
28
33
|
const [liveTime, setLiveTime] = useState(0);
|
29
34
|
|
30
35
|
const startTimer = useCallback(() => {
|
31
36
|
intervalRef.current = setInterval(() => {
|
32
|
-
if (hlsState?.running) {
|
33
|
-
setLiveTime(Date.now() - hlsState
|
37
|
+
if (hlsState?.running && hlsState?.variants[0]?.startedAt) {
|
38
|
+
setLiveTime(Date.now() - hlsState.variants[0].startedAt.getTime());
|
34
39
|
}
|
35
40
|
}, 1000);
|
36
41
|
}, [hlsState?.running, hlsState?.variants]);
|
@@ -90,6 +95,7 @@ export const RecordingStatus = () => {
|
|
90
95
|
|
91
96
|
return (
|
92
97
|
<Tooltip
|
98
|
+
boxCss={{ zIndex: 1 }}
|
93
99
|
title={getRecordingText({
|
94
100
|
isBrowserRecordingOn,
|
95
101
|
isServerRecordingOn,
|
@@ -130,7 +136,7 @@ const StartRecording = () => {
|
|
130
136
|
</Popover.Trigger>
|
131
137
|
<Popover.Portal>
|
132
138
|
<Popover.Content align="end" sideOffset={8} css={{ w: '$64' }}>
|
133
|
-
<Text variant="
|
139
|
+
<Text variant="body1" css={{ color: '$on_surface_medium' }}>
|
134
140
|
Are you sure you want to end the recording?
|
135
141
|
</Text>
|
136
142
|
<Button
|
@@ -142,8 +148,9 @@ const StartRecording = () => {
|
|
142
148
|
try {
|
143
149
|
await hmsActions.stopRTMPAndRecording();
|
144
150
|
} catch (error) {
|
151
|
+
const err = error as Error;
|
145
152
|
ToastManager.addToast({
|
146
|
-
title:
|
153
|
+
title: err.message,
|
147
154
|
variant: 'error',
|
148
155
|
});
|
149
156
|
}
|
@@ -170,14 +177,15 @@ const StartRecording = () => {
|
|
170
177
|
record: true,
|
171
178
|
});
|
172
179
|
} catch (error) {
|
173
|
-
|
180
|
+
const err = error as Error;
|
181
|
+
if (err.message.includes('stream already running')) {
|
174
182
|
ToastManager.addToast({
|
175
183
|
title: 'Recording already running',
|
176
184
|
variant: 'error',
|
177
185
|
});
|
178
186
|
} else {
|
179
187
|
ToastManager.addToast({
|
180
|
-
title:
|
188
|
+
title: err.message,
|
181
189
|
variant: 'error',
|
182
190
|
});
|
183
191
|
}
|
@@ -215,7 +223,13 @@ export const StreamActions = () => {
|
|
215
223
|
);
|
216
224
|
};
|
217
225
|
|
218
|
-
export const StopRecordingInSheet = ({
|
226
|
+
export const StopRecordingInSheet = ({
|
227
|
+
onStopRecording,
|
228
|
+
onClose,
|
229
|
+
}: {
|
230
|
+
onStopRecording: () => void;
|
231
|
+
onClose: () => void;
|
232
|
+
}) => {
|
219
233
|
return (
|
220
234
|
<Sheet.Root open={true}>
|
221
235
|
<Sheet.Content>
|
@@ -25,11 +25,13 @@ export const CamaraFlipActions = () => {
|
|
25
25
|
|
26
26
|
const videoTrackId = useHMSStore(selectLocalVideoTrackID);
|
27
27
|
const localVideoTrack = useHMSStore(selectVideoTrackByID(videoTrackId));
|
28
|
-
|
28
|
+
if (!videoInput || !videoInput?.length || !localVideoTrack?.facingMode) {
|
29
|
+
return null;
|
30
|
+
}
|
29
31
|
return (
|
30
32
|
<Box>
|
31
33
|
<IconButton
|
32
|
-
disabled={!
|
34
|
+
disabled={!isVideoOn}
|
33
35
|
onClick={async () => {
|
34
36
|
try {
|
35
37
|
await actions.switchCamera();
|
@@ -117,6 +119,7 @@ const AudioOutputSelectionSheet = ({ outputDevices, outputSelected, onChange, ch
|
|
117
119
|
{outputDevices.map(audioDevice => {
|
118
120
|
return (
|
119
121
|
<SelectWithLabel
|
122
|
+
key={audioDevice.deviceId}
|
120
123
|
label={audioDevice.label}
|
121
124
|
id={audioDevice.deviceId}
|
122
125
|
checked={audioDevice.deviceId === outputSelected}
|
@@ -14,6 +14,10 @@ const IconSection = styled(IconButton, {
|
|
14
14
|
borderTopRightRadius: 0,
|
15
15
|
borderColor: '$border_default',
|
16
16
|
borderBottomRightRadius: 0,
|
17
|
+
position: 'relative',
|
18
|
+
'&:not([disabled]):focus-visible': {
|
19
|
+
zIndex: 1,
|
20
|
+
},
|
17
21
|
'@md': {
|
18
22
|
mx: 0,
|
19
23
|
borderTopRightRadius: '$1',
|
@@ -30,8 +34,9 @@ const OptionsSection = styled(IconButton, {
|
|
30
34
|
borderColor: '$border_default',
|
31
35
|
borderBottomLeftRadius: 0,
|
32
36
|
borderLeftWidth: 0,
|
37
|
+
position: 'relative',
|
33
38
|
'&:not([disabled]):focus-visible': {
|
34
|
-
|
39
|
+
zIndex: 1,
|
35
40
|
},
|
36
41
|
'@md': {
|
37
42
|
display: 'none',
|
@@ -14,6 +14,7 @@ import { AudioVideoToggle } from './AudioVideoToggle';
|
|
14
14
|
import VideoTile from './VideoTile';
|
15
15
|
// @ts-ignore: No implicit Any
|
16
16
|
import { useSetAppDataByKey } from './AppData/useUISettings';
|
17
|
+
import { useVideoTileContext } from './hooks/useVideoTileLayout';
|
17
18
|
// @ts-ignore: No implicit Any
|
18
19
|
import { APP_DATA } from '../common/constants';
|
19
20
|
|
@@ -22,7 +23,11 @@ const MinimisedTile = ({ setMinimised }: { setMinimised: (value: boolean) => voi
|
|
22
23
|
<Flex align="center" css={{ gap: '$6', r: '$1', bg: '$surface_default', p: '$4', color: '$on_surface_high' }}>
|
23
24
|
<AudioVideoToggle hideOptions={true} />
|
24
25
|
<Text>You</Text>
|
25
|
-
<IconButton
|
26
|
+
<IconButton
|
27
|
+
className="__cancel-drag-event"
|
28
|
+
onClick={() => setMinimised(false)}
|
29
|
+
css={{ bg: 'transparent', border: 'transparent' }}
|
30
|
+
>
|
26
31
|
<ExpandIcon />
|
27
32
|
</IconButton>
|
28
33
|
</Flex>
|
@@ -41,12 +46,11 @@ export const InsetTile = () => {
|
|
41
46
|
const [minimised, setMinimised] = useSetAppDataByKey(APP_DATA.minimiseInset);
|
42
47
|
const videoTrack = useHMSStore(selectVideoTrackByID(localPeer?.videoTrack));
|
43
48
|
const isAllowedToPublish = useHMSStore(selectIsAllowedToPublish);
|
44
|
-
const
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
: desktopAspectRatio;
|
49
|
+
const videoTileProps = useVideoTileContext();
|
50
|
+
let aspectRatio = isMobile ? defaultMobileAspectRatio : desktopAspectRatio;
|
51
|
+
if (videoTrack?.width && videoTrack?.height && !isMobile) {
|
52
|
+
aspectRatio = videoTrack.width / videoTrack.height;
|
53
|
+
}
|
50
54
|
let height = insetHeightPx;
|
51
55
|
let width = height * aspectRatio;
|
52
56
|
// Convert to 16/9 in landscape mode with a max width of 240
|
@@ -82,7 +86,7 @@ export const InsetTile = () => {
|
|
82
86
|
}
|
83
87
|
|
84
88
|
return (
|
85
|
-
<Draggable bounds="parent" nodeRef={nodeRef}>
|
89
|
+
<Draggable bounds="parent" nodeRef={nodeRef} cancel=".__cancel-drag-event">
|
86
90
|
<Box
|
87
91
|
ref={nodeRef}
|
88
92
|
css={{
|
@@ -114,6 +118,8 @@ export const InsetTile = () => {
|
|
114
118
|
height={height}
|
115
119
|
containerCSS={{ background: '$surface_default' }}
|
116
120
|
canMinimise
|
121
|
+
isDragabble
|
122
|
+
{...videoTileProps}
|
117
123
|
/>
|
118
124
|
)}
|
119
125
|
</Box>
|