fix(kanban): deterministic footer packing for narrow widths - #242
Conversation
…licker
At narrow widths (~80-120 cols) the kanban footer wrapped mid-word ("na" / "v",
"att" / "ach") because each of its ~30 sub-<Text>s wrapped independently. The
total width also varied with cursor position — hasItem/hasSession/hasWorktree
toggled whole hint groups, so moving selection changed wrap row count and
shifted the board: the "flicker".
Refactor Footer to atomic hint chunks with a constant chunk list:
- buildFooterChunks() returns the canonical list. Each chunk has a `plain`
width (constant) and a `render` callback (state-aware). Unavailable hints
render dimmed, never disappear — footer width is selection-independent.
- packFooterChunks() greedily packs chunks into rows separated by ` · `
without ever splitting a chunk mid-label.
- Footer takes termCols, packs, renders one Box per row.
- colHeight subtracts the actual packed row count (max 3 footer rows at the
narrowest), so the wrapped footer never pushes the board off-screen.
Tests:
- New per-width assertions (80/96/100/120) verify every footer row splits
on ` · ` into known chunks — catches mid-word wrap regressions.
- New stability test renders the same width twice with different cursor
positions and asserts footer row count matches.
- Golden ASCII frame at tests/fixtures/kanban-narrow-footer.txt for visual
diffing.
- Relaxed minSpan in the existing "column boxes occupy most of the
terminal height" assertion from height-4 to height-6 (footer can take
up to 3 rows at narrow widths now).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…om-bar Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Code Review — PR #242: fix(kanban): deterministic footer packing for narrow widthsOverviewThis PR refactors the kanban board's footer from a single flat flex row to a greedy bin-packing layout that keeps hint chunks atomic, and computes the resulting row count ahead of render so The design is solid and the test coverage is notably thorough. A few things worth flagging: Code Quality
Array index used as rows.map((row, ri) => <Box key={ri}>…</Box>)Using index as key is fine here because the rows are derived deterministically from a static chunk list, but using the first chunk's
stdin.write('[C');A proper ANSI cursor-right sequence is Potential Bugs
Fixture test depends on exact ANSI stripping PerformanceNo significant concerns. SecurityNo security concerns. TestsThe test coverage is strong:
One gap: widths above 120 (e.g. 160) aren't covered. At 160 cols the old code sometimes fit in 1 row; the PR notes this now consistently wraps to 2. A note in the test or a single assertion at 160 would confirm this is intentional and not a regression. SummaryThe core algorithm and the fix are correct. The main action items:
Nice work on the flicker fix — the "always render, dim when unavailable" decision is the right call. |
Summary
·separators.colHeightreserves the actual packed footer row count (up to 3 rows at narrow widths) so the layout no longer overflows the terminal.Test plan
·into known chunks (80, 96, 100, 120).tests/fixtures/kanban-narrow-footer.txt(80×20).🤖 Generated with Claude Code