rc-1
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import { forwardRef, useEffect, useId, useImperativeHandle, useRef, useState, type RefObject } from 'react'
|
||||
import VectorIconTop from '../../vectors/top.svg'
|
||||
import './styles/File.css'
|
||||
import type { BackendLimit } from '../../functions/BackendTypes'
|
||||
|
||||
export interface PropsForInputFile {
|
||||
limits: BackendLimit['upload'] | undefined
|
||||
}
|
||||
|
||||
export interface HandleForInputFile {
|
||||
getPreview: () => HTMLVideoElement | HTMLImageElement | undefined
|
||||
getValue: () => File | undefined
|
||||
}
|
||||
|
||||
const InputFile = forwardRef<HandleForInputFile, PropsForInputFile>(({ limits }, ref) => {
|
||||
const componentID = useId()
|
||||
const previewRef = useRef<HTMLVideoElement | HTMLImageElement>(undefined)
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const [fileInstance, setFileInstance] = useState<File>()
|
||||
const [fileObjectURL, setFileObjectURL] = useState<string>()
|
||||
|
||||
function updateInput(file?: File) {
|
||||
if (fileObjectURL) {
|
||||
URL.revokeObjectURL(fileObjectURL)
|
||||
}
|
||||
const accept = file && !!limits?.mime_types.find((t) => file.type === t)
|
||||
if (accept) {
|
||||
setFileObjectURL(URL.createObjectURL(file))
|
||||
setFileInstance(file)
|
||||
} else {
|
||||
setFileObjectURL(undefined)
|
||||
setFileInstance(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
getPreview: () => previewRef.current,
|
||||
getValue: () => fileInstance,
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
fileObjectURL && URL.revokeObjectURL(fileObjectURL)
|
||||
}
|
||||
}, [fileObjectURL])
|
||||
|
||||
return (
|
||||
<div
|
||||
id="input-file"
|
||||
className="input-file"
|
||||
tabIndex={0}
|
||||
onClick={() => inputRef.current?.click()}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
onDrop={(e) => {
|
||||
e.preventDefault()
|
||||
updateInput(e.dataTransfer.files.item(0)!)
|
||||
}}>
|
||||
<input
|
||||
id={componentID}
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
accept={limits?.mime_types ? limits.mime_types.join(',') : '*/*'}
|
||||
onChange={(e) => {
|
||||
e.preventDefault()
|
||||
updateInput(e.target.files?.item(0) ?? undefined)
|
||||
}}
|
||||
/>
|
||||
|
||||
{!fileInstance && (
|
||||
<div className="prompt">
|
||||
<img className="icon animation-fade-in" src={VectorIconTop} />
|
||||
<span className="header animation-scroll-in">DRAG OR CLICK TO UPLOAD A FILE</span>
|
||||
{limits && (
|
||||
<span className="subheader animation-scroll-in">
|
||||
MAX: {limits.video_width_max} × {limits.video_height_max}; SIZE:{' '}
|
||||
{Math.floor(limits.filesize / 1024 / 1024)}MB; DURATION:{' '}
|
||||
{Math.floor(limits.duration / 10) * 10} SECS;
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{fileInstance && (
|
||||
<div className="preview">
|
||||
{fileInstance.type.startsWith('video') && (
|
||||
<video
|
||||
ref={previewRef as RefObject<HTMLVideoElement>}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
src={fileObjectURL}
|
||||
/>
|
||||
)}
|
||||
{fileInstance.type.startsWith('image') && (
|
||||
<img ref={previewRef as RefObject<HTMLImageElement>} src={fileObjectURL} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default InputFile
|
||||
Reference in New Issue
Block a user