|
1 | 1 | <script setup lang="ts"> |
2 | 2 |
|
3 | 3 | import { GripVertical } from "lucide-vue-next"; |
| 4 | +import { useCurrentElement, useEventListener, useMutationObserver } from "@vueuse/core"; |
| 5 | +import { computed, nextTick, onMounted } from "vue"; |
| 6 | +
|
| 7 | +const el = useCurrentElement<HTMLElement>(); |
| 8 | +const nodeViewEl = computed<HTMLElement>(() => el.value?.closest('[data-node-view-wrapper]')); |
| 9 | +
|
| 10 | +useMutationObserver(nodeViewEl, () => { |
| 11 | + if(nodeViewEl.value.draggable && !nodeViewEl.value.hasAttribute('data-dragging-handle')) { |
| 12 | + nodeViewEl.value.removeAttribute('draggable'); |
| 13 | + } |
| 14 | +}, { attributes: true }); |
| 15 | +
|
| 16 | +function onMouseDown(e) { |
| 17 | + nodeViewEl.value.setAttribute('data-dragging-handle', 'true'); |
| 18 | + nodeViewEl.value.draggable = true; |
| 19 | +} |
| 20 | +
|
| 21 | +useEventListener('mouseup', () => { |
| 22 | + if(nodeViewEl.value.hasAttribute('data-dragging-handle')) { |
| 23 | + nodeViewEl.value.removeAttribute('data-dragging-handle'); |
| 24 | + } |
| 25 | +}); |
| 26 | +
|
| 27 | +onMounted(() => { |
| 28 | + nextTick(() => { |
| 29 | + nodeViewEl.value.removeAttribute('draggable'); |
| 30 | + }); |
| 31 | +}); |
| 32 | +
|
| 33 | +useEventListener(nodeViewEl, 'dragstart', (e) => { |
| 34 | + if(!nodeViewEl.value.hasAttribute('data-dragging-handle')) { |
| 35 | + e.preventDefault(); |
| 36 | + } |
| 37 | +}); |
4 | 38 | </script> |
5 | 39 |
|
6 | 40 | <template> |
7 | 41 | <div class="z-5 absolute grid place-content-center opacity-0 right-0 top-1/2 translate-x-1/2 -translate-y-1/2 h-4 w-3 rounded-sm border bg-border duration-300 transition-opacity cursor-grab hover:bg-foreground hover:border-foreground hover:text-background in-[[data-node-view-wrapper]:hover]:opacity-100" |
8 | 42 | data-drag-handle |
| 43 | + @mousedown="onMouseDown" |
9 | 44 | > |
10 | 45 | <div class="absolute -inset-x-2 -inset-y-3"></div> |
11 | 46 | <GripVertical class="h-2.5 w-2.5" /> |
|
0 commit comments