Files
pole-book/server/node_modules/@strapi/content-manager/dist/admin/hooks/useDragAndDrop.mjs

171 lines
6.4 KiB
JavaScript

import * as React from 'react';
import { useDrop, useDrag } from 'react-dnd';
import { useKeyboardDragAndDrop } from './useKeyboardDragAndDrop.mjs';
const DIRECTIONS = {
UPWARD: 'upward',
DOWNWARD: 'downward'
};
const DROP_SENSITIVITY = {
REGULAR: 'regular',
IMMEDIATE: 'immediate'
};
/**
* A utility hook abstracting the general drag and drop hooks from react-dnd.
* Centralising the same behaviours and by default offering keyboard support.
*/ const useDragAndDrop = (active, { type = 'STRAPI_DND', index, item, onStart, onEnd, onGrabItem, onDropItem, onCancel, onMoveItem, dropSensitivity = DROP_SENSITIVITY.REGULAR })=>{
const objectRef = React.useRef(null);
const [{ handlerId, isOver }, dropRef] = useDrop({
accept: type,
collect (monitor) {
return {
handlerId: monitor.getHandlerId(),
isOver: monitor.isOver({
shallow: true
})
};
},
drop (item) {
const draggedIndex = item.index;
const newIndex = index;
if (isOver && onDropItem) {
onDropItem(draggedIndex, newIndex);
}
},
hover (item, monitor) {
if (!objectRef.current || !onMoveItem) {
return;
}
const dragIndex = item.index;
const newIndex = index;
const hoverBoundingRect = objectRef.current?.getBoundingClientRect();
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
const clientOffset = monitor.getClientOffset();
if (!clientOffset) return;
const hoverClientY = clientOffset && clientOffset.y - hoverBoundingRect.top;
if (typeof dragIndex === 'number' && typeof newIndex === 'number') {
if (dragIndex === newIndex) {
// Don't replace items with themselves
return;
}
if (dropSensitivity === DROP_SENSITIVITY.REGULAR) {
// Dragging downwards
if (dragIndex < newIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > newIndex && hoverClientY > hoverMiddleY) {
return;
}
}
// Time to actually perform the action
onMoveItem(newIndex, dragIndex);
item.index = newIndex;
} else {
// Using numbers as indices doesn't work for nested list items with path like [1, 1, 0]
if (Array.isArray(dragIndex) && Array.isArray(newIndex)) {
// Indices comparison to find item position in nested list
const minLength = Math.min(dragIndex.length, newIndex.length);
let areEqual = true;
let isLessThan = false;
let isGreaterThan = false;
for(let i = 0; i < minLength; i++){
if (dragIndex[i] < newIndex[i]) {
isLessThan = true;
areEqual = false;
break;
} else if (dragIndex[i] > newIndex[i]) {
isGreaterThan = true;
areEqual = false;
break;
}
}
// Don't replace items with themselves
if (areEqual && dragIndex.length === newIndex.length) {
return;
}
if (dropSensitivity === DROP_SENSITIVITY.REGULAR) {
// Dragging downwards
if (isLessThan && !isGreaterThan && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (isGreaterThan && !isLessThan && hoverClientY > hoverMiddleY) {
return;
}
}
}
onMoveItem(newIndex, dragIndex);
item.index = newIndex;
}
}
});
const getDragDirection = (monitor)=>{
if (monitor && monitor.isDragging() && !monitor.didDrop() && monitor.getInitialClientOffset() && monitor.getClientOffset()) {
const deltaY = monitor.getInitialClientOffset().y - monitor.getClientOffset().y;
if (deltaY > 0) return DIRECTIONS.UPWARD;
if (deltaY < 0) return DIRECTIONS.DOWNWARD;
return null;
}
return null;
};
const [{ isDragging, direction }, dragRef, dragPreviewRef] = useDrag({
type,
item () {
if (onStart) {
onStart();
}
/**
* This will be attached and it helps define the preview sizes
* when a component is flexy e.g. Relations
*/ const { width } = objectRef.current?.getBoundingClientRect() ?? {};
return {
index,
width,
...item
};
},
end () {
if (onEnd) {
onEnd();
}
},
canDrag: active,
/**
* This is useful when the item is in a virtualized list.
* However, if we don't have an ID then we want the libraries
* defaults to take care of this.
*/ isDragging: item?.id ? (monitor)=>{
return item.id === monitor.getItem().id;
} : undefined,
collect: (monitor)=>({
isDragging: monitor.isDragging(),
initialOffset: monitor.getInitialClientOffset(),
currentOffset: monitor.getClientOffset(),
direction: getDragDirection(monitor)
})
});
const handleKeyDown = useKeyboardDragAndDrop(active, index, {
onGrabItem,
onDropItem,
onCancel,
onMoveItem
});
return [
{
handlerId,
isDragging,
handleKeyDown,
isOverDropTarget: isOver,
direction
},
objectRef,
dropRef,
dragRef,
dragPreviewRef
];
};
export { DIRECTIONS, DROP_SENSITIVITY, useDragAndDrop };
//# sourceMappingURL=useDragAndDrop.mjs.map