feat(CompareBoard): add fitColumns honest column gating
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
import {
|
||||||
|
describe,
|
||||||
|
expect,
|
||||||
|
it,
|
||||||
|
} from 'vitest';
|
||||||
|
import { fitColumns } from './fitColumns';
|
||||||
|
|
||||||
|
describe('fitColumns', () => {
|
||||||
|
it('packs as many honest columns as fit, gap-aware', () => {
|
||||||
|
// each needs 600, gap 40, available 1280 -> 1 col=600, 2 cols=1240, 3=1880
|
||||||
|
expect(fitColumns({ naturalWidth: 600, available: 1280, gap: 40, maxColumns: 3 })).toBe(2);
|
||||||
|
});
|
||||||
|
it('never exceeds maxColumns even with room', () => {
|
||||||
|
expect(fitColumns({ naturalWidth: 100, available: 5000, gap: 20, maxColumns: 3 })).toBe(3);
|
||||||
|
});
|
||||||
|
it('never returns less than 1', () => {
|
||||||
|
expect(fitColumns({ naturalWidth: 9000, available: 300, gap: 20, maxColumns: 3 })).toBe(1);
|
||||||
|
});
|
||||||
|
it('fits a column at the exact boundary (inclusive)', () => {
|
||||||
|
// 2 cols: 2*600 + 1*40 = 1240 == available -> fits
|
||||||
|
expect(fitColumns({ naturalWidth: 600, available: 1240, gap: 40, maxColumns: 3 })).toBe(2);
|
||||||
|
// one px short -> only 1
|
||||||
|
expect(fitColumns({ naturalWidth: 600, available: 1239, gap: 40, maxColumns: 3 })).toBe(1);
|
||||||
|
});
|
||||||
|
it('respects a maxColumns of 1 even with unlimited room', () => {
|
||||||
|
expect(fitColumns({ naturalWidth: 100, available: 5000, gap: 20, maxColumns: 1 })).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Inputs for column gating.
|
||||||
|
*/
|
||||||
|
export interface FitColumnsInput {
|
||||||
|
/**
|
||||||
|
* The widest pairing's Pretext natural (shrink-wrap) width in px.
|
||||||
|
*/
|
||||||
|
naturalWidth: number;
|
||||||
|
/**
|
||||||
|
* Total available width in px for the columns row.
|
||||||
|
*/
|
||||||
|
available: number;
|
||||||
|
/**
|
||||||
|
* Gap in px between columns.
|
||||||
|
*/
|
||||||
|
gap: number;
|
||||||
|
/**
|
||||||
|
* Hard cap on columns that still preserve an honest measure (2–3).
|
||||||
|
*/
|
||||||
|
maxColumns: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many equal honest columns fit. Uses the real per-pairing required width
|
||||||
|
* (Pretext shrink-wrap) — the 45–75ch rule is only a fallback bound elsewhere.
|
||||||
|
* `n` columns occupy `n*naturalWidth + (n-1)*gap`. Clamped to [1, maxColumns].
|
||||||
|
*
|
||||||
|
* @param input - Natural width, available width, gap, and column cap.
|
||||||
|
* @returns The number of columns that fit, in [1, maxColumns].
|
||||||
|
*/
|
||||||
|
export function fitColumns({ naturalWidth, available, gap, maxColumns }: FitColumnsInput): number {
|
||||||
|
let fit = 1;
|
||||||
|
for (let n = 2; n <= maxColumns; n++) {
|
||||||
|
if (n * naturalWidth + (n - 1) * gap <= available) {
|
||||||
|
fit = n;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fit;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export {
|
||||||
|
fitColumns,
|
||||||
|
type FitColumnsInput,
|
||||||
|
} from './fitColumns';
|
||||||
|
export {
|
||||||
|
measureRoleHeight,
|
||||||
|
type RoleHeightInput,
|
||||||
|
} from './measureFrameHeight';
|
||||||
Reference in New Issue
Block a user