feat(ui): row-precision virtual scroll on Ink 7 + React 19#380
Merged
Conversation
Bump ink 5.2→7.0.2 + react 18.3→19.2; drop react-reconciler/yoga-layout. Retire src/renderer/ (cell-diff + ink-compat shim) — Ink 7 ships native equivalents for every motivation: alternateScreen, useAnimation, useWindowSize, useBoxMetrics, synchronized output, incrementalRendering. Default to alt-screen so the resize-ghost / scroll-yank class of bugs disappears. `--no-alt-screen` opts back into scrollback for users who need chat output preserved in shell history on exit. Row-precision virtual scroll with reading mode: scrolling away from bottom hides PromptInput and replaces it with a "📖 reading history — End / PgDn to return" indicator. PgUp/PgDn/End owned by App; ↑/↓ on an empty buffer hand off to chat scroll via PromptInput; App takes ↑/↓ directly when busy or in reading mode (PromptInput can't process them). Wheel events translate to ↑/↓ in raw mode, so the same paths cover wheel. Ctrl+P/N keeps the prompt-history binding (wheel-immune). Drop <Static> — incompatible with alt-screen (no scrollback to shelter committed cards across resize-reflow). React.memo on CardRenderer plus the reducer's reference-stable card array skips reconciler cost on unchanged cards. CardStream renders all cards inside an overflow:hidden Box; inner Box's marginTop=-scrollRows shifts content; useBoxMetrics reports inner/outer heights so App can clamp scroll bounds. CardStream.isSettled covers task / plan / subagent kinds. PromptInput's useReserveRows quantizes to 4-row buckets so per-keystroke layout doesn't churn. TickerProvider migrated to Ink 7's useAnimation. Modal-open condition collapsed from 14 OR'd checks into one reused boolean. Migrate inline tests (markdown, plan-confirm) off the cell-diff renderer to ink-testing-library. Remove dead alt-screen.ts; strip stale comments referencing removed scrollback-mode workarounds.
Ink 7 calls setRawMode on stdin during render(); CI's process.stdin isn't a TTY so it throws "Raw mode is not supported". Pass a minimal EventEmitter-based fake stdin (setRawMode no-op, isTTY=true) alongside the existing fake stdout. Affects four tests that import render directly from ink for in-process render-and-assert: ui-session-picker-currency, ui-stats-panel-currency, ui-usage-card-balance, ui-status-row-balance.
esengine
added a commit
that referenced
this pull request
May 7, 2026
ChasLui
pushed a commit
to ChasLui/DeepSeek-Reasonix
that referenced
this pull request
May 23, 2026
) * feat(ui): row-precision virtual scroll on Ink 7 + React 19 Bump ink 5.2→7.0.2 + react 18.3→19.2; drop react-reconciler/yoga-layout. Retire src/renderer/ (cell-diff + ink-compat shim) — Ink 7 ships native equivalents for every motivation: alternateScreen, useAnimation, useWindowSize, useBoxMetrics, synchronized output, incrementalRendering. Default to alt-screen so the resize-ghost / scroll-yank class of bugs disappears. `--no-alt-screen` opts back into scrollback for users who need chat output preserved in shell history on exit. Row-precision virtual scroll with reading mode: scrolling away from bottom hides PromptInput and replaces it with a "📖 reading history — End / PgDn to return" indicator. PgUp/PgDn/End owned by App; ↑/↓ on an empty buffer hand off to chat scroll via PromptInput; App takes ↑/↓ directly when busy or in reading mode (PromptInput can't process them). Wheel events translate to ↑/↓ in raw mode, so the same paths cover wheel. Ctrl+P/N keeps the prompt-history binding (wheel-immune). Drop <Static> — incompatible with alt-screen (no scrollback to shelter committed cards across resize-reflow). React.memo on CardRenderer plus the reducer's reference-stable card array skips reconciler cost on unchanged cards. CardStream renders all cards inside an overflow:hidden Box; inner Box's marginTop=-scrollRows shifts content; useBoxMetrics reports inner/outer heights so App can clamp scroll bounds. CardStream.isSettled covers task / plan / subagent kinds. PromptInput's useReserveRows quantizes to 4-row buckets so per-keystroke layout doesn't churn. TickerProvider migrated to Ink 7's useAnimation. Modal-open condition collapsed from 14 OR'd checks into one reused boolean. Migrate inline tests (markdown, plan-confirm) off the cell-diff renderer to ink-testing-library. Remove dead alt-screen.ts; strip stale comments referencing removed scrollback-mode workarounds. * test(ui): provide fake stdin for Ink 7 raw-mode check in CI Ink 7 calls setRawMode on stdin during render(); CI's process.stdin isn't a TTY so it throws "Raw mode is not supported". Pass a minimal EventEmitter-based fake stdin (setRawMode no-op, isTTY=true) alongside the existing fake stdout. Affects four tests that import render directly from ink for in-process render-and-assert: ui-session-picker-currency, ui-stats-panel-currency, ui-usage-card-balance, ui-status-row-balance. * test(ui): extract makeFakeStdin/Stdout to shared tests/helpers/ink-stdio
ChasLui
pushed a commit
to ChasLui/DeepSeek-Reasonix
that referenced
this pull request
May 23, 2026
Ink 7 + React 19 chat scroll rewrite (esengine#380), configurable web_search backend with SearXNG (esengine#338), MCP filesystem sandbox preflight + wizard mkdir confirm (esengine#362, PR esengine#379), README URL fix (esengine#375), bug template update (esengine#378).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
react-reconciler/yoga-layoutsrc/renderer/(cell-diff renderer + ink-compat shim) — Ink 7 ships native equivalents for every motivationWhy retire cell-diff
Ink 7 supersedes every reason the cell-diff renderer existed:
alternateScreenrender optionuseAnimationhook (shared internal timer)useWindowSizehookuseBoxMetrics/measureElementincrementalRenderingMaintaining a parallel renderer was tracking upstream and re-implementing what already exists. Production was running real Ink anyway since 5d-19 was never wired up.
Behavior changes
reasonix code/reasonix chatdefault to alt-screen. Pass--no-alt-screento keep chat output in shell scrollback (legacy).📖 reading history — End / PgDn to return. End or PgDn returns to live.Implementation notes
<Box overflow="hidden">clips at viewport rows; inner<Box marginTop={-scrollRows}>slides content.useBoxMetricsreports inner / outer heights souseChatScrollcan clamp scroll bounds and auto-pin to bottom on new content.<Static>: incompatible with alt-screen (no scrollback to shelter committed cards across resize-reflow).React.memo(CardRenderer)plus reference-stable cards in the reducer skips reconciler cost on unchanged history.Appowns PgUp/PgDn/End/wheel everywhere; PromptInput hands off ↑/↓ on empty buffer when pinned + idle;Apptakes ↑/↓ directly when busy or in reading mode (PromptInput can't process them).CardStream.isSettledcoverstask/plan/subagent;useReserveRowsquantizes to 4-row buckets; Ticker migrated touseAnimation; modal-open boolean reused across 14 OR'd checks; inline tests migrated off cell-diff toink-testing-library.Test plan
npm run verifypasses (typecheck + lint + 2132 tests + build)reasonix codeboots cleanly into alt-screenreasonix code --no-alt-screenstill works for users who need shell scrollback