fix(runtime): skip eager visual validation under screen-reader mode (Ink parity) (#197)
assertBoxValid (Box) and text.vue's validate() run eager render-time validation of paint-time VISUAL props (backgroundColor, border fg/bg colors, borderStyle shape) and throw into the error boundary on an invalid value (e.g. a chalk modifier name like "bold" used as a color). They were gated only by the per-node ariaHidden skip (srHidden), not by GLOBAL screen-reader mode. Under global SR mode (isScreenReaderEnabled; INK_SCREEN_READER=true) vue-tui, like Ink, linearizes the whole tree to PLAIN TEXT and never colorizes / draws borders for any node — Ink's colorize path is bypassed entirely, so it never throws on an invalid color. vue-tui still ran the eager validation for non- ariaHidden boxes under SR and threw, crashing a screen-reader user out of accessible content over a paint-only prop value. Skip the eager visual validation when global SR is on, in addition to the existing per-node srHidden skip: box.vue gates `!srHidden && (srEnabled || assertBoxValid(props))`, text.vue gates `!srHidden && (srEnabled || validate()) && hasContent`. The validation is all paint-time visual input (no structural checks), so skipping it under SR is safe and matches Ink. Verified against real Ink v7.0.4: with INK_SCREEN_READER=true a <Box backgroundColor="bold"> renders plain text and does NOT throw; without it Ink throws in colorize.js. This is an alignment fix (removes a vue-tui over-throw), not a new divergence — the existing ink-divergences entry gets a factual, unstamped note about the SR carve-out. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -748,6 +748,19 @@ different runtime behavior, ownership rule, or out-of-contract handling.
|
||||
content, and content-gated validation is a latent footgun. Principle: reasonable behavior
|
||||
over incidental Ink parity. The former `wouldRenderNonEmptyText` gate was removed.
|
||||
Screen-reader-hidden Text still returns before validation (matches Box). [VOUCHED @hyf0]
|
||||
- **Global screen-reader mode is carved out (skipped) — ALIGNS to Ink, not a new
|
||||
divergence:** all of the above validation is paint-time VISUAL input (color / bg /
|
||||
border), and under GLOBAL screen-reader mode (`isScreenReaderEnabled`;
|
||||
`INK_SCREEN_READER=true`) vue-tui — like Ink — linearizes the whole tree to PLAIN TEXT
|
||||
and never colorizes / draws borders for any node. Ink's colorize path is bypassed
|
||||
entirely under SR, so it never throws on an invalid color (run-verified against Ink
|
||||
v7.0.4: `<Box backgroundColor="bold">` with `INK_SCREEN_READER=true` renders plain text
|
||||
and does NOT throw; without it Ink throws in `colorize.js`). vue-tui previously still ran
|
||||
the eager validation for non-`ariaHidden` boxes under SR and threw — crashing a
|
||||
screen-reader user out of accessible content over a paint-only prop value. The validation
|
||||
is now skipped when global SR is on (`box.vue` / `text.vue` v-if gate on `srEnabled`),
|
||||
matching Ink. This removes a vue-tui over-throw and so is an alignment fix, not a new
|
||||
divergence. Tests: the "GLOBAL SR" cases in `background-color.test.tsx`.
|
||||
|
||||
## Non-Behavioral Notes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user