hermes-agent/ui-tui/src/app/scroll.ts
2026-04-26 04:32:55 -05:00

55 lines
1.4 KiB
TypeScript

import type { ScrollBoxHandle } from '@hermes/ink'
import type { SelectionApi } from './interfaces.js'
export interface SelectionSnap {
anchor?: { row: number } | null
focus?: { row: number } | null
isDragging?: boolean
}
export interface ScrollWithSelectionOptions {
readonly scrollRef: { readonly current: ScrollBoxHandle | null }
readonly selection: SelectionApi
}
export function scrollWithSelectionBy(delta: number, { scrollRef, selection }: ScrollWithSelectionOptions): void {
const s = scrollRef.current
if (!s) {
return
}
const cur = s.getScrollTop() + s.getPendingDelta()
const viewport = Math.max(0, s.getViewportHeight())
const max = Math.max(0, s.getScrollHeight() - viewport)
const actual = Math.max(0, Math.min(max, cur + delta)) - cur
if (actual === 0) {
return
}
const sel = selection.getState() as null | SelectionSnap
const top = s.getViewportTop()
const bottom = top + viewport - 1
if (
sel?.anchor &&
sel.focus &&
sel.anchor.row >= top &&
sel.anchor.row <= bottom &&
(sel.isDragging || (sel.focus.row >= top && sel.focus.row <= bottom))
) {
const shift = sel.isDragging ? selection.shiftAnchor : selection.shiftSelection
if (actual > 0) {
selection.captureScrolledRows(top, top + actual - 1, 'above')
} else {
selection.captureScrolledRows(bottom + actual + 1, bottom, 'below')
}
shift(-actual, top, bottom)
}
s.scrollBy(actual)
}