80 lines
2.6 KiB
Vue
80 lines
2.6 KiB
Vue
<template>
|
|
<TreeRoot v-bind="forward" v-slot="{ flattenItems }" class="list-none select-none border border-light-35 dark:border-dark-35 text-light-100 dark:text-dark-100 p-2 xl:text-base text-sm overflow-auto w-[450px] max-h-full">
|
|
<DraggableTreeItem v-for="item in flattenItems" :key="item._id" v-bind="item" class="flex items-center outline-none relative cursor-pointer hover:bg-light-20 dark:hover:bg-dark-20 data-[selected]:bg-light-35 dark:data-[selected]:bg-dark-35" @select.prevent @toggle.prevent>
|
|
<template #default="{ handleToggle, handleSelect, isExpanded, isSelected, isDragging, isDraggedOver }">
|
|
<slot :handleToggle="handleToggle"
|
|
:handleSelect="handleSelect"
|
|
:isExpanded="isExpanded"
|
|
:isSelected="isSelected"
|
|
:isDragging="isDragging"
|
|
:isDraggedOver="isDraggedOver"
|
|
:item="item"
|
|
/>
|
|
</template>
|
|
<template #hint="{ instruction }">
|
|
<div v-if="instruction">
|
|
<slot name="hint" :instruction="instruction" />
|
|
</div>
|
|
</template>
|
|
</DraggableTreeItem>
|
|
</TreeRoot>
|
|
</template>
|
|
|
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
|
import { useForwardPropsEmits, type FlattenedItem, type TreeRootEmits, type TreeRootProps } from 'radix-vue';
|
|
import { type Instruction, extractInstruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item'
|
|
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine'
|
|
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
|
|
|
|
const props = defineProps<TreeRootProps<T>>();
|
|
const emits = defineEmits<TreeRootEmits<T> & {
|
|
'updateTree': [instruction: Instruction, itemId: string, targetId: string];
|
|
}>();
|
|
|
|
defineSlots<{
|
|
default: (props: {
|
|
handleToggle: () => void,
|
|
handleSelect: () => void,
|
|
isExpanded: boolean,
|
|
isSelected: boolean,
|
|
isDragging: boolean,
|
|
isDraggedOver: boolean,
|
|
item: FlattenedItem<T>,
|
|
}) => any,
|
|
hint: (props: {
|
|
instruction: Extract<Instruction, { type: 'reorder-above' | 'reorder-below' | 'make-child' }> | null
|
|
}) => any,
|
|
}>();
|
|
|
|
const forward = useForwardPropsEmits(props, emits);
|
|
|
|
watchEffect((onCleanup) => {
|
|
const dndFunction = combine(
|
|
monitorForElements({
|
|
onDrop(args) {
|
|
const { location, source } = args;
|
|
|
|
if (!location.current.dropTargets.length)
|
|
return;
|
|
|
|
const itemId = source.data.id as string;
|
|
const target = location.current.dropTargets[0];
|
|
const targetId = target.data.id as string;
|
|
|
|
const instruction: Instruction | null = extractInstruction(
|
|
target.data,
|
|
);
|
|
|
|
if (instruction !== null)
|
|
{
|
|
emits('updateTree', instruction, itemId, targetId);
|
|
}
|
|
},
|
|
}),
|
|
)
|
|
|
|
onCleanup(() => {
|
|
dndFunction();
|
|
})
|
|
})
|
|
</script> |