@100mslive/roomkit-react 0.1.4-alpha.0 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. package/dist/{HLSView-T267ZHOS.js → HLSView-CTAJQUU4.js} +7 -11
  2. package/dist/{HLSView-T267ZHOS.js.map → HLSView-CTAJQUU4.js.map} +1 -1
  3. package/dist/PinnedTrackView-CQKONH4O.js +102 -0
  4. package/dist/PinnedTrackView-CQKONH4O.js.map +7 -0
  5. package/dist/Popover/index.d.ts +1 -0
  6. package/dist/Prebuilt/App.d.ts +25 -0
  7. package/dist/Prebuilt/index.d.ts +1 -0
  8. package/dist/Prebuilt/provider/roomLayoutProvider/index.d.ts +1 -1
  9. package/dist/Sheet/Sheet.d.ts +3093 -0
  10. package/dist/Sheet/index.d.ts +1 -0
  11. package/dist/Theme/ThemeProvider.d.ts +4 -286
  12. package/dist/Theme/stitches.config.d.ts +1 -1
  13. package/dist/{VirtualBackground-BCKXNDTD.js → VirtualBackground-GGGBJYVY.js} +31 -7
  14. package/dist/VirtualBackground-GGGBJYVY.js.map +7 -0
  15. package/dist/chunk-I2FJWE74.js +827 -0
  16. package/dist/chunk-I2FJWE74.js.map +7 -0
  17. package/dist/{chunk-NLZVUXR3.js → chunk-L2SX7GBO.js} +3020 -2189
  18. package/dist/chunk-L2SX7GBO.js.map +7 -0
  19. package/dist/chunk-NOKIGB6Y.js +1100 -0
  20. package/dist/chunk-NOKIGB6Y.js.map +7 -0
  21. package/dist/chunk-TJNDX446.js +67 -0
  22. package/dist/chunk-TJNDX446.js.map +7 -0
  23. package/dist/{chunk-3HMUOAD6.js → conference-OEO7VOJD.js} +3136 -653
  24. package/dist/conference-OEO7VOJD.js.map +7 -0
  25. package/dist/index.cjs.js +15733 -15498
  26. package/dist/index.cjs.js.map +4 -4
  27. package/dist/index.js +4 -8
  28. package/dist/meta.cjs.json +3248 -3039
  29. package/dist/meta.esbuild.json +3398 -3386
  30. package/dist/utils/animations.d.ts +16 -0
  31. package/package.json +8 -11
  32. package/src/Button/Button.tsx +4 -4
  33. package/src/Dropdown/Dropdown.tsx +2 -2
  34. package/src/IconButton/IconButton.tsx +4 -2
  35. package/src/Pagination/StyledPagination.tsx +1 -0
  36. package/src/Popover/index.tsx +2 -1
  37. package/src/Prebuilt/{App.jsx → App.tsx} +95 -48
  38. package/src/Prebuilt/Prebuilt.stories.tsx +22 -8
  39. package/src/Prebuilt/common/constants.js +1 -2
  40. package/src/Prebuilt/common/hooks.js +8 -0
  41. package/src/Prebuilt/common/utils.js +15 -0
  42. package/src/Prebuilt/components/AppData/AppData.jsx +1 -2
  43. package/src/Prebuilt/components/AppData/useUISettings.js +0 -5
  44. package/src/Prebuilt/components/AudioVideoToggle.jsx +69 -26
  45. package/src/Prebuilt/components/AuthToken.jsx +3 -2
  46. package/src/Prebuilt/components/Chat/ChatSelector.jsx +1 -1
  47. package/src/Prebuilt/components/Connection/TileConnection.jsx +0 -1
  48. package/src/Prebuilt/components/EmojiReaction.jsx +23 -73
  49. package/src/Prebuilt/components/EndSessionContent.jsx +57 -0
  50. package/src/Prebuilt/components/EqualProminence.jsx +180 -0
  51. package/src/Prebuilt/components/ErrorBoundary.jsx +4 -10
  52. package/src/Prebuilt/components/Footer/EmojiCard.jsx +34 -0
  53. package/src/Prebuilt/components/Footer/Footer.jsx +73 -0
  54. package/src/Prebuilt/components/{Header → Footer}/ParticipantList.jsx +5 -5
  55. package/src/Prebuilt/components/Header/ConferencingHeader.jsx +27 -7
  56. package/src/Prebuilt/components/Header/HeaderComponents.jsx +16 -14
  57. package/src/Prebuilt/components/Header/StreamActions.jsx +101 -36
  58. package/src/Prebuilt/components/Header/StreamingHeader.jsx +1 -1
  59. package/src/Prebuilt/components/Header/common.jsx +164 -0
  60. package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.jsx +1 -2
  61. package/src/Prebuilt/components/LeaveCard.jsx +19 -0
  62. package/src/Prebuilt/components/LeaveRoom.jsx +35 -143
  63. package/src/Prebuilt/components/LeaveSessionContent.jsx +45 -0
  64. package/src/Prebuilt/components/MoreSettings/ActionTile.jsx +55 -0
  65. package/src/Prebuilt/components/MoreSettings/ChangeNameContent.jsx +96 -0
  66. package/src/Prebuilt/components/MoreSettings/ChangeNameModal.jsx +31 -54
  67. package/src/Prebuilt/components/MoreSettings/EmbedUrl.jsx +48 -73
  68. package/src/Prebuilt/components/MoreSettings/MoreSettings.jsx +5 -221
  69. package/src/Prebuilt/components/MoreSettings/MuteAllContent.jsx +61 -0
  70. package/src/Prebuilt/components/MoreSettings/MuteAllModal.jsx +32 -49
  71. package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopLeaveRoom.jsx +129 -0
  72. package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.jsx +219 -0
  73. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebLeaveRoom.jsx +100 -0
  74. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.jsx +259 -0
  75. package/src/Prebuilt/components/Notifications/Notifications.jsx +0 -2
  76. package/src/Prebuilt/components/Notifications/ReconnectNotifications.jsx +0 -4
  77. package/src/Prebuilt/components/PIP/PIPComponent.jsx +30 -26
  78. package/src/Prebuilt/components/PIP/PIPManager.js +13 -0
  79. package/src/Prebuilt/components/PIP/index.jsx +2 -7
  80. package/src/Prebuilt/components/Pagination.jsx +4 -4
  81. package/src/Prebuilt/components/Preview/PreviewContainer.jsx +5 -13
  82. package/src/Prebuilt/components/Preview/PreviewForm.jsx +9 -5
  83. package/src/Prebuilt/components/Preview/PreviewJoin.jsx +20 -27
  84. package/src/Prebuilt/components/RaiseHand.jsx +27 -0
  85. package/src/Prebuilt/components/ScreenShare.jsx +1 -1
  86. package/src/Prebuilt/components/ScreenshareDisplay.jsx +2 -2
  87. package/src/Prebuilt/components/ScreenshareTile.jsx +2 -2
  88. package/src/Prebuilt/components/Settings/DeviceSettings.jsx +2 -1
  89. package/src/Prebuilt/components/Settings/LayoutSettings.jsx +1 -24
  90. package/src/Prebuilt/components/Settings/SettingsModal.jsx +152 -17
  91. package/src/Prebuilt/components/ShareMenuIcon.jsx +1 -0
  92. package/src/Prebuilt/components/TileMenu/TileMenu.jsx +133 -0
  93. package/src/Prebuilt/components/TileMenu/TileMenuContent.jsx +313 -0
  94. package/src/Prebuilt/components/VideoList.jsx +5 -33
  95. package/src/Prebuilt/components/VideoTile.jsx +30 -8
  96. package/src/Prebuilt/components/conference.jsx +14 -1
  97. package/src/Prebuilt/components/init/Init.jsx +0 -27
  98. package/src/Prebuilt/components/init/initUtils.js +0 -23
  99. package/src/Prebuilt/components/pdfAnnotator/pdfFileOptions.jsx +2 -1
  100. package/src/Prebuilt/components/pdfAnnotator/pdfInfo.jsx +1 -1
  101. package/src/Prebuilt/components/pdfAnnotator/shareScreenOptions.jsx +19 -8
  102. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +1 -0
  103. package/src/Prebuilt/images/pdf-share.png +0 -0
  104. package/src/Prebuilt/images/screen-share.png +0 -0
  105. package/src/Prebuilt/index.ts +1 -0
  106. package/src/Prebuilt/layouts/EmbedView.jsx +0 -1
  107. package/src/Prebuilt/layouts/InsetView.jsx +65 -24
  108. package/src/Prebuilt/layouts/PDFView.jsx +0 -1
  109. package/src/Prebuilt/layouts/SidePane.jsx +8 -7
  110. package/src/Prebuilt/layouts/WhiteboardView.jsx +2 -4
  111. package/src/Prebuilt/layouts/mainView.jsx +22 -31
  112. package/src/Prebuilt/layouts/screenShareView.jsx +0 -2
  113. package/src/Prebuilt/plugins/VirtualBackground/VirtualBackground.jsx +25 -1
  114. package/src/Prebuilt/plugins/whiteboard/index.js +1 -1
  115. package/src/Prebuilt/primitives/DialogContent.jsx +1 -1
  116. package/src/Prebuilt/provider/roomLayoutProvider/index.tsx +1 -1
  117. package/src/Sheet/Sheet.mdx +19 -0
  118. package/src/Sheet/Sheet.stories.tsx +103 -0
  119. package/src/Sheet/Sheet.tsx +118 -0
  120. package/src/Sheet/index.ts +1 -0
  121. package/src/Theme/ThemeProvider.tsx +10 -13
  122. package/src/Theme/base.config.ts +1 -1
  123. package/src/Theme/stitches.config.ts +1 -1
  124. package/src/TileMenu/StyledMenuTile.tsx +2 -2
  125. package/src/TileMenu/TileMenu.tsx +2 -0
  126. package/src/VideoTile/StyledVideoTile.tsx +5 -0
  127. package/src/utils/animations.ts +18 -0
  128. package/dist/ActiveSpeakerView-AGL73O6U.css +0 -11
  129. package/dist/ActiveSpeakerView-AGL73O6U.css.map +0 -7
  130. package/dist/ActiveSpeakerView-UPFD5RXA.js +0 -39
  131. package/dist/ActiveSpeakerView-UPFD5RXA.js.map +0 -7
  132. package/dist/HLSView-64OG755F.css +0 -11
  133. package/dist/HLSView-64OG755F.css.map +0 -7
  134. package/dist/PinnedTrackView-O4FHHHOV.js +0 -70
  135. package/dist/PinnedTrackView-O4FHHHOV.js.map +0 -7
  136. package/dist/PinnedTrackView-YWAZ2342.css +0 -11
  137. package/dist/PinnedTrackView-YWAZ2342.css.map +0 -7
  138. package/dist/VirtualBackground-BCKXNDTD.js.map +0 -7
  139. package/dist/chunk-3HMUOAD6.js.map +0 -7
  140. package/dist/chunk-6GXDYWD5.js +0 -243
  141. package/dist/chunk-6GXDYWD5.js.map +0 -7
  142. package/dist/chunk-NLZVUXR3.js.map +0 -7
  143. package/dist/chunk-ORPC2GYB.js +0 -58
  144. package/dist/chunk-ORPC2GYB.js.map +0 -7
  145. package/dist/chunk-YE4RPJYG.js +0 -811
  146. package/dist/chunk-YE4RPJYG.js.map +0 -7
  147. package/dist/conference-7KHWJZLG.css +0 -11
  148. package/dist/conference-7KHWJZLG.css.map +0 -7
  149. package/dist/conference-ETISNCLN.js +0 -3697
  150. package/dist/conference-ETISNCLN.js.map +0 -7
  151. package/dist/index.cjs.css +0 -11
  152. package/dist/index.cjs.css.map +0 -7
  153. package/dist/index.css +0 -11
  154. package/dist/index.css.map +0 -7
  155. package/dist/transcription-JJQ4UAIK.js +0 -356
  156. package/dist/transcription-JJQ4UAIK.js.map +0 -7
  157. package/src/Prebuilt/common/useSortedPeers.js +0 -28
  158. package/src/Prebuilt/components/BottomActionSheet/BottomActionSheet.jsx +0 -96
  159. package/src/Prebuilt/components/BottomActionSheet/BottomActionSheet.stories.tsx +0 -46
  160. package/src/Prebuilt/components/Footer/ConferencingFooter.jsx +0 -101
  161. package/src/Prebuilt/components/Footer/StreamingFooter.jsx +0 -71
  162. package/src/Prebuilt/components/Footer.jsx +0 -8
  163. package/src/Prebuilt/components/MoreSettings/ChangeSelfRole.jsx +0 -67
  164. package/src/Prebuilt/components/TileMenu.jsx +0 -268
  165. package/src/Prebuilt/index.d.ts +0 -20
  166. package/src/Prebuilt/index.js +0 -2
