@100mslive/roomkit-react 0.1.4-alpha.1 → 0.1.5

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.
Files changed (152) hide show
  1. package/dist/{HLSView-F2K5VSTS.js → HLSView-P57IRMAR.js} +7 -11
  2. package/dist/{HLSView-F2K5VSTS.js.map → HLSView-P57IRMAR.js.map} +1 -1
  3. package/dist/PinnedTrackView-4FYJEBTB.js +102 -0
  4. package/dist/PinnedTrackView-4FYJEBTB.js.map +7 -0
  5. package/dist/Popover/index.d.ts +1 -0
  6. package/dist/Prebuilt/App.d.ts +25 -0
  7. package/dist/Prebuilt/index.d.ts +1 -0
  8. package/dist/Prebuilt/provider/roomLayoutProvider/index.d.ts +1 -1
  9. package/dist/Sheet/Sheet.d.ts +3093 -0
  10. package/dist/Sheet/index.d.ts +1 -0
  11. package/dist/Theme/ThemeProvider.d.ts +4 -286
  12. package/dist/Theme/stitches.config.d.ts +1 -1
  13. package/dist/{VirtualBackground-S3XEPZ2T.js → VirtualBackground-GGCQJ5JM.js} +31 -7
  14. package/dist/VirtualBackground-GGCQJ5JM.js.map +7 -0
  15. package/dist/chunk-IVTWKQI3.js +827 -0
  16. package/dist/chunk-IVTWKQI3.js.map +7 -0
  17. package/dist/{chunk-42SWPN2C.js → chunk-OSM4QEQG.js} +3020 -2189
  18. package/dist/chunk-OSM4QEQG.js.map +7 -0
  19. package/dist/chunk-P5X32KOD.js +67 -0
  20. package/dist/chunk-P5X32KOD.js.map +7 -0
  21. package/dist/chunk-RVCZPPTL.js +1100 -0
  22. package/dist/chunk-RVCZPPTL.js.map +7 -0
  23. package/dist/{chunk-ESUJK7AT.js → conference-P6I6ESVF.js} +3136 -653
  24. package/dist/conference-P6I6ESVF.js.map +7 -0
  25. package/dist/index.cjs.js +15733 -15498
  26. package/dist/index.cjs.js.map +4 -4
  27. package/dist/index.js +4 -8
  28. package/dist/meta.cjs.json +3355 -3017
  29. package/dist/meta.esbuild.json +3534 -3329
  30. package/dist/utils/animations.d.ts +16 -0
  31. package/package.json +8 -10
  32. package/src/Button/Button.tsx +4 -4
  33. package/src/Dropdown/Dropdown.tsx +2 -2
  34. package/src/IconButton/IconButton.tsx +4 -2
  35. package/src/Pagination/StyledPagination.tsx +1 -0
  36. package/src/Popover/index.tsx +2 -1
  37. package/src/Prebuilt/{App.jsx → App.tsx} +95 -48
  38. package/src/Prebuilt/Prebuilt.stories.tsx +22 -8
  39. package/src/Prebuilt/common/constants.js +1 -2
  40. package/src/Prebuilt/common/hooks.js +8 -0
  41. package/src/Prebuilt/common/utils.js +15 -0
  42. package/src/Prebuilt/components/AppData/AppData.jsx +1 -2
  43. package/src/Prebuilt/components/AppData/useUISettings.js +0 -5
  44. package/src/Prebuilt/components/AudioVideoToggle.jsx +69 -26
  45. package/src/Prebuilt/components/AuthToken.jsx +3 -2
  46. package/src/Prebuilt/components/Chat/ChatSelector.jsx +1 -1
  47. package/src/Prebuilt/components/Connection/TileConnection.jsx +0 -1
  48. package/src/Prebuilt/components/EmojiReaction.jsx +23 -73
  49. package/src/Prebuilt/components/EndSessionContent.jsx +57 -0
  50. package/src/Prebuilt/components/EqualProminence.jsx +180 -0
  51. package/src/Prebuilt/components/ErrorBoundary.jsx +4 -10
  52. package/src/Prebuilt/components/Footer/EmojiCard.jsx +34 -0
  53. package/src/Prebuilt/components/Footer/Footer.jsx +73 -0
  54. package/src/Prebuilt/components/{Header → Footer}/ParticipantList.jsx +5 -5
  55. package/src/Prebuilt/components/Header/ConferencingHeader.jsx +27 -7
  56. package/src/Prebuilt/components/Header/HeaderComponents.jsx +16 -14
  57. package/src/Prebuilt/components/Header/StreamActions.jsx +101 -36
  58. package/src/Prebuilt/components/Header/StreamingHeader.jsx +1 -1
  59. package/src/Prebuilt/components/Header/common.jsx +164 -0
  60. package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.jsx +1 -2
  61. package/src/Prebuilt/components/LeaveCard.jsx +19 -0
  62. package/src/Prebuilt/components/LeaveRoom.jsx +35 -143
  63. package/src/Prebuilt/components/LeaveSessionContent.jsx +45 -0
  64. package/src/Prebuilt/components/MoreSettings/ActionTile.jsx +55 -0
  65. package/src/Prebuilt/components/MoreSettings/ChangeNameContent.jsx +96 -0
  66. package/src/Prebuilt/components/MoreSettings/ChangeNameModal.jsx +31 -54
  67. package/src/Prebuilt/components/MoreSettings/EmbedUrl.jsx +48 -73
  68. package/src/Prebuilt/components/MoreSettings/MoreSettings.jsx +5 -221
  69. package/src/Prebuilt/components/MoreSettings/MuteAllContent.jsx +61 -0
  70. package/src/Prebuilt/components/MoreSettings/MuteAllModal.jsx +32 -49
  71. package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopLeaveRoom.jsx +129 -0
  72. package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.jsx +219 -0
  73. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebLeaveRoom.jsx +100 -0
  74. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.jsx +259 -0
  75. package/src/Prebuilt/components/Notifications/Notifications.jsx +0 -2
  76. package/src/Prebuilt/components/Notifications/ReconnectNotifications.jsx +0 -4
  77. package/src/Prebuilt/components/PIP/PIPComponent.jsx +30 -26
  78. package/src/Prebuilt/components/PIP/PIPManager.js +13 -0
  79. package/src/Prebuilt/components/PIP/index.jsx +2 -7
  80. package/src/Prebuilt/components/Pagination.jsx +4 -4
  81. package/src/Prebuilt/components/Preview/PreviewContainer.jsx +5 -13
  82. package/src/Prebuilt/components/Preview/PreviewForm.jsx +9 -5
  83. package/src/Prebuilt/components/Preview/PreviewJoin.jsx +20 -27
  84. package/src/Prebuilt/components/RaiseHand.jsx +27 -0
  85. package/src/Prebuilt/components/ScreenShare.jsx +1 -1
  86. package/src/Prebuilt/components/ScreenshareDisplay.jsx +2 -2
  87. package/src/Prebuilt/components/ScreenshareTile.jsx +2 -2
  88. package/src/Prebuilt/components/Settings/DeviceSettings.jsx +2 -1
  89. package/src/Prebuilt/components/Settings/LayoutSettings.jsx +1 -24
  90. package/src/Prebuilt/components/Settings/SettingsModal.jsx +152 -17
  91. package/src/Prebuilt/components/ShareMenuIcon.jsx +1 -0
  92. package/src/Prebuilt/components/TileMenu/TileMenu.jsx +133 -0
  93. package/src/Prebuilt/components/TileMenu/TileMenuContent.jsx +313 -0
  94. package/src/Prebuilt/components/VideoList.jsx +5 -33
  95. package/src/Prebuilt/components/VideoTile.jsx +30 -8
  96. package/src/Prebuilt/components/conference.jsx +14 -1
  97. package/src/Prebuilt/components/init/Init.jsx +0 -27
  98. package/src/Prebuilt/components/init/initUtils.js +0 -23
  99. package/src/Prebuilt/components/pdfAnnotator/pdfFileOptions.jsx +2 -1
  100. package/src/Prebuilt/components/pdfAnnotator/pdfInfo.jsx +1 -1
  101. package/src/Prebuilt/components/pdfAnnotator/shareScreenOptions.jsx +19 -8
  102. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +1 -0
  103. package/src/Prebuilt/images/pdf-share.png +0 -0
  104. package/src/Prebuilt/images/screen-share.png +0 -0
  105. package/src/Prebuilt/index.ts +1 -0
  106. package/src/Prebuilt/layouts/EmbedView.jsx +0 -1
  107. package/src/Prebuilt/layouts/InsetView.jsx +65 -24
  108. package/src/Prebuilt/layouts/PDFView.jsx +0 -1
  109. package/src/Prebuilt/layouts/SidePane.jsx +8 -7
  110. package/src/Prebuilt/layouts/mainView.jsx +22 -31
  111. package/src/Prebuilt/layouts/screenShareView.jsx +0 -2
  112. package/src/Prebuilt/plugins/VirtualBackground/VirtualBackground.jsx +25 -1
  113. package/src/Prebuilt/primitives/DialogContent.jsx +1 -1
  114. package/src/Prebuilt/provider/roomLayoutProvider/index.tsx +1 -1
  115. package/src/Sheet/Sheet.mdx +19 -0
  116. package/src/Sheet/Sheet.stories.tsx +103 -0
  117. package/src/Sheet/Sheet.tsx +118 -0
  118. package/src/Sheet/index.ts +1 -0
  119. package/src/Theme/ThemeProvider.tsx +10 -13
  120. package/src/Theme/base.config.ts +1 -1
  121. package/src/Theme/stitches.config.ts +1 -1
  122. package/src/TileMenu/StyledMenuTile.tsx +2 -2
  123. package/src/TileMenu/TileMenu.tsx +2 -0
  124. package/src/VideoTile/StyledVideoTile.tsx +5 -0
  125. package/src/utils/animations.ts +18 -0
  126. package/dist/ActiveSpeakerView-V6O4K3BV.js +0 -39
  127. package/dist/ActiveSpeakerView-V6O4K3BV.js.map +0 -7
  128. package/dist/PinnedTrackView-7YQG4QKC.js +0 -70
  129. package/dist/PinnedTrackView-7YQG4QKC.js.map +0 -7
  130. package/dist/VirtualBackground-S3XEPZ2T.js.map +0 -7
  131. package/dist/chunk-42SWPN2C.js.map +0 -7
  132. package/dist/chunk-4NEZLVVH.js +0 -811
  133. package/dist/chunk-4NEZLVVH.js.map +0 -7
  134. package/dist/chunk-4ZBEFSRC.js +0 -58
  135. package/dist/chunk-4ZBEFSRC.js.map +0 -7
  136. package/dist/chunk-ESUJK7AT.js.map +0 -7
  137. package/dist/chunk-R6PDR5WZ.js +0 -243
  138. package/dist/chunk-R6PDR5WZ.js.map +0 -7
  139. package/dist/conference-7QKOMJPP.js +0 -3697
  140. package/dist/conference-7QKOMJPP.js.map +0 -7
  141. package/dist/transcription-RJA4V6PC.js +0 -356
  142. package/dist/transcription-RJA4V6PC.js.map +0 -7
  143. package/src/Prebuilt/common/useSortedPeers.js +0 -28
  144. package/src/Prebuilt/components/BottomActionSheet/BottomActionSheet.jsx +0 -96
  145. package/src/Prebuilt/components/BottomActionSheet/BottomActionSheet.stories.tsx +0 -46
  146. package/src/Prebuilt/components/Footer/ConferencingFooter.jsx +0 -101
  147. package/src/Prebuilt/components/Footer/StreamingFooter.jsx +0 -71
  148. package/src/Prebuilt/components/Footer.jsx +0 -8
  149. package/src/Prebuilt/components/MoreSettings/ChangeSelfRole.jsx +0 -67
  150. package/src/Prebuilt/components/TileMenu.jsx +0 -268
  151. package/src/Prebuilt/index.d.ts +0 -20
  152. package/src/Prebuilt/index.js +0 -2
