@100mslive/roomkit-react 0.2.8-alpha.7 → 0.2.8-alpha.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. package/dist/{HLSView-MYKM5AXS.js → HLSView-6KPQ2KD6.js} +176 -174
  2. package/dist/HLSView-6KPQ2KD6.js.map +7 -0
  3. package/dist/Prebuilt/components/HMSVideo/HLSQualitySelector.d.ts +3 -2
  4. package/dist/Prebuilt/components/HMSVideo/utils.d.ts +0 -1
  5. package/dist/Prebuilt/components/Leave/DesktopLeaveRoom.d.ts +2 -1
  6. package/dist/Prebuilt/components/Leave/LeaveRoom.d.ts +2 -1
  7. package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +2 -1
  8. package/dist/Prebuilt/components/RaiseHand.d.ts +4 -1
  9. package/dist/Sheet/Sheet.d.ts +1 -0
  10. package/dist/{chunk-DRBTAFKN.js → chunk-JQCSGJIR.js} +720 -630
  11. package/dist/chunk-JQCSGJIR.js.map +7 -0
  12. package/dist/index.cjs.js +1231 -1135
  13. package/dist/index.cjs.js.map +4 -4
  14. package/dist/index.js +1 -1
  15. package/dist/meta.cjs.json +254 -199
  16. package/dist/meta.esbuild.json +261 -204
  17. package/package.json +6 -6
  18. package/src/Button/Button.tsx +4 -4
  19. package/src/Fieldset/Fieldset.tsx +1 -1
  20. package/src/Input/PasswordInput.stories.tsx +1 -1
  21. package/src/Pagination/StyledPagination.stories.tsx +2 -2
  22. package/src/Prebuilt/IconButton.tsx +1 -1
  23. package/src/Prebuilt/components/Chat/Chat.tsx +41 -1
  24. package/src/Prebuilt/components/Chat/ChatFooter.tsx +19 -15
  25. package/src/Prebuilt/components/EmojiReaction.jsx +32 -22
  26. package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.tsx +85 -78
  27. package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +3 -4
  28. package/src/Prebuilt/components/HMSVideo/MwebHLSViewTitle.tsx +49 -56
  29. package/src/Prebuilt/components/HMSVideo/VideoTime.tsx +2 -1
  30. package/src/Prebuilt/components/HMSVideo/utils.ts +0 -8
  31. package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx +1 -1
  32. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +50 -46
  33. package/src/Prebuilt/components/Leave/LeaveRoom.tsx +10 -5
  34. package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +12 -6
  35. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +5 -2
  36. package/src/Prebuilt/components/Notifications/HandRaisedNotifications.tsx +4 -1
  37. package/src/Prebuilt/components/Polls/Voting/Voting.tsx +3 -2
  38. package/src/Prebuilt/components/Polls/common/OptionInputWithDelete.tsx +1 -1
  39. package/src/Prebuilt/components/Polls/common/utils.ts +2 -2
  40. package/src/Prebuilt/components/RaiseHand.tsx +8 -2
  41. package/src/Prebuilt/components/RoomDetails/RoomDetailsPane.tsx +41 -14
  42. package/src/Prebuilt/components/pdfAnnotator/shareScreenOptions.jsx +2 -2
  43. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +1 -1
  44. package/src/Prebuilt/layouts/HLSView.jsx +27 -24
  45. package/src/Prebuilt/layouts/SidePane.tsx +1 -2
  46. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +3 -2
  47. package/src/Prebuilt/primitives/DialogContent.jsx +1 -1
  48. package/src/Sheet/Sheet.tsx +3 -3
  49. package/dist/HLSView-MYKM5AXS.js.map +0 -7
  50. package/dist/chunk-DRBTAFKN.js.map +0 -7
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "prebuilt",
11
11
  "roomkit"
12
12
  ],
13
- "version": "0.2.8-alpha.7",
13
+ "version": "0.2.8-alpha.8",
14
14
  "author": "100ms",
15
15
  "license": "MIT",
