framer-motion
Version:
A simple and powerful JavaScript animation library
122 lines (119 loc) • 4.87 kB
JavaScript
import { mixNumber } from 'motion-dom';
import { moveItem } from 'motion-utils';
function checkReorder(order, value, offset, velocity, axis, direction = "ltr") {
const index = order.findIndex((item) => item.value === value);
if (index === -1)
return order;
if (axis === "xy") {
const { layout } = order[index];
const point = {
x: center(layout.x) + offset.x,
y: center(layout.y) + offset.y,
};
const lines = getLines(order);
const sourceLine = lines.find((line) => line.items.includes(order[index]));
const targetLine = lines.reduce((closest, line) => distanceToLine(point.y, line) < distanceToLine(point.y, closest)
? line
: closest);
if (targetLine !== sourceLine) {
return moveToLine(order, index, point.x, targetLine, direction);
}
const currentDistance = distanceToBox(point, layout);
let target = -1;
let targetDistance = currentDistance;
order.forEach((item, targetIndex) => {
if (targetIndex === index)
return;
const distance = distanceToBox(point, item.layout);
if (distance < targetDistance) {
target = targetIndex;
targetDistance = distance;
}
});
return target === -1
? order
: moveItem(order, index, index + Math.sign(target - index));
}
if (!velocity[axis])
return order;
const nextOffset = velocity[axis] > 0 ? 1 : -1;
const nextItem = order[index + nextOffset];
if (!nextItem)
return order;
const item = order[index];
const itemLayout = item.layout[axis];
const nextLayout = nextItem.layout[axis];
const nextItemCenter = center(nextLayout);
if ((nextOffset === 1 && itemLayout.max + offset[axis] > nextItemCenter) ||
(nextOffset === -1 && itemLayout.min + offset[axis] < nextItemCenter)) {
return moveItem(order, index, index + nextOffset);
}
return order;
}
/**
* The index a key takes `order[index]` to, or -1 if there's nowhere to go,
* `key` being its index in Up, Left, Down, Right, Home, End. Left and Right
* go along the order (swapped in RTL). On the "xy" axis, Up and Down go to
* the row above or below, to the item there nearest across. Home and End
* go to either end.
*/
function keyTarget(order, index, key, axis, isRTL) {
const step = key > 1 !== !!(key % 2 && isRTL) ? 1 : -1;
let target = key > 3 ? (key - 4) * (order.length - 1) : index + step;
if (axis === "xy" && key < 4 && !(key % 2) && index > -1) {
/**
* Rows top to bottom as drawn, which isn't their order with
* flex-wrap: wrap-reverse.
*/
const lines = getLines(order).sort((a, b) => a.min - b.min);
const line = lines[lines.findIndex(({ items }) => items.includes(order[index])) +
step];
const distance = (item) => Math.abs(center(item.layout.x) - center(order[index].layout.x));
target = line
? order.indexOf(line.items.reduce((nearest, item) => distance(item) < distance(nearest) ? item : nearest))
: -1;
}
return index > -1 && target !== index && order[target] ? target : -1;
}
const center = ({ min, max }) => mixNumber(min, max, 0.5);
function getLines(order) {
const lines = [];
order.forEach((item) => {
const { min, max } = item.layout.y;
const line = lines[lines.length - 1];
if (!line || min >= line.max || max <= line.min) {
lines.push({ items: [item], min, max });
}
else {
line.items.push(item);
line.min = Math.min(line.min, min);
line.max = Math.max(line.max, max);
}
});
return lines;
}
function distanceToLine(y, line) {
return y < line.min ? line.min - y : y > line.max ? y - line.max : 0;
}
function moveToLine(order, index, x, line, direction) {
const remaining = order.filter((_, itemIndex) => itemIndex !== index);
const before = line.items.find((item) => {
const itemCenter = center(item.layout.x);
return direction === "ltr" ? x < itemCenter : x > itemCenter;
});
const targetIndex = before
? remaining.indexOf(before)
: remaining.indexOf(line.items[line.items.length - 1]) + 1;
const nextOrder = [...remaining];
nextOrder.splice(targetIndex, 0, order[index]);
return nextOrder.every((item, itemIndex) => item === order[itemIndex])
? order
: nextOrder;
}
function distanceToBox(point, box) {
const x = Math.max(box.x.min - point.x, 0, point.x - box.x.max);
const y = Math.max(box.y.min - point.y, 0, point.y - box.y.max);
return x * x + y * y;
}
export { checkReorder, keyTarget };
//# sourceMappingURL=check-reorder.mjs.map