mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-06 00:15:32 +00:00
Files dragged into the window from outside now bring up a full-window overlay with large drop zones: attach to a new message and upload to Files, with the open composer first, "Upload to <folder>" on the Files screen, and add to calendar, add to contacts, open or import for .ics, .vcf and .eml files. At most four zones, the one under the pointer highlights, Esc or dragging out cancels, a drop beside the zones does nothing. Drags that start in the app never show it. A file pasted outside a text field gets the same choices as a keyboard dialog. The desktop app used to turn any file dropped on the window into a new draft (lib/desktop/window-files.ts). That handling moved to the overlay, so the "files on the window" tests in os-window.test.tsx went with it: the same cases are now in components/file-drop/__tests__.
36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
/**
|
|
* The overlay's choices without a drag: for files pasted outside a text field, and for a
|
|
* file opened with the desktop app ("Open with" in Explorer, Finder or a file manager).
|
|
* The host shows them as a dialog that works from the keyboard. Requests wait for the
|
|
* host to mount, and the host waits for a sign-in.
|
|
*/
|
|
|
|
import type { FileDropZoneId } from './zones';
|
|
|
|
export interface FileChoiceRequest {
|
|
files: File[];
|
|
/** Where the focus starts, if that choice is there. */
|
|
preferred?: FileDropZoneId;
|
|
}
|
|
|
|
type Listener = (request: FileChoiceRequest) => void;
|
|
|
|
let listener: Listener | null = null;
|
|
const waiting: FileChoiceRequest[] = [];
|
|
|
|
export function requestFileChoice(request: FileChoiceRequest): void {
|
|
if (request.files.length === 0) return;
|
|
if (listener) listener(request);
|
|
else waiting.push(request);
|
|
}
|
|
|
|
/** One host at a time. What came before it mounted is handed over at once. */
|
|
export function listenForFileChoices(next: Listener): () => void {
|
|
listener = next;
|
|
for (const request of waiting.splice(0)) next(request);
|
|
return () => {
|
|
if (listener === next) listener = null;
|
|
};
|
|
}
|
|
|