File size: 3,380 Bytes
abcf568 | 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 | import { useEffect, useRef, useState } from 'react'
import type { RefObject } from 'react'
import type { StudioCommandPanelHandle } from '../../components/StudioCommandPanel'
import { countImageItems, extractImageFilesFromDataTransfer } from '../utils/drag-transfer'
interface UsePlotStudioDragOverlayOptions {
commandPanelRef: RefObject<StudioCommandPanelHandle | null>
}
export function usePlotStudioDragOverlay({ commandPanelRef }: UsePlotStudioDragOverlayOptions) {
const [isDraggingImages, setIsDraggingImages] = useState(false)
const dragDepthRef = useRef(0)
const handleShellDragEnter = (event: React.DragEvent<HTMLDivElement>) => {
if (countImageItems(event.dataTransfer) === 0) {
return
}
event.preventDefault()
dragDepthRef.current += 1
setIsDraggingImages(true)
}
const handleShellDragOver = (event: React.DragEvent<HTMLDivElement>) => {
if (countImageItems(event.dataTransfer) === 0) {
return
}
event.preventDefault()
if (!isDraggingImages) {
setIsDraggingImages(true)
}
}
const handleShellDragLeave = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault()
if (event.currentTarget.contains(event.relatedTarget as Node | null)) {
return
}
dragDepthRef.current = Math.max(0, dragDepthRef.current - 1)
if (dragDepthRef.current === 0) {
setIsDraggingImages(false)
}
}
const handleShellDrop = async (event: React.DragEvent<HTMLDivElement>) => {
const imageFiles = extractImageFilesFromDataTransfer(event.dataTransfer)
dragDepthRef.current = 0
if (imageFiles.length === 0) {
setIsDraggingImages(false)
return
}
event.preventDefault()
setIsDraggingImages(false)
await commandPanelRef.current?.ingestImageFiles(imageFiles)
}
useEffect(() => {
const syncWindowDragState = (event: DragEvent) => {
const imageCount = countImageItems(event.dataTransfer)
if (imageCount === 0) {
return
}
if (event.type === 'dragenter' || event.type === 'dragover') {
if (event.type === 'dragenter') {
dragDepthRef.current += 1
}
setIsDraggingImages(true)
return
}
if (event.type === 'dragleave') {
dragDepthRef.current = Math.max(0, dragDepthRef.current - 1)
if (dragDepthRef.current === 0) {
setIsDraggingImages(false)
}
return
}
if (event.type === 'drop') {
dragDepthRef.current = 0
setIsDraggingImages(false)
}
}
window.addEventListener('dragenter', syncWindowDragState)
window.addEventListener('dragover', syncWindowDragState)
window.addEventListener('dragleave', syncWindowDragState)
window.addEventListener('drop', syncWindowDragState)
return () => {
window.removeEventListener('dragenter', syncWindowDragState)
window.removeEventListener('dragover', syncWindowDragState)
window.removeEventListener('dragleave', syncWindowDragState)
window.removeEventListener('drop', syncWindowDragState)
}
}, [])
return {
isDraggingImages,
shellDragBindings: {
onDragEnter: handleShellDragEnter,
onDragOver: handleShellDragOver,
onDragLeave: handleShellDragLeave,
onDrop: (event: React.DragEvent<HTMLDivElement>) => { void handleShellDrop(event) },
},
}
}
|