feat(CompareBoard): add measureRoleHeight via Pretext line count
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
import {
|
||||||
|
describe,
|
||||||
|
expect,
|
||||||
|
it,
|
||||||
|
vi,
|
||||||
|
} from 'vitest';
|
||||||
|
import { measureRoleHeight } from './measureFrameHeight';
|
||||||
|
|
||||||
|
describe('measureRoleHeight', () => {
|
||||||
|
it('multiplies pretext line count by sizePx*lineHeight', () => {
|
||||||
|
const layout = vi.fn().mockReturnValue({ lineCount: 3, height: 0 });
|
||||||
|
const prepared = {} as never;
|
||||||
|
// 3 lines * 20px * 1.5 = 90
|
||||||
|
expect(measureRoleHeight({ prepared, maxWidth: 600, sizePx: 20, lineHeight: 1.5 }, layout)).toBe(90);
|
||||||
|
});
|
||||||
|
it('passes width and pixel line-height into pretext layout', () => {
|
||||||
|
const layout = vi.fn().mockReturnValue({ lineCount: 1, height: 0 });
|
||||||
|
measureRoleHeight({ prepared: {} as never, maxWidth: 600, sizePx: 16, lineHeight: 1.25 }, layout);
|
||||||
|
expect(layout).toHaveBeenCalledWith(expect.anything(), 600, 16 * 1.25);
|
||||||
|
});
|
||||||
|
it('returns 0 when the text lays out to zero lines (empty specimen)', () => {
|
||||||
|
const layout = vi.fn().mockReturnValue({ lineCount: 0, height: 0 });
|
||||||
|
expect(measureRoleHeight({ prepared: {} as never, maxWidth: 600, sizePx: 16, lineHeight: 1.5 }, layout))
|
||||||
|
.toBe(0);
|
||||||
|
});
|
||||||
|
it('handles fractional sizes and line-heights without rounding', () => {
|
||||||
|
const layout = vi.fn().mockReturnValue({ lineCount: 2, height: 0 });
|
||||||
|
// 2 * 15.5 * 1.4 = 43.4
|
||||||
|
expect(measureRoleHeight({ prepared: {} as never, maxWidth: 320, sizePx: 15.5, lineHeight: 1.4 }, layout))
|
||||||
|
.toBeCloseTo(43.4);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import {
|
||||||
|
type PreparedText,
|
||||||
|
layout as pretextLayout,
|
||||||
|
} from '@chenglou/pretext';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inputs for measuring one role block's rendered height.
|
||||||
|
*/
|
||||||
|
export interface RoleHeightInput {
|
||||||
|
/**
|
||||||
|
* Pretext-prepared specimen text for this role+font.
|
||||||
|
*/
|
||||||
|
prepared: PreparedText;
|
||||||
|
/**
|
||||||
|
* Available width in px (the focal frame's content width).
|
||||||
|
*/
|
||||||
|
maxWidth: number;
|
||||||
|
/**
|
||||||
|
* Resolved font-size in px.
|
||||||
|
*/
|
||||||
|
sizePx: number;
|
||||||
|
/**
|
||||||
|
* Unitless line-height multiplier.
|
||||||
|
*/
|
||||||
|
lineHeight: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Height in px of a role's text block at the given width, from Pretext's
|
||||||
|
* pure-arithmetic line count.
|
||||||
|
*
|
||||||
|
* Height is `lineCount * sizePx * lineHeight` rather than Pretext's own
|
||||||
|
* `height` so it tracks the CSS box model exactly (line-height as a multiple of
|
||||||
|
* font-size), keeping measurement and render in lockstep — the zero-shift
|
||||||
|
* invariant.
|
||||||
|
*
|
||||||
|
* @param input - Prepared text plus width and resolved type metrics.
|
||||||
|
* @param layout - Pretext layout fn; injectable for unit tests, defaults to
|
||||||
|
* `@chenglou/pretext`'s `layout`.
|
||||||
|
* @returns The block height in px.
|
||||||
|
*/
|
||||||
|
export function measureRoleHeight(input: RoleHeightInput, layout = pretextLayout): number {
|
||||||
|
const { prepared, maxWidth, sizePx, lineHeight } = input;
|
||||||
|
const { lineCount } = layout(prepared, maxWidth, sizePx * lineHeight);
|
||||||
|
return lineCount * sizePx * lineHeight;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user