fix(runtime): <Transform> with no children renders no node, matching Ink (#105)
Ink's <Transform> returns null (no node) when children are undefined/null, and
that guard runs BEFORE the accessibilityLabel substitution (Transform.tsx:28-30).
vue always created a "transform" host node, so:
- an empty <Transform> in a flex `gap` row consumed a gap slot Ink never adds (P13); and
- a childless <Transform accessibilityLabel> emitted the label even though Ink's
null guard wins over it (P19).
Add the null-children guard at the top of the render fn. Vue materializes a bare
null/false/undefined/v-if=false child as a single Comment vnode and cannot tell them
apart, so the predicate treats the whole group as "no children" (slot undefined OR
every vnode is a Comment) — matching Ink for the common `{null}`/`{cond ? x : null}`
idioms and keeping <Transform> consistent with vue-tui's documented comment-anchor
model (every other component already omits a false/v-if child). An empty-string ({''},
a Text vnode) or JSX empty array ({[]}, a Fragment) still renders, matching Ink.
This deliberately diverges from Ink only for a literal {false} / {cond && x}-false
child (React's false !== null → Ink renders an empty gap-slot node); documented in
ink-divergences.md and locked by a test, since Vue physically cannot distinguish it
from null.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -145,7 +145,14 @@ built never reaches the terminal:
|
||||
- **A `v-if=false` branch (or a `null`/`false`/`undefined` child) leaves a comment anchor
|
||||
(`TuiComment`)** where Ink emits no node, but it is inert: no yoga node, paints nothing,
|
||||
never shifts a sibling's yoga index, and is skipped for the positional `<Transform>` index
|
||||
in all three squash paths (`G52`). Output equals omitting the element.
|
||||
in all three squash paths (`G52`). Output equals omitting the element. This also governs
|
||||
`<Transform>`'s own children guard: a childless `<Transform>` (or one whose only child is a
|
||||
`null`/`false`/`v-if=false` comment anchor) renders **no node** (matching Ink for `null`,
|
||||
consistent with every other component). It diverges from Ink only for a literal `{false}` /
|
||||
`{cond && x}`-false child — React's `false !== null`, so Ink renders an empty node (and a gap
|
||||
slot); Vue collapses `false`/`null` to the same `TuiComment` and cannot distinguish them, so
|
||||
it omits the node. Keeping `<Transform>` consistent with the comment-anchor model is the
|
||||
principled choice.
|
||||
- **Commit timing is deliberately Ink-aligned** — leading+trailing throttle at
|
||||
`ceil(1000/maxFps)` ≈ 32 ms (Ink's `renderThrottleMs`), synchronous resize — even though
|
||||
re-renders are Vue's fine-grained reactivity, not a React subtree re-render.
|
||||
|
||||
Reference in New Issue
Block a user