16
16
  "repository": {
@@ -82,11 +82,11 @@
82
82
  "react": ">=17.0.2 <19.0.0"
83
83
  },
84
84
  "dependencies": {
85
- "@100mslive/hls-player": "0.2.8-alpha.7",
85
+ "@100mslive/hls-player": "0.2.8-alpha.8",
86
86
  "@100mslive/hms-noise-cancellation": "0.0.0-alpha.1",
87
- "@100mslive/hms-virtual-background": "1.12.8-alpha.7",
88
- "@100mslive/react-icons": "0.9.8-alpha.7",
89
- "@100mslive/react-sdk": "0.9.8-alpha.7",
87
+ "@100mslive/hms-virtual-background": "1.12.8-alpha.8",
88
+ "@100mslive/react-icons": "0.9.8-alpha.8",
89
+ "@100mslive/react-sdk": "0.9.8-alpha.8",
90
90
  "@100mslive/types-prebuilt": "0.12.7",
91
91
  "@emoji-mart/data": "^1.0.6",
92
92
  "@emoji-mart/react": "^1.0.1",
@@ -122,5 +122,5 @@
122
122
  "uuid": "^8.3.2",
123
123
  "worker-timers": "^7.0.40"
124
124
  },
125
- "gitHead": "48bc1b57113a4245b79055a80f4f1f5d3b8795aa"
125
+ "gitHead": "cddbc3f6a55bc8612229e7cfa865eb8946b564b2"
126
126
  }
