fix(paint): continuous backgroundColor across wrapped text lines

- Wrap each text line with applyChalk(bgProps) after wrapText so
  background color is reapplied on every wrapped line (wrap-ansi
  doesn't carry ANSI state across line breaks)
- Add wrapped-text backgroundColor regression test
- Fix typo: color=" cyan" → color="cyan" in example
- Add FORCE_COLOR=3 debugging tip to AGENTS.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yunfei He
2026-05-25 11:31:00 +08:00
parent e62c802829
commit ca25ccd96e
4 changed files with 21 additions and 5 deletions
+1
View File
@@ -5,6 +5,7 @@
- Always use `defineComponent()` to define components. Never use bare `{ setup() {} }` objects — they lack component scope, so `inject`, `watch`, and `onScopeDispose` won't work correctly.
- Vue SFCs must use `<script setup>` unless there's an explicit reason not to.
- Bug fixes must follow test-first: write a failing test that reproduces the bug, then fix the code and verify the test passes.
- When debugging color/ANSI output in non-TTY environments (e.g. Claude Code shell), use `FORCE_COLOR=3` env var to force chalk to output ANSI codes.
- After completing any task, run `vp run ready` (or `vpr ready`) to verify: lint, type-check, test all packages, and build.
<!--VITE PLUS START-->
+1 -1
View File
@@ -13,7 +13,7 @@ useInput((input) => {
</script>
<template>
<Box flexDirection="column" :paddingX="1">
<Box backgroundColor="blue" borderStyle="round" width="20">
<Text bold color="cyan">vue-tui basic (template)</Text>
<Text dimColor>Try editing Counter.vue or App.vue</Text>
<Text dimColor>Press c=toggle clock, q=quit</Text>
@@ -45,3 +45,19 @@ test("child Text inherits backgroundColor from parent Box", async () => {
expect(raw).toContain("hello");
expect(raw).toContain(BG_BLUE);
});
test("wrapped text preserves backgroundColor on every line", async () => {
const { frames } = await render(
() => (
<Box backgroundColor="blue" borderStyle="single" width={10} height={4}>
<Text>long text here</Text>
</Box>
),
{ columns: 20 },
);
const raw = frames.at(-1)!;
const lines = raw.split("\n").filter(Boolean);
for (const line of lines) {
expect(line).toContain(BG_BLUE);
}
});
+3 -4
View File
@@ -217,10 +217,9 @@ function paintNode(
const wrapped = wrapText(text, cellWidth, node.props.wrap ?? "wrap");
if (inheritedBg) {
for (let i = 0; i < wrapped.length; i++) {
const lineW = stringWidth(wrapped[i]!);
if (lineW < cellWidth) {
wrapped[i] = wrapped[i]! + applyChalk(" ".repeat(cellWidth - lineW), bgProps);
}
const pad = cellWidth - stringWidth(wrapped[i]!);
const padStr = pad > 0 ? " ".repeat(pad) : "";
wrapped[i] = applyChalk(wrapped[i]! + padStr, bgProps);
}
}
output.write(x0 + layout.left, y0 + layout.top, wrapped, transformers);