@@ -1,7 +1,9 @@
1
1
  import React, { Fragment } from 'react';
2
2
  import {
3
3
  DeviceType,
4
+ HMSRoomState,
4
5
  selectLocalVideoTrackID,
6
+ selectRoomState,
5
7
  selectVideoTrackByID,
6
8
  useAVToggle,
7
9
  useDevices,
@@ -18,7 +20,7 @@ import { isMacOS } from '../common/constants';
18
20
 
19
21
  const optionsCSS = { fontWeight: '$semiBold', color: '$on_surface_high', w: '100%', p: '$8' };
20
22
 
21
- export const AudioVideoToggle = () => {
23
+ export const AudioVideoToggle = ({ hideOptions = false }) => {
22
24
  const { allDevices, selectedDeviceIDs, updateDevice } = useDevices();
23
25
  const { videoInput, audioInput } = allDevices;
24
26
 
@@ -64,40 +66,81 @@ export const AudioVideoToggle = () => {
64
66
  const actions = useHMSActions();
65
67
  const videoTrackId = useHMSStore(selectLocalVideoTrackID);
66
68
  const localVideoTrack = useHMSStore(selectVideoTrackByID(videoTrackId));
69
+ const roomState = useHMSStore(selectRoomState);
67
70
 
68
71
  return (
69
72
  <Fragment>
70
73
  {toggleAudio ? (
71
- <IconButtonWithOptions
72
- options={formattedAudioInputList}
73
- tooltipMessage={`Turn ${isLocalAudioEnabled ? 'off' : 'on'} audio (${isMacOS ? '⌘' : 'ctrl'} + d)`}
74
- icon={
75
- !isLocalAudioEnabled ? <MicOffIcon data-testid="audio_off_btn" /> : <MicOnIcon data-testid="audio_on_btn" />
76
- }
77
- active={isLocalAudioEnabled}
78
- onClick={toggleAudio}
79
- key="toggleAudio"
80
- />
74
+ hideOptions ? (
75
+ <Tooltip title={`Turn ${isLocalAudioEnabled ? 'off' : 'on'} audio (${isMacOS ? '⌘' : 'ctrl'} + d)`}>
76
+ <IconButton
77
+ active={isLocalAudioEnabled}
78
+ onClick={toggleAudio}
79
+ key="toggleAudio"
80
+ data-testid="audio_btn"
81
+ className="__cancel-drag-event"
82
+ >
83
+ {!isLocalAudioEnabled ? (
84
+ <MicOffIcon data-testid="audio_off_btn" />
85
+ ) : (
86
+ <MicOnIcon data-testid="audio_on_btn" />
87
+ )}
88
+ </IconButton>
89
+ </Tooltip>
90
+ ) : (
91
+ <IconButtonWithOptions
92
+ options={formattedAudioInputList}
93
+ tooltipMessage={`Turn ${isLocalAudioEnabled ? 'off' : 'on'} audio (${isMacOS ? '⌘' : 'ctrl'} + d)`}
94
+ icon={
95
+ !isLocalAudioEnabled ? (
96
+ <MicOffIcon data-testid="audio_off_btn" />
97
+ ) : (
98
+ <MicOnIcon data-testid="audio_on_btn" />
99
+ )
100
+ }
101
+ active={isLocalAudioEnabled}
102
+ onClick={toggleAudio}
103
+ key="toggleAudio"
104
+ />
105
+ )
81
106
  ) : null}
82
107
 
83
108
  {toggleVideo ? (
84
- <IconButtonWithOptions
85
- options={formattedVideoInputList}
86
- tooltipMessage={`Turn ${isLocalVideoEnabled ? 'off' : 'on'} video (${isMacOS ? '⌘' : 'ctrl'} + e)`}
87
- icon={
88
- !isLocalVideoEnabled ? (
89
- <VideoOffIcon data-testid="video_off_btn" />
90
- ) : (
91
- <VideoOnIcon data-testid="video_on_btn" />
92
- )
93
- }
94
- key="toggleVideo"
95
- active={isLocalVideoEnabled}
96
- onClick={toggleVideo}
97
- />
109
+ hideOptions ? (
110
+ <Tooltip title={`Turn ${isLocalVideoEnabled ? 'off' : 'on'} video (${isMacOS ? '⌘' : 'ctrl'} + e)`}>
111
+ <IconButton
112
+ key="toggleVideo"
113
+ active={isLocalVideoEnabled}
114
+ onClick={toggleVideo}
115
+ data-testid="video_btn"
116
+ className="__cancel-drag-event"
117
+ >
118
+ {!isLocalVideoEnabled ? (
119
+ <VideoOffIcon data-testid="video_off_btn" />
120
+ ) : (
121
+ <VideoOnIcon data-testid="video_on_btn" />
122
+ )}
123
+ </IconButton>
124
+ </Tooltip>
125
+ ) : (
126
+ <IconButtonWithOptions
127
+ options={formattedVideoInputList}
128
+ tooltipMessage={`Turn ${isLocalVideoEnabled ? 'off' : 'on'} video (${isMacOS ? '⌘' : 'ctrl'} + e)`}
129
+ icon={
130
+ !isLocalVideoEnabled ? (
131
+ <VideoOffIcon data-testid="video_off_btn" />
132
+ ) : (
133
+ <VideoOnIcon data-testid="video_on_btn" />
134
+ )
135
+ }
136
+ key="toggleVideo"
137
+ active={isLocalVideoEnabled}
138
+ onClick={toggleVideo}
139
+ />
140
+ )
98
141
  ) : null}
99
142
 
100
- {localVideoTrack?.facingMode ? (
143
+ {localVideoTrack?.facingMode && roomState === HMSRoomState.Preview ? (
101
144
  <Tooltip title="Switch Camera" key="switchCamera">
102
145
  <IconButton
103
146
  onClick={async () => {
@@ -22,7 +22,7 @@ import { APP_DATA, QUERY_PARAM_AUTH_TOKEN } from '../common/constants';
22
22
  const AuthToken = React.memo(({ authTokenByRoomCodeEndpoint }) => {
23
23
  const hmsActions = useHMSActions();
24
24
  const tokenEndpoint = useTokenEndpoint();
25
- const { showPreview, roomCode } = useHMSPrebuiltContext();
25
+ const { showPreview, roomCode, userId } = useHMSPrebuiltContext();
26
26
  const location = useLocation();
27
27
  const matches = useMemo(
28
28
  () =>
@@ -46,7 +46,7 @@ const AuthToken = React.memo(({ authTokenByRoomCodeEndpoint }) => {
46
46
  const code = !userRole && (roomCode || urlRoomCode);
47
47
 
48
48
  const getTokenFn = code
49
- ? () => hmsActions.getAuthTokenByRoomCode({ roomCode: code }, { endpoint: authTokenByRoomCodeEndpoint })
49
+ ? () => hmsActions.getAuthTokenByRoomCode({ roomCode: code, userId }, { endpoint: authTokenByRoomCodeEndpoint })
50
50
  : () => getToken(tokenEndpoint, uuid(), userRole, urlRoomId);
51
51
 
52
52
  getTokenFn()
@@ -66,6 +66,7 @@ const AuthToken = React.memo(({ authTokenByRoomCodeEndpoint }) => {
66
66
  authTokenByRoomCodeEndpoint,
67
67
  setAuthTokenInAppData,
68
68
  roomCode,
69
+ userId,
69
70
  ]);
70
71
 
71
72
  if (error.title) {
@@ -10,7 +10,7 @@ import {
10
10
  } from '@100mslive/react-sdk';
11
11
  import { CheckIcon } from '@100mslive/react-icons';
12
12
  import { Box, Dropdown, Flex, HorizontalDivider, Text, Tooltip } from '../../../';
13
- import { ParticipantSearch } from '../Header/ParticipantList';
13
+ import { ParticipantSearch } from '../Footer/ParticipantList';
14
14
  import { useFilteredRoles } from '../../common/hooks';
15
15
 
16
16
  const ChatDotIcon = () => {
@@ -31,7 +31,6 @@ const Wrapper = styled('div', {
31
31
  backgroundColor: '$background_dim',
32
32
  borderRadius: '$1',
33
33
  maxWidth: '85%',
34
- zIndex: 1,
35
34
  '& p,span': {
36
35
  p: '$2 $3',
37
36
  },
@@ -5,44 +5,36 @@ import {
5
5
  selectAvailableRoleNames,
6
6
  selectIsConnectedToRoom,
7
7
  selectLocalPeerID,
8
- selectLocalPeerRoleName,
9
8
  useCustomEvent,
10
9
  useHMSActions,
11
10
  useHMSStore,
12
11
  useRecordingStreaming,
13
12
  } from '@100mslive/react-sdk';
14
13
  import { EmojiIcon } from '@100mslive/react-icons';
14
+ import { EmojiCard } from './Footer/EmojiCard';
15
+ import { ToastManager } from './Toast/ToastManager';
15
16
  import { Dropdown } from '../../Dropdown';
16
- import { Flex } from '../../Layout';
17
- import { Text } from '../../Text';
18
- import { styled } from '../../Theme';
17
+ import { Box } from '../../Layout';
19
18
  import { Tooltip } from '../../Tooltip';
20
19
  import IconButton from '../IconButton';
21
20
  import { useHLSViewerRole } from './AppData/useUISettings';
22
21
  import { useDropdownList } from './hooks/useDropdownList';
23
22
  import { useIsFeatureEnabled } from './hooks/useFeatures';
24
- import { EMOJI_REACTION_TYPE, FEATURE_LIST, HLS_TIMED_METADATA_DOC_URL } from '../common/constants';
23
+ import { EMOJI_REACTION_TYPE, FEATURE_LIST } from '../common/constants';
25
24
 
26
25
  init({ data });
27
26
 
28
- // When changing emojis in the grid, keep in mind that the payload used in sendHLSTimedMetadata has a limit of 100 characters. Using bigger emoji Ids can cause the limit to be exceeded.
29
- const emojiReactionList = [
30
- [{ emojiId: '+1' }, { emojiId: '-1' }, { emojiId: 'wave' }, { emojiId: 'clap' }, { emojiId: 'fire' }],
31
- [{ emojiId: 'tada' }, { emojiId: 'heart_eyes' }, { emojiId: 'joy' }, { emojiId: 'open_mouth' }, { emojiId: 'sob' }],
32
- ];
33
-
34
27
  export const EmojiReaction = () => {
35
28
  const [open, setOpen] = useState(false);
36
- const hmsActions = useHMSActions();
37
29
  const isConnected = useHMSStore(selectIsConnectedToRoom);
30
+ const isFeatureEnabled = useIsFeatureEnabled(FEATURE_LIST.EMOJI_REACTION);
31
+ useDropdownList({ open: open, name: 'EmojiReaction' });
32
+ const hmsActions = useHMSActions();
38
33
  const roles = useHMSStore(selectAvailableRoleNames);
39
- const localPeerRole = useHMSStore(selectLocalPeerRoleName);
40
34
  const localPeerId = useHMSStore(selectLocalPeerID);
41
35
  const hlsViewerRole = useHLSViewerRole();
42
36
  const { isStreamingOn } = useRecordingStreaming();
43
- const isFeatureEnabled = useIsFeatureEnabled(FEATURE_LIST.EMOJI_REACTION);
44
37
  const filteredRoles = useMemo(() => roles.filter(role => role !== hlsViewerRole), [roles, hlsViewerRole]);
45
- useDropdownList({ open: open, name: 'EmojiReaction' });
46
38
 
47
39
  const onEmojiEvent = useCallback(data => {
48
40
  window.showFlyingEmoji(data?.emojiId, data?.senderId);
@@ -61,16 +53,21 @@ export const EmojiReaction = () => {
61
53
  };
62
54
  sendEvent(data, { roleNames: filteredRoles });
63
55
  if (isStreamingOn) {
64
- await hmsActions.sendHLSTimedMetadata([
65
- {
66
- payload: JSON.stringify(data),
67
- duration: 2,
68
- },
69
- ]);
56
+ try {
57
+ await hmsActions.sendHLSTimedMetadata([
58
+ {
59
+ payload: JSON.stringify(data),
60
+ duration: 2,
61
+ },
62
+ ]);
63
+ } catch (error) {
64
+ console.log(error);
65
+ ToastManager.addToast({ title: error.message });
66
+ }
70
67
  }
71
68
  };
72
69
 
73
- if (!isConnected || localPeerRole === hlsViewerRole || !isFeatureEnabled) {
70
+ if (!isConnected || !isFeatureEnabled) {
74
71
  return null;
75
72
  }
76
73
  return (
@@ -79,63 +76,16 @@ export const EmojiReaction = () => {
79
76
  <Dropdown.Trigger asChild data-testid="emoji_reaction_btn">
80
77
  <IconButton>
81
78
  <Tooltip title="Emoji reaction">
82
- <EmojiIcon />
79
+ <Box>
80
+ <EmojiIcon />
81
+ </Box>
83
82
  </Tooltip>
84
83
  </IconButton>
85
84
  </Dropdown.Trigger>
86
85
  <Dropdown.Content sideOffset={5} align="center" css={{ p: '$8', bg: '$surface_default' }}>
87
- {emojiReactionList.map((emojiLine, index) => (
88
- <Flex key={index} justify="between" css={{ mb: '$8' }}>
89
- {emojiLine.map(emoji => (
90
- <EmojiContainer key={emoji.emojiId} onClick={() => sendReaction(emoji.emojiId)}>
91
- <em-emoji id={emoji.emojiId} size="100%" set="apple"></em-emoji>
92
- </EmojiContainer>
93
- ))}
94
- </Flex>
95
- ))}
96
- <div style={{ textAlign: 'center' }}>
97
- <Text
98
- variant="sm"
99
- inline={true}
100
- css={{
101
- color: '$on_primary_medium',
102
- }}
103
- >
104
- Reactions will be timed for Live Streaming viewers.{' '}
105
- </Text>
106
- <Text
107
- variant="sm"
108
- inline={true}
109
- css={{
110
- color: '$primary_bright',
111
- fontWeight: '$semiBold',
112
- }}
113
- >
114
- <a
115
- href={HLS_TIMED_METADATA_DOC_URL}
116
- target="_blank"
117
- rel="noopener noreferrer"
118
- style={{ color: 'inherit', textDecoration: 'none' }}
119
- >
120
- Learn more.
121
- </a>
122
- </Text>
123
- </div>
86
+ <EmojiCard sendReaction={sendReaction} />
124
87
  </Dropdown.Content>
125
88
  </Dropdown.Root>
126
89
  </Fragment>
127
90
  );
128
91
  };
129
-
130
- const EmojiContainer = styled('span', {
131
- position: 'relative',
132
- cursor: 'pointer',
133
- width: '$16',
134
- height: '$16',
135
- p: '$4',
136
- '&:hover': {
137
- p: '7px',
138
- bg: '$surface_brighter',
139
- borderRadius: '$1',
140
- },
141
- });
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import { AlertTriangleIcon, CrossIcon } from '@100mslive/react-icons';
3
+ import { Button } from '../../Button';
4
+ import { Box, Flex } from '../../Layout';
5
+ import { Text } from '../../Text';
6
+ import { useShowStreamingUI } from '../common/hooks';
7
+
8
+ export const EndSessionContent = ({ setShowEndStreamAlert, stopStream, leaveRoom, isModal = false }) => {
9
+ const showStreamingUI = useShowStreamingUI();
10
+ return (
11
+ <Box>
12
+ <Flex
13
+ css={{
14
+ color: '$alert_error_default',
15
+ display: 'flex',
16
+ alignItems: 'center',
17
+ }}
18
+ >
19
+ <AlertTriangleIcon style={{ marginRight: '0.5rem' }} />
20
+ <Text variant="lg" css={{ color: 'inherit', fontWeight: '$semiBold' }}>
21
+ End {showStreamingUI ? 'Stream' : 'Session'}
22
+ </Text>
23
+ {isModal ? null : (
24
+ <Box css={{ color: '$on_surface_high', ml: 'auto' }} onClick={() => setShowEndStreamAlert(false)}>
25
+ <CrossIcon />
26
+ </Box>
27
+ )}
28
+ </Flex>
29
+ <Text variant="sm" css={{ color: '$on_surface_medium', mb: '$8', mt: '$4' }}>
30
+ The {showStreamingUI ? 'stream' : 'session'} will end for everyone. You can't undo this action.
31
+ </Text>
32
+ <Flex align="center" justify="between" css={{ w: '100%', gap: '$8' }}>
33
+ <Button
34
+ outlined
35
+ variant="standard"
36
+ css={{ w: '100%', '@md': { display: 'none' } }}
37
+ onClick={() => setShowEndStreamAlert(false)}
38
+ >
39
+ Cancel
40
+ </Button>
41
+ <Button
42
+ variant="danger"
43
+ css={{ w: '100%' }}
44
+ onClick={async () => {
45
+ await stopStream();
46
+ leaveRoom();
47
+ setShowEndStreamAlert(false);
48
+ }}
49
+ id="stopStream"
50
+ data-testid="stop_stream_btn"
51
+ >
52
+ End {showStreamingUI ? 'Stream' : 'Session'}
53
+ </Button>
54
+ </Flex>
55
+ </Box>
56
+ );
57
+ };
@@ -0,0 +1,180 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { useMeasure, useMedia } from 'react-use';
3
+ import {
4
+ getPeersWithTiles,
5
+ selectLocalPeer,
6
+ selectPeers,
7
+ selectRemotePeers,
8
+ selectTracksMap,
9
+ useHMSStore,
10
+ useHMSVanillaStore,
11
+ } from '@100mslive/react-sdk';
12
+ import { Box, Flex } from '../../Layout';
13
+ import { config as cssConfig } from '../../Theme';
14
+ import { InsetTile } from '../layouts/InsetView';
15
+ import { useRoomLayout } from '../provider/roomLayoutProvider';
16
+ import { Pagination } from './Pagination';
17
+ import VideoTile from './VideoTile';
18
+ import { useUISettings } from './AppData/useUISettings';
19
+ import PeersSorter from '../common/PeersSorter';
20
+ import { UI_SETTINGS } from '../common/constants';
21
+
22
+ const aspectRatioConfig = { default: [1 / 1, 4 / 3, 16 / 9], mobile: [1 / 1, 3 / 4, 9 / 16] };
23
+
24
+ export function EqualProminence() {
25
+ const layout = useRoomLayout();
26
+ const { enable_local_tile_inset: isInsetEnabled = true } =
27
+ //@ts-ignore
28
+ layout?.screens?.conferencing?.default?.elements?.video_tile_layout?.grid || {};
29
+ const peers = useHMSStore(isInsetEnabled ? selectRemotePeers : selectPeers);
30
+ const [sortedPeers, setSortedPeers] = useState(peers);
31
+ const localPeer = useHMSStore(selectLocalPeer);
32
+ const vanillaStore = useHMSVanillaStore();
33
+ const isMobile = useMedia(cssConfig.media.md);
34
+ let maxTileCount = useUISettings(UI_SETTINGS.maxTileCount);
35
+ maxTileCount = isMobile ? Math.min(maxTileCount, 6) : maxTileCount;
36
+ const [pagesWithTiles, setPagesWithTiles] = useState([]);
37
+ const [page, setPage] = useState(0);
38
+ const [ref, { width, height }] = useMeasure();
39
+ const peersSorter = useMemo(() => new PeersSorter(vanillaStore), [vanillaStore]);
40
+ const pageSize = pagesWithTiles[0]?.length;
41
+
42
+ useEffect(() => {
43
+ // currentPageIndex should not exceed pages length
44
+ if (page >= pagesWithTiles.length) {
45
+ setPage(0);
46
+ }
47
+ }, [pagesWithTiles.length, page]);
48
+
49
+ useEffect(() => {
50
+ if (width === 0 || height === 0) {
51
+ return;
52
+ }
53
+ const tracksMap = vanillaStore.getState(selectTracksMap);
54
+ const peersWithTiles = getPeersWithTiles(
55
+ sortedPeers.length === 0 ? [localPeer] : sortedPeers,
56
+ tracksMap,
57
+ () => false,
58
+ );
59
+ const noOfPages = Math.ceil(peersWithTiles.length / maxTileCount);
60
+ let remaining = peersWithTiles.length;
61
+ let sliceStart = 0;
62
+ let pagesList = [];
63
+ // split into pages
64
+ for (let i = 0; i < noOfPages; i++) {
65
+ const count = Math.min(remaining, maxTileCount);
66
+ pagesList.push(peersWithTiles.slice(sliceStart, sliceStart + count));
67
+ remaining = remaining - count;
68
+ sliceStart += count;
69
+ }
70
+ // calculate dimesions for each page
71
+ for (const page of pagesList) {
72
+ const noOfTilesInPage = page.length;
73
+ let maxCols =
74
+ noOfTilesInPage > 2 && noOfTilesInPage < 9
75
+ ? Math.ceil(noOfTilesInPage / 2)
76
+ : Math.ceil(Math.sqrt(noOfTilesInPage));
77
+ if (isMobile) {
78
+ maxCols = noOfTilesInPage < 4 ? 1 : Math.min(maxCols, 2);
79
+ }
80
+ let maxRows = Math.ceil(noOfTilesInPage / maxCols);
81
+ let index = 0;
82
+ // convert the current page to a matrix(grid)
83
+ const matrix = new Array(maxRows).fill(null).map((_, i) => {
84
+ const numCols = Math.min(maxCols, noOfTilesInPage - i * maxCols);
85
+ let rowElements = [];
86
+ for (let j = 0; j < numCols; j++) {
87
+ if (index < page.length) {
88
+ rowElements.push(page[index++]);
89
+ }
90
+ }
91
+ return rowElements;
92
+ });
93
+
94
+ const maxHeight = height - (maxRows - 1) * 8;
95
+ const maxRowHeight = maxHeight / matrix.length;
96
+ const aspectRatios =
97
+ isMobile && (noOfTilesInPage === 1 || noOfTilesInPage > 3)
98
+ ? aspectRatioConfig.mobile
99
+ : aspectRatioConfig.default;
100
+ // calculate height and width of each tile in a row
101
+ for (const row of matrix) {
102
+ let tileWidth = (width - (row.length - 1) * 8) / row.length;
103
+ let tileHeight = 0;
104
+ const calcHeights = aspectRatios.map(aR => tileWidth / aR);
105
+ for (const h of calcHeights) {
106
+ if (h < maxRowHeight) {
107
+ if (tileHeight < h) {
108
+ tileHeight = h;
109
+ }
110
+ }
111
+ }
112
+
113
+ // tileHeight is not calculated as it could be exceeding the max possible height
114
+ // find the max possible width instead
115
+ if (tileHeight === 0) {
116
+ tileHeight = maxRowHeight;
117
+ const calcWidths = aspectRatios.map(aR => tileHeight * aR);
118
+ tileWidth = 0;
119
+ for (const w of calcWidths) {
120
+ if (w < width) {
121
+ if (tileWidth < w) {
122
+ tileWidth = w;
123
+ }
124
+ }
125
+ }
126
+ }
127
+ for (let i = 0; i < row.length; i++) {
128
+ row[i].width = tileWidth;
129
+ row[i].height = tileHeight;
130
+ }
131
+ }
132
+ }
133
+ setPagesWithTiles(pagesList);
134
+ }, [width, height, maxTileCount, vanillaStore, sortedPeers, page, isMobile, localPeer]);
135
+
136
+ useEffect(() => {
137
+ if (page !== 0) {
138
+ return;
139
+ }
140
+ peersSorter.setPeersAndTilesPerPage({
141
+ peers,
142
+ tilesPerPage: pageSize || maxTileCount,
143
+ });
144
+ peersSorter.onUpdate(setSortedPeers);
145
+ }, [page, peersSorter, peers, pageSize, maxTileCount]);
146
+
147
+ return (
148
+ <Flex direction="column" css={{ flex: '1 1 0', h: '100%', position: 'relative', minWidth: 0 }}>
149
+ <Box
150
+ ref={ref}
151
+ css={{
152
+ flex: '1 1 0',
153
+ gap: '$4',
154
+ display: 'flex',
155
+ placeContent: 'center',
156
+ alignItems: 'center',
157
+ justifyContent: 'center',
158
+ flexFlow: 'row wrap',
159
+ minHeight: 0,
160
+ }}
161
+ >
162
+ {pagesWithTiles[page]?.map(tile => {
163
+ return (
164
+ <VideoTile
165
+ key={tile.track?.id || tile.peer?.id}
166
+ width={tile.width}
167
+ height={tile.height}
168
+ peerId={tile.peer?.id}
169
+ trackId={tile.track?.id}
170
+ rootCSS={{ padding: 0 }}
171
+ objectFit="contain"
172
+ />
173
+ );
174
+ })}
175
+ </Box>
176
+ {pagesWithTiles.length > 1 && <Pagination page={page} onPageChange={setPage} numPages={pagesWithTiles.length} />}
177
+ {isInsetEnabled && sortedPeers.length > 0 && <InsetTile />}
178
+ </Flex>
179
+ );
180
+ }
@@ -1,5 +1,4 @@
1
1
  import React, { Component } from 'react';
2
- import { logMessage } from 'zipyai';
3
2
  import { CopyIcon } from '@100mslive/react-icons';
4
3
  import { Button } from '../../Button';
5
4
  import { Box, Flex } from '../../Layout';
@@ -16,15 +15,10 @@ export class ErrorBoundary extends Component {
16
15
  componentDidCatch(error, errorInfo) {
17
16
  console.error(`react error boundary - ${error.message}`, error, errorInfo);
18
17
  // Catch errors in any components below and re-render with error message
19
- this.setState(
20
- {
21
- error: error?.message,
22
- errorInfo: errorInfo,
23
- },
24
- () => {
25
- logMessage(`uiError - ${this.state.error} - ${JSON.stringify(this.state.errorInfo)}`);
26
- },
27
- );
18
+ this.setState({
19
+ error: error?.message,
20
+ errorInfo: errorInfo,
21
+ });
28
22
  }
29
23
 
30
24
  render() {
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { Flex } from '../../../Layout';
3
+ import { styled } from '../../../Theme';
4
+
5
+ // When changing emojis in the grid, keep in mind that the payload used in sendHLSTimedMetadata has a limit of 100 characters. Using bigger emoji Ids can cause the limit to be exceeded.
6
+ const emojiReactionList = [
7
+ [{ emojiId: '+1' }, { emojiId: '-1' }, { emojiId: 'wave' }, { emojiId: 'clap' }, { emojiId: 'fire' }],
8
+ [{ emojiId: 'tada' }, { emojiId: 'heart_eyes' }, { emojiId: 'joy' }, { emojiId: 'open_mouth' }, { emojiId: 'sob' }],
9
+ ];
10
+
11
+ export const EmojiCard = ({ sendReaction }) => {
12
+ return emojiReactionList.map((emojiLine, index) => (
13
+ <Flex key={index} justify="between" css={{ mb: '$8' }}>
14
+ {emojiLine.map(emoji => (
15
+ <EmojiContainer key={emoji.emojiId} onClick={() => sendReaction(emoji.emojiId)}>
16
+ <em-emoji id={emoji.emojiId} size="100%" set="apple"></em-emoji>
17
+ </EmojiContainer>
18
+ ))}
19
+ </Flex>
20
+ ));
21
+ };
22
+
23
+ const EmojiContainer = styled('span', {
24
+ position: 'relative',
25
+ cursor: 'pointer',
26
+ width: '$16',
27
+ height: '$16',
28
+ p: '$4',
29
+ '&:hover': {
30
+ p: '7px',
31
+ bg: '$surface_brighter',
32
+ borderRadius: '$1',
33
+ },
34
+ });