@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
@@ -10,7 +10,6 @@ import {
10
10
  import { config as cssConfig } from '../../../Theme';
11
11
 
12
12
  const aspectRatioConfig = { default: [1 / 1, 4 / 3, 16 / 9], mobile: [1 / 1, 3 / 4, 9 / 16] };
13
- const gap = 8; // gap between flex items
14
13
 
15
14
  export const usePagesWithTiles = ({ peers, maxTileCount }: { peers: HMSPeer[]; maxTileCount: number }) => {
16
15
  const vanillaStore = useHMSVanillaStore();
@@ -39,9 +38,11 @@ export const usePagesWithTiles = ({ peers, maxTileCount }: { peers: HMSPeer[]; m
39
38
  export const useTileLayout = ({
40
39
  pageList,
41
40
  maxTileCount,
41
+ edgeToEdge = false,
42
42
  }: {
43
43
  pageList: TrackWithPeerAndDimensions[][];
44
44
  maxTileCount: number;
45
+ edgeToEdge?: boolean;
45
46
  }) => {
46
47
  const vanillaStore = useHMSVanillaStore();
47
48
  const [ref, { width, height }] = useMeasure<HTMLDivElement>();
@@ -76,6 +77,7 @@ export const useTileLayout = ({
76
77
  return rowElements;
77
78
  });
78
79
 
80
+ const gap = edgeToEdge && isMobile ? 0 : 8; // gap between flex items
79
81
  const maxHeight = height - (maxRows - 1) * gap;
80
82
  const maxRowHeight = maxHeight / matrix.length;
81
83
  const aspectRatios =
@@ -86,25 +88,29 @@ export const useTileLayout = ({
86
88
  for (const row of matrix) {
87
89
  let tileWidth = (width - (row.length - 1) * gap) / row.length;
88
90
  let tileHeight = 0;
89
- const calcHeights = aspectRatios.map(aR => tileWidth / aR);
90
- for (const h of calcHeights) {
91
- if (h < maxRowHeight) {
92
- if (tileHeight < h) {
93
- tileHeight = h;
91
+ if (edgeToEdge) {
92
+ tileHeight = maxRowHeight;
93
+ } else {
94
+ const calcHeights = aspectRatios.map(aR => tileWidth / aR);
95
+ for (const h of calcHeights) {
96
+ if (h < maxRowHeight) {
97
+ if (tileHeight < h) {
98
+ tileHeight = h;
99
+ }
94
100
  }
95
101
  }
96
- }
97
102
 
98
- // tileHeight is not calculated as it could be exceeding the max possible height
99
- // find the max possible width instead
100
- if (tileHeight === 0) {
101
- tileHeight = maxRowHeight;
102
- const calcWidths = aspectRatios.map(aR => tileHeight * aR);
103
- tileWidth = 0;
104
- for (const w of calcWidths) {
105
- if (w < width) {
106
- if (tileWidth < w) {
107
- tileWidth = w;
103
+ // tileHeight is not calculated as it could be exceeding the max possible height
104
+ // find the max possible width instead
105
+ if (tileHeight === 0) {
106
+ tileHeight = maxRowHeight;
107
+ const calcWidths = aspectRatios.map(aR => tileHeight * aR);
108
+ tileWidth = 0;
109
+ for (const w of calcWidths) {
110
+ if (w < width) {
111
+ if (tileWidth < w) {
112
+ tileWidth = w;
113
+ }
108
114
  }
109
115
  }
110
116
  }
@@ -116,6 +122,6 @@ export const useTileLayout = ({
116
122
  }
117
123
  }
118
124
  setPagesWithTiles([...pageList]);
119
- }, [width, height, maxTileCount, pageList, vanillaStore, isMobile]);
125
+ }, [width, height, maxTileCount, pageList, vanillaStore, isMobile, edgeToEdge]);
120
126
  return { pagesWithTiles, ref };
121
127
  };
@@ -5,7 +5,9 @@ type TileContextType = {
5
5
  hideParticipantNameOnTile?: boolean;
6
6
  roundedVideoTile?: boolean;
7
7
  hideAudioMuteOnTile?: boolean;
8
+ hideAudioLevelOnTile?: boolean;
8
9
  objectFit?: 'cover' | 'contain';
10
+ hideMetadataOnTile?: boolean;
9
11
  };
10
12
 
11
13
  export const VideoTileContext = React.createContext<TileContextType>({
@@ -13,7 +15,9 @@ export const VideoTileContext = React.createContext<TileContextType>({
13
15
  hideParticipantNameOnTile: false,
14
16
  roundedVideoTile: true,
15
17
  hideAudioMuteOnTile: false,
18
+ hideAudioLevelOnTile: false,
16
19
  objectFit: 'contain',
20
+ hideMetadataOnTile: false,
17
21
  });
18
22
 
19
23
  export const useVideoTileContext = () => {
@@ -1,7 +1,5 @@
1
1
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import {
3
- selectLocalPeerID,
4
- selectLocalPeerRoleName,
5
3
  selectPeers,
6
4
  selectPeerScreenSharing,
7
5
  throwErrorHandler,
@@ -25,21 +23,13 @@ export const EmbedView = () => {
25
23
  export const EmbebScreenShareView = ({ children }) => {
26
24
  const peers = useHMSStore(selectPeers);
27
25
 
28
- const localPeerID = useHMSStore(selectLocalPeerID);
29
- const localPeerRole = useHMSStore(selectLocalPeerRoleName);
30
26
  const peerPresenting = useHMSStore(selectPeerScreenSharing);
31
- const isPresenterFromMyRole = peerPresenting?.roleName?.toLowerCase() === localPeerRole?.toLowerCase();
32
- const amIPresenting = localPeerID === peerPresenting?.id;
33
- const showPresenterInSmallTile = amIPresenting || isPresenterFromMyRole;
34
27
  const [, setActiveScreenSharePeer] = useSetAppDataByKey(APP_DATA.activeScreensharePeerId);
35
28
 
36
29
  const smallTilePeers = useMemo(() => {
37
30
  const smallTilePeers = peers.filter(peer => peer.id !== peerPresenting?.id);
38
- if (showPresenterInSmallTile && peerPresenting) {
39
- smallTilePeers.unshift(peerPresenting); // put presenter on first page
40
- }
41
31
  return smallTilePeers;
42
- }, [peers, peerPresenting, showPresenterInSmallTile]);
32
+ }, [peers, peerPresenting]);
43
33
 
44
34
  useEffect(() => {
45
35
  setActiveScreenSharePeer(peerPresenting?.id);
@@ -1,9 +1,9 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
- import { useFullscreen, useToggle } from 'react-use';
2
+ import { useFullscreen, useMedia, useToggle } from 'react-use';
3
3
  import { HLSPlaybackState, HMSHLSPlayer, HMSHLSPlayerEvents } from '@100mslive/hls-player';
4
4
  import screenfull from 'screenfull';
5
5
  import { selectAppData, selectHLSState, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
6
- import { ExpandIcon, RadioIcon, ShrinkIcon } from '@100mslive/react-icons';
6
+ import { ColoredHandIcon, ExpandIcon, RadioIcon, ShrinkIcon } from '@100mslive/react-icons';
7
7
  import { HlsStatsOverlay } from '../components/HlsStatsOverlay';
8
8
  import { HMSVideoPlayer } from '../components/HMSVideo';
9
9
  import { FullScreenButton } from '../components/HMSVideo/FullscreenButton';
@@ -14,7 +14,7 @@ import { IconButton } from '../../IconButton';
14
14
  import { Box, Flex } from '../../Layout';
15
15
  import { Loading } from '../../Loading';
16
16
  import { Text } from '../../Text';
17
- import { useTheme } from '../../Theme';
17
+ import { config, useTheme } from '../../Theme';
18
18
  import { Tooltip } from '../../Tooltip';
19
19
  import { APP_DATA, EMOJI_REACTION_TYPE } from '../common/constants';
20
20
 
@@ -26,7 +26,8 @@ const HLSView = () => {
26
26
  const hlsState = useHMSStore(selectHLSState);
27
27
  const enablHlsStats = useHMSStore(selectAppData(APP_DATA.hlsStats));
28
28
  const hmsActions = useHMSActions();
29
- const { themeType } = useTheme();
29
+ const { themeType, theme } = useTheme();
30
+ const [streamEnded, setStreamEnded] = useState(false);
30
31
  let [hlsStatsState, setHlsStatsState] = useState(null);
31
32
  const hlsUrl = hlsState.variants[0]?.url;
32
33
  const [availableLayers, setAvailableLayers] = useState([]);
@@ -37,6 +38,12 @@ const HLSView = () => {
37
38
  const [isPaused, setIsPaused] = useState(false);
38
39
  const isFullScreenSupported = screenfull.isEnabled;
39
40
  const [show, toggle] = useToggle(false);
41
+ const [controlsVisible, setControlsVisible] = useState(true);
42
+ const controlsRef = useRef();
43
+ const controlsTimerRef = useRef();
44
+ const [qualityDropDownOpen, setQualityDropDownOpen] = useState(false);
45
+
46
+ const isMobile = useMedia(config.media.md);
40
47
  const isFullScreen = useFullscreen(hlsViewRef, show, {
41
48
  onClose: () => toggle(false),
42
49
  });
@@ -58,6 +65,19 @@ const HLSView = () => {
58
65
  };
59
66
  }, []);
60
67
 
68
+ useEffect(() => {
69
+ const videoElem = videoRef.current;
70
+ const setStreamEndedCallback = () => {
71
+ setStreamEnded(true);
72
+ // no point keeping the callback attached once the streaming is ended
73
+ videoElem?.removeEventListener('ended', setStreamEndedCallback);
74
+ };
75
+ videoElem?.addEventListener('ended', setStreamEndedCallback);
76
+ return () => {
77
+ videoElem?.removeEventListener('ended', setStreamEndedCallback);
78
+ };
79
+ }, [hlsUrl]);
80
+
61
81
  /**
62
82
  * initialize HMSHLSPlayer and add event listeners.
63
83
  */
@@ -82,7 +102,7 @@ const HLSView = () => {
82
102
  const parsedPayload = parsePayload(payload);
83
103
  switch (parsedPayload.type) {
84
104
  case EMOJI_REACTION_TYPE:
85
- window.showFlyingEmoji(parsedPayload?.emojiId, parsedPayload?.senderId);
105
+ window.showFlyingEmoji?.({ emojiId: parsedPayload?.emojiId, senderId: parsedPayload?.senderId });
86
106
  break;
87
107
  default: {
88
108
  const toast = {
@@ -167,6 +187,43 @@ const HLSView = () => {
167
187
  hmsActions.setAppData(APP_DATA.hlsStats, !enablHlsStats);
168
188
  };
169
189
 
190
+ useEffect(() => {
191
+ if (controlsVisible && isFullScreen && !qualityDropDownOpen) {
192
+ if (controlsTimerRef.current) {
193
+ clearTimeout(controlsTimerRef.current);
194
+ }
195
+ controlsTimerRef.current = setTimeout(() => {
196
+ setControlsVisible(false);
197
+ }, 5000);
198
+ }
199
+ if (!isFullScreen && controlsTimerRef.current) {
200
+ clearTimeout(controlsTimerRef.current);
201
+ }
202
+ return () => {
203
+ if (controlsTimerRef.current) {
204
+ clearTimeout(controlsTimerRef.current);
205
+ }
206
+ };
207
+ }, [controlsVisible, isFullScreen, qualityDropDownOpen]);
208
+
209
+ const onHoverHandler = useCallback(
210
+ event => {
211
+ if (event.type === 'mouseenter' || qualityDropDownOpen) {
212
+ setControlsVisible(true);
213
+ return;
214
+ }
215
+ if (event.type === 'mouseleave') {
216
+ setControlsVisible(false);
217
+ } else if (isFullScreen && !controlsVisible && event.type === 'mousemove') {
218
+ setControlsVisible(true);
219
+ if (controlsTimerRef.current) {
220
+ clearTimeout(controlsTimerRef.current);
221
+ }
222
+ }
223
+ },
224
+ [controlsVisible, isFullScreen, qualityDropDownOpen],
225
+ );
226
+
170
227
  return (
171
228
  <Flex
172
229
  key="hls-viewer"
@@ -179,7 +236,7 @@ const HLSView = () => {
179
236
  {hlsStatsState?.url && enablHlsStats ? (
180
237
  <HlsStatsOverlay hlsStatsState={hlsStatsState} onClose={sfnOverlayClose} />
181
238
  ) : null}
182
- {hlsUrl && hlsState.running ? (
239
+ {hlsUrl && !streamEnded ? (
183
240
  <Flex
184
241
  id="hls-player-container"
185
242
  align="center"
@@ -188,7 +245,6 @@ const HLSView = () => {
188
245
  width: '100%',
189
246
  margin: '0 auto',
190
247
  height: '100%',
191
- background: 'linear-gradient(180deg, rgba(0, 0, 0, 0.00) 0%, #000 100%)',
192
248
  }}
193
249
  >
194
250
  <HLSAutoplayBlockedPrompt open={isHlsAutoplayBlocked} unblockAutoPlay={unblockAutoPlay} />
@@ -203,100 +259,114 @@ const HLSView = () => {
203
259
  <Loading width={72} height={72} />
204
260
  </Flex>
205
261
  )}
206
- <HMSVideoPlayer.Root ref={videoRef}>
262
+ <HMSVideoPlayer.Root
263
+ ref={videoRef}
264
+ onMouseEnter={onHoverHandler}
265
+ onMouseMove={onHoverHandler}
266
+ onMouseLeave={onHoverHandler}
267
+ >
207
268
  <Flex
269
+ ref={controlsRef}
208
270
  direction="column"
209
271
  justify="flex-end"
210
272
  align="flex-start"
211
273
  css={{
212
- background: 'linear-gradient(180deg, rgba(0, 0, 0, 0.00) 0%, #000 100%)',
274
+ position: 'absolute',
275
+ bottom: '0',
276
+ left: '0',
277
+ background: `linear-gradient(180deg, ${theme.colors.background_dim.value}00 29.46%, ${theme.colors.background_dim.value}A3 100%);`,
278
+ width: '100%',
279
+ pt: '$8',
280
+ flexShrink: 0,
281
+ transition: 'visibility 0s 0.5s, opacity 0.5s linear',
282
+ visibility: controlsVisible ? `` : `hidden`,
283
+ opacity: controlsVisible ? `1` : '0',
213
284
  }}
214
285
  >
215
- {hlsPlayer && (
216
- <HMSVideoPlayer.Progress
217
- onValueChange={currentTime => {
218
- hlsPlayer.seekTo(currentTime);
286
+ {!isMobile && (
287
+ <HMSVideoPlayer.Controls.Root
288
+ css={{
289
+ p: '$4 $8',
219
290
  }}
220
- hlsPlayer={hlsPlayer}
221
- />
222
- )}
223
-
224
- <HMSVideoPlayer.Controls.Root css={{ p: '$4 $8' }}>
225
- <HMSVideoPlayer.Controls.Left>
226
- <HMSVideoPlayer.PlayButton
227
- onClick={async () => {
228
- isPaused ? await hlsPlayer?.play() : hlsPlayer?.pause();
229
- }}
230
- isPaused={isPaused}
231
- />
232
- <HMSVideoPlayer.Duration hlsPlayer={hlsPlayer} />
233
- <HMSVideoPlayer.Volume hlsPlayer={hlsPlayer} />
234
- <IconButton
235
- variant="standard"
236
- css={{ px: '$2' }}
237
- onClick={async () => {
238
- await hlsPlayer.seekToLivePosition();
239
- setIsVideoLive(true);
240
- }}
241
- key="jump-to-live_btn"
242
- data-testid="jump-to-live_btn"
243
- >
244
- <Tooltip title="Go to Live" side="top">
245
- <Flex justify="center" gap={2} align="center">
246
- <Box
247
- css={{
248
- height: '$4',
249
- width: '$4',
250
- background: isVideoLive ? '$alert_error_default' : '$on_primary_medium',
251
- r: '$1',
252
- }}
253
- />
254
- <Text
255
- variant={{
256
- '@sm': 'xs',
257
- }}
258
- css={{
259
- c: isVideoLive ? '$on_primary_high' : '$on_primary_medium',
260
- }}
261
- >
262
- {isVideoLive ? 'LIVE' : 'GO LIVE'}
263
- </Text>
264
- </Flex>
265
- </Tooltip>
266
- </IconButton>
267
- </HMSVideoPlayer.Controls.Left>
268
-
269
- <HMSVideoPlayer.Controls.Right>
270
- {availableLayers.length > 0 ? (
271
- <HLSQualitySelector
272
- layers={availableLayers}
273
- selection={currentSelectedQuality}
274
- onQualityChange={handleQuality}
275
- isAuto={isUserSelectedAuto}
291
+ >
292
+ <HMSVideoPlayer.Controls.Left>
293
+ <HMSVideoPlayer.PlayButton
294
+ onClick={async () => {
295
+ isPaused ? await hlsPlayer?.play() : hlsPlayer?.pause();
296
+ }}
297
+ isPaused={isPaused}
276
298
  />
277
- ) : null}
278
- {isFullScreenSupported ? (
279
- <FullScreenButton
280
- isFullScreen={isFullScreen}
281
- onToggle={toggle}
282
- icon={isFullScreen ? <ShrinkIcon /> : <ExpandIcon />}
283
- />
284
- ) : null}
285
- </HMSVideoPlayer.Controls.Right>
286
- </HMSVideoPlayer.Controls.Root>
299
+ <HMSVideoPlayer.Duration hlsPlayer={hlsPlayer} />
300
+ <HMSVideoPlayer.Volume hlsPlayer={hlsPlayer} />
301
+ <IconButton
302
+ variant="standard"
303
+ css={{ px: '$2' }}
304
+ onClick={async () => {
305
+ await hlsPlayer.seekToLivePosition();
306
+ setIsVideoLive(true);
307
+ }}
308
+ key="jump-to-live_btn"
309
+ data-testid="jump-to-live_btn"
310
+ >
311
+ <Tooltip title="Go to Live" side="top">
312
+ <Flex justify="center" gap={2} align="center">
313
+ <Box
314
+ css={{
315
+ height: '$4',
316
+ width: '$4',
317
+ background: isVideoLive ? '$alert_error_default' : '$on_primary_medium',
318
+ r: '$1',
319
+ }}
320
+ />
321
+ <Text
322
+ variant={{
323
+ '@sm': 'xs',
324
+ }}
325
+ css={{
326
+ c: isVideoLive ? '$on_surface_high' : '$on_surface_medium',
327
+ }}
328
+ >
329
+ {isVideoLive ? 'LIVE' : 'GO LIVE'}
330
+ </Text>
331
+ </Flex>
332
+ </Tooltip>
333
+ </IconButton>
334
+ </HMSVideoPlayer.Controls.Left>
335
+
336
+ <HMSVideoPlayer.Controls.Right>
337
+ {availableLayers.length > 0 ? (
338
+ <HLSQualitySelector
339
+ layers={availableLayers}
340
+ onOpen={setQualityDropDownOpen}
341
+ open={qualityDropDownOpen}
342
+ selection={currentSelectedQuality}
343
+ onQualityChange={handleQuality}
344
+ isAuto={isUserSelectedAuto}
345
+ />
346
+ ) : null}
347
+ {isFullScreenSupported ? (
348
+ <FullScreenButton
349
+ isFullScreen={isFullScreen}
350
+ onToggle={toggle}
351
+ icon={isFullScreen ? <ShrinkIcon /> : <ExpandIcon />}
352
+ />
353
+ ) : null}
354
+ </HMSVideoPlayer.Controls.Right>
355
+ </HMSVideoPlayer.Controls.Root>
356
+ )}
287
357
  </Flex>
288
358
  </HMSVideoPlayer.Root>
289
359
  </Flex>
290
360
  ) : (
291
361
  <Flex align="center" justify="center" direction="column" css={{ size: '100%', px: '$10' }}>
292
362
  <Flex css={{ c: '$on_surface_high', r: '$round', bg: '$surface_default', p: '$2' }}>
293
- <RadioIcon height={56} width={56} />
363
+ {streamEnded ? <ColoredHandIcon height={56} width={56} /> : <RadioIcon height={56} width={56} />}
294
364
  </Flex>
295
365
  <Text variant="h5" css={{ c: '$on_surface_high', mt: '$10', mb: 0, textAlign: 'center' }}>
296
- Stream yet to start
366
+ {streamEnded ? 'Stream has ended' : 'Stream yet to start'}
297
367
  </Text>
298
368
  <Text variant="md" css={{ textAlign: 'center', mt: '$4', c: '$on_surface_medium' }}>
299
- Sit back and relax
369
+ {streamEnded ? 'Have a nice day!' : 'Sit back and relax'}
300
370
  </Text>
301
371
  </Flex>
302
372
  )}
@@ -2,29 +2,35 @@ import React from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import { ConferencingScreen } from '@100mslive/types-prebuilt';
4
4
  import { selectAppData, selectVideoTrackByPeerID, useHMSStore } from '@100mslive/react-sdk';
5
- // @ts-ignore: No implicit Any
6
- import { Chat } from '../components/Chat/Chat';
7
- // @ts-ignore: No implicit Any
8
- import { ParticipantList } from '../components/Footer/ParticipantList';
5
+ import { SidePaneTabs } from '../components/SidePaneTabs';
9
6
  // @ts-ignore: No implicit Any
10
7
  import { StreamingLanding } from '../components/Streaming/StreamingLanding';
8
+ import { TileCustomisationProps } from '../components/VideoLayouts/GridLayout';
11
9
  // @ts-ignore: No implicit Any
12
10
  import VideoTile from '../components/VideoTile';
13
11
  import { Box, Flex } from '../../Layout';
14
12
  import { config as cssConfig } from '../../Theme';
13
+ import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
15
14
  // @ts-ignore: No implicit Any
16
15
  import { APP_DATA, SIDE_PANE_OPTIONS } from '../common/constants';
17
16
 
18
- const SidePane = ({ screenType }: { screenType: keyof ConferencingScreen }) => {
17
+ const SidePane = ({
18
+ screenType,
19
+ tileProps,
20
+ hideControls = false,
21
+ }: {
22
+ screenType: keyof ConferencingScreen;
23
+ tileProps: TileCustomisationProps;
24
+ hideControls: boolean;
25
+ }) => {
19
26
  const isMobile = useMedia(cssConfig.media.md);
20
27
  const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane));
21
28
  const activeScreensharePeerId = useHMSStore(selectAppData(APP_DATA.activeScreensharePeerId));
22
29
  const trackId = useHMSStore(selectVideoTrackByPeerID(activeScreensharePeerId))?.id;
30
+ const { elements } = useRoomLayoutConferencingScreen();
23
31
  let ViewComponent;
24
- if (sidepane === SIDE_PANE_OPTIONS.PARTICIPANTS) {
25
- ViewComponent = <ParticipantList />;
26
- } else if (sidepane === SIDE_PANE_OPTIONS.CHAT) {
27
- ViewComponent = <Chat screenType={screenType} />;
32
+ if (sidepane === SIDE_PANE_OPTIONS.PARTICIPANTS || sidepane === SIDE_PANE_OPTIONS.CHAT) {
33
+ ViewComponent = <SidePaneTabs screenType={screenType} hideControls={hideControls} active={sidepane} />;
28
34
  } else if (sidepane === SIDE_PANE_OPTIONS.STREAMING) {
29
35
  ViewComponent = <StreamingLanding />;
30
36
  }
@@ -32,7 +38,15 @@ const SidePane = ({ screenType }: { screenType: keyof ConferencingScreen }) => {
32
38
  return null;
33
39
  }
34
40
 
35
- const mwebStreamingChat = isMobile && sidepane === SIDE_PANE_OPTIONS.CHAT;
41
+ const tileLayout = {
42
+ hideParticipantNameOnTile: tileProps?.hide_participant_name_on_tile,
43
+ roundedVideoTile: tileProps?.rounded_video_tile,
44
+ hideAudioMuteOnTile: tileProps?.hide_audio_mute_on_tile,
45
+ hideMetadataOnTile: tileProps?.hide_metadata_on_tile,
46
+ objectFit: tileProps?.video_object_fit,
47
+ };
48
+
49
+ const mwebStreamingChat = isMobile && sidepane === SIDE_PANE_OPTIONS.CHAT && elements?.chat?.is_overlay;
36
50
 
37
51
  return (
38
52
  <Flex
@@ -53,7 +67,7 @@ const SidePane = ({ screenType }: { screenType: keyof ConferencingScreen }) => {
53
67
  width="100%"
54
68
  height={225}
55
69
  rootCSS={{ p: 0, alignSelf: 'start', flexShrink: 0 }}
56
- objectFit="contain"
70
+ {...tileLayout}
57
71
  />
58
72
  )}
59
73
  {!!ViewComponent && (
@@ -1,43 +1,30 @@
1
- import React, { Suspense, useCallback, useEffect } from 'react';
2
- import { HMSException } from '@100mslive/hms-video';
1
+ import React, { Suspense, useEffect } from 'react';
3
2
  import {
4
3
  ConferencingScreen,
5
4
  DefaultConferencingScreen_Elements,
6
5
  HLSLiveStreamingScreen_Elements,
7
6
  } from '@100mslive/types-prebuilt';
8
- import {
9
- selectIsConnectedToRoom,
10
- selectLocalPeerRoleName,
11
- selectPermissions,
12
- useHMSActions,
13
- useHMSStore,
14
- useRecordingStreaming,
15
- } from '@100mslive/react-sdk';
7
+ import { selectIsConnectedToRoom, selectLocalPeerRoleName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
16
8
  // @ts-ignore: No implicit Any
17
9
  import FullPageProgress from '../components/FullPageProgress';
18
- // @ts-ignore: No implicit Any
19
10
  import { GridLayout } from '../components/VideoLayouts/GridLayout';
20
11
  import { Flex } from '../../Layout';
21
12
  // @ts-ignore: No implicit Any
22
13
  import { EmbedView } from './EmbedView';
23
14
  // @ts-ignore: No implicit Any
24
15
  import { PDFView } from './PDFView';
25
- // @ts-ignore: No implicit Any
26
16
  import SidePane from './SidePane';
27
17
  // @ts-ignore: No implicit Any
28
18
  import { WaitingView } from './WaitingView';
29
19
  // import { useWhiteboardMetadata } from '../plugins/whiteboard';
30
20
  import {
31
21
  usePDFAnnotator,
32
- useSetAppDataByKey,
33
22
  useUrlToEmbed,
34
23
  useWaitingViewerRole,
35
24
  // @ts-ignore: No implicit Any
36
25
  } from '../components/AppData/useUISettings';
37
26
  // @ts-ignore: No implicit Any
38
- import { useShowStreamingUI } from '../common/hooks';
39
- // @ts-ignore: No implicit Any
40
- import { APP_DATA, SESSION_STORE_KEY } from '../common/constants';
27
+ import { SESSION_STORE_KEY } from '../common/constants';
41
28
 
42
29
  // const WhiteboardView = React.lazy(() => import("./WhiteboardView"));
43
30
  // @ts-ignore: No implicit Any
@@ -46,9 +33,11 @@ const HLSView = React.lazy(() => import('./HLSView'));
46
33
  export const VideoStreamingSection = ({
47
34
  screenType,
48
35
  elements,
36
+ hideControls = false,
49
37
  }: {
50
38
  screenType: keyof ConferencingScreen;
51
39
  elements: DefaultConferencingScreen_Elements | HLSLiveStreamingScreen_Elements;
40
+ hideControls: boolean;
52
41
  }) => {
53
42
  const localPeerRole = useHMSStore(selectLocalPeerRoleName);
54
43
  // const { whiteboardOwner: whiteboardShared } = useWhiteboardMetadata();
@@ -57,36 +46,6 @@ export const VideoStreamingSection = ({
57
46
  const waitingViewerRole = useWaitingViewerRole();
58
47
  const urlToIframe = useUrlToEmbed();
59
48
  const pdfAnnotatorActive = usePDFAnnotator();
60
- const { isHLSRunning } = useRecordingStreaming();
61
- const [isHLSStarted, setHLSStarted] = useSetAppDataByKey(APP_DATA.hlsStarted);
62
- const permissions = useHMSStore(selectPermissions);
63
- const showStreamingUI = useShowStreamingUI();
64
-
65
- const startHLS = useCallback(async () => {
66
- try {
67
- if (isHLSStarted) {
68
- return;
69
- }
70
- setHLSStarted(true);
71
- await hmsActions.startHLSStreaming();
72
- } catch (error) {
73
- if ((error as HMSException).message?.includes('beam already started')) {
74
- return;
75
- }
76
- setHLSStarted(false);
77
- }
78
- }, [hmsActions, isHLSStarted, setHLSStarted]);
79
-
80
- useEffect(() => {
81
- if (!isConnected) {
82
- return;
83
- }
84
- // Is a streaming kit and broadcaster joins
85
- if (permissions?.hlsStreaming && !isHLSRunning && showStreamingUI) {
86
- startHLS();
87
- }
88
- // eslint-disable-next-line react-hooks/exhaustive-deps
89
- }, [isConnected]);
90
49
 
91
50
  useEffect(() => {
92
51
  if (!isConnected) {
@@ -125,7 +84,12 @@ export const VideoStreamingSection = ({
125
84
  }}
126
85
  >
127
86
  {ViewComponent}
128
- <SidePane screenType={screenType} />
87
+ <SidePane
88
+ screenType={screenType}
89
+ // @ts-ignore
90
+ tileProps={(elements as DefaultConferencingScreen_Elements)?.video_tile_layout?.grid}
91
+ hideControls={hideControls}
92
+ />
129
93
  </Flex>
130
94
  </Suspense>
131
95
  );
@@ -1,9 +1,16 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
2
  import { useMedia } from 'react-use';
3
- import { selectLocalPeerID, selectPeerNameByID, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
3
+ import {
4
+ selectLocalPeerID,
5
+ selectPeerNameByID,
6
+ useCustomEvent,
7
+ useHMSStore,
8
+ useHMSVanillaStore,
9
+ } from '@100mslive/react-sdk';
4
10
  import { Box, Flex } from '../../Layout';
5
11
  import { Text } from '../../Text';
6
12
  import { config as cssConfig, keyframes } from '../../Theme';
13
+ import { EMOJI_REACTION_TYPE } from '../common/constants';
7
14
 
8
15
  let emojiCount = 1;
9
16
 
@@ -42,7 +49,7 @@ export function FlyingEmoji() {
42
49
  const startingPoints = useMemo(() => getStartingPoints(isMobile), [isMobile]);
43
50
 
44
51
  const showFlyingEmoji = useCallback(
45
- (emojiId, senderId) => {
52
+ ({ emojiId, senderId }) => {
46
53
  if (!emojiId || !senderId || document.hidden) {
47
54
  return;
48
55
  }
@@ -67,6 +74,11 @@ export function FlyingEmoji() {
67
74
  [localPeerId, vanillaStore, startingPoints],
68
75
  );
69
76
 
77
+ useCustomEvent({
78
+ type: EMOJI_REACTION_TYPE,
79
+ onEvent: showFlyingEmoji,
80
+ });
81
+
70
82
  useEffect(() => {
71
83
  window.showFlyingEmoji = showFlyingEmoji;
72
84
  }, [showFlyingEmoji]);