fix(runtime): content-size auto-width <Static> isolated paint (Ink parity, G64) (#64)

Ink content-sizes the position:absolute, auto-width static box: Static.tsx
sets `{position:'absolute', flexDirection:'column', ...customStyle}` with no
width, ink.tsx calculateLayout never sets the static node's width, and
renderer.ts reads node.staticNode.yogaNode.getComputedWidth() — the computed
width of a yoga absolute, auto-width node, which shrinks to its CONTENT. So
flex-fill children (Spacer/flexGrow/justifyContent/percent) inside a Static
item collapse to content width instead of expanding to the terminal width.

The G44 fix over-forced the iso root to full terminal width (setWidth(columns)),
so a Spacer/flexGrow child expanded to fill the terminal. This refines G44: for
an AUTO-width static node we now leave the iso root width auto and cap it at the
available columns with setMaxWidth(columns), content-sizing exactly like Ink
while still wrapping anything wider than the terminal. The explicit-width
(POINT/PERCENT) copyStyle path from G44 is unchanged and still wins.

Verified against the built Ink reference (v7.0.4, 40b3a75): a Static item Box
row [LEFT][Spacer][RIGHT] at cols=80 renders "LEFTRIGHT" (Spacer collapses),
and [A][flexGrow][B] renders "AB".

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Yunfei He
2026-05-30 15:42:05 +08:00
committed by GitHub
parent 8cadcca95c
commit e7992bb06b
3 changed files with 377 additions and 67 deletions
+1 -1
View File
@@ -109,7 +109,7 @@ Non-obvious calls made while fixing gaps, recorded for review in the final repor
| G61 | stdout-stderr-stdin-size-cursor | Bracketed-paste disable write during stdin dispose() lacks Ink's destroyed/writableEnded (canWriteToStdout) guard — sweep-8 LOW | P3 | todo | — | — |
| G62 | render-lifecycle-reconciler | resolveExit()/teardown() writable-stream checks omit the writableLength fallback + stdout.writable flag that Ink's getWritableStreamState uses — sweep-8 LOW | P3 | todo | — | — |
| G63 | text-wrap-transform | Transform applied to the FULL line THEN horizontally clipped; Ink clips THEN transforms (output.ts), so a width-sensitive transform (gradient / OSC-8 hyperlink) inside an overflowX:hidden box gets the wrong char span (MEDIUM, sweep-9) | P1 | pr-open | `fix/parity-clip-then-transform` | #63 |
| G64 | static-newline-spacer | `<Static>` isolated paint forces terminal width; Ink content-sizes the static box (position:absolute, auto width) so flex-fill children (Spacer/flexGrow/justify/align/percent) collapse to content — refines G44's over-correction (MEDIUM, sweep-9) | P1 | todo | — | — |
| G64 | static-newline-spacer | `<Static>` isolated paint forces terminal width; Ink content-sizes the static box (position:absolute, auto width) so flex-fill children (Spacer/flexGrow/justify/align/percent) collapse to content — refines G44's over-correction (MEDIUM, sweep-9) | P1 | pr-open | `fix/parity-static-content-size` | #64 |
| G65 | app-exit-instances-animation-sr | SR unchanged-frame skip compares WRAPPED output, not Ink's UNWRAPPED linearization — diverges on resize with identical content — sweep-9 LOW | P3 | todo | — | — |
| G66 | app-exit-instances-animation-sr | app.waitUntilRenderFlush() lacks Ink's unmount/unmounting short-circuit to awaitExit() — sweep-9 LOW | P3 | todo | — | — |