UNPKG

fluid-dnd

Version:

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

122 lines (121 loc) 6.61 kB
import { HORIZONTAL, VERTICAL } from '../..'; import { getAfterMargin, getAxisValue, getBeforeMargin, getBorderBeforeWidthValue, getDistanceValue, getPropByDirection, getRect, getScrollElementValue, getScrollValue, getValueFromProperty } from '../../utils/GetStyles'; import { getBeforeStyles, getGapInfo } from '../../utils/ParseStyles'; const getContentPosition = (direction, droppable) => { const { paddingBefore } = getPropByDirection(direction); const borderBeforeWidthDroppable = getBorderBeforeWidthValue(direction, droppable); const paddingBeforeDroppable = getValueFromProperty(droppable, paddingBefore); const axisValue = getAxisValue(direction, getRect(droppable)); return borderBeforeWidthDroppable + paddingBeforeDroppable + axisValue; }; const getGroupTranslate = (droppable, draggable) => { const [top, left] = getBeforeStyles(draggable); const verticalContentPosition = getContentPosition(VERTICAL, droppable); const horizontalContentPosition = getContentPosition(HORIZONTAL, droppable); return [horizontalContentPosition - left, verticalContentPosition - top]; }; export default function getTranslateBeforeDropping(direction, siblings, sourceIndex, targetIndex, scroll, previousScroll, initialWindowScroll, droppable, draggable) { let height = 0; let width = 0; const isGroupDropping = Boolean(sourceIndex < 0 && draggable); if (sourceIndex === targetIndex && !isGroupDropping) { return addScrollToTranslate({ height, width }, direction, scroll, initialWindowScroll, isGroupDropping); } const [sourceElement, targetElement, siblingsBetween, isDraggedFoward] = getElementsRange(siblings, sourceIndex, targetIndex, draggable); if (isGroupDropping) { const [x, y] = getGroupTranslate(droppable, draggable); height += y; width += x; } const [gap, hasGaps] = getGapInfo(droppable, direction); const [afterMarginOutside, beforeMarginOutside, spaceBeforeDraggedElement] = getBeforeAfterMarginBaseOnDraggedDirection(sourceElement, targetElement?.previousElementSibling, isDraggedFoward, hasGaps, isGroupDropping, direction); const [beforeSpace, space, afterSpace] = spaceWithMargins(siblingsBetween, gap, hasGaps, direction); const spaceBetween = getSpaceBetween(space, beforeSpace, afterSpace, beforeMarginOutside, afterMarginOutside, gap); const [scrollElementValue] = getScrollElementValue(direction, droppable); const scrollChange = isGroupDropping ? scrollElementValue : getScrollChange(droppable, previousScroll, direction); const spaceCalc = isDraggedFoward ? spaceBetween - spaceBeforeDraggedElement : spaceBeforeDraggedElement - spaceBetween; const translate = spaceCalc - scrollChange; if (direction === VERTICAL) { height += translate; } else if (direction === HORIZONTAL) { width += translate; } return addScrollToTranslate({ height, width }, direction, scroll, initialWindowScroll, isGroupDropping); } const getScrollChange = (parentElement, previousScroll, direction) => { const [scrollParent] = getScrollElementValue(direction, parentElement); const [previousScrollValue] = getScrollElementValue(direction, previousScroll); return scrollParent - previousScrollValue; }; const getSpaceBetween = (innerSpace, beforeMarginSpace, afterMarginSpace, beforeMarginOutside, afterMarginOutside, gap) => { const beforeMarginCalc = Math.max(beforeMarginSpace, afterMarginOutside); const afterMarginCalc = Math.max(afterMarginSpace, beforeMarginOutside); return afterMarginCalc + innerSpace + beforeMarginCalc + gap; }; const getElementsRange = (siblings, sourceIndex, targetIndex, draggable) => { const isDraggedFoward = sourceIndex < targetIndex; const [firstIndex, secondIndex] = [sourceIndex, targetIndex].toSorted((a, b) => a - b); const sourceElement = siblings[sourceIndex] ?? draggable; const targetElement = siblings[targetIndex]; let siblingsBetween = isDraggedFoward ? siblings.slice(firstIndex + 1, secondIndex + 1) : siblings.slice(firstIndex, secondIndex); if (firstIndex < 0 && draggable) { siblingsBetween = siblings.slice(firstIndex + 1, secondIndex); } return [sourceElement, targetElement, siblingsBetween, isDraggedFoward]; }; const spaceWithMargins = (siblings, gap, hasGaps, direction) => { if (siblings.length == 0) { return [0, 0, 0]; } const beforeSpace = getAfterMargin(direction, siblings[0]); let afterSpace = 0; let space = -beforeSpace; for (const [index, sibling] of siblings.entries()) { const [siblingSpace] = getDistanceValue(direction, getRect(sibling)); const siblingBeforeMargin = getBeforeMargin(direction, sibling); if (hasGaps) { afterSpace += siblingBeforeMargin; } if (hasGaps && index > 0) { afterSpace += gap; } else { afterSpace = Math.max(afterSpace, siblingBeforeMargin); } space += afterSpace + siblingSpace; afterSpace = getAfterMargin(direction, sibling); } return [beforeSpace, space, afterSpace]; }; const addScrollToTranslate = (translate, direction, initialScroll, initialWindowScroll, isGroupDropping) => { const actualWindowScroll = getScrollValue(direction, window); const initialScrollProp = getScrollValue(direction, initialScroll); const scrollChange = isGroupDropping ? 0 : initialScrollProp - 2 * actualWindowScroll + getScrollValue(direction, initialWindowScroll); const [, distance] = getDistanceValue(direction, translate); translate[distance] += scrollChange; return translate; }; const getBeforeAfterMarginBaseOnDraggedDirection = (draggedElement, previousElement, isDraggedFoward, hasGaps, isGroupDropping, direction) => { const previousElementByDirection = isDraggedFoward ? draggedElement.previousElementSibling : previousElement; return getBeforeAfterMargin(previousElementByDirection, draggedElement, hasGaps, isGroupDropping, direction); }; const getBeforeAfterMargin = (previousElement, nextElement, hasGaps, isGroupDropping, direction) => { if (hasGaps) { return [0, 0, 0]; } const afterMarginValue = getAfterMargin(direction, isGroupDropping ? null : previousElement); const beforeMarginValue = getBeforeMargin(direction, nextElement); let spaceBeforeDraggedElement = Math.max(afterMarginValue, beforeMarginValue); return [afterMarginValue, beforeMarginValue, spaceBeforeDraggedElement]; };