UNPKG

fluid-dnd

Version:

An agnostic drag and drop library to sort all kind of lists. With current support for vue, react and svelte

134 lines (133 loc) 6.35 kB
import { getAxisValue, getBefore, getBeforeMarginValue, getBorderBeforeWidthValue, getDistanceValue, getInnerDistance, getNearestParentPositionWithTranslate, getOffsetValue, getPageValue, getPropByDirection, getRect, getScrollValue, hasTransform, isSameNode } from '../utils/GetStyles'; import { HORIZONTAL, VERTICAL } from '..'; import { useScroll } from './autoScroll'; import { HANDLER_CLASS, DRAGGING_CLASS } from '../utils/classes'; import { containClass } from '../utils/dom/classList'; export const usePositioning = (draggedElement, coordinateTransforms) => { let currentOffset = { offsetX: 0, offsetY: 0 }; let position = { top: 0, left: 0 }; let translate = { x: 0, y: 0 }; const [updateScrollByPosition] = useScroll(draggedElement); const updateTranform = (newTranslate) => { draggedElement.style.transform = `translate( ${newTranslate.x}px, ${newTranslate.y}px)`; }; const updatePosition = (position) => { draggedElement.style.top = `${position.top}px`; draggedElement.style.left = `${position.left}px`; }; const setTransform = (element, parent, pagePosition, direction) => { const getTranslateWihtDirection = (translateDirection) => { const pageValue = getPageValue(translateDirection, pagePosition); const scrollValue = getScrollValue(translateDirection, window); const innerDistance = getInnerDistance(translateDirection, window); const [distanceValue] = getDistanceValue(translateDirection, getRect(element)); const border = getBorderBeforeWidthValue(translateDirection, element); const margin = getBeforeMarginValue(translateDirection, element); const elementPosittion = pageValue - getOffsetValue(translateDirection, currentOffset); const beforefixecParentValue = getNearestParentPositionWithTranslate(element, translateDirection); if (elementPosittion >= scrollValue - distanceValue / 2 && elementPosittion <= scrollValue + innerDistance) { const parentPosition = getParentPosition(translateDirection, parent); const newTranslate = elementPosittion - getBefore(translateDirection, position) - border - margin - scrollValue - beforefixecParentValue - parentPosition; updateScroll(translateDirection); return newTranslate; } const defaultTransalation = getAxisValue(translateDirection, translate); return defaultTransalation; }; const updateScroll = (translateDirection) => { if (element && containClass(element, DRAGGING_CLASS) && translateDirection === direction) { updateScrollByPosition(direction, parent, position, translate); } }; const updateTranlateByDirection = (direction) => { const { axis } = getPropByDirection(direction); translate[axis] = getTranslateWihtDirection(direction); updateTranform(mapCoordinate()); }; updateTranlateByDirection(HORIZONTAL); updateTranlateByDirection(VERTICAL); }; const mapCoordinate = () => { let coordinate = translate; for (const transform of coordinateTransforms) { coordinate = transform(coordinate, draggedElement); } return coordinate; }; const updateTransformState = (event, element) => { const [tempPosition, offset] = getTransformState(event, element, draggedElement); position = tempPosition; updatePosition(position); currentOffset = offset; }; return [setTransform, updateTransformState]; }; const getOffsetWithDraggable = (direction, element, draggable) => { return (getBefore(direction, getRect(element)) - getBefore(direction, getRect(draggable)) - getBorderBeforeWidthValue(direction, draggable)); }; const getOffset = (event, draggable) => { let { offsetX, offsetY, target } = event; let targetHandler = getHandlerElementAncestor(target, draggable); const targetElement = target; if (targetElement && targetHandler && !isSameNode(targetElement, targetHandler)) { offsetX += getOffsetWithDraggable(HORIZONTAL, targetElement, targetHandler); offsetY += getOffsetWithDraggable(VERTICAL, targetElement, targetHandler); } if (targetHandler && draggable != target) { offsetX += getOffsetWithDraggable(HORIZONTAL, targetHandler, draggable); offsetY += getOffsetWithDraggable(VERTICAL, targetHandler, draggable); } return { offsetX, offsetY }; }; const getHandlerElementAncestor = (target, draggable) => { const targetHandler = target?.closest(`.${HANDLER_CLASS}`); if (targetHandler && isSameNode(draggable, targetHandler)) { return target; } return targetHandler; }; const getPositionByDistance = (direction, event, element, offsetEvent) => { const beforefixecParentValue = getNearestParentPositionWithTranslate(element, direction); const parent = element.parentElement; const parentPosition = getParentPosition(direction, parent); return (getPageValue(direction, event) - getOffsetValue(direction, offsetEvent) - getBeforeMarginValue(direction, element) - getBorderBeforeWidthValue(direction, element) - getScrollValue(direction, window) - beforefixecParentValue - parentPosition); }; const getParentPosition = (direction, element) => { return element && hasAncestorTransform(element) ? getBefore(direction, getRect(element)) : 0; }; const hasAncestorTransform = (element) => { let current = element; while (current) { const currentElementHasTransform = hasTransform(current); if (currentElementHasTransform) { return true; } current = current.parentElement; } return false; }; export const getTransformState = (event, element, draggable) => { const offset = getOffset(event, draggable); return [ { top: getPositionByDistance(VERTICAL, event, element, offset), left: getPositionByDistance(HORIZONTAL, event, element, offset) }, offset ]; };