Skip to content

Commit fec831f

Browse files
committed
refactor: split controls into different files
1 parent fa8c68a commit fec831f

File tree

6 files changed

+140
-133
lines changed

6 files changed

+140
-133
lines changed

src/components/media/audio/sound.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
ProgressSlider,
1717
TranscriptToggle,
1818
VolumeSettings,
19-
} from '../controls/controls'
19+
} from '../controls/commonControls'
2020
import TimeIndicator from '../timeIndicator/timeIndicator'
2121
import Transcript from '../transcript/transcript'
2222

src/components/media/controls/controls.tsx renamed to src/components/media/controls/commonControls.tsx

Lines changed: 4 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,18 @@
1-
import './controls.css'
1+
import './commonControls.css'
22

33
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'
44
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'
55
import Box from '@mui/material/Box'
66
import Button from '@mui/material/Button'
7-
import Icon from '@mui/material/Icon'
8-
import IconButton from '@mui/material/IconButton'
97
import LinearProgress from '@mui/material/LinearProgress'
108
import Slider from '@mui/material/Slider'
119
import Typography from '@mui/material/Typography'
12-
import React, { useEffect, useState } from 'react'
10+
import React, { useState } from 'react'
1311

1412
import { formatDurationTime } from '../../helper'
13+
import { MediaIconButton } from './mediaIconButton'
1514