@@ -0,0 +1,73 @@
1
+ import React from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { selectLocalPeerRoleName, useHMSStore } from '@100mslive/react-sdk';
4
+ import { config as cssConfig, Footer as AppFooter } from '../../..';
5
+ import { AudioVideoToggle } from '../AudioVideoToggle';
6
+ import { EmojiReaction } from '../EmojiReaction';
7
+ import { LeaveRoom } from '../LeaveRoom';
8
+ import { MoreSettings } from '../MoreSettings/MoreSettings';
9
+ import { RaiseHand } from '../RaiseHand';
10
+ import { ScreenshareToggle } from '../ScreenShare';
11
+ import { ChatToggle } from './ChatToggle';
12
+ import { ParticipantCount } from './ParticipantList';
13
+ import { useHLSViewerRole } from '../AppData/useUISettings';
14
+
15
+ export const Footer = () => {
16
+ const isMobile = useMedia(cssConfig.media.md);
17
+ const localPeerRole = useHMSStore(selectLocalPeerRoleName);
18
+ const hlsViewerRole = useHLSViewerRole();
19
+ const isHlsViewer = hlsViewerRole === localPeerRole;
20
+
21
+ return (
22
+ <AppFooter.Root
23
+ css={{
24
+ flexWrap: 'nowrap',
25
+ '@md': {
26
+ justifyContent: 'center',
27
+ gap: '$10',
28
+ },
29
+ }}
30
+ >
31
+ <AppFooter.Left
32
+ css={{
33
+ '@md': {
34
+ w: 'unset',
35
+ p: '0',
36
+ gap: '$10',
37
+ },
38
+ }}
39
+ >
40
+ {isMobile ? <LeaveRoom /> : null}
41
+ <AudioVideoToggle />
42
+ </AppFooter.Left>
43
+ <AppFooter.Center
44
+ css={{
45
+ '@md': {
46
+ w: 'unset',
47
+ gap: '$10',
48
+ },
49
+ }}
50
+ >
51
+ {isMobile ? (
52
+ <>
53
+ {isHlsViewer ? <RaiseHand /> : null}
54
+ <ChatToggle />
55
+ <MoreSettings />
56
+ </>
57
+ ) : (
58
+ <>
59
+ <ScreenshareToggle />
60
+ {isHlsViewer ? <RaiseHand /> : null}
61
+ <EmojiReaction />
62
+ <LeaveRoom />
63
+ </>
64
+ )}
65
+ </AppFooter.Center>
66
+ <AppFooter.Right>
67
+ <ChatToggle />
68
+ <ParticipantCount />
69
+ <MoreSettings />
70
+ </AppFooter.Right>
71
+ </AppFooter.Root>
72
+ );
73
+ };
@@ -21,11 +21,11 @@ import {
21
21
  SpeakerIcon,
22
22
  VerticalMenuIcon,
23
23
  } from '@100mslive/react-icons';
