Margin box + vertical flow helpers on top of PrawnEx.
Tracks a PDF baseline cursor (cursor_y) so you avoid repeating page_h - N
arithmetic for common stacks (title, paragraphs, table, spacer). Coordinates
match the rest of PrawnEx: origin bottom-left, y increases upward.
Phases
- Flow —
attach/2,heading/3,paragraph/3,spacer/2,table/3,escape/2,to_doc/1. - B — stacks —
vstack/3(vertical list of flow blocks),hstack/3(fixed-width columns). - C — region + pagination — optional
region:onattach/2; when content would extend belowfloor_y, a new page is started (on_overflow: :new_page, default). No automatic splitting of a single oversized paragraph across pages. - D — markup — see
PrawnEx.Layout.Markup(parse/1,apply/2).
Typical use:
doc
|> PrawnEx.add_page()
|> PrawnEx.Layout.attach(page_size: :a4, margins: %{top: 60, left: 50, right: 50, bottom: 50})
|> PrawnEx.Layout.heading("INVOICE", font_size: 24)
|> PrawnEx.Layout.paragraph("Acme Inc.\n123 Main St", font_size: 10, line_height: 14)
|> PrawnEx.Layout.to_doc()Escape hatch for one-off coordinates: escape/2.
Summary
Functions
Attaches flow state to doc. Requires at least one page.
Low-level escape: fun receives (doc, ctx) where ctx is a map with :cursor_y,
:content_left, :content_width, :page_w, :page_h, :margins. Return {new_doc, new_cursor_y}.
Single-line heading. Options: :font, :font_size (default from :level), :level (1 or 2),
:lead (default 1.0), :gap_after (default 6).
Horizontal row of fixed-width columns (Phase B). Each column is {width_pt, fn sub_layout -> sub_layout}.
The function receives a layout whose content_left / content_width / cursor_y are scoped to that
column; merge the returned doc and advance the outer cursor by the deepest column drop plus
:row_gap_after (default 8).
Wrapped paragraph using PrawnEx.text_box/3. Options: :font_name, :font_size (default 10),
:line_height (default font_size * 1.2), :width (default content width), :gap_after (default 8).
Preserves newlines like text_box / Text.wrap_to_lines.
Moves the baseline cursor down the page by pts points (decreases PDF y).
Draws a table whose top edge sits clearance pt below the current cursor.
Returns the underlying document for PrawnEx.build/2 callbacks or to_binary/1.
Vertical stack of flow blocks (Phase B). blocks are tuples
Types
Functions
@spec attach( PrawnEx.Document.t(), keyword() ) :: t()
Attaches flow state to doc. Requires at least one page.
Options:
:page_size— passed toPrawnEx.Units.page_size/1(default fromdoc.opts[:page_size]or:a4):margins— a number (all sides) or%{left:, right:, top:, bottom:}(missing keys default to 50):region—%{floor_y: y}or barey(PDF y); content must not extend below this y (see Phase C). When unset, no automatic page breaks are inserted.:on_overflow—:new_page(default when region set) or:clip(draw anyway; no new page)
Initial cursor_y is the first text baseline under the top margin: page_h - margins.top.
Low-level escape: fun receives (doc, ctx) where ctx is a map with :cursor_y,
:content_left, :content_width, :page_w, :page_h, :margins. Return {new_doc, new_cursor_y}.
Single-line heading. Options: :font, :font_size (default from :level), :level (1 or 2),
:lead (default 1.0), :gap_after (default 6).
Horizontal row of fixed-width columns (Phase B). Each column is {width_pt, fn sub_layout -> sub_layout}.
The function receives a layout whose content_left / content_width / cursor_y are scoped to that
column; merge the returned doc and advance the outer cursor by the deepest column drop plus
:row_gap_after (default 8).
Options: :gap between columns (default 8), :row_gap_after (default 10),
:min_row_depth — minimum vertical budget in pt for the row (default 22). Short columns
only move the cursor by gap_after pixels; without a floor, the next block can overlap the row.
Wrapped paragraph using PrawnEx.text_box/3. Options: :font_name, :font_size (default 10),
:line_height (default font_size * 1.2), :width (default content width), :gap_after (default 8).
Preserves newlines like text_box / Text.wrap_to_lines.
Moves the baseline cursor down the page by pts points (decreases PDF y).
Draws a table whose top edge sits clearance pt below the current cursor.
Forwards options to PrawnEx.table/3 except: :clearance (default 20), :after_gap (default 12),
and :at / :page_size are supplied automatically unless you pass :page_size in opts.
@spec to_doc(t()) :: PrawnEx.Document.t()
Returns the underlying document for PrawnEx.build/2 callbacks or to_binary/1.
@spec vstack(t(), [flow_block()], keyword()) :: t()
Vertical stack of flow blocks (Phase B). blocks are tuples:
{:heading, text, opts}— passed toheading/3{:paragraph, text, opts}— passed toparagraph/3{:spacer, pts}— passed tospacer/2{:table, rows, opts}— passed totable/3{:run, fn layout -> layout end}— custom
Options: :gap — extra spacer inserted between blocks (not after the last).