ar-design
Version:
AR Design is a (react | nextjs) ui library.
126 lines (125 loc) • 6.16 kB
JavaScript
"use client";
import React, { useEffect, useRef } from "react";
import "../../../assets/css/components/data-display/dnd/styles.css";
import { ARIcon } from "../../icons";
let _fromColumn = undefined;
const DnD = function ({ data, renderItem, columnKey, onChange, confing = { isMoveIcon: true } }) {
// refs
const _arDnD = useRef(null);
const _dragItem = useRef(null);
// useEffects
useEffect(() => {
if (!_arDnD.current || data.length === 0)
return;
_arDnD.current.childNodes.forEach((item) => {
const _item = item;
// Events
_item.ondragstart = (event) => {
const dragItem = event.currentTarget;
_dragItem.current = dragItem;
dragItem.classList.add("drag-item");
const index = [..._arDnD.current.children].indexOf(dragItem);
const draggedData = data[index];
if (event.dataTransfer) {
// #region Shadow
const shadow = document.createElement("div");
shadow.innerHTML = `
<div class="ar-dnd-shadow">
<i class="bi bi-gear-wide-connected"></i>
<span>Dragging...</span>
</div>
`;
shadow.style.position = "absolute";
shadow.style.top = "-9999px";
document.body.appendChild(shadow);
event.dataTransfer.setDragImage(shadow, 0, 0);
// #endregion
event.dataTransfer.setData("item", JSON.stringify(draggedData));
event.dataTransfer.setData("fromColumn", columnKey ?? "");
_fromColumn = columnKey ?? undefined;
}
// Korumaya başla.
if (_arDnD.current && columnKey && _fromColumn !== columnKey) {
_arDnD.current.childNodes.forEach((item) => {
const placeholder = document.createElement("div");
placeholder.setAttribute("data-id", "placeholder");
placeholder.style.position = "absolute";
placeholder.style.inset = "0";
item.appendChild(placeholder);
});
}
};
_item.ondragover = (event) => {
event.preventDefault();
const overItem = event.currentTarget;
const rect = overItem.getBoundingClientRect();
// Otomatik scroll.
if (rect.top < 250)
window.scrollBy(0, -20);
if (rect.bottom > window.innerHeight - 150)
window.scrollBy(0, 20);
// Sadece aynı kolondaysa drag-drop yap.
if (columnKey && _fromColumn !== columnKey) {
// Placeholder'ı temizle
const nodes = document.querySelectorAll("[data-id='placeholder']");
nodes.forEach((node) => node.remove());
// Placeholder element oluştur.
const placeholder = document.createElement("div");
placeholder.setAttribute("data-id", "placeholder");
placeholder.classList.add("placeholder");
// Fare pozisyonuna göre yerleştir.
const isBelow = event.clientY > rect.top + rect.height / 2;
if (isBelow) {
overItem.parentNode?.insertBefore(placeholder, overItem.nextSibling);
}
else {
overItem.parentNode?.insertBefore(placeholder, overItem);
}
return; // taşıma yapma ama placeholder gösterilsin.
}
// Gerçek taşıma işlemi.
if (_dragItem.current !== overItem) {
if (_arDnD.current && _dragItem.current) {
const dragItemIndex = [..._arDnD.current.children].indexOf(_dragItem.current);
const dropItemIndex = [..._arDnD.current.children].indexOf(overItem);
if (dragItemIndex === -1 || dropItemIndex === -1)
return;
_arDnD.current.insertBefore(_dragItem.current, dragItemIndex < dropItemIndex ? overItem.nextSibling : overItem);
const movedItem = data.splice(dragItemIndex, 1)[0];
if (movedItem) {
data.splice(dropItemIndex, 0, movedItem);
onChange?.(data);
}
}
}
};
_item.ondragend = (event) => {
const item = event.currentTarget;
item.classList.remove("drag-item");
item.classList.add("end-item");
setTimeout(() => {
item.classList.remove("end-item");
if (item.classList.length === 0)
item.removeAttribute("class");
}, 1000);
};
});
_arDnD.current.ondragover = (event) => event.preventDefault();
return () => {
if (!_arDnD.current)
return;
_arDnD.current.childNodes.forEach((item) => {
const _item = item;
_item.ondragstart = null;
_item.ondragover = null;
_item.ondragend = null;
});
_arDnD.current.ondragover = null;
};
}, [data]);
return (React.createElement("div", { ref: _arDnD, className: "ar-dnd" }, data.map((item, index) => (React.createElement("div", { key: index, className: "item", draggable: true },
confing?.isMoveIcon && (React.createElement("div", { className: "move" },
React.createElement(ARIcon, { icon: "GripVertical", fill: "var(--blue-500)", size: 18 }))),
React.createElement("div", { className: "content" }, renderItem(item, index)))))));
};
export default DnD;