feat(app): middle click to open new tab (#36215)
This commit is contained in:
@@ -2,11 +2,30 @@ import { describe, expect, test } from "bun:test"
|
|||||||
import { shouldOpenSessionInBackground } from "./home-session-open"
|
import { shouldOpenSessionInBackground } from "./home-session-open"
|
||||||
|
|
||||||
describe("shouldOpenSessionInBackground", () => {
|
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", () => {
|
test("requires only the platform primary modifier", () => {
|
||||||
expect(shouldOpenSessionInBackground({ mac: true, meta: true, ctrl: false, shift: false, alt: false })).toBe(true)
|
expect(shouldOpenSessionInBackground({ button: 0, mac: true, meta: true, ctrl: false, shift: false, alt: false })).toBe(
|
||||||
expect(shouldOpenSessionInBackground({ mac: false, meta: false, ctrl: true, shift: false, alt: false })).toBe(true)
|
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({ button: 0, mac: false, meta: false, ctrl: true, shift: false, alt: false })).toBe(
|
||||||
expect(shouldOpenSessionInBackground({ mac: false, meta: true, ctrl: false, shift: false, alt: false })).toBe(false)
|
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,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
export function shouldOpenSessionInBackground(input: {
|
export function shouldOpenSessionInBackground(input: {
|
||||||
|
button: number
|
||||||
mac: boolean
|
mac: boolean
|
||||||
meta: boolean
|
meta: boolean
|
||||||
ctrl: boolean
|
ctrl: boolean
|
||||||
shift: boolean
|
shift: boolean
|
||||||
alt: boolean
|
alt: boolean
|
||||||
}) {
|
}) {
|
||||||
|
if (input.button === 1) return true
|
||||||
|
if (input.button !== 0) return false
|
||||||
if (input.shift || input.alt) return false
|
if (input.shift || input.alt) return false
|
||||||
if (input.mac) return input.meta && !input.ctrl
|
if (input.mac) return input.meta && !input.ctrl
|
||||||
return input.ctrl && !input.meta
|
return input.ctrl && !input.meta
|
||||||
|
|||||||
@@ -240,10 +240,11 @@ function useHomeSessionHeaderOpacity(groups: () => HomeSessionGroup[]) {
|
|||||||
return { setViewport, setContentRef, setHeaderRef, update, titleOpacity }
|
return { setViewport, setContentRef, setHeaderRef, update, titleOpacity }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cmd+click on macOS (Ctrl+click elsewhere) opens a session tab in the
|
// Middle-click or Cmd+click on macOS (Ctrl+click elsewhere) opens a session
|
||||||
// background without navigating, matching browser conventions.
|
// tab in the background without navigating, matching browser conventions.
|
||||||
function isBackgroundOpen(event: MouseEvent) {
|
function isBackgroundOpen(event: MouseEvent) {
|
||||||
return shouldOpenSessionInBackground({
|
return shouldOpenSessionInBackground({
|
||||||
|
button: event.button,
|
||||||
mac: typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform),
|
mac: typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform),
|
||||||
meta: event.metaKey,
|
meta: event.metaKey,
|
||||||
ctrl: event.ctrlKey,
|
ctrl: event.ctrlKey,
|
||||||
@@ -1386,7 +1387,15 @@ function HomeSessionSearchResultRow(props: {
|
|||||||
group: !!showProjectName(),
|
group: !!showProjectName(),
|
||||||
}}
|
}}
|
||||||
onMouseEnter={() => props.onHighlight()}
|
onMouseEnter={() => props.onHighlight()}
|
||||||
|
onMouseDown={(event) => {
|
||||||
|
if (event.button === 1) event.preventDefault()
|
||||||
|
}}
|
||||||
onClick={(event) => props.onSelect(props.record.session, { background: isBackgroundOpen(event) })}
|
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
|
<HomeSessionLeading
|
||||||
project={props.record.project}
|
project={props.record.project}
|
||||||
@@ -1446,7 +1455,15 @@ function HomeSessionRow(props: {
|
|||||||
type="button"
|
type="button"
|
||||||
data-component="home-session-row"
|
data-component="home-session-row"
|
||||||
class={`${HOME_ROW} h-10 min-w-0 flex-1 gap-2 py-3 pl-3 pr-10`}
|
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) })}
|
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
|
<HomeSessionLeading
|
||||||
project={props.record.project}
|
project={props.record.project}
|
||||||
|
|||||||
Reference in New Issue
Block a user