diff --git a/src/components/PaneRow.tsx b/src/components/PaneRow.tsx index 16158bd..2a8d566 100644 --- a/src/components/PaneRow.tsx +++ b/src/components/PaneRow.tsx @@ -1,15 +1,15 @@ /** * PaneRow — the shared parent | current | preview 3-pane layout primitive. * - * Implements yazi's `mgr.ratio = [1, 2, 2]` contract: three columns grow at - * 1/5 : 2/5 : 2/5 of the row width via Yoga `flexGrow`, so every list tab - * renders an identical, layout-stable shell. Columns use `flexBasis={0}` so - * the ratio is exact regardless of content width — a column's content can - * never stretch its slot. + * Implements yazi's `mgr.ratio` contract: three columns grow at + * 20% : 50% : 30% (PANE_RATIO 2:5:3) of the row width via Yoga `flexGrow`, + * so every list tab renders an identical, layout-stable shell. Columns use + * `flexBasis={0}` so the ratio is exact regardless of content width — a + * column's content can never stretch its slot. * * Column semantics (per the yazi depth model): * parent — the previous-depth list. Renders a muted `—` placeholder and - * KEEPS its 1/5 slot when blank (never collapses to width 0). + * KEEPS its 20% slot when blank (never collapses to width 0). * Borderless (no left/right/top/bottom edge). Carries the single * header row: the CURRENT column's title renders top-left in the * parent's slot (the panes above current/preview were removed). @@ -184,7 +184,7 @@ export function PaneRow(props: PaneRowProps) { return ( - {/* ── parent (1/5) — previous-depth list; title row top-left ───────── */} + {/* ── parent (20%) — previous-depth list; title row top-left ────────── */} focused()} /> - {/* ── preview (2/5) — hovered-item detail; no border, no header ────── */} + {/* ── preview (30%) — hovered-item detail; no border, no header ────── */} { } }); -// ── Unit: three columns at 1:2:2 regardless of null children ─────────────── +// ── Unit: three columns at 2:5:3 regardless of null children ─────────────── describe("PaneRow layout", () => { - test("renders three columns at 1:2:2 even with null parent/preview", async () => { + test("renders three columns at 2:5:3 even with null parent/preview", async () => { const { spans, destroy } = await renderPaneRow({ parent: null, current: () => ITEM, @@ -132,15 +132,15 @@ describe("PaneRow layout", () => { const widths = columnWidths(spans); expect(widths).toHaveLength(3); const [p, c, v] = widths; - // 100-wide row splits as 20 / 40 / 40 (1/5 : 2/5 : 2/5). + // 100-wide row splits as 20 / 50 / 30 (2 : 5 : 3 of 10). expect(p).toBe(20); - expect(c).toBe(40); - expect(v).toBe(40); - // Exact 1:2:2 proportion (within 1 col rounding). - expect(c).toBeGreaterThanOrEqual(p * 2 - 1); - expect(c).toBeLessThanOrEqual(p * 2 + 1); - expect(v).toBeGreaterThanOrEqual(p * 2 - 1); - expect(v).toBeLessThanOrEqual(p * 2 + 1); + expect(c).toBe(50); + expect(v).toBe(30); + // Exact 2:5:3 proportion (within 1 col rounding). + expect(c).toBeGreaterThanOrEqual(Math.round(p * 2.5) - 1); + expect(c).toBeLessThanOrEqual(Math.round(p * 2.5) + 1); + expect(v).toBeGreaterThanOrEqual(Math.round(p * 1.5) - 1); + expect(v).toBeLessThanOrEqual(Math.round(p * 1.5) + 1); // Parent keeps a visibly non-zero slot and renders the muted placeholder. expect(p).toBeGreaterThan(4); const body = spans.lines @@ -150,7 +150,7 @@ describe("PaneRow layout", () => { expect(body).toContain("ITEM"); }); - test("keeps the 1/5 parent slot across widths (ratio stable)", async () => { + test("keeps the 20% parent slot across widths (ratio stable)", async () => { const { spans, destroy } = await renderPaneRow({ parent: null, current: () => x, @@ -159,9 +159,9 @@ describe("PaneRow layout", () => { }); cleanups.push(destroy); const [p, c, v] = columnWidths(spans); - expect(p).toBe(14); // 70 → 14 / 28 / 28 - expect(c).toBe(28); - expect(v).toBe(28); + expect(p).toBe(14); // 70 → 14 / 35 / 21 + expect(c).toBe(35); + expect(v).toBe(21); }); }); @@ -181,9 +181,9 @@ describe("PaneRow current-pane borders", () => { }); cleanups.push(destroy); - // 100-wide row splits as 20 / 40 / 40: the current pane's edges sit at - // columns 20 and 59. No horizontal or corner glyphs — edges only. - expect(borderColumns(spans)).toEqual([20, 59]); + // 100-wide row splits as 20 / 50 / 30: the current pane's edges sit at + // columns 20 and 69. No horizontal or corner glyphs — edges only. + expect(borderColumns(spans)).toEqual([20, 69]); expect(frameText(spans)).not.toMatch(boxGlyphs); }); @@ -196,7 +196,7 @@ describe("PaneRow current-pane borders", () => { }); cleanups.push(destroy); - expect(borderColumns(spans)).toEqual([20, 59]); + expect(borderColumns(spans)).toEqual([20, 69]); expect(frameText(spans)).not.toMatch(boxGlyphs); }); @@ -208,7 +208,7 @@ describe("PaneRow current-pane borders", () => { focused: () => true, }); cleanups.push(destroy); - expect(borderColumns(spans)).toEqual([20, 59]); + expect(borderColumns(spans)).toEqual([20, 69]); expect(frameText(spans)).not.toMatch(boxGlyphs); const { spans: spans2, destroy: destroy2 } = await renderPaneRow({ @@ -218,7 +218,7 @@ describe("PaneRow current-pane borders", () => { focused: () => false, }); cleanups.push(destroy2); - expect(borderColumns(spans2)).toEqual([20, 59]); + expect(borderColumns(spans2)).toEqual([20, 69]); expect(frameText(spans2)).not.toMatch(boxGlyphs); }); @@ -229,7 +229,7 @@ describe("PaneRow current-pane borders", () => { preview: null, }); cleanups.push(destroy); - expect(borderColumns(spans)).toEqual([20, 59]); + expect(borderColumns(spans)).toEqual([20, 69]); expect(frameText(spans)).not.toMatch(boxGlyphs); }); });