@100mslive/roomkit-react 0.1.6-alpha.0 → 0.1.6-alpha.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. package/dist/{HLSView-PY2FKWX3.js → HLSView-QMU5JK7U.js} +208 -118
  2. package/dist/HLSView-QMU5JK7U.js.map +7 -0
  3. package/dist/Prebuilt/AppContext.d.ts +1 -1
  4. package/dist/Prebuilt/components/Chat/ChatFooter.d.ts +7 -0
  5. package/dist/Prebuilt/components/Connection/ConnectionIndicator.d.ts +6 -0
  6. package/dist/Prebuilt/components/Connection/TileConnection.d.ts +10 -0
  7. package/dist/Prebuilt/components/Footer/ChatToggle.d.ts +2 -0
  8. package/dist/Prebuilt/components/Footer/RoleAccordion.d.ts +14 -0
  9. package/dist/Prebuilt/components/Footer/RoleOptions.d.ts +6 -0
  10. package/dist/Prebuilt/components/Header/StreamActions.d.ts +11 -0
  11. package/dist/Prebuilt/components/Leave/DesktopLeaveRoom.d.ts +4 -3
  12. package/dist/Prebuilt/components/Leave/EndSessionContent.d.ts +4 -3
  13. package/dist/Prebuilt/components/Leave/LeaveCard.d.ts +1 -2
  14. package/dist/Prebuilt/components/Leave/LeaveSessionContent.d.ts +3 -1
  15. package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +4 -3
  16. package/dist/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.d.ts +6 -0
  17. package/dist/Prebuilt/components/Preview/PreviewContainer.d.ts +3 -0
  18. package/dist/Prebuilt/components/Preview/PreviewJoin.d.ts +16 -0
  19. package/dist/Prebuilt/components/RoleChangeRequestModal.d.ts +2 -0
  20. package/dist/Prebuilt/components/SecondaryTiles.d.ts +1 -1
  21. package/dist/Prebuilt/components/SidePaneTabs.d.ts +7 -0
  22. package/dist/Prebuilt/components/VideoLayouts/EqualProminence.d.ts +1 -1
  23. package/dist/Prebuilt/components/VideoLayouts/Grid.d.ts +1 -0
  24. package/dist/Prebuilt/components/VideoLayouts/GridLayout.d.ts +5 -3
  25. package/dist/Prebuilt/components/VideoLayouts/ProminenceLayout.d.ts +6 -3
  26. package/dist/Prebuilt/components/VideoLayouts/RoleProminence.d.ts +1 -1
  27. package/dist/Prebuilt/components/VideoLayouts/ScreenshareLayout.d.ts +1 -1
  28. package/dist/Prebuilt/components/VideoLayouts/interface.d.ts +1 -0
  29. package/dist/Prebuilt/components/hooks/useAutoStartStreaming.d.ts +1 -0
  30. package/dist/Prebuilt/components/hooks/useRedirectToLeave.d.ts +3 -0
  31. package/dist/Prebuilt/components/hooks/useTileLayout.d.ts +2 -1
  32. package/dist/Prebuilt/components/hooks/useVideoTileLayout.d.ts +2 -0
  33. package/dist/Prebuilt/layouts/SidePane.d.ts +4 -1
  34. package/dist/Prebuilt/layouts/VideoStreamingSection.d.ts +2 -1
  35. package/dist/{VirtualBackground-AYDHYLIZ.js → VirtualBackground-37FXUPYO.js} +6 -6
  36. package/dist/VirtualBackground-37FXUPYO.js.map +7 -0
  37. package/dist/{chunk-GQD2AGWW.js → chunk-KBVIZGYW.js} +12 -2
  38. package/dist/{chunk-GQD2AGWW.js.map → chunk-KBVIZGYW.js.map} +2 -2
  39. package/dist/{chunk-RXTHJUMZ.js → chunk-WVGGQZK4.js} +986 -436
  40. package/dist/chunk-WVGGQZK4.js.map +7 -0
  41. package/dist/{chunk-E2M2ZSOL.js → chunk-ZKE2N5LH.js} +2 -2
  42. package/dist/{conference-V2XZGTKU.js → conference-FJJQ4TXX.js} +1136 -1301
  43. package/dist/conference-FJJQ4TXX.js.map +7 -0
  44. package/dist/index.cjs.js +3565 -3092
  45. package/dist/index.cjs.js.map +4 -4
  46. package/dist/index.js +2 -2
  47. package/dist/meta.cjs.json +773 -525
  48. package/dist/meta.esbuild.json +833 -579
  49. package/package.json +8 -7
  50. package/src/Prebuilt/App.tsx +10 -21
  51. package/src/Prebuilt/AppContext.tsx +1 -1
  52. package/src/Prebuilt/IconButton.jsx +10 -0
  53. package/src/Prebuilt/common/PeersSorter.ts +1 -1
  54. package/src/Prebuilt/common/constants.js +1 -2
  55. package/src/Prebuilt/common/utils.js +1 -1
  56. package/src/Prebuilt/components/AppData/AppData.jsx +8 -2
  57. package/src/Prebuilt/components/AppData/useUISettings.js +6 -6
  58. package/src/Prebuilt/components/AudioVideoToggle.jsx +8 -6
  59. package/src/Prebuilt/components/Chat/Chat.jsx +24 -11
  60. package/src/Prebuilt/components/Chat/ChatBody.jsx +20 -21
  61. package/src/Prebuilt/components/Chat/{ChatFooter.jsx → ChatFooter.tsx} +38 -13
  62. package/src/Prebuilt/components/Chat/useEmojiPickerStyles.js +5 -4
  63. package/src/Prebuilt/components/Connection/{ConnectionIndicator.jsx → ConnectionIndicator.tsx} +12 -4
  64. package/src/Prebuilt/components/Connection/{TileConnection.jsx → TileConnection.tsx} +20 -6
  65. package/src/Prebuilt/components/EmojiReaction.jsx +2 -6
  66. package/src/Prebuilt/components/Footer/{ChatToggle.jsx → ChatToggle.tsx} +4 -1
  67. package/src/Prebuilt/components/Footer/Footer.tsx +30 -5
  68. package/src/Prebuilt/components/Footer/ParticipantList.jsx +15 -49
  69. package/src/Prebuilt/components/Footer/{RoleAccordion.jsx → RoleAccordion.tsx} +33 -17
  70. package/src/Prebuilt/components/Footer/RoleOptions.tsx +155 -0
  71. package/src/Prebuilt/components/FullPageProgress.jsx +3 -3
  72. package/src/Prebuilt/components/HMSVideo/Controls.jsx +1 -0
  73. package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx +39 -17
  74. package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +2 -2
  75. package/src/Prebuilt/components/HMSVideo/VideoProgress.jsx +5 -6
  76. package/src/Prebuilt/components/HMSVideo/VolumeControl.jsx +1 -1
  77. package/src/Prebuilt/components/Header/HeaderComponents.jsx +8 -1
  78. package/src/Prebuilt/components/Header/{StreamActions.jsx → StreamActions.tsx} +23 -9
  79. package/src/Prebuilt/components/Header/common.jsx +5 -2
  80. package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.jsx +6 -1
  81. package/src/Prebuilt/components/InsetTile.tsx +15 -8
  82. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +21 -11
  83. package/src/Prebuilt/components/Leave/EndSessionContent.tsx +2 -5
  84. package/src/Prebuilt/components/Leave/LeaveCard.tsx +1 -3
  85. package/src/Prebuilt/components/Leave/LeaveRoom.tsx +28 -25
  86. package/src/Prebuilt/components/Leave/LeaveSessionContent.tsx +8 -2
  87. package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +8 -8
  88. package/src/Prebuilt/components/MoreSettings/ChangeNameContent.jsx +4 -0
  89. package/src/Prebuilt/components/MoreSettings/MoreSettings.tsx +1 -1
  90. package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +9 -23
  91. package/src/Prebuilt/components/MoreSettings/SplitComponents/{MwebOptions.jsx → MwebOptions.tsx} +89 -28
  92. package/src/Prebuilt/components/Notifications/Notifications.jsx +44 -28
  93. package/src/Prebuilt/components/Notifications/ReconnectNotifications.jsx +5 -11
  94. package/src/Prebuilt/components/Pagination.tsx +14 -12
  95. package/src/Prebuilt/components/Preview/{PreviewContainer.jsx → PreviewContainer.tsx} +11 -2
  96. package/src/Prebuilt/components/Preview/PreviewForm.tsx +6 -8
  97. package/src/Prebuilt/components/Preview/{PreviewJoin.jsx → PreviewJoin.tsx} +44 -21
  98. package/src/Prebuilt/components/{RoleChangeRequestModal.jsx → RoleChangeRequestModal.tsx} +36 -17
  99. package/src/Prebuilt/components/ScreenshareTile.jsx +6 -7
  100. package/src/Prebuilt/components/SecondaryTiles.tsx +12 -10
  101. package/src/Prebuilt/components/SidePaneTabs.tsx +120 -0
  102. package/src/Prebuilt/components/TileMenu/TileMenu.jsx +1 -1
  103. package/src/Prebuilt/components/TileMenu/TileMenuContent.jsx +14 -10
  104. package/src/Prebuilt/components/Toast/ToastConfig.jsx +5 -4
  105. package/src/Prebuilt/components/VideoLayouts/EqualProminence.tsx +13 -10
  106. package/src/Prebuilt/components/VideoLayouts/Grid.tsx +36 -34
  107. package/src/Prebuilt/components/VideoLayouts/GridLayout.tsx +33 -15
  108. package/src/Prebuilt/components/VideoLayouts/ProminenceLayout.tsx +45 -31
  109. package/src/Prebuilt/components/VideoLayouts/RoleProminence.tsx +12 -9
  110. package/src/Prebuilt/components/VideoLayouts/ScreenshareLayout.tsx +25 -9
  111. package/src/Prebuilt/components/VideoLayouts/interface.ts +1 -0
  112. package/src/Prebuilt/components/VideoTile.jsx +45 -53
  113. package/src/Prebuilt/components/conference.jsx +71 -74
  114. package/src/Prebuilt/components/hooks/useAutoStartStreaming.tsx +57 -0
  115. package/src/Prebuilt/components/hooks/useMetadata.jsx +19 -28
  116. package/src/Prebuilt/components/hooks/useRedirectToLeave.tsx +34 -0
  117. package/src/Prebuilt/components/hooks/useRoleProminencePeers.tsx +1 -1
  118. package/src/Prebuilt/components/hooks/useTileLayout.tsx +24 -18
  119. package/src/Prebuilt/components/hooks/useVideoTileLayout.ts +4 -0
  120. package/src/Prebuilt/layouts/EmbedView.jsx +1 -11
  121. package/src/Prebuilt/layouts/HLSView.jsx +152 -82
  122. package/src/Prebuilt/layouts/SidePane.tsx +25 -11
  123. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +11 -47
  124. package/src/Prebuilt/plugins/FlyingEmoji.jsx +14 -2
  125. package/src/Prebuilt/plugins/VirtualBackground/VirtualBackground.jsx +3 -3
  126. package/src/Prebuilt/provider/roomLayoutProvider/hooks/useFetchRoomLayout.ts +2 -2
  127. package/src/Prebuilt/services/FeatureFlags.jsx +0 -1
  128. package/src/VideoTile/StyledVideoTile.tsx +1 -0
  129. package/dist/HLSView-PY2FKWX3.js.map +0 -7
  130. package/dist/VirtualBackground-AYDHYLIZ.js.map +0 -7
  131. package/dist/chunk-RXTHJUMZ.js.map +0 -7
  132. package/dist/conference-V2XZGTKU.js.map +0 -7
  133. package/src/Prebuilt/components/AudioLevel/BeamSpeakerLabelsLogging.jsx +0 -16
  134. package/src/Prebuilt/components/Chat/ChatParticipantHeader.jsx +0 -73
  135. package/src/Prebuilt/components/VideoList.jsx +0 -73
  136. /package/dist/{chunk-E2M2ZSOL.js.map → chunk-ZKE2N5LH.js.map} +0 -0
