Fix drag leave event over child elements

When dragging over a child element of the dropzone, a drag leave event from the
dropzone is fired. This caused the handleDragLeave function to be called.

Before the dragLeave event on the dropzone is fired, first a dragEnter event on
the child is fired. By keeping a counter in the state, a premature dragLeave
effect in the dropzone is prevented.

The dragCount is kept in a local variable in handleOnDragLeave because only the
render method gets the most recent state. Reading from state in a regular
function will see an old value (and hence think it is still dragged over even
though the counter dropped to 0).
This commit is contained in:
Armin Friedl 2020-05-22 22:31:19 +02:00
parent 7f4bc536b9
commit aad91c21f6
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8

View file

@ -14,6 +14,7 @@ export default function Upload(props) {
let fileInputRef = useRef(null); let fileInputRef = useRef(null);
let [files, setFiles] = useState([]); let [files, setFiles] = useState([]);
let [dragging, setDragging] = useState(false); let [dragging, setDragging] = useState(false);
let [dragCount, setDragCount] = useState(0);
useEffect(() => { useEffect(() => {
window.addEventListener("dragover",function(e){ window.addEventListener("dragover",function(e){
@ -95,6 +96,7 @@ export default function Upload(props) {
setFiles([...files, ...fileListToArray(evFiles)]); setFiles([...files, ...fileListToArray(evFiles)]);
setDragging(false); setDragging(false);
setDragCount(0);
} }
function fileListToArray(fileList) { function fileListToArray(fileList) {
@ -110,12 +112,19 @@ export default function Upload(props) {
function handleOnDragEnter(ev) { function handleOnDragEnter(ev) {
stopEvent(ev); stopEvent(ev);
setDragging(true); if(dragCount === 0) setDragging(true);
setDragCount(dragCount+1);
} }
function handleOnDragLeave(ev) { function handleOnDragLeave(ev) {
stopEvent(ev); stopEvent(ev);
setDragging(false); let dc = dragCount;
dc -= 1;
setDragCount(dc);
if(dc === 0) setDragging(false);
} }
function stopEvent(ev) { function stopEvent(ev) {
@ -137,22 +146,15 @@ export default function Upload(props) {
if(dragging){ if(dragging){
return( return(
<> <>
<img className="dropzone-icon" alt="dropzone icon" src={drop} <img className="dropzone-icon" alt="dropzone icon" src={drop} />
onDragLeave={stopEvent} /> <h5 className="text-primary">Drop now!</h5>
<h5 className="text-primary"
onDragLeave={stopEvent}>
Drop now!
</h5>
</> </>
); );
}else { }else {
return( return(
<> <>
<img className="dropzone-icon-upload" alt="dropzone icon" src={upload} <img className="dropzone-icon-upload" alt="dropzone icon" src={upload} />
onDragLeave={stopEvent} /> <h5>Click or Drop</h5>
<h5 onDragLeave={stopEvent}>
Click or Drop
</h5>
</> </>
); );
} }
@ -162,17 +164,17 @@ export default function Upload(props) {
<div className="container"> <div className="container">
{logFiles()} {logFiles()}
<div className="columns"> <div className="columns">
<div className="column col-4 col-sm-12" <div className="column col-4 col-sm-12">
onDrop={handleDrop} <div className="dropzone c-hand py-2"
onClick={handleClick} onDrop={handleDrop}
onDragOver={stopEvent} onClick={handleClick}
onDragEnter={handleOnDragEnter} onDragOver={stopEvent}
onDragLeave={handleOnDragLeave}> onDragEnter={handleOnDragEnter}
onDragLeave={handleOnDragLeave}>
<div className="dropzone c-hand py-2" > <input className="d-hide" ref={fileInputRef} type="file" multiple onChange={handleFileInputChange} />
<input className="d-hide" ref={fileInputRef} type="file" multiple
onDragLeave={stopEvent} onChange={handleFileInputChange} />
{zoneContent(dragging)} {zoneContent(dragging)}
</div> </div>
</div> </div>