import { BLOCK_FORMATS, DISK_FORMATS, DriveNumber, FLOPPY_FORMATS, MassStorage } from 'js/formats/types'; import { h, JSX, RefObject } from 'preact'; import { useEffect, useRef } from 'preact/hooks'; import { loadLocalFile } from './util/files'; import { spawn } from './util/promises'; export interface DiskDragTargetProps extends JSX.HTMLAttributes { storage: MassStorage | undefined; driveNo?: DriveNumber; formats: typeof FLOPPY_FORMATS | typeof BLOCK_FORMATS | typeof DISK_FORMATS; dropRef?: RefObject; onError: (error: unknown) => void; } export const DiskDragTarget = ({ storage, driveNo, dropRef, formats, onError, children, ...props }: DiskDragTargetProps) => { const ref = useRef(null); useEffect(() => { const div = dropRef?.current || ref.current; if (div) { const onDragOver = (event: DragEvent) => { event.preventDefault(); const dt = event.dataTransfer; if (dt) { if (Array.from(dt.items).every((item) => item.kind === 'file')) { dt.dropEffect = 'copy'; } else { dt.dropEffect = 'none'; } } }; const onDragEnd = (event: DragEvent) => { const dt = event.dataTransfer; if (dt?.items) { for (let i = 0; i < dt.items.length; i++) { dt.items.remove(i); } } else { dt?.clearData(); } }; const onDrop = (event: DragEvent) => { event.preventDefault(); event.stopPropagation(); const targetDrive = driveNo ?? 1; //TODO(whscullin) Maybe pick available drive const dt = event.dataTransfer; if (dt?.files.length === 1 && storage) { spawn(async () => { try { await loadLocalFile(storage, formats, targetDrive, dt.files[0]); } catch (e) { onError(e); } }); } else if (dt?.files.length === 2 && storage) { spawn(async () => { try { await loadLocalFile(storage, formats, 1, dt.files[0]); await loadLocalFile(storage, formats, 2, dt.files[1]); } catch (e) { onError(e); } }); } }; div.addEventListener('dragover', onDragOver); div.addEventListener('dragend', onDragEnd); div.addEventListener('drop', onDrop); return () => { div.removeEventListener('dragover', onDragOver); div.removeEventListener('dragend', onDragEnd); div.removeEventListener('drop', onDrop); }; } }, [driveNo, dropRef, formats, onError, storage]); return (
{children}
); };