@carbon/ibm-products-web-components
Version:
Carbon for IBM Products Web Components
137 lines (134 loc) • 4.64 kB
JavaScript
/**
* Copyright IBM Corp. 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Copyright IBM Corp. 2025, 2025
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Makes a given element draggable using a handle element.
*@param draggable - object which accepts el and optional attributes handle,focusableInHandle,dragStep and shiftDragStep
*/
const makeDraggable = ({ el, dragHandle, focusableDragHandle, dragStep, shiftDragStep, }) => {
if (dragHandle) {
dragHandle.style.cursor = 'move';
el.style.cursor = 'default';
}
else {
el.style.cursor = 'move';
}
let isDragging = false;
let currentX = 0;
let currentY = 0;
let initialMouseX = 0;
let initialMouseY = 0;
const dispatch = (type, detail) => {
const eventInit = {
detail,
bubbles: true,
};
el.dispatchEvent(new CustomEvent(type, eventInit));
};
const onKeyDown = (e) => {
if (e.key === 'Enter') {
isDragging = !isDragging;
}
if (isDragging) {
dispatch('dragstart', { keyboard: true });
}
else {
dispatch('dragend', { keyboard: true });
}
if (!isDragging) {
return;
}
const distance = e.shiftKey ? (shiftDragStep !== null && shiftDragStep !== void 0 ? shiftDragStep : 32) : (dragStep !== null && dragStep !== void 0 ? dragStep : 8);
switch (e.key) {
case 'Enter':
case ' ':
e.preventDefault();
break;
case 'ArrowLeft':
el.style.left = `${el.offsetLeft - distance}px`;
break;
case 'ArrowRight':
el.style.left = `${el.offsetLeft + distance}px`;
break;
case 'ArrowUp':
el.style.top = `${el.offsetTop - distance}px`;
break;
case 'ArrowDown':
el.style.top = `${el.offsetTop + distance}px`;
break;
}
};
const onMouseDown = (e) => {
const target = e.target;
if (!(target instanceof Node)) {
return;
}
const isTargetInHandle = dragHandle
? dragHandle.contains(target)
: el.contains(target);
if (!isTargetInHandle) {
return;
}
const style = window.getComputedStyle(el);
const matrix = new DOMMatrix(style.transform);
currentX = matrix.m41;
currentY = matrix.m42;
// Store the mouse position at the start of the drag
initialMouseX = e.clientX;
initialMouseY = e.clientY;
isDragging = true;
dispatch('dragstart', { mouse: true });
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp, { once: true });
};
const onMouseMove = (e) => {
if (!isDragging) {
return;
}
// Calculate the change in mouse position from the start
const dx = e.clientX - initialMouseX;
const dy = e.clientY - initialMouseY;
// Add that change to the element's original translation
el.style.transform = `translate(${currentX + dx}px, ${currentY + dy}px)`;
};
const onMouseUp = () => {
if (!isDragging) {
return;
}
isDragging = false;
dispatch('dragend', { mouse: true });
document.removeEventListener('mousemove', onMouseMove);
};
if (dragHandle) {
dragHandle.addEventListener('mousedown', onMouseDown);
}
else {
el.addEventListener('mousedown', onMouseDown);
}
focusableDragHandle === null || focusableDragHandle === void 0 ? void 0 : focusableDragHandle.addEventListener('keydown', onKeyDown);
const draggableCleanup = () => {
if (dragHandle) {
dragHandle.removeEventListener('mousedown', onMouseDown);
}
else {
el.removeEventListener('mousedown', onMouseDown);
}
focusableDragHandle === null || focusableDragHandle === void 0 ? void 0 : focusableDragHandle.removeEventListener('keydown', onKeyDown);
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
return {
cleanup: draggableCleanup,
};
};
export { makeDraggable };
//# sourceMappingURL=makeDraggable.js.map