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

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 (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
+ };