@nextgensoftwares/folio-plugin-toc
Chapters, outline, table-of-contents block, navigator and scroll-to-section. Guide: Table of contents plugin. in progress
Plugin
| Export | Signature | Description |
|---|---|---|
tocPlugin | (options?: TocPluginOptions) => TocPlugin | schema, renderer, tocEntry painter, commands, UI items and wrapLayout |
type TocPluginOptions | defaults?: Partial<TocAttrs>, chaptersStartOnNewPage?: boolean (adds the rule below), maxPasses?: number (default 3) | |
type TocPlugin | FolioPlugin whose wrapLayout returns a TocLayoutFn | |
h1StartsPageRule | FormatRuleLike | same semantics as @nextgensoftwares/folio-formatter's h1StartsPage |
Schema
| Export | Description |
|---|---|
TOC_TYPE, ENTRY_FRAGMENT | 'tableOfContents', 'tocEntry' |
tocNodeSpec, tocSchema | the atom block node and its Partial<SchemaSpec> |
tocAttrs(attrs) | defaults applied, bad values sanitized → TocAttrs |
TocAttrs | { title: string | null; levels: number; leaders: Leaders; numbered: boolean; dir: 'ltr' | 'rtl' | null; entries: TocSnapshotEntry[] | null } |
Leaders | 'dots' | 'none' |
TocSnapshotEntry | { level, text, page } persisted by "Update table" |
tocRenderer | BlockRenderer: rows from live data or the snapshot, each with an invisible tocEntry fragment |
Live page numbers
| Export | Signature | Description |
|---|---|---|
withTableOfContents | (next: LayoutFn, opts?: { maxPasses?: number }) => TocLayoutFn | fixed point around a host layout function |
LayoutFn | (doc: FolioDocument) => DocumentLayout | |
TocLayoutFn | LayoutFn & { readonly stats: TocLayoutStats; readonly outline: () => Outline } | |
TocLayoutStats | { passes: number; overheadMs: number; converged: boolean } | for the last call |
computeTocData | (toc, entries, layout | null, blockMap?) => TocData | rows for a TOC node from a layout (blockMap translates indices of an older layout) |
tocDataOf | (node) => TocData | undefined | live data of a laid-out TOC node |
TocData, TocRow | { rows }; { level, text, page, number? } | |
tocRowsFor | (node: FolioNode) => readonly TocRow[] | the rows the screen shows: live layout data, else the "Update table" snapshot (entries attr), else none |
tocDocxExporter | (attrs, ctx: TocDocxContext) => Promise<unknown[] | undefined> | exporters.docx entry: the title (a styled paragraph, not a heading), then one static-text paragraph per row with the screen's per-level indent, outline number and a right tab stop (dot leader unless leaders: 'none') for the page number; undefined without ctx.node |
TocDocxContext | { node?, dir, width, theme?, blocks(nodes) } | the structural subset of export-docx's context the exporter uses |
Outline
| Export | Description |
|---|---|
OutlineTracker | incremental outline: update(content) => Outline (same object when no heading changed), current, previousIndex(block) |
Outline, OutlineEntry, TocRef | { entries, tocs }; { id, node, block, level, text, visual }; { node, block } |
headingInfo(node) | { level, text, visual } | null, memoized by node identity |
visualLevel(v) | level 1–6 from a visualHeading value (2, "2", "h2", true = 1) |
lowerBound(list, block) | first index whose block ≥ block |
chaptersBreakPages(entries) | every real H1 after the first has pageBreakBefore |
outlineNumbers(entries) | "1", "1.1", "1.0.1"… counted from the shallowest level (memoized) |
visibleRows(entries, collapsed, filter?), OutlineRow | navigator rows { index, entry, depth, hasChildren, expanded } |
parentOf(entries, i) | nearest previous entry with a smaller level, or -1 |
chapters(entries, layout), Chapter | H1s with page ranges { entry, index, number, firstPage, lastPage, firstNumber, lastNumber } |
Resolving positions
| Export | Signature | Description |
|---|---|---|
DocPoint | { page: number; y: number } | page index + y in page px |
pageOfBlock | (pages, block, from?, to?) => number | binary search over page.blocks (no fragments built); -1 if absent |
blockTop | (page, block) => number | top y of a block on a page (reads that page's fragments only) |
blockPosition | (layout, block) => (DocPoint & { number }) | null | where a block starts |
entryPages | (layout, entries) => Int32Array | page index per entry, galloping forward |
activeEntry | (entries, layout, at: DocPoint, slack?) => number | scroll spy: the entry whose section contains at |
Scroll math
| Export | Description |
|---|---|
PageStackGeometry | { pad, gap, zoom, pageHeight, pageTop? } of a virtualized page column (pageTop: the view's pageTop, for mixed page heights) |
slotHeight(g) | pageHeight × zoom + gap |
scrollTopFor(target, g, margin?) | scrollTop that puts a point near the top |
pointAt(scrollTop, g, pageCount) | inverse of scrollTopFor |
visiblePages(scrollTop, viewport, g, pageCount) | { first, last } |
Commands
| Export | Signature | Description |
|---|---|---|
insertToc | (attrs?) => Command | insert at the selection and select it |
setTocAttrs | (patch, pos?) => Command | change attrs |
setTocLevels, setTocLeaders | (value, pos?) => Command | shorthands |
updateToc | (editor, pos?) => Command | store current rows with page numbers in entries |
removeToc | (pos?) => Command | remove the selected/first TOC |
targetToc | (state, pos?) => number | null | the TOC a command acts on |
setChaptersStartOnNewPage | (on: boolean) => Command | pageBreakBefore on every top-level H1 but a leading one |
chaptersStartOnNewPage | (state) => boolean | is that set? |
newChapter | (opts?: NewChapterOptions) => Command | Heading 1 at the caret (at: before top-level block at), "Chapter N" selected; breaks when chapters do (pageBreak overrides); one undo step |
makeChapter | ({ pageBreak? }?) => Command | caret's top-level paragraph/heading → Heading 1 |
selectChapterTitle | (index?) => Command | select the title of a chapter (default: the caret's) |
chapterIndexAt | (state, block?) => number | null | top-level index of the chapter around a block |
NewChapterOptions | { pageBreak?, title?(n), at? } | |
chapterInheritPlugin | () => Plugin | ProseMirror plugin: new chapters inherit pageBreakBefore from neighbouring chapters (in tocPlugin().pmPlugins) |
Navigation
| Export | Signature | Description |
|---|---|---|
TocHost | { scrollTo(target: DocPoint); viewportTop(): DocPoint | null; subscribe(fn): () => void } | the view's scroll adapter |
registerTocHost | (editor, host) => () => void | register (returns unregister) |
tocHostOf | (editor) => TocHost | undefined | |
outlineOf | (editor) => Outline | the editor's current outline (incremental) |
goToBlock | (editor, block, host?) => DocPoint | null | caret to a block's start, scroll to it |
goToTocEntry | (editor, tocBlock, k, host?) => DocPoint | null | follow row k of a TOC |
React
| Export | Description |
|---|---|
OutlineNavigator, OutlineNavigatorProps | { editor, host?, numbering?, rowHeight? }: searchable, collapsible, virtualized outline with scroll spy and chapter view |
TocEntryPainter, TocEntryPainterProps, tocEntryAt(page, x, y) | link painter for tocEntry fragments; hit-test helper |
useOutline(editor), useTocHost(editor, explicit?), useActiveEntry(host, outline, layout) | deferred outline, registered host, scroll spy |
Chapters setting
doc.attrs.chapters ({ enabled, level }) decides whether headings of a level are chapters: the Chapters view, "New chapter", chapter context items and "Chapters start on a new page" show only while chapters are on, and they start header/footer sections. The outline lists headings either way. tocPlugin({ chapters }) sets the default for documents that don't store it.
| Export | Signature | Description |
|---|---|---|
chapterConfig | (doc) => { enabled, level } | the document's setting, else the plugin default |
setChapterSettings | (patch: ChapterSettings) => Command | store it in the document (toc.setChapters) |
setChapterDefaults | (c?: ChapterSettings) => void | the default (called by tocPlugin) |
isChapterHeading | (node, { enabled, level }) => boolean | a chapter heading |
withChapterDefaults | (next: LayoutFn) => LayoutFn | layout sees the plugin default when the document has none (part of wrapLayout) |