@@ -0,0 +1,120 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { ConferencingScreen } from '@100mslive/types-prebuilt';
3
+ import { selectPeerCount, useHMSStore } from '@100mslive/react-sdk';
4
+ import { CrossIcon } from '@100mslive/react-icons';
5
+ // @ts-ignore: No implicit Any
6
+ import { Chat } from './Chat/Chat';
7
+ // @ts-ignore: No implicit Any
8
+ import { ParticipantList } from './Footer/ParticipantList';
9
+ import { Flex, IconButton, Tabs, Text } from '../..';
10
+ import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
11
+ // @ts-ignore: No implicit Any
12
+ import { useSidepaneReset, useSidepaneToggle } from './AppData/useSidepane';
13
+ // @ts-ignore: No implicit Any
14
+ import { SIDE_PANE_OPTIONS } from '../common/constants';
15
+
16
+ const tabTriggerCSS = {
17
+ color: '$on_surface_high',
18
+ p: '$4',
19
+ fontWeight: '$semiBold',
20
+ fontSize: '$sm',
21
+ w: '100%',
22
+ justifyContent: 'center',
23
+ };
24
+
25
+ export const SidePaneTabs = React.memo<{
26
+ active: 'Participants | Chat';
27
+ screenType: keyof ConferencingScreen;
28
+ hideControls?: boolean;
29
+ }>(({ active = SIDE_PANE_OPTIONS.CHAT, screenType, hideControls }) => {
30
+ const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT);
31
+ const toggleParticipants = useSidepaneToggle(SIDE_PANE_OPTIONS.PARTICIPANTS);
32
+ const resetSidePane = useSidepaneReset();
33
+ const [activeTab, setActiveTab] = useState(active);
34
+ const peerCount = useHMSStore(selectPeerCount);
35
+ const { elements } = useRoomLayoutConferencingScreen();
36
+ const showChat = !!elements?.chat;
37
+ const showParticipants = !!elements?.participant_list;
38
+ const hideTabs = !(showChat && showParticipants);
39
+
40
+ useEffect(() => {
41
+ if (activeTab === SIDE_PANE_OPTIONS.CHAT && !showChat && showParticipants) {
42
+ setActiveTab(SIDE_PANE_OPTIONS.PARTICIPANTS);
43
+ } else if (activeTab === SIDE_PANE_OPTIONS.PARTICIPANTS && showChat && !showParticipants) {
44
+ setActiveTab(SIDE_PANE_OPTIONS.CHAT);
45
+ } else if (!showChat && !showParticipants) {
46
+ resetSidePane();
47
+ }
48
+ }, [showChat, activeTab, showParticipants, resetSidePane]);
49
+
50
+ return (
51
+ <Flex
52
+ direction="column"
53
+ css={{
54
+ color: '$on_primary_high',
55
+ h: '100%',
56
+ }}
57
+ >
58
+ {hideTabs ? (
59
+ <>
60
+ <Text variant="sm" css={{ fontWeight: '$semiBold', p: '$4', c: '$on_surface_high', pr: '$12' }}>
61
+ {showChat ? 'Chat' : `Participants (${peerCount})`}
62
+ </Text>
63
+ {showChat ? <Chat screenType={screenType} hideControls={hideControls} /> : <ParticipantList />}
64
+ </>
65
+ ) : (
66
+ <Tabs.Root
67
+ value={activeTab}
68
+ onValueChange={setActiveTab}
69
+ css={{
70
+ flexDirection: 'column',
71
+ size: '100%',
72
+ }}
73
+ >
74
+ <Tabs.List css={{ w: 'calc(100% - $12)', p: '$2', borderRadius: '$2', bg: '$surface_default' }}>
75
+ <Tabs.Trigger
76
+ value={SIDE_PANE_OPTIONS.CHAT}
77
+ onClick={toggleChat}
78
+ css={{
79
+ ...tabTriggerCSS,
80
+ color: activeTab !== SIDE_PANE_OPTIONS.CHAT ? '$on_surface_low' : '$on_surface_high',
81
+ }}
82
+ >
83
+ Chat
84
+ </Tabs.Trigger>
85
+ <Tabs.Trigger
86
+ value={SIDE_PANE_OPTIONS.PARTICIPANTS}
87
+ onClick={toggleParticipants}
88
+ css={{
89
+ ...tabTriggerCSS,
90
+ color: activeTab !== SIDE_PANE_OPTIONS.PARTICIPANTS ? '$on_surface_low' : '$on_surface_high',
91
+ }}
92
+ >
93
+ Participants ({peerCount})
94
+ </Tabs.Trigger>
95
+ </Tabs.List>
96
+ <Tabs.Content value={SIDE_PANE_OPTIONS.PARTICIPANTS} css={{ p: 0 }}>
97
+ <ParticipantList />
98
+ </Tabs.Content>
99
+ <Tabs.Content value={SIDE_PANE_OPTIONS.CHAT} css={{ p: 0 }}>
100
+ <Chat screenType={screenType} hideControls={hideControls} />
101
+ </Tabs.Content>
102
+ </Tabs.Root>
103
+ )}
104
+ <IconButton
105
+ css={{ position: 'absolute', right: '$10', top: '$11' }}
106
+ onClick={e => {
107
+ e.stopPropagation();
108
+ if (activeTab === SIDE_PANE_OPTIONS.CHAT) {
109
+ toggleChat();
110
+ } else {
111
+ toggleParticipants();
112
+ }
113
+ }}
114
+ data-testid="close_chat"
115
+ >
116
+ <CrossIcon />
117
+ </IconButton>
118
+ </Flex>
119
+ );
120
+ });
@@ -73,7 +73,7 @@ const TileMenu = ({
73
73
  <StyledMenuTile.Root open={open} onOpenChange={setOpen}>
74
74
  <StyledMenuTile.Trigger
75
75
  data-testid="participant_menu_btn"
76
- css={{ bg: `${theme.colors.background_dim.value}A3` }}
76
+ css={{ bg: `${theme.colors.background_dim.value}A3`, p: '$2', w: 'unset', h: 'unset' }}
77
77
  onClick={e => e.stopPropagation()}
78
78
  className={isMobile ? '__cancel-drag-event' : ''}
79
79
  >
@@ -1,4 +1,5 @@
1
1
  import React, { Fragment } from 'react';
2
+ import { useMedia } from 'react-use';
2
3
  import {
3
4
  selectPermissions,
4
5
  selectSessionStore,
@@ -24,6 +25,7 @@ import {
24
25
  import { Box, Flex } from '../../../Layout';
25
26
  import { Slider } from '../../../Slider';
26
27
  import { Text } from '../../../Text';
28
+ import { config as cssConfig } from '../../../Theme';
27
29
  import { StyledMenuTile } from '../../../TileMenu';
28
30
  import { ToastManager } from '../Toast/ToastManager';
29
31
  import { useSetAppDataByKey } from '../AppData/useUISettings';
@@ -62,7 +64,7 @@ const SpotlightActions = ({
62
64
  onSpotLightClick();
63
65
  }}
64
66
  >
65
- <StarIcon />
67
+ <StarIcon height={20} width={20} />
66
68
  <span>{isTileSpotlighted ? 'Remove from Spotlight' : 'Spotlight Tile for everyone'}</span>
67
69
  </StyledMenuTile.ItemButton>
68
70
  );
@@ -83,7 +85,7 @@ const PinActions = ({ audioTrackID, videoTrackID }) => {
83
85
  css={spacingCSS}
84
86
  onClick={() => (isTilePinned ? setPinnedTrackId() : setPinnedTrackId(videoTrackID || audioTrackID))}
85
87
  >
86
- <PinIcon />
88
+ <PinIcon height={20} width={20} />
87
89
  <span>{isTilePinned ? 'Unpin' : 'Pin'} Tile for myself</span>
88
90
  </StyledMenuTile.ItemButton>
89
91
  </>
@@ -96,7 +98,7 @@ const MinimiseInset = () => {
96
98
  return (
97
99
  <>
98
100
  <StyledMenuTile.ItemButton css={spacingCSS} onClick={() => setMinimised(!minimised)}>
99
- <ShrinkIcon />
101
+ <ShrinkIcon height={20} width={20} />
100
102
  <span>{minimised ? 'Show' : 'Minimise'} your video</span>
101
103
  </StyledMenuTile.ItemButton>
102
104
  </>
@@ -210,6 +212,8 @@ export const TileMenuContent = props => {
210
212
  type: REMOTE_STOP_SCREENSHARE_TYPE,
211
213
  });
212
214
 
215
+ const isMobile = useMedia(cssConfig.media.md);
216
+
213
217
  return isLocal ? (
214
218
  (showPinAction || canMinimise) && (
215
219
  <>
@@ -222,7 +226,7 @@ export const TileMenuContent = props => {
222
226
  closeSheetOnClick();
223
227
  }}
224
228
  >
225
- <PencilIcon />
229
+ <PencilIcon height={20} width={20} />
226
230
  <Text variant="sm" css={{ '@md': { fontWeight: '$semiBold' }, c: '$on_surface_high' }}>
227
231
  Change Name
228
232
  </Text>
@@ -240,7 +244,7 @@ export const TileMenuContent = props => {
240
244
  }}
241
245
  data-testid={isVideoEnabled ? 'mute_video_participant_btn' : 'unmute_video_participant_btn'}
242
246
  >
243
- {isVideoEnabled ? <VideoOnIcon /> : <VideoOffIcon />}
247
+ {isVideoEnabled ? <VideoOnIcon height={20} width={20} /> : <VideoOffIcon height={20} width={20} />}
244
248
  <span>{isVideoEnabled ? 'Mute' : 'Request Unmute'}</span>
245
249
  </StyledMenuTile.ItemButton>
246
250
  ) : null}
@@ -254,7 +258,7 @@ export const TileMenuContent = props => {
254
258
  }}
255
259
  data-testid={isVideoEnabled ? 'mute_audio_participant_btn' : 'unmute_audio_participant_btn'}
256
260
  >
257
- {isAudioEnabled ? <MicOnIcon /> : <MicOffIcon />}
261
+ {isAudioEnabled ? <MicOnIcon height={20} width={20} /> : <MicOffIcon height={20} width={20} />}
258
262
  <span>{isAudioEnabled ? 'Mute' : 'Request Unmute'}</span>
259
263
  </StyledMenuTile.ItemButton>
260
264
  ) : null}
