import { useRef } from "react"; import { useDispatch } from "react-redux"; import { createTemplate } from "../template"; import { moveItem } from "../../store/reducers/treeReducer"; import styles from "../Resizable/resizable.module.css"; const getPosi = (x, y, rect, display, direction) => { const xoff = x - rect.x; const yoff = y - rect.y; let xpos = 0, ypos = 0; if (xoff > (rect.width * 20) / 100) xpos = 1; if (xoff > (rect.width * 80) / 100) xpos = 2; if (yoff > (rect.height * 20) / 100) ypos = 1; if (yoff > (rect.height * 80) / 100) ypos = 2; if (display === "block" || ["column", "column-reverse"].includes(direction)) { if (ypos === 0) return "top"; if (ypos === 1) return "inside"; return "bottom"; } else { if (xpos === 0) return "left"; if (xpos === 1) return "inside"; return "right"; } }; export function useDrag({ root }) { const dispatch = useDispatch(); const draggedNodeRef = useRef(null); const draggedWrapperRef = useRef(null); const handleDragStart = (e) => { e.stopPropagation(); if (!e.target.getAttribute("data-id")) return; draggedNodeRef.current = e.target; let draggedWrapper = document.createElement("div"); let draggedImage = document.createElement("div"); draggedWrapper.classList.add(styles.dragwrapper); draggedImage.classList.add(styles.dragimage); draggedImage.innerText = e.target.parentNode.children[0].innerText; draggedWrapper.appendChild(draggedImage); document.body.appendChild(draggedWrapper); e.dataTransfer.setDragImage(draggedImage, -20, -20); draggedWrapperRef.current = draggedWrapper; }; const handleDragEnd = () => { draggedNodeRef.current = null; if (draggedWrapperRef && draggedWrapperRef.current) draggedWrapperRef.current.remove(); draggedWrapperRef.current = null; }; const handleDragOver = (e) => { e.preventDefault(); e.stopPropagation(); const targetId = e.target.getAttribute("data-target") || e.target.getAttribute("data-root"); const draggedId = draggedNodeRef.current?.getAttribute("data-id"); if (!targetId || draggedId == targetId) return; if (targetId == root) { } else { let aParent = e.target.parentNode?.parentNode; if (e.target.getAttribute("data-target")) aParent = aParent?.parentNode; if (!aParent) return; const display = aParent.style.display || "block"; const direction = aParent.style.flexDirection || "row"; e.target.classList.add(styles.dborder); const rect = e.target.getBoundingClientRect(); switch (getPosi(e.clientX, e.clientY, rect, display, direction)) { case "inside": e.target.classList.remove( styles.dtop, styles.dbottom, styles.dleft, styles.dright ); e.target.classList.add(styles.dinside); break; case "top": e.target.classList.remove( styles.dinside, styles.dbottom, styles.dleft, styles.dright ); e.target.classList.add(styles.dtop); break; case "right": e.target.classList.remove( styles.dinside, styles.dtop, styles.dbottom, styles.dleft ); e.target.classList.add(styles.dright); break; case "bottom": e.target.classList.remove( styles.dinside, styles.dtop, styles.dleft, styles.dright ); e.target.classList.add(styles.dbottom); break; case "left": e.target.classList.remove( styles.dinside, styles.dtop, styles.dbottom, styles.dright ); e.target.classList.add(styles.dleft); break; default: break; } } }; const handleDrop = (e) => { e.stopPropagation(); e.target.classList.remove( styles.dborder, styles.dinside, styles.dtop, styles.dbottom, styles.dleft, styles.dright ); const targetId = e.target.getAttribute("data-target") || e.target.getAttribute("data-root"); const draggedId = draggedNodeRef.current?.getAttribute("data-id") || createTemplate({ type: e.dataTransfer.getData("type"), dispatch }); if (!targetId || !draggedId || draggedId == targetId) return; if (targetId == root) { dispatch(moveItem({ node: draggedId, referenceNode: targetId, pos: -1 })); } else { let aParent = e.target.parentNode?.parentNode; if (e.target.getAttribute("data-target")) aParent = aParent?.parentNode; if (!aParent) return; const display = aParent.style.display || "block"; const direction = aParent.style.flexDirection || "row"; const rect = e.target.getBoundingClientRect(); switch (getPosi(e.clientX, e.clientY, rect, display, direction)) { case "inside": dispatch( moveItem({ node: draggedId, referenceNode: targetId, pos: -1 }) ); break; case "top": dispatch( moveItem({ node: draggedId, referenceNode: targetId, pos: 0 }) ); break; case "right": dispatch( moveItem({ node: draggedId, referenceNode: targetId, pos: 1 }) ); break; case "bottom": dispatch( moveItem({ node: draggedId, referenceNode: targetId, pos: 1 }) ); break; case "left": dispatch( moveItem({ node: draggedId, referenceNode: targetId, pos: 0 }) ); break; default: break; } } draggedNodeRef.current = null; if (draggedWrapperRef && draggedWrapperRef.current) draggedWrapperRef.current.remove(); draggedWrapperRef.current = null; }; const handleDragLeave = (e) => { e.target.classList.remove( styles.dborder, styles.dinside, styles.dtop, styles.dbottom, styles.dleft, styles.dright ); }; return { handleDragStart, handleDragEnd, handleDragOver, handleDrop, handleDragLeave, }; }