mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-24 02:44:10 +00:00
fix(tui): ignore stray releases on new session controls (#42673)
This commit is contained in:
parent
552fd40ef8
commit
ab7a0bf65c
2 changed files with 74 additions and 2 deletions
|
|
@ -345,6 +345,7 @@ function VerticalSessionTabs(props: { controller?: SessionTabsController; animat
|
|||
let rail: { screenX: number; screenY: number } | undefined
|
||||
let scroll: ScrollBoxRenderable | undefined
|
||||
let didDrag = false
|
||||
let addPressed = false
|
||||
// A captured drag ends with a synthetic up on its drop target; do not turn that into a click.
|
||||
let suppressClick = false
|
||||
|
||||
|
|
@ -760,7 +761,8 @@ function VerticalSessionTabs(props: { controller?: SessionTabsController; animat
|
|||
onMouseDown={(event: MouseEvent) => {
|
||||
didDrag = false
|
||||
setDragging(undefined)
|
||||
if (event.button !== RIGHT_MOUSE_BUTTON) return
|
||||
addPressed = event.button !== RIGHT_MOUSE_BUTTON
|
||||
if (addPressed) return
|
||||
if (!rail) return
|
||||
setContextMenu({ x: event.x, y: event.y })
|
||||
event.preventDefault()
|
||||
|
|
@ -769,8 +771,11 @@ function VerticalSessionTabs(props: { controller?: SessionTabsController; animat
|
|||
onMouseUp={(event: MouseEvent) => {
|
||||
if (event.button === RIGHT_MOUSE_BUTTON) return
|
||||
if (suppressClick) return
|
||||
if (!addPressed) return
|
||||
addPressed = false
|
||||
if (!newTab()) tabs.add?.()
|
||||
}}
|
||||
onMouseDragEnd={() => (addPressed = false)}
|
||||
>
|
||||
<text
|
||||
width={2}
|
||||
|
|
@ -837,6 +842,7 @@ function HorizontalSessionTabs(props: { controller?: SessionTabsController; anim
|
|||
const [contextMenu, setContextMenu] = createSignal<TabContextMenuState>()
|
||||
let strip: { screenX: number; screenY: number } | undefined
|
||||
let didDrag = false
|
||||
let addPressed = false
|
||||
// A captured drag ends with a synthetic up on its drop target; do not turn that into a click.
|
||||
let suppressClick = false
|
||||
const hueStep = () => (mode() === "light" ? 800 : 200)
|
||||
|
|
@ -1203,7 +1209,8 @@ function HorizontalSessionTabs(props: { controller?: SessionTabsController; anim
|
|||
onMouseDown={(event) => {
|
||||
didDrag = false
|
||||
setDragging(undefined)
|
||||
if (event.button !== RIGHT_MOUSE_BUTTON) return
|
||||
addPressed = event.button !== RIGHT_MOUSE_BUTTON
|
||||
if (addPressed) return
|
||||
setContextMenu({ x: event.x, y: event.y })
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
|
@ -1211,8 +1218,11 @@ function HorizontalSessionTabs(props: { controller?: SessionTabsController; anim
|
|||
onMouseUp={(event) => {
|
||||
if (event.button === RIGHT_MOUSE_BUTTON) return
|
||||
if (suppressClick) return
|
||||
if (!addPressed) return
|
||||
addPressed = false
|
||||
tabs.add?.()
|
||||
}}
|
||||
onMouseDragEnd={() => (addPressed = false)}
|
||||
>
|
||||
{" + "}
|
||||
</text>
|
||||
|
|
|
|||
62
packages/tui/test/component/session-tabs-mouse.test.tsx
Normal file
62
packages/tui/test/component/session-tabs-mouse.test.tsx
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/** @jsxImportSource @opentui/solid */
|
||||
import { testRender } from "@opentui/solid"
|
||||
import { expect, test } from "bun:test"
|
||||
import { createSignal } from "solid-js"
|
||||
import { ConfigProvider } from "../../src/config"
|
||||
import { EMPTY_SESSION_TAB_STATUS, SessionTabs, type SessionTabsController } from "../../src/component/session-tabs"
|
||||
import { ThemeProvider } from "../../src/context/theme"
|
||||
import { emptyThemeSource } from "../fixture/fixture"
|
||||
import { TestTuiContexts } from "../fixture/tui-environment"
|
||||
import { createTuiResolvedConfig } from "../fixture/tui-runtime"
|
||||
|
||||
test("releasing a transcript selection over tab controls does not activate them", async () => {
|
||||
const [active, setActive] = createSignal("first")
|
||||
const [added, setAdded] = createSignal(0)
|
||||
const controller = {
|
||||
tabs: () => [
|
||||
{ sessionID: "first", title: "First" },
|
||||
{ sessionID: "second", title: "Second" },
|
||||
],
|
||||
current: active,
|
||||
select: setActive,
|
||||
close() {},
|
||||
move() {},
|
||||
add: () => setAdded((value) => value + 1),
|
||||
status: () => EMPTY_SESSION_TAB_STATUS,
|
||||
} satisfies SessionTabsController
|
||||
const app = await testRender(
|
||||
() => (
|
||||
<TestTuiContexts>
|
||||
<ConfigProvider config={createTuiResolvedConfig({ tabs: { enabled: true } })}>
|
||||
<ThemeProvider mode="dark" source={emptyThemeSource}>
|
||||
<box flexDirection="column">
|
||||
<SessionTabs controller={controller} animations={false} />
|
||||
<text>selectable transcript text</text>
|
||||
</box>
|
||||
</ThemeProvider>
|
||||
</ConfigProvider>
|
||||
</TestTuiContexts>
|
||||
),
|
||||
{ width: 60, height: 3 },
|
||||
)
|
||||
|
||||
try {
|
||||
app.renderer.start()
|
||||
await app.waitForFrame((frame) => frame.includes("Second"))
|
||||
await app.mockMouse.pressDown(5, 1)
|
||||
await app.mockMouse.release(40, 0)
|
||||
expect(active()).toBe("first")
|
||||
|
||||
await app.mockMouse.click(40, 0)
|
||||
expect(active()).toBe("second")
|
||||
|
||||
await app.mockMouse.pressDown(5, 1)
|
||||
await app.mockMouse.release(58, 0)
|
||||
expect(added()).toBe(0)
|
||||
|
||||
await app.mockMouse.click(58, 0)
|
||||
expect(added()).toBe(1)
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue