Skip to content

Grid



Sort


TIP

Select multiple items by pressing shift or alt/cmd.

vue
<script lang="ts" setup>
import createDragDropObservable, {
  addClasses,
  autoScroll,
  dragImage,
  indicator,
  reorderItems,
} from 'dndrxjs'

import { onMounted, onUnmounted, ref } from 'vue'
import COLORS from './data/MOCK_DATA_COLORS.json'
import { useSelectStuff } from './select-stuff'
import 'dndrxjs/dist/styles.css'

const items = ref(COLORS.map(hex => ({ id: hex })))
const container = ref<HTMLElement | null>(null)

onMounted(() => {
  const subscription = createDragDropObservable({
    vertical: false,
    container: container.value!,
    dropPositionFn: ({ dragElement, dropElement }) => 'around',
    getSelectedElements: () =>
      Array.from(container.value!.querySelectorAll('.selected')),
  })
    .pipe(
      addClasses(),
      indicator({ offset: 3 }),
      autoScroll(),
      dragImage({ minElements: 1 }),
    )
    .subscribe(({ type, dragElements, dropElement, position }) => {
      if (type === 'DragEnd' && !!dropElement) {
        const selectedItems = dragElements.map(
          e =>
            items.value.find(item => item.id === e.getAttribute('data-id'))!,
        )
        const index = Number.parseInt(dropElement.getAttribute('data-index')!)
        if (position === 'after') {
          items.value = reorderItems(items.value, selectedItems, index + 1)
        }
        else if (position === 'before') {
          items.value = reorderItems(items.value, selectedItems, index)
        }
      }
    })

  const { destroy } = useSelectStuff(container.value!, selected =>
    Array.from(container.value!.querySelectorAll('[data-id]')).forEach(el =>
      !selected.includes(el.getAttribute('data-id')!)
        ? el.classList.remove('selected')
        : el.classList.add('selected'),
    ))
  onUnmounted(() => {
    destroy()
    subscription.unsubscribe()
  })
})
</script>

<template>
  <div class="demo">
    <div
      ref="container"
      style="
        display: grid;
        grid: auto-flow/ repeat(10, 1fr);
        position: relative;
        gap: 6px;
      "
    >
      <div
        v-for="(item, index) in items"
        :key="item.id"
        draggable="false"
        style="
          height: 55px;
          padding: 5px;
          font-size: 11px;
          font-weight: bold;
          line-height: 1.25;
          cursor: grab;
          border-radius: 4px;
          display: flex;
          color: #fff;
          text-align: center;
          align-items: center;
          justify-content: center;
          background: #eee;
        "
        :style="{ background: item.id }"
        :data-index="index"
        :data-id="item.id"
      >
        <span>{{ item.id }}</span>
      </div>
    </div>
  </div>
</template>



Swap


vue
<script lang="ts" setup>
import createDragDropObservable, {
  addClasses,
  autoScroll,
  dragImage,
  indicator,
} from 'dndrxjs'

import { onMounted, onUnmounted, ref } from 'vue'
import { swapElements } from '../src/utils'
import COLORS from './data/MOCK_DATA_COLORS.json'

const items = ref(COLORS.map(hex => ({ id: hex })))
const container = ref<HTMLElement | null>(null)
onMounted(() => {
  const subscription = createDragDropObservable({
    container: container.value!,
    vertical: false,
    dropPositionFn: ({ dragElement, dropElement }) => 'in',
  })
    .pipe(
      addClasses(),
      indicator({ offset: 3 }),
      autoScroll(),
      dragImage({ minElements: 0 }),
    )
    .subscribe(({ type, dragElements, dropElement, position }) => {
      if (type === 'DragEnd' && !!dropElement) {
        const index1 = Number.parseInt(dropElement.getAttribute('data-index')!)
        const index2 = Number.parseInt(dragElements[0].getAttribute('data-index')!)
        if (position === 'in') {
          swapElements(items.value, index1, index2)
        }
      }
    })

  onUnmounted(() => subscription.unsubscribe())
})
</script>

<template>
  <div class="demo">
    <div
      ref="container"
      style="
        display: grid;
        grid: auto-flow/ repeat(10, 1fr);
        position: relative;
        gap: 6px;
      "
    >
      <div
        v-for="(item, index) in items"
        :key="item.id"
        draggable="false"
        style="
          height: 55px;
          padding: 5px;
          font-size: 11px;
          font-weight: bold;
          line-height: 1.25;
          cursor: grab;
          border-radius: 4px;
          display: flex;
          color: #fff;
          text-align: center;
          align-items: center;
          justify-content: center;
          background: #eee;
        "
        :style="{ background: item.id }"
        :data-index="index"
        :data-id="item.id"
      >
        <span>{{ item.id }}</span>
      </div>
    </div>
  </div>
</template>