UNPKG

fluid-dnd

Version:

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

120 lines (119 loc) 4.51 kB
import ConfigHandler from './configHandler'; import { draggableIsOutside, isSameNode } from '../utils/GetStyles'; import { IsHTMLElement } from '../utils/typesCheckers'; import { setEventWithInterval } from '../utils/SetStyles'; import { getClassesSelector } from '../utils/dom/classList'; const MapConfig = (coreConfig, mapFrom) => { const { config, droppable } = coreConfig; const { onInsertEvent, onDragEnd } = config; const mapOnInsertEvent = (index, value) => { return onInsertEvent(index, mapFrom(value, droppable), true); }; const mapOnDragEnd = (eventData) => { const { index, value } = eventData; onDragEnd({ index, value: mapFrom(value, droppable) }); }; return { ...config, onDragEnd: mapOnDragEnd, onInsertEvent: mapOnInsertEvent }; }; export class DroppableConfigurator { initial; current; parent; draggableElement; groupClass; dragEvent; changeDroppable; mapFrom; constructor(draggableElement, droppableGroupClass, parent, setTransformDragEvent, changeDroppable, mapFrom) { this.parent = parent; this.draggableElement = draggableElement; this.groupClass = droppableGroupClass; this.dragEvent = setTransformDragEvent; this.mapFrom = mapFrom; this.initial = ConfigHandler.getConfig(parent); this.changeDroppable = changeDroppable; } getDraggableAncestor(clientX, clientY, draggable) { return document .elementsFromPoint(clientX, clientY) .filter((element) => !isSameNode(draggable, element)); } getElementBelow(currentElement, event) { const getElementBelow = (config) => { const [elementBelow] = config.getDraggableAncestor(event.clientX, event.clientY, currentElement); return elementBelow; }; return getElementBelow(this); } getCurrent(currentElement, event) { const elementBelow = this.getElementBelow(currentElement, event); if (!this.groupClass || !elementBelow) { return; } const currentDroppable = elementBelow.closest(getClassesSelector(this.groupClass)); return currentDroppable; } isOutsideOfAllDroppables(currentElement) { const droppables = this.groupClass ? Array.from(document.querySelectorAll(getClassesSelector(this.groupClass))) : [this.parent]; return droppables.every((droppable) => draggableIsOutside(currentElement, droppable)); } isNotInsideAnotherDroppable(currentElement, droppable) { const isOutside = draggableIsOutside(currentElement, droppable); return !isOutside || this.isOutsideOfAllDroppables(currentElement); } onScrollEvent() { this.dragEvent(); } setOnScroll(droppable) { setEventWithInterval(droppable, 'onscroll', () => { this.onScrollEvent(); }); } getConfigFrom(element) { const coreConfig = ConfigHandler.getConfig(element); if (!coreConfig) { return undefined; } if (isSameNode(this.parent, element)) { return coreConfig; } return { ...coreConfig, config: MapConfig(coreConfig, this.mapFrom) }; } droppableIfInsideCurrent(droppable, current) { return droppable && !isSameNode(current, droppable) && current.contains(droppable); } getCurrentConfig(event) { const currentElement = this.draggableElement; const currentDroppable = this.getCurrent(currentElement, event); if (this.current && this.isNotInsideAnotherDroppable(currentElement, this.current?.droppable) && !this.droppableIfInsideCurrent(currentDroppable, this.current?.droppable)) { return this.current; } if (!currentDroppable) { return this.getConfigFrom(this.parent); } if (IsHTMLElement(currentDroppable) && !currentDroppable.onscroll) { this.setOnScroll(currentDroppable); } return this.getConfigFrom(currentDroppable); } updateConfig(event) { const oldDroppableConfig = this.current; this.current = this.getCurrentConfig(event); this.changeDroppable(this.current, oldDroppableConfig); } isOutside(event) { const currentElement = this.draggableElement; return !Boolean(this.getCurrent(currentElement, event)); } }