@100mslive/roomkit-react 0.2.8-alpha.7 → 0.2.8-alpha.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. package/dist/{HLSView-MYKM5AXS.js → HLSView-TOMPA4E4.js} +191 -188
  2. package/dist/HLSView-TOMPA4E4.js.map +7 -0
  3. package/dist/Prebuilt/components/HMSVideo/HLSQualitySelector.d.ts +3 -2
  4. package/dist/Prebuilt/components/HMSVideo/VideoProgress.d.ts +1 -3
  5. package/dist/Prebuilt/components/HMSVideo/index.d.ts +1 -3
  6. package/dist/Prebuilt/components/HMSVideo/utils.d.ts +0 -1
  7. package/dist/Prebuilt/components/Leave/DesktopLeaveRoom.d.ts +2 -1
  8. package/dist/Prebuilt/components/Leave/LeaveRoom.d.ts +2 -1
  9. package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +2 -1
  10. package/dist/Prebuilt/components/RaiseHand.d.ts +4 -1
  11. package/dist/Sheet/Sheet.d.ts +1 -0
  12. package/dist/{chunk-DRBTAFKN.js → chunk-FUDX3LDB.js} +820 -723
  13. package/dist/chunk-FUDX3LDB.js.map +7 -0
  14. package/dist/index.cjs.js +1324 -1220
  15. package/dist/index.cjs.js.map +4 -4
  16. package/dist/index.js +1 -1
  17. package/dist/meta.cjs.json +274 -209
  18. package/dist/meta.esbuild.json +283 -216
  19. package/package.json +6 -6
  20. package/src/Button/Button.tsx +4 -4
  21. package/src/Fieldset/Fieldset.tsx +1 -1
  22. package/src/Input/PasswordInput.stories.tsx +1 -1
  23. package/src/Pagination/StyledPagination.stories.tsx +2 -2
  24. package/src/Prebuilt/IconButton.tsx +1 -1
  25. package/src/Prebuilt/components/Chat/Chat.tsx +41 -1
  26. package/src/Prebuilt/components/Chat/ChatFooter.tsx +19 -15
  27. package/src/Prebuilt/components/EmojiReaction.jsx +32 -22
  28. package/src/Prebuilt/components/Footer/RoleOptions.tsx +125 -126
  29. package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.tsx +85 -78
  30. package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +3 -4
  31. package/src/Prebuilt/components/HMSVideo/MwebHLSViewTitle.tsx +49 -56
  32. package/src/Prebuilt/components/HMSVideo/VideoProgress.tsx +6 -6
  33. package/src/Prebuilt/components/HMSVideo/VideoTime.tsx +2 -1
  34. package/src/Prebuilt/components/HMSVideo/utils.ts +0 -8
  35. package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx +1 -1
  36. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +50 -46
  37. package/src/Prebuilt/components/Leave/LeaveRoom.tsx +10 -5
  38. package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +12 -6
  39. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +5 -2
  40. package/src/Prebuilt/components/Notifications/HandRaisedNotifications.tsx +4 -1
  41. package/src/Prebuilt/components/Polls/Voting/Voting.tsx +3 -2
  42. package/src/Prebuilt/components/Polls/common/OptionInputWithDelete.tsx +1 -1
  43. package/src/Prebuilt/components/Polls/common/utils.ts +2 -2
  44. package/src/Prebuilt/components/RaiseHand.tsx +8 -2
  45. package/src/Prebuilt/components/RoomDetails/RoomDetailsPane.tsx +41 -14
  46. package/src/Prebuilt/components/pdfAnnotator/shareScreenOptions.jsx +2 -2
  47. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +1 -1
  48. package/src/Prebuilt/layouts/HLSView.jsx +58 -47
  49. package/src/Prebuilt/layouts/SidePane.tsx +1 -2
  50. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +3 -2
  51. package/src/Prebuilt/primitives/DialogContent.jsx +1 -1
  52. package/src/Sheet/Sheet.tsx +3 -3
  53. package/dist/HLSView-MYKM5AXS.js.map +0 -7
  54. package/dist/chunk-DRBTAFKN.js.map +0 -7
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "prebuilt",
11
11
  "roomkit"
