Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 4 additions & 21 deletions packages/layout-engine/contracts/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { cloneColumnLayout, extractHeaderFooterSpace, normalizeColumnLayout, widthsEqual } from './index.js';
import type { FlowBlock, Layout, PainterDOM, PainterPDF } from './index.js';
import type { FlowBlock, Layout } from './index.js';

describe('contracts', () => {
it('accepts a basic FlowBlock structure', () => {
Expand All @@ -20,7 +20,7 @@ describe('contracts', () => {
expect(block.id).toBe('block-1');
});

it('describes a minimal layout', async () => {
it('describes a minimal layout', () => {
const layout: Layout = {
pageSize: { w: 612, h: 792 },
pages: [
Expand Down Expand Up @@ -62,25 +62,8 @@ describe('contracts', () => {
},
};

const domPainter: PainterDOM = {
paint(received, mount) {
mount.dataset.pageCount = String(received.pages.length);
},
};

const pdfPainter: PainterPDF = {
async render(received) {
expect(received.pages.length).toBeGreaterThan(0);
return new Blob([JSON.stringify(received)]);
},
};

const mount = document.createElement('div');
domPainter.paint(layout, mount);
expect(mount.dataset.pageCount).toBe('1');

const blob = await pdfPainter.render(layout);
expect(blob).toBeInstanceOf(Blob);
expect(layout.pages.length).toBe(1);
expect(layout.pages[0].fragments.length).toBe(1);
});

it('extracts header/footer spacing from margins', () => {
Expand Down
74 changes: 0 additions & 74 deletions packages/layout-engine/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1880,87 +1880,13 @@ export type WrapExclusion = {
wrapText: WrapTextMode;
};

export type RenderedLineInfo = {
el: HTMLElement;
top: number;
height: number;
};

/**
* Interface for position mapping from ProseMirror transactions.
* Used to efficiently update DOM position attributes without full re-render.
*/
export interface PositionMapping {
/** Transform a position from old to new document coordinates */
map(pos: number, bias?: number): number;
/** Array of step maps - length indicates transaction complexity */
readonly maps: readonly unknown[];
}

/**
* Rendering flow mode.
* - `paginated`: discrete page surfaces
* - `semantic`: continuous flow surface
*/
export type FlowMode = 'paginated' | 'semantic';

export interface PainterDOM {
paint(layout: Layout, mount: HTMLElement, mapping?: PositionMapping): void;
/**
* Updates the painter's internal block and measure data without reinstantiating.
*
* This method is an optimization for incremental rendering pipelines that need to
* refresh the underlying data (e.g., after content edits) without creating a new
* painter instance. It updates the painter's internal lookup tables to reflect
* the new blocks and measures.
*
* Header and footer blocks should be provided when the layout includes header/footer
* content that needs to be rendered. These are typically generated by the layout
* engine's header/footer adapter and should be passed through to the painter.
*
* @param blocks - Main document blocks to be rendered in the page body
* @param measures - Measurements corresponding to the main document blocks (must match blocks array length)
* @param headerBlocks - Optional array of blocks for header content. When provided, headerMeasures must also be provided.
* @param headerMeasures - Optional measurements for header blocks (must match headerBlocks array length when provided)
* @param footerBlocks - Optional array of blocks for footer content. When provided, footerMeasures must also be provided.
* @param footerMeasures - Optional measurements for footer blocks (must match footerBlocks array length when provided)
*
* @throws {Error} When blocks and measures array lengths don't match
* @throws {Error} When headerBlocks is provided without headerMeasures or vice versa
* @throws {Error} When headerBlocks and headerMeasures lengths don't match
* @throws {Error} When footerBlocks is provided without footerMeasures or vice versa
* @throws {Error} When footerBlocks and footerMeasures lengths don't match
*
* @example
* ```typescript
* // Basic usage with main document only
* painter.setData(blocks, measures);
*
* // With headers and footers
* painter.setData(
* mainBlocks,
* mainMeasures,
* headerBlocks,
* headerMeasures,
* footerBlocks,
* footerMeasures
* );
* ```
*/
setData?(
blocks: FlowBlock[],
measures: Measure[],
headerBlocks?: FlowBlock[],
headerMeasures?: Measure[],
footerBlocks?: FlowBlock[],
footerMeasures?: Measure[],
): void;
}

export interface PainterPDF {
render(layout: Layout): Promise<Blob>;
}

export const extractHeaderFooterSpace = (
margins?: PageMargins | null,
): {
Expand Down
Loading
Loading