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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. package/dist/HLSView-FBEGJ3L7.js +1396 -0
  2. package/dist/HLSView-FBEGJ3L7.js.map +7 -0
  3. package/dist/Prebuilt/common/hooks.d.ts +3 -0
  4. package/dist/Prebuilt/components/Chat/MwebChatOption.d.ts +1 -1
  5. package/dist/Prebuilt/components/HMSVideo/FullscreenButton.d.ts +5 -0
  6. package/dist/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.d.ts +5 -0
  7. package/dist/Prebuilt/components/HMSVideo/HLSCaptionSelector.d.ts +1 -2
  8. package/dist/Prebuilt/components/HMSVideo/HLSQualitySelector.d.ts +13 -0
  9. package/dist/Prebuilt/components/HMSVideo/MwebHLSViewTitle.d.ts +2 -0
  10. package/dist/Prebuilt/components/HMSVideo/PlayButton.d.ts +6 -0
  11. package/dist/Prebuilt/components/HMSVideo/PlayPauseButton.d.ts +6 -0
  12. package/dist/Prebuilt/components/HMSVideo/PlayerContext.d.ts +8 -0
  13. package/dist/Prebuilt/components/HMSVideo/SeekControls.d.ts +7 -0
  14. package/dist/Prebuilt/components/HMSVideo/VideoProgress.d.ts +5 -0
  15. package/dist/Prebuilt/components/HMSVideo/VideoTime.d.ts +2 -0
  16. package/dist/Prebuilt/components/HMSVideo/VolumeControl.d.ts +2 -0
  17. package/dist/Prebuilt/components/HMSVideo/index.d.ts +26 -0
  18. package/dist/Prebuilt/components/HMSVideo/utils.d.ts +8 -0
  19. package/dist/Prebuilt/components/Leave/DesktopLeaveRoom.d.ts +2 -1
  20. package/dist/Prebuilt/components/Leave/LeaveRoom.d.ts +2 -1
  21. package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +2 -3
  22. package/dist/Prebuilt/components/MwebLandscapePrompt.d.ts +1 -1
  23. package/dist/Prebuilt/components/RaiseHand.d.ts +5 -0
  24. package/dist/Prebuilt/components/SidePaneTabs.d.ts +1 -1
  25. package/dist/Sheet/Sheet.d.ts +1 -0
  26. package/dist/{chunk-72B32WVR.js → chunk-R2JJJQR3.js} +1684 -1316
  27. package/dist/chunk-R2JJJQR3.js.map +7 -0
  28. package/dist/index.cjs.js +2866 -2053
  29. package/dist/index.cjs.js.map +4 -4
  30. package/dist/index.js +1 -1
  31. package/dist/meta.cjs.json +786 -299
  32. package/dist/meta.esbuild.json +805 -307
  33. package/package.json +7 -6
  34. package/src/Button/Button.tsx +4 -4
  35. package/src/Fieldset/Fieldset.tsx +1 -1
  36. package/src/Input/PasswordInput.stories.tsx +1 -1
  37. package/src/Pagination/StyledPagination.stories.tsx +2 -2
  38. package/src/Prebuilt/IconButton.tsx +1 -1
  39. package/src/Prebuilt/common/hooks.ts +21 -0
  40. package/src/Prebuilt/components/AppData/useSidepane.js +34 -7
  41. package/src/Prebuilt/components/AudioVideoToggle.tsx +2 -1
  42. package/src/Prebuilt/components/AuthToken.jsx +1 -1
  43. package/src/Prebuilt/components/Chat/Chat.tsx +41 -1
  44. package/src/Prebuilt/components/Chat/ChatFooter.tsx +33 -13
  45. package/src/Prebuilt/components/Chat/MwebChatOption.tsx +1 -1
  46. package/src/Prebuilt/components/ConferenceScreen.tsx +48 -7
  47. package/src/Prebuilt/components/EmojiReaction.jsx +33 -23
  48. package/src/Prebuilt/components/Footer/Footer.tsx +0 -1
  49. package/src/Prebuilt/components/Footer/RoleOptions.tsx +138 -125
  50. package/src/Prebuilt/components/HMSVideo/Controls.jsx +1 -1
  51. package/src/Prebuilt/components/HMSVideo/FullscreenButton.tsx +13 -0
  52. package/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.tsx +72 -0
  53. package/src/Prebuilt/components/HMSVideo/HLSCaptionSelector.tsx +4 -2
  54. package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.tsx +248 -0
  55. package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +17 -7
  56. package/src/Prebuilt/components/HMSVideo/MwebHLSViewTitle.tsx +84 -0
  57. package/src/Prebuilt/components/HMSVideo/PlayButton.tsx +27 -0
  58. package/src/Prebuilt/components/HMSVideo/PlayPauseButton.tsx +27 -0
  59. package/src/Prebuilt/components/HMSVideo/PlayerContext.tsx +15 -0
  60. package/src/Prebuilt/components/HMSVideo/SeekControls.tsx +22 -0
  61. package/src/Prebuilt/components/HMSVideo/VideoProgress.tsx +95 -0
  62. package/src/Prebuilt/components/HMSVideo/VideoTime.tsx +43 -0
  63. package/src/Prebuilt/components/HMSVideo/{VolumeControl.jsx → VolumeControl.tsx} +6 -4
  64. package/src/Prebuilt/components/HMSVideo/{index.js → index.ts} +6 -2
  65. package/src/Prebuilt/components/HMSVideo/{HMSVIdeoUtils.js → utils.ts} +5 -5
  66. package/src/Prebuilt/components/Header/StreamActions.tsx +1 -1
  67. package/src/Prebuilt/components/IconButtonWithOptions/IconButtonWithOptions.tsx +1 -1
  68. package/src/Prebuilt/components/Leave/DesktopLeaveRoom.tsx +50 -46
  69. package/src/Prebuilt/components/Leave/LeaveRoom.tsx +15 -4
  70. package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +46 -27
  71. package/src/Prebuilt/components/MoreSettings/MoreSettings.tsx +3 -1
  72. package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +37 -31
  73. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +12 -8
  74. package/src/Prebuilt/components/MwebLandscapePrompt.tsx +14 -3
  75. package/src/Prebuilt/components/Notifications/HandRaisedNotifications.tsx +5 -2
  76. package/src/Prebuilt/components/Notifications/PeerNotifications.tsx +1 -1
  77. package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +19 -8
  78. package/src/Prebuilt/components/Polls/Voting/Voting.tsx +3 -2
  79. package/src/Prebuilt/components/Polls/common/OptionInputWithDelete.tsx +1 -1
  80. package/src/Prebuilt/components/Polls/common/utils.ts +2 -2
  81. package/src/Prebuilt/components/RaiseHand.tsx +24 -0
  82. package/src/Prebuilt/components/RoomDetails/RoomDetailsPane.tsx +41 -14
  83. package/src/Prebuilt/components/SidePaneTabs.tsx +56 -48
  84. package/src/Prebuilt/components/StatsForNerds.jsx +14 -6
  85. package/src/Prebuilt/components/Streaming/Common.jsx +1 -1
  86. package/src/Prebuilt/components/TileMenu/TileMenuContent.tsx +2 -2
  87. package/src/Prebuilt/components/Toast/ToastBatcher.js +8 -1
  88. package/src/Prebuilt/components/Toast/ToastConfig.jsx +17 -0
  89. package/src/Prebuilt/components/VideoLayouts/RoleProminence.tsx +1 -1
  90. package/src/Prebuilt/components/hooks/useRoleProminencePeers.tsx +2 -1
  91. package/src/Prebuilt/components/pdfAnnotator/shareScreenOptions.jsx +2 -2
  92. package/src/Prebuilt/components/pdfAnnotator/uploadedFile.jsx +1 -1
  93. package/src/Prebuilt/layouts/HLSView.jsx +359 -178
  94. package/src/Prebuilt/layouts/SidePane.tsx +145 -59
  95. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +22 -2
  96. package/src/Prebuilt/primitives/DialogContent.jsx +1 -1
  97. package/src/Prebuilt/provider/roomLayoutProvider/index.tsx +1 -1
  98. package/src/Sheet/Sheet.tsx +7 -3
  99. package/dist/HLSView-37B2YVTC.js +0 -987
  100. package/dist/HLSView-37B2YVTC.js.map +0 -7
  101. package/dist/chunk-72B32WVR.js.map +0 -7
  102. package/src/Prebuilt/components/HMSVideo/FullscreenButton.jsx +0 -18
  103. package/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.jsx +0 -35
  104. package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx +0 -127
  105. package/src/Prebuilt/components/HMSVideo/PlayButton.jsx +0 -13
  106. package/src/Prebuilt/components/HMSVideo/VideoProgress.jsx +0 -76
  107. package/src/Prebuilt/components/HMSVideo/VideoTime.jsx +0 -33
  108. package/src/Prebuilt/components/RaiseHand.jsx +0 -17
