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

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 (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
  );