Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@uppy/webcam: refactor to TypeScript #4870

Merged
merged 18 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ module.exports = {
{
files: [
'*.test.js',
'*.test.ts',
'test/endtoend/*.js',
'bin/**.js',
],
Expand Down
9 changes: 0 additions & 9 deletions packages/@uppy/webcam/src/CameraIcon.jsx

This file was deleted.

19 changes: 19 additions & 0 deletions packages/@uppy/webcam/src/CameraIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { h } from 'preact'

export default (): JSX.Element => {
aduh95 marked this conversation as resolved.
Show resolved Hide resolved
return (
<svg
aria-hidden="true"
focusable="false"
fill="#0097DC"
width="66"
height="55"
viewBox="0 0 66 55"
>
<path
d="M57.3 8.433c4.59 0 8.1 3.51 8.1 8.1v29.7c0 4.59-3.51 8.1-8.1 8.1H8.7c-4.59 0-8.1-3.51-8.1-8.1v-29.7c0-4.59 3.51-8.1 8.1-8.1h9.45l4.59-7.02c.54-.54 1.35-1.08 2.16-1.08h16.2c.81 0 1.62.54 2.16 1.08l4.59 7.02h9.45zM33 14.64c-8.62 0-15.393 6.773-15.393 15.393 0 8.62 6.773 15.393 15.393 15.393 8.62 0 15.393-6.773 15.393-15.393 0-8.62-6.773-15.393-15.393-15.393zM33 40c-5.648 0-9.966-4.319-9.966-9.967 0-5.647 4.318-9.966 9.966-9.966s9.966 4.319 9.966 9.966C42.966 35.681 38.648 40 33 40z"
fillRule="evenodd"
/>
</svg>
)
}
119 changes: 0 additions & 119 deletions packages/@uppy/webcam/src/CameraScreen.jsx

This file was deleted.

163 changes: 163 additions & 0 deletions packages/@uppy/webcam/src/CameraScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/* eslint-disable jsx-a11y/media-has-caption */
import type { I18n } from '@uppy/utils/lib/Translator'
import { h, Component } from 'preact'
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<T>(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<CameraScreenProps> {
private videoElement: HTMLVideoElement

refs: any

componentDidMount(): void {
const { onFocus } = this.props
onFocus()
}

componentWillUnmount(): void {
const { onStop } = this.props
onStop()
}

render(): JSX.Element {
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: React.VideoHTMLAttributes<HTMLVideoElement> = {
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 <video> props
videoProps.srcObject = src
}

return (
<div className="uppy uppy-Webcam-container">
<div className="uppy-Webcam-videoContainer">
<video
/* eslint-disable-next-line no-return-assign */
ref={(videoElement) => (this.videoElement = videoElement!)}
className={`uppy-Webcam-video ${
mirror ? 'uppy-Webcam-video--mirrored' : ''
}`}
/* eslint-disable-next-line react/jsx-props-no-spreading */
{...videoProps}
/>
</div>
<div className="uppy-Webcam-footer">
<div className="uppy-Webcam-videoSourceContainer">
{shouldShowVideoSourceDropdown
? VideoSourceSelect(this.props)
: null}
</div>
<div className="uppy-Webcam-buttonContainer">
{shouldShowSnapshotButton && (
<SnapshotButton onSnapshot={onSnapshot} i18n={i18n} />
)}

{shouldShowRecordButton && (
<RecordButton
recording={recording}
onStartRecording={onStartRecording}
onStopRecording={onStopRecording}
i18n={i18n}
/>
)}

{hasRecordedVideo && (
<SubmitButton onSubmit={onSubmit} i18n={i18n} />
)}

{hasRecordedVideo && (
<DiscardButton onDiscard={onDiscardRecordedVideo} i18n={i18n} />
)}
</div>

<div className="uppy-Webcam-recordingLength">
{shouldShowRecordingLength && (
<RecordingLength
recordingLengthSeconds={recordingLengthSeconds}
i18n={i18n}
/>
)}
</div>
</div>
</div>
)
}
}

export default CameraScreen
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import type { I18n } from '@uppy/utils/lib/Translator'
import { h } from 'preact'

function DiscardButton ({ onDiscard, i18n }) {
interface DiscardButtonProps {
onDiscard: () => void
i18n: I18n
}

function DiscardButton({ onDiscard, i18n }: DiscardButtonProps): JSX.Element {
return (
<button
className="uppy-u-reset uppy-c-btn uppy-Webcam-button uppy-Webcam-button--discard"
Expand Down
11 changes: 0 additions & 11 deletions packages/@uppy/webcam/src/PermissionsScreen.jsx

This file was deleted.

28 changes: 28 additions & 0 deletions packages/@uppy/webcam/src/PermissionsScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { I18n } from '@uppy/utils/lib/Translator'
import { h } from 'preact'

interface PermissionScreenProps {
hasCamera: boolean
icon: () => JSX.Element | null
i18n: I18n
}

export default ({
aduh95 marked this conversation as resolved.
Show resolved Hide resolved
icon,
i18n,
hasCamera,
}: PermissionScreenProps): JSX.Element => {
return (
<div className="uppy-Webcam-permissons">
<div className="uppy-Webcam-permissonsIcon">{icon()}</div>
<h1 className="uppy-Webcam-title">
{hasCamera ? i18n('allowAccessTitle') : i18n('noCameraTitle')}
</h1>
<p>
{hasCamera
? i18n('allowAccessDescription')
: i18n('noCameraDescription')}
</p>
</div>
)
}
Loading
Loading