JSFiddle - React, Tailwind, and code Playground

by justjohn

HTML

<ul id="list">
    <li>a</li>
    <li>b</li>
    <li>c</li>
    <li>d</li>
</ul>

CSS

#list {
  -moz-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;
  user-select: none;
}

#list, #list li {
  position: relative;
  list-style-type: none;
  padding: 0;
  margin: 0;
  display: block;
}

#list li {
  border: 1px solid black;
  margin: 5px;
  padding: 2px;
  -webkit-transform: translate3d(0, 0, 0);
  z-index: 1;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

#list li.hover {
  background: silver;
}

#list li.down {
  background: red;
}

#list li.dragging {
  visibility: hidden;
}

#list li.preview {
  background: red;
  position: absolute;
  z-index: 10;
  opacity: 0.9;
}

JavaScript

var Draggable = function(target, dragContainer, set) {
  this.el = target;
  this.container = dragContainer;
  this.set = set;
  
  this.on('mousedown', 'mousedown');
  this.on('mouseup',   'mouseup');
  this.on('mouseover', 'mouseover');
  this.on('mouseout',  'mouseout');
  this.on('mousemove', 'mousemove');
};

Draggable.prototype.bindContainer = function() {
  this.container.addEventListener('mousemove', this, false);
  this.container.addEventListener('mouseup', this, false);
};

Draggable.prototype.unbindContainer = function() {
  this.container.removeEventListener('mousemove', this, false);
  this.container.removeEventListener('mouseup', this, false);
};

Draggable.prototype.handleEvent = function(e) {
  // handler for events from the container
  // this is used to bind/unbind on start/end of dragging.
  switch (e.type) {
    case 'mousemove':
      this.dragmove(e);
      break;
      
    case 'mouseup':
      this.dragup(e);
      break;
  }
};

Draggable.prototype.on = function(ev, method, el) {
  var that = this,
      target = el || this.el;
  
  target.addEventListener(ev, function(e){that[method](e);}, false);
};
  
Draggable.prototype.addClass = function(cls, el) {
  var target = el || this.el;
  
  if (target.className.indexOf(cls) < 0)
    target.className = (target.className + " " + cls).trim();
};

Draggable.prototype.removeClass = function(cls, el) {
  var target = el || this.el;
  
  target.className = target.className.replace(cls, "").trim();
};

Draggable.prototype.mousedown = function(e) {
  var button = e.which,
      target = e.target;
  
  if (button == 1) {
    this.down = true;
    this.addClass('down');
    this.bindContainer();
  
    this.start = {
      x: e.x,
      y: e.y + 5
    };
  
    // console.log('mousedown', e);
  }
};

Draggable.prototype.mouseup = function(e) {
  this.down = false;
  this.removeClass('down');
  
  this.start = undefined;
  
  // console.log('mouseup', e);
};

Draggable.prototype.mouseover =...