@100mslive/roomkit-react 0.1.7 → 0.1.8-alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. package/dist/AudioLevel/AudioLevel.d.ts +5 -8
  2. package/dist/AudioLevel/index.d.ts +2 -1
  3. package/dist/AudioLevel/useBorderAudioLevel.d.ts +8 -0
  4. package/dist/{HLSView-3S74KF3A.js → HLSView-IQRPLYNH.js} +5 -4
  5. package/dist/{HLSView-3S74KF3A.js.map → HLSView-IQRPLYNH.js.map} +2 -2
  6. package/dist/Prebuilt/components/Chip.d.ts +12 -0
  7. package/dist/Prebuilt/components/PrebuiltDialogPortal.d.ts +4 -0
  8. package/dist/{VirtualBackground-3TI5NA4V.js → VirtualBackground-GP4ATXD3.js} +3 -3
  9. package/dist/{chunk-36X4ZCLC.js → chunk-2H5NIZB7.js} +2 -2
  10. package/dist/{chunk-Z7P5WITU.js → chunk-GLYGPYNS.js} +560 -1190
  11. package/dist/chunk-GLYGPYNS.js.map +7 -0
  12. package/dist/{chunk-5DQ3WTED.js → chunk-Z3O2WGWV.js} +2 -2
  13. package/dist/{chunk-5DQ3WTED.js.map → chunk-Z3O2WGWV.js.map} +1 -1
  14. package/dist/{conference-JNABIZBG.js → conference-JD35TNH4.js} +1351 -662
  15. package/dist/conference-JD35TNH4.js.map +7 -0
  16. package/dist/index.cjs.js +3387 -3297
  17. package/dist/index.cjs.js.map +4 -4
  18. package/dist/index.js +4 -2
  19. package/dist/meta.cjs.json +1001 -826
  20. package/dist/meta.esbuild.json +1053 -877
  21. package/package.json +6 -6
  22. package/src/AudioLevel/AudioLevel.tsx +79 -30
  23. package/src/AudioLevel/audio-level.png +0 -0
  24. package/src/AudioLevel/index.ts +2 -1
  25. package/src/AudioLevel/useBorderAudioLevel.tsx +34 -0
  26. package/src/Prebuilt/App.tsx +1 -0
  27. package/src/Prebuilt/common/utils.js +0 -7
  28. package/src/Prebuilt/components/{Chip.jsx → Chip.tsx} +13 -2
  29. package/src/Prebuilt/components/Footer/ParticipantList.jsx +23 -12
  30. package/src/Prebuilt/components/Footer/RoleAccordion.tsx +43 -3
  31. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +7 -4
  32. package/src/Prebuilt/components/MoreSettings/ChangeNameModal.jsx +3 -2
  33. package/src/Prebuilt/components/MoreSettings/EmbedUrl.jsx +3 -2
  34. package/src/Prebuilt/components/MwebLandscapePrompt.jsx +58 -0
  35. package/src/Prebuilt/components/Notifications/HLSFailureModal.jsx +3 -2
  36. package/src/Prebuilt/components/Notifications/PermissionErrorModal.jsx +3 -2
  37. package/src/Prebuilt/components/PrebuiltDialogPortal.tsx +6 -0
  38. package/src/Prebuilt/components/Preview/PreviewJoin.tsx +4 -3
  39. package/src/Prebuilt/components/RoleChangeModal.jsx +3 -2
  40. package/src/Prebuilt/components/RoleChangeRequest/RequestPrompt.tsx +3 -2
  41. package/src/Prebuilt/components/Settings/SettingsModal.jsx +3 -2
  42. package/src/Prebuilt/components/Settings/StartRecording.jsx +3 -2
  43. package/src/Prebuilt/components/StatsForNerds.jsx +3 -2
  44. package/src/Prebuilt/components/VideoTile.jsx +22 -69
  45. package/src/Prebuilt/components/pdfAnnotator/pdfFileOptions.jsx +3 -2
  46. package/src/Prebuilt/components/pdfAnnotator/shareScreenOptions.jsx +4 -29
  47. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +3 -2
  48. package/src/Prebuilt/layouts/HLSView.jsx +1 -0
  49. package/src/Prebuilt/primitives/DialogContent.jsx +5 -4
  50. package/dist/chunk-Z7P5WITU.js.map +0 -7
  51. package/dist/conference-JNABIZBG.js.map +0 -7
  52. /package/dist/{VirtualBackground-3TI5NA4V.js.map → VirtualBackground-GP4ATXD3.js.map} +0 -0
  53. /package/dist/{chunk-36X4ZCLC.js.map → chunk-2H5NIZB7.js.map} +0 -0
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "prebuilt",
11
11
  "roomkit"