@@ -262,7 +266,7 @@ export const TileMenuContent = props => {
262
266
  {audioTrackID ? (
263
267
  <StyledMenuTile.VolumeItem data-testid="participant_volume_slider" css={{ ...spacingCSS, mb: '$0' }}>
264
268
  <Flex align="center" gap={1}>
265
- <SpeakerIcon />
269
+ <SpeakerIcon height={20} width={20} />
266
270
  <Box as="span" css={{ ml: '$4' }}>
267
271
  Volume ({volume})
268
272
  </Box>
@@ -278,7 +282,7 @@ export const TileMenuContent = props => {
278
282
  </>
279
283
  )}
280
284
 
281
- <SimulcastLayers trackId={videoTrackID} />
285
+ {isMobile ? null : <SimulcastLayers trackId={videoTrackID} />}
282
286
 
283
287
  {removeOthers ? (
284
288
  <StyledMenuTile.RemoveItem
@@ -293,7 +297,7 @@ export const TileMenuContent = props => {
293
297
  }}
294
298
  data-testid="remove_participant_btn"
295
299
  >
296
- <RemoveUserIcon />
300
+ <RemoveUserIcon height={20} width={20} />
297
301
  <span>Remove Participant</span>
298
302
  </StyledMenuTile.RemoveItem>
299
303
  ) : null}
@@ -306,7 +310,7 @@ export const TileMenuContent = props => {
306
310
  }}
