@100mslive/roomkit-react 0.1.18-alpha.1 → 0.1.19-alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. package/dist/{HLSView-MR7RYQZB.js → HLSView-GG4WVUQY.js} +2 -2
  2. package/dist/Prebuilt/common/constants.d.ts +2 -6
  3. package/dist/Prebuilt/components/Chat/Chat.d.ts +2 -0
  4. package/dist/Prebuilt/components/Chat/ChatActions.d.ts +12 -0
  5. package/dist/Prebuilt/components/Chat/ChatBody.d.ts +8 -0
  6. package/dist/Prebuilt/components/Chat/ChatFooter.d.ts +2 -2
  7. package/dist/Prebuilt/components/Chat/ChatStates.d.ts +1 -1
  8. package/dist/Prebuilt/components/Chat/MwebChatOption.d.ts +1 -1
  9. package/dist/Prebuilt/components/Chat/PinnedMessage.d.ts +1 -3
  10. package/dist/Prebuilt/components/hooks/useChatBlacklist.d.ts +4 -0
  11. package/dist/Prebuilt/components/hooks/useSetPinnedMessages.d.ts +3 -10
  12. package/dist/Prebuilt/components/hooks/useUnreadPollQuizPresent.d.ts +5 -0
  13. package/dist/{chunk-WFHOR7AP.js → chunk-GXJIUWTP.js} +10083 -4574
  14. package/dist/chunk-GXJIUWTP.js.map +7 -0
  15. package/dist/index.cjs.js +12716 -7192
  16. package/dist/index.cjs.js.map +4 -4
  17. package/dist/index.js +1 -1
  18. package/dist/meta.cjs.json +367 -240
  19. package/dist/meta.esbuild.json +377 -250
  20. package/package.json +6 -6
  21. package/src/Prebuilt/common/constants.ts +4 -4
  22. package/src/Prebuilt/components/Chat/Chat.tsx +108 -0
  23. package/src/Prebuilt/components/Chat/ChatActions.tsx +297 -0
  24. package/src/Prebuilt/components/Chat/ChatBody.tsx +444 -0
  25. package/src/Prebuilt/components/Chat/ChatFooter.tsx +9 -3
  26. package/src/Prebuilt/components/Chat/ChatStates.tsx +5 -0
  27. package/src/Prebuilt/components/Chat/MwebChatOption.tsx +1 -1
  28. package/src/Prebuilt/components/Chat/PinnedMessage.tsx +4 -2
  29. package/src/Prebuilt/components/Footer/PollsToggle.tsx +12 -3
  30. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +5 -1
  31. package/src/Prebuilt/components/Polls/CreateQuestions/QuestionForm.jsx +3 -3
  32. package/src/Prebuilt/components/Polls/Voting/Leaderboard.tsx +9 -1
  33. package/src/Prebuilt/components/Polls/Voting/LeaderboardEntry.tsx +6 -6
  34. package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +20 -23
  35. package/src/Prebuilt/components/Polls/common/MultipleChoiceOptions.jsx +1 -1
  36. package/src/Prebuilt/components/SidePaneTabs.tsx +33 -11
  37. package/src/Prebuilt/components/hooks/useChatBlacklist.ts +7 -1
  38. package/src/Prebuilt/components/hooks/useSetPinnedMessages.ts +19 -11
  39. package/src/Prebuilt/components/hooks/useUnreadPollQuizPresent.tsx +20 -0
  40. package/src/Prebuilt/provider/roomLayoutProvider/index.tsx +11 -2
  41. package/dist/chunk-WFHOR7AP.js.map +0 -7
  42. package/src/Prebuilt/components/Chat/Chat.jsx +0 -124
  43. package/src/Prebuilt/components/Chat/ChatBody.jsx +0 -726
  44. /package/dist/{HLSView-MR7RYQZB.js.map → HLSView-GG4WVUQY.js.map} +0 -0
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "prebuilt",
11
11
  "roomkit"
