fix: fluid drop instead of the whole list lurching

Letting go of a card was abrupt and pulled its neighbours with it. Frame
capture showed non-dragged rows moving about 68px after release, still
going 13 frames later.

Two things owned transform on the same elements: manual shift transforms
for the gap, and animate:flip for the reorder. On drop, flip measured a
"before" rect that already had a manual offset in it, then the order
changed and the offsets cleared in the same update, so it animated toward
a position that never existed.

One owner each now. The list reorders as the pointer crosses each
boundary rather than on release, so flip moves the displaced cards on its
own, one swap at a time, and the swaps look right while you're dragging.
Only the lifted card is positioned by hand, with flip off for it so it
stays under the pointer. By release the order is already final, and
nothing moves but that card settling.

After the change, every non-dragged row moves 0px on release and the
dropped card eases 4px into place.

Slot geometry is replaced with offsetTop and offsetHeight, layout values
that ignore transforms, so the target can't feed back into itself and
can't go stale.

Removes src/lib/drag.js and its tests. The rule they covered doesn't exist
in this design any more.
This commit is contained in:
Aculix Technologies
2026-08-16 01:33:51 +05:30
parent 00d1e211fe
commit 19e8ac2f61
4 changed files with 84 additions and 152 deletions
+10 -5
View File
@@ -248,6 +248,7 @@ body {
/* A real list, so screen readers announce item counts and position. */
.task-items {
position: relative;
display: flex;
flex-direction: column;
gap: 12px;
@@ -294,13 +295,17 @@ html.dark .task-item.dragging {
0 4px 8px rgba(0, 0, 0, 0.35);
}
/* Cards sliding aside to open the gap. */
.task-item.drag-settling {
transition: transform 200ms cubic-bezier(0.2, 0, 0, 1);
/* The released card easing back into its slot. It keeps the raised z-index so
it stays above its neighbours on the way down, and supplies the transition
that the lifted state deliberately withheld. */
.task-item.settling {
z-index: 20;
transition:
transform 240ms cubic-bezier(0.2, 0, 0, 1),
box-shadow 240ms ease,
border-color 240ms ease;
}
/* A drag is in progress: suppress hover lift on the cards being displaced,
which would otherwise fight the transform that opens the gap. */
.task-item:hover {
background-color: var(--hover);
transform: translateY(-2px);