mirror of
https://github.com/aculix/negotium.git
synced 2026-09-11 07:28:17 +00:00
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:
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* How far a row should slide, in pixels, while another row is being dragged
|
||||
* over the list.
|
||||
*
|
||||
* A lifted card vacates exactly its own height plus one gap, so every row it
|
||||
* passes travels by that same amount — `shift` — and everything else stays
|
||||
* put. The result is a real gap at the destination, which doubles as the drop
|
||||
* indicator and is therefore always accurate.
|
||||
*
|
||||
* Negative moves a row up the list, positive moves it down.
|
||||
*/
|
||||
export function displacement(index, fromIndex, toIndex, shift) {
|
||||
if (fromIndex === null || toIndex === null) return 0
|
||||
if (index === fromIndex) return 0
|
||||
|
||||
if (fromIndex < toIndex && index > fromIndex && index <= toIndex) return -shift
|
||||
if (fromIndex > toIndex && index >= toIndex && index < fromIndex) return shift
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { displacement } from './drag.js'
|
||||
|
||||
const SHIFT = 70
|
||||
|
||||
describe('displacement', () => {
|
||||
it('is zero when nothing is being dragged', () => {
|
||||
expect(displacement(2, null, null, SHIFT)).toBe(0)
|
||||
})
|
||||
|
||||
it('is zero for the dragged row itself', () => {
|
||||
expect(displacement(1, 1, 3, SHIFT)).toBe(0)
|
||||
})
|
||||
|
||||
it('is zero when the row would not move', () => {
|
||||
expect(displacement(2, 2, 2, SHIFT)).toBe(0)
|
||||
})
|
||||
|
||||
describe('dragging downward', () => {
|
||||
// Row 0 heading to slot 2: rows 1 and 2 slide up into the vacated space,
|
||||
// row 3 stays put.
|
||||
it('slides passed rows up', () => {
|
||||
expect(displacement(1, 0, 2, SHIFT)).toBe(-SHIFT)
|
||||
expect(displacement(2, 0, 2, SHIFT)).toBe(-SHIFT)
|
||||
})
|
||||
|
||||
it('leaves rows beyond the destination alone', () => {
|
||||
expect(displacement(3, 0, 2, SHIFT)).toBe(0)
|
||||
})
|
||||
|
||||
it('leaves rows above the origin alone', () => {
|
||||
expect(displacement(0, 1, 3, SHIFT)).toBe(0)
|
||||
})
|
||||
|
||||
it('includes the destination row itself', () => {
|
||||
expect(displacement(3, 0, 3, SHIFT)).toBe(-SHIFT)
|
||||
})
|
||||
})
|
||||
|
||||
describe('dragging upward', () => {
|
||||
// Row 3 heading to slot 1: rows 1 and 2 slide down.
|
||||
it('slides passed rows down', () => {
|
||||
expect(displacement(1, 3, 1, SHIFT)).toBe(SHIFT)
|
||||
expect(displacement(2, 3, 1, SHIFT)).toBe(SHIFT)
|
||||
})
|
||||
|
||||
it('leaves rows above the destination alone', () => {
|
||||
expect(displacement(0, 3, 1, SHIFT)).toBe(0)
|
||||
})
|
||||
|
||||
it('leaves rows below the origin alone', () => {
|
||||
expect(displacement(4, 3, 1, SHIFT)).toBe(0)
|
||||
})
|
||||
|
||||
it('includes the destination row itself', () => {
|
||||
expect(displacement(0, 2, 0, SHIFT)).toBe(SHIFT)
|
||||
})
|
||||
})
|
||||
|
||||
it('moves exactly one row for a single-step drag', () => {
|
||||
expect(displacement(1, 0, 1, SHIFT)).toBe(-SHIFT)
|
||||
expect(displacement(2, 0, 1, SHIFT)).toBe(0)
|
||||
})
|
||||
|
||||
it('displaces every row between the ends of a full-list drag', () => {
|
||||
const shifts = [0, 1, 2, 3, 4].map(i => displacement(i, 0, 4, SHIFT))
|
||||
expect(shifts).toEqual([0, -SHIFT, -SHIFT, -SHIFT, -SHIFT])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user