12
12
  ],
13
- "version": "0.1.18-alpha.1",
13
+ "version": "0.1.19-alpha.0",
14
14
  "author": "100ms",
15
15
  "license": "MIT",
16
16
  "files": [
@@ -76,10 +76,10 @@
76
76
  "react": ">=17.0.2 <19.0.0"
77
77
  },
78
78
  "dependencies": {
79
- "@100mslive/hls-player": "0.1.27-alpha.1",
80
- "@100mslive/hms-virtual-background": "1.11.27-alpha.1",
81
- "@100mslive/react-icons": "0.8.27-alpha.1",
82
- "@100mslive/react-sdk": "0.8.27-alpha.1",
79
+ "@100mslive/hls-player": "0.1.28-alpha.0",
80
+ "@100mslive/hms-virtual-background": "1.11.28-alpha.0",
81
+ "@100mslive/react-icons": "0.8.28-alpha.0",
82
+ "@100mslive/react-sdk": "0.8.28-alpha.0",
83
83
  "@100mslive/types-prebuilt": "0.12.5",
84
84
  "@emoji-mart/data": "^1.0.6",
85
85
  "@emoji-mart/react": "^1.0.1",
@@ -115,5 +115,5 @@
115
115
  "uuid": "^8.3.2",
116
116
  "worker-timers": "^7.0.40"
117
117
  },
118
- "gitHead": "ce20a10ac4c2cea6ac8a7cc4ffc0226c45aa8975"
118
+ "gitHead": "92b555102a4b5f0cc1f2913738c56a8e8cdf4b2b"
119
119
  }
