fix(runtime): reset yoga props to default on dynamic removal (Ink parity, G19) (#48)

* fix(runtime): reset yoga props to default on dynamic removal (Ink parity, G19)

Removed style props now reset to the yoga default (margin/padding/min/gap/flexGrow→0, flexShrink→1, flexBasis→auto, flexDirection→ROW, flexWrap→NO_WRAP, alignItems→STRETCH, alignSelf→AUTO, justifyContent→FLEX_START, position→RELATIVE) instead of keeping a stale value — matches Ink's reconciler diff + styles.ts.

The fix threads the previous prop value (prev) from patchProp into applyYogaProp so that resets only fire on genuine removals (prev is a real value, not null/undefined from Vue's initial-mount or never-set patches). RESETTABLE_PROPS is extended with all newly resettable keys.

Follow-up blocker fixes:
- marginX/marginY/paddingX/paddingY now map to Yoga.EDGE_HORIZONTAL/EDGE_VERTICAL (matching Ink styles.ts) instead of concrete EDGE_START/END/TOP/BOTTOM. They compose with the specific edges per yoga precedence, so removing an axis shorthand no longer clobbers a surviving marginLeft/etc.
- applyYogaProp and all setters now treat null the same as undefined (value == null) for the removal/reset path. Vue's host renderer passes next=null (not undefined) when a key disappears from a spread props object (e.g. Static spreads style into host props), which previously bypassed the reset and forwarded raw null into yoga (NaN/0 corruption).

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

* chore(parity): ledger — G19 pr-open, reconcile G18 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 06:31:39 +08:00
committed by GitHub
parent 216a7021a0
commit 2c597e7169
5 changed files with 443 additions and 58 deletions
+2 -2
View File
@@ -52,8 +52,8 @@ Non-obvious calls made while fixing gaps, recorded for review in the final repor
| G15 | box-layout-border | Vertical border sides not shifted up when borderTop=false (Ink offsetY) — left/right rails mispositioned | P2 | merged | `fix/parity-border-1cell` | #37 |
| G16 | box-layout-border | Per-edge borderDimColor=false cannot override general borderDimColor (`\|\| dimAll` vs Ink's `??`) | P3 | merged | `fix/parity-border-dim` | #44 |
| 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 | pr-open | `fix/parity-signal-teardown` | #47 |
| G19 | box-layout-border | Dynamic removal of most yoga style props does not reset to default (stale layout) | P2 | todo | — | — |
| 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 | pr-open | `fix/parity-yoga-reset` | #48 |
| G20 | stdout-stderr-stdin-size-cursor | writeToStdout/writeToStderr lack an isUnmounted/teardown guard (post-teardown writes corrupt terminal) | P2 | todo | — | — |
| G21 | text-wrap-transform | Nested <Transform> in <Text> gets hardcoded index 0 vs child sibling position (squash path) | P3 | todo | — | — |
| G22 | app-exit-instances-animation-sr | SR role dedup inherits grandparent role; Ink dedups only vs immediate parent | P3 | todo | — | — |