12
12
  ],
13
- "version": "0.1.7",
13
+ "version": "0.1.8-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.16",
80
- "@100mslive/hms-virtual-background": "1.11.16",
81
- "@100mslive/react-icons": "0.8.16",
82
- "@100mslive/react-sdk": "0.8.16",
79
+ "@100mslive/hls-player": "0.1.17-alpha.0",
80
+ "@100mslive/hms-virtual-background": "1.11.17-alpha.0",
81
+ "@100mslive/react-icons": "0.8.17-alpha.0",
82
+ "@100mslive/react-sdk": "0.8.17-alpha.0",
83
83
  "@100mslive/types-prebuilt": "0.12.0",
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": "c06edac3e71481de08e948ffe0affaf705564ad1"
118
+ "gitHead": "d6e072de081b508a297ebc1684a33a8e9db048ef"
119
119
  }
@@ -1,34 +1,83 @@
1
- import { useCallback, useRef } from 'react';
2
- import { HMSTrackID } from '@100mslive/hms-video-store';
3
- import { useAudioLevelStyles } from '@100mslive/react-sdk';
4
- import { useTheme } from '../Theme';
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { selectTrackAudioByID, useHMSVanillaStore } from '@100mslive/react-sdk';
3
+ import { Box, Flex } from '../Layout';
4
+ import { keyframes } from '../Theme';
5
+ //@ts-ignore
6
+ import bg from './audio-level.png';
5
7
 
