import { isMotionValue, mixNumber, motionValue } from "motion-dom"; import { moveItem } from "motion-utils"; //#region src/components/reorder/utils.ts 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 center = { x: mixNumber(layout.x.min, layout.x.max, .5) + offset.x, y: mixNumber(layout.y.min, layout.y.max, .5) + offset.y }; const lines = getLines(order); const sourceLine = lines.find((line) => line.items.includes(order[index])); const targetLine = lines.reduce((closest, line) => distanceToLine(center.y, line) < distanceToLine(center.y, closest) ? line : closest); if (targetLine !== sourceLine) return moveToLine(order, index, center.x, targetLine, direction); const currentDistance = distanceToBox(center, layout); let target = -1; let targetDistance = currentDistance; order.forEach((item, targetIndex) => { if (targetIndex === index) return; const distance = distanceToBox(center, 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 itemLayout = order[index].layout[axis]; const nextLayout = nextItem.layout[axis]; const nextItemCenter = mixNumber(nextLayout.min, nextLayout.max, .5); if (nextOffset === 1 && itemLayout.max + offset[axis] > nextItemCenter || nextOffset === -1 && itemLayout.min + offset[axis] < nextItemCenter) return moveItem(order, index, index + nextOffset); return order; } 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 center = mixNumber(item.layout.x.min, item.layout.x.max, .5); return direction === "ltr" ? x < center : x > center; }); 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; } var isSeparated = (a, b) => a.max <= b.min || b.max <= a.min; function detectAxis(layouts) { let x = false; let y = false; for (let i = 0; i < layouts.length; i++) for (let j = i + 1; j < layouts.length; j++) { x ||= isSeparated(layouts[i].x, layouts[j].x); y ||= isSeparated(layouts[i].y, layouts[j].y); if (x && y) return "xy"; } return x ? "x" : "y"; } function useDefaultMotionValue(value, defaultValue = 0) { return isMotionValue(value) ? value : motionValue(defaultValue); } //#endregion export { checkReorder, detectAxis, useDefaultMotionValue };