Drag-drop

by Julien Roche

HTML

<article class="drop-container">
    <div class="drag-item" draggable="false" data-id="id-1">
      <span class="drag-item__icon">Icon</span>
      <span>&nbsp;</span>
      <span>A1</span>
    </div>
    <div class="drag-item" draggable="false" data-id="id-2">
      <span class="drag-item__icon">Icon</span>
      <span>&nbsp;</span>
      <span>A2</span>
    </div>
    <div class="drag-item" draggable="false" data-id="id-3">
      <span class="drag-item__icon">Icon</span>
      <span>&nbsp;</span>
      <span>A3</span>
    </div>
    <div class="drag-item" draggable="false" data-id="id-4">
      <span class="drag-item__icon">Icon</span>
      <span>&nbsp;</span>
      <span>A4</span>
    </div>
</article>

CSS

html,
body {
  height: 100%;
  margin: 0 0 0 0;
  padding: 0 0 0 0;
}

body {
  background-color: grey;
  display: flex;
  margin: 1rem;
}

.drop-container {
  background-color: white;
  flex: 1 1 auto;
  margin: 1rem;
}

.drag-item {
  background-color: orange;
  height: 2rem;
  margin: 1rem;
  user-select: none;

  &.drag-item--drag {
    background-color: aqua;
  }

  &.drag-item--dragenter {
    opacity: 0.25;
  }

  & .drag-item__icon {
    background: red;
    cursor: move;
  }
}

JavaScript

const iconElements = Array.from(document.querySelectorAll('.drag-item__icon'));

iconElements.forEach((element) => {
  const draggableParentElement = element.closest('.drag-item');

  element.addEventListener('pointerenter', () => {
    draggableParentElement.setAttribute('draggable', 'true');
  }, false);

  element.addEventListener('pointerleave', () => {
    draggableParentElement.setAttribute('draggable', 'false');
  }, false);
});

const draggableElements = Array.from(document.querySelectorAll('.drag-item'));

draggableElements.forEach((element) => {
  element.addEventListener('dragstart', (event) => {
    element.classList.add('drag-item--drag');
    event.dataTransfer.setData('text/plain', element.dataset.id);
    event.dataTransfer.dropEffect = 'copy';
    event.dataTransfer.dropEffect = 'copy';
  }, false);

  element.addEventListener('dragend', () => {
    element.classList.remove('drag-item--drag');
    element.classList.remove('drag-item--dragenter');
  }, false);

  element.addEventListener('dragenter', (event) => {
    if (element.classList.contains('drag-item--drag')) {
      return;
    }

    element.classList.add('drag-item--dragenter');
  }, false);

  element.addEventListener('dragleave', (event) => {
    if (element.classList.contains('drag-item--drag')) {
      return;
    }

    element.classList.remove('drag-item--dragenter');
  }, false);

  element.addEventListener('drop', (event) => {
    event.preventDefault();

    const id = event.dataTransfer.getData('text/plain');
    const elementToMove = document.querySelector(`[data-id="${id}"]`)
    element.after(elementToMove);
    element.classList.remove('drag-item--dragenter');
  }, false);
});

const dropContainerElement = document.querySelector('.drop-container')
dropContainerElement.addEventListener('dragover', (event) => {
  event.preventDefault();
}, false);

dropContainerElement.addEventListener('dragleave', (event) => {
 ...