Add typography roles, text primitives, fontkit measurer and layout lint

Txt always sets an absolute line height; RenderTxt never does. Row pins
every cell and stacks when the fill column would be too narrow. IdText and
FitText shrink then chunk or truncate. The fontkit measurer matches react-pdf
text widths exactly. A TypeScript-AST lint test enforces the layout rules
(no lineHeight outside Txt, no non-literal fixed/wrap/minPresenceAhead,
flexGrow needs flexBasis, no stray absolute positioning).
This commit is contained in:
2026-10-04 04:48:19 +05:30
parent bf4b85563b
commit 3818b1eeed
22 changed files with 1375 additions and 34 deletions
+3 -4
View File
@@ -4,7 +4,8 @@ import path from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import { InvoiceDocument, type InvoicePdfProps } from "./InvoiceDocument";
import { registerPdfFonts } from "./fonts";
import { describeBox, findOverlaps, renderPdfText, type RenderedPdf, type TextBox } from "./testing/pdfText";
import { assertNoOverlap } from "./testing/asserts";
import { describeBox, renderPdfText, type RenderedPdf, type TextBox } from "./testing/pdfText";
import type { BankAccount, InvoiceItem, Settings } from "../lib/types";
registerPdfFonts(path.resolve(process.cwd(), "public/fonts"));
@@ -146,12 +147,10 @@ const textOf = (items: TextBox[]) => items.map((t) => t.str).join(" ");
function checkCommon(pdf: RenderedPdf) {
const n = pdf.pages.length;
expect(pdf.raw).not.toContain("/BaseFont /Helvetica");
assertNoOverlap(pdf.pages);
pdf.pages.forEach((page, idx) => {
const k = idx + 1;
const overlaps = findOverlaps(page).map(([a, b]) => `${describeBox(a)} x ${describeBox(b)}`);
expect(overlaps, `page ${k} overlaps`).toEqual([]);
for (const t of page.items) {
const isFooter = t.top > 780;
expect(t.x0, `page ${k} ${describeBox(t)} left`).toBeGreaterThanOrEqual(MARGIN_L);