fix(tui): keep streaming progress stable during interaction

This commit is contained in:
Brooklyn Nicholson 2026-04-26 04:23:57 -05:00
parent 1c964ed43f
commit 355e0ae960
15 changed files with 278 additions and 106 deletions

View file

@ -29,7 +29,7 @@ import {
FOCUS_IN,
FOCUS_OUT
} from '../termio/csi.js'
import { DBP, DFE, DISABLE_MOUSE_TRACKING, EBP, EFE, HIDE_CURSOR, SHOW_CURSOR } from '../termio/dec.js'
import { DBP, DFE, DISABLE_MOUSE_TRACKING, EBP, EFE, SHOW_CURSOR } from '../termio/dec.js'
import AppContext from './AppContext.js'
import { ClockProvider } from './ClockContext.js'
@ -206,10 +206,9 @@ export default class App extends PureComponent<Props, State> {
)
}
override componentDidMount() {
// In accessibility mode, keep the native cursor visible for screen magnifiers and other tools
if (this.props.stdout.isTTY) {
this.props.stdout.write(HIDE_CURSOR)
}
// Keep the native terminal cursor visible. Ink parks it at the declared
// input caret after each frame, so the terminal emulator provides the
// normal blinking block/bar without React-driven blink re-renders.
}
override componentWillUnmount() {
if (this.props.stdout.isTTY) {
@ -470,7 +469,7 @@ export default class App extends PureComponent<Props, State> {
}
if (this.props.stdout.isTTY) {
this.props.stdout.write(HIDE_CURSOR + EFE)
this.props.stdout.write(EFE)
}
this.inputEmitter.emit('resume')
@ -569,18 +568,19 @@ function processKeysInBatch(app: App, items: ParsedInput[], _unused1: undefined,
/** Exported for testing. Mutates app.props.selection and click/hover state. */
export function handleMouseEvent(app: App, m: ParsedMouse): void {
// Allow disabling click handling while keeping wheel scroll (which goes
// through the keybinding system as 'wheelup'/'wheeldown', not here).
if (isMouseClicksDisabled()) {
return
}
const sel = app.props.selection
// Terminal coords are 1-indexed; screen buffer is 0-indexed
const col = m.col - 1
const row = m.row - 1
const baseButton = m.button & 0x03
// Allow disabling app click/selection handling while keeping wheel scroll
// and DOM mouse dispatch alive. Put this after coordinate/button decoding
// and exempt non-left buttons so scrollbar/right-click handlers still work.
if (isMouseClicksDisabled() && baseButton === 0) {
return
}
if (m.action === 'press') {
if ((m.button & 0x20) !== 0 && baseButton === 3) {
if (app.mouseCaptureTarget) {