@@ -121,15 +121,15 @@ export enum INTERACTION_TYPE {
121
121
  export enum QUESTION_TYPE_TITLE {
122
122
  'single-choice' = 'Single Choice',
123
123
  'multiple-choice' = 'Multiple Choice',
124
- 'short-answer' = 'Short Answer',
125
- 'long-answer' = 'Long Answer',
124
+ // 'short-answer' = 'Short Answer',
125
+ // 'long-answer' = 'Long Answer',
126
126
  }
127
127
 
128
128
  export enum QUESTION_TYPE {
129
129
  SINGLE_CHOICE = 'single-choice',
130
130
  MULTIPLE_CHOICE = 'multiple-choice',
131
- SHORT_ANSWER = 'short-answer',
132
- LONG_ANSWER = 'long-answer',
131
+ // SHORT_ANSWER = 'short-answer',
132
+ // LONG_ANSWER = 'long-answer',
133
133
  }
134
134
 
135
135
  export const ROLE_CHANGE_DECLINED = 'role_change_declined';
@@ -0,0 +1,108 @@
1
+ import React, { MutableRefObject, useCallback, useRef } from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { VariableSizeList } from 'react-window';
4
+ import { selectSessionStore, selectUnreadHMSMessagesCount } from '@100mslive/hms-video-store';
5
+ import { selectHMSMessagesCount, useHMSActions, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
6
+ import { ChevronDownIcon } from '@100mslive/react-icons';
7
+ import { Button } from '../../../Button';
8
+ import { Flex } from '../../../Layout';
9
+ import { config as cssConfig } from '../../../Theme';
10
+ import { ChatBody } from './ChatBody';
11
+ import { ChatFooter } from './ChatFooter';
12
+ import { ChatBlocked, ChatPaused } from './ChatStates';
13
+ import { PinnedMessage } from './PinnedMessage';
14
+ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
15
+ import { SESSION_STORE_KEY } from '../../common/constants';
16
+
17
+ export const Chat = () => {
18
+ const { elements } = useRoomLayoutConferencingScreen();
19
+ const listRef = useRef<VariableSizeList | null>(null);
20
+ const hmsActions = useHMSActions();
21
+ const vanillaStore = useHMSVanillaStore();
22
+ const { enabled: isChatEnabled = true } = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE)) || {};
23
+ const isMobile = useMedia(cssConfig.media.md);
24
+ const scrollToBottom = useCallback(
25
+ (unreadCount = 0) => {
26
+ if (listRef.current && listRef.current.scrollToItem && unreadCount > 0) {
27
+ const messagesCount = vanillaStore.getState(selectHMSMessagesCount);
28
+ listRef.current?.scrollToItem(messagesCount, 'end');
29
+ requestAnimationFrame(() => {
30
+ listRef.current?.scrollToItem(messagesCount, 'end');
31
+ });
32
+ hmsActions.setMessageRead(true);
33
+ }
34
+ },
35
+ [hmsActions, vanillaStore],
36
+ );
37
+
38
+ return (
39
+ <Flex
40
+ direction="column"
41
+ css={{
42
+ size: '100%',
43
+ gap: '$4',
44
+ }}
45
+ >
46
+ {isMobile && elements?.chat?.is_overlay ? null : <PinnedMessage />}
47
+ <ChatBody ref={listRef} scrollToBottom={scrollToBottom} />
48
+ <ChatPaused />
49
+ <ChatBlocked />
50
+ {isMobile && elements?.chat?.is_overlay ? <PinnedMessage /> : null}
51
+ {isChatEnabled ? (
52
+ <ChatFooter onSend={scrollToBottom}>
53
+ <NewMessageIndicator scrollToBottom={scrollToBottom} listRef={listRef} />
54
+ </ChatFooter>
55
+ ) : null}
56
+ </Flex>
57
+ );
58
+ };
59
+
60
+ const NewMessageIndicator = ({
61
+ scrollToBottom,
62
+ listRef,
63
+ }: {
64
+ scrollToBottom: (count: number) => void;
65
+ listRef: MutableRefObject<VariableSizeList | null>;
66
+ }) => {
67
+ const unreadCount = useHMSStore(selectUnreadHMSMessagesCount);
68
+ if (!unreadCount || !listRef.current) {
69
+ return null;
70
+ }
71
+ // @ts-ignore
72
+ const outerElement = listRef.current._outerRef;
73
+ // @ts-ignore
74
+ if (outerElement.scrollHeight === listRef.current.state.scrollOffset + outerElement.offsetHeight) {
75
+ return null;
76
+ }
77
+ return (
78
+ <Flex
79
+ justify="center"
80
+ css={{
81
+ width: '100%',
82
+ left: 0,
83
+ bottom: '$28',
84
+ position: 'absolute',
85
+ }}
86
+ >
87
+ <Button
88
+ variant="standard"
89
+ onClick={() => {
90
+ scrollToBottom(unreadCount);
91
+ }}
92
+ icon
93
+ css={{
94
+ p: '$3 $4',
95
+ pl: '$6',
96
+ '& > svg': { ml: '$4' },
97
+ borderRadius: '$round',
98
+ fontSize: '$xs',
99
+ fontWeight: '$semiBold',
100
+ c: '$on_secondary_high',
101
+ }}
102
+ >
103
+ New {unreadCount === 1 ? 'message' : 'messages'}
104
+ <ChevronDownIcon height={16} width={16} />
105
+ </Button>
106
+ </Flex>
107
+ );
108
+ };
@@ -0,0 +1,297 @@
1
+ import React, { useCallback, useState } from 'react';
2
+ import { HMSMessage, selectLocalPeerName, selectPermissions, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
3
+ import {
4
+ CopyIcon,
5
+ CrossCircleIcon,
6
+ CrossIcon,
7
+ EyeCloseIcon,
8
+ PeopleRemoveIcon,
9
+ PinIcon,
10
+ ReplyIcon,
11
+ VerticalMenuIcon,
12
+ } from '@100mslive/react-icons';
13
+ import { Dropdown } from '../../../Dropdown';
14
+ import { IconButton } from '../../../IconButton';
15
+ import { Flex } from '../../../Layout';
16
+ import { Sheet } from '../../../Sheet';
17
+ import { Text } from '../../../Text';
18
+ import { Tooltip } from '../../../Tooltip';
19
+ // @ts-ignore
20
+ import { ToastManager } from '../Toast/ToastManager';
21
+ import { MwebChatOption } from './MwebChatOption';
22
+ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
23
+ import { useChatBlacklist, useIsPeerBlacklisted } from '../hooks/useChatBlacklist';
24
+ import { useSetPinnedMessages } from '../hooks/useSetPinnedMessages';
25
+ import { SESSION_STORE_KEY } from '../../common/constants';
26
+
27
+ const iconStyle = { height: '1.125rem', width: '1.125rem' };
28
+ const tooltipBoxCSS = {
29
+ fontSize: '$xs',
30
+ backgroundColor: '$surface_default',
31
+ p: '$1 $5',
32
+ fontWeight: '$regular',
33
+ borderRadius: '$3',
34
+ };
35
+
36
+ export const ChatActions = ({
37
+ showPinAction,
38
+ onReply,
39
+ showReply,
40
+ message,
41
+ sentByLocalPeer,
42
+ isMobile,
43
+ openSheet,
44
+ setOpenSheet,
45
+ }: {
46
+ showPinAction: boolean;
47
+ onReply: () => void;
48
+ showReply: boolean;
49
+ message: HMSMessage;
50
+ sentByLocalPeer: boolean;
51
+ isMobile: boolean;
52
+ openSheet: boolean;
53
+ setOpenSheet: (value: boolean) => void;
54
+ }) => {
55
+ const { elements } = useRoomLayoutConferencingScreen();
56
+ const { can_hide_message, can_block_user } = elements?.chat?.real_time_controls || {
57
+ can_hide_message: false,
58
+ can_block_user: false,
59
+ };
60
+ const [open, setOpen] = useState(false);
61
+ const actions = useHMSActions();
62
+ const canRemoveOthers = useHMSStore(selectPermissions)?.removeOthers;
63
+ const { blacklistItem: blacklistPeer } = useChatBlacklist(SESSION_STORE_KEY.CHAT_PEER_BLACKLIST);
64
+ const localPeerName = useHMSStore(selectLocalPeerName);
65
+ const { setPinnedMessages, unpinBlacklistedMessages } = useSetPinnedMessages();
66
+
67
+ const { blacklistItem: blacklistMessage, blacklistedIDs: blacklistedMessageIDs } = useChatBlacklist(
68
+ SESSION_STORE_KEY.CHAT_MESSAGE_BLACKLIST,
69
+ );
70
+
71
+ const isSenderBlocked = useIsPeerBlacklisted({ peerCustomerUserId: message.senderUserId });
72
+
73
+ const updatePinnedMessages = useCallback(
74
+ (messageID = '') => {
75
+ const blacklistedMessageIDSet = new Set([...(blacklistedMessageIDs || []), messageID]);
76
+ unpinBlacklistedMessages(blacklistedMessageIDSet);
77
+ },
78
+ [blacklistedMessageIDs, unpinBlacklistedMessages],
79
+ );
80
+
81
+ const copyMessageContent = useCallback(() => {
82
+ try {
83
+ navigator?.clipboard.writeText(message.message);
84
+ ToastManager.addToast({
85
+ title: 'Message copied successfully',
86
+ });
87
+ } catch (e) {
88
+ console.log(e);
89
+ ToastManager.addToast({
90
+ title: 'Could not copy message',
91
+ });
92
+ }
93
+ }, [message]);
94
+
95
+ const options: Record<
96
+ string,
97
+ {
98
+ text: string;
99
+ tooltipText?: string;
100
+ icon: React.ReactNode;
101
+ onClick: () => void | Promise<void>;
102
+ show: boolean;
103
+ color?: string;
104
+ }
105
+ > = {
106
+ reply: {
107
+ text: message.recipientRoles?.length ? 'Reply to Group' : 'Reply Privately',
108
+ tooltipText: message.recipientRoles?.length ? 'Reply to Group' : 'Reply Privately',
109
+ icon: <ReplyIcon style={iconStyle} />,
110
+ onClick: onReply,
111
+ show: showReply,
112
+ },
113
+ pin: {
114
+ text: 'Pin message',
115
+ tooltipText: 'Pin',
116
+ icon: <PinIcon style={iconStyle} />,
117
+ onClick: () => setPinnedMessages(message, localPeerName || ''),
118
+ show: showPinAction,
119
+ },
120
+ copy: {
121
+ text: 'Copy text',
122
+ tooltipText: 'Copy',
123
+ icon: <CopyIcon style={iconStyle} />,
124
+ onClick: copyMessageContent,
125
+ show: true,
126
+ },
127
+ hide: {
128
+ text: message.recipientPeer ? 'Hide for both' : 'Hide for everyone',
129
+ icon: <EyeCloseIcon style={iconStyle} />,
130
+ onClick: async () => {
131
+ blacklistMessage(message.id);
132
+ updatePinnedMessages(message.id);
133
+ },
134
+ show: !!can_hide_message,
135
+ },
136
+ block: {
137
+ text: 'Block from chat',
138
+ icon: <CrossCircleIcon style={iconStyle} />,
139
+ onClick: async () => {
140
+ if (message.senderUserId) {
141
+ blacklistPeer(message.senderUserId);
142
+ }
143
+ },
144
+ color: '$alert_error_default',
145
+ show: !!can_block_user && !sentByLocalPeer && !isSenderBlocked,
146
+ },
147
+ remove: {
148
+ text: 'Remove Partipant',
149
+ icon: <PeopleRemoveIcon style={iconStyle} />,
150
+ color: '$alert_error_default',
151
+ show: !!canRemoveOthers && !sentByLocalPeer,
152
+ onClick: async () => {
153
+ if (!message.sender) {
154
+ return;
155
+ }
156
+ try {
157
+ await actions.removePeer(message.sender, '');
158
+ } catch (error) {
159
+ ToastManager.addToast({ title: (error as Error).message, variant: 'error' });
160
+ }
161
+ },
162
+ },
163
+ };
164
+
165
+ if (isMobile) {
166
+ return (
167
+ <Sheet.Root open={openSheet} onOpenChange={setOpenSheet}>
168
+ <Sheet.Content css={{ bg: '$surface_default', pb: '$14' }} onClick={() => setOpenSheet(false)}>
169
+ <Sheet.Title
170
+ css={{
171
+ display: 'flex',
172
+ color: '$on_surface_high',
173
+ w: '100%',
174
+ justifyContent: 'space-between',
175
+ mt: '$8',
176
+ fontSize: '$md',
177
+ px: '$10',
178
+ pb: '$8',
179
+ borderBottom: '1px solid $border_bright',
180
+ alignItems: 'center',
181
+ }}
182
+ >
183
+ Message options
184
+ <Sheet.Close css={{ color: '$on_surface_high' }} onClick={() => setOpenSheet(false)}>
185
+ <CrossIcon />
186
+ </Sheet.Close>
187
+ </Sheet.Title>
188
+
189
+ {Object.keys(options).map(optionKey => {
190
+ const option = options[optionKey];
191
+ return option.show ? (
192
+ <MwebChatOption
193
+ key={optionKey}
194
+ text={option.text}
195
+ icon={option.icon}
196
+ onClick={option.onClick}
197
+ color={option?.color}
198
+ />
199
+ ) : null;
200
+ })}
201
+ </Sheet.Content>
202
+ </Sheet.Root>
203
+ );
204
+ }
205
+
206
+ return (
207
+ <Dropdown.Root open={open} onOpenChange={setOpen} css={{ '@md': { display: 'none' } }}>
208
+ <Flex
209
+ className="chat_actions"
210
+ css={{
211
+ background: '$surface_bright',
212
+ borderRadius: '$1',
213
+ p: '$2',
214
+ opacity: open ? 1 : 0,
215
+ position: 'absolute',
216
+ right: 0,
217
+ zIndex: 1,
218
+ '@md': { opacity: 1 },
219
+ }}
220
+ >
221
+ {options.reply.show ? (
222
+ <Tooltip boxCss={tooltipBoxCSS} title={options.reply.tooltipText}>
223
+ <IconButton data-testid="reply_message_btn" onClick={options.reply.onClick}>
224
+ {options.reply.icon}
225
+ </IconButton>
226
+ </Tooltip>
227
+ ) : null}
228
+ {options.pin.show ? (
229
+ <Tooltip boxCss={tooltipBoxCSS} title={options.pin.tooltipText}>
230
+ <IconButton data-testid="pin_message_btn" onClick={options.pin.onClick}>
231
+ {options.pin.icon}
232
+ </IconButton>
233
+ </Tooltip>
234
+ ) : null}
235
+
236
+ {options.copy.show ? (
237
+ <Tooltip boxCss={tooltipBoxCSS} title={options.copy.tooltipText}>
238
+ <IconButton onClick={options.copy.onClick} data-testid="copy_message_btn">
239
+ <CopyIcon style={iconStyle} />
240
+ </IconButton>
241
+ </Tooltip>
242
+ ) : null}
243
+
244
+ {options.block.show || options.hide.show || options.remove.show ? (
245
+ <Tooltip boxCss={tooltipBoxCSS} title="More actions">
246
+ <Dropdown.Trigger asChild>
247
+ <IconButton>
248
+ <VerticalMenuIcon style={iconStyle} />
249
+ </IconButton>
250
+ </Dropdown.Trigger>
251
+ </Tooltip>
252
+ ) : null}
253
+ </Flex>
254
+ <Dropdown.Portal>
255
+ <Dropdown.Content
256
+ sideOffset={5}
257
+ align="end"
258
+ css={{ width: '$48', backgroundColor: '$surface_bright', py: '$0', border: '1px solid $border_bright' }}
259
+ >
260
+ {options.hide.show ? (
261
+ <Dropdown.Item data-testid="hide_message_btn" onClick={options.hide.onClick}>
262
+ {options.hide.icon}
263
+ <Text variant="sm" css={{ ml: '$4', fontWeight: '$semiBold' }}>
264
+ {options.hide.text}
265
+ </Text>
266
+ </Dropdown.Item>
267
+ ) : null}
268
+
269
+ {options.block.show ? (
270
+ <Dropdown.Item
271
+ data-testid="block_peer_btn"
272
+ onClick={options.block.onClick}
273
+ css={{ color: options.block.color }}
274
+ >
275
+ {options.block.icon}
276
+ <Text variant="sm" css={{ ml: '$4', color: 'inherit', fontWeight: '$semiBold' }}>
277
+ {options.block.text}
278
+ </Text>
279
+ </Dropdown.Item>
280
+ ) : null}
281
+ {options.remove.show ? (
282
+ <Dropdown.Item
283
+ data-testid="remove_peer_btn"
284
+ onClick={options.remove.onClick}
285
+ css={{ color: options.remove.color }}
286
+ >
287
+ {options.remove.icon}
288
+ <Text variant="sm" css={{ ml: '$4', color: 'inherit', fontWeight: '$semiBold' }}>
289
+ {options.remove.text}
290
+ </Text>
291
+ </Dropdown.Item>
292
+ ) : null}
293
+ </Dropdown.Content>
294
+ </Dropdown.Portal>
295
+ </Dropdown.Root>
296
+ );
297
+ };