react-kanban-kit
Version:
A flexible and customizable Kanban board component for React applications, built with TypeScript and modern drag-and-drop functionality powered by Atlassian's pragmatic-drag-and-drop.
188 lines (187 loc) • 5.84 kB
JavaScript
import { useRef, useState, useCallback, useEffect } from "react";
import { withPrefix } from "../../utils/getPrefix.es.js";
import { dropTargetForElements, draggable } from "../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/adapter/element-adapter.es.js";
import { setCustomNativeDragPreview } from "../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.es.js";
import { preserveOffsetOnSource } from "../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/public-utils/element/custom-native-drag-preview/preserve-offset-on-source.es.js";
import { combine } from "../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/public-utils/combine.es.js";
import { autoScrollForElements } from "../../node_modules/@atlaskit/pragmatic-drag-and-drop-auto-scroll/dist/esm/entry-point/element.es.js";
import { useKanbanContext } from "../../context/KanbanContext.es.js";
const isCardData = (data) => {
return data.type === "card";
};
const isColumnData = (data) => {
return data.type === "column";
};
const idle = {
type: "idle"
};
const useColumnDnd = (data, index, items, onColumnDndStateChange) => {
useKanbanContext();
const headerRef = useRef(null);
const outerFullHeightRef = useRef(null);
const innerRef = useRef(null);
const [state, setState] = useState(idle);
const cardOverShadowCount = state.type === "is-card-over" && !state.isOverChildCard ? 1 : 0;
const totalTasksCount = data.totalChildrenCount + cardOverShadowCount;
const setIsCardOver = useCallback(({
data: data2,
location
}) => {
const innerMost = location.current.dropTargets[0];
const isOverChildCard = Boolean(innerMost == null ? void 0 : innerMost.data["card-drop-target"]);
const proposed = {
type: "is-card-over",
dragging: data2.rect,
isOverChildCard
};
setState(proposed);
}, []);
const handleGenerateDragPreview = useCallback(({
location,
nativeSetDragImage
}) => {
setCustomNativeDragPreview({
nativeSetDragImage,
getOffset: preserveOffsetOnSource({
element: headerRef.current,
input: location.current.input
}),
render({
container
}) {
const rect = innerRef.current.getBoundingClientRect();
const preview = innerRef.current.cloneNode(true);
if (!preview)
return;
preview.style.width = `${rect.width}px`;
preview.style.height = `${rect.height}px`;
preview.style.transform = "rotate(4deg)";
container.appendChild(preview);
}
});
}, []);
const handleDragStart = useCallback(() => {
setState({
type: "is-dragging"
});
}, []);
const handleDrop = useCallback(() => {
setState(idle);
}, []);
const handleDragEnter = useCallback(({
source,
location
}) => {
if (isCardData(source.data)) {
setIsCardOver({
data: source.data,
location
});
return;
}
if (isColumnData(source.data) && source.data.columnId !== data.id) {
setState({
type: "is-column-over"
});
}
}, [data.id, setIsCardOver]);
const handleDropTargetChange = useCallback(({
source,
location
}) => {
if (isCardData(source.data)) {
setIsCardOver({
data: source.data,
location
});
return;
}
}, [setIsCardOver]);
const handleDragLeave = useCallback(({
source
}) => {
if (isColumnData(source.data) && source.data.columnId === data.id) {
return;
}
setState(idle);
}, [data.id]);
const canDrop = useCallback(({
source
}) => {
return source.data.type === "card" || source.data.type === "column";
}, []);
const canScroll = useCallback(({
source
}) => {
return source.data.type === "card";
}, []);
const getConfiguration = useCallback(() => {
return {
maxScrollSpeed: "standard"
};
}, []);
useEffect(() => {
if (!outerFullHeightRef.current || !innerRef.current || !headerRef.current) {
console.warn("not ready");
return;
}
const scroller = outerFullHeightRef.current.querySelector(`.${withPrefix("column-content-list")}`);
const columnData = {
type: "column",
columnId: data.id,
column: data,
index
};
return combine(draggable({
element: headerRef.current,
getInitialData: () => columnData,
onGenerateDragPreview: handleGenerateDragPreview,
onDragStart: handleDragStart,
onDrop: handleDrop,
//TODO: add dnd in columns
canDrag: () => false
}), dropTargetForElements({
element: outerFullHeightRef.current,
getData: () => columnData,
canDrop,
getIsSticky: () => true,
onDragStart: ({
source,
location
}) => {
if (isCardData(source.data)) {
setIsCardOver({
data: source.data,
location
});
}
},
onDragEnter: handleDragEnter,
onDropTargetChange: handleDropTargetChange,
onDragLeave: handleDragLeave,
onDrop: handleDrop
}), autoScrollForElements({
canScroll,
getConfiguration,
element: scroller
}));
}, [data, index, items == null ? void 0 : items.length, handleGenerateDragPreview, handleDragStart, handleDrop, canDrop, setIsCardOver, handleDragEnter, handleDropTargetChange, handleDragLeave, canScroll, getConfiguration]);
useEffect(() => {
onColumnDndStateChange == null ? void 0 : onColumnDndStateChange({
state,
column: data
});
}, [state, onColumnDndStateChange]);
return {
headerRef,
outerFullHeightRef,
innerRef,
state,
cardOverShadowCount,
totalTasksCount
};
};
export {
useColumnDnd
};
//# sourceMappingURL=useColumnDnd.es.js.map