fix(runtime): pass child sibling index to nested <Transform> (Ink parity, G21) (#50)

* fix(runtime): pass child sibling index to nested <Transform> (Ink parity, G21)

paint.ts renderTextWithInlineStyles and text-measure.ts flattenLeaves squash
loops now pass the child's position index to child.transform instead of a
hardcoded 0, matching Ink squash-text-nodes.ts:13,38 where internal_transform
receives the plain loop counter over node.childNodes (all siblings). A nested
<Transform> that is the Nth child of a <Text> therefore gets index = N. Both
spots use the same index basis so paint and measurement agree. Refines the
earlier G06 refutation — the inline/squash path was the real gap.

Also adds the `innerText.length > 0` guard in text-measure.ts flattenLeaves so
measurement skips transforms on empty text (matching paint.ts and Ink:34), and
converts screen-reader.ts squashTextContent to use forEach-with-index so the
nested-Transform index is correct in SR mode too (was hardcoded 0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(parity): ledger — G21 pr-open, reconcile G20 merged

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Yunfei He
2026-05-30 07:01:26 +08:00
committed by GitHub
parent b4787ba277
commit fb6fe16022
7 changed files with 106 additions and 12 deletions
+2 -2
View File
@@ -54,8 +54,8 @@ Non-obvious calls made while fixing gaps, recorded for review in the final repor
| G17 | render-lifecycle-reconciler | Screen-reader live-path edges: <Static> still grid-painted (Ink linearizes, skipStaticElements:false) + empty SR frame gets a trailing newline (Ink writes wrapped output directly) | P3 | merged | `fix/parity-sr-edges` | #45 |
| G18 | render-lifecycle-reconciler | No signal-based teardown — terminal corrupted on SIGINT/SIGTERM/SIGHUP (Ink signal-exit at mount) | P1 | merged | `fix/parity-signal-teardown` | #47 |
| G19 | box-layout-border | Dynamic removal of most yoga style props does not reset to default (stale layout) | P2 | merged | `fix/parity-yoga-reset` | #48 |
| G20 | stdout-stderr-stdin-size-cursor | writeToStdout/writeToStderr lack an isUnmounted/teardown guard (post-teardown writes corrupt terminal) | P2 | pr-open | `fix/parity-write-after-unmount` | #49 |
| G21 | text-wrap-transform | Nested <Transform> in <Text> gets hardcoded index 0 vs child sibling position (squash path) | P3 | todo | — | — |
| G20 | stdout-stderr-stdin-size-cursor | writeToStdout/writeToStderr lack an isUnmounted/teardown guard (post-teardown writes corrupt terminal) | P2 | merged | `fix/parity-write-after-unmount` | #49 |
| G21 | text-wrap-transform | Nested <Transform> in <Text> gets hardcoded index 0 vs child sibling position (squash path) | P3 | pr-open | `fix/parity-transform-index` | #50 |
| G22 | app-exit-instances-animation-sr | SR role dedup inherits grandparent role; Ink dedups only vs immediate parent | P3 | todo | — | — |
| G23 | app-exit-instances-animation-sr | <Transform> under <Box> SR-joins children with newline; Ink concatenates | P3 | todo | — | — |
| G24 | render-lifecycle-reconciler | Renders ALL <Static> nodes; Ink renders only the most-recent staticNode (multi-Static support — candidate) | P3 | candidate | — (see ink-parity.md) | — |