UNPKG

framer-motion

Version:

A simple and powerful JavaScript animation library

122 lines (119 loc) • 4.87 kB
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