JSFiddle - React, Tailwind, and code Playground

by Alon Rotem

HTML

<div class='menueditor'>
  <ul>
    <li id="d"  class="topmenuitem" draggable='true'>Item 1
      <ul>
        <li class="submenu-placeholder" draggable='true'>Placeholder</li>
      </ul>
    </li>
    <li class="topmenuitem" draggable='true'>Item 2
      <ul>
        <li class="submenu" draggable='true'>menu 2.1</li>
        <li class="submenu" draggable='true'>menu 2.2</li>
      </ul>
    </li>
    <li class="topmenuitem" draggable='true'>Item 3
      <ul>
        <li class="submenu" draggable='true'>menu 3.1</li>
      </ul>
    </li>
  </ul>

  <div id="messag">Nothing is happening</div>
  <!--
<span style='background-color:red; color: white; padding: 5px; ' draggable='true'>SPAN</span>
<span style='background-color:green; color: white; padding: 5px; position:absolute;'>SPAN</span>
</div>
-->

CSS

.menueditor
{
  height:140px;
  /*background-color:yellow;*/
  /*width:40%;*/
}

.topmenuitem
{
  list-style-type: none;
  background-color: red;
  padding: 10px;
  color: white;
  border: 1px solid black;
  
}

.submenu
{
    list-style-type: none;
    background-color: teal;
    padding: 10px;
    border: 1px solid black;
}
.submenu-placeholder
{
    list-style-type: none;
    background-color: yellow;
    color: black;
    padding: 10px;
    border: 1px solid black;  
}


li.drag-sort-active {
  background: transparent;
  color: transparent;
  border: 1px solid #4ca1af;
}

li.drag-sort-active li {
  background: transparent;
  color: transparent;
  border: 0;
}

JavaScript

(() => {
  var sortableLists = document.getElementsByClassName("topmenuitem");
  Array.prototype.map.call(sortableLists, (item) => {
    // 	Array.prototype.map.call(list.children, (item) => {
    item.ondrag = handleDrag;
    item.ondragend = handleDrop;
  });
  
  /*
  document.onmousemove = function(event){
      x = event.clientX;
    	y = event.clientY;
      showMessage(x + ", " + y);
      document.getElementById("d").style.position="absolute";
      document.getElementById("d").style.top = y +"px";
      document.getElementById("d").style.left = x +"px";
  };*/
  //  });
})();

/*
✓ Draggin top menu to another top menu.
Draggin top menu into another submenu (if it has no sub of itself)
Draggin submenu into top menu.
Draggin submenu items among themselves
*/

function handleDrag(item) {

  const selectedItem = item.target,
    list = selectedItem.parentNode,
    x = event.clientX,
    y = event.clientY;

  var itemtype = selectedItem.classList.contains("topmenuitem") ?
    "top item" :
    "submenu";
  

  selectedItem.classList.add('drag-sort-active');
  let swapItem = document.elementFromPoint(x, y) === null ?
    selectedItem :
    document.elementFromPoint(x, y);
    
    var swapitemtype = selectedItem.classList.contains("topmenuitem") ?
    "top item" :
    "submenu";
    showMessage("dragging " + itemtype + " onto "+swapitemtype+"...");

  if (list === swapItem.parentNode) {
    swapItem = swapItem !== selectedItem.nextSibling ?
      swapItem :
      swapItem.nextSibling;
    list.insertBefore(selectedItem, swapItem);
  }
}

function handleDrop(item) {
  showMessage("dropped.");
  item.target.classList.remove('drag-sort-active');
}

function showMessage(text) {
  var container = document.getElementById("messag");
  if (text && container) {
    container.textContent = text;
  }
}