/**
* Drag module
* @module drag
*/
/**
* Resets the position and styling of a draggable element.
*
* @param {HTMLElement} interactable - The draggable element to reset.
*/
function resetInteractable(interactable) {
interactable.style.position = "static";
interactable.style.left = null;
interactable.style.top = null;
interactable.style.zIndex = null;
}
/**
* Makes an element draggable, applying custom behavior for dragging and dropping.
*
* @param {HTMLElement} interactable - The element to make draggable.
* @param {function(HTMLElement): boolean} checkDrop - A callback function to check
* if the interactable is dropped in a valid drop zone. Should return `true` if valid.
* @param {function(): boolean} isDraggable - A callback function to determine
* if the element can be dragged. Should return `true` if draggable.
*
* @description
* This function allows an element to be dragged across the screen with the mouse.
* During the drag, the element's style changes for visual feedback (e.g., scaling
* and reduced opacity). The `checkDrop` callback verifies if the drop is valid,
* resetting the element's position if it's not.
*
* @example
* // Make a patch draggable
* makeInteractableDraggable(patchElement, checkDropCallback, () => isDraggable);
*/
export function makeInteractableDraggable(interactable, checkDrop, isDraggable) {
interactable.addEventListener("mousedown", (e) => {
if (isDraggable()) {
let offsetX = e.clientX - interactable.offsetLeft;
let offsetY = e.clientY - interactable.offsetTop;
interactable.style.position = "absolute";
interactable.style.zIndex = "1000";
interactable.style.transition = "none";
interactable.style.transform = "scale(1.2)";
interactable.style.opacity = 0.8;
/**
* Handles the drag movement by updating the element's position.
*
* @param {MouseEvent} e - The mouse move event.
*/
function onMouseMove(e) {
const x = e.clientX - offsetX;
const y = e.clientY - offsetY;
interactable.style.left = `${x}px`;
interactable.style.top = `${y}px`;
}
/**
* Handles the drop event, resetting or finalizing the element's position.
*/
function onMouseUp() {
interactable.style.transition = "all 0.3s ease";
interactable.style.transform = "scale(1)";
interactable.style.opacity = 1;
if (!checkDrop(interactable)) {
resetInteractable(interactable);
}
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
}
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
}
});
}