Fix drag n drop jank in tier list maker
Some checks failed
E2E Tests / e2e (push) Has been cancelled
Tests and checks on push / run-checks-and-tests (push) Has been cancelled
Updates translation progress / update-translation-progress-issue (push) Has been cancelled

This commit is contained in:
Kalle
2026-09-22 21:54:04 +03:00
parent 6b40e59df6
commit 621555f2ea
4 changed files with 49 additions and 11 deletions

View File

@@ -24,7 +24,7 @@ export function DraggableItem({ item }: DraggableItemProps) {
});
const style = {
transform: CSS.Transform.toString(transform),
transform: CSS.Translate.toString(transform),
transition,
opacity: isDragging ? 0.3 : 1,
};

View File

@@ -1,6 +1,6 @@
import { useDroppable } from "@dnd-kit/core";
import {
horizontalListSortingStrategy,
rectSortingStrategy,
SortableContext,
useSortable,
} from "@dnd-kit/sortable";
@@ -47,9 +47,12 @@ export function TierRow({ tier }: TierRowProps) {
const items = getItemsInTier(tier.id);
const { t } = useTranslation(["tier-list-maker", "common"]);
const { setNodeRef, isOver } = useDroppable({
const { setNodeRef, over } = useDroppable({
id: tier.id,
});
const itemIds = items.map(tierListItemId);
const isOver =
over !== null && (over.id === tier.id || itemIds.includes(String(over.id)));
const combinedRef = useLockedHeightWhileDragging({
setNodeRef,
@@ -193,10 +196,7 @@ export function TierRow({ tier }: TierRowProps) {
: t("tier-list-maker:dropItems")}
</div>
) : items.length > 0 ? (
<SortableContext
items={items.map(tierListItemId)}
strategy={horizontalListSortingStrategy}
>
<SortableContext items={itemIds} strategy={rectSortingStrategy}>
{items.map((item) => (
<DraggableItem key={tierListItemId(item)} item={item} />
))}

View File

@@ -1,4 +1,4 @@
import type { CollisionDetection, Modifier } from "@dnd-kit/core";
import type { ClientRect, CollisionDetection, Modifier } from "@dnd-kit/core";
import {
closestCenter,
DndContext,
@@ -71,9 +71,30 @@ const tierAwareCollisionDetection: CollisionDetection = (args) => {
(tierIdFromSortableId(String(container.id)) !== null) === isTierDrag,
);
return isTierDrag
? closestCenter({ ...args, droppableContainers })
: pointerWithin({ ...args, droppableContainers });
if (isTierDrag) return closestCenter({ ...args, droppableContainers });
const pointerCollisions = pointerWithin({ ...args, droppableContainers });
// gaps between items would otherwise resolve to the tier itself, snapping the sort preview back
const tierZoneCollision = pointerCollisions.find((collision) =>
String(collision.id).startsWith("tier-"),
);
const tierZoneRect = tierZoneCollision
? args.droppableRects.get(tierZoneCollision.id)
: undefined;
if (!tierZoneCollision || !tierZoneRect) return pointerCollisions;
const itemsInTierZone = droppableContainers.filter((container) => {
const rect = args.droppableRects.get(container.id);
return (
container.id !== tierZoneCollision.id &&
rect !== undefined &&
isRectCenterWithin(rect, tierZoneRect)
);
});
if (itemsInTierZone.length === 0) return [tierZoneCollision];
return closestCenter({ ...args, droppableContainers: itemsInTierZone });
};
const restrictTierDragToVerticalAxis: Modifier = (args) =>
@@ -412,3 +433,15 @@ function ResetPopover({ handleReset }: { handleReset: () => void }) {
</SendouPopover>
);
}
function isRectCenterWithin(rect: ClientRect, container: ClientRect) {
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
return (
centerX >= container.left &&
centerX <= container.right &&
centerY >= container.top &&
centerY <= container.bottom
);
}

View File

@@ -0,0 +1,5 @@
---
navItem: tier-list-maker
type: bug
---
Dragging items in tier list maker tiers with multiple rows no longer jumps around or leaves gaps in the preview