@eigenpal/docx-editor-core/layout-engine/types
Layout Engine Types
Core types for the paginated layout engine. Converts document blocks + measurements into positioned fragments on pages.
Functions(1)
assertExhaustiveFlowBlock
Exhaustiveness guard for `FlowBlock`-shaped switches. Call from the `default` arm with the still-typed value; TypeScript will refuse to compile if any variant of `FlowBlock` was missed. The thrown error names the calling site so runtime failures (e.g. an old adapter compiled against a newer core) point future debuggers at the contract.
declare function assertExhaustiveFlowBlock(block: never, site: string): never;Type aliases(60)
BlockId
Unique identifier for a block in the document. Format: typically `${index}-${type}` or just the block index.
type BlockId = string | number;BorderStyle
Border specification for paragraphs.
type BorderStyle = {
style?: string;
width?: number;
color?: string;
space?: number;
};CellBorders
Cell borders (all four sides).
type CellBorders = {
top?: CellBorderSpec;
bottom?: CellBorderSpec;
left?: CellBorderSpec;
right?: CellBorderSpec;
};CellBorderSpec
Cell border specification for rendering.
type CellBorderSpec = {
width?: number;
color?: string;
style?: string;
};ColumnBreakBlock
Column break block.
type ColumnBreakBlock = {
kind: 'columnBreak';
id: BlockId;
pmStart?: number;
pmEnd?: number;
};ColumnBreakMeasure
Measurement result for column break (no visual size).
type ColumnBreakMeasure = {
kind: 'columnBreak';
};ColumnLayout
Column layout configuration.
type ColumnLayout = {
count: number;
gap: number;
equalWidth?: boolean;
separator?: boolean;
};DocumentPosition
Position within the document model.
type DocumentPosition = {
blockIndex: number;
runIndex?: number;
charOffset?: number;
pmPos?: number;
};FieldRun
A field run (PAGE, NUMPAGES, etc.) that gets substituted at render time.
type FieldRun = RunFormatting & {
kind: 'field';
fieldType: 'PAGE' | 'NUMPAGES' | 'DATE' | 'TIME' | 'OTHER';
fallback?: string;
pmStart?: number;
pmEnd?: number;
};FloatingTablePosition
Floating table positioning info (pixel values).
type FloatingTablePosition = {
horzAnchor?: 'margin' | 'page' | 'text';
vertAnchor?: 'margin' | 'page' | 'text';
tblpX?: number;
tblpXSpec?: 'left' | 'center' | 'right' | 'inside' | 'outside';
tblpY?: number;
tblpYSpec?: 'top' | 'center' | 'bottom' | 'inside' | 'outside' | 'inline';
topFromText?: number;
bottomFromText?: number;
leftFromText?: number;
rightFromText?: number;
};FlowBlock
Union of every block kind the layout engine knows about.
Three switches over `block.kind` must stay in sync with this type: - `runLayoutPipeline` in `layout-engine/index.ts` (this package) - `measureBlock` in `packages/react/src/paged-editor/PagedEditor.tsx` - `measureBlock` in `packages/vue/src/composables/useDocxEditor.ts`
All three end in `assertExhaustiveFlowBlock(block, '<site>')` so adding a new variant here without updating every site is a typecheck error.
type FlowBlock = ParagraphBlock | TableBlock | ImageBlock | TextBoxBlock | SectionBreakBlock | PageBreakBlock | ColumnBreakBlock;FootnoteContent
Pre-calculated footnote content for layout and rendering.
type FootnoteContent = {
id: number;
displayNumber: number;
blocks: FlowBlock[];
measures: Measure[];
height: number;
};Fragment
Union of all fragment types.
type Fragment = ParagraphFragment | TableFragment | ImageFragment | TextBoxFragment;FragmentBase
Base fragment properties common to all fragment types.
type FragmentBase = {
blockId: BlockId;
x: number;
y: number;
width: number;
pmStart?: number;
pmEnd?: number;
};HitTestResult
Result of hit-testing a click position.
type HitTestResult = {
pageIndex: number;
fragment?: Fragment;
localX?: number;
localY?: number;
};HyperlinkInfo
Hyperlink information for a run.
type HyperlinkInfo = {
href: string;
tooltip?: string;
noDefaultStyle?: boolean;
};ImageBlock
An anchored/floating image block.
type ImageBlock = {
kind: 'image';
id: BlockId;
src: string;
width: number;
height: number;
alt?: string;
transform?: string;
anchor?: {
isAnchored?: boolean;
offsetH?: number;
offsetV?: number;
behindDoc?: boolean;
};
hlinkHref?: string;
pmStart?: number;
pmEnd?: number;
};ImageFragment
An image fragment positioned on a page.
type ImageFragment = FragmentBase & {
kind: 'image';
height: number;
isAnchored?: boolean;
zIndex?: number;
};ImageMeasure
Measurement result for an image block.
type ImageMeasure = {
kind: 'image';
width: number;
height: number;
};ImageRun
An inline image run.
type ImageRun = {
kind: 'image';
src: string;
width: number;
height: number;
alt?: string;
transform?: string;
position?: ImageRunPosition;
wrapType?: string;
displayMode?: 'inline' | 'block' | 'float';
cssFloat?: 'left' | 'right' | 'none';
distTop?: number;
distBottom?: number;
distLeft?: number;
distRight?: number;
cropTop?: number;
cropRight?: number;
cropBottom?: number;
cropLeft?: number;
opacity?: number;
pmStart?: number;
pmEnd?: number;
};ImageRunPosition
Position data for floating/anchored images.
type ImageRunPosition = {
horizontal?: {
relativeTo?: string;
posOffset?: number;
align?: string;
};
vertical?: {
relativeTo?: string;
posOffset?: number;
align?: string;
};
};Final layout output ready for rendering/painting.
type Layout = {
pageSize: {
w: number;
h: number;
};
pages: Page[];
columns?: ColumnLayout;
headers?: Record<string, HeaderFooterLayout>;
footers?: Record<string, HeaderFooterLayout>;
pageGap?: number;
};LayoutOptions
Options for the layout engine.
type LayoutOptions = {
pageSize: {
w: number;
h: number;
};
margins: PageMargins;
finalPageSize?: {
w: number;
h: number;
};
finalMargins?: PageMargins;
columns?: ColumnLayout;
pageGap?: number;
defaultLineHeight?: number;
headerContentHeights?: HeaderFooterContentHeights;
footerContentHeights?: HeaderFooterContentHeights;
titlePage?: boolean;
evenAndOddHeaders?: boolean;
footnoteReservedHeights?: Map<number, number>;
bodyBreakType?: 'continuous' | 'nextPage' | 'evenPage' | 'oddPage';
};LineBreakRun
A line break run.
type LineBreakRun = {
kind: 'lineBreak';
pmStart?: number;
pmEnd?: number;
};ListNumPr
List numbering properties for a paragraph.
type ListNumPr = {
numId?: number;
ilvl?: number;
};Measure
Union of all measurement types.
type Measure = ParagraphMeasure | ImageMeasure | TableMeasure | TextBoxMeasure | SectionBreakMeasure | PageBreakMeasure | ColumnBreakMeasure;MeasuredLine
A measured line within a paragraph.
type MeasuredLine = {
fromRun: number;
fromChar: number;
toRun: number;
toChar: number;
width: number;
ascent: number;
descent: number;
lineHeight: number;
leftOffset?: number;
rightOffset?: number;
segments?: MeasuredLineSegment[];
};MeasuredLineSegment
type MeasuredLineSegment = {
fromRun: number;
fromChar: number;
toRun: number;
toChar: number;
width: number;
leftOffset: number;
availableWidth: number;
};A rendered page containing positioned fragments.
type Page = {
number: number;
fragments: Fragment[];
margins: PageMargins;
size: {
w: number;
h: number;
};
orientation?: 'portrait' | 'landscape';
sectionIndex?: number;
headerFooterRefs?: {
headerDefault?: string;
headerFirst?: string;
headerEven?: string;
footerDefault?: string;
footerFirst?: string;
footerEven?: string;
};
footnoteIds?: number[];
footnoteReservedHeight?: number;
columns?: ColumnLayout;
};PageBreakBlock
Explicit page break block.
type PageBreakBlock = {
kind: 'pageBreak';
id: BlockId;
pmStart?: number;
pmEnd?: number;
};PageBreakMeasure
Measurement result for page break (no visual size).
type PageBreakMeasure = {
kind: 'pageBreak';
};PageMargins
Page margin configuration.
type PageMargins = {
top: number;
right: number;
bottom: number;
left: number;
header?: number;
footer?: number;
};ParagraphAttrs
Paragraph block attributes.
type ParagraphAttrs = {
alignment?: 'left' | 'center' | 'right' | 'justify';
spacing?: ParagraphSpacing;
spacingExplicit?: {
before?: boolean;
after?: boolean;
};
indent?: ParagraphIndent;
keepNext?: boolean;
keepLines?: boolean;
pageBreakBefore?: boolean;
styleId?: string;
contextualSpacing?: boolean;
bidi?: boolean;
borders?: ParagraphBorders;
shading?: string;
tabs?: TabStop[];
numPr?: ListNumPr;
listMarker?: string;
listIsBullet?: boolean;
listMarkerHidden?: boolean;
listMarkerFontFamily?: string;
listMarkerFontSize?: number;
defaultFontSize?: number;
defaultFontFamily?: string;
suppressEmptyParagraphHeight?: boolean;
};ParagraphBlock
A paragraph block containing runs.
type ParagraphBlock = {
kind: 'paragraph';
id: BlockId;
runs: Run[];
attrs?: ParagraphAttrs;
pmStart?: number;
pmEnd?: number;
};ParagraphBorders
Paragraph borders.
type ParagraphBorders = {
top?: BorderStyle;
bottom?: BorderStyle;
left?: BorderStyle;
right?: BorderStyle;
between?: BorderStyle;
bar?: BorderStyle;
};ParagraphFragment
A paragraph fragment positioned on a page. May span only part of the paragraph's lines if split across pages.
type ParagraphFragment = FragmentBase & {
kind: 'paragraph';
fromLine: number;
toLine: number;
height: number;
continuesFromPrev?: boolean;
continuesOnNext?: boolean;
};ParagraphIndent
Paragraph indentation configuration.
type ParagraphIndent = {
left?: number;
right?: number;
firstLine?: number;
hanging?: number;
};ParagraphMeasure
Measurement result for a paragraph block.
type ParagraphMeasure = {
kind: 'paragraph';
lines: MeasuredLine[];
totalHeight: number;
};ParagraphSpacing
Paragraph spacing configuration.
type ParagraphSpacing = {
before?: number;
after?: number;
line?: number;
lineUnit?: 'px' | 'multiplier';
lineRule?: 'auto' | 'exact' | 'atLeast';
};Union of all run types.
type Run = TextRun | TabRun | ImageRun | LineBreakRun | FieldRun;RunFormatting
Common run formatting properties applied to text runs.
type RunFormatting = {
bold?: boolean;
italic?: boolean;
underline?: boolean | {
style?: string;
color?: string;
};
strike?: boolean;
color?: string;
highlight?: string;
fontFamily?: string;
fontSize?: number;
letterSpacing?: number;
superscript?: boolean;
subscript?: boolean;
allCaps?: boolean;
smallCaps?: boolean;
positionPx?: number;
horizontalScale?: number;
kerningMinPt?: number;
imprint?: boolean;
emboss?: boolean;
textShadow?: boolean;
textOutline?: boolean;
emphasisMark?: 'dot' | 'comma' | 'circle' | 'underDot';
hidden?: boolean;
rtl?: boolean;
textEffect?: 'blinkBackground' | 'lights' | 'antsBlack' | 'antsRed' | 'shimmer' | 'sparkle';
hyperlink?: HyperlinkInfo;
footnoteRefId?: number;
endnoteRefId?: number;
commentIds?: number[];
isInsertion?: boolean;
isDeletion?: boolean;
changeAuthor?: string;
changeDate?: string;
changeRevisionId?: number;
};SectionBreakBlock
Section break block defining page layout changes.
type SectionBreakBlock = {
kind: 'sectionBreak';
id: BlockId;
type?: 'continuous' | 'nextPage' | 'evenPage' | 'oddPage';
pageSize?: {
w: number;
h: number;
};
orientation?: 'portrait' | 'landscape';
margins?: PageMargins;
columns?: ColumnLayout;
};SectionBreakMeasure
Measurement result for section break (no visual size).
type SectionBreakMeasure = {
kind: 'sectionBreak';
};TabAlignment
Tab stop alignment types
type TabAlignment = 'start' | 'end' | 'center' | 'decimal' | 'bar' | 'clear';TableBlock
A table block containing rows.
type TableBlock = {
kind: 'table';
id: BlockId;
rows: TableRow[];
columnWidths?: number[];
width?: number;
widthType?: string;
justification?: 'left' | 'center' | 'right';
indent?: number;
floating?: FloatingTablePosition;
pmStart?: number;
pmEnd?: number;
};TableCell
A table cell with content.
type TableCell = {
id: BlockId;
blocks: FlowBlock[];
colSpan?: number;
rowSpan?: number;
width?: number;
widthValue?: number;
widthType?: string;
verticalAlign?: 'top' | 'center' | 'bottom';
background?: string;
borders?: CellBorders;
padding?: {
top: number;
right: number;
bottom: number;
left: number;
};
noWrap?: boolean;
};TableCellMeasure
Measurement result for a table cell.
type TableCellMeasure = {
blocks: Measure[];
width: number;
height: number;
colSpan?: number;
rowSpan?: number;
};TableFragment
A table fragment positioned on a page. May span only part of the table's rows if split across pages.
type TableFragment = FragmentBase & {
kind: 'table';
fromRow: number;
toRow: number;
height: number;
isFloating?: boolean;
continuesFromPrev?: boolean;
continuesOnNext?: boolean;
headerRowCount?: number;
};TableMeasure
Measurement result for a table block.
type TableMeasure = {
kind: 'table';
rows: TableRowMeasure[];
columnWidths: number[];
totalWidth: number;
totalHeight: number;
};TableRow
A table row containing cells.
type TableRow = {
id: BlockId;
cells: TableCell[];
height?: number;
heightRule?: 'auto' | 'atLeast' | 'exact';
isHeader?: boolean;
};TableRowMeasure
Measurement result for a table row.
type TableRowMeasure = {
cells: TableCellMeasure[];
height: number;
};A tab character run.
type TabRun = RunFormatting & {
kind: 'tab';
width?: number;
pmStart?: number;
pmEnd?: number;
};TabStop
Tab stop definition
type TabStop = {
val: TabAlignment;
pos: number;
leader?: 'none' | 'dot' | 'hyphen' | 'underscore' | 'heavy' | 'middleDot';
};TextBoxBlock
Text box block — positioned container with paragraph content.
type TextBoxBlock = {
kind: 'textBox';
id: BlockId;
width: number;
height?: number;
fillColor?: string;
outlineWidth?: number;
outlineColor?: string;
outlineStyle?: string;
margins?: {
top: number;
bottom: number;
left: number;
right: number;
};
content: ParagraphBlock[];
displayMode?: 'inline' | 'float' | 'block';
cssFloat?: 'left' | 'right' | 'none';
wrapType?: string;
wrapText?: WrapTextDirection;
anchorTarget?: 'followingBlock';
position?: ImageRunPosition;
distTop?: number;
distBottom?: number;
distLeft?: number;
distRight?: number;
pmStart?: number;
pmEnd?: number;
};TextBoxFragment
A text box fragment positioned on a page.
type TextBoxFragment = FragmentBase & {
kind: 'textBox';
height: number;
isFloating?: boolean;
zIndex?: number;
};TextBoxMeasure
Measurement result for a text box block.
type TextBoxMeasure = {
kind: 'textBox';
width: number;
height: number;
innerMeasures: ParagraphMeasure[];
};TextRun
A text run within a paragraph.
type TextRun = RunFormatting & {
kind: 'text';
text: string;
hyperlink?: HyperlinkInfo;
pmStart?: number;
pmEnd?: number;
};WrapTextDirection
type WrapTextDirection = 'bothSides' | 'left' | 'right' | 'largest';Variables(2)
DEFAULT_TEXTBOX_MARGINS
Default internal margins for text boxes (OOXML defaults in pixels)
DEFAULT_TEXTBOX_MARGINS: {
top: number;
bottom: number;
left: number;
right: number;
}DEFAULT_TEXTBOX_WIDTH
Default text box width in pixels when no width is specified
DEFAULT_TEXTBOX_WIDTH = 200