diff --git a/src/__tests__/component-boundary-layout.test.ts b/src/__tests__/component-boundary-layout.test.ts index a024707..bc7a29a 100644 --- a/src/__tests__/component-boundary-layout.test.ts +++ b/src/__tests__/component-boundary-layout.test.ts @@ -203,3 +203,65 @@ describe("commitUpdate layout cache invalidation", () => { expect(result2.lines[1]).toContain("B"); }); }); + +describe("Single-side borders on a one-row box", () => { + const SIDE = { + borderStyle: "single" as const, + borderTop: false, + borderBottom: false, + borderRight: false, + }; + + /** Two columns side by side, the right one carrying a left border. */ + const split = (lines: readonly string[]) => + React.createElement( + Box, + { flexDirection: "column", width: 40, height: 6 }, + React.createElement(Text, null, "header"), + React.createElement( + Box, + { flexDirection: "row", width: 40 }, + React.createElement( + Box, + { width: 10 }, + React.createElement(Text, null, "left"), + ), + React.createElement( + Box, + { width: 12, flexDirection: "column", ...SIDE, borderLeft: true }, + ...lines.map((line) => React.createElement(Text, { key: line }, line)), + ), + ), + ); + + it("draws a left border when the box is only one row tall", () => { + // A left-only border is a single vertical bar, so it is drawable at any + // height. The 2x2 minimum belongs to a border that draws BOTH sides of an + // axis; applying it here dropped the divider from every one-row column. + const { output } = renderToString(split(["one"]), { width: 40, height: 6 }); + expect(output.split("\n")[1]).toContain("│"); + }); + + it("draws it at two rows as well, so the fix is not height-specific", () => { + const { output } = renderToString(split(["one", "two"]), { + width: 40, + height: 6, + }); + expect(output.split("\n")[1]).toContain("│"); + }); + + it("still refuses a full border that cannot fit its own sides", () => { + // The guard is not gone, only narrowed: a box one column wide cannot hold + // a left AND a right border, and must draw neither. + const { output } = renderToString( + React.createElement( + Box, + { flexDirection: "column", width: 40, height: 4 }, + React.createElement(Box, { width: 1, borderStyle: "single" as const }, + React.createElement(Text, null, "x")), + ), + { width: 40, height: 4 }, + ); + expect(output).not.toContain("│"); + }); +}); diff --git a/src/reconciler/renderer.ts b/src/reconciler/renderer.ts index d761c03..7e5f148 100644 --- a/src/reconciler/renderer.ts +++ b/src/reconciler/renderer.ts @@ -1276,7 +1276,13 @@ function paintBorder( dimFlags: BorderDimFlags = NO_DIM, inheritedBg: number = DEFAULT_COLOR, ): void { - if (style === "none" || width < 2 || height < 2) return; + // Two cells are needed only on an axis that draws BOTH of its sides. A + // left-only border is a single vertical bar, drawable at height 1, which is + // exactly what a one-row column is; the same holds for a top-only border at + // width 1. + const minWidth = sides.left && sides.right ? 2 : 1; + const minHeight = sides.top && sides.bottom ? 2 : 1; + if (style === "none" || width < minWidth || height < minHeight) return; const chars = BORDER_CHARS[style]; const fg = color; const bg = DEFAULT_COLOR;