fluid-dnd
Version:
An agnostic drag and drop library to sort all kind of lists. With current support for vue, react and svelte
108 lines (107 loc) • 4.29 kB
JavaScript
import { VERTICAL } from '.';
import useDroppable from './useDroppable';
import ConfigHandler from './config/configHandler';
import { isTempElement, observeMutation } from './utils/observer';
import { addClass } from './utils/dom/classList';
import { DRAGGABLE_CLASS, DROPPABLE_CLASS } from './utils/classes';
const getConfig = (listCondig, config) => {
const onRemoveAtEvent = (index, sync) => {
return listCondig.removeAtEvent(index, sync);
};
const onInsertEvent = (index, value, sync) => {
return listCondig.insertEvent(index, value, sync);
};
const onGetLegth = () => {
return listCondig.getLength();
};
const onGetValue = (index) => {
return listCondig.getValue(index);
};
const defaultMapFrom = (object) => {
return object;
};
return {
direction: config?.direction ?? VERTICAL,
handlerSelector: config?.handlerSelector ?? DRAGGABLE_CLASS,
draggingClass: config?.draggingClass ?? 'dragging',
droppableClass: config?.droppableClass ?? 'droppable-hover',
isDraggable: config?.isDraggable ?? (() => true),
onDragStart: config?.onDragStart ?? (() => { }),
onDragEnd: config?.onDragEnd ?? (() => { }),
onDragOver: config?.onDragOver ?? (() => { }),
droppableGroup: config?.droppableGroup,
onRemoveAtEvent,
onInsertEvent,
onGetLegth,
onGetValue,
animationDuration: config?.animationDuration ?? 200,
removingClass: config?.removingClass ?? 'removing',
insertingFromClass: config?.insertingFromClass ?? 'from-inserting',
delayBeforeRemove: config?.delayBeforeRemove ?? 200,
delayBeforeInsert: config?.delayBeforeInsert ?? 200,
mapFrom: config?.mapFrom ?? defaultMapFrom,
delayBeforeTouchMoveEvent: config?.delayBeforeTouchMoveEvent ?? 150,
coordinateTransform: config?.coordinateTransform ?? [(coordinate) => coordinate],
};
};
export default function dragAndDrop(listCondig, handlerPublisher, config, indexAttr = 'index') {
let removeAtFromElements = [];
let insertAtFromElements = [];
let currentObserver;
const coreConfig = getConfig(listCondig, config);
const removeAt = (index) => {
for (const removeAtFromElement of removeAtFromElements) {
removeAtFromElement(index);
}
};
const insertAt = (index, value) => {
const listLegth = coreConfig.onGetLegth();
if (listLegth === 0) {
listCondig.insertToListEmpty(coreConfig, index, value);
}
else {
for (const insertAtFromElement of insertAtFromElements) {
insertAtFromElement(index, value);
}
}
};
const makeChildrensDraggable = (parent) => {
const [removeAtFromElementList, insertAtFromElementList] = useDroppable(coreConfig, handlerPublisher, parent, indexAttr);
removeAtFromElements = removeAtFromElementList;
insertAtFromElements = insertAtFromElementList;
};
const childrenMutationFilter = (mutation) => {
const addedNodes = Array.from(mutation.addedNodes ?? [])
.values()
.filter((element) => !isTempElement(element))
.toArray();
const removedNodes = Array.from(mutation.removedNodes ?? [])
.values()
.filter((element) => !isTempElement(element))
.toArray();
return addedNodes.length > 0 || removedNodes.length > 0;
};
const observeChildrens = (parent) => {
currentObserver = observeMutation(() => {
makeChildrensDraggable(parent);
}, parent, { childList: true }, childrenMutationFilter);
};
const makeDroppable = (parent) => {
addClass(parent, DROPPABLE_CLASS);
};
const addConfigHandler = (parent) => {
ConfigHandler.addConfig(parent, coreConfig);
};
const onChangeParent = (parent) => {
if (!parent) {
return;
}
makeDroppable(parent);
addConfigHandler(parent);
observeChildrens(parent);
makeChildrensDraggable(parent);
ConfigHandler.removeObsoleteConfigs();
return currentObserver;
};
return [removeAt, insertAt, onChangeParent];
}