Stop the drag from selecting the tab's text
Build App (Preview) / compute-version (pull_request) Successful in 4s
Build App (Preview) / create-release (pull_request) Successful in 1s
Build App (Preview) / build-macos (pull_request) Successful in 2m39s
Build App (Preview) / build-windows (pull_request) Successful in 5m39s
Build App (Preview) / build-linux (pull_request) Successful in 5m56s

A pointer-driven drag is still a mouse drag as far as the browser is
concerned, so moving a tab highlighted its label blue — something the OS
drag image never did, and the last visible difference between this and
a real drag.

`select-none` on the tab. The rename field gets `select-text` back:
`user-select` inherits, and selecting text is exactly what that field is
for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-11 11:00:06 -07:00
co-authored by Claude Opus 5
parent 5bd80a05bc
commit 85ea3956e8
2 changed files with 16 additions and 3 deletions
@@ -127,6 +127,19 @@ describe("MainTabs reordering", () => {
expect(useAppState.getState().activeTabKey).toBe(HOME); expect(useAppState.getState().activeTabKey).toBe(HOME);
}); });
it("does not let a drag select the tab's text", () => {
// A pointer-driven drag is still a mouse drag as far as the browser is
// concerned, so without this the label highlights blue while you move it.
// The rename field is exempt — selecting there is the whole point.
render(<MainTabs />);
for (const tab of screen.getAllByRole("tab")) {
expect(tab.className).toContain("select-none");
}
fireEvent.doubleClick(screen.getAllByRole("tab")[1]);
expect(screen.getByLabelText("Rename tab").className).toContain("select-text");
});
it("shows the tab itself under the cursor while dragging", () => { it("shows the tab itself under the cursor while dragging", () => {
// A dimmed source tab and a thin line do not read as "I am holding this // A dimmed source tab and a thin line do not read as "I am holding this
// tab" — the dragged copy is what makes the gesture legible. // tab" — the dragged copy is what makes the gesture legible.
+3 -3
View File
@@ -178,7 +178,7 @@ export default function MainTabs() {
}; };
const tabClass = (active: boolean, dragging: boolean) => const tabClass = (active: boolean, dragging: boolean) =>
`flex items-center gap-1.5 pl-3 pr-1.5 h-full text-xs cursor-pointer border-r border-[var(--border-color)] transition-colors ${ `flex items-center gap-1.5 pl-3 pr-1.5 h-full text-xs cursor-pointer select-none border-r border-[var(--border-color)] transition-colors ${
active active
? "bg-[var(--bg-primary)] text-[var(--text-primary)]" ? "bg-[var(--bg-primary)] text-[var(--text-primary)]"
: "text-[var(--text-secondary)] hover:text-[var(--text-primary)]" : "text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
@@ -402,7 +402,7 @@ export default function MainTabs() {
if (e.key === "Enter") (e.target as HTMLInputElement).blur(); if (e.key === "Enter") (e.target as HTMLInputElement).blur();
if (e.key === "Escape") setRenamingId(null); if (e.key === "Escape") setRenamingId(null);
}} }}
className="max-w-[180px] px-1 py-0 bg-[var(--bg-primary)] border border-[var(--accent)] rounded-[var(--radius-control)] text-xs text-[var(--text-primary)]" className="max-w-[180px] px-1 py-0 select-text bg-[var(--bg-primary)] border border-[var(--accent)] rounded-[var(--radius-control)] text-xs text-[var(--text-primary)]"
/> />
) : ( ) : (
<span className="truncate max-w-[180px]" title={displayLabel}> <span className="truncate max-w-[180px]" title={displayLabel}>
@@ -465,7 +465,7 @@ export default function MainTabs() {
<div <div
aria-hidden="true" aria-hidden="true"
data-testid="tab-drag-ghost" data-testid="tab-drag-ghost"
className="fixed z-50 flex items-center gap-1.5 px-3 h-8 text-xs rounded-[var(--radius-control)] bg-[var(--bg-primary)] text-[var(--text-primary)] border border-[var(--accent)] pointer-events-none" className="fixed z-50 flex items-center gap-1.5 px-3 h-8 text-xs rounded-[var(--radius-control)] bg-[var(--bg-primary)] text-[var(--text-primary)] border border-[var(--accent)] pointer-events-none select-none"
style={{ style={{
left: ghost.x, left: ghost.x,
top: ghost.y, top: ghost.y,