import type { FC } from '../../../lib/teact/teact'; import React, { memo, useEffect, useRef } from '../../../lib/teact/teact'; import buildClassName from '../../../util/buildClassName'; import captureEscKeyListener from '../../../util/captureEscKeyListener'; import getFilesFromDataTransferItems from './helpers/getFilesFromDataTransferItems'; import useLastCallback from '../../../hooks/useLastCallback'; import usePrevious from '../../../hooks/usePrevious'; import useShowTransition from '../../../hooks/useShowTransition'; import Portal from '../../ui/Portal'; import DropTarget from './DropTarget'; import './DropArea.scss'; export type OwnProps = { isOpen: boolean; withQuick?: boolean; onHide: NoneToVoidFunction; onFileSelect: (files: File[], suggestCompression?: boolean) => void; }; export enum DropAreaState { None = 'none', Document = 'document', QuickFile = 'quick_file', } const DROP_LEAVE_TIMEOUT_MS = 150; const DropArea: FC = ({ isOpen, withQuick, onHide, onFileSelect, }) => { // eslint-disable-next-line no-null/no-null const hideTimeoutRef = useRef(null); const prevWithQuick = usePrevious(withQuick); const { shouldRender, transitionClassNames } = useShowTransition(isOpen); useEffect(() => (isOpen ? captureEscKeyListener(onHide) : undefined), [isOpen, onHide]); const handleFilesDrop = useLastCallback(async (e: React.DragEvent) => { const { dataTransfer: dt } = e; let files: File[] = []; if (dt.files && dt.files.length > 0 && (!dt.items || !dt.items.length)) { files = files.concat(Array.from(dt.files)); } else if (dt.items && dt.items.length > 0) { const folderFiles = await getFilesFromDataTransferItems(dt.items); if (folderFiles?.length) { files = files.concat(folderFiles); } } onHide(); onFileSelect(files, withQuick ? false : undefined); }); const handleQuickFilesDrop = useLastCallback((e: React.DragEvent) => { const { dataTransfer: dt } = e; if (dt.files && dt.files.length > 0) { onHide(); onFileSelect(Array.from(dt.files), true); } }); const handleDragLeave = useLastCallback((e: React.DragEvent) => { e.stopPropagation(); const { target: fromTarget, relatedTarget: toTarget } = e; // Esc button pressed during drag event if ( (fromTarget as HTMLDivElement).matches('.DropTarget, .DropArea') && ( !toTarget || !(toTarget as HTMLDivElement)!.matches('.DropTarget, .DropArea') ) ) { hideTimeoutRef.current = window.setTimeout(() => { onHide(); }, DROP_LEAVE_TIMEOUT_MS); } }); const handleDragOver = () => { if (hideTimeoutRef.current) { window.clearTimeout(hideTimeoutRef.current); } }; if (!shouldRender) { return undefined; } const shouldRenderQuick = withQuick || prevWithQuick; const className = buildClassName( 'DropArea', transitionClassNames, ); return (
{shouldRenderQuick && }
); }; export default memo(DropArea);