@100mslive/roomkit-react 0.1.8-alpha.0 → 0.1.9-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/{HLSView-IQRPLYNH.js → HLSView-U53QN3AC.js} +3 -3
  2. package/dist/Modal/Dialog.d.ts +402 -1706
  3. package/dist/Prebuilt/App.d.ts +6 -0
  4. package/dist/Prebuilt/AppContext.d.ts +2 -0
  5. package/dist/Prebuilt/AppStateContext.d.ts +16 -0
  6. package/dist/Prebuilt/components/ConferenceScreen.d.ts +2 -0
  7. package/dist/Prebuilt/components/Footer/PaginatedParticipants.d.ts +5 -0
  8. package/dist/Prebuilt/components/Footer/PollsToggle.d.ts +2 -0
  9. package/dist/Prebuilt/components/Footer/RoleAccordion.d.ts +10 -3
  10. package/dist/Prebuilt/components/LeaveScreen.d.ts +2 -0
  11. package/dist/Prebuilt/components/MwebLandscapePrompt.d.ts +2 -0
  12. package/dist/Prebuilt/components/Notifications/AutoplayBlockedModal.d.ts +2 -0
  13. package/dist/Prebuilt/components/Notifications/HLSFailureModal.d.ts +2 -0
  14. package/dist/Prebuilt/components/Notifications/InitErrorModal.d.ts +2 -0
  15. package/dist/Prebuilt/components/Notifications/Notifications.d.ts +2 -0
  16. package/dist/Prebuilt/components/Notifications/PeerNotifications.d.ts +1 -0
  17. package/dist/Prebuilt/components/Notifications/PermissionErrorModal.d.ts +2 -0
  18. package/dist/Prebuilt/components/Notifications/ReconnectNotifications.d.ts +2 -0
  19. package/dist/Prebuilt/components/Notifications/TrackBulkUnmuteModal.d.ts +2 -0
  20. package/dist/Prebuilt/components/Notifications/TrackNotifications.d.ts +1 -0
  21. package/dist/Prebuilt/components/Notifications/TrackUnmuteModal.d.ts +2 -0
  22. package/dist/Prebuilt/components/Polls/Polls.d.ts +2 -0
  23. package/dist/Prebuilt/components/Preview/PreviewJoin.d.ts +1 -2
  24. package/dist/Prebuilt/components/Preview/PreviewScreen.d.ts +2 -0
  25. package/dist/Prebuilt/components/hooks/useRedirectToLeave.d.ts +1 -1
  26. package/dist/{VirtualBackground-GP4ATXD3.js → VirtualBackground-PMLQPJB6.js} +3 -5
  27. package/dist/{VirtualBackground-GP4ATXD3.js.map → VirtualBackground-PMLQPJB6.js.map} +1 -1
  28. package/dist/chunk-ANQRGVIX.js +14441 -0
  29. package/dist/chunk-ANQRGVIX.js.map +7 -0
  30. package/dist/{chunk-Z3O2WGWV.js → chunk-XQ2NRKIW.js} +66 -3
  31. package/dist/chunk-XQ2NRKIW.js.map +7 -0
  32. package/dist/context/DialogContext.d.ts +6 -0
  33. package/dist/hooks/useDialogContainerSelector.d.ts +1 -0
  34. package/dist/index.cjs.js +10956 -9818
  35. package/dist/index.cjs.js.map +4 -4
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +6 -2
  38. package/dist/meta.cjs.json +4076 -3201
  39. package/dist/meta.esbuild.json +4391 -3623
  40. package/dist/utils/animations.d.ts +11 -0
  41. package/package.json +6 -7
  42. package/src/AudioLevel/AudioLevel.tsx +1 -1
  43. package/src/Modal/Dialog.tsx +31 -3
  44. package/src/Prebuilt/App.tsx +49 -97
  45. package/src/Prebuilt/AppContext.tsx +6 -0
  46. package/src/Prebuilt/AppStateContext.tsx +71 -0
  47. package/src/Prebuilt/common/constants.js +36 -1
  48. package/src/Prebuilt/common/utils.js +47 -0
  49. package/src/Prebuilt/components/AppData/AppData.jsx +6 -1
  50. package/src/Prebuilt/components/AppData/useSidepane.js +23 -1
  51. package/src/Prebuilt/components/AppData/useUISettings.js +49 -5
  52. package/src/Prebuilt/components/Chip.tsx +6 -2
  53. package/src/Prebuilt/components/{conference.jsx → ConferenceScreen.tsx} +34 -46
  54. package/src/Prebuilt/components/Footer/Footer.tsx +5 -0
  55. package/src/Prebuilt/components/Footer/PaginatedParticipants.tsx +125 -0
  56. package/src/Prebuilt/components/Footer/ParticipantList.jsx +55 -24
  57. package/src/Prebuilt/components/Footer/PollsToggle.tsx +22 -0
  58. package/src/Prebuilt/components/Footer/RoleAccordion.tsx +87 -85
  59. package/src/Prebuilt/components/Footer/RoleOptions.tsx +1 -1
  60. package/src/Prebuilt/components/Header/StreamActions.tsx +5 -3
  61. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +4 -5
  62. package/src/Prebuilt/components/Leave/LeaveRoom.tsx +0 -4
  63. package/src/Prebuilt/components/{PostLeave.jsx → LeaveScreen.tsx} +6 -13
  64. package/src/Prebuilt/components/MoreSettings/ChangeNameModal.jsx +2 -3
  65. package/src/Prebuilt/components/MoreSettings/EmbedUrl.jsx +2 -3
  66. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +18 -1
  67. package/src/Prebuilt/components/{MwebLandscapePrompt.jsx → MwebLandscapePrompt.tsx} +10 -11
  68. package/src/Prebuilt/components/Notifications/{AutoplayBlockedModal.jsx → AutoplayBlockedModal.tsx} +2 -1
  69. package/src/Prebuilt/components/Notifications/{HLSFailureModal.jsx → HLSFailureModal.tsx} +10 -8
  70. package/src/Prebuilt/components/Notifications/{InitErrorModal.jsx → InitErrorModal.tsx} +5 -2
  71. package/src/Prebuilt/components/Notifications/{Notifications.jsx → Notifications.tsx} +41 -27
  72. package/src/Prebuilt/components/Notifications/{PeerNotifications.jsx → PeerNotifications.tsx} +3 -0
  73. package/src/Prebuilt/components/Notifications/{PermissionErrorModal.jsx → PermissionErrorModal.tsx} +6 -4
  74. package/src/Prebuilt/components/Notifications/{ReconnectNotifications.jsx → ReconnectNotifications.tsx} +11 -6
  75. package/src/Prebuilt/components/Notifications/{TrackBulkUnmuteModal.jsx → TrackBulkUnmuteModal.tsx} +9 -3
  76. package/src/Prebuilt/components/Notifications/{TrackUnmuteModal.jsx → TrackUnmuteModal.tsx} +9 -3
  77. package/src/Prebuilt/components/Notifications/index.tsx +1 -0
  78. package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.jsx +229 -0
  79. package/src/Prebuilt/components/Polls/CreatePollQuiz/Timer.jsx +71 -0
  80. package/src/Prebuilt/components/Polls/CreateQuestions/CreateQuestions.jsx +132 -0
  81. package/src/Prebuilt/components/Polls/CreateQuestions/DeleteQuestionModal.jsx +66 -0
  82. package/src/Prebuilt/components/Polls/CreateQuestions/QuestionForm.jsx +251 -0
  83. package/src/Prebuilt/components/Polls/CreateQuestions/SavedQuestion.jsx +57 -0
  84. package/src/Prebuilt/components/Polls/Polls.tsx +28 -0
  85. package/src/Prebuilt/components/Polls/Voting/PollResultSummary.jsx +125 -0
  86. package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +249 -0
  87. package/src/Prebuilt/components/Polls/Voting/StandardVoting.jsx +40 -0
  88. package/src/Prebuilt/components/Polls/Voting/TimedVoting.jsx +36 -0
  89. package/src/Prebuilt/components/Polls/Voting/Voting.jsx +99 -0
  90. package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +101 -0
  91. package/src/Prebuilt/components/Polls/common/OptionInputWithDelete.jsx +25 -0
  92. package/src/Prebuilt/components/Polls/common/SingleChoiceOptions.jsx +125 -0
  93. package/src/Prebuilt/components/Polls/common/StatusIndicator.jsx +47 -0
  94. package/src/Prebuilt/components/Polls/common/VoteCount.jsx +28 -0
  95. package/src/Prebuilt/components/Polls/common/VoteProgress.jsx +17 -0
  96. package/src/Prebuilt/components/Polls/common/VoterList.jsx +22 -0
  97. package/src/Prebuilt/components/Polls/common/Votes.jsx +72 -0
  98. package/src/Prebuilt/components/Preview/PreviewForm.tsx +3 -2
  99. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +29 -21
  100. package/src/Prebuilt/components/Preview/{PreviewContainer.tsx → PreviewScreen.tsx} +2 -19
  101. package/src/Prebuilt/components/RaiseHand.jsx +1 -1
  102. package/src/Prebuilt/components/RoleChangeModal.jsx +2 -3
  103. package/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +2 -3
  104. package/src/Prebuilt/components/Settings/SettingsModal.jsx +2 -3
  105. package/src/Prebuilt/components/Settings/StartRecording.jsx +15 -4
  106. package/src/Prebuilt/components/SidePaneTabs.tsx +32 -6
  107. package/src/Prebuilt/components/StatsForNerds.jsx +2 -3
  108. package/src/Prebuilt/components/Streaming/Common.jsx +31 -21
  109. package/src/Prebuilt/components/VideoLayouts/ScreenshareLayout.tsx +8 -9
  110. package/src/Prebuilt/components/VideoTile.jsx +28 -39
  111. package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +3 -3
  112. package/src/Prebuilt/components/hooks/useDropdownSelection.jsx +1 -1
  113. package/src/Prebuilt/components/hooks/useRedirectToLeave.tsx +9 -17
  114. package/src/Prebuilt/components/pdfAnnotator/pdfFileOptions.jsx +2 -3
  115. package/src/Prebuilt/components/pdfAnnotator/submitPdf.jsx +1 -1
  116. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +2 -3
  117. package/src/Prebuilt/layouts/EmbedView.jsx +47 -60
  118. package/src/Prebuilt/layouts/PDFView.jsx +49 -99
  119. package/src/Prebuilt/layouts/SidePane.tsx +9 -4
  120. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +2 -2
  121. package/src/Prebuilt/primitives/DialogContent.jsx +4 -5
  122. package/src/context/DialogContext.tsx +13 -0
  123. package/src/hooks/useDialogContainerSelector.tsx +7 -0
  124. package/src/index.ts +1 -0
  125. package/src/utils/animations.ts +6 -0
  126. package/dist/Prebuilt/components/PrebuiltDialogPortal.d.ts +0 -4
  127. package/dist/Prebuilt/components/Preview/PreviewContainer.d.ts +0 -3
  128. package/dist/chunk-2H5NIZB7.js +0 -70
  129. package/dist/chunk-2H5NIZB7.js.map +0 -7
  130. package/dist/chunk-GLYGPYNS.js +0 -7125
  131. package/dist/chunk-GLYGPYNS.js.map +0 -7
  132. package/dist/chunk-Z3O2WGWV.js.map +0 -7
  133. package/dist/conference-JD35TNH4.js +0 -6503
  134. package/dist/conference-JD35TNH4.js.map +0 -7
  135. package/src/Prebuilt/components/GoLiveButton.jsx +0 -42
  136. package/src/Prebuilt/components/PrebuiltDialogPortal.tsx +0 -6
  137. package/src/Prebuilt/components/Streaming/HLSStreaming.jsx +0 -220
  138. package/src/Prebuilt/components/Streaming/RTMPStreaming.jsx +0 -334
  139. package/src/Prebuilt/components/Streaming/StreamingLanding.jsx +0 -76
  140. /package/dist/{HLSView-IQRPLYNH.js.map → HLSView-U53QN3AC.js.map} +0 -0
  141. /package/{src/Prebuilt/components/Notifications/index.jsx → dist/Prebuilt/components/Notifications/index.d.ts} +0 -0
  142. /package/src/Prebuilt/components/Notifications/{TrackNotifications.jsx → TrackNotifications.tsx} +0 -0
