UNPKG

@carbon/ibm-products-web-components

Version:
137 lines (134 loc) 4.64 kB
/** * 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