-
Notifications
You must be signed in to change notification settings - Fork 12
/
event.ts
115 lines (102 loc) · 3.57 KB
/
event.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import type { FileDropOptions } from "./options";
import { FileWithPath, fromEvent } from "file-selector";
import { processFiles, Files, isFileWithPath } from "./file";
export interface FileDropEvent {
readonly id?: string;
readonly options: FileDropOptions;
readonly isFileDialogOpen: boolean;
readonly isDraggingFiles: boolean;
}
export interface FileDropDragEvent extends FileDropEvent {
files: File[];
event: DragEvent;
}
export interface FileDropSelectEvent extends FileDropEvent {
files: Files;
event: Event;
method: "drop" | "input";
}
export interface Events {
/**
* one or more files has been selected in the file dialog or drag-and-dropped
*/
filedrop: FileDropSelectEvent;
/**
* a dragenter event has occurred on the container element containnig one or more files
*/
filedragenter: FileDropDragEvent;
/**
* a dragleave event has occurred on the container element containing one or more files
*/
filedragleave: FileDropDragEvent;
/**
* a dragover event has occurred on the container element containing one or more files
*/
filedragover: FileDropDragEvent;
/**
* the file dialog has been canceled without selecting files
*/
filedialogcancel: FileDropEvent;
/**
* the file dialog has been closed with files selected
*/
filedialogclose: FileDropEvent;
/**
* the file dialog has been opened
*/
filedialogopen: FileDropEvent;
/**
* a dragenter event has occurred on the `document`
*
* Note: event is named windowfiledragenter so not to confuse `document` with file
*/
windowfiledragenter: FileDropDragEvent;
/**
* a dragleave event has occurred on the `document`
*
* Note: event is named windowfiledragleave so not to confuse document with file
*/
windowfiledragleave: FileDropDragEvent;
/**
* a dragover event has occurred on the `document`
*
* Note: event is named windowfiledragover so not to confuse document with file
*/
windowfiledragover: FileDropDragEvent;
}
export function isDragEvent(event: Event | DragEvent): event is DragEvent {
return "dataTransfer" in event;
}
type EventWithFiles = Event & { target: { files: File[] } };
export function doesEventTargetHaveFiles(event: Event | EventWithFiles): event is EventWithFiles {
return "files" in event.target;
}
function isTargetHTMLElement(target: EventTarget): target is HTMLElement {
return "tagName" in target;
}
function doesTargetHaveFiles(target: EventTarget): target is HTMLInputElement {
return "files" in target;
}
function isEventTargetHTMLElementInput(ev: InputEvent | Event): ev is Event & { target: HTMLInputElement } {
return isTargetHTMLElement(ev.target) && doesTargetHaveFiles(ev.target);
}
export function isEventWithFiles(ev: Event): boolean {
if (isEventTargetHTMLElementInput(ev)) {
return !!ev.target.files.length;
}
return (
isDragEvent(ev) && ev.dataTransfer.types.some((t) => t === "Files" || t === "application/x-moz-file")
);
}
export async function extractFilesFromEvent(ev: Event): Promise<FileWithPath[]> {
const res = await fromEvent(ev);
const files = res.map((f) => (isFileWithPath(f) ? f : f.getAsFile()));
return files as FileWithPath[];
}
export async function getFilesFromEvent(ev: Event, opts: FileDropOptions): Promise<Files> {
const files = await extractFilesFromEvent(ev);
return processFiles(files, opts);
}
export function isNode(target: EventTarget | Node): target is Node {
return "childNodes" in target;
}