12
12
  ],
13
- "version": "0.2.8-alpha.7",
13
+ "version": "0.2.8-alpha.9",
14
14
  "author": "100ms",
15
15
  "license": "MIT",
16
16
  "repository": {
@@ -82,11 +82,11 @@
82
82
  "react": ">=17.0.2 <19.0.0"
83
83
  },
84
84
  "dependencies": {
85
- "@100mslive/hls-player": "0.2.8-alpha.7",
85
+ "@100mslive/hls-player": "0.2.8-alpha.9",
86
86
  "@100mslive/hms-noise-cancellation": "0.0.0-alpha.1",
87
- "@100mslive/hms-virtual-background": "1.12.8-alpha.7",
88
- "@100mslive/react-icons": "0.9.8-alpha.7",
89
- "@100mslive/react-sdk": "0.9.8-alpha.7",
87
+ "@100mslive/hms-virtual-background": "1.12.8-alpha.9",
88
+ "@100mslive/react-icons": "0.9.8-alpha.9",
89
+ "@100mslive/react-sdk": "0.9.8-alpha.9",
90
90
  "@100mslive/types-prebuilt": "0.12.7",
91
91
  "@emoji-mart/data": "^1.0.6",
92
92
  "@emoji-mart/react": "^1.0.1",
@@ -122,5 +122,5 @@
122
122
  "uuid": "^8.3.2",
123
123
  "worker-timers": "^7.0.40"
124
124
  },
125
- "gitHead": "48bc1b57113a4245b79055a80f4f1f5d3b8795aa"
125
+ "gitHead": "2a735b6edf0b63927744abb555b47ab9be6e5891"
126
126
  }
