JSFiddle - React, Tailwind, and code Playground
by Vladimir Kutepov
HTML
<ul>
<li class="source">#1 source</li>
<li class="source">#2 source</li>
<li class="source">#3 source</li>
</ul>
<ul>
<li class="target">#4 target</li>
<li class="target">#5 target</li>
<li class="target">#6 target</li>
</ul>
<ul>
<li class="source target">#7 source and target</li>
<li class="source target">#8 source and target</li>
<li class="source target">#9 source and target</li>
</ul>
<button type="button">Destroy</button>
CSS
ul {
background: LightYellow;
padding: 0.5rem 2rem;
}
li {
border: 1px solid Transparent;
}
.dragging {
pointer-events: none;
background: Orange;
}
.highlight {
border-color: Orange;
border-style: dotted;
}
JavaScript
class List {
constructor(el) {
this.el = el;
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.el.addEventListener('mousedown', this.handleMouseDown);
}
handleMouseDown(event) {
const el = event.target;
if (this.el.contains(el) && el.classList.contains('source')) {
event.preventDefault(); // prevent native dnd
this.source = el;
this.startX = event.pageX;
this.startY = event.pageY;
window.addEventListener('mousemove', this.handleMouseMove);
window.addEventListener('mouseup', this.handleMouseUp);
window.addEventListener('mouseover', this.handleMouseOver);
window.addEventListener('mouseout', this.handleMouseOut);
}
}
handleMouseMove(event) {
const offsetX = event.pageX - this.startX;
const offsetY = event.pageY - this.startY;
this.source.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
this.source.classList.add('dragging');
}
handleMouseUp(event) {
window.removeEventListener('mousemove', this.handleMouseMove);
window.removeEventListener('mouseup', this.handleMouseUp);
window.removeEventListener('mouseover', this.handleMouseOver);
window.removeEventListener('mouseout', this.handleMouseOut);
const el = event.target;
if (this.source !== el && el.classList.contains('target')) {
el.parentNode.insertBefore(this.source, el);
el.classList.remove('highlight');
}
this.source.classList.remove('dragging');
this.source.style.transform = '';
this.source = null;
}
handleMouseOver(event) {
const el = event.target;
if (this.source !== el && el.classList.contains('target')) {
el.classList.add('highlight');
}
}
handleMouseOut(event) {
const el = event.target;
el.classList.remove('highlight');
}
destroy() {
window.removeEventListener('mousemove',...