import { Download, DownloadDone } from '@mui/icons-material' import clsx from 'clsx' import { CSSProperties, ComponentType, ReactNode, useRef, useState, } from 'react' import toast from 'react-hot-toast' import { useTranslation } from 'react-i18next' import { TransProps } from '@dao-dao/types' import { Loader } from '../logo/Loader' export type FileDropInputProps = { onSelect: (file: File, fileUrl: string) => void | Promise Icon?: ComponentType<{ className: string }> IconHover?: ComponentType<{ className: string }> dropHereText?: string dragHereOrSelect?: ReactNode Trans?: ComponentType className?: string style?: CSSProperties loading?: boolean hideText?: boolean allowedMimetypes?: string[] } export const FileDropInput = ({ onSelect, Icon = Download, IconHover = DownloadDone, dropHereText, dragHereOrSelect, Trans, className, style, loading, hideText, allowedMimetypes, }: FileDropInputProps) => { const { t } = useTranslation() const [dragHovering, setDragHovering] = useState(false) const inputRef = useRef(null) return (
inputRef.current?.click()} onDragEnter={(e) => { e.preventDefault() e.stopPropagation() setDragHovering(true) }} onDragLeave={(e) => { e.preventDefault() e.stopPropagation() setDragHovering(false) }} onDragOver={ // Prevent default behavior which is stopping drop event from firing. We // want to allow dropping. (e) => { e.preventDefault() e.stopPropagation() } } onDrop={(e) => { // Prevent default behavior which is to open the file in the browser. e.preventDefault() e.stopPropagation() setDragHovering(false) // Select file if exists. const file = e.dataTransfer.files?.[0] if (file) { if ( allowedMimetypes?.length && !allowedMimetypes.includes(file.type) ) { toast.error( t('error.invalidFileTypeAllowed', { types: allowedMimetypes.join(', '), }) ) return } onSelect(file, URL.createObjectURL(file)) } }} style={style} > { // Select file if exists, and then unselect so another file can be // selected. const file = e.target.files?.[0] if (file) { // Unselect file. e.target.value = '' if ( allowedMimetypes?.length && !allowedMimetypes.includes(file.type) ) { toast.error( t('error.invalidFileTypeAllowed', { types: allowedMimetypes.join(', '), }) ) return } onSelect(file, URL.createObjectURL(file)) } }} onClick={(e) => { // Don't click on parent which also opens file dialog. e.stopPropagation() }} ref={inputRef} type="file" /> {loading ? (
) : ( !hideText && (
{dragHovering ? ( ) : ( )}

{dragHovering ? dropHereText || t('form.dropFileHere') : dragHereOrSelect || (Trans && ( Drag file here or{' '} click {' '} to select one. ))}

) )}
) }