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