fix(tui): manage focus in devtools panels (#38555)

Co-authored-by: James Long <17031+jlongster@users.noreply.github.com>
This commit is contained in:
opencode-agent[bot] 2026-07-23 18:58:02 +00:00 committed by GitHub
commit 2a9f8e3a2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,4 +1,4 @@
import { TextAttributes } from "@opentui/core"
import { TextAttributes, type Renderable } from "@opentui/core"
import { TimeToFirstDraw, useRenderer, useTerminalDimensions } from "@opentui/solid"
import { open } from "node:fs/promises"
import { tmpdir } from "node:os"
@ -33,6 +33,7 @@ export function DevToolsBar() {
const plugins = usePlugin()
const theme = useTheme()
const keymap = Keymap.use()
const renderer = useRenderer()
const dimensions = useTerminalDimensions()
const { themeV2, mode, supports, setMode } = theme
const elevatedTheme = theme.contextual("elevated").themeV2
@ -41,6 +42,7 @@ export function DevToolsBar() {
const [dumpPath, setDumpPath] = createSignal<string>()
const [dumpError, setDumpError] = createSignal<string>()
const [frontendSamples, setFrontendSamples] = createSignal<readonly ProcessSample[]>([])
let focus: Renderable | null
const connected = createMemo(() => client.connection.status() === "connected")
const serverIndicator = createMemo(() => connectionIndicator(client.connection.status(), client.connection.attempt()))
const themePerformance = createMemo(
@ -54,7 +56,22 @@ export function DevToolsBar() {
address: info.urls[0] ? new URL(info.urls[0]).host : "Unknown",
}
})
const toggle = (next: Panel) => setPanel((current) => (current === next ? undefined : next))
const close = () => {
setPanel()
setTimeout(() => {
if (panel() || !focus || focus.isDestroyed) return
focus.focus()
focus = null
}, 1)
}
const toggle = (next: Panel) => {
if (panel() === next) return close()
if (!panel()) {
focus = renderer.currentFocusedRenderable
focus?.blur()
}
setPanel(next)
}
const nextMode = () => (mode() === "dark" ? "light" : "dark")
const canSwitchMode = () => supports(nextMode())
const runtime = createMemo(() => runtimeStatus(frontendSamples()))
@ -67,7 +84,7 @@ export function DevToolsBar() {
if (!panel() || event.name !== "escape") return
event.preventDefault()
event.stopPropagation()
setPanel()
close()
},
{ priority: 10 },
)
@ -205,7 +222,7 @@ export function DevToolsBar() {
width={dimensions().width}
height={Math.max(0, dimensions().height - 1)}
backgroundColor="transparent"
onMouseUp={() => setPanel()}
onMouseUp={close}
/>
</Show>
<BarItem active={panel() === "server"} onClick={() => toggle("server")}>