Skip to content

Multiple Lists

Demo

Demo

vue
<script lang="ts" setup>
import type { TreeNode,
} from 'dndrxjs'
import createDragDropObservable, {
  addClasses,
  autoScroll,
  dragImage,
  indicator,
  moveTreeNodesById,
} from 'dndrxjs'
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 subscription = createDragDropObservable({
    container: 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'
    },
  })
    .pipe(
      addClasses(),
      indicator({ offset: 0 }),
      autoScroll(),
      dragImage({ minElements: 1 }),
    )
    .subscribe(({ type, dropElement, dragElements, position }) => {
      if (!!dropElement && type === 'DragEnd') {
        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(() => subscription.unsubscribe())
})
</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>