import { defineComponent, onUnmounted, type PropType, ref } from 'vue'; import type { BCMSNavItemMergeEvent, BCMSNavItemType } from '../../../types'; import BCMSLink from '../../link'; import BCMSIcon from '../../icon'; const component = defineComponent({ props: { item: { type: Object as PropType, required: true }, cyTag: String, draggable: Boolean, isNested: Boolean, }, emits: { merge: (_: BCMSNavItemMergeEvent) => { return true; }, }, setup(props, ctx) { const isExtended = ref(props.item.selected); let itemClicked = false; const isDragging = ref(false); let ghostEle: HTMLElement; function handleDragging(event: MouseEvent) { if (props.draggable) { // event.preventDefault(); itemClicked = true; document.addEventListener('mouseup', handleDrop); document.addEventListener('mousemove', handleMouseMove); const currentTarget = event.currentTarget as HTMLElement; if (currentTarget) { currentTarget.classList.add('nav-dragging'); currentTarget .querySelector('span') ?.classList.add('text-green', 'dark:text-yellow'); } } } function handleMouseMove(event: MouseEvent) { event.preventDefault(); if (ghostEle) { ghostEle.style.left = `${event.clientX}px`; ghostEle.style.top = `${event.clientY}px`; } if (itemClicked) { isDragging.value = true; } } function handleDrop(event: MouseEvent) { event.preventDefault(); if (ghostEle) { document.body.removeChild(ghostEle); } if (itemClicked && isDragging) { // check if we are not dropping item onto itself const dropTargetId = findFirstParent(event.target as HTMLElement); const dropTargetElement = document.querySelector( `[data-drag-id="${dropTargetId}"]`, ); if ( dropTargetElement && dropTargetElement.classList.contains('nav-dragging') ) { const currentNavDragging = document.querySelector('.nav-dragging'); if (currentNavDragging) { currentNavDragging.classList.remove('nav-dragging'); currentNavDragging .querySelector('span') ?.classList.remove('text-green', 'dark:text-yellow'); } document.removeEventListener('mouseup', handleDrop); document.removeEventListener('mousemove', handleMouseMove); return false; } ctx.emit('merge', { src: props.item, targetId: findFirstParent(event.target as HTMLElement), }); } itemClicked = false; isDragging.value = false; const currentNavDragging = document.querySelector('.nav-dragging'); if (currentNavDragging) { currentNavDragging.classList.remove('nav-dragging'); currentNavDragging .querySelector('span') ?.classList.remove('text-green', 'dark:text-yellow'); } document.removeEventListener('mouseup', handleDrop); document.removeEventListener('mousemove', handleMouseMove); } function findFirstParent(target: HTMLElement | undefined): string { if (!target) { return 'root'; } let dragId = target.getAttribute('data-drag-id'); if (dragId) { return dragId; } const parent = target.parentElement as HTMLElement | undefined; if (!parent) { return 'root'; } dragId = target.getAttribute('data-drag-id'); return dragId ? dragId : findFirstParent(parent); } function handleGroupMouseEnter(event: MouseEvent) { const target = event.currentTarget as HTMLElement; const draggingElement = document.querySelector( '.nav-dragging', ) as HTMLElement; if (draggingElement && target.getAttribute('data-nested') === 'true') { isExtended.value = true; target.classList.remove('after:opacity-0'); target.classList.add('after:opacity-100'); } } function handleChildMouseEnter(event: MouseEvent) { const target = event.currentTarget as HTMLElement; const draggingElement = document.querySelector( '.nav-dragging', ) as HTMLElement; const isInsideNest = !!target.closest('[data-nested="true"'); if ( !isInsideNest && draggingElement && target.getAttribute('data-drag-id') !== draggingElement.getAttribute('data-drag-id') && target.getAttribute('data-nested') !== 'true' ) { target.classList.remove('after:opacity-0'); target.classList.add('after:opacity-100'); } } function handleItemMouseLeave(event: MouseEvent) { const target = event.currentTarget as HTMLElement; target.classList.remove('after:opacity-100'); target.classList.add('after:opacity-0'); } function handleGhostStart(event: DragEvent) { event.preventDefault(); const target = event.currentTarget as HTMLElement; ghostEle = document.createElement('div'); ghostEle.classList.add( 'fixed', 'z-1000000', '-translate-x-1/2', '-translate-y-1/2', 'text-sm', 'px-4', 'pt-[5px]', 'pb-1', 'font-semibold', 'bg-[rgba(220,220,220,0.8)]', 'rounded', 'pointer-events-none', 'dark:bg-darkGrey/80', 'dark:text-white', ); ghostEle.innerHTML = target.getAttribute('data-label') || ''; document.body.appendChild(ghostEle); event.dataTransfer?.setDragImage(ghostEle, 0, 0); } onUnmounted(() => { document.removeEventListener('mouseup', handleDrop); document.removeEventListener('mousemove', handleMouseMove); }); return () => ( <> {props.item.type === 'parent' ? (
  • ) : ( <> {props.item.visible && (
  • {typeof props.item.onClick === 'string' ? ( {props.item.name} {props.item.icon && ( )} ) : ( {props.item.name} {props.item.icon && ( )} )}
  • )} )} ); }, }); export default component;