import { createPretextPageLayoutEngine } from "plitejs/pagination";
import {
PagedEditable,
usePageLayout,
} from "plitejs/pagination/react";
import { EditorRoot, useEditor } from "plitejs/react";
import { useMemo, useRef } from "react";
const DocumentEditor = () => {
const editor = useEditor({ initialValue });
const editableRef = useRef<HTMLDivElement>(null);
const engine = useMemo(() => createPretextPageLayoutEngine(), []);
const layout = usePageLayout(editableRef);
return (
<EditorRoot editor={editor}>
<output>{layout?.pages.length ?? 0} pages</output>
<PagedEditable
ref={editableRef}
engine={engine}
page={{ margins: 72, preset: "letter" }}
pageView={{ gap: 24, mode: "single" }}
renderPage={({ attributes, page }) => (
<div {...attributes} aria-label={`Page ${page.index + 1}`} />
)}
/>
</EditorRoot>
);
};import { createPretextPageLayoutEngine } from "plitejs/pagination";
import {
PagedEditable,
usePageLayout,
} from "plitejs/pagination/react";
import { EditorRoot, useEditor } from "plitejs/react";
import { useMemo, useRef } from "react";
const DocumentEditor = () => {
const editor = useEditor({ initialValue });
const editableRef = useRef<HTMLDivElement>(null);
const engine = useMemo(() => createPretextPageLayoutEngine(), []);
const layout = usePageLayout(editableRef);
return (
<EditorRoot editor={editor}>
<output>{layout?.pages.length ?? 0} pages</output>
<PagedEditable
ref={editableRef}
engine={engine}
page={{ margins: 72, preset: "letter" }}
pageView={{ gap: 24, mode: "single" }}
renderPage={({ attributes, page }) => (
<div {...attributes} aria-label={`Page ${page.index + 1}`} />
)}
/>
</EditorRoot>
);
};PagedEditable accepts ordinary Editable props, including element and leaf
renderers and event handlers. renderPage receives page attributes and page
geometry. It renders page chrome without document children; the paged surface
places editable content on the shared canvas.
pageView.mode accepts "single" and "spread". Page settings can be a
PageSettings value or an EditorStateField<PageSettings>, so applications can
keep shared page settings in editor state without storing derived geometry.
usePageLayout(editableRef) reads the snapshot published by that exact
editable host. It returns null before the first valid layout and when
measurement fails. A measurement failure reaches the editor's
lifecycleErrorSink once, and again only after a measurement succeeds or the
error message changes. Sibling paged surfaces keep separate snapshots.
Inline-flow text is the default. Non-text block structures describe their fragmentation through one provider:
<PagedEditable
page={{ margins: 72, preset: "letter" }}
fragmentation={({ element }) => {
if (element.type === "image") {
return { type: "atomic", size: { height: 320, width: 480 } };
}
if (element.type === "table") {
return {
type: "direct-children",
sizes: element.children.map(() => ({ height: 36, width: 624 })),
};
}
if (element.type === "code") {
return { type: "text", keepTogether: true };
}
}}
/><PagedEditable
page={{ margins: 72, preset: "letter" }}
fragmentation={({ element }) => {
if (element.type === "image") {
return { type: "atomic", size: { height: 320, width: 480 } };
}
if (element.type === "table") {
return {
type: "direct-children",
sizes: element.children.map(() => ({ height: 36, width: 624 })),
};
}
if (element.type ===
text measures inline runs and can request soft keep-together behavior.atomic places one indivisible box with an explicit size.direct-children places each immediate child from its explicit size.Plite derives all paths from the document snapshot and validates that the plan matches the node shape. Oversized content is placed once and expands occupied page geometry instead of being dropped.
Call usePageLayoutFragments() inside an element renderer to read that
element's mounted page placements. This is useful when a renderer owns a
fragment-aware boundary for direct children. The hook derives the current path
from renderer context; callers do not pass paths.
measurePages(editor, options) reads one coherent editor snapshot and returns
an immutable PageLayoutSnapshot. It neither subscribes nor publishes.
import {
createEstimatedPageLayoutEngine,
measurePages,
} from "plitejs/pagination";
const snapshot = measurePages(editor, {
engine: createEstimatedPageLayoutEngine(),
page: { margins: 72, preset: "a4" },
});import {
createEstimatedPageLayoutEngine,
measurePages,
} from "plitejs/pagination";
const snapshot = measurePages(editor, {
engine: createEstimatedPageLayoutEngine(),
page: { margins: 72, preset: "a4" },
});Use createPretextPageLayoutEngine() for browser font measurement. Its options
control whitespace, word breaking, cache size, and cold-block estimation. A
custom PageLayoutEngine receives detached immutable input and must conserve
source ranges, fragment order, paths, and declared non-text sizes.
Use typography.block and typography.text to match the rendered line height,
spacing, font, and letter spacing. Font loading invalidates the built-in
Pretext measurement cache for mounted paged surfaces.
Pass a named root to PagedEditable or measurePages to measure and render
that root. Omit root for the primary document. "main" is an internal root
spelling and is rejected at the public boundary.
pageSettingsCodec persists validated finite PageSettings values in a state
field. The built-in presets are "a4" and "letter".
PagedEditable mounts the complete paged DOM by default. Set virtualize when
the complete surface exceeds the product's measured interaction or memory
budget. Pagination keeps visible, selected, and explicitly materialized page
content mounted in one coordinate system.
Omitted content remains in the Plite value, history, and collaboration state. Model selection and clipboard serialization can cross it. Native browser find, assistive technology, DOM printing, and third-party DOM integrations see only mounted content. Use a complete model-based export when those jobs need the whole document.
The Pretext engine uses browser font metrics. Font files, operating systems, and browsers can produce different line breaks. Treat live pagination as view state. Products that require identical exported pages need a controlled measurement environment for that export.