react-movable
Version:
Drag and drop lists.
122 lines (121 loc) • 3.5 kB
JavaScript
export function arrayMove(array, from, to) {
array = array.slice();
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
return array;
}
export function arrayRemove(array, index) {
array = array.slice();
array.splice(index, 1);
return array;
}
export function getTranslateOffset(element) {
const style = window.getComputedStyle(element);
return (Math.max(parseInt(style["margin-top"], 10), parseInt(style["margin-bottom"], 10)) + element.getBoundingClientRect().height);
}
export function isTouchEvent(event) {
return ((event.touches && event.touches.length) ||
(event.changedTouches && event.changedTouches.length));
}
export function transformItem(element, offsetY = 0, offsetX = 0) {
if (!element)
return;
if (offsetY === null || offsetX === null) {
element.style.removeProperty("transform");
return;
}
element.style.transform =
`translate(${offsetX}px, ${offsetY}px)`;
}
export function isItemTransformed(element) {
return !!element.style.transform;
}
export function setItemTransition(element, duration, timing) {
if (element) {
element.style["transition"] =
`transform ${duration}ms${timing ? ` ${timing}` : ""}`;
}
}
// returns the "slot" for the targetValue, aka where it should go
// in an ordered "array", it starts with -1 index
export function binarySearch(array, targetValue) {
let min = 0;
let max = array.length - 1;
let guess;
while (min <= max) {
guess = Math.floor((max + min) / 2);
if (!array[guess + 1] ||
(array[guess] <= targetValue && array[guess + 1] >= targetValue)) {
return guess;
}
else if (array[guess] < targetValue && array[guess + 1] < targetValue) {
min = guess + 1;
}
else {
max = guess - 1;
}
}
return -1;
}
// adapted from https://github.com/alexreardon/raf-schd
export const schd = (fn) => {
let lastArgs = [];
let frameId = null;
const wrapperFn = (...args) => {
lastArgs = args;
if (frameId) {
return;
}
frameId = requestAnimationFrame(() => {
frameId = null;
fn(...lastArgs);
});
};
wrapperFn.cancel = () => {
if (frameId) {
cancelAnimationFrame(frameId);
}
};
return wrapperFn;
};
export function checkIfInteractive(target, rootElement) {
const DISABLED_ELEMENTS = [
"input",
"textarea",
"select",
"option",
"optgroup",
"video",
"audio",
"button",
"a",
];
const DISABLED_ROLES = [
"button",
"link",
"checkbox",
"radio",
"switch",
"tab",
];
if (!target || !rootElement)
return false;
while (target !== rootElement) {
if (target.getAttribute("data-movable-handle")) {
return false;
}
if (DISABLED_ELEMENTS.includes(target.tagName.toLowerCase())) {
return true;
}
const role = target.getAttribute("role");
if (role && DISABLED_ROLES.includes(role.toLowerCase())) {
return true;
}
if (target.tagName.toLowerCase() === "label" &&
target.hasAttribute("for")) {
return true;
}
if (target.tagName)
target = target.parentElement;
}
return false;
}