fix(card_drag): extend drop rects one trailing row so beyond-extent drops land

computeSlotRectsForDrop adds cols slots past maxSlot; classifyCardDrag and
drawCardDropTarget use it instead of the render rects. doReorderDrop already
accepts any non-negative slot. New tests cover beyond-extent resolves,
empty-bank trailing row, gap pixels still miss, empty-cell within-extent works.
This commit is contained in:
2026-07-27 03:31:29 -04:00
parent 9a1bcbcf7a
commit d2cc33e9de
5 changed files with 124 additions and 2 deletions
+21
View File
@@ -995,6 +995,26 @@ static void testReorderSampleSameSlotIsNoOp() {
CHECK(book.serialize() == jsonBefore);
}
// Reorder to a slot BEYOND the current maxSlot — the trailing-drop case. The model
// places the card at the exact target slot (no shift, slot is empty), leaving the card's
// old slot empty. This is the pure-layer gate for the DAW beyond-extent drop repro.
static void testReorderSampleBeyondMaxSlot() {
BankBook book;
CHECK(book.pool().index.add(sampleWith("a")) == AddResult::Added);
CHECK(book.pool().index.add(sampleWith("b")) == AddResult::Added);
book.reconcileSlots(); // a@0, b@1 -> maxSlot = 1
CHECK(book.pool().slots.maxSlot() == 1);
// Drag "b" to slot 5 (well beyond maxSlot=1). Should succeed: slot 5 is empty,
// no insert-shift needed, b just takes slot 5.
CHECK(book.reorderSample("id-b", kPoolBankId, 5));
CHECK(book.pool().slots.slotOf("id-b") == 5);
CHECK(book.pool().slots.slotOf("id-a") == 0); // a untouched
// maxSlot is now 5; slot 1 is empty (gap).
CHECK(book.pool().slots.maxSlot() == 5);
CHECK(book.pool().slots.idAt(1).empty()); // b's old slot is now a gap
}
// --- BankBook L7: Alt-replace mutator ----------------------------------------
static void testReplaceSampleTakesSlotAndRemovesOccupant() {
@@ -1113,6 +1133,7 @@ int main() {
testOrderedSampleIdsReconcilesLazily();
testReorderSampleRejectsUnknown();
testReorderSampleSameSlotIsNoOp();
testReorderSampleBeyondMaxSlot();
testReplaceSampleTakesSlotAndRemovesOccupant();
testReplaceSampleNonDestructiveFileStays();
testReplaceSampleRejectionsNoMutation();