16-
interface MediaIconButtonProps {
17-
onClick: () => void
18-
action:
19-
| 'play'
20-
| 'pause'
21-
| 'forward'
22-
| 'replay'
23-
| 'volumeUp'
24-
| 'volumeOff'
25-
| 'pictureInPicture'
26-
| 'pictureInPictureExit'
27-
| 'fullscreen'
28-
| 'fullscreenExit'
29-
| 'captionsOn'
30-
| 'captionsOff'
31-
className?: string
32-
color?: string
33-
}
34-
35-
interface MediaControls {
15+
export interface MediaControls {
3616
mediaElement: HTMLMediaElement
3717
color?: string
3818
}
@@ -43,54 +23,12 @@ interface Toggle {
4323
color?: string
4424
}
4525

46-
interface FullscreenToggleProps {
47-
element: HTMLElement
48-
color?: string
49-
}
50-
5126
interface MoveTenSecondsButtonProps extends MediaControls {
5227
movement: 'replay' | 'forward'
5328
}
5429

5530
const percentMultiple = 100
5631

57-
export function MediaIconButton(props: MediaIconButtonProps) {
58-
const controls = {
59-
play: { symbol: 'play_circle', label: 'play' },
60-
pause: { symbol: 'pause_circle', label: 'pause' },
61-
forward: { symbol: 'forward_10', label: 'forward ten seconds' },
62-
replay: { symbol: 'replay_10', label: 'replay ten seconds' },
63-
volumeUp: { symbol: 'volume_up', label: 'mute' },
64-
volumeOff: { symbol: 'volume_off', label: 'unmute' },
65-
pictureInPicture: {
66-
symbol: 'picture_in_picture',
67-
label: 'picture in picture',
68-
},
69-
pictureInPictureExit: {
70-
symbol: 'picture_in_picture_off',
71-
label: 'exit picture in picture',
72-
},
73-
fullscreen: { symbol: 'fullscreen', label: 'fullscreen' },
74-
fullscreenExit: { symbol: 'fullscreen_exit', label: 'exit fullscreen' },
75-
captionsOn: { symbol: 'closed_caption', label: 'show captions' },
76-
captionsOff: { symbol: 'closed_caption_disabled', label: 'hide captions' },
77-
}
78-
return (
79-
<IconButton
80-
onClick={props.onClick}
81-
aria-label={`click to ${controls[props.action].label}`}
82-
className={props.className}
83-
data-cy={`${props.action}-button`}
84-
>
85-
<Icon sx={{ color: props.color }}>
86-
<span className="material-symbols-rounded">
87-
{controls[props.action].symbol}
88-
</span>
89-
</Icon>
90-
</IconButton>
91-
)
92-
}
93-
9432
export function ProgressSlider(props: MediaControls) {
9533
const formattedElapsedTime = formatDurationTime(
9634
props.mediaElement.currentTime
@@ -270,69 +208,6 @@ export function PausePlayToggle(props: MediaControls) {
270208
)
271209
}
272210

273-
export function PictureInPictureToggle(props: MediaControls) {
274-
const [isPictureInPicture, setIsPictureInPicture] = useState(
275-
!!document.pictureInPictureElement
276-
)
277-
278-
const videoElement = props.mediaElement as HTMLVideoElement
279-
280-
const action = isPictureInPicture
281-
? 'pictureInPictureExit'
282-
: 'pictureInPicture'
283-
284-
function handlePictureInPicture() {
285-
if (isPictureInPicture) {
286-
document.exitPictureInPicture()
287-
} else {
288-
videoElement.requestPictureInPicture()
289-
}
290-
}
291-
292-
videoElement.onenterpictureinpicture = function () {
293-
setIsPictureInPicture(true)
294-
}
295-
videoElement.onleavepictureinpicture = function () {
296-
setIsPictureInPicture(false)
297-
}
298-
299-
return (
300-
<MediaIconButton
301-
onClick={handlePictureInPicture}
302-
action={action}
303-
color={props.color}
304-
/>
305-
)
306-
}
307-
308-
export function FullscreenToggle(props: FullscreenToggleProps) {
309-
const [isFullscreen, setIsFullscreen] = useState(!!document.fullscreenElement)
310-
311-
useEffect(() => {
312-
document.addEventListener('fullscreenchange', () => {
313-
setIsFullscreen(!isFullscreen)
314-
})
315-
}, [isFullscreen])
316-
317-
const action = isFullscreen ? 'fullscreenExit' : 'fullscreen'
318-
319-
function handleFullscreen() {
320-
if (isFullscreen) {
321-
document.exitFullscreen()
322-
} else {
323-
props.element.requestFullscreen()
324-
}
325-
}
326-
327-
return (
328-
<MediaIconButton
329-
onClick={handleFullscreen}
330-
action={action}
331-
color={props.color}
332-
/>
333-
)
334-
}
335-
336211
export function PlaybackRateButton(props: MediaControls) {
337212
const [playbackRate, setPlaybackRate] = useState(
338213
props.mediaElement.playbackRate
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import Icon from '@mui/material/Icon'
2+
import IconButton from '@mui/material/IconButton'
3+
4+
interface MediaIconButtonProps {
5+
onClick: () => void
6+
action:
7+
| 'play'
8+
| 'pause'
9+
| 'forward'
10+
| 'replay'
11+
| 'volumeUp'
12+
| 'volumeOff'
13+
| 'pictureInPicture'
14+
| 'pictureInPictureExit'
15+
| 'fullscreen'
16+
| 'fullscreenExit'
17+
| 'captionsOn'
18+
| 'captionsOff'
19+
className?: string
20+
color?: string
21+
}
22+
23+
export function MediaIconButton(props: MediaIconButtonProps) {
24+
const controls = {
25+
play: { symbol: 'play_circle', label: 'play' },
26+
pause: { symbol: 'pause_circle', label: 'pause' },
27+
forward: { symbol: 'forward_10', label: 'forward ten seconds' },
28+
replay: { symbol: 'replay_10', label: 'replay ten seconds' },
29+
volumeUp: { symbol: 'volume_up', label: 'mute' },
30+
volumeOff: { symbol: 'volume_off', label: 'unmute' },
31+
pictureInPicture: {
32+
symbol: 'picture_in_picture',
33+
label: 'picture in picture',
34+
},
35+
pictureInPictureExit: {
36+
symbol: 'picture_in_picture_off',
37+
label: 'exit picture in picture',
38+
},
39+
fullscreen: { symbol: 'fullscreen', label: 'fullscreen' },
40+
fullscreenExit: { symbol: 'fullscreen_exit', label: 'exit fullscreen' },
41+
captionsOn: { symbol: 'closed_caption', label: 'show captions' },
42+
captionsOff: { symbol: 'closed_caption_disabled', label: 'hide captions' },
43+
}
44+
return (
45+
<IconButton
46+
onClick={props.onClick}
47+
aria-label={`click to ${controls[props.action].label}`}
48+
className={props.className}
49+
data-cy={`${props.action}-button`}
50+
>
51+
<Icon sx={{ color: props.color }}>
52+
<span className="material-symbols-rounded">
53+
{controls[props.action].symbol}
54+
</span>
55+
</Icon>
56+
</IconButton>
57+
)
58+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { useEffect, useState } from 'react'
2+
3+
import type { MediaControls } from './commonControls'
4+
import { MediaIconButton } from './mediaIconButton'
5+
6+
interface FullscreenToggleProps {
7+
element: HTMLElement
8+
color?: string
9+
}
10+
11+
export function PictureInPictureToggle(props: MediaControls) {
12+
const [isPictureInPicture, setIsPictureInPicture] = useState(
13+
!!document.pictureInPictureElement
14+
)
15+
16+
const videoElement = props.mediaElement as HTMLVideoElement
17+
18+
const action = isPictureInPicture
19+
? 'pictureInPictureExit'
20+
: 'pictureInPicture'
21+
22+
function handlePictureInPicture() {
23+
if (isPictureInPicture) {
24+
document.exitPictureInPicture()
25+
} else {
26+
videoElement.requestPictureInPicture()
27+
}
28+
}
29+
30+
videoElement.onenterpictureinpicture = function () {
31+
setIsPictureInPicture(true)
32+
}
33+
videoElement.onleavepictureinpicture = function () {
34+
setIsPictureInPicture(false)
35+
}
36+
37+
return (
38+
<MediaIconButton
39+
onClick={handlePictureInPicture}
40+
action={action}
41+
color={props.color}
42+
/>
43+
)
44+
}
45+
46+
export function FullscreenToggle(props: FullscreenToggleProps) {
47+
const [isFullscreen, setIsFullscreen] = useState(!!document.fullscreenElement)
48+
49+
useEffect(() => {
50+
document.addEventListener('fullscreenchange', () => {
51+
setIsFullscreen(!isFullscreen)
52+
})
53+
}, [isFullscreen])
54+
55+
const action = isFullscreen ? 'fullscreenExit' : 'fullscreen'
56+
57+
function handleFullscreen() {
58+
if (isFullscreen) {
59+
document.exitFullscreen()
60+
} else {
61+
props.element.requestFullscreen()
62+
}
63+
}
64+
65+
return (
66+
<MediaIconButton
67+
onClick={handleFullscreen}
68+
action={action}
69+
color={props.color}
70+
/>
71+
)
72+
}

src/components/video/video.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ import React, { useEffect, useRef, useState } from 'react'
1010

1111
import { formatDurationTime } from '../helper'
1212
import {
13-
FullscreenToggle,
1413
MoveTenSecondsButton,
1514
PausePlayToggle,
16-
PictureInPictureToggle,
1715
ProgressSlider,
1816
TranscriptToggle,
1917
VolumeSettings,
20-
} from '../media/controls/controls'
18+
} from '../media/controls/commonControls'
19+
import {
20+
FullscreenToggle,
21+
PictureInPictureToggle,
22+
} from '../media/controls/videoControls'
2123
import TimeIndicator from '../media/timeIndicator/timeIndicator'
2224
import Transcript from '../media/transcript/transcript'
2325
import type { VideoFormat } from '../types'

0 commit comments

Comments
 (0)