@100mslive/roomkit-react 0.1.14-alpha.1 → 0.1.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. package/dist/{HLSView-JTO7E2KW.js → HLSView-662T7R7H.js} +2 -2
  2. package/dist/Prebuilt/common/constants.d.ts +1 -0
  3. package/dist/Prebuilt/common/hooks.d.ts +24 -0
  4. package/dist/Prebuilt/components/Chat/{Navigation.d.ts → ArrowNavigation.d.ts} +1 -2
  5. package/dist/Prebuilt/components/Chat/ChatFooter.d.ts +2 -4
  6. package/dist/Prebuilt/components/Chat/ChatSelector.d.ts +5 -0
  7. package/dist/Prebuilt/components/Chat/ChatSelectorContainer.d.ts +2 -0
  8. package/dist/Prebuilt/components/Chat/ChatStates.d.ts +3 -0
  9. package/dist/Prebuilt/components/Chat/StickIndicator.d.ts +5 -0
  10. package/dist/Prebuilt/components/Chat/useUnreadCount.d.ts +4 -0
  11. package/dist/Prebuilt/components/ChatSettings.d.ts +2 -0
  12. package/dist/Prebuilt/components/Preview/PreviewForm.d.ts +2 -1
  13. package/dist/Prebuilt/components/SidePaneTabs.d.ts +0 -2
  14. package/dist/Prebuilt/components/TileMenu/TileMenuContent.d.ts +19 -0
  15. package/dist/Prebuilt/components/VirtualBackground/VBOption.d.ts +2 -1
  16. package/dist/Prebuilt/components/hooks/useChatBlacklist.d.ts +2 -1
  17. package/dist/Prebuilt/components/hooks/useSetPinnedMessages.d.ts +1 -1
  18. package/dist/Prebuilt/layouts/SidePane.d.ts +1 -3
  19. package/dist/{chunk-TOKLXTAS.js → chunk-2B7YYNHQ.js} +1651 -1229
  20. package/dist/chunk-2B7YYNHQ.js.map +7 -0
  21. package/dist/index.cjs.js +2074 -1609
  22. package/dist/index.cjs.js.map +4 -4
  23. package/dist/index.js +1 -1
  24. package/dist/meta.cjs.json +451 -115
  25. package/dist/meta.esbuild.json +457 -121
  26. package/package.json +6 -6
  27. package/src/Prebuilt/common/constants.ts +1 -0
  28. package/src/Prebuilt/common/{hooks.js → hooks.ts} +4 -5
  29. package/src/Prebuilt/components/AppData/AppData.tsx +1 -0
  30. package/src/Prebuilt/components/AppData/useUISettings.js +2 -1
  31. package/src/Prebuilt/components/AuthToken.jsx +16 -8
  32. package/src/Prebuilt/components/Chat/{Navigation.tsx → ArrowNavigation.tsx} +3 -19
  33. package/src/Prebuilt/components/Chat/Chat.jsx +15 -44
  34. package/src/Prebuilt/components/Chat/ChatBody.jsx +114 -69
  35. package/src/Prebuilt/components/Chat/ChatFooter.tsx +128 -130
  36. package/src/Prebuilt/components/Chat/ChatSelector.tsx +225 -0
  37. package/src/Prebuilt/components/Chat/ChatSelectorContainer.tsx +158 -0
  38. package/src/Prebuilt/components/Chat/{ChatStates.jsx → ChatStates.tsx} +4 -4
  39. package/src/Prebuilt/components/Chat/PinnedMessage.tsx +59 -41
  40. package/src/Prebuilt/components/Chat/StickIndicator.tsx +24 -0
  41. package/src/Prebuilt/components/Chat/useUnreadCount.ts +19 -0
  42. package/src/Prebuilt/components/ChatSettings.tsx +68 -0
  43. package/src/Prebuilt/components/Footer/ParticipantList.jsx +2 -1
  44. package/src/Prebuilt/components/Header/ParticipantFilter.jsx +2 -1
  45. package/src/Prebuilt/components/Notifications/ChatNotifications.tsx +1 -1
  46. package/src/Prebuilt/components/Preview/PreviewForm.tsx +3 -0
  47. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +2 -1
  48. package/src/Prebuilt/components/SidePaneTabs.tsx +48 -50
  49. package/src/Prebuilt/components/TileMenu/{TileMenuContent.jsx → TileMenuContent.tsx} +72 -41
  50. package/src/Prebuilt/components/VirtualBackground/VBCollection.tsx +2 -1
  51. package/src/Prebuilt/components/VirtualBackground/VBOption.tsx +3 -0
  52. package/src/Prebuilt/components/VirtualBackground/VBToggle.jsx +1 -1
  53. package/src/Prebuilt/components/hooks/useChatBlacklist.ts +8 -6
  54. package/src/Prebuilt/components/hooks/useSetPinnedMessages.ts +2 -7
  55. package/src/Prebuilt/layouts/SidePane.tsx +1 -5
  56. package/src/Prebuilt/provider/roomLayoutProvider/constants/index.ts +1 -0
  57. package/dist/chunk-TOKLXTAS.js.map +0 -7
  58. package/src/Prebuilt/components/Chat/ChatSelector.jsx +0 -161
  59. package/src/Prebuilt/components/Chat/ChatSelectorContainer.jsx +0 -81
  60. package/src/Prebuilt/components/Chat/useUnreadCount.js +0 -17
  61. /package/dist/{HLSView-JTO7E2KW.js.map → HLSView-662T7R7H.js.map} +0 -0
