@100mslive/roomkit-react 0.3.14-alpha.0 → 0.3.14-alpha.10

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 (46) hide show
  1. package/dist/Diagnostics/AudioTest.d.ts +2 -0
  2. package/dist/Diagnostics/BrowserTest.d.ts +81 -0
  3. package/dist/Diagnostics/ConnectivityTest.d.ts +7 -0
  4. package/dist/Diagnostics/Diagnostics.d.ts +2 -0
  5. package/dist/Diagnostics/VideoTest.d.ts +2 -0
  6. package/dist/Diagnostics/components.d.ts +18 -0
  7. package/dist/Diagnostics/hms.d.ts +9 -0
  8. package/dist/Diagnostics/index.d.ts +1 -0
  9. package/dist/{HLSView-USRUP6VG.js → HLSView-PL2BEA32.js} +2 -2
  10. package/dist/{HLSView-7LHIA6HH.css → HLSView-TAAU7UCF.css} +3 -3
  11. package/dist/{HLSView-7LHIA6HH.css.map → HLSView-TAAU7UCF.css.map} +1 -1
  12. package/dist/Prebuilt/App.d.ts +1 -0
  13. package/dist/Prebuilt/components/Notifications/PermissionErrorModal.d.ts +5 -1
  14. package/dist/Stats/index.d.ts +1 -0
  15. package/dist/{chunk-DYDYPNYY.js → chunk-EKH2S2VL.js} +13835 -2768
  16. package/dist/chunk-EKH2S2VL.js.map +7 -0
  17. package/dist/index.cjs.css +2 -2
  18. package/dist/index.cjs.css.map +1 -1
  19. package/dist/index.cjs.js +14870 -3708
  20. package/dist/index.cjs.js.map +4 -4
  21. package/dist/index.css +2 -2
  22. package/dist/index.css.map +1 -1
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +5 -1
  25. package/dist/meta.cjs.json +972 -197
  26. package/dist/meta.esbuild.json +984 -205
  27. package/package.json +7 -7
  28. package/src/Diagnostics/AudioTest.tsx +176 -0
  29. package/src/Diagnostics/BrowserTest.tsx +139 -0
  30. package/src/Diagnostics/ConnectivityTest.tsx +359 -0
  31. package/src/Diagnostics/DeviceSelector.jsx +71 -0
  32. package/src/Diagnostics/Diagnostics.tsx +134 -0
  33. package/src/Diagnostics/VideoTest.tsx +68 -0
  34. package/src/Diagnostics/components.tsx +96 -0
  35. package/src/Diagnostics/hms.ts +9 -0
  36. package/src/Diagnostics/index.ts +1 -0
  37. package/src/Prebuilt/App.tsx +3 -0
  38. package/src/Prebuilt/components/Chat/ChatFooter.tsx +20 -3
  39. package/src/Prebuilt/components/Header/common.jsx +3 -0
  40. package/src/Prebuilt/components/Notifications/Notifications.tsx +2 -2
  41. package/src/Prebuilt/components/Notifications/PermissionErrorModal.tsx +13 -11
  42. package/src/Prebuilt/components/StatsForNerds.jsx +1 -13
  43. package/src/Stats/index.tsx +1 -0
  44. package/src/index.ts +1 -0
  45. package/dist/chunk-DYDYPNYY.js.map +0 -7
  46. /package/dist/{HLSView-USRUP6VG.js.map → HLSView-PL2BEA32.js.map} +0 -0
