|
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