feat: add tab drop preview indicator for split pane drag-and-drop

This commit is contained in:
Mohamed Boudra
2026-03-18 20:09:28 +07:00
parent b763d4358e
commit ed9a15c0bd
7 changed files with 329 additions and 38 deletions
@@ -0,0 +1,73 @@
import { describe, expect, it } from "vitest";
import { computeTabDropPreview } from "@/components/split-container-tab-drop-preview";
import type { WorkspaceTabDescriptor } from "@/screens/workspace/workspace-tabs-types";
function tab(tabId: string): WorkspaceTabDescriptor {
return {
key: tabId,
tabId,
kind: "draft",
target: {
kind: "draft",
draftId: tabId,
},
};
}
describe("computeTabDropPreview", () => {
const targetTabs = [tab("a"), tab("b"), tab("c"), tab("d")];
it("returns a before-target insertion index for cross-pane drops on the left half", () => {
expect(
computeTabDropPreview({
activePaneId: "source",
activeTabId: "x",
overPaneId: "target",
overTabId: "c",
targetTabs,
activeRect: { left: 180, width: 40 },
overRect: { left: 200, width: 100 },
})
).toEqual({
paneId: "target",
insertionIndex: 2,
indicatorIndex: 2,
});
});
it("returns an after-target insertion index for cross-pane drops on the right half", () => {
expect(
computeTabDropPreview({
activePaneId: "source",
activeTabId: "x",
overPaneId: "target",
overTabId: "c",
targetTabs,
activeRect: { left: 280, width: 40 },
overRect: { left: 200, width: 100 },
})
).toEqual({
paneId: "target",
insertionIndex: 3,
indicatorIndex: 3,
});
});
it("adjusts same-pane drops so insertion indexes match arrayMove semantics", () => {
expect(
computeTabDropPreview({
activePaneId: "pane",
activeTabId: "b",
overPaneId: "pane",
overTabId: "d",
targetTabs,
activeRect: { left: 460, width: 40 },
overRect: { left: 400, width: 100 },
})
).toEqual({
paneId: "pane",
insertionIndex: 3,
indicatorIndex: 4,
});
});
});