Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/__tests__/component-boundary-layout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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("│");
});
});
8 changes: 7 additions & 1 deletion src/reconciler/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down