From aefb32533c30cede4aef1fd38bd62df299234346 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 11 Mar 2024 16:30:03 +0200 Subject: [PATCH] @uppy/webcam: refactor to TypeScript (#4870) Co-authored-by: Merlijn Vos --- .eslintrc.js | 1 + packages/@uppy/webcam/src/CameraIcon.jsx | 9 - packages/@uppy/webcam/src/CameraIcon.tsx | 19 + packages/@uppy/webcam/src/CameraScreen.jsx | 119 ----- packages/@uppy/webcam/src/CameraScreen.tsx | 164 +++++++ .../{DiscardButton.jsx => DiscardButton.tsx} | 8 +- .../@uppy/webcam/src/PermissionsScreen.jsx | 11 - .../@uppy/webcam/src/PermissionsScreen.tsx | 28 ++ .../{RecordButton.jsx => RecordButton.tsx} | 33 +- packages/@uppy/webcam/src/RecordingLength.jsx | 12 - packages/@uppy/webcam/src/RecordingLength.tsx | 25 + ...{SnapshotButton.jsx => SnapshotButton.tsx} | 13 +- .../{SubmitButton.jsx => SubmitButton.tsx} | 14 +- .../@uppy/webcam/src/VideoSourceSelect.jsx | 22 - .../@uppy/webcam/src/VideoSourceSelect.tsx | 33 ++ .../src/{Webcam.test.js => Webcam.test.ts} | 44 +- .../webcam/src/{Webcam.jsx => Webcam.tsx} | 459 +++++++++++------- packages/@uppy/webcam/src/formatSeconds.js | 12 - .../@uppy/webcam/src/formatSeconds.test.js | 12 - .../@uppy/webcam/src/formatSeconds.test.ts | 12 + packages/@uppy/webcam/src/formatSeconds.ts | 7 + packages/@uppy/webcam/src/index.js | 1 - packages/@uppy/webcam/src/index.ts | 1 + .../@uppy/webcam/src/{locale.js => locale.ts} | 15 +- .../@uppy/webcam/src/supportsMediaRecorder.js | 6 - ....test.js => supportsMediaRecorder.test.ts} | 14 +- .../@uppy/webcam/src/supportsMediaRecorder.ts | 9 + packages/@uppy/webcam/tsconfig.build.json | 25 + packages/@uppy/webcam/tsconfig.json | 21 + 29 files changed, 747 insertions(+), 402 deletions(-) delete mode 100644 packages/@uppy/webcam/src/CameraIcon.jsx create mode 100644 packages/@uppy/webcam/src/CameraIcon.tsx delete mode 100644 packages/@uppy/webcam/src/CameraScreen.jsx create mode 100644 packages/@uppy/webcam/src/CameraScreen.tsx rename packages/@uppy/webcam/src/{DiscardButton.jsx => DiscardButton.tsx} (79%) delete mode 100644 packages/@uppy/webcam/src/PermissionsScreen.jsx create mode 100644 packages/@uppy/webcam/src/PermissionsScreen.tsx rename packages/@uppy/webcam/src/{RecordButton.jsx => RecordButton.tsx} (52%) delete mode 100644 packages/@uppy/webcam/src/RecordingLength.jsx create mode 100644 packages/@uppy/webcam/src/RecordingLength.tsx rename packages/@uppy/webcam/src/{SnapshotButton.jsx => SnapshotButton.tsx} (55%) rename packages/@uppy/webcam/src/{SubmitButton.jsx => SubmitButton.tsx} (62%) delete mode 100644 packages/@uppy/webcam/src/VideoSourceSelect.jsx create mode 100644 packages/@uppy/webcam/src/VideoSourceSelect.tsx rename packages/@uppy/webcam/src/{Webcam.test.js => Webcam.test.ts} (62%) rename packages/@uppy/webcam/src/{Webcam.jsx => Webcam.tsx} (54%) delete mode 100644 packages/@uppy/webcam/src/formatSeconds.js delete mode 100644 packages/@uppy/webcam/src/formatSeconds.test.js create mode 100644 packages/@uppy/webcam/src/formatSeconds.test.ts create mode 100644 packages/@uppy/webcam/src/formatSeconds.ts delete mode 100644 packages/@uppy/webcam/src/index.js create mode 100644 packages/@uppy/webcam/src/index.ts rename packages/@uppy/webcam/src/{locale.js => locale.ts} (72%) delete mode 100644 packages/@uppy/webcam/src/supportsMediaRecorder.js rename packages/@uppy/webcam/src/{supportsMediaRecorder.test.js => supportsMediaRecorder.test.ts} (61%) create mode 100644 packages/@uppy/webcam/src/supportsMediaRecorder.ts create mode 100644 packages/@uppy/webcam/tsconfig.build.json create mode 100644 packages/@uppy/webcam/tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index 9e749f1436..74c9677e37 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -340,6 +340,7 @@ module.exports = { { files: [ '*.test.js', + '*.test.ts', 'test/endtoend/*.js', 'bin/**.js', ], diff --git a/packages/@uppy/webcam/src/CameraIcon.jsx b/packages/@uppy/webcam/src/CameraIcon.jsx deleted file mode 100644 index add8393463..0000000000 --- a/packages/@uppy/webcam/src/CameraIcon.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import { h } from 'preact' - -export default () => { - return ( - - ) -} diff --git a/packages/@uppy/webcam/src/CameraIcon.tsx b/packages/@uppy/webcam/src/CameraIcon.tsx new file mode 100644 index 0000000000..09084a86b6 --- /dev/null +++ b/packages/@uppy/webcam/src/CameraIcon.tsx @@ -0,0 +1,19 @@ +import { h, type ComponentChild } from 'preact' + +export default function CameraIcon(): ComponentChild { + return ( + + ) +} diff --git a/packages/@uppy/webcam/src/CameraScreen.jsx b/packages/@uppy/webcam/src/CameraScreen.jsx deleted file mode 100644 index 479a67b9c8..0000000000 --- a/packages/@uppy/webcam/src/CameraScreen.jsx +++ /dev/null @@ -1,119 +0,0 @@ -/* eslint-disable jsx-a11y/media-has-caption */ -import { h, Component } from 'preact' -import SnapshotButton from './SnapshotButton.jsx' -import RecordButton from './RecordButton.jsx' -import RecordingLength from './RecordingLength.jsx' -import VideoSourceSelect from './VideoSourceSelect.jsx' -import SubmitButton from './SubmitButton.jsx' -import DiscardButton from './DiscardButton.jsx' - -function isModeAvailable (modes, mode) { - return modes.includes(mode) -} - -class CameraScreen extends Component { - componentDidMount () { - const { onFocus } = this.props - onFocus() - } - - componentWillUnmount () { - const { onStop } = this.props - onStop() - } - - render () { - const { - src, - recordedVideo, - recording, - modes, - supportsRecording, - videoSources, - showVideoSourceDropdown, - showRecordingLength, - onSubmit, - i18n, - mirror, - onSnapshot, - onStartRecording, - onStopRecording, - onDiscardRecordedVideo, - recordingLengthSeconds, - } = this.props - - const hasRecordedVideo = !!recordedVideo - const shouldShowRecordButton = !hasRecordedVideo && supportsRecording && ( - isModeAvailable(modes, 'video-only') - || isModeAvailable(modes, 'audio-only') - || isModeAvailable(modes, 'video-audio') - ) - const shouldShowSnapshotButton = !hasRecordedVideo && isModeAvailable(modes, 'picture') - const shouldShowRecordingLength = supportsRecording && showRecordingLength && !hasRecordedVideo - const shouldShowVideoSourceDropdown = showVideoSourceDropdown && videoSources && videoSources.length > 1 - - const videoProps = { - playsinline: true, - } - - if (recordedVideo) { - videoProps.muted = false - videoProps.controls = true - videoProps.src = recordedVideo - - // reset srcObject in dom. If not resetted, stream sticks in element - if (this.videoElement) { - this.videoElement.srcObject = undefined - } - } else { - videoProps.muted = true - videoProps.autoplay = true - videoProps.srcObject = src - } - - return ( -
-
-
-
-
- {shouldShowVideoSourceDropdown - ? VideoSourceSelect(this.props) - : null} -
-
- {shouldShowSnapshotButton && } - - {shouldShowRecordButton && ( - - )} - - {hasRecordedVideo && } - - {hasRecordedVideo && } -
- -
- {shouldShowRecordingLength && ( - - )} -
-
-
- ) - } -} - -export default CameraScreen diff --git a/packages/@uppy/webcam/src/CameraScreen.tsx b/packages/@uppy/webcam/src/CameraScreen.tsx new file mode 100644 index 0000000000..c7b7cf275e --- /dev/null +++ b/packages/@uppy/webcam/src/CameraScreen.tsx @@ -0,0 +1,164 @@ +/* eslint-disable jsx-a11y/media-has-caption */ +import type { I18n } from '@uppy/utils/lib/Translator' +import { h, Component, type ComponentChild } from 'preact' +import type { HTMLAttributes } from 'preact/compat' +import SnapshotButton from './SnapshotButton.tsx' +import RecordButton from './RecordButton.tsx' +import RecordingLength from './RecordingLength.tsx' +import VideoSourceSelect, { + type VideoSourceSelectProps, +} from './VideoSourceSelect.tsx' +import SubmitButton from './SubmitButton.tsx' +import DiscardButton from './DiscardButton.tsx' + +function isModeAvailable(modes: T[], mode: any): mode is T { + return modes.includes(mode) +} + +interface CameraScreenProps extends VideoSourceSelectProps { + onFocus: () => void + onStop: () => void + + src: MediaStream | null + recording: boolean + modes: string[] + supportsRecording: boolean + showVideoSourceDropdown: boolean + showRecordingLength: boolean + onSubmit: () => void + i18n: I18n + mirror: boolean + onSnapshot: () => void + onStartRecording: () => void + onStopRecording: () => void + onDiscardRecordedVideo: () => void + recordingLengthSeconds: number +} + +class CameraScreen extends Component { + private videoElement: HTMLVideoElement + + refs: any + + componentDidMount(): void { + const { onFocus } = this.props + onFocus() + } + + componentWillUnmount(): void { + const { onStop } = this.props + onStop() + } + + render(): ComponentChild { + const { + src, + // @ts-expect-error TODO: remove unused + recordedVideo, + recording, + modes, + supportsRecording, + videoSources, + showVideoSourceDropdown, + showRecordingLength, + onSubmit, + i18n, + mirror, + onSnapshot, + onStartRecording, + onStopRecording, + onDiscardRecordedVideo, + recordingLengthSeconds, + } = this.props + + const hasRecordedVideo = !!recordedVideo + const shouldShowRecordButton = + !hasRecordedVideo && + supportsRecording && + (isModeAvailable(modes, 'video-only') || + isModeAvailable(modes, 'audio-only') || + isModeAvailable(modes, 'video-audio')) + const shouldShowSnapshotButton = + !hasRecordedVideo && isModeAvailable(modes, 'picture') + const shouldShowRecordingLength = + supportsRecording && showRecordingLength && !hasRecordedVideo + const shouldShowVideoSourceDropdown = + showVideoSourceDropdown && videoSources && videoSources.length > 1 + + const videoProps: HTMLAttributes = { + playsInline: true, + } + + if (recordedVideo) { + videoProps.muted = false + videoProps.controls = true + videoProps.src = recordedVideo + + // reset srcObject in dom. If not resetted, stream sticks in element + if (this.videoElement) { + this.videoElement.srcObject = null + } + } else { + videoProps.muted = true + videoProps.autoPlay = true + // @ts-expect-error srcObject does not exist on