JSFiddle - React, Tailwind, and code Playground

by theodorejb

HTML

<a href="#" id="drag" draggable="true">Drag me</a>

<div id="drop" dropzone="copy">
    <p>
        Text node in child
        <p>Text node in grandchild</p>
    </p>
</div>

CSS

body {
    padding: 5px;
    font-family: Arial, sans-serif;
}
#drag {
    display: inline-block;
    text-decoration: none;
    border: 1px solid gray;
    color: #111;
    background-color: #dfdfdf;
    padding: 8px 14px;
}
#drop {
    margin-top: 10px;
    background-color: #e3e3e3;
    padding: 8px;
}
#drop.over {
    background-color: #d1d1d1;
}
#drop.dragging {
    padding: 18px;
    border: 1px dashed gray;
}
#drop p {
    margin: 10px 0;
}
#drop * {pointer-events: none;}

JavaScript

/*
 * This fiddle demonstrates a technique to prevent dragleave
 * events from firing on parent elements when dragging over
 * their children. Simply set the pointer-events CSS property
 * to none on child elments of the drop target:
 *
 * #dropTarget * {pointer-events: none;}
 * 
 * Note that *all* child nodes must be within a containing
 * element for this to work in Firefox (no text nodes directly
 * inside the drop target).
 *
 * Internet Explorer 8-10 do not support pointer events, so as
 * a fallback event listeners are added to each child node,
 * which add or remove an 'ignore-drag-leave' class from 
 * the drop target. This works because the dragenter event on 
 * child nodes is fired before the dragleave event on the parent.
 *
 * Open your console to view logged events as they are fired.
 * 
 * This technique is tested and working on Chrome 29, Firefox
 * 24, and Internet Explorer 8-11.
 * More information: http://stackoverflow.com/a/18542687/1170489
 */

var drag = document.getElementById('drag');
var drop = document.getElementById('drop');

addEvent(drag, 'dragstart', startDrag);
addEvent(drag, 'dragend', endDrag);

addEvent(drop, 'dragenter', handleDragEnter);
addEvent(drop, 'dragleave', handleDragLeave);
addEvent(drop, 'dragover', handleDragOver);
addEvent(drop, 'drop', handleDrop);

if (!pointerEventsSupport() && drop.hasChildNodes) {
    var children = drop.childNodes;
    for (var i = 0; i < children.length; i++) {
        var node = children[i];
        addEvent(node, 'dragenter', handleChildDragEnter);
        addEvent(node, 'dragleave', handleChildDragLeave);
        console.log('Added event listeners to child node #' + i);
    }
}

function startDrag(e) {
    console.log('Dragging button');
    e.dataTransfer.setData("Text", "my data");
    e.dataTransfer.dropEffect = "copy";
    $(drop).addClass('dragging');
}

function endDrag(e) {
    console.log('Finished dragging button');
    $(drop).removeClass('dragging');
}

function...