@@ -0,0 +1,47 @@
1
+ // @ts-check
2
+ import React from 'react';
3
+ import { Flex, Text } from '../../../../';
4
+
5
+ export const StatusIndicator = ({ isLive, shouldShowTimer }) => {
6
+ return (
7
+ <Flex align="center">
8
+ <Flex
9
+ css={{
10
+ backgroundColor: isLive ? '$alert_error_default' : '$secondary_default',
11
+ p: '$2 $4',
12
+ borderRadius: shouldShowTimer ? '$0 0 0 $0' : '$0',
13
+ }}
14
+ >
15
+ <Text
16
+ variant="caption"
17
+ css={{
18
+ fontWeight: '$semiBold',
19
+ color: '$on_surface_high',
20
+ }}
21
+ >
22
+ {isLive ? 'LIVE' : 'ENDED'}
23
+ </Text>
24
+ </Flex>
25
+
26
+ {shouldShowTimer ? (
27
+ <Flex
28
+ css={{
29
+ borderRadius: '0 $0 $0 0',
30
+ p: '$2 $4',
31
+ backgroundColor: '$background_default',
32
+ }}
33
+ >
34
+ <Text
35
+ variant="caption"
36
+ css={{
37
+ fontWeight: '$semiBold',
38
+ color: '$on_surface_high',
39
+ }}
40
+ >
41
+ 0:32
42
+ </Text>
43
+ </Flex>
44
+ ) : null}
45
+ </Flex>
46
+ );
47
+ };
@@ -0,0 +1,28 @@
1
+ // @ts-check
2
+ import React from 'react';
3
+ import { Flex, Text } from '../../../../';
4
+
5
+ export const VoteCount = ({ isQuiz, voteCount, isCorrectAnswer }) => {
6
+ return (
7
+ <Flex css={{ alignItems: 'center' }}>
8
+ {isQuiz && (
9
+ <Text
10
+ variant="xs"
11
+ css={{
12
+ p: '$2',
13
+ mr: '$2',
14
+ color: isCorrectAnswer ? '$alert_success' : '$alert_error_default',
15
+ borderRadius: '$1',
16
+ border: `1px solid ${isCorrectAnswer ? '$alert_success' : '$alert_error_default'}`,
17
+ }}
18
+ >
19
+ {isCorrectAnswer ? 'Correct' : 'Incorrect'}
20
+ </Text>
21
+ )}
22
+ <Text variant="sm" css={{ color: '$on_surface_medium' }}>
23
+ {voteCount}&nbsp;
24
+ {voteCount === 1 ? 'vote' : 'votes'}
25
+ </Text>
26
+ </Flex>
27
+ );
28
+ };
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { Progress } from '../../../../';
3
+
4
+ export const VoteProgress = ({ option, totalResponses }) => {
5
+ const showProgress = typeof option.voteCount === 'number' && typeof totalResponses === 'number' && totalResponses > 0;
6
+ const progressValue = (100 * option.voteCount) / totalResponses;
7
+
8
+ return showProgress ? (
9
+ <Progress.Root value={progressValue}>
10
+ <Progress.Content
11
+ style={{
12
+ transform: `translateX(-${100 - progressValue}%)`,
13
+ }}
14
+ />
15
+ </Progress.Root>
16
+ ) : null;
17
+ };
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { Avatar, Flex, Text } from '../../../../';
3
+
4
+ export const VoterList = ({ voters }) => {
5
+ return voters.map((voter, index) => (
6
+ <Flex align="center" key={`${voter}-${index}`} css={{ gap: '$4', py: '$2' }}>
7
+ <Avatar
8
+ name={voter}
9
+ css={{
10
+ position: 'relative',
11
+ transform: 'unset',
12
+ fontSize: '$tiny',
13
+ size: '$9',
14
+ p: '$4',
15
+ }}
16
+ />
17
+ <Text variant="xs" css={{ color: '$on_surface_medium', fontWeight: '$semiBold' }}>
18
+ {voter}
19
+ </Text>
20
+ </Flex>
21
+ ));
22
+ };
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ import { Avatar, Box, Flex, Text, Tooltip } from '../../../../';
3
+ import { VoterList } from './VoterList';
4
+
5
+ // Shows number of votes, avatars of voters and list of voters on hover
6
+ export const Votes = ({ voters }) => {
7
+ const hiddenVotersCount = voters.length > 2 ? voters.length - 2 : 0;
8
+
9
+ return (
10
+ <Flex align="center" css={{ gap: '$4' }}>
11
+ <Text variant="sm" css={{ color: '$on_surface_medium' }}>
12
+ {voters.length}&nbsp;
13
+ {voters.length && voters.length !== 1 ? 'votes' : 'votes'}
14
+ </Text>
15
+ <Tooltip
16
+ side="bottom"
17
+ align="start"
18
+ disabled={hiddenVotersCount === 0}
19
+ boxCss={{
20
+ backgroundColor: '$surface_brighter',
21
+ borderRadius: '$1',
22
+ p: '$4 $6',
23
+ top: '$2',
24
+ zIndex: '20',
25
+ minWidth: '$44',
26
+ }}
27
+ title={<VoterList voters={voters} />}
28
+ >
29
+ <Flex align="center">
30
+ {voters.length
31
+ ? voters.slice(0, 2).map((voter, index) => (
32
+ <Avatar
33
+ name={voter}
34
+ css={{
35
+ position: 'relative',
36
+ transform: 'unset',
37
+ left: `${index * -1}px`,
38
+ fontSize: '$tiny',
39
+ size: '$9',
40
+ p: '$4',
41
+ zIndex: '5',
42
+ }}
43
+ />
44
+ ))
45
+ : null}
46
+ {hiddenVotersCount ? (
47
+ <Box
48
+ css={{
49
+ backgroundColor: '$secondary_default',
50
+ borderRadius: '$round',
51
+ position: 'relative',
52
+ left: '-$2',
53
+ p: '$2 $3',
54
+ }}
55
+ >
56
+ <Text
57
+ variant="caption"
58
+ css={{
59
+ fontWeight: '$semiBold',
60
+ color: '$on_surface_high',
61
+ fontSize: '$tiny',
62
+ }}
63
+ >
64
+ +{hiddenVotersCount}
65
+ </Text>
66
+ </Box>
67
+ ) : null}
68
+ </Flex>
69
+ </Tooltip>
70
+ </Flex>
71
+ );
72
+ };
@@ -27,10 +27,11 @@ const PreviewForm = ({
27
27
  e.preventDefault();
28
28
  };
29
29
  const isMobile = useMedia(cssConfig.media.md);
30
- const { isHLSRunning } = useRecordingStreaming();
30
+ const { isHLSRunning, isRTMPRunning } = useRecordingStreaming();
31
31
  const layout = useRoomLayout();
32
32
  const { join_form: joinForm = {} } = layout?.screens?.preview?.default?.elements || {};
33
- const showGoLive = joinForm?.join_btn_type === JoinForm_JoinBtnType.JOIN_BTN_TYPE_JOIN_AND_GO_LIVE && !isHLSRunning;
33
+ const showGoLive =
34
+ joinForm?.join_btn_type === JoinForm_JoinBtnType.JOIN_BTN_TYPE_JOIN_AND_GO_LIVE && !isHLSRunning && !isRTMPRunning;
34
35
 
35
36
  return (
36
37
  <Form
@@ -1,5 +1,5 @@
1
- import React, { Fragment, Suspense, useCallback, useEffect, useState } from 'react';
2
- import { useMedia } from 'react-use';
1
+ import React, { Fragment, Suspense, useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { useMeasure, useMedia } from 'react-use';
3
3
  import {
4
4
  HMSRoomState,
5
5
  selectIsLocalVideoEnabled,
@@ -38,7 +38,7 @@ import { useAuthToken, useUISettings } from '../AppData/useUISettings';
38
38
  // @ts-ignore: No implicit Any
39
39
  import { defaultPreviewPreference, UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences';
40
40
  // @ts-ignore: No implicit Any
41
- import { getFormattedCount } from '../../common/utils';
41
+ import { calculateAvatarAndAttribBoxSize, getFormattedCount } from '../../common/utils';
42
42
  // @ts-ignore: No implicit Any
43
43
  import { UI_SETTINGS } from '../../common/constants';
44
44
 
@@ -53,13 +53,24 @@ const getParticipantChipContent = (peerCount = 0) => {
53
53
  return `${formattedNum} other${parseInt(formattedNum) === 1 ? '' : 's'} in the session`;
54
54
  };
55
55
 
56
+ const useLocalTileAspectRatio = () => {
57
+ const localPeer = useHMSStore(selectLocalPeer);
58
+ const videoTrack = useHMSStore(selectVideoTrackByID(localPeer?.videoTrack));
59
+ const isMobile = useMedia(cssConfig.media.md);
60
+ let aspectRatio = 0;
61
+ if (videoTrack?.width && videoTrack?.height) {
62
+ aspectRatio = videoTrack.width / videoTrack.height;
63
+ } else {
64
+ aspectRatio = isMobile ? 9 / 16 : 16 / 9;
65
+ }
66
+ return aspectRatio;
67
+ };
68
+
56
69
  const PreviewJoin = ({
57
- onJoin,
58
70
  skipPreview,
59
71
  initialName,
60
72
  asRole,
61
73
  }: {
62
- onJoin: () => void;
63
74
  skipPreview?: boolean;
64
75
  initialName?: string;
65
76
  asRole?: string;
@@ -99,16 +110,11 @@ const PreviewJoin = ({
99
110
  name,
100
111
  });
101
112
  join();
102
- onJoin && onJoin();
103
- }, [join, name, setPreviewPreference, onJoin]);
113
+ }, [join, name, setPreviewPreference]);
104
114
  const roomLayout = useRoomLayout();
105
115
 
106
116
  const { preview_header: previewHeader = {} } = roomLayout?.screens?.preview?.default?.elements || {};
107
- const localPeer = useHMSStore(selectLocalPeer);
108
- const videoTrack = useHMSStore(selectVideoTrackByID(localPeer?.videoTrack));
109
- const isMobile = useMedia(cssConfig.media.md);
110
- const aspectRatio =
111
- videoTrack?.width && videoTrack?.height ? videoTrack.width / videoTrack.height : isMobile ? 9 / 16 : 16 / 9;
117
+ const aspectRatio = useLocalTileAspectRatio();
112
118
  useEffect(() => {
113
119
  if (authToken) {
114
120
  if (skipPreview) {
@@ -201,13 +207,16 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
201
207
  const trackSelector = selectVideoTrackByID(localPeer?.videoTrack);
202
208
  const track = useHMSStore(trackSelector);
203
209
  const showMuteIcon = !isLocalAudioEnabled || !toggleAudio;
204
- const videoTrack = useHMSStore(selectVideoTrackByID(localPeer?.videoTrack));
205
- const isMobile = useMedia(cssConfig.media.md);
206
- const aspectRatio =
207
- videoTrack?.width && videoTrack?.height ? videoTrack.width / videoTrack.height : isMobile ? 9 / 16 : 16 / 9;
210
+ const aspectRatio = useLocalTileAspectRatio();
211
+ const [ref, { width: calculatedWidth, height: calculatedHeight }] = useMeasure<HTMLDivElement>();
212
+ const [avatarSize, attribBoxSize] = useMemo(
213
+ () => calculateAvatarAndAttribBoxSize(calculatedWidth, calculatedHeight),
214
+ [calculatedWidth, calculatedHeight],
215
+ );
208
216
 
209
217
  return (
210
218
  <StyledVideoTile.Container
219
+ ref={ref}
211
220
  css={{
212
221
  bg: '$surface_default',
213
222
  aspectRatio,
@@ -232,20 +241,19 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
232
241
 
233
242
  {!isVideoOn ? (
234
243
  <StyledVideoTile.AvatarContainer>
235
- <Avatar name={name} data-testid="preview_avatar_tile" />
244
+ <Avatar name={name} data-testid="preview_avatar_tile" size={avatarSize} />
236
245
  </StyledVideoTile.AvatarContainer>
237
246
  ) : null}
238
247
  </>
239
- ) : !error ? (
240
- <FullPageProgress />
241
248
  ) : null}
249
+ {!localPeer && !error ? <FullPageProgress /> : null}
242
250
 
243
251
  {showMuteIcon ? (
244
- <StyledVideoTile.AudioIndicator>
252
+ <StyledVideoTile.AudioIndicator size={attribBoxSize}>
245
253
  <MicOffIcon />
246
254
  </StyledVideoTile.AudioIndicator>
247
255
  ) : (
248
- <StyledVideoTile.AudioIndicator size="medium">
256
+ <StyledVideoTile.AudioIndicator size={attribBoxSize}>
249
257
  <AudioLevel trackId={localPeer?.audioTrack} />
250
258
  </StyledVideoTile.AudioIndicator>
251
259
  )}
@@ -1,5 +1,4 @@
1
1
  import React from 'react';
2
- import { useNavigate, useParams } from 'react-router-dom';
3
2
  import { useSearchParam } from 'react-use';
4
3
  import { Flex } from '../../..';
5
4
  import { useHMSPrebuiltContext } from '../../AppContext';
@@ -14,25 +13,16 @@ import { useAuthToken } from '../AppData/useUISettings';
14
13
  // @ts-ignore: No implicit Any
15
14
  import { QUERY_PARAM_PREVIEW_AS_ROLE } from '../../common/constants';
16
15
 
17
- const PreviewContainer = () => {
18
- const navigate = useNavigate();
16
+ export const PreviewScreen = () => {
19
17
  const { isPreviewScreenEnabled } = useRoomLayoutPreviewScreen();
20
18
  const skipPreview = !isPreviewScreenEnabled;
21
19
  const previewAsRole = useSearchParam(QUERY_PARAM_PREVIEW_AS_ROLE);
22
20
  const { userName } = useHMSPrebuiltContext();
23
21
  const initialName = userName || (skipPreview ? 'Beam' : '');
24
- const { roomId: urlRoomId, role: userRole } = useParams(); // from the url
25
22
  const authToken = useAuthToken();
26
23
  const roomLayout = useRoomLayout();
27
24
  const { preview_header: previewHeader = {} } = roomLayout?.screens?.preview?.default?.elements || {};
28
25
 
29
- const onJoin = () => {
30
- let meetingURL = `/meeting/${urlRoomId}`;
31
- if (userRole) {
32
- meetingURL += `/${userRole}`;
33
- }
34
- navigate(meetingURL);
35
- };
36
26
  return (
37
27
  <Flex direction="column" css={{ size: '100%' }}>
38
28
  <Flex
@@ -41,12 +31,7 @@ const PreviewContainer = () => {
41
31
  align="center"
42
32
  >
43
33
  {authToken && Object.keys(previewHeader).length > 0 ? (
44
- <PreviewJoin
45
- initialName={initialName}
46
- skipPreview={skipPreview}
47
- asRole={previewAsRole ?? undefined}
48
- onJoin={onJoin}
49
- />
34
+ <PreviewJoin initialName={initialName} skipPreview={skipPreview} asRole={previewAsRole ?? undefined} />
50
35
  ) : (
51
36
  <FullPageProgress />
52
37
  )}
@@ -54,5 +39,3 @@ const PreviewContainer = () => {
54
39
  </Flex>
55
40
  );
56
41
  };
57
-
58
- export default PreviewContainer;
@@ -9,7 +9,7 @@ export const RaiseHand = () => {
9
9
  const { isHandRaised, toggleHandRaise } = useMyMetadata();
10
10
  return (
11
11
  <Tooltip title={isHandRaised ? 'Lower hand' : 'Raise hand'}>
12
- <IconButton active={!isHandRaised} onClick={async () => await toggleHandRaise()}>
12
+ <IconButton data-testid="hand_raise_btn" active={!isHandRaised} onClick={async () => await toggleHandRaise()}>
13
13
  <HandIcon />
14
14
  </IconButton>
15
15
  </Tooltip>
@@ -9,7 +9,6 @@ import { Box, Flex } from '../../Layout';
9
9
  import { Dialog } from '../../Modal';
10
10
  import { Text } from '../../Text';
11
11
  import { Tooltip } from '../../Tooltip';
12
- import { PrebuiltDialogPortal } from './PrebuiltDialogPortal';
13
12
  import { useDropdownSelection } from './hooks/useDropdownSelection';
14
13
  import { useFilteredRoles } from '../common/hooks';
15
14
  import { textEllipsis } from '../../utils';
@@ -48,7 +47,7 @@ export const RoleChangeModal = ({ peerId, onOpenChange }) => {
48
47
  const peerNameMaxWidth = 200;
49
48
  return (
50
49
  <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
51
- <PrebuiltDialogPortal>
50
+ <Dialog.Portal>
52
51
  <Dialog.Overlay />
53
52
  <Dialog.Content css={{ width: 'min(400px,80%)', p: '$10' }}>
54
53
  <Dialog.Title css={{ p: 0 }} asChild>
@@ -180,7 +179,7 @@ export const RoleChangeModal = ({ peerId, onOpenChange }) => {
180
179
  </Box>
181
180
  </Flex>
182
181
  </Dialog.Content>
183
- </PrebuiltDialogPortal>
182
+ </Dialog.Portal>
184
183
  </Dialog.Root>
185
184
  );
186
185
  };
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import { Box, Button, config as cssConfig, Dialog, Flex, Text } from '../../..';
4
4
  import { Sheet } from '../../../Sheet';
5
- import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
6
5
 
7
6
  export const RequestPrompt = ({
8
7
  open = true,
@@ -35,7 +34,7 @@ export const RequestPrompt = ({
35
34
 
36
35
  return (
37
36
  <Dialog.Root open={open} onOpenChange={onOpenChange}>
38
- <PrebuiltDialogPortal>
37
+ <Dialog.Portal>
39
38
  <Dialog.Overlay />
40
39
  <Dialog.Content css={{ p: '$10' }}>
41
40
  <Dialog.Title css={{ p: 0, display: 'flex', flexDirection: 'row', gap: '$md', justifyContent: 'center' }}>
@@ -44,7 +43,7 @@ export const RequestPrompt = ({
44
43
  <Box css={{ mt: '$4', mb: '$10' }}>{body}</Box>
45
44
  <RequestActions actionText={actionText} onAction={onAction} />
46
45
  </Dialog.Content>
47
- </PrebuiltDialogPortal>
46
+ </Dialog.Portal>
48
47
  </Dialog.Root>
49
48
  );
50
49
  };
@@ -9,7 +9,6 @@ import { Sheet } from '../../../Sheet';
9
9
  import { Tabs } from '../../../Tabs';
10
10
  import { Text } from '../../../Text';
11
11
  import { config as cssConfig } from '../../../Theme';
12
- import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
13
12
  import { settingContent, settingsList } from './common.js';
14
13
 
15
14
  const SettingsModal = ({ open, onOpenChange, screenType, children = <></> }) => {
@@ -187,7 +186,7 @@ const DesktopSettingModal = ({
187
186
  return (
188
187
  <Dialog.Root open={open} onOpenChange={onOpenChange}>
189
188
  <Dialog.Trigger asChild>{children}</Dialog.Trigger>
190
- <PrebuiltDialogPortal>
189
+ <Dialog.Portal>
191
190
  <Dialog.Overlay />
192
191
  <Dialog.Content
193
192
  css={{
@@ -257,7 +256,7 @@ const DesktopSettingModal = ({
257
256
  </IconButton>
258
257
  </Dialog.Close>
259
258
  </Dialog.Content>
260
- </PrebuiltDialogPortal>
259
+ </Dialog.Portal>
261
260
  </Dialog.Root>
262
261
  );
263
262
  };
@@ -2,13 +2,24 @@ import React, { useState } from 'react';
2
2
  import { selectPermissions, useHMSActions, useHMSStore, useRecordingStreaming } from '@100mslive/react-sdk';
3
3
  import { AlertTriangleIcon } from '@100mslive/react-icons';
4
4
  import { Button, Dialog, Flex, Text } from '../../../';
5
- import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
6
5
  import { ResolutionInput } from '../Streaming/ResolutionInput';
7
- import { getResolution } from '../Streaming/RTMPStreaming';
8
6
  import { ToastManager } from '../Toast/ToastManager';
9
7
  import { useSetAppDataByKey } from '../AppData/useUISettings';
10
8
  import { APP_DATA, RTMP_RECORD_DEFAULT_RESOLUTION } from '../../common/constants';
11
9
 
10
+ export function getResolution(recordingResolution) {
11
+ const resolution = {};
12
+ if (recordingResolution.width) {
13
+ resolution.width = recordingResolution.width;
14
+ }
15
+ if (recordingResolution.height) {
16
+ resolution.height = recordingResolution.height;
17
+ }
18
+ if (Object.keys(resolution).length > 0) {
19
+ return resolution;
20
+ }
21
+ }
22
+
12
23
  const StartRecording = ({ open, onOpenChange }) => {
13
24
  const permissions = useHMSStore(selectPermissions);
14
25
  const [resolution, setResolution] = useState(RTMP_RECORD_DEFAULT_RESOLUTION);
@@ -22,7 +33,7 @@ const StartRecording = ({ open, onOpenChange }) => {
22
33
  if (isBrowserRecordingOn) {
23
34
  return (
24
35
  <Dialog.Root open={open} onOpenChange={onOpenChange}>
25
- <PrebuiltDialogPortal>
36
+ <Dialog.Portal>
26
37
  <Dialog.Content
27
38
  css={{
28
39
  width: 'min(400px,80%)',
@@ -67,7 +78,7 @@ const StartRecording = ({ open, onOpenChange }) => {
67
78
  </Button>
68
79
  </Flex>
69
80
  </Dialog.Content>
70
- </PrebuiltDialogPortal>
81
+ </Dialog.Portal>
71
82
  </Dialog.Root>
72
83
  );
73
84
  }
@@ -1,13 +1,14 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { useMedia } from 'react-use';
3
- import { ConferencingScreen } from '@100mslive/types-prebuilt';
3
+ import { ConferencingScreen, DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
4
4
  import { selectPeerCount, useHMSStore } from '@100mslive/react-sdk';
5
5
  import { CrossIcon } from '@100mslive/react-icons';
6
6
  // @ts-ignore: No implicit Any
7
7
  import { Chat } from './Chat/Chat';
8
+ import { PaginatedParticipants } from './Footer/PaginatedParticipants';
8
9
  // @ts-ignore: No implicit Any
9
10
  import { ParticipantList } from './Footer/ParticipantList';
10
- import { config as cssConfig, Flex, IconButton, Tabs, Text } from '../..';
11
+ import { Box, config as cssConfig, Flex, IconButton, Tabs, Text } from '../..';
11
12
  import { Tooltip } from '../../Tooltip';
12
13
  // @ts-ignore: No implicit Any
13
14
  import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
@@ -46,6 +47,7 @@ export const SidePaneTabs = React.memo<{
46
47
  const toggleParticipants = useSidepaneToggle(SIDE_PANE_OPTIONS.PARTICIPANTS);
47
48
  const resetSidePane = useSidepaneReset();
48
49
  const [activeTab, setActiveTab] = useState(active);
50
+ const [activeRole, setActiveRole] = useState('');
49
51
  const peerCount = useHMSStore(selectPeerCount);
50
52
  const { elements } = useRoomLayoutConferencingScreen();
51
53
  const showChat = !!elements?.chat;
@@ -53,6 +55,7 @@ export const SidePaneTabs = React.memo<{
53
55
  const hideTabs = !(showChat && showParticipants);
54
56
  const isMobile = useMedia(cssConfig.media.md);
55
57
  const isOverlayChat = !!elements?.chat?.is_overlay && isMobile;
58
+ const { off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {};
56
59
  const isChatOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.CHAT);
57
60
 
58
61
  useEffect(() => {
@@ -69,6 +72,25 @@ export const SidePaneTabs = React.memo<{
69
72
  setActiveTab(active);
70
73
  }, [active]);
71
74
 
75
+ if (activeRole) {
76
+ return (
77
+ <Flex
78
+ direction="column"
79
+ css={{
80
+ color: '$on_primary_high',
81
+ h: '100%',
82
+ marginTop: hideControls && isOverlayChat ? '$17' : '0',
83
+ transition: 'margin 0.3s ease-in-out',
84
+ position: 'relative',
85
+ }}
86
+ >
87
+ <Box css={{ position: 'absolute', left: 0, top: 0, size: '100%', zIndex: 21, bg: '$surface_dim' }}>
88
+ <PaginatedParticipants roleName={activeRole} onBack={() => setActiveRole('')} />
89
+ </Box>
90
+ </Flex>
91
+ );
92
+ }
93
+
72
94
  return (
73
95
  <Flex
74
96
  direction="column"
@@ -95,7 +117,11 @@ export const SidePaneTabs = React.memo<{
95
117
  )}
96
118
  </Text>
97
119
 
98
- {showChat ? <Chat screenType={screenType} /> : <ParticipantList />}
120
+ {showChat ? (
121
+ <Chat screenType={screenType} />
122
+ ) : (
123
+ <ParticipantList offStageRoles={off_stage_roles} onActive={setActiveRole} />
124
+ )}
99
125
  </>
100
126
  ) : (
101
127
  <Tabs.Root
@@ -125,11 +151,11 @@ export const SidePaneTabs = React.memo<{
125
151
  color: activeTab !== SIDE_PANE_OPTIONS.PARTICIPANTS ? '$on_surface_low' : '$on_surface_high',
126
152
  }}
127
153
  >
128
- Participants <ParticipantCount count={peerCount} />
154
+ Participants &nbsp; <ParticipantCount count={peerCount} />
129
155
  </Tabs.Trigger>
130
156
  </Tabs.List>
131
157
  <Tabs.Content value={SIDE_PANE_OPTIONS.PARTICIPANTS} css={{ p: 0 }}>
132
- <ParticipantList />
158
+ <ParticipantList offStageRoles={off_stage_roles} onActive={setActiveRole} />
133
159
  </Tabs.Content>
134
160
  <Tabs.Content value={SIDE_PANE_OPTIONS.CHAT} css={{ p: 0 }}>
135
161
  <Chat screenType={screenType} />
@@ -141,7 +167,7 @@ export const SidePaneTabs = React.memo<{
141
167
 
142
168
  {isOverlayChat && isChatOpen ? null : (
143
169
  <IconButton
144
- css={{ position: 'absolute', right: '$10', top: '$11', '@md': { top: '$8', right: '$8' } }}
170
+ css={{ position: 'absolute', right: '$9', top: '$11', '@md': { top: '$8', right: '$6' } }}
145
171
  onClick={e => {
146
172
  e.stopPropagation();
147
173
  if (activeTab === SIDE_PANE_OPTIONS.CHAT) {
@@ -15,7 +15,6 @@ import { Dialog } from '../../Modal';
15
15
  import { Switch } from '../../Switch';
16
16
  import { Text } from '../../Text';
17
17
  import { DialogDropdownTrigger } from '../primitives/DropdownTrigger';
18
- import { PrebuiltDialogPortal } from './PrebuiltDialogPortal';
19
18
  import { useSetUiSettings } from './AppData/useUISettings';
20
19
  import { useDropdownSelection } from './hooks/useDropdownSelection';
21
20
  import { UI_SETTINGS } from '../common/constants';
@@ -40,7 +39,7 @@ export const StatsForNerds = ({ onOpenChange }) => {
40
39
 
41
40
  return (
42
41
  <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
43
- <PrebuiltDialogPortal>
42
+ <Dialog.Portal>
44
43
  <Dialog.Overlay />
45
44
  <Dialog.Content
46
45
  css={{
@@ -119,7 +118,7 @@ export const StatsForNerds = ({ onOpenChange }) => {
119
118
  <TrackStats trackID={selectedStat.id} layer={selectedStat.layer} local={selectedStat.local} />
120
119
  )}
121
120
  </Dialog.Content>
122
- </PrebuiltDialogPortal>
121
+ </Dialog.Portal>
123
122
  </Dialog.Root>
124
123
  );
125
124
  };