@@ -20,22 +20,22 @@ const getOutlinedVariants = (
20
20
  textDisabled: string,
21
21
  ) => {
22
22
  return {
23
- bg: '$transparent',
23
+ bg: 'transparent',
24
24
  border: `solid $space$px $colors${base}`,
25
25
  c: text,
26
26
  '&[disabled]': {
27
27
  c: textDisabled,
28
- bg: '$transparent',
28
+ bg: 'transparent',
29
29
  border: `solid $space$px $colors${disabled}`,
30
30
  cursor: 'not-allowed',
31
31
  },
32
32
  '&:not([disabled]):hover': {
33
33
  border: `solid $space$px $colors${hover}`,
34
- bg: '$transparent',
34
+ bg: 'transparent',
35
35
  },
36
36
  '&:not([disabled]):active': {
37
37
  border: `solid $space$px $colors${active}`,
38
- bg: '$transparent',
38
+ bg: 'transparent',
39
39
  },
40
40
  '&:not([disabled]):focus-visible': {
41
41
  boxShadow: `0 0 0 3px $colors${base}`,
@@ -5,7 +5,7 @@ const StyledFieldset = styled('fieldset', {
5
5
  alignItems: 'center',
6
6
  justifyContent: 'space-between',
7
7
  border: 'none',
8
- backgroundColor: '$transparent',
8
+ backgroundColor: 'transparent',
9
9
  });
10
10
 
11
11
  export const Fieldset = StyledFieldset;
@@ -25,7 +25,7 @@ const Template: ComponentStory<typeof PasswordInput.Root> = args => {
25
25
  showPassword={showPassword}
26
26
  onChange={e => setText(e.target.value)}
27
27
  />
28
- <PasswordInput.Icons ref={ref} css={{ bg: '$transparent' }}>
28
+ <PasswordInput.Icons ref={ref} css={{ bg: 'transparent' }}>
29
29
  <PasswordInput.ShowIcon
30
30
  showPassword={showPassword}
31
31
  onClick={() => {
@@ -41,7 +41,7 @@ const PaginationComponent = ({ page: propsPage, setPage: propsSetPage, numPages
41
41
  disabled={disableLeft}
42
42
  onClick={prevPage}
43
43
  type="button"
44
- css={{ padding: 0, border: 'none', backgroundColor: '$transparent' }}
44
+ css={{ padding: 0, border: 'none', backgroundColor: 'transparent' }}
45
45
  >
46
46
  <ChevronLeftIcon width={16} height={16} style={{ cursor: disableLeft ? 'not-allowed' : 'pointer' }} />
47
47
  </StyledPagination.Chevron>
@@ -54,7 +54,7 @@ const PaginationComponent = ({ page: propsPage, setPage: propsSetPage, numPages
54
54
  disabled={disableRight}
55
55
  onClick={nextPage}
56
56
  type="button"
57
- css={{ padding: 0, border: 'none', backgroundColor: '$transparent' }}
57
+ css={{ padding: 0, border: 'none', backgroundColor: 'transparent' }}
58
58
  >
59
59
  <ChevronRightIcon width={16} height={16} style={{ cursor: disableRight ? 'not-allowed' : 'pointer' }} />
60
60
  </StyledPagination.Chevron>
@@ -11,7 +11,7 @@ const IconButton = styled(BaseIconButton, {
11
11
  active: {
12
12
  true: {
13
13
  color: '$on_surface_high',
14
- backgroundColor: '$transparent',
14
+ backgroundColor: 'transparent',
15
15
  },
16
16
  false: {
17
17
  border: '1px solid transparent',
@@ -2,16 +2,20 @@ import React, { MutableRefObject, useCallback, useRef } from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import { VariableSizeList } from 'react-window';
4
4
  import { selectSessionStore, selectUnreadHMSMessagesCount } from '@100mslive/hms-video-store';
5
+ import { match } from 'ts-pattern';
5
6
  import { selectHMSMessagesCount, useHMSActions, useHMSStore, useHMSVanillaStore } from '@100mslive/react-sdk';
6
7
  import { ChevronDownIcon } from '@100mslive/react-icons';
7
8
  import { Button } from '../../../Button';
8
- import { Flex } from '../../../Layout';
9
+ import { Box, Flex } from '../../../Layout';
9
10
  import { config as cssConfig } from '../../../Theme';
11
+ // @ts-ignore: No implicit any
12
+ import { EmojiReaction } from '../EmojiReaction';
10
13
  import { ChatBody } from './ChatBody';
11
14
  import { ChatFooter } from './ChatFooter';
12
15
  import { ChatBlocked, ChatPaused } from './ChatStates';
13
16
  import { PinnedMessage } from './PinnedMessage';
14
17
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
18
+ import { useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
15
19
  import { SESSION_STORE_KEY } from '../../common/constants';
16
20
 
17
21
  export const Chat = () => {
@@ -21,6 +25,9 @@ export const Chat = () => {
21
25
  const vanillaStore = useHMSVanillaStore();
22
26
  const { enabled: isChatEnabled = true } = useHMSStore(selectSessionStore(SESSION_STORE_KEY.CHAT_STATE)) || {};
23
27
  const isMobile = useMedia(cssConfig.media.md);
28
+ const isMobileHLSStream = useMobileHLSStream();
29
+ const isLandscapeStream = useLandscapeHLSStream();
30
+
24
31
  const scrollToBottom = useCallback(
25
32
  (unreadCount = 0) => {
26
33
  if (listRef.current && listRef.current.scrollToItem && unreadCount > 0) {
@@ -46,6 +53,7 @@ export const Chat = () => {
46
53
  >
47
54
  {isMobile && elements?.chat?.is_overlay ? null : <PinnedMessage />}
48
55
  <ChatBody ref={listRef} scrollToBottom={scrollToBottom} />
56
+
49
57
  <ChatPaused />
50
58
  <ChatBlocked />
51
59
  {isMobile && elements?.chat?.is_overlay ? <PinnedMessage /> : null}
@@ -54,6 +62,38 @@ export const Chat = () => {
54
62
  <NewMessageIndicator scrollToBottom={scrollToBottom} listRef={listRef} />
55
63
  </ChatFooter>
56
64
  ) : null}
65
+ {(isMobileHLSStream || isLandscapeStream) && (
66
+ <Box
67
+ css={{
68
+ position: 'absolute',
69
+ ...match({ isLandscapeStream, isChatEnabled })
70
+ .with(
71
+ {
72
+ isLandscapeStream: true,
73
+ isChatEnabled: true,
74
+ },
75
+ () => ({ bottom: '$19', right: '$10' }),
76
+ )
77
+ .with(
78
+ {
79
+ isLandscapeStream: true,
80
+ isChatEnabled: false,
81
+ },
82
+ () => ({ bottom: '$20', right: '$10' }),
83
+ )
84
+ .with(
85
+ {
86
+ isLandscapeStream: false,
87
+ isChatEnabled: true,
88
+ },
89
+ () => ({ bottom: '$19', right: '$8' }),
90
+ )
91
+ .otherwise(() => ({})),
92
+ }}
93
+ >
94
+ <EmojiReaction />
95
+ </Box>
96
+ )}
57
97
  </Flex>
58
98
  );
59
99
  };
@@ -8,16 +8,16 @@ import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover,
8
8
  import { IconButton } from '../../../IconButton';
9
9
  import { MoreSettings } from '../MoreSettings/MoreSettings';
10
10
  import { RaiseHand } from '../RaiseHand';
11
- // @ts-ignore
11
+ // @ts-ignore: No implicit any
12
12
  import { ToastManager } from '../Toast/ToastManager';
13
13
  import { ChatSelectorContainer } from './ChatSelectorContainer';
14
14
  import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
15
- // @ts-ignore
15
+ // @ts-ignore: No implicit any
16
16
  import { useChatDraftMessage } from '../AppData/useChatState';
17
- // @ts-ignore
17
+ // @ts-ignore: No implicit any
18
18
  import { useSetSubscribedChatSelector, useSubscribeChatSelector } from '../AppData/useUISettings';
19
19
  import { useIsPeerBlacklisted } from '../hooks/useChatBlacklist';
20
- // @ts-ignore
20
+ // @ts-ignore: No implicit any
21
21
  import { useEmojiPickerStyles } from './useEmojiPickerStyles';
22
22
  import { useDefaultChatSelection, useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
23
23
  import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants';
@@ -148,7 +148,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
148
148
  }
149
149
 
150
150
  return (
151
- <Box>
151
+ <Box css={{ position: 'relative' }}>
152
152
  <Flex>
153
153
  <ChatSelectorContainer />
154
154
  {canDisableChat && isMobile && isOverlayChat ? (
@@ -202,10 +202,12 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
202
202
  align="center"
203
203
  css={{
204
204
  bg: isOverlayChat && isMobile ? '$surface_dim' : '$surface_default',
205
+ minHeight: '$16',
205
206
  maxHeight: '$24',
206
207
  position: 'relative',
208
+ py: '$6',
207
209
  pl: '$8',
208
- flexGrow: '1',
210
+ flexGrow: 1,
209
211
  r: '$1',
210
212
  '@md': {
211
213
  minHeight: 'unset',
@@ -266,15 +268,17 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo
266
268
  </BaseIconButton>
267
269
  </Flex>
268
270
  {(isMwebHLSStream || isLandscapeHLSStream) && (
269
- <Flex
270
- css={{
271
- alignItems: 'center',
272
- }}
273
- gap="1"
274
- >
275
- {noAVPermissions ? <RaiseHand /> : null}
276
- <MoreSettings elements={elements} screenType={screenType} />
277
- </Flex>
271
+ <>
272
+ <Flex
273
+ css={{
274
+ alignItems: 'center',
275
+ }}
276
+ gap="1"
277
+ >
278
+ {noAVPermissions ? <RaiseHand css={{ bg: '$surface_default' }} /> : null}
279
+ <MoreSettings elements={elements} screenType={screenType} />
280
+ </Flex>
281
+ </>
278
282
  )}
279
283
  </Flex>
280
284
  )}
@@ -1,4 +1,4 @@
1
- import React, { Fragment, useState } from 'react';
1
+ import React, { useState } from 'react';
2
2
  import { useMedia } from 'react-use';
3
3
  import data from '@emoji-mart/data/sets/14/apple.json';
4
4
  import { init } from 'emoji-mart';
@@ -7,9 +7,7 @@ import {
7
7
  selectIsConnectedToRoom,
8
8
  selectLocalPeerID,
9
9
  useCustomEvent,
10
- // useHMSActions,
11
10
  useHMSStore,
12
- // useRecordingStreaming,
13
11
  } from '@100mslive/react-sdk';
14
12
  import { EmojiIcon } from '@100mslive/react-icons';
15
13
  import { EmojiCard } from './Footer/EmojiCard';
@@ -20,6 +18,7 @@ import { config as cssConfig } from '../../Theme';
20
18
  import { Tooltip } from '../../Tooltip';
21
19
  import IconButton from '../IconButton';
22
20
  import { useDropdownList } from './hooks/useDropdownList';
21
+ import { useLandscapeHLSStream, useMobileHLSStream } from '../common/hooks';
23
22
  import { EMOJI_REACTION_TYPE } from '../common/constants';
24
23
 
25
24
  init({ data });
@@ -33,6 +32,9 @@ export const EmojiReaction = () => {
33
32
  const localPeerId = useHMSStore(selectLocalPeerID);
34
33
  // const { isStreamingOn } = useRecordingStreaming();
35
34
  const isMobile = useMedia(cssConfig.media.md);
35
+ const isLandscape = useMedia(cssConfig.media.ls);
36
+ const isMobileHLSStream = useMobileHLSStream();
37
+ const isLandscapeStream = useLandscapeHLSStream();
36
38
 
37
39
  const { sendEvent } = useCustomEvent({
38
40
  type: EMOJI_REACTION_TYPE,
@@ -65,24 +67,32 @@ export const EmojiReaction = () => {
65
67
  if (!isConnected) {
66
68
  return null;
67
69
  }
68
- return isMobile ? (
69
- <EmojiCard sendReaction={sendReaction} />
70
- ) : (
71
- <Fragment>
72
- <Dropdown.Root open={open} onOpenChange={setOpen}>
73
- <Dropdown.Trigger asChild data-testid="emoji_reaction_btn">
74
- <IconButton>
75
- <Tooltip title="Emoji reaction">
76
- <Box>
77
- <EmojiIcon />
78
- </Box>
79
- </Tooltip>
80
- </IconButton>
81
- </Dropdown.Trigger>
82
- <Dropdown.Content sideOffset={5} align="center" css={{ p: '$8', bg: '$surface_default' }}>
83
- <EmojiCard sendReaction={sendReaction} />
84
- </Dropdown.Content>
85
- </Dropdown.Root>
86
- </Fragment>
70
+
71
+ if ((isMobile || isLandscape) && !(isLandscapeStream || isMobileHLSStream)) {
72
+ return <EmojiCard sendReaction={sendReaction} />;
73
+ }
74
+ return (
75
+ <Dropdown.Root open={open} onOpenChange={setOpen}>
76
+ <Dropdown.Trigger asChild data-testid="emoji_reaction_btn">
77
+ <IconButton
78
+ css={
79
+ isMobile || isLandscape ? { bg: '$surface_default', r: '$round', border: '1px solid $border_bright' } : {}
80
+ }
81
+ >
82
+ <Tooltip title="Emoji reaction">
83
+ <Box>
84
+ <EmojiIcon />
85
+ </Box>
86
+ </Tooltip>
87
+ </IconButton>
88
+ </Dropdown.Trigger>
89
+ <Dropdown.Content
90
+ sideOffset={5}
91
+ align={isMobileHLSStream || isLandscapeStream ? 'end' : 'center'}
92
+ css={{ p: '$8', bg: '$surface_default' }}
93
+ >
94
+ <EmojiCard sendReaction={sendReaction} />
95
+ </Dropdown.Content>
96
+ </Dropdown.Root>
87
97
  );
88
98
  };
@@ -14,6 +14,7 @@ export function HLSQualitySelector({
14
14
  onQualityChange,
15
15
  selection,
16
16
  isAuto,
17
+ containerRef,
17
18
  }: {
18
19
  open: boolean;
19
20
  onOpenChange: (value: boolean) => void;
@@ -21,9 +22,14 @@ export function HLSQualitySelector({
21
22
  onQualityChange: (quality: { [key: string]: string | number } | HMSHLSLayer) => void;
22
23
  selection: HMSHLSLayer;
23
24
  isAuto: boolean;
25
+ containerRef?: HTMLDivElement;
24
26
  }) {
25
27
  const isMobile = useMedia(config.media.md);
26
28
  const isLandscape = useIsLandscape();
29
+
30
+ if (layers.length === 0) {
31
+ return null;
32
+ }
27
33
  if (isMobile || isLandscape) {
28
34
  return (
29
35
  <Sheet.Root open={open} onOpenChange={onOpenChange}>
@@ -39,86 +45,87 @@ export function HLSQualitySelector({
39
45
  <SettingsIcon />
40
46
  </Flex>
41
47
  </Sheet.Trigger>
42
-
43
- {layers.length > 0 && (
44
- <Sheet.Content css={{ bg: '$surface_default', pb: '$1' }} onClick={() => onOpenChange(false)}>
45
- <Sheet.Title
46
- css={{
47
- display: 'flex',
48
- color: '$on_surface_high',
49
- w: '100%',
50
- justifyContent: 'space-between',
51
- mt: '$8',
52
- fontSize: '$md',
53
- px: '$10',
54
- pb: '$8',
55
- borderBottom: '1px solid $border_bright',
56
- alignItems: 'center',
57
- }}
58
- >
59
- Quality
60
- <Sheet.Close css={{ color: '$on_surface_high' }} onClick={() => onOpenChange(false)}>
61
- <CrossIcon />
62
- </Sheet.Close>
63
- </Sheet.Title>
64
- {layers.map(layer => {
65
- return (
66
- <Flex
67
- align="center"
68
- css={{
69
- w: '100%',
70
- bg: '$surface_default',
71
- '&:hover': {
72
- bg: '$surface_brighter',
73
- },
74
- cursor: 'pointer',
75
- gap: '$4',
76
- py: '$8',
77
- px: '$10',
78
- }}
79
- key={layer.width}
80
- onClick={() => onQualityChange(layer)}
81
- >
82
- <Text variant="caption" css={{ fontWeight: '$semiBold' }}>
83
- {getQualityText(layer)}
84
- </Text>
85
- <Text variant="caption" css={{ flex: '1 1 0', c: '$on_surface_low', pl: '$2' }}>
86
- {getBitrateText(layer)}
87
- </Text>
88
- {!isAuto && layer.width === selection?.width && layer.height === selection?.height && (
89
- <CheckIcon width="16px" height="16px" />
90
- )}
91
- </Flex>
92
- );
93
- })}
94
- <Flex
95
- align="center"
96
- css={{
97
- w: '100%',
98
- bg: '$surface_default',
99
- '&:hover': {
100
- bg: '$surface_brighter',
101
- },
102
- cursor: 'pointer',
103
- gap: '$4',
104
- py: '$8',
105
- px: '$10',
106
- }}
107
- key="auto"
108
- onClick={() => onQualityChange({ height: 'auto' })}
109
- >
110
- <Text variant="caption" css={{ fontWeight: '$semiBold', flex: '1 1 0' }}>
111
- Auto
112
- </Text>
113
- {isAuto && <CheckIcon width="16px" height="16px" />}
114
- </Flex>
115
- </Sheet.Content>
116
- )}
48
+ <Sheet.Content
49
+ container={containerRef}
50
+ css={{ bg: '$surface_default', pb: '$1' }}
51
+ onClick={() => onOpenChange(false)}
52
+ >
53
+ <Sheet.Title
54
+ css={{
55
+ display: 'flex',
56
+ color: '$on_surface_high',
57
+ w: '100%',
58
+ justifyContent: 'space-between',
59
+ mt: '$8',
60
+ fontSize: '$md',
61
+ px: '$10',
62
+ pb: '$8',
63
+ borderBottom: '1px solid $border_bright',
64
+ alignItems: 'center',
65
+ }}
66
+ >
67
+ Quality
68
+ <Sheet.Close css={{ color: '$on_surface_high' }} onClick={() => onOpenChange(false)}>
69
+ <CrossIcon />
70
+ </Sheet.Close>
71
+ </Sheet.Title>
72
+ {layers.map(layer => {
73
+ return (
74
+ <Flex
75
+ align="center"
76
+ css={{
77
+ w: '100%',
78
+ bg: '$surface_default',
79
+ '&:hover': {
80
+ bg: '$surface_brighter',
81
+ },
82
+ cursor: 'pointer',
83
+ gap: '$4',
84
+ py: '$8',
85
+ px: '$10',
86
+ }}
87
+ key={layer.width}
88
+ onClick={() => onQualityChange(layer)}
89
+ >
90
+ <Text variant="caption" css={{ fontWeight: '$semiBold' }}>
91
+ {getQualityText(layer)}
92
+ </Text>
93
+ <Text variant="caption" css={{ flex: '1 1 0', c: '$on_surface_low', pl: '$2' }}>
94
+ {getBitrateText(layer)}
95
+ </Text>
96
+ {!isAuto && layer.width === selection?.width && layer.height === selection?.height && (
97
+ <CheckIcon width="16px" height="16px" />
98
+ )}
99
+ </Flex>
100
+ );
101
+ })}
102
+ <Flex
103
+ align="center"
104
+ css={{
105
+ w: '100%',
106
+ bg: '$surface_default',
107
+ '&:hover': {
108
+ bg: '$surface_brighter',
109
+ },
110
+ cursor: 'pointer',
111
+ gap: '$4',
112
+ py: '$8',
113
+ px: '$10',
114
+ }}
115
+ key="auto"
116
+ onClick={() => onQualityChange({ height: 'auto' })}
117
+ >
118
+ <Text variant="caption" css={{ fontWeight: '$semiBold', flex: '1 1 0' }}>
119
+ Auto
120
+ </Text>
121
+ {isAuto && <CheckIcon width="16px" height="16px" />}
122
+ </Flex>
123
+ </Sheet.Content>
117
124
  </Sheet.Root>
118
125
  );
119
126
  }
120
127
  return (
121
- <Dropdown.Root open={open} onOpenChange={value => onOpenChange(value)}>
128
+ <Dropdown.Root open={open} onOpenChange={value => onOpenChange(value)} modal={false}>
122
129
  <Dropdown.Trigger asChild data-testid="quality_selector">
123
130
  <Flex
124
131
  css={{
@@ -169,7 +176,7 @@ export function HLSQualitySelector({
169
176
  </Tooltip>
170
177
  </Flex>
171
178
  </Dropdown.Trigger>
172
- {layers.length > 0 && (
179
+ <Dropdown.Portal container={containerRef}>
173
180
  <Dropdown.Content
174
181
  sideOffset={5}
175
182
  align="end"
@@ -232,7 +239,7 @@ export function HLSQualitySelector({
232
239
  {isAuto && <CheckIcon width="16px" height="16px" />}
233
240
  </Dropdown.Item>
234
241
  </Dropdown.Content>
235
- )}
242
+ </Dropdown.Portal>
236
243
  </Dropdown.Root>
237
244
  );
238
245
  }
@@ -14,13 +14,12 @@ export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
14
14
  position: 'relative',
15
15
  '& video::cue': {
16
16
  color: 'white',
17
- // textShadow: '0px 0px 4px #000',
18
17
  whiteSpace: 'pre-line',
19
- fontSize: '$lg',
18
+ fontSize: '$sm',
20
19
  fontStyle: 'normal',
21
- fontWeight: '$semiBold',
20
+ fontWeight: '$regular',
22
21
  lineHeight: '$sm',
23
- letterSpacing: '0.5px',
22
+ letterSpacing: '0.25px',
24
23
  },
25
24
  '& video::-webkit-media-text-track-display': {
26
25
  padding: '0 $4',