From 621555f2ea6d9e53cf64c7606323d26d21156ae2 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Tue, 22 Sep 2026 21:54:04 +0300 Subject: [PATCH] Fix drag n drop jank in tier list maker --- .../components/DraggableItem.tsx | 2 +- .../tier-list-maker/components/TierRow.tsx | 12 +++--- .../routes/tier-list-maker.tsx | 41 +++++++++++++++++-- ...2026-09-22-tier-list-maker-drag-preview.md | 5 +++ 4 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 changelog/2026-09-22-tier-list-maker-drag-preview.md diff --git a/app/features/tier-list-maker/components/DraggableItem.tsx b/app/features/tier-list-maker/components/DraggableItem.tsx index d32aa6b50..93c81bace 100644 --- a/app/features/tier-list-maker/components/DraggableItem.tsx +++ b/app/features/tier-list-maker/components/DraggableItem.tsx @@ -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, }; diff --git a/app/features/tier-list-maker/components/TierRow.tsx b/app/features/tier-list-maker/components/TierRow.tsx index 912a310a7..991ba8906 100644 --- a/app/features/tier-list-maker/components/TierRow.tsx +++ b/app/features/tier-list-maker/components/TierRow.tsx @@ -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")} ) : items.length > 0 ? ( - + {items.map((item) => ( ))} diff --git a/app/features/tier-list-maker/routes/tier-list-maker.tsx b/app/features/tier-list-maker/routes/tier-list-maker.tsx index 21a2df76a..e61a3c970 100644 --- a/app/features/tier-list-maker/routes/tier-list-maker.tsx +++ b/app/features/tier-list-maker/routes/tier-list-maker.tsx @@ -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 }) { ); } + +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 + ); +} diff --git a/changelog/2026-09-22-tier-list-maker-drag-preview.md b/changelog/2026-09-22-tier-list-maker-drag-preview.md new file mode 100644 index 000000000..c6c63479f --- /dev/null +++ b/changelog/2026-09-22-tier-list-maker-drag-preview.md @@ -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