/** * The arithmetic of the sortable list shared by the shape, pixel art and tilemap lists: which row * shows which item, which gap a drop falls into, and what move that makes in the owner's order. */ import { describe, expect, it } from 'vitest'; import { dropGap, dropMove, rowOrder } from '../../src/ui/sortable'; const ROW = 30; describe('sortable list', () => { it('shows a layer list upside down – the item drawn last is the top row', () => { expect(rowOrder(['bottom', 'middle', 'top'], true)).toEqual(['top', 'middle', 'bottom']); expect(rowOrder(['first', 'second'], false)).toEqual(['first', 'second']); }); it('drops into the gap the pointer is nearest to', () => { expect(dropGap(3, 2, ROW)).toBe(0); expect(dropGap(3, 20, ROW)).toBe(1); expect(dropGap(3, 44, ROW)).toBe(1); expect(dropGap(3, 46, ROW)).toBe(2); // Outside the list there is no gap: a drop above it is the first, below it the last. expect(dropGap(3, 400, ROW)).toBe(3); expect(dropGap(3, -40, ROW)).toBe(0); }); it('turns a drop into a move of the model, the top row being the last item when reversed', () => { // Three items, so the rows are the model indices [2, 1, 0]: the top row dropped at the // bottom gap becomes the first item of the model, the one drawn first. expect(dropMove(3, 0, 3, true)).toEqual({ from: 2, to: 0 }); expect(dropMove(3, 2, 0, true)).toEqual({ from: 0, to: 2 }); expect(dropMove(3, 1, 0, true)).toEqual({ from: 1, to: 2 }); }); it('keeps the indices as they are in a list shown in model order', () => { // Frames: the first row is the first frame. The top row dropped at the bottom becomes the last. expect(dropMove(3, 0, 3, false)).toEqual({ from: 0, to: 2 }); expect(dropMove(3, 2, 0, false)).toEqual({ from: 2, to: 0 }); expect(dropMove(3, 0, 2, false)).toEqual({ from: 0, to: 1 }); }); it('is no move when the row lands where it already is', () => { for (const reversed of [true, false]) { expect(dropMove(3, 1, 1, reversed)).toBeNull(); expect(dropMove(3, 1, 2, reversed)).toBeNull(); expect(dropMove(3, 5, 1, reversed)).toBeNull(); } }); });