Skip to Content
API Referencepdf-export-client

@stesura/pdf-export-client

Browser side of PDF export: the toolbar button, and the shell for the export page the server loads. The server side is @stesura/pdf-export-server; the PDF export guide covers setup.

Toolbar

pdfUiExtension adds the PDF export group to the toolbar’s Export tab:

import { pdfUiExtension } from '@stesura/pdf-export-client' <StesuraEditor uiExtensions={[pdfUiExtension]} />

For a custom endpoint, file name or request headers, build the extension with createPdfUiExtension(props) (once, at module scope), or mount PdfExportGroup (the button in a labelled toolbar group, which is what the extension mounts) or the bare PdfExportButton yourself. The button posts { doc, fileName, experimental, layout?, docId? } to the endpoint (experimental is the editor’s experimental features, which the export page must lay out with) and downloads the PDF; failures, including a non-PDF response, show a toast unless you pass onError. Both take the same props:

PdfExportButtonProps

NameTypeDefault
endpointstring

Export endpoint. Defaults to ${NEXT_PUBLIC_BASE_PATH}/api/export/pdf; an absolute URL points at a standalone export service.

fileNamestring

Download file name. Defaults to document.pdf.

onError(error: Error) => void

Called instead of the default toast when an export fails.

onLosses(losses: ExportLosses) => void

Called instead of the default warning toast when the PDF was produced without some content (images that never loaded, embedded files dropped, characters no bundled font covers) or paginates differently from the editor.

getLayoutManifest(state: EditorState) => ExportLayoutManifest | null

The editor’s current page starts (paginationLayoutManifest from @stesura/pagination), sent with the export so the server can report a PDF that paginates differently from what the user sees.

docIdstring

The host’s id for the document, logged by the server with a layout mismatch.

getRequestHeaders() => HeadersInit | Promise<HeadersInit>

Extra headers for each export request, fetched right before it is sent — e.g. a short-lived ticket for a standalone export service. A rejection fails the export like any other error.

Standalone export service

When rendering runs on its own host, the browser posts the document there directly and your app only vouches for the request with a one-use ticket. exportTicketHeaders(tokenEndpoint) is a ready-made getRequestHeaders: before each export it POSTs to your token route (which answers { token }, minted with mintExportToken from @stesura/pdf-export-server/token) and sends the ticket as Authorization: Bearer ….

import { createPdfUiExtension, exportTicketHeaders } from '@stesura/pdf-export-client' export const pdfExport = createPdfUiExtension({ endpoint: 'https://pdf.example.com/render', getRequestHeaders: exportTicketHeaders('/api/export/token'), })

Export page (/shell)

ExportEditorShell ({ children: ReactNode; isSettled?: () => boolean; layoutManifest?: () => ExportLayoutManifest | null }) wraps the read-only editor on the export route. It provides the clipping viewport, publishes window.__stesuraPdfExport (ExportApi) and flags <body> with data-export-ready or data-export-error once the layout has settled. The editor stays in your app, so it keeps your plugins and extensions.

import { ExportEditorShell } from '@stesura/pdf-export-client/shell' <ExportEditorShell> <StesuraEditor printMode editable={false} toolbar={false} … /> </ExportEditorShell>

Pass isSettled to settle on the pagination engine’s own signal: with it the export is ready within a few animation frames of the last layout pass, instead of after ~400ms of unchanged geometry.

import { getPaginationActivity, isPaginationIdle } from '@stesura/pagination' const isSettled = () => isPaginationIdle(editorState) && getPaginationActivity(editorState).engineRuns > 0

It is on its own subpath because it loads the print stylesheet, whose @page rule can’t be scoped and must only load on the export route. Don’t import @stesura/pdf-export-client/print.css yourself.

The server injects the document as window.__STESURA_EXPORT_DOC__ (an ExportPayload) before any page script runs; importing the shell types that global. If the payload is missing, set document.body.dataset.exportError rather than rendering nothing, or the server waits until its timeout. The guide lists the rest of the export page’s requirements.

Protocol types

The contract between the export page and the server, from @stesura/core/types so the server can import it without depending on this package.

ExportApi

Window-level API the server drives (window.__stesuraPdfExport). Optional members may be missing from older client bundles.

NameTypeDefault
status"error" | "ready" | "pending"
errorstring
manifestExportPageInfo[]
outlineExportOutlineNode[]

Heading tree for the PDF outline/bookmarks panel.

fieldsExportField[][]

[data-pdf-field] boxes per page; outer index === manifest index.

insertionsExportInsertion[]

Embedded PDF files to splice in, in document order.

languagestring

BCP-47 tag of the document’s language, stamped as the PDF’s /Lang.

warningsstring[]

Non-fatal losses (e.g. an image that never loaded), logged by the server.

lossesExportLosses

The counts behind warnings, reported back to the exporting user.

layoutExportLayoutManifest

The export page’s layout, compared with the editor’s (ExportLayoutManifest).

timingsRecord<string, number>

Client-side phase durations in ms (fonts, images, settle, links).

measurementsunknown

The host’s own measurements of the settled layout (ExportEditorShell’s measure).

showPage(index: number) => { width: number; height: number; }

Positions page index in the clipping viewport; returns the size to print at.

showRun(start: number, count: number) => { width: number; height: number; advance: number; } | null

Positions count consecutive same-size pages of one section to print as one tall sheet, page tops advance apart. Null when the pages are not uniformly spaced; the server then falls back to showPage.

ExportPayload

Payload the server injects via page.addInitScript, before any page script runs.

NameTypeDefault
docJSONContent
fileNamestring
experimentalExportExperimental

ExportPageInfo

One printable page, in global page order (sections in DOM order, pages by index).

NameTypeDefault
sectionIndexnumber

Index of the owning .pm_section in DOM order.

pageIndexnumber

0-based page index within the section (matches data-page-index).

widthnumber

Page width in CSS px (section’s --section-width).

heightnumber

Page height in CSS px (section’s --section-page-height).

One clickable region on a page. A link that wraps across lines produces one entry per client rect (internal ones share the same target).

NameTypeDefault
kind"url" | "internal"
rectExportLinkRect

ExportLinkRect

Axis-aligned box in page-local CSS px (origin: the page’s top-left corner).

NameTypeDefault
xnumber
ynumber
widthnumber
heightnumber

ExportOutlineNode

One bookmark in the PDF outline (heading), with its GoTo destination.

NameTypeDefault
titlestring
pageIndexnumber

Manifest / merged-PDF page index of the heading.

ynumber

Heading top in page-local CSS px from the page top.

childrenExportOutlineNode[]
Last updated on