Merge origin/main (CI quality gates) into the 1.1.0 release

# Conflicts:
#	package-lock.json
#	src/views/NewInvoice.tsx
This commit is contained in:
2026-10-06 09:43:47 +05:30
52 changed files with 6100 additions and 1080 deletions
-2
View File
@@ -15,8 +15,6 @@ export const REVERSE_GAP = 4;
export const HEADING_AFTER = 4;
/** Space between the closing block's two columns. */
export const CLOSING_COLUMN_GAP = 16;
/** Slate: space between a mark and the business name in the dark band. */
const NAME_AFTER_LOGO = 7.8;
/** Space above and below the thin rule that separates the stack from TOTAL. */
export const STACK_RULE = { before: 2, after: 8, thickness: 0.75 };
const MIN_NAME_W = 40;
+2 -10
View File
@@ -1,17 +1,9 @@
import { mkdirSync, writeFileSync } from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
import type { AuditIssue } from "../engine/audit";
import { PAGE_SIZES } from "../engine/geometry";
import { PAGE_LABEL_ID, TABLE_HEAD_ID, TABLE_ROW_PREFIX, CLOSING_ID, TOTALS_ID } from "../engine/ids";
import { walk, type LayoutNode, type LayoutPage, type Rect } from "../engine/layoutTree";
import { forbiddenProbe, SLOT_RULES, slotContent, type SlotName } from "../model/slots";
import { frameForPrefs, renderInvoicePdf } from "../render/invoice";
import { loadCanvas, pagePng } from "../testing/rasterize";
import { SLOT_ID } from "../blocks/slots";
import { META_ID, SUPPLIER_ID, TITLE_ID } from "./classic/ids";
import { HEADER_GAP, headerCols } from "./classic/plan";
import { FIXTURE_GSTIN, FIXTURES, buildFixture, ensureSetup, makeItems, PAGE_SIZE_IDS, prefsFor, renderFixture, type FixtureSpec, type Rendered } from "./harness";
import { renderInvoicePdf } from "../render/invoice";
import { FIXTURES, buildFixture, ensureSetup, PAGE_SIZE_IDS, prefsFor, renderFixture, type FixtureSpec } from "./harness";
import { TEMPLATES } from "./registry";
/**
+1 -1
View File
@@ -1,6 +1,6 @@
import { Image, View } from "@react-pdf/renderer";
import type { ReactNode } from "react";
import { colsDetailed, pinned } from "../../engine/columns";
import { pinned } from "../../engine/columns";
import { CLOSING_ID, TABLE_HEAD_ID, TABLE_ROW_PREFIX, TOTALS_ID } from "../../engine/ids";
import { AvailableWidthProvider } from "../../blocks/AvailableWidth";
import { BottomSpacer } from "../../blocks/BottomSpacer";
+1 -1
View File
@@ -202,7 +202,7 @@ function Parties({ ctx }: { ctx: Ctx }) {
const blocks: ReactNode[] = [<ClientBlock key="a" ctx={ctx} width={text[0]} />];
let k = 1;
if (plan.info.hasBank) blocks.push(<PayableBlock key="b" ctx={ctx} width={text[k++]} />);
if (plan.info.hasIds) blocks.push(<IdsBlock key="c" ctx={ctx} width={text[k++]} />);
if (plan.info.hasIds) blocks.push(<IdsBlock key="c" ctx={ctx} width={text[k]} />);
const specs: ColSpec[] = cols.map((w, i) => (i === cols.length - 1 ? { fill: true } : { fixed: w }));
return (
<View style={{ ...pinned(plan.W), paddingLeft: v.inset.left } as never}>
+1 -1
View File
@@ -151,7 +151,7 @@ export function planMarble(model: RenderModel, frame: PageFrame, v: MarbleVarian
let k = 0;
const clientW = textW(k++);
const bankW = hasBank ? textW(k++) : 0;
const idsW = hasIds ? textW(k++) : 0;
const idsW = hasIds ? textW(k) : 0;
const head = leading(r.heading) + v.parties.headingGap;
let clientH = head + textHeight(r.body, c.name, clientW);
for (const l of c.addressLines) clientH += textHeight(r.body, l, clientW);
+1 -1
View File
@@ -295,7 +295,7 @@ export function planNeutral(model: RenderModel, frame: PageFrame, v: NeutralVari
for (const l of lines) payH += textHeight(r.address, l, payW);
}
if (v.id === "serenity") signH += leading(r.label) + 4;
let closingH = 0;
let closingH: number;
if (v.payTo.where === "closing") closingH = Math.max(payH, signH);
else closingH = signH;
if (model.cancelled) closingH += 10 + textHeight(r.small, CANCELLED_SENTENCE, W);