Skip to content

Multiple Lists

Demo

vue
<script lang="ts" setup>
import { createDragDrop } from 'dnd-ts'
import { type TreeNode, moveTreeNodesById } from 'dnd-ts/utils'
import { onMounted, onUnmounted, ref } from 'vue'
import MOCK_TREE from './data/MOCK_TREE.json'

const container = ref(null)
const root = ref<TreeNode<string>>(MOCK_TREE)

onMounted(() => {
  const instance = createDragDrop(container.value!, {
    handleSelector: '[data-id]:not([data-has-children])',
    dragOverThrottle: 10,
    dropPositionFn: ({ dragElement, dropElement }) => {
      const isDropElementParent = dropElement.getAttribute('data-parent-id') === null
      const isOwnChild = dropElement.contains(dragElement)
      return isOwnChild ? 'in' : isDropElementParent ? 'in' : 'around'
    },
    addClasses: true,
    indicator: { offset: 0 },
    autoScroll: true,
    dragImage: { minElements: 1 },
    onDragEnd({ dropElement, dragElements, position }) {
      if (!dropElement)
        return
      const index = Number.parseInt(dropElement.getAttribute('data-index')!)
      const dropElementId = dropElement.getAttribute('data-id')!
      const dropElementParentId = dropElement.getAttribute('data-parent-id') || 'root'
      const selectedIds = dragElements.map(e => e.getAttribute('data-id')!)

      if (position === 'in') {
        moveTreeNodesById(root.value, dropElementId, selectedIds, 0)
      }
      else if (position === 'after') {
        moveTreeNodesById(root.value, dropElementParentId, selectedIds, index + 1)
      }
      else if (position === 'before') {
        moveTreeNodesById(root.value, dropElementParentId, selectedIds, index)
      }
    },
  })

  onUnmounted(() => instance.destroy())
})
</script>

<template>
  <div
    ref="container"
    class="multi-list"
    style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 18px"
  >
    <div
      v-for="row in root.children"
      :key="row.id"
      class="demo"
      style="
        overflow-y: auto;
        box-sizing: border-box;
        max-height: 400px;
        min-height: 150px;
        border-radius: 10px;
        padding: 0;
      "
      :data-id="row.id"
      :data-has-children="row.children.length > 0"
    >
      <ul class="list">
        <li
          v-for="(item, index) in row.children"
          :key="item.id"
          :data-id="item.id"
          :data-index="index"
          :data-parent-id="row.id"
          style="margin: 0; padding: 5px; display: flex"
        >
          <span
            class="list-item"
            style="padding-top: 20px; padding-bottom: 20px; gap: 10px"
          >
            <img src="/handle.svg">
            <span style="">{{ item.data }}</span>
          </span>
        </li>
      </ul>
    </div>
  </div>
</template>