@@ -2,20 +2,22 @@ import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'reac
2
2
  import { useMedia } from 'react-use';
3
3
  import data from '@emoji-mart/data';
4
4
  import Picker from '@emoji-mart/react';
5
- import { selectLocalPeer, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
5
+ import { selectLocalPeer, selectPeerNameByID, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
6
6
  import { EmojiIcon, PauseCircleIcon, SendIcon, VerticalMenuIcon } from '@100mslive/react-icons';
7
7
  import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover, styled, Text } from '../../..';
8
8
  import { IconButton } from '../../../IconButton';
9
9
  // @ts-ignore
10
10
  import { ToastManager } from '../Toast/ToastManager';
11
+ import { ChatSelectorContainer } from './ChatSelectorContainer';
11
12
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
12
13
  // import { ChatSelectorContainer } from './ChatSelectorContainer';
13
14
  // @ts-ignore
14
15
  import { useChatDraftMessage } from '../AppData/useChatState';
15
16
  // @ts-ignore
16
- import { useEmojiPickerStyles } from './useEmojiPickerStyles';
17
+ import { useSubscribeChatSelector } from '../AppData/useUISettings';
17
18
  // @ts-ignore
18
- import { SESSION_STORE_KEY } from '../../common/constants';
19
+ import { useEmojiPickerStyles } from './useEmojiPickerStyles';
20
+ import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants';
19
21
 
20
22
  const TextArea = styled('textarea', {
21
23
  width: '100%',
@@ -69,17 +71,7 @@ function EmojiPicker({ onSelect }: { onSelect: (emoji: any) => void }) {
69
71
  );
70
72
  }
71
73
 
72
- export const ChatFooter = ({
73
- role,
74
- peerId,
75
- onSend,
76
- children /* onSelect, selection, screenType */,
77
- }: {
78
- role: any;
79
- peerId: string;
80
- onSend: any;
81
- children: ReactNode;
82
- }) => {
74
+ export const ChatFooter = ({ onSend, children }: { onSend: () => void; children: ReactNode }) => {
83
75
  const hmsActions = useHMSActions();
84
76
  const inputRef = useRef<HTMLTextAreaElement>(null);
85
77
  const [draftMessage, setDraftMessage] = useChatDraftMessage();
@@ -89,17 +81,21 @@ export const ChatFooter = ({
89
81
  const localPeer = useHMSStore(selectLocalPeer);
90
82
  const isOverlayChat = elements?.chat?.is_overlay;
91
83
  const canDisableChat = !!elements?.chat?.real_time_controls?.can_disable_chat;
92
-
84
+ const isPublicChatEnabled = !!elements?.chat?.public_chat_enabled;
85
+ const selectedPeer = useSubscribeChatSelector(CHAT_SELECTOR.PEER_ID);
86
+ const selectedRole = useSubscribeChatSelector(CHAT_SELECTOR.ROLE);
87
+ const selectorPeerName = useHMSStore(selectPeerNameByID(selectedPeer));
88
+ const selection = selectorPeerName || selectedRole || CHAT_SELECTOR.EVERYONE;
93
89
  const sendMessage = useCallback(async () => {
94
90
  const message = inputRef?.current?.value;
95
91
  if (!message || !message.trim().length) {
96
92
  return;
97
93
  }
98
94
  try {
99
- if (role) {
100
- await hmsActions.sendGroupMessage(message, [role]);
101
- } else if (peerId) {
102
- await hmsActions.sendDirectMessage(message, peerId);
95
+ if (selectedRole) {
96
+ await hmsActions.sendGroupMessage(message, [selectedRole]);
97
+ } else if (selectedPeer) {
98
+ await hmsActions.sendDirectMessage(message, selectedPeer);
103
99
  } else {
104
100
  await hmsActions.sendBroadcastMessage(message);
105
101
  }
@@ -111,7 +107,7 @@ export const ChatFooter = ({
111
107
  const err = error as Error;
112
108
  ToastManager.addToast({ title: err.message });
113
109
  }
114
- }, [role, peerId, hmsActions, onSend]);
110
+ }, [selectedRole, selectedPeer, hmsActions, onSend]);
115
111
 
116
112
  useEffect(() => {
117
113
  const messageElement = inputRef.current;
@@ -129,122 +125,124 @@ export const ChatFooter = ({
129
125
 
130
126
  return (
131
127
  <Box>
132
- {/* {screenType !== 'hls_live_streaming' ? (
133
- <ChatSelectorContainer onSelect={onSelect} role={role} peerId={peerId} selection={selection} />
134
- ) : null} */}
135
- {canDisableChat ? (
136
- <Flex align="center" justify="end" css={{ w: '100%', mb: '$4' }}>
137
- <Popover.Root>
138
- <Popover.Trigger asChild>
139
- <IconButton css={{ border: '1px solid $border_bright' }}>
140
- <VerticalMenuIcon height="16" width="16" />
141
- </IconButton>
142
- </Popover.Trigger>
143
- <Popover.Portal>
144
- <Popover.Content
145
- align="end"
146
- side="top"
147
- onClick={() => {
148
- const chatState = {
149
- enabled: false,
150
- updatedBy: {
151
- peerId: localPeer?.id,
152
- userId: localPeer?.customerUserId,
153
- userName: localPeer?.name,
154
- },
155
- updatedAt: Date.now(),
156
- };
157
- hmsActions.sessionStore.set(SESSION_STORE_KEY.CHAT_STATE, chatState);
158
- }}
159
- css={{
160
- backgroundColor: '$surface_default',
161
- display: 'flex',
162
- alignItems: 'center',
163
- gap: '$4',
164
- borderRadius: '$1',
165
- color: '$on_surface_high',
166
- cursor: 'pointer',
167
- '&:hover': { backgroundColor: '$surface_dim' },
168
- }}
169
- >
170
- <PauseCircleIcon />
171
- <Text variant="sm" css={{ fontWeight: '$semiBold' }}>
172
- Pause Chat
173
- </Text>
174
- </Popover.Content>
175
- </Popover.Portal>
176
- </Popover.Root>
177
- </Flex>
178
- ) : null}
179
- <Flex align="center" css={{ gap: '$4', w: '100%' }}>
180
- <Flex
181
- align="center"
182
- css={{
183
- bg: isOverlayChat && isMobile ? '$surface_dim' : '$surface_default',
184
- minHeight: '$16',
185
- maxHeight: '$24',
186
- position: 'relative',
187
- py: '$6',
188
- pl: '$8',
189
- flexGrow: 1,
190
- r: '$1',
191
- '@md': {
192
- minHeight: 'unset',
193
- h: '$14',
194
- boxSizing: 'border-box',
195
- },
196
- }}
197
- >
198
- {children}
199
- <TextArea
128
+ <Flex>
129
+ <ChatSelectorContainer />
130
+ {canDisableChat && isMobile && isOverlayChat ? (
131
+ <Flex align="center" justify="end" css={{ mb: '$4' }}>
132
+ <Popover.Root>
133
+ <Popover.Trigger asChild>
134
+ <IconButton css={{ border: '1px solid $border_bright' }}>
135
+ <VerticalMenuIcon height="16" width="16" />
136
+ </IconButton>
137
+ </Popover.Trigger>
138
+ <Popover.Portal>
139
+ <Popover.Content
140
+ align="end"
141
+ side="top"
142
+ onClick={() => {
143
+ const chatState = {
144
+ enabled: false,
145
+ updatedBy: {
146
+ peerId: localPeer?.id,
147
+ userId: localPeer?.customerUserId,
148
+ userName: localPeer?.name,
149
+ },
150
+ updatedAt: Date.now(),
151
+ };
152
+ hmsActions.sessionStore.set(SESSION_STORE_KEY.CHAT_STATE, chatState);
153
+ }}
154
+ css={{
155
+ backgroundColor: '$surface_default',
156
+ display: 'flex',
157
+ alignItems: 'center',
158
+ gap: '$4',
159
+ borderRadius: '$1',
160
+ color: '$on_surface_high',
161
+ cursor: 'pointer',
162
+ '&:hover': { backgroundColor: '$surface_dim' },
163
+ }}
164
+ >
165
+ <PauseCircleIcon />
166
+ <Text variant="sm" css={{ fontWeight: '$semiBold' }}>
167
+ Pause Chat
168
+ </Text>
169
+ </Popover.Content>
170
+ </Popover.Portal>
171
+ </Popover.Root>
172
+ </Flex>
173
+ ) : null}
174
+ </Flex>
175
+ {!(selection === CHAT_SELECTOR.EVERYONE && !isPublicChatEnabled) && (
176
+ <Flex align="center" css={{ gap: '$4', w: '100%' }}>
177
+ <Flex
178
+ align="center"
200
179
  css={{
201
- c: '$on_surface_high',
202
- '&:valid ~ .send-msg': { color: '$on_surface_high' },
203
- '& ~ .send-msg': { color: '$on_surface_low' },
204
- '&::placeholder': { color: '$on_surface_medium' },
180
+ bg: isOverlayChat && isMobile ? '$surface_dim' : '$surface_default',
181
+ minHeight: '$16',
182
+ maxHeight: '$24',
183
+ position: 'relative',
184
+ py: '$6',
185
+ pl: '$8',
186
+ flexGrow: 1,
187
+ r: '$1',
188
+ '@md': {
189
+ minHeight: 'unset',
190
+ h: '$14',
191
+ boxSizing: 'border-box',
192
+ },
205
193
  }}
206
- placeholder={message_placeholder}
207
- ref={inputRef}
208
- required
209
- autoFocus={!isMobile}
210
- onKeyPress={async event => {
211
- if (event.key === 'Enter') {
212
- if (!event.shiftKey) {
213
- event.preventDefault();
214
- await sendMessage();
215
- }
216
- }
217
- }}
218
- autoComplete="off"
219
- aria-autocomplete="none"
220
- onPaste={e => e.stopPropagation()}
221
- onCut={e => e.stopPropagation()}
222
- onCopy={e => e.stopPropagation()}
223
- />
224
- {!isMobile ? (
225
- <EmojiPicker
226
- onSelect={(emoji: any) => {
227
- if (inputRef.current) {
228
- inputRef.current.value += ` ${emoji.native} `;
194
+ >
195
+ {children}
196
+ <TextArea
197
+ css={{
198
+ c: '$on_surface_high',
199
+ '&:valid ~ .send-msg': { color: '$on_surface_high' },
200
+ '& ~ .send-msg': { color: '$on_surface_low' },
201
+ '&::placeholder': { color: '$on_surface_medium' },
202
+ }}
203
+ placeholder={message_placeholder}
204
+ ref={inputRef}
205
+ required
206
+ autoFocus={!isMobile}
207
+ onKeyPress={async event => {
208
+ if (event.key === 'Enter') {
209
+ if (!event.shiftKey) {
210
+ event.preventDefault();
211
+ await sendMessage();
212
+ }
229
213
  }
230
214
  }}
215
+ autoComplete="off"
216
+ aria-autocomplete="none"
217
+ onPaste={e => e.stopPropagation()}
218
+ onCut={e => e.stopPropagation()}
219
+ onCopy={e => e.stopPropagation()}
231
220
  />
232
- ) : null}
233
- <BaseIconButton
234
- className="send-msg"
235
- onClick={sendMessage}
236
- css={{
237
- ml: 'auto',
238
- height: 'max-content',
239
- mr: '$4',
240
- '&:hover': { c: isMobile ? '' : '$on_surface_medium' },
241
- }}
242
- data-testid="send_msg_btn"
243
- >
244
- <SendIcon />
245
- </BaseIconButton>
221
+ {!isMobile ? (
222
+ <EmojiPicker
223
+ onSelect={emoji => {
224
+ if (inputRef.current) {
225
+ inputRef.current.value += ` ${emoji.native} `;
226
+ }
227
+ }}
228
+ />
229
+ ) : null}
230
+ <BaseIconButton
231
+ className="send-msg"
232
+ onClick={sendMessage}
233
+ css={{
234
+ ml: 'auto',
235
+ height: 'max-content',
236
+ mr: '$4',
237
+ '&:hover': { c: isMobile ? '' : '$on_surface_medium' },
238
+ }}
239
+ data-testid="send_msg_btn"
240
+ >
241
+ <SendIcon />
242
+ </BaseIconButton>
243
+ </Flex>
246
244
  </Flex>
247
- </Flex>
245
+ )}
248
246
  </Box>
249
247
  );
250
248
  };
@@ -0,0 +1,225 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import {
4
+ HMSPeer,
5
+ selectMessagesUnreadCountByPeerID,
6
+ selectMessagesUnreadCountByRole,
7
+ selectRemotePeers,
8
+ selectUnreadHMSMessagesCount,
9
+ useHMSStore,
10
+ } from '@100mslive/react-sdk';
11
+ import { CheckIcon, PeopleIcon } from '@100mslive/react-icons';
12
+ import { Box, CSS, Dropdown, Flex, HorizontalDivider, Text, Tooltip } from '../../..';
13
+ import { config as cssConfig } from '../../../Theme';
14
+ // @ts-ignore
15
+ import { ParticipantSearch } from '../Footer/ParticipantList';
16
+ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
17
+ // @ts-ignore
18
+ import { useSetSubscribedChatSelector } from '../AppData/useUISettings';
19
+ import { useFilteredRoles } from '../../common/hooks';
20
+ import { CHAT_SELECTOR } from '../../common/constants';
21
+
22
+ const ChatDotIcon = () => {
23
+ return <Box css={{ size: '$6', bg: '$primary_default', mx: '$2', r: '$round' }} />;
24
+ };
25
+
26
+ const SelectorItem = ({
27
+ value,
28
+ active,
29
+ onClick,
30
+ unreadCount,
31
+ icon = undefined,
32
+ }: {
33
+ value: string;
34
+ active: boolean;
35
+ onClick: () => void;
36
+ unreadCount: number;
37
+ icon?: React.JSX.Element;
38
+ }) => {
39
+ const isMobile = useMedia(cssConfig.media.md);
40
+
41
+ const Root = !isMobile
42
+ ? Dropdown.Item
43
+ : ({ children, ...rest }: { children: React.ReactNode; css: CSS }) => (
44
+ <Flex {...rest} css={{ p: '$6 $8', ...rest.css }}>
45
+ {children}
46
+ </Flex>
47
+ );
48
+ return (
49
+ <Root
50
+ data-testid="chat_members"
51
+ css={{ align: 'center', px: '$10', py: '$4', bg: '$surface_default' }}
52
+ onClick={onClick}
53
+ >
54
+ <Text
55
+ variant="sm"
56
+ css={{ display: 'flex', alignItems: 'center', gap: '$4', fontWeight: '$semiBold', color: '$on_surface_high' }}
57
+ >
58
+ {icon}
59
+ {value}
60
+ </Text>
61
+ <Flex align="center" css={{ ml: 'auto', color: '$on_primary_high' }}>
62
+ {unreadCount > 0 && (
63
+ <Tooltip title={`${unreadCount} unread`}>
64
+ <Box css={{ mr: active ? '$3' : 0 }}>
65
+ <ChatDotIcon />
66
+ </Box>
67
+ </Tooltip>
68
+ )}
69
+ {active && <CheckIcon width={16} height={16} />}
70
+ </Flex>
71
+ </Root>
72
+ );
73
+ };
74
+
75
+ const SelectorHeader = React.memo(
76
+ ({ isHorizontalDivider = true, children }: { isHorizontalDivider?: boolean; children: React.ReactNode }) => {
77
+ return (
78
+ <Box css={{ flexShrink: 0 }}>
79
+ {isHorizontalDivider && <HorizontalDivider space={4} />}
80
+ <Text
81
+ variant="overline"
82
+ css={{ p: '$4 $10', fontWeight: '$semiBold', textTransform: 'uppercase', color: '$on_surface_medium' }}
83
+ >
84
+ {children}
85
+ </Text>
86
+ </Box>
87
+ );
88
+ },
89
+ );
90
+
91
+ const Everyone = React.memo(({ active }: { active: boolean }) => {
92
+ const unreadCount: number = useHMSStore(selectUnreadHMSMessagesCount);
93
+ const [, setPeerSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.PEER_ID);
94
+ const [, setRoleSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.ROLE);
95
+ return (
96
+ <SelectorItem
97
+ value="Everyone"
98
+ icon={<PeopleIcon />}
99
+ active={active}
100
+ unreadCount={unreadCount}
101
+ onClick={() => {
102
+ setPeerSelector('');
103
+ setRoleSelector('');
104
+ }}
105
+ />
106
+ );
107
+ });
108
+
109
+ const RoleItem = React.memo(({ role, active }: { role: string; active: boolean }) => {
110
+ const unreadCount: number = useHMSStore(selectMessagesUnreadCountByRole(role));
111
+ const [, setPeerSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.PEER_ID);
112
+ const [, setRoleSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.ROLE);
113
+ return (
114
+ <SelectorItem
115
+ value={role}
116
+ active={active}
117
+ unreadCount={unreadCount}
118
+ onClick={() => {
119
+ setPeerSelector('');
120
+ setRoleSelector(role);
121
+ }}
122
+ />
123
+ );
124
+ });
125
+
126
+ const PeerItem = ({ peerId, name, active }: { name: string; peerId: string; active: boolean }) => {
127
+ const unreadCount: number = useHMSStore(selectMessagesUnreadCountByPeerID(peerId));
128
+ const [, setPeerSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.PEER_ID);
129
+ const [, setRoleSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.ROLE);
130
+
131
+ return (
132
+ <SelectorItem
133
+ value={name}
134
+ active={active}
135
+ unreadCount={unreadCount}
136
+ onClick={() => {
137
+ setPeerSelector(peerId);
138
+ setRoleSelector('');
139
+ }}
140
+ />
141
+ );
142
+ };
143
+
144
+ const VirtualizedSelectItemList = ({
145
+ peers,
146
+ selectedRole,
147
+ selectedPeerId,
148
+ searchValue,
149
+ }: {
150
+ peers: HMSPeer[];
151
+ selectedRole: string;
152
+ selectedPeerId: string;
153
+ searchValue: string;
154
+ }) => {
155
+ const roles = useFilteredRoles();
156
+ const isMobile = useMedia(cssConfig.media.md);
157
+ const filteredPeers = useMemo(
158
+ () =>
159
+ peers.filter(
160
+ // search should be empty or search phrase should be included in name
161
+ peer => !searchValue || peer.name.toLowerCase().includes(searchValue.toLowerCase()),
162
+ ),
163
+ [peers, searchValue],
164
+ );
165
+
166
+ const listItems = useMemo(() => {
167
+ const selectItems = !searchValue ? [<Everyone active={!selectedRole && !selectedPeerId} />] : [];
168
+
169
+ roles.length > 0 && !searchValue && selectItems.push(<SelectorHeader>Roles</SelectorHeader>);
170
+ !searchValue &&
171
+ roles.forEach(userRole =>
172
+ selectItems.push(<RoleItem key={userRole} active={selectedRole === userRole} role={userRole} />),
173
+ );
174
+
175
+ filteredPeers.length > 0 && selectItems.push(<SelectorHeader>Participants</SelectorHeader>);
176
+ filteredPeers.forEach(peer =>
177
+ selectItems.push(
178
+ <PeerItem key={peer.id} name={peer.name} peerId={peer.id} active={peer.id === selectedPeerId} />,
179
+ ),
180
+ );
181
+
182
+ return selectItems;
183
+ }, [searchValue, selectedRole, selectedPeerId, roles, filteredPeers]);
184
+
185
+ if (!isMobile) {
186
+ return (
187
+ <Dropdown.Group css={{ overflowY: 'auto', maxHeight: '$64', bg: '$surface_default' }}>
188
+ {listItems.map((item, index) => (
189
+ <Box key={index}>{item}</Box>
190
+ ))}
191
+ </Dropdown.Group>
192
+ );
193
+ }
194
+ return (
195
+ <>
196
+ {listItems.map((item, index) => (
197
+ <Box key={index}>{item}</Box>
198
+ ))}
199
+ </>
200
+ );
201
+ };
202
+
203
+ export const ChatSelector = ({ role, peerId }: { role: string; peerId: string }) => {
204
+ const { elements } = useRoomLayoutConferencingScreen();
205
+ const peers = useHMSStore(selectRemotePeers);
206
+ const [search, setSearch] = useState('');
207
+
208
+ const isPrivateChatEnabled = !!elements?.chat?.private_chat_enabled;
209
+
210
+ return (
211
+ <>
212
+ {peers.length > 0 && isPrivateChatEnabled && (
213
+ <Box css={{ px: '$4' }}>
214
+ <ParticipantSearch onSearch={setSearch} placeholder="Search for participants" />
215
+ </Box>
216
+ )}
217
+ <VirtualizedSelectItemList
218
+ selectedRole={role}
219
+ selectedPeerId={peerId}
220
+ peers={isPrivateChatEnabled ? peers : []}
221
+ searchValue={search}
222
+ />
223
+ </>
224
+ );
225
+ };