|
8 | 8 | isEvtWithFiles, |
9 | 9 | isIeOrEdge, |
10 | 10 | isPropagationStopped, |
11 | | - onDocumentDragOver, |
12 | | - TOO_MANY_FILES_REJECTION, |
| 11 | + TOO_MANY_FILES_REJECTION |
13 | 12 | } from "./../utils/index"; |
14 | 13 | import { onMount, onDestroy, createEventDispatcher } from "svelte"; |
15 | 14 |
|
|
47 | 46 | isDragReject: false, |
48 | 47 | draggedFiles: [], |
49 | 48 | acceptedFiles: [], |
50 | | - fileRejections: [], |
| 49 | + fileRejections: [] |
51 | 50 | }; |
52 | 51 |
|
53 | 52 | let rootRef; |
|
113 | 112 | dragTargetsRef = [...dragTargetsRef, event.target]; |
114 | 113 |
|
115 | 114 | if (isEvtWithFiles(event)) { |
116 | | - Promise.resolve(getFilesFromEvent(event)).then((draggedFiles) => { |
| 115 | + Promise.resolve(getFilesFromEvent(event)).then(draggedFiles => { |
117 | 116 | if (isPropagationStopped(event) && !noDragEventsBubbling) { |
118 | 117 | return; |
119 | 118 | } |
|
122 | 121 | state.isDragActive = true; |
123 | 122 |
|
124 | 123 | dispatch("dragenter", { |
125 | | - dragEvent: event, |
| 124 | + dragEvent: event |
126 | 125 | }); |
127 | 126 | }); |
128 | 127 | } |
|
140 | 139 |
|
141 | 140 | if (isEvtWithFiles(event)) { |
142 | 141 | dispatch("dragover", { |
143 | | - dragEvent: event, |
| 142 | + dragEvent: event |
144 | 143 | }); |
145 | 144 | } |
146 | 145 |
|
|
153 | 152 |
|
154 | 153 | // Only deactivate once the dropzone and all children have been left |
155 | 154 | const targets = dragTargetsRef.filter( |
156 | | - (target) => rootRef && rootRef.contains(target) |
| 155 | + target => rootRef && rootRef.contains(target) |
157 | 156 | ); |
158 | 157 | // Make sure to remove a target present multiple times only once |
159 | 158 | // (Firefox may fire dragenter/dragleave multiple times on the same element) |
|
171 | 170 |
|
172 | 171 | if (isEvtWithFiles(event)) { |
173 | 172 | dispatch("dragleave", { |
174 | | - dragEvent: event, |
| 173 | + dragEvent: event |
175 | 174 | }); |
176 | 175 | } |
177 | 176 | } |
|
184 | 183 |
|
185 | 184 | if (isEvtWithFiles(event)) { |
186 | 185 | dispatch("filedropped", { |
187 | | - event, |
188 | | - }); |
189 | | - Promise.resolve(getFilesFromEvent(event)).then((files) => { |
| 186 | + event |
| 187 | + }) |
| 188 | + Promise.resolve(getFilesFromEvent(event)).then(files => { |
190 | 189 | if (isPropagationStopped(event) && !noDragEventsBubbling) { |
191 | 190 | return; |
192 | 191 | } |
193 | 192 |
|
194 | 193 | const acceptedFiles = []; |
195 | 194 | const fileRejections = []; |
196 | 195 |
|
197 | | - files.forEach((file) => { |
| 196 | + files.forEach(file => { |
198 | 197 | const [accepted, acceptError] = fileAccepted(file, accept); |
199 | 198 | const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize); |
200 | 199 | if (accepted && sizeMatch) { |
201 | 200 | acceptedFiles.push(file); |
202 | 201 | } else { |
203 | | - const errors = [acceptError, sizeError].filter((e) => e); |
| 202 | + const errors = [acceptError, sizeError].filter(e => e); |
204 | 203 | fileRejections.push({ file, errors }); |
205 | 204 | } |
206 | 205 | }); |
207 | 206 |
|
208 | 207 | if (!multiple && acceptedFiles.length > 1) { |
209 | 208 | // Reject everything and empty accepted files |
210 | | - acceptedFiles.forEach((file) => { |
| 209 | + acceptedFiles.forEach(file => { |
211 | 210 | fileRejections.push({ file, errors: [TOO_MANY_FILES_REJECTION] }); |
212 | 211 | }); |
213 | 212 | acceptedFiles.splice(0); |
|
224 | 223 | dispatch("drop", { |
225 | 224 | acceptedFiles, |
226 | 225 | fileRejections, |
227 | | - event, |
| 226 | + event |
228 | 227 | }); |
229 | 228 |
|
230 | 229 | if (fileRejections.length > 0) { |
231 | 230 | dispatch("droprejected", { |
232 | 231 | fileRejections, |
233 | | - event, |
| 232 | + event |
234 | 233 | }); |
235 | 234 | } |
236 | 235 |
|
237 | 236 | if (acceptedFiles.length > 0) { |
238 | 237 | dispatch("dropaccepted", { |
239 | 238 | acceptedFiles, |
240 | | - event, |
| 239 | + event |
241 | 240 | }); |
242 | 241 | } |
243 | 242 | }); |
|
263 | 262 | } |
264 | 263 | } |
265 | 264 |
|
| 265 | + // allow the entire document to be a drag target |
| 266 | + function onDocumentDragOver(event) { |
| 267 | + if (preventDropOnDocument) { |
| 268 | + event.preventDefault(); |
| 269 | + } |
| 270 | + } |
| 271 | +
|
266 | 272 | let dragTargetsRef = []; |
267 | 273 | function onDocumentDrop(event) { |
| 274 | + if (!preventDropOnDocument) { |
| 275 | + return; |
| 276 | + } |
268 | 277 | if (rootRef && rootRef.contains(event.target)) { |
269 | 278 | // If we intercepted an event for our instance, let it propagate down to the instance's onDrop handler |
270 | 279 | return; |
|
290 | 299 | } |
291 | 300 | } |
292 | 301 |
|
293 | | - onMount(() => { |
294 | | - window.addEventListener("focus", onWindowFocus, false); |
295 | | - if (preventDropOnDocument) { |
296 | | - document.addEventListener("dragover", onDocumentDragOver, false); |
297 | | - document.addEventListener("drop", onDocumentDrop, false); |
298 | | - } |
299 | | - }); |
300 | | -
|
301 | 302 | onDestroy(() => { |
302 | | - window.removeEventListener("focus", onWindowFocus, false); |
303 | | - if (preventDropOnDocument) { |
304 | | - document.removeEventListener("dragover", onDocumentDragOver); |
305 | | - document.removeEventListener("drop", onDocumentDrop); |
306 | | - } |
| 303 | + // This is critical for canceling the timeout behaviour on `onWindowFocus()` |
| 304 | + inputRef = null; |
307 | 305 | }); |
308 | 306 |
|
309 | 307 | function onInputElementClick(event) { |
310 | 308 | event.stopPropagation(); |
311 | 309 | } |
312 | 310 | </script> |
313 | 311 |
|
| 312 | +<style> |
| 313 | + .dropzone { |
| 314 | + flex: 1; |
| 315 | + display: flex; |
| 316 | + flex-direction: column; |
| 317 | + align-items: center; |
| 318 | + padding: 20px; |
| 319 | + border-width: 2px; |
| 320 | + border-radius: 2px; |
| 321 | + border-color: #eeeeee; |
| 322 | + border-style: dashed; |
| 323 | + background-color: #fafafa; |
| 324 | + color: #bdbdbd; |
| 325 | + outline: none; |
| 326 | + transition: border 0.24s ease-in-out; |
| 327 | + } |
| 328 | + .dropzone:focus { |
| 329 | + border-color: #2196f3; |
| 330 | + } |
| 331 | +</style> |
| 332 | +
|
| 333 | +<svelte:window on:focus={onWindowFocus} on:dragover={onDocumentDragOver} on:drop={onDocumentDrop} /> |
| 334 | +
|
314 | 335 | <div |
315 | 336 | bind:this={rootRef} |
316 | 337 | tabindex="0" |
|
324 | 345 | on:dragenter={composeDragHandler(onDragEnterCb)} |
325 | 346 | on:dragover={composeDragHandler(onDragOverCb)} |
326 | 347 | on:dragleave={composeDragHandler(onDragLeaveCb)} |
327 | | - on:drop={composeDragHandler(onDropCb)} |
328 | | -> |
| 348 | + on:drop={composeDragHandler(onDropCb)}> |
329 | 349 | <input |
330 | 350 | {accept} |
331 | 351 | {multiple} |
332 | 352 | {required} |
333 | 353 | type="file" |
334 | | - {name} |
| 354 | + name={name} |
335 | 355 | autocomplete="off" |
336 | 356 | tabindex="-1" |
337 | | - on:blur |
338 | 357 | on:change={onDropCb} |
339 | 358 | on:click={onInputElementClick} |
340 | | - on:invalid |
341 | 359 | bind:this={inputRef} |
342 | | - style="display: none;" |
343 | | - /> |
| 360 | + style="display: none;" /> |
344 | 361 | <slot> |
345 | 362 | <p>Drag 'n' drop some files here, or click to select files</p> |
346 | 363 | </slot> |
347 | 364 | </div> |
348 | | -
|
349 | | -<style> |
350 | | - .dropzone { |
351 | | - flex: 1; |
352 | | - display: flex; |
353 | | - flex-direction: column; |
354 | | - align-items: center; |
355 | | - padding: 20px; |
356 | | - border-width: 2px; |
357 | | - border-radius: 2px; |
358 | | - border-color: #eeeeee; |
359 | | - border-style: dashed; |
360 | | - background-color: #fafafa; |
361 | | - color: #bdbdbd; |
362 | | - outline: none; |
363 | | - transition: border 0.24s ease-in-out; |
364 | | - } |
365 | | - .dropzone:focus { |
366 | | - border-color: #2196f3; |
367 | | - } |
368 | | -</style> |
0 commit comments