@@ -0,0 +1,248 @@
1
+ import React from 'react';
2
+ import { useMedia } from 'react-use';
3
+ import { HMSHLSLayer } from '@100mslive/hls-player';
4
+ import { CheckIcon, CrossIcon, SettingsIcon } from '@100mslive/react-icons';
5
+ import { Box, Dropdown, Flex, Text, Tooltip } from '../../..';
6
+ import { Sheet } from '../../../Sheet';
7
+ import { config } from '../../../Theme';
8
+ import { useIsLandscape } from '../../common/hooks';
9
+
10
+ export function HLSQualitySelector({
11
+ open,
12
+ onOpenChange,
13
+ layers,
14
+ onQualityChange,
15
+ selection,
16
+ isAuto,
17
+ containerRef,
18
+ }: {
19
+ open: boolean;
20
+ onOpenChange: (value: boolean) => void;
21
+ layers: HMSHLSLayer[];
22
+ onQualityChange: (quality: { [key: string]: string | number } | HMSHLSLayer) => void;
23
+ selection: HMSHLSLayer;
24
+ isAuto: boolean;
25
+ containerRef?: HTMLDivElement;
26
+ }) {
27
+ const isMobile = useMedia(config.media.md);
28
+ const isLandscape = useIsLandscape();
29
+
30
+ if (layers.length === 0) {
31
+ return null;
32
+ }
33
+ if (isMobile || isLandscape) {
34
+ return (
35
+ <Sheet.Root open={open} onOpenChange={onOpenChange}>
36
+ <Sheet.Trigger asChild data-testid="quality_selector">
37
+ <Flex
38
+ css={{
39
+ color: '$on_primary_high',
40
+ r: '$1',
41
+ cursor: 'pointer',
42
+ p: '$2',
43
+ }}
44
+ >
45
+ <SettingsIcon />
46
+ </Flex>
47
+ </Sheet.Trigger>
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>
124
+ </Sheet.Root>
125
+ );
126
+ }
127
+ return (
128
+ <Dropdown.Root open={open} onOpenChange={value => onOpenChange(value)} modal={false}>
129
+ <Dropdown.Trigger asChild data-testid="quality_selector">
130
+ <Flex
131
+ css={{
132
+ color: '$on_primary_high',
133
+ r: '$1',
134
+ cursor: 'pointer',
135
+ p: '$2',
136
+ }}
137
+ >
138
+ <Tooltip title="Select Quality" side="top">
139
+ <Flex align="center">
140
+ <Box
141
+ css={{
142
+ w: '$9',
143
+ h: '$9',
144
+ display: 'inline-flex',
145
+ alignItems: 'center',
146
+ c: '$on_surface_high',
147
+ }}
148
+ >
149
+ <SettingsIcon />
150
+ </Box>
151
+ <Text
152
+ variant={{
153
+ '@md': 'sm',
154
+ '@sm': 'xs',
155
+ '@xs': 'tiny',
156
+ }}
157
+ css={{ display: 'flex', alignItems: 'center', ml: '$2', c: '$on_surface_medium' }}
158
+ >
159
+ {isAuto && (
160
+ <>
161
+ Auto
162
+ <Box
163
+ css={{
164
+ mx: '$2',
165
+ w: '$2',
166
+ h: '$2',
167
+ background: '$on_surface_medium',
168
+ r: '$1',
169
+ }}
170
+ />
171
+ </>
172
+ )}
173
+ {selection && Math.min(selection.width || 0, selection.height || 0)}p
174
+ </Text>
175
+ </Flex>
176
+ </Tooltip>
177
+ </Flex>
178
+ </Dropdown.Trigger>
179
+ <Dropdown.Portal container={containerRef}>
180
+ <Dropdown.Content
181
+ sideOffset={5}
182
+ align="end"
183
+ css={{
184
+ height: 'auto',
185
+ maxHeight: '$52',
186
+ w: '$40',
187
+ bg: '$surface_bright',
188
+ py: '$4',
189
+ gap: '$4',
190
+ display: 'grid',
191
+ }}
192
+ >
193
+ {layers.map(layer => {
194
+ return (
195
+ <Dropdown.Item
196
+ onClick={() => onQualityChange(layer)}
197
+ key={layer.width}
198
+ css={{
199
+ bg:
200
+ !isAuto && layer.width === selection?.width && layer.height === selection?.height
201
+ ? '$surface_default'
202
+ : '$surface_bright',
203
+ '&:hover': {
204
+ bg: '$surface_brighter',
205
+ },
206
+ p: '$2 $4 $2 $8',
207
+ h: '$12',
208
+ gap: '$2',
209
+ }}
210
+ >
211
+ <Text variant="caption" css={{ fontWeight: '$semiBold' }}>
212
+ {getQualityText(layer)}
213
+ </Text>
214
+ <Text variant="caption" css={{ flex: '1 1 0', c: '$on_surface_low', pl: '$2' }}>
215
+ {getBitrateText(layer)}
216
+ </Text>
217
+ {!isAuto && layer.width === selection?.width && layer.height === selection?.height && (
218
+ <CheckIcon width="16px" height="16px" />
219
+ )}
220
+ </Dropdown.Item>
221
+ );
222
+ })}
223
+ <Dropdown.Item
224
+ onClick={() => onQualityChange({ height: 'auto' })}
225
+ key="auto"
226
+ css={{
227
+ bg: !isAuto ? '$surface_bright' : '$surface_default',
228
+ '&:hover': {
229
+ bg: '$surface_brighter',
230
+ },
231
+ p: '$2 $4 $2 $8',
232
+ h: '$12',
233
+ gap: '$2',
234
+ }}
235
+ >
236
+ <Text variant="caption" css={{ fontWeight: '$semiBold', flex: '1 1 0' }}>
237
+ Auto
238
+ </Text>
239
+ {isAuto && <CheckIcon width="16px" height="16px" />}
240
+ </Dropdown.Item>
241
+ </Dropdown.Content>
242
+ </Dropdown.Portal>
243
+ </Dropdown.Root>
244
+ );
245
+ }
246
+
247
+ const getQualityText = (layer: HMSHLSLayer) => `${Math.min(layer.height || 0, layer.width || 0)}p `;
248
+ const getBitrateText = (layer: HMSHLSLayer) => `(${(Number(layer.bitrate / 1000) / 1000).toFixed(2)} Mbps)`;
@@ -1,5 +1,5 @@
1
1
  import React, { forwardRef } from 'react';