6
- /**
7
- * pass in a track id and get a ref. That ref can be attached to an element which will have border
8
- * as per audio level post that.
9
- */
10
- export function useBorderAudioLevel(audioTrackId?: HMSTrackID) {
11
- const { theme } = useTheme();
12
- const color = theme.colors.primary_default.value;
13
- const getStyle = useCallback(
14
- (level: number) => {
15
- const style: Record<string, string> = {
16
- transition: 'outline 0.4s ease-in-out',
17
- };
18
- style['outline'] = level ? `${sigmoid(level) * 4}px solid ${color}` : '0px solid transparent';
19
- return style;
20
- },
21
- [color],
8
+ // keep the calculated values before hand to avoid recalcuation everytime
9
+ const positionValues = new Array(101).fill(0).reduce((acc, _, index) => {
10
+ acc[index] = Math.round((index / 100) * 4) / 4; // convert to 0.25 multiples
11
+ return acc;
12
+ }, {});
13
+
14
+ const barAnimation = keyframes({
15
+ from: {
16
+ maskSize: '4em .8em',
17
+ '-webkit-mask-position-y': '.1em',
18
+ maskPosition: 'initial .1em',
19
+ },
20
+
21
+ '50%': {
22
+ maskSize: '4em 1em',
23
+ '-webkit-mask-position-y': 0,
24
+ maskPosition: 'initial 0',
25
+ },
26
+
27
+ to: {
28
+ maskSize: '4em .8em',
29
+ '-webkit-mask-position-y': '.1em',
30
+ maskPosition: 'initial 0',
31
+ },
32
+ });
33
+
34
+ const AudioBar = () => {
35
+ return (
36
+ <Box
37
+ css={{
38
+ width: '.25em',
39
+ height: '1em',
40
+ maskImage: `url(${bg})`,
41
+ '-webkit-mask-repeat': 'no-repeat',
42
+ backgroundColor: '$on_primary_high',
43
+ maskSize: '4em 1em',
44
+ }}
45
+ />
22
46
  );
23
- const ref = useRef(null);
24
- useAudioLevelStyles({
25
- trackId: audioTrackId,
26
- getStyle,
27
- ref,
28
- });
29
- return ref;
30
- }
47
+ };
48
+
49
+ export const AudioLevel = ({ trackId, size }: { trackId?: string; size?: 'small' | 'medium' }) => {
50
+ const ref = useRef<HTMLDivElement | null>(null);
51
+ const vanillaStore = useHMSVanillaStore();
31
52
 
32
- export const sigmoid = (z: number) => {
33
- return 1 / (1 + Math.exp(-z));
53
+ useEffect(() => {
54
+ const unsubscribe = vanillaStore.subscribe(audioLevel => {
55
+ if (ref.current) {
56
+ let index = 0;
57
+ //@ts-ignore
58
+ for (const child of ref.current.children) {
59
+ const positionX = `-${positionValues[audioLevel] * (index === 1 ? 2.5 : 1.25)}em`;
60
+ child.style['-webkit-mask-position-x'] = positionX;
61
+ child.style['mask-position'] = `${positionX} 0`;
62
+ child.style['animation'] =
63
+ positionValues[audioLevel] > 0 ? `${barAnimation} 0.6s steps(3,jump-none) 0s infinite` : 'none';
64
+ index++;
65
+ }
66
+ }
67
+ }, selectTrackAudioByID(trackId));
68
+ return unsubscribe;
69
+ }, [vanillaStore, trackId]);
70
+ return (
71
+ <Flex
72
+ ref={ref}
73
+ css={{
74
+ fontSize: size === 'small' ? '0.75rem' : '1rem',
75
+ gap: size === 'small' ? '$1' : '$2',
76
+ }}
77
+ >
78
+ <AudioBar />
79
+ <AudioBar />
80
+ <AudioBar />
81
+ </Flex>
82
+ );
34
83
  };
Binary file
@@ -1 +1,2 @@
1
- export { useBorderAudioLevel } from './AudioLevel';
1
+ export { useBorderAudioLevel } from './useBorderAudioLevel';
2
+ export { AudioLevel } from './AudioLevel';
@@ -0,0 +1,34 @@
1
+ import { useCallback, useRef } from 'react';
2
+ import { HMSTrackID } from '@100mslive/hms-video-store';
3
+ import { useAudioLevelStyles } from '@100mslive/react-sdk';
4
+ import { useTheme } from '../Theme';
5
+
6
+ /**
7
+ * pass in a track id and get a ref. That ref can be attached to an element which will have border
8
+ * as per audio level post that.
9
+ */
10
+ export function useBorderAudioLevel(audioTrackId?: HMSTrackID) {
11
+ const { theme } = useTheme();
12
+ const color = theme.colors.primary_default.value;
13
+ const getStyle = useCallback(
14
+ (level: number) => {
15
+ const style: Record<string, string> = {
16
+ transition: 'outline 0.4s ease-in-out',
17
+ };
18
+ style['outline'] = level ? `${sigmoid(level) * 4}px solid ${color}` : '0px solid transparent';
19
+ return style;
20
+ },
21
+ [color],
22
+ );
23
+ const ref = useRef(null);
24
+ useAudioLevelStyles({
25
+ trackId: audioTrackId,
26
+ getStyle,
27
+ ref,
28
+ });
29
+ return ref;
30
+ }
31
+
32
+ export const sigmoid = (z: number) => {
33
+ return 1 / (1 + Math.exp(-z));
34
+ };
@@ -218,6 +218,7 @@ export const HMSPrebuilt = React.forwardRef<HMSPrebuiltRefType, HMSPrebuiltProps
218
218
  <AppData appDetails={metadata} tokenEndpoint={tokenByRoomIdRoleEndpoint} />
219
219
  <Init />
220
220
  <Box
221
+ id="prebuilt-container"
221
222
  css={{
222
223
  bg: '$background_dim',
223
224
  size: '100%',
@@ -88,10 +88,3 @@ export const formatTime = timeInSeconds => {
88
88
  const hour = hours !== 0 ? `${hours < 10 ? '0' : ''}${hours}:` : '';
89
89
  return `${hour}${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
90
90
  };
91
-
92
- export const getAttributeBoxSize = (width, height) => {
93
- if (!width || !height) {
94
- return '';
95
- }
96
- return width < 180 || height < 180 ? 'small' : 'medium';
97
- };
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Flex } from '../../Layout';
3
3
  import { Text } from '../../Text';
4
+ import { CSS } from '../../Theme';
4
5
 
5
6
  const Chip = ({
6
7
  icon = <></>,
@@ -8,12 +9,22 @@ const Chip = ({
8
9
  backgroundColor = '$surface_default',
9
10
  textColor = '$on_surface_high',
10
11
  hideIfNoContent = false,
12
+ onClick,
13
+ css = {},
14
+ }: {
15
+ icon?: React.JSX.Element;
16
+ content: string;
17
+ backgroundColor?: string;
18
+ textColor?: string;
19
+ hideIfNoContent?: boolean;
20
+ onClick?: () => void | Promise<void>;
21
+ css?: CSS;
11
22
  }) => {
12
23
  if (hideIfNoContent && !content) {
13
- return;
24
+ return null;
14
25
  }
15
26
  return (
16
- <Flex align="center" css={{ backgroundColor, p: '$4 $6', borderRadius: '$4' }}>
27
+ <Flex align="center" css={{ backgroundColor, p: '$4 $6', borderRadius: '$4', ...css }} onClick={() => onClick?.()}>
17
28
  {icon}
18
29
  <Text variant="sm" css={{ fontWeight: '$semiBold', color: textColor, ml: '$2' }}>
19
30
  {content}
@@ -127,13 +127,15 @@ const VirtualizedParticipants = ({ peersOrderedByRoles = {}, isConnected, filter
127
127
  flex: '1 1 0',
128
128
  }}
129
129
  >
130
- <RoleAccordion
131
- peerList={handRaisedList}
132
- roleName="Hand Raised"
133
- filter={filter}
134
- isConnected={isConnected}
135
- isHandRaisedAccordion
136
- />
130
+ {handRaisedList.length > 0 ? (
131
+ <RoleAccordion
132
+ peerList={handRaisedList}
133
+ roleName="Hand Raised"
134
+ filter={filter}
135
+ isConnected={isConnected}
136
+ isHandRaisedAccordion
137
+ />
138
+ ) : null}
137
139
  {Object.keys(peersOrderedByRoles).map(role => (
138
140
  <RoleAccordion
139
141
  key={role}
@@ -179,7 +181,10 @@ export const Participant = ({ peer, isConnected }) => {
179
181
  const ParticipantActions = React.memo(({ peerId, role, isLocal }) => {
180
182
  const isHandRaised = useHMSStore(selectHasPeerHandRaised(peerId));
181
183
  const canChangeRole = useHMSStore(selectPermissions)?.changeRole;
182
- const shouldShowMoreActions = canChangeRole;
184
+ const canRemoveOthers = useHMSStore(selectPermissions)?.removeOthers;
185
+ const { elements } = useRoomLayoutConferencingScreen();
186
+ const { on_stage_exp } = elements || {};
187
+ const shouldShowMoreActions = (on_stage_exp && canChangeRole) || canRemoveOthers;
183
188
  const isAudioMuted = !useHMSStore(selectIsPeerAudioEnabled(peerId));
184
189
 
185
190
  return (
@@ -210,15 +215,21 @@ const ParticipantActions = React.memo(({ peerId, role, isLocal }) => {
210
215
  </Flex>
211
216
  ) : null}
212
217
 
213
- {shouldShowMoreActions && !isLocal ? <ParticipantMoreActions peerId={peerId} role={role} /> : null}
218
+ {shouldShowMoreActions && !isLocal ? (
219
+ <ParticipantMoreActions
220
+ peerId={peerId}
221
+ role={role}
222
+ elements={elements}
223
+ canChangeRole={canChangeRole}
224
+ canRemoveOthers={canRemoveOthers}
225
+ />
226
+ ) : null}
214
227
  </Flex>
215
228
  );
216
229
  });
217
230
 
218
- const ParticipantMoreActions = ({ peerId, role }) => {
231
+ const ParticipantMoreActions = ({ peerId, role, elements, canChangeRole, canRemoveOthers }) => {
219
232
  const hmsActions = useHMSActions();
220
- const { changeRole: canChangeRole, removeOthers: canRemoveOthers } = useHMSStore(selectPermissions);
221
- const { elements } = useRoomLayoutConferencingScreen();
222
233
  const {
223
234
  bring_to_stage_label,
224
235
  remove_from_stage_label,
@@ -1,10 +1,12 @@
1
- import React from 'react';
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { useMeasure } from 'react-use';
3
3
  import { FixedSizeList } from 'react-window';
4
- import { HMSPeer } from '@100mslive/react-sdk';
4
+ import { HMSPeer, HMSPeerListIterator, useHMSActions } from '@100mslive/react-sdk';
5
+ import { AddCircleIcon } from '@100mslive/react-icons';
5
6
  import { Accordion } from '../../../Accordion';
6
7
  import { Box, Flex } from '../../../Layout';
7
8
  import { Text } from '../../../Text';
9
+ import Chip from '../Chip';
8
10
  // @ts-ignore: No implicit Any
9
11
  import { Participant } from './ParticipantList';
10
12
  import { RoleOptions } from './RoleOptions';
@@ -38,11 +40,34 @@ export const RoleAccordion = ({
38
40
  filter?: { search: string };
39
41
  }) => {
40
42
  const [ref, { width }] = useMeasure<HTMLDivElement>();
43
+ const actions = useHMSActions();
41
44
  const showAcordion = filter?.search ? peerList.some(peer => peer.name.toLowerCase().includes(filter.search)) : true;
45
+ const [hasNext, setHasNext] = useState(false);
46
+ const iteratorRef = useRef<HMSPeerListIterator | null>(null);
42
47
 
43
- if (!showAcordion || (isHandRaisedAccordion && filter?.search) || peerList.length === 0) {
48
+ const loadNext = useCallback(() => {
49
+ if (!roleName || roleName === 'Hand Raised') {
50
+ return;
51
+ }
52
+ if (!iteratorRef.current) {
53
+ iteratorRef.current = actions.getPeerListIterator({ role: roleName });
54
+ }
55
+ iteratorRef.current
56
+ .next()
57
+ .catch(console.error)
58
+ .finally(() => {
59
+ setHasNext(iteratorRef.current ? iteratorRef.current.hasNext() : false);
60
+ });
61
+ }, [actions, roleName]);
62
+
63
+ useEffect(() => {
64
+ loadNext();
65
+ }, [loadNext]);
66
+
67
+ if (!showAcordion || (isHandRaisedAccordion && filter?.search) || (peerList.length === 0 && filter?.search)) {
44
68
  return null;
45
69
  }
70
+
46
71
  const height = ROW_HEIGHT * peerList.length;
47
72
 
48
73
  return (
@@ -86,6 +111,21 @@ export const RoleAccordion = ({
86
111
  >
87
112
  {VirtualizedParticipantItem}
88
113
  </FixedSizeList>
114
+ {hasNext ? (
115
+ <Chip
116
+ icon={<AddCircleIcon />}
117
+ content="Load More"
118
+ onClick={loadNext}
119
+ backgroundColor="$secondary_default"
120
+ css={{
121
+ w: 'max-content',
122
+ borderRadius: '$size$9',
123
+ m: '$2 auto',
124
+ p: '$4',
125
+ cursor: 'pointer',
126
+ }}
127
+ />
128
+ ) : null}
89
129
  </Accordion.Content>
90
130
  </Accordion.Item>
91
131
  </Accordion.Root>
@@ -1,11 +1,14 @@
1
1
  import React, { Fragment, useState } from 'react';
2
2
  import { ConferencingScreen } from '@100mslive/types-prebuilt';
3
+ // @ts-ignore: No implicit Any
3
4
  import { selectIsConnectedToRoom, selectPermissions, useHMSStore, useRecordingStreaming } from '@100mslive/react-sdk';
5
+ // @ts-ignore: No implicit Any
4
6
  import { ExitIcon, StopIcon, VerticalMenuIcon } from '@100mslive/react-icons';
5
7
  import { Dropdown } from '../../../Dropdown';
6
8
  import { Box, Flex } from '../../../Layout';
7
9
  import { Dialog } from '../../../Modal';
8
10
  import { Tooltip } from '../../../Tooltip';
11
+ import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
9
12
  import { EndSessionContent } from './EndSessionContent';
10
13
  import { LeaveIconButton, MenuTriggerButton } from './LeaveAtoms';
11
14
  import { LeaveCard } from './LeaveCard';
@@ -135,7 +138,7 @@ export const DesktopLeaveRoom = ({
135
138
  )}
136
139
 
137
140
  <Dialog.Root open={showEndStreamAlert} modal={false}>
138
- <Dialog.Portal>
141
+ <PrebuiltDialogPortal>
139
142
  <Dialog.Overlay />
140
143
  <Dialog.Content css={{ w: 'min(420px, 90%)', p: '$8', bg: '$surface_dim' }}>
141
144
  <EndSessionContent
@@ -145,16 +148,16 @@ export const DesktopLeaveRoom = ({
145
148
  isModal
146
149
  />
147
150
  </Dialog.Content>
148
- </Dialog.Portal>
151
+ </PrebuiltDialogPortal>
149
152
  </Dialog.Root>
150
153
 
151
154
  <Dialog.Root open={showLeaveRoomAlert} modal={false}>
152
- <Dialog.Portal>
155
+ <PrebuiltDialogPortal>
153
156
  <Dialog.Overlay />
154
157
  <Dialog.Content css={{ w: 'min(420px, 90%)', p: '$8', bg: '$surface_dim' }}>
155
158
  <LeaveSessionContent setShowLeaveRoomAlert={setShowLeaveRoomAlert} leaveRoom={leaveRoom} isModal />
156
159
  </Dialog.Content>
157
- </Dialog.Portal>
160
+ </PrebuiltDialogPortal>
158
161
  </Dialog.Root>
159
162
  </Fragment>
160
163
  );
@@ -3,6 +3,7 @@ import { useMedia } from 'react-use';
3
3
  import { selectLocalPeerName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
4
4
  import { config as cssConfig, Dialog } from '../../../';
5
5
  import { Sheet } from '../../../Sheet';
6
+ import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
6
7
  import { ToastManager } from '../Toast/ToastManager';
7
8
  import { ChangeNameContent } from './ChangeNameContent';
8
9
  import { UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences';
@@ -58,12 +59,12 @@ export const ChangeNameModal = ({ onOpenChange, openParentSheet = null }) => {
58
59
 
59
60
  return (
60
61
  <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
61
- <Dialog.Portal>
62
+ <PrebuiltDialogPortal>
62
63
  <Dialog.Overlay />
63
64
  <Dialog.Content css={{ bg: '$surface_dim', width: 'min(400px,80%)', p: '$10' }}>
64
65
  <ChangeNameContent {...props} />
65
66
  </Dialog.Content>
66
- </Dialog.Portal>
67
+ </PrebuiltDialogPortal>
67
68
  </Dialog.Root>
68
69
  );
69
70
  };
@@ -1,6 +1,7 @@
1
1
  import React, { useState } from 'react';
2
2
  import { LinkIcon } from '@100mslive/react-icons';
3
3
  import { Button, Dialog, Dropdown, Flex, Input, Text } from '../../../';
4
+ import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
4
5
  import { useSetAppDataByKey } from '../AppData/useUISettings';
5
6
  import { APP_DATA } from '../../common/constants';
6
7
 
@@ -30,7 +31,7 @@ export function EmbedUrlModal({ onOpenChange }) {
30
31
 
31
32
  return (
32
33
  <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
33
- <Dialog.Portal>
34
+ <PrebuiltDialogPortal>
34
35
  <Dialog.Overlay />
35
36
  <Dialog.Content css={{ w: 'min(420px, 90%)', p: '$8', bg: '$surface_dim' }}>
36
37
  <Dialog.Title
@@ -75,7 +76,7 @@ export function EmbedUrlModal({ onOpenChange }) {
75
76
  </Button>
76
77
  </Flex>
77
78
  </Dialog.Content>
78
- </Dialog.Portal>
79
+ </PrebuiltDialogPortal>
79
80
  </Dialog.Root>
80
81
  );
81
82
  }
@@ -0,0 +1,58 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { RefreshIcon } from '@100mslive/react-icons';
3
+ import { Button } from '../../Button';
4
+ import { Box, Flex } from '../../Layout';
5
+ import { Dialog } from '../../Modal';
6
+ import { Text } from '../../Text';
7
+ import { PrebuiltDialogPortal } from './PrebuiltDialogPortal';
8
+ import { isAndroid, isIOS } from '../common/constants';
9
+
10
+ export const MwebLandscapePrompt = () => {
11
+ const isMobile = isAndroid || isIOS;
12
+ const [showMwebLandscapePrompt, setShowMwebLandscapePrompt] = useState(false);
13
+
14
+ useEffect(() => {
15
+ const handleResize = () => {
16
+ setShowMwebLandscapePrompt(isMobile && window.innerHeight < window.innerWidth);
17
+ };
18
+
19
+ handleResize();
20
+ window.addEventListener('resize', handleResize);
21
+
22
+ return () => {
23
+ window.removeEventListener('resize', handleResize);
24
+ };
25
+ }, []);
26
+
27
+ return (
28
+ <Dialog.Root open={showMwebLandscapePrompt} onOpenChange={setShowMwebLandscapePrompt}>
29
+ <PrebuiltDialogPortal>
30
+ <Dialog.Overlay />
31
+ <Dialog.Content css={{ w: 'min(420px, 90%)', p: '$8', bg: '$surface_dim' }}>
32
+ <Box>
33
+ <Flex
34
+ css={{
35
+ color: '$primary_default',
36
+ display: 'flex',
37
+ alignItems: 'center',
38
+ }}
39
+ >
40
+ <RefreshIcon style={{ marginRight: '0.5rem' }} />
41
+ <Text variant="lg" css={{ color: '$on_surface_high', fontWeight: '$semiBold' }}>
42
+ Please rotate your device
43
+ </Text>
44
+ </Flex>
45
+ <Text variant="sm" css={{ color: '$on_surface_medium', mb: '$8', mt: '$4' }}>
46
+ We do not support landscape mode as of now, please use the app in portrait mode for the best experience.
47
+ </Text>
48
+ <Flex align="center" justify="between" css={{ w: '100%', gap: '$8' }}>
49
+ <Button outlined variant="standard" css={{ w: '100%' }} onClick={() => setShowMwebLandscapePrompt(false)}>
50
+ Continue anyway
51
+ </Button>
52
+ </Flex>
53
+ </Box>
54
+ </Dialog.Content>
55
+ </PrebuiltDialogPortal>
56
+ </Dialog.Root>
57
+ );
58
+ };
@@ -4,6 +4,7 @@ import { Button } from '../../../Button';
4
4
  import { Flex } from '../../../Layout';
5
5
  import { Dialog } from '../../../Modal';
6
6
  import { Text } from '../../../Text';
7
+ import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
7
8
  import { useSetAppDataByKey } from '../AppData/useUISettings';
8
9
  import { APP_DATA } from '../../common/constants';
9
10
 
@@ -37,7 +38,7 @@ export function HLSFailureModal() {
37
38
  }
38
39
  }}
39
40
  >
40
- <Dialog.Portal>
41
+ <PrebuiltDialogPortal>
41
42
  <Dialog.Overlay />
42
43
  <Dialog.Content css={{ w: 'min(360px, 90%)' }}>
43
44
  <Dialog.Title
@@ -65,7 +66,7 @@ export function HLSFailureModal() {
65
66
  </Button>
66
67
  </Flex>
67
68
  </Dialog.Content>
68
- </Dialog.Portal>
69
+ </PrebuiltDialogPortal>
69
70
  </Dialog.Root>
70
71
  ) : null;
71
72
  }
@@ -4,6 +4,7 @@ import { HMSNotificationTypes, useHMSNotifications } from '@100mslive/react-sdk'
4
4
  import { Button, config as cssConfig, Dialog, Flex, Text } from '../../../';
5
5
  import androidPermissionAlert from '../../images/android-perm-1.png';
6
6
  import iosPermissions from '../../images/ios-perm-0.png';
7
+ import { PrebuiltDialogPortal } from '../PrebuiltDialogPortal';
7
8
  import { isAndroid, isIOS } from '../../common/constants';
8
9
 
9
10
  export function PermissionErrorModal() {
@@ -39,7 +40,7 @@ export function PermissionErrorModal() {
39
40
 
40
41
  return deviceType ? (
41
42
  <Dialog.Root open={!!deviceType}>
42
- <Dialog.Portal>
43
+ <PrebuiltDialogPortal>
43
44
  <Dialog.Overlay />
44
45
  <Dialog.Content css={{ w: 'min(380px, 90%)', p: '$8' }}>
45
46
  <Dialog.Title
@@ -118,7 +119,7 @@ export function PermissionErrorModal() {
118
119
  </Flex>
119
120
  ) : null}
120
121
  </Dialog.Content>
121
- </Dialog.Portal>
122
+ </PrebuiltDialogPortal>
122
123
  </Dialog.Root>
123
124
  ) : null;
124
125
  }
@@ -0,0 +1,6 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { Dialog } from '../../Modal';
3
+
4
+ export const PrebuiltDialogPortal = ({ children }: { children: ReactNode }) => (
5
+ <Dialog.Portal container={document.getElementById('prebuilt-container')}>{children}</Dialog.Portal>
6
+ );
@@ -14,6 +14,7 @@ import {
14
14
  } from '@100mslive/react-sdk';
15
15
  import { MicOffIcon, SettingsIcon } from '@100mslive/react-icons';
16
16
  import { Avatar, Box, config as cssConfig, Flex, flexCenter, styled, StyledVideoTile, Text, Video } from '../../..';
17
+ import { AudioLevel } from '../../../AudioLevel';
17
18
  import { useHMSPrebuiltContext } from '../../AppContext';
18
19
  // @ts-ignore: No implicit Any
19
20
  import IconButton from '../../IconButton';
@@ -31,8 +32,6 @@ import { Logo } from '../Header/HeaderComponents';
31
32
  // @ts-ignore: No implicit Any
32
33
  import SettingsModal from '../Settings/SettingsModal';
33
34
  // @ts-ignore: No implicit Any
34
- import { AudioLevel } from '../VideoTile';
35
- // @ts-ignore: No implicit Any
36
35
  import PreviewForm from './PreviewForm';
37
36
  // @ts-ignore: No implicit Any
38
37
  import { useAuthToken, useUISettings } from '../AppData/useUISettings';
@@ -246,7 +245,9 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
246
245
  <MicOffIcon />
247
246
  </StyledVideoTile.AudioIndicator>
248
247
  ) : (
249
- <AudioLevel trackId={localPeer?.audioTrack} />
248
+ <StyledVideoTile.AudioIndicator size="medium">
249
+ <AudioLevel trackId={localPeer?.audioTrack} />
250
+ </StyledVideoTile.AudioIndicator>
250
251
  )}
251
252
  </StyledVideoTile.Container>
252
253
  );
@@ -9,6 +9,7 @@ import { Box, Flex } from '../../Layout';
9
9
  import { Dialog } from '../../Modal';
10
10
  import { Text } from '../../Text';
11
11
  import { Tooltip } from '../../Tooltip';
12
+ import { PrebuiltDialogPortal } from './PrebuiltDialogPortal';
12
13
  import { useDropdownSelection } from './hooks/useDropdownSelection';
13
14
  import { useFilteredRoles } from '../common/hooks';
14
15
  import { textEllipsis } from '../../utils';
@@ -47,7 +48,7 @@ export const RoleChangeModal = ({ peerId, onOpenChange }) => {
47
48
  const peerNameMaxWidth = 200;
48
49
  return (
49
50
  <Dialog.Root defaultOpen onOpenChange={onOpenChange}>
50
- <Dialog.Portal>
51
+ <PrebuiltDialogPortal>
51
52
  <Dialog.Overlay />
52
53
  <Dialog.Content css={{ width: 'min(400px,80%)', p: '$10' }}>
53
54
  <Dialog.Title css={{ p: 0 }} asChild>
@@ -179,7 +180,7 @@ export const RoleChangeModal = ({ peerId, onOpenChange }) => {
179
180
  </Box>
180
181
  </Flex>
181
182
  </Dialog.Content>
182
- </Dialog.Portal>
183
+ </PrebuiltDialogPortal>
183
184
  </Dialog.Root>
184
185
  );
185
186
  };