feat: pagination — numbering formats, forced breaks, resets, PDF page labels (#46)#55
Merged
Merged
Conversation
… labels (#46) Overhauls the pagination system so postext can produce books and long-form documents with the numbering conventions readers expect (roman front matter, arabic chapters from 1, chapters opening on the right-hand page, etc.). - `page.pageNumbering` (format + startAt) drives the document-wide default. - `:::pagebreak` and `:::numbering` directives parsed as new block type, consumed by the placement pipeline as control markers. - Heading `breakBefore` (enabled + parity) forces page opens per level, padding with a blank parity page when needed. - `VDTPage` now carries `pageNumberValue`, `pageLabel`, `pageNumberFormat`, and `blankForParity`. - `buildPageLabels` / `collectPageLabelRuns` added to `numbering.ts`. - PDF backend emits a `/PageLabels` number tree matching VDT runs, with per-page `P` prefix fallback past Z for alpha formats. - `{pageNumber}` placeholder now resolves to `page.pageLabel`. - Sandbox: Numbering subsection under Page; `Break before` toggle + parity selector per heading level. - New warnings: unknown directive, invalid numbering format / startAt, invalid parity, parity cascade, alpha PDF overflow. - Docs updated in EN + ES (configuration, document-format, sandbox). - Tests: buildPageLabels, collectPageLabelRuns, directive parser. Closes #46 Unblocks #45 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
12 tasks
…uetas y herramientas
When a heading `breakBefore: { parity: 'odd' }` or `:::pagebreak{parity=...}`
forces a new page on a specific parity, a blank padding page can be
inserted to push the next content onto the right side. That blank page
was previously inheriting the PREVIOUS chapter's title in the
`{chapterTitle}` header placeholder — making the reader think chapter N
continues across a blank left-hand page before chapter N+1 begins.
Conceptually the blank page only exists because of the upcoming chapter,
so the parity padding should carry the new chapter's title. After
computing titles the walker now scans backwards from each H1's page
index and overwrites any consecutive `blankForParity` pages with the
upcoming chapter's title.
`computeChapterTitles` gains an optional `pages?: ChapterTitlePageInfo[]`
parameter for backwards compatibility — existing callers that only pass
`(blocks, totalPages)` keep the legacy behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…arse
next-intl parses messages through ICU MessageFormat, so a literal `{...}`
was being read as a malformed placeholder and the sandbox page crashed
with `INVALID_MESSAGE: MALFORMED_ARGUMENT`. Removing the example
attributes from the tooltip sidesteps the parser entirely — the button's
default action already inserts a directive with sensible defaults, so the
tooltip doesn't need to spell the attribute syntax out.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e parity
Adds two new values to `HeadingBreakParity` (and the `:::pagebreak{parity=...}`
attribute): `'always-odd'` and `'always-even'`. These guarantee at least
one mandatory blank separator page between the previous content and the
new heading, on top of the existing parity guarantee.
The leading separator is flagged `blankForForce: true` — it belongs to
the *previous* chapter (acts as a deliberate end-of-chapter gap). Any
parity padding that follows is still `blankForParity: true` and
belongs to the *new* chapter, preserving the prior fix.
`computeChapterTitles` stops its backward walk at `blankForForce`
pages, so the separator keeps the previous title in its header.
Sandbox:
- SelectInput for `breakBefore.parity` now exposes 5 options and the
whole conditional block is wrapped in `NestedGroup` for consistent
visual grouping with other toggle + children patterns.
- EN/ES labels added for the two new modes.
- Warnings validator accepts the new attribute values.
Docs + tests updated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a document opens with a heading that has `breakBefore.enabled` (or the source begins with a `:::pagebreak`), the placement cursor is already sitting on page 0 with nothing placed yet. Running parity or `always-*` padding at that point would insert a spurious leading blank page — there is no previous content to separate from. `enforcePageParity` now short-circuits when the cursor is on page 0 and every column of that page is still empty. Once any content has been placed, parity enforcement behaves exactly as before. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
page.pageNumbering(format + startAt) plus:::pagebreak/:::numberingdirectives and per-headingbreakBeforeso documents can mix roman front matter, arabic chapters from 1, and chapters opening on the right-hand page.VDTPagenow carriespageNumberValue/pageLabel/pageNumberFormat/blankForParity; the PDF backend emits a/PageLabelsnumber tree (with/Pprefix fallback past Z for alpha).{pageNumber}placeholder now resolves topage.pageLabel.unknownDirective,numberingInvalid*,pagebreakInvalidParity,parityCascade,alphaPdfOverflow), docs (EN + ES), and tests land in the same PR.Closes #46
Unblocks #45
Test plan
pnpm --filter postext test— 188 passing (addsnumbering-page.test.tsanddirectives.test.ts, updatesexports.test.ts)pnpm check-types— postext / postext-pdf / postext-sandbox clean; web typecheck error is pre-existing ondeveloppnpm lint— no new errors (pre-existing warnings only inpostext-sandbox):::numbering+ headingbreakBefore: { enabled: true, parity: 'odd' }and confirm the PDF page indicator matches the printed labels in Preview / Acrobat🤖 Generated with Claude Code