@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)
assertExhaustiveFlowBlockfunctionSource ↗
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;Interfaces (2)
InlineSdtWidgetinterfaceSource ↗
Inline SDT widget metadata carried by a painted text run.
interface InlineSdtWidget| Member | Type | Summary |
|---|---|---|
| alias? | string | Word alias value (`w:alias`). |
| checked? | boolean | Live checkbox glyph state. |
| groupId | string | Stable per-document id derived from the ProseMirror node position. |
| kind | 'checkbox' | |
| pos | number | ProseMirror position of the inline SDT node. |
| tag? | string | Word tag value (`w:tag`). |
SdtGroupinterfaceSource ↗
Identity of a block-level Structured Document Tag (content control) enclosing a run of flow blocks. Block SDTs flatten into their child flow blocks for pagination; each child carries its group(s) so the painter draws the boundary.
interface SdtGroup| Member | Type | Summary |
|---|---|---|
| alias? | string | |
| bound? | boolean | |
| checked? | boolean | |
| id | string | |
| lock? | string | |
| repeatingItem? | boolean | |
| sdtType | string | |
| tag? | string |
Type aliases (60)
BlockIdtypeSource ↗
Unique identifier for a block in the document. Format: typically ${index}-${type} or just the block index.
type BlockId = string | number;BorderStyletypeSource ↗
Border specification for paragraphs.
type BorderStyle = {
style?: string;
width?: number;
color?: string;
space?: number;
};CellBorderstypeSource ↗
Cell borders (all four sides).
type CellBorders = {
top?: CellBorderSpec;
bottom?: CellBorderSpec;
left?: CellBorderSpec;
right?: CellBorderSpec;
};CellBorderSpectypeSource ↗
Cell border specification for rendering.
type CellBorderSpec = {
width?: number;
color?: string;
style?: string;
};ColumnBreakBlocktypeSource ↗
Column break block.
type ColumnBreakBlock = {
sdtGroups?: SdtGroup[];
kind: 'columnBreak';
id: BlockId;
pmStart?: number;
pmEnd?: number;
};ColumnBreakMeasuretypeSource ↗
Measurement result for column break (no visual size).
type ColumnBreakMeasure = {
kind: 'columnBreak';
};ColumnLayouttypeSource ↗
Column layout configuration.
type ColumnLayout = {
count: number;
gap: number;
equalWidth?: boolean;
separator?: boolean;
};DocumentPositiontypeSource ↗
Position within the document model.
type DocumentPosition = {
blockIndex: number;
runIndex?: number;
charOffset?: number;
pmPos?: number;
};FieldRuntypeSource ↗
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;
};FloatingTablePositiontypeSource ↗
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;
};FlowBlocktypeSource ↗
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;FootnoteContenttypeSource ↗
Pre-calculated footnote content for layout and rendering.
type FootnoteContent = {
id: number;
displayNumber: number;
blocks: FlowBlock[];
measures: Measure[];
height: number;
};FragmenttypeSource ↗
Union of all fragment types.
type Fragment = ParagraphFragment | TableFragment | ImageFragment | TextBoxFragment;FragmentBasetypeSource ↗
Base fragment properties common to all fragment types.
type FragmentBase = {
blockId: BlockId;
x: number;
y: number;
width: number;
pmStart?: number;
pmEnd?: number;
};HeaderFooterContentHeightstypeSource ↗
Header/footer content heights by variant type.
type HeaderFooterContentHeights = Partial<Record<'default' | 'first' | 'even' | 'odd', number>>;HeaderFooterLayouttypeSource ↗
Header/footer layout for a specific type.
type HeaderFooterLayout = {
height: number;
fragments: Fragment[];
};HitTestResulttypeSource ↗
Result of hit-testing a click position.
type HitTestResult = {
pageIndex: number;
fragment?: Fragment;
localX?: number;
localY?: number;
};HyperlinkInfotypeSource ↗
Hyperlink information for a run.
type HyperlinkInfo = {
href: string;
tooltip?: string;
noDefaultStyle?: boolean;
};ImageBlocktypeSource ↗
An anchored/floating image block.
type ImageBlock = {
sdtGroups?: SdtGroup[];
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;
};ImageFragmenttypeSource ↗
An image fragment positioned on a page.
type ImageFragment = FragmentBase & {
kind: 'image';
height: number;
isAnchored?: boolean;
zIndex?: number;
};ImageMeasuretypeSource ↗
Measurement result for an image block.
type ImageMeasure = {
kind: 'image';
width: number;
height: number;
};ImageRuntypeSource ↗
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;
isInsertion?: boolean;
isDeletion?: boolean;
changeAuthor?: string;
changeDate?: string;
changeRevisionId?: number;
pmStart?: number;
pmEnd?: number;
};ImageRunPositiontypeSource ↗
Position data for floating/anchored images.
type ImageRunPosition = {
horizontal?: {
relativeTo?: string;
posOffset?: number;
align?: string;
};
vertical?: {
relativeTo?: string;
posOffset?: number;
align?: string;
};
};LayouttypeSource ↗
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;
};LayoutOptionstypeSource ↗
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';
};LineBreakRuntypeSource ↗
A line break run.
type LineBreakRun = {
kind: 'lineBreak';
pmStart?: number;
pmEnd?: number;
};ListNumPrtypeSource ↗
List numbering properties for a paragraph.
type ListNumPr = {
numId?: number;
ilvl?: number;
};MeasuretypeSource ↗
Union of all measurement types.
type Measure = ParagraphMeasure | ImageMeasure | TableMeasure | TextBoxMeasure | SectionBreakMeasure | PageBreakMeasure | ColumnBreakMeasure;MeasuredLinetypeSource ↗
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[];
floatSkipBefore?: number;
};MeasuredLineSegmenttypeSource ↗
type MeasuredLineSegment = {
fromRun: number;
fromChar: number;
toRun: number;
toChar: number;
width: number;
leftOffset: number;
availableWidth: number;
};PagetypeSource ↗
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;
footnoteColumns?: number;
columns?: ColumnLayout;
};PageBreakBlocktypeSource ↗
Explicit page break block.
type PageBreakBlock = {
sdtGroups?: SdtGroup[];
kind: 'pageBreak';
id: BlockId;
pmStart?: number;
pmEnd?: number;
};PageBreakMeasuretypeSource ↗
Measurement result for page break (no visual size).
type PageBreakMeasure = {
kind: 'pageBreak';
};PageMarginstypeSource ↗
Page margin configuration.
type PageMargins = {
top: number;
right: number;
bottom: number;
left: number;
header?: number;
footer?: number;
};ParagraphAttrstypeSource ↗
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;
listMarkerSuffix?: 'tab' | 'space' | 'nothing';
listMarkerRevision?: 'ins' | 'del';
defaultTabStopTwips?: number;
defaultFontSize?: number;
defaultFontFamily?: string;
suppressEmptyParagraphHeight?: boolean;
pPrIns?: RevisionInfo | null;
pPrDel?: RevisionInfo | null;
};ParagraphBlocktypeSource ↗
A paragraph block containing runs.
type ParagraphBlock = {
sdtGroups?: SdtGroup[];
kind: 'paragraph';
id: BlockId;
paraId?: string;
runs: Run[];
attrs?: ParagraphAttrs;
pmStart?: number;
pmEnd?: number;
};ParagraphBorderstypeSource ↗
Paragraph borders.
type ParagraphBorders = {
top?: BorderStyle;
bottom?: BorderStyle;
left?: BorderStyle;
right?: BorderStyle;
between?: BorderStyle;
bar?: BorderStyle;
};ParagraphFragmenttypeSource ↗
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;
};ParagraphIndenttypeSource ↗
Paragraph indentation configuration.
type ParagraphIndent = {
left?: number;
right?: number;
firstLine?: number;
hanging?: number;
};ParagraphMeasuretypeSource ↗
Measurement result for a paragraph block.
type ParagraphMeasure = {
kind: 'paragraph';
lines: MeasuredLine[];
totalHeight: number;
};ParagraphSpacingtypeSource ↗
Paragraph spacing configuration.
type ParagraphSpacing = {
before?: number;
after?: number;
line?: number;
lineUnit?: 'px' | 'multiplier';
lineRule?: 'auto' | 'exact' | 'atLeast';
};RuntypeSource ↗
Union of all run types.
type Run = TextRun | TabRun | ImageRun | LineBreakRun | FieldRun;RunFormattingtypeSource ↗
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;
};SectionBreakBlocktypeSource ↗
Section break block defining page layout changes.
type SectionBreakBlock = {
sdtGroups?: SdtGroup[];
kind: 'sectionBreak';
id: BlockId;
type?: 'continuous' | 'nextPage' | 'evenPage' | 'oddPage';
pageSize?: {
w: number;
h: number;
};
orientation?: 'portrait' | 'landscape';
margins?: PageMargins;
columns?: ColumnLayout;
};SectionBreakMeasuretypeSource ↗
Measurement result for section break (no visual size).
type SectionBreakMeasure = {
kind: 'sectionBreak';
};TabAlignmenttypeSource ↗
Tab stop alignment types
type TabAlignment = 'start' | 'end' | 'center' | 'decimal' | 'bar' | 'clear';TableBlocktypeSource ↗
A table block containing rows.
type TableBlock = {
sdtGroups?: SdtGroup[];
kind: 'table';
id: BlockId;
rows: TableRow[];
columnWidths?: number[];
width?: number;
widthType?: string;
justification?: 'left' | 'center' | 'right';
bidi?: boolean;
indent?: number;
floating?: FloatingTablePosition;
pmStart?: number;
pmEnd?: number;
};TableCelltypeSource ↗
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;
trackedMarker?: CellMarker;
};TableCellMeasuretypeSource ↗
Measurement result for a table cell.
type TableCellMeasure = {
blocks: Measure[];
width: number;
height: number;
colSpan?: number;
rowSpan?: number;
};TableFragmenttypeSource ↗
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;
topClip?: number;
bottomClip?: number;
};TableMeasuretypeSource ↗
Measurement result for a table block.
type TableMeasure = {
kind: 'table';
rows: TableRowMeasure[];
columnWidths: number[];
totalWidth: number;
totalHeight: number;
};TableRowtypeSource ↗
A table row containing cells.
type TableRow = {
id: BlockId;
cells: TableCell[];
height?: number;
heightRule?: 'auto' | 'atLeast' | 'exact';
isHeader?: boolean;
cantSplit?: boolean;
trackedIns?: RevisionInfo;
trackedDel?: RevisionInfo;
};TableRowMeasuretypeSource ↗
Measurement result for a table row.
type TableRowMeasure = {
cells: TableCellMeasure[];
height: number;
};TabRuntypeSource ↗
A tab character run.
type TabRun = RunFormatting & {
kind: 'tab';
width?: number;
pmStart?: number;
pmEnd?: number;
};TabStoptypeSource ↗
Tab stop definition
type TabStop = {
val: TabAlignment;
pos: number;
leader?: 'none' | 'dot' | 'hyphen' | 'underscore' | 'heavy' | 'middleDot';
};TextBoxBlocktypeSource ↗
Text box block — positioned container with paragraph content.
type TextBoxBlock = {
sdtGroups?: SdtGroup[];
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;
};TextBoxFragmenttypeSource ↗
A text box fragment positioned on a page.
type TextBoxFragment = FragmentBase & {
kind: 'textBox';
height: number;
isFloating?: boolean;
zIndex?: number;
};TextBoxMeasuretypeSource ↗
Measurement result for a text box block.
type TextBoxMeasure = {
kind: 'textBox';
width: number;
height: number;
innerMeasures: ParagraphMeasure[];
};TextRuntypeSource ↗
A text run within a paragraph.
type TextRun = RunFormatting & {
kind: 'text';
text: string;
hyperlink?: HyperlinkInfo;
pmStart?: number;
pmEnd?: number;
inlineSdtWidget?: InlineSdtWidget;
};WrapTextDirectiontypeSource ↗
type WrapTextDirection = 'bothSides' | 'left' | 'right' | 'largest';Variables (2)
DEFAULT_TEXTBOX_MARGINSconstSource ↗
Default internal margins for text boxes (OOXML defaults in pixels)
DEFAULT_TEXTBOX_MARGINS: {
top: number;
bottom: number;
left: number;
right: number;
}DEFAULT_TEXTBOX_WIDTHconstSource ↗
Default text box width in pixels when no width is specified
DEFAULT_TEXTBOX_WIDTH = 200