2
- import { Flex } from '../../../';
2
+ import { Flex } from '../../../Layout';
3
3
 
4
4
  export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
5
5
  return (
@@ -8,18 +8,25 @@ export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
8
8
  css={{
9
9
  size: '100%',
10
10
  position: 'relative',
11
+ justifyContent: 'center',
12
+ '@md': {
13
+ height: 'auto',
14
+ '& video': {
15
+ height: '$60 !important',
16
+ },
17
+ },
11
18
  '& video::cue': {
12
19
  color: 'white',
13
- // textShadow: '0px 0px 4px #000',
14
20
  whiteSpace: 'pre-line',
15
- fontSize: '$lg',
21
+ fontSize: '$sm',
16
22
  fontStyle: 'normal',
17
- fontWeight: '$semiBold',
23
+ fontWeight: '$regular',
18
24
  lineHeight: '$sm',
19
- letterSpacing: '0.5px',
25
+ letterSpacing: '0.25px',
20
26
  },
21
27
  '& video::-webkit-media-text-track-display': {
22
28
  padding: '0 $4',
29
+ boxShadow: '0px 1px 3px 0px #000000A3',
23
30
  },
24
31
  '& video::-webkit-media-text-track-container': {
25
32
  fontSize: '$space$10 !important',
@@ -30,9 +37,12 @@ export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => {
30
37
  >
31
38
  <video
32
39
  style={{
33
- flex: '1 1 0',
34
40
  margin: '0 auto',
35
- minHeight: '0',
41
+ objectFit: 'contain',
42
+ width: 'auto',
43
+ height: 'auto',
44
+ maxWidth: '100%',
45
+ maxHeight: '100%',
36
46
  }}
37
47
  ref={videoRef}
38
48
  playsInline
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+ import { ChevronDownIcon } from '@100mslive/react-icons';
3
+ import { Flex } from '../../../Layout';
4
+ import { Text } from '../../../Text';
5
+ // @ts-ignore: No implicit any
6
+ import { Logo } from '../Header/HeaderComponents';
7
+ import { RoomDetailsRow } from '../RoomDetails/RoomDetailsRow';
8
+ import { useRoomLayoutHeader } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
9
+ // @ts-ignore
10
+ import { useIsSidepaneTypeOpen, useSidepaneToggle } from '../AppData/useSidepane';
11
+ import { SIDE_PANE_OPTIONS } from '../../common/constants';
12
+
13
+ /*
14
+ player handler --> left -> go live with timer or live, right -> expand icon
15
+ inbetween -> play pause icon, double tap to go back/forward
16
+ seekbar
17
+ half page will have chat or participant view
18
+ */
19
+ export const HLSViewTitle = () => {
20
+ const { title, details } = useRoomLayoutHeader();
21
+ const toggleDetailsPane = useSidepaneToggle(SIDE_PANE_OPTIONS.ROOM_DETAILS);
22
+ const isDetailSidepaneOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.ROOM_DETAILS);
23
+
24
+ if (isDetailSidepaneOpen) {
25
+ return (
26
+ <Flex
27
+ gap="4"
28
+ align="center"
29
+ justify="between"
30
+ css={{
31
+ position: 'relative',
32
+ h: 'fit-content',
33
+ w: '100%',
34
+ borderBottom: '1px solid $border_bright',
35
+ p: '$8',
36
+ backgroundColor: '$surface_dim',
37
+ }}
38
+ >
39
+ <Text variant="sub2" css={{ fontWeight: '$semiBold' }}>
40
+ About Session
41
+ </Text>
42
+ <Flex
43
+ onClick={toggleDetailsPane}
44
+ css={{
45
+ color: '$on_surface_high',
46
+ cursor: 'pointer',
47
+ '&:hover': { opacity: '0.8' },
48
+ }}
49
+ >
50
+ <ChevronDownIcon />
51
+ </Flex>
52
+ </Flex>
53
+ );
54
+ }
55
+ return (
56
+ <Flex
57
+ gap="4"
58
+ align="center"
59
+ css={{
60
+ position: 'relative',
61
+ h: 'fit-content',
62
+ w: '100%',
63
+ borderBottom: '1px solid $border_bright',
64
+ p: '$8',
65
+ backgroundColor: '$surface_dim',
66
+ }}
67
+ >
68
+ <Logo />
69
+ <Flex direction="column">
70
+ {title ? (
71
+ <Text variant="sub2" css={{ fontWeight: '$semiBold' }}>
72
+ {title}
73
+ </Text>
74
+ ) : null}
75
+ <Flex>
76
+ <RoomDetailsRow details={details} />
77
+ <Text variant="caption" css={{ color: '$on_surface_medium' }} onClick={toggleDetailsPane}>
78
+ &nbsp;...more
79
+ </Text>
80
+ </Flex>
81
+ </Flex>
82
+ </Flex>
83
+ );
84
+ };
@@ -0,0 +1,27 @@
1
+ import React, { MouseEvent } from 'react';
2
+ import { PauseIcon, PlayIcon } from '@100mslive/react-icons';
3
+ import { IconButton, Tooltip } from '../../..';
4
+ import { useHMSPlayerContext } from './PlayerContext';
5
+
6
+ export const PlayButton = ({
7
+ isPaused,
8
+ width = 20,
9
+ height = 20,
10
+ }: {
11
+ isPaused: boolean;
12
+ width: number;
13
+ height: number;
14
+ }) => {
15
+ const { hlsPlayer } = useHMSPlayerContext();
16
+ const onClick = async (event: MouseEvent) => {
17
+ event?.stopPropagation();
18
+ isPaused ? await hlsPlayer?.play() : hlsPlayer?.pause();
19
+ };
20
+ return (
21
+ <Tooltip title={isPaused ? 'Play' : 'Pause'} side="top">
22
+ <IconButton onClick={onClick} data-testid="play_pause_btn">
23
+ {isPaused ? <PlayIcon width={width} height={height} /> : <PauseIcon width={width} height={height} />}
24
+ </IconButton>
25
+ </Tooltip>
26
+ );
27
+ };
@@ -0,0 +1,27 @@
1
+ import React, { MouseEvent } from 'react';
2
+ import { PauseIcon, PlayIcon } from '@100mslive/react-icons';
3
+ import { IconButton, Tooltip } from '../../..';
4
+ import { useHMSPlayerContext } from './PlayerContext';
5
+
6
+ export const PlayPauseButton = ({
7
+ isPaused,
8
+ width = 20,
9
+ height = 20,
10
+ }: {
11
+ isPaused: boolean;
12
+ width: number;
13
+ height: number;
14
+ }) => {
15
+ const { hlsPlayer } = useHMSPlayerContext();
16
+ const onClick = async (event: MouseEvent) => {
17
+ event?.stopPropagation();
18
+ isPaused ? await hlsPlayer?.play() : hlsPlayer?.pause();
19
+ };
20
+ return (
21
+ <Tooltip title={isPaused ? 'Play' : 'Pause'} side="top">
22
+ <IconButton onClick={onClick} data-testid="play_pause_btn">
23
+ {isPaused ? <PlayIcon width={width} height={height} /> : <PauseIcon width={width} height={height} />}
24
+ </IconButton>
25
+ </Tooltip>
26
+ );
27
+ };
@@ -0,0 +1,15 @@
1
+ import React, { useContext } from 'react';
2
+ import { HMSHLSPlayer } from '@100mslive/hls-player';
3
+
4
+ type IHMSPlayerContext = {
5
+ hlsPlayer?: HMSHLSPlayer;
6
+ };
7
+
8
+ export const HMSPlayerContext = React.createContext<IHMSPlayerContext>({
9
+ hlsPlayer: undefined,
10
+ });
11
+
12
+ export const useHMSPlayerContext = () => {
13
+ const context = useContext(HMSPlayerContext);
14
+ return context;
15
+ };
@@ -0,0 +1,22 @@
1
+ import React, { MouseEventHandler } from 'react';
2
+ import { IconButton, Tooltip } from '../../..';
3
+
4
+ export const SeekControls = ({
5
+ title,
6
+ onClick,
7
+ children,
8
+ css,
9
+ }: {
10
+ title: string;
11
+ onClick?: MouseEventHandler<HTMLButtonElement>;
12
+ css: any;
13
+ children: React.ReactNode;
14
+ }) => {
15
+ return (
16
+ <Tooltip title={title} side="top">
17
+ <IconButton onClick={onClick} data-testid="backward_forward_arrow_btn" css={css}>
18
+ {children}
19
+ </IconButton>
20
+ </Tooltip>
21
+ );
22
+ };
@@ -0,0 +1,95 @@
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
+ import { Box, Flex, Slider } from '../../..';
3
+ import { useHMSPlayerContext } from './PlayerContext';
4
+ import { getPercentage } from './utils';
5
+
6
+ export const VideoProgress = ({
7
+ seekProgress,
8
+ setSeekProgress,
9
+ }: {
10
+ seekProgress: boolean;
11
+ setSeekProgress: (value: boolean) => void;
12
+ }) => {
13
+ const { hlsPlayer } = useHMSPlayerContext();
14
+ const [videoProgress, setVideoProgress] = useState<number>(0);
15
+ const [bufferProgress, setBufferProgress] = useState(0);
16
+ const videoEl = hlsPlayer?.getVideoElement();
17
+
18
+ const setProgress = useCallback(() => {
19
+ if (!videoEl) {
20
+ return;
21
+ }
22
+ const duration = isFinite(videoEl.duration) ? videoEl.duration : videoEl.seekable?.end(0) || 0;
23
+ const videoProgress = Math.floor(getPercentage(videoEl.currentTime, duration));
24
+ let bufferProgress = 0;
25
+ if (videoEl.buffered.length > 0) {
26
+ bufferProgress = Math.floor(getPercentage(videoEl.buffered?.end(0), duration));
27
+ }
28
+ setVideoProgress(isNaN(videoProgress) ? 0 : videoProgress);
29
+ setBufferProgress(isNaN(bufferProgress) ? 0 : bufferProgress);
30
+ }, [videoEl]);
31
+ const timeupdateHandler = useCallback(() => {
32
+ if (!videoEl || seekProgress) {
33
+ return;
34
+ }
35
+ setProgress();
36
+ }, [seekProgress, setProgress, videoEl]);
37
+ useEffect(() => {
38
+ if (!videoEl) {
39
+ return;
40
+ }
41
+ videoEl.addEventListener('timeupdate', timeupdateHandler);
42
+ return function cleanup() {
43
+ videoEl?.removeEventListener('timeupdate', timeupdateHandler);
44
+ };
45
+ }, [timeupdateHandler, videoEl]);
46
+
47
+ const onProgress = (progress: number[]) => {
48
+ const progress1 = Math.floor(getPercentage(progress[0], 100));
49
+ const videoEl = hlsPlayer?.getVideoElement();
50
+ if (!videoEl) {
51
+ return;
52
+ }
53
+ const duration = isFinite(videoEl.duration) ? videoEl.duration : videoEl.seekable?.end(0) || 0;
54
+ const currentTime = (progress1 * duration) / 100;
55
+ hlsPlayer?.seekTo(currentTime);
56
+ setProgress();
57
+ };
58
+
59
+ if (!videoEl) {
60
+ return null;
61
+ }
62
+ return (
63
+ <Flex align="center" css={{ cursor: 'pointer', h: '$2', alignSelf: 'stretch' }}>
64
+ <Slider
65
+ id="video-actual-rest"
66
+ css={{
67
+ cursor: 'pointer',
68
+ h: '$2',
69
+ zIndex: 1,
70
+ transition: `all .2s ease .5s`,
71
+ }}
72
+ min={0}
73
+ max={100}
74
+ step={1}
75
+ value={[videoProgress]}
76
+ showTooltip={false}
77
+ onValueChange={onProgress}
78
+ onPointerDown={() => setSeekProgress(true)}
79
+ onPointerUp={() => setSeekProgress(false)}
80
+ thumbStyles={{ w: '$6', h: '$6' }}
81
+ />
82
+ <Box
83
+ id="video-buffer"
84
+ css={{
85
+ h: '$2',
86
+ width: `${bufferProgress - videoProgress}%`,
87
+ background: '$on_surface_high',
88
+ position: 'absolute',
89
+ left: `${videoProgress}%`,
90
+ opacity: '25%',
91
+ }}
92
+ />
93
+ </Flex>
94
+ );
95
+ };
@@ -0,0 +1,43 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { HMSHLSPlayerEvents } from '@100mslive/hls-player';
3
+ import { Text } from '../../../Text';
4
+ import { useHMSPlayerContext } from './PlayerContext';
5
+ import { getDurationFromSeconds } from './utils';
6
+
7
+ export const VideoTime = () => {
8
+ const { hlsPlayer } = useHMSPlayerContext();
9
+ const [videoTime, setVideoTime] = useState('');
10
+
11
+ useEffect(() => {
12
+ const timeupdateHandler = (currentTime: number) => {
13
+ const videoEl = hlsPlayer?.getVideoElement();
14
+ if (videoEl) {
15
+ const duration = isFinite(videoEl.duration) ? videoEl.duration : videoEl.seekable.end(0) || 0;
16
+ setVideoTime(getDurationFromSeconds(duration - currentTime));
17
+ } else {
18
+ setVideoTime(getDurationFromSeconds(currentTime));
19
+ }
20
+ };
21
+ if (hlsPlayer) {
22
+ hlsPlayer.on(HMSHLSPlayerEvents.CURRENT_TIME, timeupdateHandler);
23
+ }
24
+ return function cleanup() {
25
+ hlsPlayer?.off(HMSHLSPlayerEvents.CURRENT_TIME, timeupdateHandler);
26
+ };
27
+ }, [hlsPlayer]);
28
+
29
+ return hlsPlayer ? (
30
+ <Text
31
+ variant="body1"
32
+ css={{
33
+ minWidth: '$16',
34
+ c: '$on_surface_medium',
35
+ display: 'flex',
36
+ justifyContent: 'center',
37
+ fontWeight: '$regular',
38
+ }}
39
+ >
40
+ -{videoTime}
41
+ </Text>
42
+ ) : null;
43
+ };
@@ -1,8 +1,10 @@
1
1
  import React, { useState } from 'react';
2
2
  import { VolumeOneIcon, VolumeTwoIcon, VolumeZeroIcon } from '@100mslive/react-icons';
3
- import { Flex, Slider } from '../../../';
3
+ import { Flex, Slider } from '../../..';
4
+ import { useHMSPlayerContext } from './PlayerContext';
4
5
 
5
- export const VolumeControl = ({ hlsPlayer }) => {
6
+ export const VolumeControl = () => {
7
+ const { hlsPlayer } = useHMSPlayerContext();
6
8
  const [volume, setVolume] = useState(hlsPlayer?.volume ?? 100);
7
9
  const [showSlider, setShowSlider] = useState(false);
8
10
 
@@ -47,7 +49,7 @@ export const VolumeControl = ({ hlsPlayer }) => {
47
49
  step={1}
48
50
  value={[volume]}
49
51
  onValueChange={volume => {
50
- hlsPlayer.setVolume(volume[0]);
52
+ hlsPlayer?.setVolume(volume[0]);
51
53
  setVolume(volume[0]);
52
54
  }}
53
55
  thumbStyles={{ w: '$6', h: '$6' }}
@@ -56,7 +58,7 @@ export const VolumeControl = ({ hlsPlayer }) => {
56
58
  );
57
59
  };
58
60
 
59
- const VolumeIcon = ({ volume, onClick }) => {
61
+ const VolumeIcon = ({ volume, onClick }: { volume: number; onClick: () => void }) => {
60
62
  if (volume === 0) {
61
63
  return <VolumeZeroIcon style={{ cursor: 'pointer', transition: 'color 0.3s' }} onClick={onClick} />;
62
64
  }
@@ -1,13 +1,16 @@
1
+ // @ts-ignore
1
2
  import { LeftControls, RightControls, VideoControls } from './Controls';
3
+ // @ts-ignore
2
4
  import { HMSVideo } from './HMSVideo';
3
- import { PlayButton } from './PlayButton';
5
+ import { PlayPauseButton } from './PlayPauseButton';
6
+ import { SeekControls } from './SeekControls';
4
7
  import { VideoProgress } from './VideoProgress';
5
8
  import { VideoTime } from './VideoTime';
6
9
  import { VolumeControl } from './VolumeControl';
7
10
 
8
11
  export const HMSVideoPlayer = {
9
12
  Root: HMSVideo,
10
- PlayButton: PlayButton,
13
+ PlayPauseButton: PlayPauseButton,
11
14
  Progress: VideoProgress,
12
15
  Duration: VideoTime,
13
16
  Volume: VolumeControl,
@@ -16,4 +19,5 @@ export const HMSVideoPlayer = {
16
19
  Left: LeftControls,
17
20
  Right: RightControls,
18
21
  },
22
+ Seeker: SeekControls,
19
23
  };