main
ts 56 lines 2.33 KB
Raw
1 import { DragEvent } from 'react'
2 import { moveFiles } from './clip'
3 import { DirEntry } from './state'
4
5 let entry = '' // dataTransfer.getData is not available onDragOver, so we use this var to keep track
6 let accept = false
7 let classedEl: HTMLElement | undefined
8 const className = 'drop-over'
9
10 export const dragFilesSource = (de: DirEntry) => de.canDelete() ? {
11 draggable: true,
12 onDragStart(ev: DragEvent) {
13 entry = (ev.target as HTMLElement).getAttribute('href') || ''
14 },
15 ...de.canUpload() && dragFilesDestination,
16 } : null
17
18 export const dragFilesDestination = {
19 onDragOver(ev: DragEvent) {
20 if (!accept) return
21 ev.preventDefault()
22 ev.stopPropagation()
23 ev.dataTransfer.dropEffect = 'move' // on most browser this just avoids the "+" icon of the 'copy' operation
24 },
25 onDrop(ev: DragEvent) {
26 classedEl?.classList.remove(className)
27 const el = ev.currentTarget as HTMLElement
28 const src = entry
29 if (!src) return
30 const dst = el.getAttribute('href') || '/'
31 if (src === dst) return
32 ev.preventDefault()
33 void moveFiles([src], dst)
34 },
35 onDragEnter(ev: DragEvent) { // we "accept" here and in dropOver, but this is fired first, so we calculate it here
36 accept = false
37 const src = entry
38 if (!src) return
39 const dst = (ev.currentTarget as HTMLElement).getAttribute('href') || '/'
40 if (src === dst) return
41 accept = true
42 const el = ev.currentTarget as HTMLElement
43 if (el.tagName !== 'A') return
44 classedEl?.classList.remove(className)
45 classedEl = el
46 el.classList.add(className) // manipulating the dom is a risk with react, and would cause problems if React is changing classes in the meantime, but for now this is not the case, so we keep the code simpler
47 },
48 onDragLeave(ev: DragEvent) {
49 if (ev.relatedTarget && ev.currentTarget.contains(ev.relatedTarget as any)) return // with the nested dom (SPAN in A) we can get a second enter before the leave of the previous, and getting the correct behavior was actually empirical: test thoroughly for any change
50 if (!accept) return
51 const el = ev.currentTarget as HTMLElement
52 if (el !== classedEl) return
53 if (el.tagName !== 'A') return
54 classedEl?.classList.remove(className)
55 },
56 }