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

Sign up to get free protection for your applications and to get access to all the features.
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';