307
311
  css={spacingCSS}
308
312
  >
309
- <ShareScreenIcon />
313
+ <ShareScreenIcon height={20} width={20} />
310
314
  <span>Stop Screenshare</span>
311
315
  </StyledMenuTile.RemoveItem>
312
316
  ) : null}
@@ -109,7 +109,7 @@ export const ToastConfig = {
109
109
  };
110
110
  },
111
111
  },
112
- METADATA_UPDATED: {
112
+ RAISE_HAND: {
113
113
  single: notification => {
114
114
  return {
115
115
  title: `${notification.data?.name} raised hand`,
@@ -118,10 +118,11 @@ export const ToastConfig = {
118
118
  };
119
119
  },
120
120
  multiple: notifications => {
121
+ const count = new Set(notifications.map(notification => notification.data?.id)).size;
121
122
  return {
122
- title: `${notifications[notifications.length - 1].data?.name} and ${
123
- notifications.length - 1
124
- } others raised hand`,
123
+ title: `${notifications[notifications.length - 1].data?.name} ${
124
+ count > 1 ? `${count} and others` : ''
125
+ } raised hand`,
125
126
  icon: <HandIcon />,
126
127
  action: <HandRaiseAction isSingleHandRaise={false} />,
127
128
  };
@@ -13,7 +13,7 @@ import { usePagesWithTiles, useTileLayout } from '../hooks/useTileLayout';
13
13
  // @ts-ignore: No implicit Any
14
14
  import { UI_SETTINGS } from '../../common/constants';
15
15
 
16
- export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, onPageSize }: LayoutProps) {
16
+ export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, onPageSize, edgeToEdge }: LayoutProps) {
17
17
  const localPeer = useHMSStore(selectLocalPeer);
18
18
  const isMobile = useMedia(cssConfig.media.md);
19
19
  let maxTileCount = useUISettings(UI_SETTINGS.maxTileCount);
@@ -35,6 +35,7 @@ export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, o
35
35
  const { ref, pagesWithTiles } = useTileLayout({
36
36
  pageList,
37
37
  maxTileCount,
38
+ edgeToEdge,
38
39
  });
39
40
  const [page, setPage] = useState(0);
40
41
  const pageSize = pagesWithTiles[0]?.length || 0;
@@ -47,15 +48,17 @@ export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, o
47
48
 
48
49
  return (
49
50
  <Flex direction="column" css={{ flex: '1 1 0', h: '100%', position: 'relative', minWidth: 0 }}>
50
- <Grid tiles={pagesWithTiles[page]} ref={ref} />
51
- <Pagination
52
- page={page}
53
- onPageChange={page => {
54
- setPage(page);
55
- onPageChange?.(page);
56
- }}
57
- numPages={pagesWithTiles.length}
58
- />
51
+ <Grid tiles={pagesWithTiles[page]} ref={ref} edgeToEdge={edgeToEdge} />
52
+ {!edgeToEdge && (
53
+ <Pagination
54
+ page={page}
55
+ onPageChange={page => {
56
+ setPage(page);
57
+ onPageChange?.(page);
58
+ }}
59
+ numPages={pagesWithTiles.length}
60
+ />
61
+ )}
59
62
  {isInsetEnabled && pageList.length > 0 && pageList[0][0].peer.id !== localPeer?.id && <InsetTile />}
60
63
  </Flex>
61
64
  );
@@ -5,37 +5,39 @@ import { Box } from '../../../Layout';
5
5
  import VideoTile from '../VideoTile';
6
6
  import { useVideoTileContext } from '../hooks/useVideoTileLayout';
7
7
 
8
- export const Grid = React.forwardRef<HTMLDivElement, { tiles: TrackWithPeerAndDimensions[] }>(({ tiles }, ref) => {
9
- const videoTileProps = useVideoTileContext();
10
- return (
11
- <Box
12
- ref={ref}
13
- css={{
14
- flex: '1 1 0',
15
- gap: '$4',
16
- py: '$4',
17
- display: 'flex',
18
- placeContent: 'center',
19
- alignItems: 'center',
20
- justifyContent: 'center',
21
- flexFlow: 'row wrap',
22
- minHeight: 0,
23
- }}
24
- >
25
- {tiles?.map(tile => {
26
- return (
27
- <VideoTile
28
- key={tile.track?.id || tile.peer?.id}
29
- width={tile.width}
30
- height={tile.height}
31
- peerId={tile.peer?.id}
32
- trackId={tile.track?.id}
33
- rootCSS={{ padding: 0 }}
34
- objectFit="contain"
35
- {...videoTileProps}
36
- />
37
- );
38
- })}
39
- </Box>
40
- );
41
- });
8
+ export const Grid = React.forwardRef<HTMLDivElement, { tiles: TrackWithPeerAndDimensions[]; edgeToEdge?: boolean }>(
9
+ ({ tiles, edgeToEdge }, ref) => {
10
+ const videoTileProps = useVideoTileContext();
11
+ return (
12
+ <Box
13
+ ref={ref}
14
+ css={{
15
+ flex: '1 1 0',
16
+ gap: '$4',
17
+ display: 'flex',
18
+ placeContent: 'center',
19
+ alignItems: 'center',
20
+ justifyContent: 'center',
21
+ flexFlow: 'row wrap',
22
+ minHeight: 0,
23
+ '@md': { gap: edgeToEdge ? 0 : '$4' },
24
+ }}
25
+ >
26
+ {tiles?.map(tile => {
27
+ return (
28
+ <VideoTile
29
+ key={tile.track?.id || tile.peer?.id}
30
+ width={tile.width}
31
+ height={tile.height}
32
+ peerId={tile.peer?.id}
33
+ trackId={tile.track?.id}
34
+ rootCSS={{ padding: 0 }}
35
+ objectFit="contain"
36
+ {...videoTileProps}
37
+ />
38
+ );
39
+ })}
40
+ </Box>
41
+ );
42
+ },
43
+ );
@@ -1,12 +1,6 @@
1
1
  import React, { useEffect, useMemo, useState } from 'react';
2
2
  import { GridVideoTileLayout } from '@100mslive/types-prebuilt/elements/video_tile_layout';
3
- import {
4
- selectPeers,
5
- selectPeerScreenSharing,
6
- selectRemotePeers,
7
- useHMSStore,
8
- useHMSVanillaStore,
9
- } from '@100mslive/react-sdk';
3
+ import { selectPeers, selectPeerScreenSharing, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
10
4
  import { EqualProminence } from './EqualProminence';
11
5
  import { RoleProminence } from './RoleProminence';
12
6
  import { ScreenshareLayout } from './ScreenshareLayout';
@@ -15,14 +9,17 @@ import { usePinnedTrack } from '../AppData/useUISettings';
15
9
  import { VideoTileContext } from '../hooks/useVideoTileLayout';
16
10
  import PeersSorter from '../../common/PeersSorter';
17
11
 
18
- export type GridLayoutProps = GridVideoTileLayout & {
12
+ export type TileCustomisationProps = {
19
13
  hide_participant_name_on_tile: boolean;
20
- hide_audio_level_on_tile: boolean;
21
14
  rounded_video_tile: boolean;
22
15
  hide_audio_mute_on_tile: boolean;
23
16
  video_object_fit: 'contain' | 'cover';
17
+ edge_to_edge: boolean;
18
+ hide_metadata_on_tile: boolean;
24
19
  };
25
20
 
21
+ export type GridLayoutProps = GridVideoTileLayout & TileCustomisationProps;
22
+
26
23
  export const GridLayout = ({
27
24
  enable_local_tile_inset: isInsetEnabled = false,
28
25
  prominent_roles: prominentRoles = [],
@@ -31,13 +28,26 @@ export const GridLayout = ({
31
28
  rounded_video_tile = true,
32
29
  hide_audio_mute_on_tile = false,
33
30
  video_object_fit = 'contain',
31
+ edge_to_edge = false,
32
+ hide_metadata_on_tile = false,
34
33
  }: GridLayoutProps) => {
35
34
  const peerSharing = useHMSStore(selectPeerScreenSharing);
36
35
  const pinnedTrack = usePinnedTrack();
37
- const isRoleProminence = prominentRoles.length > 0 || pinnedTrack;
38
- const peers = useHMSStore(isInsetEnabled && !isRoleProminence && !peerSharing ? selectRemotePeers : selectPeers);
36
+ const peers = useHMSStore(selectPeers);
37
+ const isRoleProminence =
38
+ (prominentRoles.length &&
39
+ peers.some(
40
+ peer => peer.roleName && prominentRoles.includes(peer.roleName) && (peer.videoTrack || peer.audioTrack),
41
+ )) ||
42
+ pinnedTrack;
43
+ const updatedPeers = useMemo(() => {
44
+ if (isInsetEnabled && !isRoleProminence && !peerSharing) {
45
+ return peers.filter(peer => !peer.isLocal);
46
+ }
47
+ return peers;
48
+ }, [isInsetEnabled, isRoleProminence, peerSharing, peers]);
39
49
  const vanillaStore = useHMSVanillaStore();
40
- const [sortedPeers, setSortedPeers] = useState(peers);
50
+ const [sortedPeers, setSortedPeers] = useState(updatedPeers);
41
51
  const peersSorter = useMemo(() => new PeersSorter(vanillaStore), [vanillaStore]);
42
52
  const [pageSize, setPageSize] = useState(0);
43
53
  const [mainPage, setMainPage] = useState(0);
@@ -46,6 +56,7 @@ export const GridLayout = ({
46
56
  hideParticipantNameOnTile: hide_participant_name_on_tile,
47
57
  roundedVideoTile: rounded_video_tile,
48
58
  hideAudioMuteOnTile: hide_audio_mute_on_tile,
59
+ hideMetadataOnTile: hide_metadata_on_tile,
49
60
  objectFit: video_object_fit,
50
61
  };
51
62
 
@@ -54,16 +65,21 @@ export const GridLayout = ({
54
65
  return;
55
66
  }
56
67
  peersSorter.setPeersAndTilesPerPage({
57
- peers,
68
+ peers: updatedPeers,
58
69
  tilesPerPage: pageSize,
59
70
  });
60
71
  peersSorter.onUpdate(setSortedPeers);
61
- }, [mainPage, peersSorter, peers, pageSize]);
72
+ }, [mainPage, peersSorter, updatedPeers, pageSize]);
62
73
 
63
74
  if (peerSharing) {
64
75
  return (
65
76
  <VideoTileContext.Provider value={tileLayout}>
66
- <ScreenshareLayout peers={sortedPeers} onPageSize={setPageSize} onPageChange={setMainPage} />
77
+ <ScreenshareLayout
78
+ peers={sortedPeers}
79
+ onPageSize={setPageSize}
80
+ onPageChange={setMainPage}
81
+ edgeToEdge={edge_to_edge}
82
+ />
67
83
  </VideoTileContext.Provider>
68
84
  );
69
85
  } else if (isRoleProminence) {
@@ -75,6 +91,7 @@ export const GridLayout = ({
75
91
  onPageChange={setMainPage}
76
92
  prominentRoles={prominentRoles}
77
93
  isInsetEnabled={isInsetEnabled}
94
+ edgeToEdge={edge_to_edge}
78
95
  />
79
96
  </VideoTileContext.Provider>
80
97
  );
@@ -86,6 +103,7 @@ export const GridLayout = ({
86
103
  onPageSize={setPageSize}
87
104
  onPageChange={setMainPage}
88
105
  isInsetEnabled={isInsetEnabled}
106
+ edgeToEdge={edge_to_edge}
89
107
  />
90
108
  </VideoTileContext.Provider>
91
109
  );
@@ -1,13 +1,16 @@
1
1
  import React from 'react';
2
2
  import { TrackWithPeerAndDimensions } from '@100mslive/react-sdk';
3
- import { Flex } from '../../../Layout';
3
+ import { Box, Flex } from '../../../Layout';
4
4
  import { CSS } from '../../../Theme';
5
5
  // @ts-ignore: No implicit Any
6
6
  import VideoTile from '../VideoTile';
7
7
  import { useVideoTileContext } from '../hooks/useVideoTileLayout';
8
8
 
9
- const Root = ({ children }: React.PropsWithChildren) => (
10
- <Flex direction="column" css={{ size: '100%', gap: '$6' }}>
9
+ const Root = ({ children, edgeToEdge }: React.PropsWithChildren<{ edgeToEdge?: boolean }>) => (
10
+ <Flex
11
+ direction="column"
12
+ css={{ h: '100%', flex: '1 1 0', minWidth: 0, gap: '$6', '@md': { gap: edgeToEdge ? 0 : '$6' } }}
13
+ >
11
14
  {children}
12
15
  </Flex>
13
16
  );
@@ -20,36 +23,47 @@ const ProminentSection = ({ children, css = {} }: React.PropsWithChildren<{ css?
20
23
  );
21
24
  };
22
25
 
23
- const SecondarySection = ({ tiles, children }: React.PropsWithChildren<{ tiles: TrackWithPeerAndDimensions[] }>) => {
26
+ const SecondarySection = ({
27
+ tiles,
28
+ children,
29
+ edgeToEdge,
30
+ }: React.PropsWithChildren<{ tiles: TrackWithPeerAndDimensions[]; edgeToEdge?: boolean }>) => {
24
31
  const tileLayoutProps = useVideoTileContext();
32
+ if (!tiles?.length) {
33
+ return null;
34
+ }
25
35
  return (
26
- <Flex direction="column" css={{ flexBasis: tiles?.length > 0 ? 154 : 0, minHeight: 0, gap: '$2' }}>
27
- <Flex justify="center" align="center" css={{ gap: '$4', minHeight: 0, margin: '0 auto' }}>
28
- {tiles?.map(tile => {
29
- return (
30
- <VideoTile
31
- key={tile.track?.id || tile.peer?.id}
32
- height="100%"
33
- peerId={tile.peer?.id}
34
- trackId={tile.track?.id}
35
- rootCSS={{
36
- padding: 0,
37
- flex: '1 1 0',
38
- maxWidth: 'max-content',
39
- }}
40
- containerCSS={{
41
- width: 'unset',
42
- aspectRatio: 16 / 9,
43
- '@md': { aspectRatio: 1 },
44
- }}
45
- objectFit="contain"
46
- {...tileLayoutProps}
47
- />
48
- );
49
- })}
50
- </Flex>
51
- {children}
52
- </Flex>
36
+ <Box
37
+ css={{
38
+ display: 'grid',
39
+ gridTemplateRows: React.Children.count(children) > 0 ? '136px auto' : '154px',
40
+ gridTemplateColumns: `repeat(${tiles.length}, minmax(0, 1fr))`,
41
+ margin: '0 auto',
42
+ gap: '$2 $4',
43
+ placeItems: 'center',
44
+ '@md': { gap: edgeToEdge ? 0 : '$4' },
45
+ }}
46
+ >
47
+ {tiles.map(tile => {
48
+ return (
49
+ <VideoTile
50
+ key={tile.track?.id || tile.peer?.id}
51
+ peerId={tile.peer?.id}
52
+ trackId={tile.track?.id}
53
+ rootCSS={{
54
+ padding: 0,
55
+ maxWidth: 240,
56
+ maxHeight: '100%',
57
+ aspectRatio: 16 / 9,
58
+ '@md': { aspectRatio: 1 },
59
+ }}
60
+ objectFit="contain"
61
+ {...tileLayoutProps}
62
+ />
63
+ );
64
+ })}
65
+ <Box css={{ gridColumn: `1/span ${tiles.length}` }}>{children}</Box>
66
+ </Box>
53
67
  );
54
68
  };
55
69
 
@@ -15,6 +15,7 @@ export function RoleProminence({
15
15
  peers,
16
16
  onPageChange,
17
17
  onPageSize,
18
+ edgeToEdge,
18
19
  }: LayoutProps) {
19
20
  const { prominentPeers, secondaryPeers } = useRoleProminencePeers(prominentRoles, peers, isInsetEnabled);
20
21
  const localPeer = useHMSStore(selectLocalPeer);
@@ -41,15 +42,17 @@ export function RoleProminence({
41
42
  <ProminenceLayout.ProminentSection>
42
43
  <Grid ref={ref} tiles={pagesWithTiles[page]} />
43
44
  </ProminenceLayout.ProminentSection>
44
- <Pagination
45
- page={page}
46
- onPageChange={page => {
47
- setPage(page);
48
- onPageChange?.(page);
49
- }}
50
- numPages={pagesWithTiles.length}
51
- />
52
- <SecondaryTiles peers={secondaryPeers} isInsetEnabled={isInsetEnabled} />
45
+ {!edgeToEdge && (
46
+ <Pagination
47
+ page={page}
48
+ onPageChange={page => {
49
+ setPage(page);
50
+ onPageChange?.(page);
51
+ }}
52
+ numPages={pagesWithTiles.length}
53
+ />
54
+ )}
55
+ <SecondaryTiles peers={secondaryPeers} isInsetEnabled={isInsetEnabled} edgeToEdge={edgeToEdge} />
53
56
  {isInsetEnabled && localPeer && !prominentPeers.includes(localPeer) && <InsetTile />}
54
57
  </ProminenceLayout.Root>
55
58
  );