@@ -20,22 +20,22 @@ const getOutlinedVariants = (
20
20
  textDisabled: string,
21
21
  ) => {
22
22
  return {
23
- bg: '$transparent',
23
+ bg: 'transparent',
24
24
  border: `solid $space$px $colors${base}`,
25
25
  c: text,
26
26
  '&[disabled]': {
27
27
  c: textDisabled,
28
- bg: '$transparent',
28
+ bg: 'transparent',
29
29
  border: `solid $space$px $colors${disabled}`,
30
30
  cursor: 'not-allowed',
31
31
  },
32
32
  '&:not([disabled]):hover': {
33
33
  border: `solid $space$px $colors${hover}`,
34
- bg: '$transparent',
34
+ bg: 'transparent',
35
35
  },
36
36
  '&:not([disabled]):active': {
37
37
  border: `solid $space$px $colors${active}`,
38
- bg: '$transparent',
38
+ bg: 'transparent',
39
39
  },
40
40
  '&:not([disabled]):focus-visible': {
41
41
  boxShadow: `0 0 0 3px $colors${base}`,
@@ -5,7 +5,7 @@ const StyledFieldset = styled('fieldset', {
5
5
  alignItems: 'center',
6
6
  justifyContent: 'space-between',
7
7
  border: 'none',
8
- backgroundColor: '$transparent',
8
+ backgroundColor: 'transparent',
9
9
  });
10
10
 
11
11
  export const Fieldset = StyledFieldset;
@@ -25,7 +25,7 @@ const Template: ComponentStory<typeof PasswordInput.Root> = args => {
25
25
  showPassword={showPassword}
26
26
  onChange={e => setText(e.target.value)}
27
27
  />
28
- <PasswordInput.Icons ref={ref} css={{ bg: '$transparent' }}>
28
+ <PasswordInput.Icons ref={ref} css={{ bg: 'transparent' }}>
29
29
  <PasswordInput.ShowIcon
30
30
  showPassword={showPassword}
31
31
  onClick={() => {
@@ -41,7 +41,7 @@ const PaginationComponent = ({ page: propsPage, setPage: propsSetPage, numPages
41
41
  disabled={disableLeft}
42
42
  onClick={prevPage}
43
43
  type="button"
44
- css={{ padding: 0, border: 'none', backgroundColor: '$transparent' }}
44
+ css={{ padding: 0, border: 'none', backgroundColor: 'transparent' }}
45
45
  >
46
46
  <ChevronLeftIcon width={16} height={16} style={{ cursor: disableLeft ? 'not-allowed' : 'pointer' }} />
47
47
  </StyledPagination.Chevron>
@@ -54,7 +54,7 @@ const PaginationComponent = ({ page: propsPage, setPage: propsSetPage, numPages
54
54
  disabled={disableRight}
55
55
  onClick={nextPage}
56
56
  type="button"
57
- css={{ padding: 0, border: 'none', backgroundColor: '$transparent' }}
57
+ css={{ padding: 0, border: 'none', backgroundColor: 'transparent' }}
58
58
  >
59
59
  <ChevronRightIcon width={16} height={16} style={{ cursor: disableRight ? 'not-allowed' : 'pointer' }} />
60
60
  </StyledPagination.Chevron>
@@ -11,7 +11,7 @@ const IconButton = styled(BaseIconButton, {
11
11
  active: {
12
12
  true: {
13
13
  color: '$on_surface_high',
14
- backgroundColor: '$transparent',
14
+ backgroundColor: 'transparent',
15
15
  },
16
16
  false: {
17
17
  border: '1px solid transparent',
@@ -2,16 +2,20 @@ import React, { MutableRefObject, useCallback, useRef } from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import { VariableSizeList } from 'react-window';
4
4
  import { selectSessionStore, selectUnreadHMSMessagesCount } from '@100mslive/hms-video-store';
5
+ import { match } from 'ts-pattern';
5
6
  import { selectHMSMessagesCount, useHMSActions, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
6
7
  import { ChevronDownIcon } from '@100mslive/react-icons';
7
8
  import { Button } from '../../../Button';
8
- import { Flex } from '../../../Layout';
9
+ import { Box, Flex } from '../../../Layout';
9
10
  import { config as cssConfig } from '../../../Theme';
11
+ // @ts-ignore: No implicit any
12
+ import { EmojiReaction } from '../EmojiReaction';
10
13
  import { ChatBody } from './ChatBody';
11
14
  import { ChatFooter } from './ChatFooter';
12
15
  import { ChatBlocked, ChatPaused } from './ChatStates';
13
16
  import { PinnedMessage } from './PinnedMessage';
14
17
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
18
+ import { useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
15
19
  import { SESSION_STORE_KEY } from '../../common/constants';
16
20
 
17
21
  export const Chat = () => {
@@ -21,6 +25,9 @@ export const Chat = () => {
21
25
  const vanillaStore = useHMSVanillaStore();
22
26
  const { enabled: isChatEnabled = true } = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE)) || {};
23
27
  const isMobile = useMedia(cssConfig.media.md);
28
+ const isMobileHLSStream = useMobileHLSStream();
29
+ const isLandscapeStream = useLandscapeHLSStream();
30
+
24
31
  const scrollToBottom = useCallback(
25
32
  (unreadCount = 0) => {
26
33
  if (listRef.current && listRef.current.scrollToItem && unreadCount > 0) {
@@ -46,6 +53,7 @@ export const Chat = () => {
46
53
  >
47
54
  {isMobile && elements?.chat?.is_overlay ? null : <PinnedMessage />}
48
55
  <ChatBody ref={listRef} scrollToBottom={scrollToBottom} />
56
+
49
57
  <ChatPaused />
50
58
  <ChatBlocked />
51
59
  {isMobile && elements?.chat?.is_overlay ? <PinnedMessage /> : null}
@@ -54,6 +62,38 @@ export const Chat = () => {
54
62
  <NewMessageIndicator scrollToBottom={scrollToBottom} listRef={listRef} />
55
63
  </ChatFooter>
56
64
  ) : null}
65
+ {(isMobileHLSStream || isLandscapeStream) && (
66
+ <Box
67
+ css={{
68
+ position: 'absolute',
69
+ ...match({ isLandscapeStream, isChatEnabled })
70
+ .with(
71
+ {
72
+ isLandscapeStream: true,
73
+ isChatEnabled: true,
74
+ },
75
+ () => ({ bottom: '$19', right: '$10' }),
76
+ )
77
+ .with(
78
+ {
79
+ isLandscapeStream: true,
80
+ isChatEnabled: false,
81
+ },
82
+ () => ({ bottom: '$20', right: '$10' }),
83
+ )
84
+ .with(
85
+ {
86
+ isLandscapeStream: false,
87
+ isChatEnabled: true,
88
+ },
89
+ () => ({ bottom: '$19', right: '$8' }),
90
+ )
91
+ .otherwise(() => ({})),
92
+ }}
93
+ >
94
+ <EmojiReaction />
95
+ </Box>
96
+ )}
57
97
  </Flex>
58
98
  );
59
99
  };
@@ -8,16 +8,16 @@ import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover,
8
8
  import { IconButton } from '../../../IconButton';
9
9
  import { MoreSettings } from '../MoreSettings/MoreSettings';
10
10
  import { RaiseHand } from '../RaiseHand';
11
- // @ts-ignore
11
+ // @ts-ignore: No implicit any
12
12
  import { ToastManager } from '../Toast/ToastManager';
13
13
  import { ChatSelectorContainer } from './ChatSelectorContainer';
14
14
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
15
- // @ts-ignore
15
+ // @ts-ignore: No implicit any
16
16
  import { useChatDraftMessage } from '../AppData/useChatState';
17
- // @ts-ignore
17
+ // @ts-ignore: No implicit any
18
18
  import { useSetSubscribedChatSelector, useSubscribeChatSelector } from '../AppData/useUISettings';
19
19
  import { useIsPeerBlacklisted } from '../hooks/useChatBlacklist';
20
- // @ts-ignore
20
+ // @ts-ignore: No implicit any
21
21
  import { useEmojiPickerStyles } from './useEmojiPickerStyles';
22
22
  import { useDefaultChatSelection, useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
23
23
  import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants';
@@ -148,7 +148,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
148
148
  }
149
149
 
150
150
  return (
151
- <Box>
151
+ <Box css={{ position: 'relative' }}>
152
152
  <Flex>
153
153
  <ChatSelectorContainer />
154
154
  {canDisableChat && isMobile && isOverlayChat ? (
@@ -202,10 +202,12 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
202
202
  align="center"
203
203
  css={{
204
204
  bg: isOverlayChat && isMobile ? '$surface_dim' : '$surface_default',
205
+ minHeight: '$16',
205
206
  maxHeight: '$24',
206
207
  position: 'relative',
208
+ py: '$6',
207
209
  pl: '$8',
208
- flexGrow: '1',
210
+ flexGrow: 1,
209
211
  r: '$1',
210
212
  '@md': {
211
213
  minHeight: 'unset',
@@ -266,15 +268,17 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
266
268
  </BaseIconButton>
267
269
  </Flex>
268
270
  {(isMwebHLSStream || isLandscapeHLSStream) && (
269
- <Flex
270
- css={{
271
- alignItems: 'center',
272
- }}
273
- gap="1"
274
- >
275
- {noAVPermissions ? <RaiseHand /> : null}
276
- <MoreSettings elements={elements} screenType={screenType} />
277
- </Flex>
271
+ <>
272
+ <Flex
273
+ css={{
274
+ alignItems: 'center',
275
+ }}
276
+ gap="1"
277
+ >
278
+ {noAVPermissions ? <RaiseHand css={{ bg: '$surface_default' }} /> : null}
279
+ <MoreSettings elements={elements} screenType={screenType} />
280
+ </Flex>
281
+ </>
278
282
  )}
279
283
  </Flex>
280
284
  )}
@@ -1,4 +1,4 @@
1
- import React, { Fragment, useState } from 'react';
1
+ import React, { useState } from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import data from '@emoji-mart/data/sets/14/apple.json';
4
4
  import { init } from 'emoji-mart';
@@ -7,9 +7,7 @@ import {
7
7
  selectIsConnectedToRoom,
8
8
  selectLocalPeerID,
9
9
  useCustomEvent,
10
- // useHMSActions,
11
10
  useHMSStore,
12
- // useRecordingStreaming,
13
11
  } from '@100mslive/react-sdk';
14
12
  import { EmojiIcon } from '@100mslive/react-icons';
15
13
  import { EmojiCard } from './Footer/EmojiCard';
@@ -20,6 +18,7 @@ import { config as cssConfig } from '../../Theme';
20
18
  import { Tooltip } from '../../Tooltip';
21
19
  import IconButton from '../IconButton';
22
20
  import { useDropdownList } from './hooks/useDropdownList';
21
+ import { useLandscapeHLSStream, useMobileHLSStream } from '../common/hooks';
23
22
  import { EMOJI_REACTION_TYPE } from '../common/constants';
24
23
 
25
24
  init({ data });
@@ -33,6 +32,9 @@ export const EmojiReaction = () => {
33
32
  const localPeerId = useHMSStore(selectLocalPeerID);
34
33
  // const { isStreamingOn } = useRecordingStreaming();
35
34
  const isMobile = useMedia(cssConfig.media.md);
35
+ const isLandscape = useMedia(cssConfig.media.ls);
36
+ const isMobileHLSStream = useMobileHLSStream();
37
+ const isLandscapeStream = useLandscapeHLSStream();
36
38
 
37
39
  const { sendEvent } = useCustomEvent({
38
40
  type: EMOJI_REACTION_TYPE,
@@ -65,24 +67,32 @@ export const EmojiReaction = () => {
65
67
  if (!isConnected) {
66
68
  return null;
67
69
  }
68
- return isMobile ? (
69
- <EmojiCard sendReaction={sendReaction} />
70
- ) : (
71
- <Fragment>
72
- <Dropdown.Root open={open} onOpenChange={setOpen}>
73
- <Dropdown.Trigger asChild data-testid="emoji_reaction_btn">
74
- <IconButton>
75
- <Tooltip title="Emoji reaction">
76
- <Box>
77
- <EmojiIcon />
78
- </Box>
79
- </Tooltip>
80
- </IconButton>
81
- </Dropdown.Trigger>
82
- <Dropdown.Content sideOffset={5} align="center" css={{ p: '$8', bg: '$surface_default' }}>
83
- <EmojiCard sendReaction={sendReaction} />
84
- </Dropdown.Content>
85
- </Dropdown.Root>
86
- </Fragment>
70
+
71
+ if ((isMobile || isLandscape) && !(isLandscapeStream || isMobileHLSStream)) {
72
+ return <EmojiCard sendReaction={sendReaction} />;
73
+ }
74
+ return (
75
+ <Dropdown.Root open={open} onOpenChange={setOpen}>
76
+ <Dropdown.Trigger asChild data-testid="emoji_reaction_btn">
77
+ <IconButton
78
+ css={
79
+ isMobile || isLandscape ? { bg: '$surface_default', r: '$round', border: '1px solid $border_bright' } : {}
80
+ }
81
+ >
82
+ <Tooltip title="Emoji reaction">
83
+ <Box>
84
+ <EmojiIcon />
85
+ </Box>
86
+ </Tooltip>
87
+ </IconButton>
88
+ </Dropdown.Trigger>
89
+ <Dropdown.Content
90
+ sideOffset={5}
91
+ align={isMobileHLSStream || isLandscapeStream ? 'end' : 'center'}
92
+ css={{ p: '$8', bg: '$surface_default' }}
93
+ >
94
+ <EmojiCard sendReaction={sendReaction} />
95
+ </Dropdown.Content>
96
+ </Dropdown.Root>
87
97
  );
88
98
  };
@@ -1,12 +1,13 @@
1
1
  import React, { useState } from 'react';
2
2
  import { DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt';
3
+ import { match } from 'ts-pattern';
3
4
  import {
4
5
  HMSPeer,
5
6
  selectPermissions,
6
7
  selectRoleByRoleName,
8
+ selectTracksMap,
7
9
  useHMSActions,
8
10
  useHMSStore,
9
- useHMSVanillaStore,
10
11
  } from '@100mslive/react-sdk';
11
12
  import {
12
13
  MicOffIcon,
@@ -32,12 +33,59 @@ const optionTextCSS = {
32
33
  whiteSpace: 'nowrap',
33
34
  };
34
35
 
35
- const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleName: string }) => {
36
- const vanillaStore = useHMSVanillaStore();
37
- const store = vanillaStore.getState();
38
- const hmsActions = useHMSActions();
36
+ const DropdownWrapper = ({ children }: { children: React.ReactNode }) => {
37
+ const [openOptions, setOpenOptions] = useState(false);
38
+ if (React.Children.toArray(children).length === 0) {
39
+ return null;
40
+ }
41
+ React.Children.map(children, child => {
42
+ console.log({ child });
43
+ });
44
+ return (
45
+ <Dropdown.Root open={openOptions} onOpenChange={setOpenOptions}>
46
+ <Dropdown.Trigger
47
+ data-testid="role_group_options"
48
+ onClick={e => e.stopPropagation()}
49
+ className="role_actions"
50
+ asChild
51
+ css={{
52
+ p: '$1',
53
+ r: '$0',
54
+ c: '$on_surface_high',
55
+ visibility: openOptions ? 'visible' : 'hidden',
56
+ '&:hover': {
57
+ c: '$on_surface_medium',
58
+ },
59
+ '@md': {
60
+ visibility: 'visible',
61
+ },
62
+ }}
63
+ >
64
+ <Flex>
65
+ <VerticalMenuIcon />
66
+ </Flex>
67
+ </Dropdown.Trigger>
68
+ <Dropdown.Content
69
+ onClick={e => e.stopPropagation()}
70
+ css={{ w: 'max-content', bg: '$surface_default', py: 0 }}
71
+ align="end"
72
+ >
73
+ {children}
74
+ </Dropdown.Content>
75
+ </Dropdown.Root>
76
+ );
77
+ };
78
+
79
+ export const RoleOptions = ({ roleName, peerList }: { roleName: string; peerList: HMSPeer[] }) => {
39
80
  const permissions = useHMSStore(selectPermissions);
81
+ const hmsActions = useHMSActions();
82
+ const { elements } = useRoomLayoutConferencingScreen();
83
+ const { on_stage_role, off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {};
84
+ const canRemoveRoleFromStage = permissions?.changeRole && roleName === on_stage_role;
40
85
  const role = useHMSStore(selectRoleByRoleName(roleName));
86
+ const canPublishAudio = role.publishParams.allowed.includes('audio');
87
+ const canPublishVideo = role.publishParams.allowed.includes('video');
88
+ const tracks = useHMSStore(selectTracksMap);
41
89
 
42
90
  let isVideoOnForSomePeers = false;
43
91
  let isAudioOnForSomePeers = false;
@@ -46,8 +94,8 @@ const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleNam
46
94
  if (peer.isLocal) {
47
95
  return;
48
96
  }
49
- const isAudioOn = !!peer.audioTrack && store.tracks[peer.audioTrack]?.enabled;
50
- const isVideoOn = !!peer.videoTrack && store.tracks[peer.videoTrack]?.enabled;
97
+ const isAudioOn = !!peer.audioTrack && tracks[peer.audioTrack]?.enabled;
98
+ const isVideoOn = !!peer.videoTrack && tracks[peer.videoTrack]?.enabled;
51
99
  isAudioOnForSomePeers = isAudioOnForSomePeers || isAudioOn;
52
100
  isVideoOnForSomePeers = isVideoOnForSomePeers || isVideoOn;
53
101
  });
@@ -60,75 +108,11 @@ const MuteUnmuteOption = ({ roleName, peerList }: { peerList: HMSPeer[]; roleNam
60
108
  }
61
109
  };
62
110
 
63
- if (!role) {
64
- return null;
65
- }
66
-
67
- return (
68
- <>
69
- {role.publishParams.allowed.includes('audio') && (
70
- <>
71
- {isAudioOnForSomePeers && permissions?.mute ? (
72
- <Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('audio', false)}>
73
- <MicOffIcon />
74
- <Text variant="sm" css={optionTextCSS}>
75
- Mute Audio for All
76
- </Text>
77
- </Dropdown.Item>
78
- ) : null}
79
-
80
- {!isAudioOnForSomePeers && permissions?.unmute ? (
81
- <Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('audio', true)}>
82
- <MicOnIcon />
83
- <Text variant="sm" css={optionTextCSS}>
84
- Request to Unmute Audio for All
85
- </Text>
86
- </Dropdown.Item>
87
- ) : null}
88
- </>
89
- )}
90
-
91
- {role.publishParams.allowed.includes('video') && (
92
- <>
93
- {isVideoOnForSomePeers && permissions?.mute ? (
94
- <Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('video', false)}>
95
- <VideoOffIcon />
96
- <Text variant="sm" css={optionTextCSS}>
97
- Mute Video for All
98
- </Text>
99
- </Dropdown.Item>
100
- ) : null}
101
-
102
- {!isVideoOnForSomePeers && permissions?.unmute ? (
103
- <Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('video', true)}>
104
- <VideoOnIcon />
105
- <Text variant="sm" css={optionTextCSS}>
106
- Request to Unmute Video for All
107
- </Text>
108
- </Dropdown.Item>
109
- ) : null}
110
- </>
111
- )}
112
- </>
113
- );
114
- };
115
-
116
- export const RoleOptions = ({ roleName, peerList }: { roleName: string; peerList: HMSPeer[] }) => {
117
- const [openOptions, setOpenOptions] = useState(false);
118
- const permissions = useHMSStore(selectPermissions);
119
- const hmsActions = useHMSActions();
120
- const { elements } = useRoomLayoutConferencingScreen();
121
- const { on_stage_role, off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {};
122
- const canMuteOrUnmute = permissions?.mute || permissions?.unmute;
123
- const canRemoveRoleFromStage = permissions?.changeRole && roleName === on_stage_role;
124
- const role = useHMSStore(selectRoleByRoleName(roleName));
125
-
126
111
  // on stage and off stage roles
127
112
  const canRemoveRoleFromRoom =
128
113
  permissions?.removeOthers && (on_stage_role === roleName || off_stage_roles?.includes(roleName));
129
114
 
130
115
  if (
131
- !(canMuteOrUnmute || canRemoveRoleFromStage || canRemoveRoleFromRoom) ||
132
116
  peerList.length === 0 ||
133
117
  // if only local peer is present no need to show any options
134
118
  (peerList.length === 1 && peerList[0].isLocal) ||
@@ -157,60 +141,75 @@ export const RoleOptions = ({ roleName, peerList }: { roleName: string; peerList
157
141
  };
158
142
 
159
143
  return (
160
- <Dropdown.Root open={openOptions} onOpenChange={setOpenOptions}>
161
- <Dropdown.Trigger
162
- data-testid="role_group_options"
163
- onClick={e => e.stopPropagation()}
164
- className="role_actions"
165
- asChild
166
- css={{
167
- p: '$1',
168
- r: '$0',
169
- c: '$on_surface_high',
170
- visibility: openOptions ? 'visible' : 'hidden',
171
- '&:hover': {
172
- c: '$on_surface_medium',
173
- },
174
- '@md': {
175
- visibility: 'visible',
176
- },
177
- }}
178
- >
179
- <Flex>
180
- <VerticalMenuIcon />
181
- </Flex>
182
- </Dropdown.Trigger>
183
- <Dropdown.Content
184
- onClick={e => e.stopPropagation()}
185
- css={{ w: 'max-content', bg: '$surface_default', py: 0 }}
186
- align="end"
187
- >
188
- {canRemoveRoleFromStage && (
189
- <Dropdown.Item
190
- css={{ ...dropdownItemCSS, borderBottom: '1px solid $border_bright' }}
191
- onClick={removeAllFromStage}
192
- >
193
- <PersonRectangleIcon />
194
- <Text variant="sm" css={optionTextCSS}>
195
- Remove all from Stage
196
- </Text>
197
- </Dropdown.Item>
198
- )}
199
-
200
- {canMuteOrUnmute && <MuteUnmuteOption peerList={peerList} roleName={roleName} />}
201
-
202
- {canRemoveRoleFromRoom && (
203
- <Dropdown.Item
204
- css={{ ...dropdownItemCSS, borderTop: '1px solid $border_bright', color: '$alert_error_default' }}
205
- onClick={removePeersFromRoom}
206
- >
207
- <RemoveUserIcon />
208
- <Text variant="sm" css={{ ...optionTextCSS, color: 'inherit' }}>
209
- Remove all from Room
210
- </Text>
211
- </Dropdown.Item>
212
- )}
213
- </Dropdown.Content>
214
- </Dropdown.Root>
144
+ <DropdownWrapper>
145
+ {canRemoveRoleFromStage ? (
146
+ <Dropdown.Item
147
+ css={{ ...dropdownItemCSS, borderBottom: '1px solid $border_bright' }}
148
+ onClick={removeAllFromStage}
149
+ >
150
+ <PersonRectangleIcon />
151
+ <Text variant="sm" css={optionTextCSS}>
152
+ Remove all from Stage
153
+ </Text>
154
+ </Dropdown.Item>
155
+ ) : null}
156
+
157
+ {match({ canPublishAudio, isAudioOnForSomePeers, canMute: permissions?.mute, canUnmute: permissions?.unmute })
158
+ .with({ canPublishAudio: true, isAudioOnForSomePeers: true, canMute: true }, () => {
159
+ return (
160
+ <Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('audio', false)}>
161
+ <MicOffIcon />
162
+ <Text variant="sm" css={optionTextCSS}>
163
+ Mute Audio for All
164
+ </Text>
165
+ </Dropdown.Item>
166
+ );
167
+ })
168
+ .with({ canPublishAudio: true, isAudioOnForSomePeers: false, canUnmute: true }, () => {
169
+ return (
170
+ <Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('audio', true)}>
171
+ <MicOnIcon />
172
+ <Text variant="sm" css={optionTextCSS}>
173
+ Request to Unmute Audio for All
174
+ </Text>
175
+ </Dropdown.Item>
176
+ );
177
+ })
178
+ .otherwise(() => null)}
179
+ {match({ canPublishVideo, isVideoOnForSomePeers, canMute: permissions?.mute, canUnmute: permissions?.unmute })
180
+ .with({ canPublishVideo: true, isVideoOnForSomePeers: true, canMute: true }, () => {
181
+ return (
182
+ <Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('video', false)}>
183
+ <VideoOffIcon />
184
+ <Text variant="sm" css={optionTextCSS}>
185
+ Mute Video for All
186
+ </Text>
187
+ </Dropdown.Item>
188
+ );
189
+ })
190
+ .with({ canPublishVideo: true, isVideoOnForSomePeers: false, canUnmute: true }, () => {
191
+ return (
192
+ <Dropdown.Item css={dropdownItemCSS} onClick={() => setTrackEnabled('video', true)}>
193
+ <VideoOnIcon />
194
+ <Text variant="sm" css={optionTextCSS}>
195
+ Request to Unmute Video for All
196
+ </Text>
197
+ </Dropdown.Item>
198
+ );
199
+ })
200
+ .otherwise(() => null)}
201
+
202
+ {canRemoveRoleFromRoom ? (
203
+ <Dropdown.Item
204
+ css={{ ...dropdownItemCSS, borderTop: '1px solid $border_bright', color: '$alert_error_default' }}
205
+ onClick={removePeersFromRoom}
206
+ >
207
+ <RemoveUserIcon />
208
+ <Text variant="sm" css={{ ...optionTextCSS, color: 'inherit' }}>
209
+ Remove all from Room
210
+ </Text>
211
+ </Dropdown.Item>
212
+ ) : null}
213
+ </DropdownWrapper>
215
214
  );
216
215
  };