@@ -0,0 +1,96 @@
1
+ import React, { useContext } from 'react';
2
+ import { Button } from '../Button';
3
+ import { Box, Flex } from '../Layout';
4
+ import { Text } from '../Text';
5
+ import { CSS } from '../Theme';
6
+ import { hmsDiagnostics } from './hms';
7
+
8
+ export const DiagnosticsSteps: Record<string, string> = {
9
+ browser: 'Browser Support',
10
+ video: 'Test Video',
11
+ audio: 'Test Audio',
12
+ connectivity: 'Connection Quality',
13
+ };
14
+
15
+ export const DiagnosticsContext = React.createContext<{
16
+ activeStep: string;
17
+ setActiveStep: React.Dispatch<React.SetStateAction<string>>;
18
+ connectivityTested: boolean;
19
+ setConnectivityTested: React.Dispatch<React.SetStateAction<boolean>>;
20
+ }>({
21
+ activeStep: 'video',
22
+ setActiveStep: () => {
23
+ return;
24
+ },
25
+ connectivityTested: false,
26
+ setConnectivityTested: () => {
27
+ return;
28
+ },
29
+ });
30
+
31
+ export const TestContainer = ({ css, children }: { css?: CSS; children: React.ReactNode }) => {
32
+ return <Box css={{ p: '$10', ...css }}>{children}</Box>;
33
+ };
34
+
35
+ export const TestFooter = ({
36
+ error,
37
+ ctaText,
38
+ children,
39
+ }: {
40
+ ctaText?: string;
41
+ error?: Error;
42
+ children?: React.ReactNode;
43
+ }) => {
44
+ const { activeStep, setActiveStep } = useContext(DiagnosticsContext);
45
+
46
+ const onNextStep = () => {
47
+ if (activeStep === 'audio') {
48
+ hmsDiagnostics.stopMicCheck();
49
+ } else if (activeStep === 'video') {
50
+ hmsDiagnostics.stopCameraCheck();
51
+ } else if (activeStep === 'connectivity') {
52
+ hmsDiagnostics.stopConnectivityCheck();
53
+ }
54
+
55
+ const keys = Object.keys(DiagnosticsSteps);
56
+ setActiveStep(step => keys[keys.indexOf(step) + 1]);
57
+ };
58
+
59
+ return (
60
+ <Flex
61
+ css={{
62
+ py: '$8',
63
+ px: '$10',
64
+ position: 'sticky',
65
+ bottom: '0',
66
+ background: '$background_dim',
67
+ justifyContent: 'space-between',
68
+ alignItems: 'center',
69
+ borderTop: '1px solid $border_default',
70
+ fontSize: '$sm',
71
+ borderBottomLeftRadius: '$1',
72
+ borderBottomRightRadius: '$1',
73
+ lineHeight: '$sm',
74
+ zIndex: 1001,
75
+ '@lg': { flexDirection: 'column', gap: '$8' },
76
+ }}
77
+ >
78
+ <Box>{error && <Text css={{ c: '$alert_error_default' }}>Error: {error.message}</Text>}</Box>
79
+ {children ? (
80
+ children
81
+ ) : (
82
+ <Flex align="center" css={{ gap: '$8', '@lg': { flexDirection: 'column' } }}>
83
+ <Text css={{ c: '$on_primary_medium' }}>{ctaText}</Text>
84
+ <Flex align="center" gap="4">
85
+ <Button onClick={onNextStep} variant="standard" outlined={true}>
86
+ Skip
87
+ </Button>
88
+ <Button disabled={!!error} onClick={onNextStep}>
89
+ Yes
90
+ </Button>
91
+ </Flex>
92
+ </Flex>
93
+ )}
94
+ </Flex>
95
+ );
96
+ };
@@ -0,0 +1,9 @@
1
+ // @ts-check
2
+ import { HMSReactiveStore } from '@100mslive/hms-video-store';
3
+
4
+ const hms = new HMSReactiveStore();
5
+ export const hmsStore = hms.getStore();
6
+ export const hmsActions = hms.getActions();
7
+ export const hmsNotifications = hms.getNotifications();
8
+ export const hmsStats = hms.getStats();
9
+ export const hmsDiagnostics = hms.getDiagnosticsSDK();
@@ -0,0 +1 @@
1
+ export { Diagnostics } from './Diagnostics';
@@ -65,6 +65,7 @@ export type HMSPrebuiltProps = {
65
65
  options?: HMSPrebuiltOptions;
66
66
  screens?: Screens;
67
67
  authToken?: string;
68
+ leaveOnUnload?: boolean;
68
69
  onLeave?: () => void;
69
70
  onJoin?: () => void;
70
71
  /**
@@ -92,6 +93,7 @@ export const HMSPrebuilt = React.forwardRef<HMSPrebuiltRefType, HMSPrebuiltProps
92
93
  themes,
93
94
  options: { userName = '', userId = '', endpoints } = {},
94
95
  screens,
96
+ leaveOnUnload = true,
95
97
  onLeave,
96
98
  onJoin,
97
99
  },
@@ -188,6 +190,7 @@ export const HMSPrebuilt = React.forwardRef<HMSPrebuiltRefType, HMSPrebuiltProps
188
190
  store={reactiveStore.current?.hmsStore}
189
191
  notifications={reactiveStore.current?.hmsNotifications}
190
192
  stats={reactiveStore.current?.hmsStats}
193
+ leaveOnUnload={leaveOnUnload}
191
194
  >
192
195
  <RoomLayoutProvider roomLayoutEndpoint={roomLayoutEndpoint} overrideLayout={overrideLayout}>
193
196
  <RoomLayoutContext.Consumer>
@@ -22,6 +22,8 @@ import { useEmojiPickerStyles } from './useEmojiPickerStyles';
22
22
  import { useDefaultChatSelection, useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
23
23
  import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants';
24
24
 
25
+ const CHAT_MESSAGE_LIMIT = 2000;
26
+
25
27
  const TextArea = styled('textarea', {
26
28
  width: '100%',
27
29
  bg: 'transparent',
@@ -90,6 +92,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
90
92
  const selection = selectedPeer.name || selectedRole || defaultSelection;
91
93
  const isLocalPeerBlacklisted = useIsPeerBlacklisted({ local: true });
92
94
  const isMwebHLSStream = useMobileHLSStream();
95
+ const [messageLengthExceeded, setMessageLengthExceeded] = useState(false);
93
96
  const isLandscapeHLSStream = useLandscapeHLSStream();
94
97
 
95
98
  useEffect(() => {
@@ -105,7 +108,10 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
105
108
 
106
109
  const resetInputHeight = useCallback(() => {
107
110
  if (inputRef.current) {
108
- inputRef.current.style.height = `${Math.max(32, inputRef.current.value ? inputRef.current.scrollHeight : 0)}px`;
111
+ inputRef.current.style.height = `${Math.max(
112
+ 32,
113
+ inputRef.current.value ? Math.min(inputRef.current.scrollHeight, 24 * 4) : 0,
114
+ )}px`;
109
115
  }
110
116
  }, []);
111
117
 
@@ -146,6 +152,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
146
152
  if (messageElement) {
147
153
  messageElement.value = draftMessage;
148
154
  updateInputHeight();
155
+ setMessageLengthExceeded(draftMessage.length > CHAT_MESSAGE_LIMIT);
149
156
  }
150
157
  }, [draftMessage]);
151
158
 
@@ -230,6 +237,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
230
237
  >
231
238
  {children}
232
239
  <TextArea
240
+ maxLength={CHAT_MESSAGE_LIMIT + 10}
233
241
  css={{
234
242
  c: '$on_surface_high',
235
243
  '&:valid ~ .send-msg': { color: '$on_surface_high' },
@@ -243,7 +251,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
243
251
  autoFocus={!(isMobile || isLandscapeHLSStream)}
244
252
  onKeyPress={async event => {
245
253
  if (event.key === 'Enter') {
246
- if (!event.shiftKey) {
254
+ if (!event.shiftKey && !messageLengthExceeded) {
247
255
  event.preventDefault();
248
256
  await sendMessage();
249
257
  }
@@ -251,7 +259,10 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
251
259
  }}
252
260
  autoComplete="off"
253
261
  aria-autocomplete="none"
254
- onChange={updateInputHeight}
262
+ onChange={e => {
263
+ updateInputHeight();
264
+ setMessageLengthExceeded(e.target.value.length > CHAT_MESSAGE_LIMIT);
265
+ }}
255
266
  onBlur={resetInputHeight}
256
267
  onPaste={e => e.stopPropagation()}
257
268
  onCut={e => e.stopPropagation()}
@@ -269,6 +280,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
269
280
  <BaseIconButton
270
281
  className="send-msg"
271
282
  onClick={sendMessage}
283
+ disabled={messageLengthExceeded}
272
284
  css={{
273
285
  ml: 'auto',
274
286
  height: 'max-content',
@@ -295,6 +307,11 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
295
307
  )}
296
308
  </Flex>
297
309
  )}
310
+ {messageLengthExceeded && (
311
+ <Text variant="xs" css={{ color: '$alert_error_default', fontWeight: '$semiBold', mt: '$1', ml: '$7' }}>
312
+ Message cannot exceed 2000 characters
313
+ </Text>
314
+ )}
298
315
  </Box>
299
316
  );
300
317
  };
@@ -15,6 +15,7 @@ import {
15
15
  CrossIcon,
16
16
  HeadphonesIcon,
17
17
  SpeakerIcon,
18
+ TelePhoneIcon,
18
19
  } from '@100mslive/react-icons';
19
20
  import { HorizontalDivider } from '../../../Divider';
20
21
  import { Label } from '../../../Label';
@@ -82,6 +83,8 @@ export const AudioActions = () => {
82
83
  AudioIcon = <BluetoothIcon />;
83
84
  } else if (currentSelection && currentSelection.label.toLowerCase().includes('wired')) {
84
85
  AudioIcon = <HeadphonesIcon />;
86
+ } else if (currentSelection && currentSelection.label.toLowerCase().includes('earpiece')) {
87
+ AudioIcon = <TelePhoneIcon />;
85
88
  }
86
89
  return (
87
90
  <AudioSelectionSheet
@@ -24,7 +24,7 @@ import { ChatNotifications } from './ChatNotifications';
24
24
  import { HandRaisedNotifications } from './HandRaisedNotifications';
25
25
  import { InitErrorModal } from './InitErrorModal';
26
26
  import { PeerNotifications } from './PeerNotifications';
27
- import { PermissionErrorModal } from './PermissionErrorModal';
27
+ import { PermissionErrorNotificationModal } from './PermissionErrorModal';
28
28
  import { ReconnectNotifications } from './ReconnectNotifications';
29
29
  import { TrackBulkUnmuteModal } from './TrackBulkUnmuteModal';
30
30
  import { TrackNotifications } from './TrackNotifications';
@@ -197,7 +197,7 @@ export function Notifications() {
197
197
  {roomState === HMSRoomState.Connected ? <PeerNotifications /> : null}
198
198
  <ReconnectNotifications />
199
199
  <AutoplayBlockedModal />
200
- <PermissionErrorModal />
200
+ <PermissionErrorNotificationModal />
201
201
  <InitErrorModal />
202
202
  <ChatNotifications />
203
203
  <HandRaisedNotifications />
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { useMedia } from 'react-use';
3
- import { HMSNotificationTypes, useHMSNotifications } from '@100mslive/react-sdk';
3
+ import { HMSException, HMSNotificationTypes, useHMSNotifications } from '@100mslive/react-sdk';
4
4
  import { Button, config as cssConfig, Dialog, Flex, Text } from '../../..';
5
5
  // @ts-ignore: No implicit Any
6
6
  import androidPermissionAlert from '../../images/android-perm-1.png';
@@ -9,22 +9,24 @@ import iosPermissions from '../../images/ios-perm-0.png';
9
9
  // @ts-ignore: No implicit Any
10
10
  import { isAndroid, isIOS } from '../../common/constants';
11
11
 
12
- export function PermissionErrorModal() {
12
+ export function PermissionErrorNotificationModal() {
13
13
  const notification = useHMSNotifications(HMSNotificationTypes.ERROR);
14
+ return <PermissionErrorModal error={notification?.data} />;
15
+ }
16
+
17
+ export const PermissionErrorModal = ({ error }: { error?: HMSException }) => {
14
18
  const [deviceType, setDeviceType] = useState('');
15
19
  const [isSystemError, setIsSystemError] = useState(false);
16
20
  const isMobile = useMedia(cssConfig.media.md);
17
-
18
21
  useEffect(() => {
19
22
  if (
20
- !notification ||
21
- (notification.data?.code !== 3001 && notification.data?.code !== 3011) ||
22
- (notification.data?.code === 3001 && notification.data?.message.includes('screen'))
23
+ !error ||
24
+ (error?.code !== 3001 && error?.code !== 3011) ||
25
+ (error?.code === 3001 && error?.message.includes('screen'))
23
26
  ) {
24
27
  return;
25
28
  }
26
- console.error(`[${notification.type}]`, notification);
27
- const errorMessage = notification.data?.message;
29
+ const errorMessage = error?.message;
28
30
  const hasAudio = errorMessage.includes('audio');
29
31
  const hasVideo = errorMessage.includes('video');
30
32
  const hasScreen = errorMessage.includes('screen');
@@ -37,8 +39,8 @@ export function PermissionErrorModal() {
37
39
  } else if (hasScreen) {
38
40
  setDeviceType('screen');
39
41
  }
40
- setIsSystemError(notification.data.code === 3011);
41
- }, [notification]);
42
+ setIsSystemError(error.code === 3011);
43
+ }, [error]);
42
44
 
43
45
  return deviceType ? (
44
46
  <Dialog.Root open={!!deviceType}>
@@ -131,4 +133,4 @@ export function PermissionErrorModal() {
131
133
  </Dialog.Portal>
132
134
  </Dialog.Root>
133
135
  ) : null;
134
- }
136
+ };
@@ -13,6 +13,7 @@ import { Dropdown } from '../../Dropdown';
13
13
  import { Label } from '../../Label';
14
14
  import { Box, Flex } from '../../Layout';
15
15
  import { Dialog } from '../../Modal';
16
+ import { formatBytes } from '../../Stats';
16
17
  import { Switch } from '../../Switch';
17
18
  import { Text } from '../../Text';
18
19
  import { DialogDropdownTrigger } from '../primitives/DropdownTrigger';
@@ -245,16 +246,3 @@ const StatsRow = React.memo(({ label, value }) => (
245
246
  </Text>
246
247
  </Box>
247
248
  ));
248
-
249
- const formatBytes = (bytes, unit = 'B', decimals = 2) => {
250
- if (bytes === undefined) return '-';
251
- if (bytes === 0) return '0 ' + unit;
252
-
253
- const k = 1024;
254
- const dm = decimals < 0 ? 0 : decimals;
255
- const sizes = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'].map(size => size + unit);
256
-
257
- const i = Math.floor(Math.log(bytes) / Math.log(k));
258
-
259
- return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
260
- };
@@ -1 +1,2 @@
1
1
  export { VideoTileStats } from './Stats';
2
+ export { formatBytes } from './formatBytes';
package/src/index.ts CHANGED
@@ -38,3 +38,4 @@ export * from './Prebuilt';
38
38
  export * from './Progress';
39
39
  export * from './context/DialogContext';
40
40
  export * from './TextArea';
41
+ export * from './Diagnostics';