docs/plans/2026-05-21-slate-v2-pagination-page-flow-fix.md
Fix the experimental pagination example so typing does not grow the first page surface. Page chrome must be fixed layout-owned geometry; the editable must be a separate editor layer.
.tmp/slate-v2.PagedEditable around fixed page surfaces plus one editor overlay.PagedEditable renders <Editable> as children of page index 0.minHeight: page.height, so editor content growth
can grow page 0 forever.layoutWithLines and line-range APIs, but the current
Slate layout engine only stores line counts. True fragmented editing remains a
later architecture step.PagedEditable now renders page surfaces and the editor layer as siblings.
Page renderers receive children: null; page chrome no longer owns the
editable tree.projectRange now accepts page geometry options so spread/single placement
and selection projection use the same geometry primitive.getSlatePageLayoutGeometry and tests for fixed page
pagination, single/spread placement, and spread-aware range projection.PagedEditable and the pagination example to use fixed
absolute page chrome plus one editor overlay.http://localhost:3100/examples/pagination:
typing 240 chars at the document start changed page count to 2 while page 0
stayed at fixed scaled height 869.419px.bun --filter slate-layout test,
bun --filter slate-layout typecheck, bun typecheck:site,
bun --filter slate-layout build, and final bun check.../premirror setup. New target: copy the Premirror model more
directly by making the editor overlay cover the whole page stack and
positioning text lines from layout fragments.lines, PagedEditable uses a
full-stack editor overlay, and the example projects decorated leaves into
absolute page coordinates.pages 5 | blocks 56, facing pages across
two rows plus one trailing page, no document-level horizontal scroll, and
screenshot at
.tmp/019e46be-4ec4-7d11-bc6e-9fcf033a8803/pagination-premirror-setup.png.bun --filter slate-layout test, bun --filter slate-layout-pretext test, bun --filter slate-layout typecheck, bun --filter slate-layout-pretext typecheck, bun typecheck:site,
bun --filter slate-layout build, bun --filter slate-layout-pretext build,
bun lint:fix, and final bun check.insertBreak at the document start made
leading empty paragraphs invisible and one Backspace removed all of them.
Added getSlatePageLayoutProjection, projected empty blocks into real
paragraph boxes, switched the example element bridge from object identity to
Slate path keys, and fixed core Backspace to remove one preceding empty
paragraph per command.slate-layout projection test for repeated empty
blocks, slate-layout-pretext empty-line test, slate delete regression for
repeated leading breaks, and Chromium pagination integration coverage for
eight leading breaks plus one Backspace.bun test ./packages/slate/test/delete-contract.ts --bail 1, bun test ./packages/slate/test --bail 1,
bun --filter slate-layout test, bun --filter slate-layout-pretext test,
package typechecks/builds for slate, slate-layout, and
slate-layout-pretext, bun lint:fix, bun check, and
PLAYWRIGHT_RETRIES=0 PLAYWRIGHT_WORKERS=1 bun run playwright playwright/integration/examples/pagination.test.ts --project=chromium.insertBreak operations. Browser proof at
http://localhost:3101/examples/pagination: caret left 93.3387, frame left
93.1210, so the caret is 0.2177px inside the frame.[0,0] offset 290.0 and 1 and expects selection at [0,0]
offset 290.slate-layout pagination so small root
split: 'avoid' boxes move whole to the next page when they do not fit the
current page remainder.slate-layout coverage for avoid-split page moves, a
Chromium fixture regression proving the first 42 synthetic paragraphs contain
no blank spacer, and a rich Markdown regression proving the code block stays
inside a debug content frame. Browser screenshots:
.tmp/019e46be-4ec4-7d11-bc6e-9fcf033a8803/pagination-fixed-top.png and
.tmp/019e46be-4ec4-7d11-bc6e-9fcf033a8803/pagination-rich-fixed.png.getSlatePageLayoutDecorations iterated
per-run but passed line-wide rects to every run, so each leaf painted at the
same absolute left/top. Changed decoration rects to run-scoped text rects
while extending only the final run hit rect through the blank line tail.
Added package and Chromium regressions for mixed inline non-overlap. Browser
proof at http://localhost:3100/examples/pagination: mixed paragraph has 8
leaves, overlap count 0, screenshot
.tmp/019e46be-4ec4-7d11-bc6e-9fcf033a8803/pagination-rich-inline-fixed.png.slate-layout still synthesized line runs with 8px * chars, ignoring
Helvetica bold/italic and monospace code widths. slate-layout-pretext now
emits measured runs per line using each run's own font and letter spacing.
Added package coverage for font-aware run positions and Chromium coverage for
non-overlap plus no loose non-final run spacing. Visual proof screenshot:
.tmp/019e46be-4ec4-7d11-bc6e-9fcf033a8803/pagination-rich-inline-spacing-fixed-playwright.png.