24
- import { Avatar, Box, Dropdown, Flex, Input, Slider, Text, textEllipsis } from '../../../';
24
+ import { Avatar, Box, Dropdown, Flex, Input, Slider, Text, textEllipsis } from '../../..';
25
25
  import IconButton from '../../IconButton';
26
26
  import { ConnectionIndicator } from '../Connection/ConnectionIndicator';
27
+ import { ParticipantFilter } from '../Header/ParticipantFilter';
27
28
  import { RoleChangeModal } from '../RoleChangeModal';
28
- import { ParticipantFilter } from './ParticipantFilter';
29
29
  import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane';
30
30
  import { isInternalRole } from '../../common/utils';
31
31
  import { SIDE_PANE_OPTIONS } from '../../common/constants';
@@ -232,7 +232,7 @@ const ParticipantMoreActions = ({ onRoleChange, peerId }) => {
232
232
  const actions = useHMSActions();
233
233
  const [open, setOpen] = useState(false);
234
234
  return (
235
- <Dropdown.Root open={open} onOpenChange={value => setOpen(value)}>
235
+ <Dropdown.Root open={open} onOpenChange={value => setOpen(value)} modal={false}>
236
236
  <Dropdown.Trigger asChild data-testid="participant_more_actions" css={{ p: '$2', r: '$0' }} tabIndex={0}>
237
237
  <Text>
238
238
  <VerticalMenuIcon />
@@ -320,8 +320,8 @@ export const ParticipantSearch = ({ onSearch, placeholder }) => {
320
320
  </Box>
321
321
  <Input
322
322
  type="text"
323
- placeholder={placeholder || 'Find what you are looking for'}
324
- css={{ w: '100%', pl: '$14' }}
323
+ placeholder={placeholder || 'Search among participants'}
324
+ css={{ w: '100%', pl: '$14', bg: '$surface_bright' }}
325
325
  value={value}
326
326
  onKeyDown={event => {
327
327
  event.stopPropagation();
@@ -1,16 +1,31 @@
1
1
  import React from 'react';
2
- import { Flex } from '../../../';
3
- import { SpeakerTag } from './HeaderComponents';
4
- import { ParticipantCount } from './ParticipantList';
5
- import { StreamActions } from './StreamActions';
2
+ import { useMedia } from 'react-use';
3
+ import { HMSRoomState, selectRoomState, useHMSStore } from '@100mslive/react-sdk';
4
+ import { config as cssConfig, Flex } from '../../../';
5
+ import { Logo, SpeakerTag } from './HeaderComponents';
6
+ import { LiveStatus, RecordingStatus, StreamActions } from './StreamActions';
7
+ import { AudioOutputActions, CamaraFlipActions } from './common';
6
8
 
7
9
  export const ConferencingHeader = () => {
10
+ const roomState = useHMSStore(selectRoomState);
11
+ const isMobile = useMedia(cssConfig.media.md);
12
+ const isPreview = roomState === HMSRoomState.Preview;
13
+ // no header if there in preview
14
+ if (isPreview) {
15
+ return <></>;
16
+ }
8
17
  return (
9
18
  <Flex justify="between" align="center" css={{ position: 'relative', height: '100%' }}>
10
- <Flex align="center" css={{ position: 'absolute', left: '$10' }}>
19
+ <Flex align="center" gap="2" css={{ position: 'absolute', left: '$10' }}>
20
+ <Logo />
11
21
  <SpeakerTag />
22
+ {isMobile && (
23
+ <Flex align="center" css={{ gap: '$4' }}>
24
+ <LiveStatus />
25
+ <RecordingStatus />
26
+ </Flex>
27
+ )}
12
28
  </Flex>
13
-
14
29
  <Flex
15
30
  align="center"
16
31
  css={{
@@ -20,7 +35,12 @@ export const ConferencingHeader = () => {
20
35
  }}
21
36
  >
22
37
  <StreamActions />
23
- <ParticipantCount />
38
+ {isMobile && (
39
+ <>
40
+ <CamaraFlipActions />
41
+ <AudioOutputActions />
42
+ </>
43
+ )}
24
44
  </Flex>
25
45
  </Flex>
26
46
  );
@@ -2,25 +2,27 @@ import React from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import { selectDominantSpeaker, selectIsConnectedToRoom, useHMSStore } from '@100mslive/react-sdk';
4
4
  import { VolumeOneIcon } from '@100mslive/react-icons';
5
- import { config as cssConfig, Flex, styled, Text, textEllipsis } from '../../../';
5
+ import { config as cssConfig, Flex, styled, Text, textEllipsis, VerticalDivider } from '../../../';
6
6
  import { useRoomLayout } from '../../provider/roomLayoutProvider';
7
7
  import { isStreamingKit } from '../../common/utils';
8
8
 
9
9
  export const SpeakerTag = () => {
10
10
  const dominantSpeaker = useHMSStore(selectDominantSpeaker);
11
- return dominantSpeaker && dominantSpeaker.name ? (
12
- <Flex
13
- align="center"
14
- justify="center"
15
- css={{ flex: '1 1 0', color: '$on_primary_high', '@md': { display: 'none' } }}
16
- >
17
- <VolumeOneIcon />
18
- <Text variant="md" css={{ ...textEllipsis(200), ml: '$2' }} title={dominantSpeaker.name}>
19
- {dominantSpeaker.name}
20
- </Text>
21
- </Flex>
22
- ) : (
23
- <></>
11
+ return (
12
+ dominantSpeaker &&
13
+ dominantSpeaker.name && (
14
+ <Flex
15
+ align="center"
16
+ justify="center"
17
+ css={{ flex: '1 1 0', color: '$on_primary_high', '@md': { display: 'none' } }}
18
+ >
19
+ <VerticalDivider css={{ ml: '$8' }} />
20
+ <VolumeOneIcon />
21
+ <Text variant="md" css={{ ...textEllipsis(200), ml: '$2' }} title={dominantSpeaker.name}>
22
+ {dominantSpeaker.name}
23
+ </Text>
24
+ </Flex>
25
+ )
24
26
  );
25
27
  };
26
28
 
@@ -1,7 +1,8 @@
1
- import React, { Fragment, useState } from 'react';
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import {
4
4
  HMSRoomState,
5
+ selectHLSState,
5
6
  selectIsConnectedToRoom,
6
7
  selectPermissions,
7
8
  selectRoomState,
@@ -9,31 +10,65 @@ import {
9
10
  useHMSStore,
10
11
  useRecordingStreaming,
11
12
  } from '@100mslive/react-sdk';
12
- import { RecordIcon, WrenchIcon } from '@100mslive/react-icons';
13
- import { Box, Button, config as cssConfig, Flex, Loading, Popover, Text, Tooltip } from '../../../';
14
- import GoLiveButton from '../GoLiveButton';
13
+ import { AlertTriangleIcon, CrossIcon, RecordIcon } from '@100mslive/react-icons';
14
+ import { Box, Button, config as cssConfig, Flex, HorizontalDivider, Loading, Popover, Text, Tooltip } from '../../../';
15
+ import { Sheet } from '../../../Sheet';
15
16
  import { ResolutionInput } from '../Streaming/ResolutionInput';
16
17
  import { getResolution } from '../Streaming/RTMPStreaming';
17
18
  import { ToastManager } from '../Toast/ToastManager';
18
19
  import { AdditionalRoomState, getRecordingText } from './AdditionalRoomState';
19
- import { useSidepaneToggle } from '../AppData/useSidepane';
20
20
  import { useSetAppDataByKey } from '../AppData/useUISettings';
21
- import { APP_DATA, RTMP_RECORD_DEFAULT_RESOLUTION, SIDE_PANE_OPTIONS } from '../../common/constants';
21
+ import { formatTime } from '../../common/utils';
22
+ import { APP_DATA, RTMP_RECORD_DEFAULT_RESOLUTION } from '../../common/constants';
22
23
 
23
24
  export const LiveStatus = () => {
24
25
  const { isHLSRunning, isRTMPRunning } = useRecordingStreaming();
26
+ const hlsState = useHMSStore(selectHLSState);
27
+ const isMobile = useMedia(cssConfig.media.md);
28
+ const intervalRef = useRef(null);
29
+
30
+ const [liveTime, setLiveTime] = useState(0);
31
+
32
+ const startTimer = useCallback(() => {
33
+ intervalRef.current = setInterval(() => {
34
+ if (hlsState?.running) {
35
+ setLiveTime(Date.now() - hlsState?.variants[0]?.startedAt.getTime());
36
+ }
37
+ }, 1000);
38
+ }, [hlsState?.running, hlsState?.variants]);
39
+
40
+ useEffect(() => {
41
+ if (hlsState?.running) {
42
+ startTimer();
43
+ }
44
+ if (!hlsState?.running && intervalRef.current) {
45
+ clearInterval(intervalRef.current);
46
+ }
47
+ return () => {
48
+ if (intervalRef.current) {
49
+ clearInterval(intervalRef.current);
50
+ }
51
+ };
52
+ }, [hlsState.running, isMobile, startTimer]);
53
+
25
54
  if (!isHLSRunning && !isRTMPRunning) {
26
55
  return null;
27
56
  }
28
57
  return (
29
- <Flex align="center">
58
+ <Flex
59
+ align="center"
60
+ gap="1"
61
+ css={{
62
+ border: '1px solid $border_default',
63
+ padding: '$4 $6 $4 $6',
64
+ borderRadius: '$1',
65
+ }}
66
+ >
30
67
  <Box css={{ w: '$4', h: '$4', r: '$round', bg: '$alert_error_default', mr: '$2' }} />
31
- <Text>
32
- Live
33
- <Text as="span" css={{ '@md': { display: 'none' } }}>
34
- &nbsp;with {isHLSRunning ? 'HLS' : 'RTMP'}
35
- </Text>
36
- </Text>
68
+ <Flex align="center" gap="2">
69
+ <Text variant={!isMobile ? 'button' : 'body2'}>LIVE</Text>
70
+ <Text variant="caption">{hlsState?.variants?.length > 0 ? formatTime(liveTime) : ''}</Text>
71
+ </Flex>
37
72
  </Flex>
38
73
  );
39
74
  };
@@ -41,6 +76,7 @@ export const LiveStatus = () => {
41
76
  export const RecordingStatus = () => {
42
77
  const { isBrowserRecordingOn, isServerRecordingOn, isHLSRecordingOn, isRecordingOn } = useRecordingStreaming();
43
78
  const permissions = useHMSStore(selectPermissions);
79
+ const isMobile = useMedia(cssConfig.media.md);
44
80
 
45
81
  if (
46
82
  !isRecordingOn ||
@@ -50,8 +86,10 @@ export const RecordingStatus = () => {
50
86
  value => !!value,
51
87
  )
52
88
  ) {
53
- return null;
89
+ // show recording icon in mobile without popover
90
+ if (!(isMobile && isRecordingOn)) return null;
54
91
  }
92
+
55
93
  return (
56
94
  <Tooltip
57
95
  title={getRecordingText({
@@ -60,28 +98,18 @@ export const RecordingStatus = () => {
60
98
  isHLSRecordingOn,
61
99
  })}
62
100
  >
63
- <Box
101
+ <Flex
64
102
  css={{
65
103
  color: '$alert_error_default',
104
+ alignItems: 'center',
66
105
  }}
67
106
  >
68
107
  <RecordIcon width={24} height={24} />
69
- </Box>
108
+ </Flex>
70
109
  </Tooltip>
71
110
  );
72
111
  };
73
112
 
74
- const EndStream = () => {
75
- const toggleStreaming = useSidepaneToggle(SIDE_PANE_OPTIONS.STREAMING);
76
-
77
- return (
78
- <Button data-testid="end_stream" variant="danger" icon onClick={toggleStreaming}>
79
- <WrenchIcon />
80
- Manage Stream
81
- </Button>
82
- );
83
- };
84
-
85
113
  const StartRecording = () => {
86
114
  const permissions = useHMSStore(selectPermissions);
87
115
  const [resolution, setResolution] = useState(RTMP_RECORD_DEFAULT_RESOLUTION);
@@ -192,24 +220,61 @@ const StartRecording = () => {
192
220
  );
193
221
  };
194
222
 
223
+ /**
224
+ * @description only start recording button will be shown.
225
+ */
195
226
  export const StreamActions = () => {
196
227
  const isConnected = useHMSStore(selectIsConnectedToRoom);
197
- const permissions = useHMSStore(selectPermissions);
198
228
  const isMobile = useMedia(cssConfig.media.md);
199
- const { isStreamingOn } = useRecordingStreaming();
200
229
  const roomState = useHMSStore(selectRoomState);
201
230
 
202
231
  return (
203
232
  <Flex align="center" css={{ gap: '$4' }}>
204
233
  <AdditionalRoomState />
205
- <Flex align="center" css={{ gap: '$4', '@md': { display: 'none' } }}>
206
- {roomState !== HMSRoomState.Preview ? <LiveStatus /> : null}
207
- <RecordingStatus />
208
- </Flex>
209
- {isConnected && !isMobile ? <StartRecording /> : null}
210
- {isConnected && (permissions.hlsStreaming || permissions.rtmpStreaming) && (
211
- <Fragment>{isStreamingOn ? <EndStream /> : <GoLiveButton />}</Fragment>
234
+ {!isMobile && (
235
+ <Flex align="center" css={{ gap: '$4' }}>
236
+ <RecordingStatus />
237
+ {roomState !== HMSRoomState.Preview ? <LiveStatus /> : null}
238
+ </Flex>
212
239
  )}
240
+ {isConnected && !isMobile ? <StartRecording /> : null}
213
241
  </Flex>
214
242
  );
215
243
  };
244
+
245
+ export const StopRecordingInSheet = ({ onStopRecording, onClose }) => {
246
+ return (
247
+ <Sheet.Root open={true}>
248
+ <Sheet.Content>
249
+ <Sheet.Title css={{ p: '$10' }}>
250
+ <Flex direction="row" justify="between" css={{ w: '100%', c: '$alert_error_default' }}>
251
+ <Flex justify="start" align="center" gap="3">
252
+ <AlertTriangleIcon />
253
+ <Text variant="h5" css={{ c: '$alert_error_default' }}>
254
+ Stop Recording
255
+ </Text>
256
+ </Flex>
257
+ <Sheet.Close css={{ color: 'white' }} onClick={onClose}>
258
+ <CrossIcon />
259
+ </Sheet.Close>
260
+ </Flex>
261
+ </Sheet.Title>
262
+ <HorizontalDivider />
263
+ <Box as="div" css={{ p: '$10', overflowY: 'scroll', maxHeight: '70vh' }}>
264
+ <Text variant="caption" css={{ c: '$on_surface_medium', pb: '$8' }}>
265
+ Are you sure you want to stop recording? You can’t undo this action.
266
+ </Text>
267
+ <Button
268
+ variant="danger"
269
+ css={{ width: '100%' }}
270
+ type="submit"
271
+ data-testid="popup_change_btn"
272
+ onClick={onStopRecording}
273
+ >
274
+ Stop
275
+ </Button>
276
+ </Box>
277
+ </Sheet.Content>
278
+ </Sheet.Root>
279
+ );
280
+ };
@@ -2,10 +2,10 @@ import React from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import { config as cssConfig, Flex } from '../../../';
4
4
  import { EmojiReaction } from '../EmojiReaction';
5
+ import { ParticipantCount } from '../Footer/ParticipantList';
5
6
  import { LeaveRoom } from '../LeaveRoom';
6
7
  import MetaActions from '../MetaActions';
7
8
  import { SpeakerTag } from './HeaderComponents';
8
- import { ParticipantCount } from './ParticipantList';
9
9
  import { LiveStatus, RecordingStatus, StreamActions } from './StreamActions';
10
10
 
11
11
  export const StreamingHeader = () => {
@@ -0,0 +1,164 @@
1
+ import React from 'react';
2
+ import {
3
+ DeviceType,
4
+ selectIsLocalVideoEnabled,
5
+ selectLocalVideoTrackID,
6
+ selectVideoTrackByID,
7
+ useDevices,
8
+ useHMSActions,
9
+ useHMSStore,
10
+ } from '@100mslive/react-sdk';
11
+ import { CameraFlipIcon, CheckIcon, CrossIcon, SpeakerIcon } from '@100mslive/react-icons';
12
+ import { HorizontalDivider } from '../../../Divider';
13
+ import { Label } from '../../../Label';
14
+ import { Box, Flex } from '../../../Layout';
15
+ import { Sheet } from '../../../Sheet';
16
+ import { Text } from '../../../Text';
17
+ import IconButton from '../../IconButton';
18
+ import { ToastManager } from '../Toast/ToastManager';
19
+
20
+ export const CamaraFlipActions = () => {
21
+ const actions = useHMSActions();
22
+ const { allDevices } = useDevices();
23
+ const { videoInput } = allDevices;
24
+ const isVideoOn = useHMSStore(selectIsLocalVideoEnabled);
25
+
26
+ const videoTrackId = useHMSStore(selectLocalVideoTrackID);
27
+ const localVideoTrack = useHMSStore(selectVideoTrackByID(videoTrackId));
28
+
29
+ return (
30
+ <Box>
31
+ <IconButton
32
+ disabled={!videoInput?.length || !isVideoOn || !localVideoTrack?.facingMode}
33
+ onClick={async () => {
34
+ try {
35
+ await actions.switchCamera();
36
+ } catch (e) {
37
+ ToastManager.addToast({
38
+ title: `Error while flipping camera ${e.message || ''}`,
39
+ variant: 'error',
40
+ });
41
+ }
42
+ }}
43
+ >
44
+ <CameraFlipIcon />
45
+ </IconButton>
46
+ </Box>
47
+ );
48
+ };
49
+
50
+ export const AudioOutputActions = () => {
51
+ const { allDevices, selectedDeviceIDs, updateDevice } = useDevices();
52
+ const { audioOutput } = allDevices;
53
+ // don't show speaker selector where the API is not supported, and use
54
+ // a generic word("Audio") for Mic. In some cases(Chrome Android for e.g.) this changes both mic and speaker keeping them in sync.
55
+ const shouldShowAudioOutput = 'setSinkId' in HTMLMediaElement.prototype;
56
+
57
+ /**
58
+ * Chromium browsers return an audioOutput with empty label when no permissions are given
59
+ */
60
+ const audioOutputFiltered = audioOutput?.filter(item => !!item.label) ?? [];
61
+ if (!shouldShowAudioOutput || !audioOutputFiltered?.length > 0) {
62
+ return null;
63
+ }
64
+ return (
65
+ <AudioOutputSelectionSheet
66
+ outputDevices={audioOutput}
67
+ outputSelected={selectedDeviceIDs.outputDevices}
68
+ onChange={async deviceId => {
69
+ try {
70
+ await updateDevice({
71
+ deviceId,
72
+ deviceType: DeviceType.audioOutput,
73
+ });
74
+ } catch (e) {
75
+ ToastManager.addToast({
76
+ title: `Error while changing audio output ${e.message || ''}`,
77
+ variant: 'error',
78
+ });
79
+ }
80
+ }}
81
+ >
82
+ <Box>
83
+ <IconButton>
84
+ <SpeakerIcon />
85
+ </IconButton>
86
+ </Box>
87
+ </AudioOutputSelectionSheet>
88
+ );
89
+ };
90
+
91
+ const AudioOutputSelectionSheet = ({ outputDevices, outputSelected, onChange, children }) => {
92
+ return (
93
+ <Sheet.Root>
94
+ <Sheet.Trigger asChild>{children}</Sheet.Trigger>
95
+ <Sheet.Content>
96
+ <Sheet.Title css={{ py: '$10', px: '$8', alignItems: 'center' }}>
97
+ <Flex direction="row" justify="between" css={{ w: '100%' }}>
98
+ <Text variant="h6" css={{ display: 'flex' }}>
99
+ Audio Output
100
+ </Text>
101
+ <Sheet.Close>
102
+ <IconButton as="div" data-testid="dialog_cross_icon">
103
+ <CrossIcon />
104
+ </IconButton>
105
+ </Sheet.Close>
106
+ </Flex>
107
+ </Sheet.Title>
108
+ <HorizontalDivider />
109
+ <Flex
110
+ direction="column"
111
+ css={{
112
+ px: '$8',
113
+ maxHeight: '80vh',
114
+ overflowY: 'scroll',
115
+ }}
116
+ >
117
+ {outputDevices.map(audioDevice => {
118
+ return (
119
+ <SelectWithLabel
120
+ label={audioDevice.label}
121
+ id={audioDevice.deviceId}
122
+ checked={audioDevice.deviceId === outputSelected}
123
+ onChange={() => onChange(audioDevice.deviceId)}
124
+ />
125
+ );
126
+ })}
127
+ </Flex>
128
+ </Sheet.Content>
129
+ </Sheet.Root>
130
+ );
131
+ };
132
+
133
+ const SelectWithLabel = ({ label, icon = <></>, checked, id, onChange }) => {
134
+ return (
135
+ <Flex
136
+ align="center"
137
+ css={{
138
+ my: '$2',
139
+ py: '$8',
140
+ w: '100%',
141
+ borderBottom: '1px solid $border_default',
142
+ }}
143
+ onClick={onChange}
144
+ >
145
+ <Label
146
+ htmlFor={id}
147
+ css={{
148
+ fontSize: '$md',
149
+ fontWeight: '$semiBold',
150
+ color: checked ? '$on_surface_high' : '$on_surface_low',
151
+ cursor: 'pointer',
152
+ display: 'flex',
153
+ alignItems: 'center',
154
+ gap: '$8',
155
+ flex: '1 1 0',
156
+ }}
157
+ >
158
+ {icon}
159
+ {label}
160
+ </Label>
161
+ {checked && <CheckIcon width={24} height={24} />}
162
+ </Flex>
163
+ );
164
+ };
@@ -46,13 +46,12 @@ export const IconButtonWithOptions = ({
46
46
  onClick = () => {
47
47
  return;
48
48
  },
49
- key = '',
50
49
  }) => {
51
50
  const bgCss = { backgroundColor: active ? '$transparent' : '$secondary_dim' };
52
51
  const iconCss = { color: active ? '$on_surface_high' : '$on_primary_high' };
53
52
  return (
54
53
  <Flex>
55
- <IconSection css={bgCss} onClick={onClick} key={key}>
54
+ <IconSection css={bgCss} onClick={onClick}>
56
55
  <Tooltip disabled={!tooltipMessage} title={tooltipMessage}>
57
56
  <Flex align="center" justify="center" css={iconCss}>
58
57
  {icon}
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { Box, Flex } from '../../Layout';
3
+ import { Text } from '../../Text';
4
+
5
+ export const LeaveCard = ({ icon, title, subtitle, onClick, bg, titleColor, subtitleColor, css = {} }) => {
6
+ return (
7
+ <Flex css={{ p: '$10', flexGrow: 1, gap: '$8', bg, ...css }} onClick={onClick}>
8
+ <Box css={{ color: titleColor }}>{icon}</Box>
9
+ <Box css={{ gap: '$2' }}>
10
+ <Text variant="lg" css={{ color: titleColor }}>
11
+ {title}
12
+ </Text>
13
+ <Text variant="sm" css={{ color: subtitleColor }}>
14
+ {subtitle}
15
+ </Text>
16
+ </Box>
17
+ </Flex>
18
+ );
19
+ };