Просмотр исходного кода

feat(app): middle click to open new tab (#36215)

Aarav Sareen 1 месяц назад
Родитель
Сommit
97f502e79a

+ 24 - 5
packages/app/src/pages/home-session-open.test.ts

@@ -2,11 +2,30 @@ import { describe, expect, test } from "bun:test"
 import { shouldOpenSessionInBackground } from "./home-session-open"
 
 describe("shouldOpenSessionInBackground", () => {
+  test("opens middle clicks in the background", () => {
+    expect(shouldOpenSessionInBackground({ button: 1, mac: true, meta: false, ctrl: false, shift: false, alt: false })).toBe(
+      true,
+    )
+    expect(shouldOpenSessionInBackground({ button: 2, mac: true, meta: false, ctrl: false, shift: false, alt: false })).toBe(
+      false,
+    )
+  })
+
   test("requires only the platform primary modifier", () => {
-    expect(shouldOpenSessionInBackground({ mac: true, meta: true, ctrl: false, shift: false, alt: false })).toBe(true)
-    expect(shouldOpenSessionInBackground({ mac: false, meta: false, ctrl: true, shift: false, alt: false })).toBe(true)
-    expect(shouldOpenSessionInBackground({ mac: true, meta: true, ctrl: false, shift: true, alt: false })).toBe(false)
-    expect(shouldOpenSessionInBackground({ mac: false, meta: false, ctrl: true, shift: false, alt: true })).toBe(false)
-    expect(shouldOpenSessionInBackground({ mac: false, meta: true, ctrl: false, shift: false, alt: false })).toBe(false)
+    expect(shouldOpenSessionInBackground({ button: 0, mac: true, meta: true, ctrl: false, shift: false, alt: false })).toBe(
+      true,
+    )
+    expect(shouldOpenSessionInBackground({ button: 0, mac: false, meta: false, ctrl: true, shift: false, alt: false })).toBe(
+      true,
+    )
+    expect(shouldOpenSessionInBackground({ button: 0, mac: true, meta: true, ctrl: false, shift: true, alt: false })).toBe(
+      false,
+    )
+    expect(shouldOpenSessionInBackground({ button: 0, mac: false, meta: false, ctrl: true, shift: false, alt: true })).toBe(
+      false,
+    )
+    expect(shouldOpenSessionInBackground({ button: 0, mac: false, meta: true, ctrl: false, shift: false, alt: false })).toBe(
+      false,
+    )
   })
 })

+ 3 - 0
packages/app/src/pages/home-session-open.ts

@@ -1,10 +1,13 @@
 export function shouldOpenSessionInBackground(input: {
+  button: number
   mac: boolean
   meta: boolean
   ctrl: boolean
   shift: boolean
   alt: boolean
 }) {
+  if (input.button === 1) return true
+  if (input.button !== 0) return false
   if (input.shift || input.alt) return false
   if (input.mac) return input.meta && !input.ctrl
   return input.ctrl && !input.meta

+ 19 - 2
packages/app/src/pages/home.tsx

@@ -240,10 +240,11 @@ function useHomeSessionHeaderOpacity(groups: () => HomeSessionGroup[]) {
   return { setViewport, setContentRef, setHeaderRef, update, titleOpacity }
 }
 
-// Cmd+click on macOS (Ctrl+click elsewhere) opens a session tab in the
-// background without navigating, matching browser conventions.
+// Middle-click or Cmd+click on macOS (Ctrl+click elsewhere) opens a session
+// tab in the background without navigating, matching browser conventions.
 function isBackgroundOpen(event: MouseEvent) {
   return shouldOpenSessionInBackground({
+    button: event.button,
     mac: typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform),
     meta: event.metaKey,
     ctrl: event.ctrlKey,
@@ -1386,7 +1387,15 @@ function HomeSessionSearchResultRow(props: {
         group: !!showProjectName(),
       }}
       onMouseEnter={() => props.onHighlight()}
+      onMouseDown={(event) => {
+        if (event.button === 1) event.preventDefault()
+      }}
       onClick={(event) => props.onSelect(props.record.session, { background: isBackgroundOpen(event) })}
+      onAuxClick={(event) => {
+        if (!isBackgroundOpen(event)) return
+        event.preventDefault()
+        props.onSelect(props.record.session, { background: true })
+      }}
     >
       <HomeSessionLeading
         project={props.record.project}
@@ -1446,7 +1455,15 @@ function HomeSessionRow(props: {
         type="button"
         data-component="home-session-row"
         class={`${HOME_ROW} h-10 min-w-0 flex-1 gap-2 py-3 pl-3 pr-10`}
+        onMouseDown={(event) => {
+          if (event.button === 1) event.preventDefault()
+        }}
         onClick={(event) => props.openSession(props.record.session, { background: isBackgroundOpen(event) })}
+        onAuxClick={(event) => {
+          if (!isBackgroundOpen(event)) return
+          event.preventDefault()
+          props.openSession(props.record.session, { background: true })
+        }}
       >
         <HomeSessionLeading
           project={props.record.project}