export interface WorkspaceFileDragEvent { readonly dataTransfer: { readonly types: ReadonlyArray; readonly files: Iterable; dropEffect: string; }; readonly relatedTarget: EventTarget | null; readonly currentTarget: { contains(target: Node | null): boolean; }; preventDefault(): void; } export interface WorkspaceFileDropHost { setDragActive(active: boolean): void; addFiles(files: File[]): void; } function isFileDrag(event: WorkspaceFileDragEvent): boolean { return event.dataTransfer.types.includes("Files"); } function movedWithinDropTarget(event: WorkspaceFileDragEvent): boolean { return event.relatedTarget !== null && event.currentTarget.contains(event.relatedTarget as Node); } export function makeWorkspaceFileDropHandlers(host: WorkspaceFileDropHost) { return { onDragEnter(event: WorkspaceFileDragEvent) { if (!isFileDrag(event)) return; event.preventDefault(); if (movedWithinDropTarget(event)) return; host.setDragActive(true); }, onDragOver(event: WorkspaceFileDragEvent) { if (!isFileDrag(event)) return; event.preventDefault(); event.dataTransfer.dropEffect = "copy"; host.setDragActive(true); }, onDragLeave(event: WorkspaceFileDragEvent) { if (!isFileDrag(event)) return; event.preventDefault(); if (movedWithinDropTarget(event)) return; host.setDragActive(false); }, onDrop(event: WorkspaceFileDragEvent) { if (!isFileDrag(event)) return; event.preventDefault(); host.setDragActive(false); host.addFiles(Array.from(event.dataTransfer.files)); }, }; }