Commands: Sections & Track Changes
Page layout commands (sections, page breaks, line numbers, headers and footers) from core, and the track-changes commands from @stesura/track-changes.
// section, page-break and header/footer commands ship in core
import { addSection, removeSection, setSectionFormat } from "@stesura/core/commands";
// track-changes commands ship in the track-changes feature pack
import {
enableTrackChanges,
disableTrackChanges,
toggleTrackChanges,
toggleTrackChangesVisibility,
resolveTrackChanges,
resolveAllTrackChanges,
selectTrackChanges,
} from "@stesura/track-changes";Track changes also requires transactionModifier={trackChangesTransactionModifier} on StesuraEditor so transactions flow through the diff layer:
import { trackChangesTransactionModifier } from "@stesura/track-changes";
<StesuraEditor /* ... */ transactionModifier={trackChangesTransactionModifier} />Sections
addSection
Split the current section after the top-level block holding the cursor. The blocks after it move into a new section that inherits the current one’s page setup and header/footer, and the cursor moves into the new section.
addSection(): CommandremoveSection / removeSectionAt
Remove the section containing the selection, appending its content to the previous section. Refused, with a toast, on the first section. removeSectionAt takes the section node’s position instead of reading the selection.
removeSection: Command
removeSectionAt(sectionPos: number): CommandsetSectionFormat
Set the current section’s orientation, page size and/or margins in one step. A page size whose aspect contradicts the orientation is transposed to match it, and an orientation change without a size swaps the page’s width and height. Refused when nothing changes.
setSectionFormat(options: SectionOptions): Command
type SectionOptions = {
orientation?: "portrait" | "landscape";
pageSize?: { width: number; height: number };
margin?: { // merged over the current margins
top?: number;
bottom?: number;
left?: number;
right?: number;
layout?: "narrow" | "moderate" | "wide" | "custom";
};
header?: boolean; // ignored by this command
footer?: boolean; // ignored by this command
};There is no section background colour. The canvas behind the pages is set with setDocBgColor(color) (the docBgColor doc attr).
setOrientation
Switch the current section between portrait and landscape, swapping page width and height. Refused when already in that orientation.
setOrientation(orientation: "portrait" | "landscape"): CommandinsertPageBreak
Insert a hard page break at the cursor (Word’s Ctrl+Enter). The paragraph is split around the break and the cursor lands after it; at the end of a block, the split leaves an empty paragraph for the cursor. Refused inside tables and outside section content.
insertPageBreak: CommandinsertPageNumber
Insert a page-number field at the cursor. Refused inside code blocks.
insertPageNumber({ pageType: "currentPage" | "totalPages" }): CommandinsertPageOfPage
Insert a “1 of 12” pair of page-number fields. middleText is the bare separator word (default "of"); a space is added on each side.
insertPageOfPage(middleText?: string): CommandLine Numbers
setLineNumbers
Merge attributes into the section’s line numbering (starting from the defaults when it is off), clamped to bounds.
setLineNumbers(attrs: Partial<{
countBy: number; // show only every Nth number (default 1)
distance: number; // gutter gap in px (default 10)
restart: "continuous" | "newPage" | "newSection"; // default "continuous"
start: number; // first line's number, 1-based (default 1)
}>): CommandtoggleLineNumbers
Turn the section’s line numbering on (with the defaults) or off.
toggleLineNumbers(): CommandtoggleSuppressLineNumbers
Toggle suppressLineNumbers on every suppressible block in the selection. Suppressed lines are skipped by the counter (Word semantics), not merely hidden. Pass suppress to force a value.
toggleSuppressLineNumbers(suppress?: boolean): CommandlineNumbersSuppressed
State reader, not a command: true when every suppressible block in the selection is suppressed.
lineNumbersSuppressed(state: EditorState): booleanHeaders & Footers
focusHeaderFooter
Select the content of the current section’s header or footer and set the headerFooterSyncPluginKey meta { openHeaderId, openFooterId }. It does not open the header/footer panel (nothing reads that meta), and on the main editor headerFooterGuardPlugin moves the selection back into the body. To open the panel, see Header & Footer.
focusHeaderFooter(focusOn: "header" | "footer"): CommandopenHeader / openFooter
Set the headerFooterSyncPluginKey meta { openHeaderId: nodeId } / { openFooterId: nodeId }. Nothing reads it, so the panel does not open.
openHeader(nodeId: string): Command
openFooter(nodeId: string): CommandsetHeaderFooterDistance
Set the section’s headerFromTop / footerFromBottom (px). Pass sectionId when dispatching on the main editor while a header/footer sub-editor holds focus. Refused when nothing changes.
setHeaderFooterDistance(options: {
headerFromTop?: number;
footerFromBottom?: number;
}, sectionId?: string): CommandinsertHeaderFooterContent / deleteHeaderFooterContent
Add or remove a header_footer_content variant on both the section’s header and footer. Inserting adds one empty paragraph wherever the variant is missing. Deleting the "default" variant is refused. insertHeaderFooterContentTr(tr, state, sectionId, variant) in @stesura/core/commands/internal is the composable form.
type HeaderFooterVariant = "default" | "first" | "even";
insertHeaderFooterContent(sectionId: string, variant: HeaderFooterVariant): Command
deleteHeaderFooterContent(sectionId: string, variant: HeaderFooterVariant): CommandinsertPageNumberPreset
Insert a page number into a section’s header (top) or footer (bottom) as a Word-style preset: a borderless 1×3 table with left-, centre- and right-aligned columns. Creates the variant if needed, all in one transaction. Dispatch it on the main editor, not a header/footer sub-editor.
insertPageNumberPreset({
sectionId: string,
variant?: HeaderFooterVariant, // default "default"
position: { vertical: "top" | "bottom"; horizontal: "left" | "center" | "right" },
pageType?: "currentPage" | "totalPages" // default "currentPage"
}): CommandfixHeadersFooters
Repair header/footer structure: resolve null and duplicate variants, mirror each variant on both header and footer (always including "default"), and give every content node at least one paragraph. Refused when nothing needs fixing.
fixHeadersFooters: CommandWhich variants a section displays (different first page, odd/even) follows from which header_footer_content nodes exist, so insertHeaderFooterContent / deleteHeaderFooterContent toggle them — see Header & Footer.
Borders
Border commands (setBorders, toggleOutline, insertHorizontalRule) are documented on the tables page. They also apply to styled blocks and horizontal rules.
Track Changes
enableTrackChanges / disableTrackChanges / toggleTrackChanges
Turn track-changes recording on or off. The optional show argument also sets visibility at the same time. Omitted, turning tracking on also turns visibility on, and turning it off leaves visibility as it is. In review mode, disableTrackChanges and toggleTrackChanges return false.
enableTrackChanges(show?: boolean): Command
disableTrackChanges(show?: boolean): Command
toggleTrackChanges(show?: boolean): CommandtoggleTrackChangesVisibility
Flip whether pending suggestions are displayed. Tracking itself is untouched — edits keep being recorded while the markup is hidden.
toggleTrackChangesVisibility: CommandselectTrackChanges
Move the selection to cover the tracked change with the given id — inline marks and block-level suggestions (a deleted row, a pending attribute change) alike.
selectTrackChanges(selectionId: string): CommandresolveTrackChanges
Accept or reject the suggestion under the cursor (or covering the selection). With an empty selection it resolves the whole same-user, same-burst change; a drawn selection resolves every suggestion it touches, in full. moveToNext jumps to the next suggestion afterwards.
Dry runs (toolbar probes) answer false on a document with no pending changes, so Accept/Reject buttons disable themselves when there is nothing to review — the same applies to resolveAllTrackChanges and disableTrackChanges, which return false rather than dispatching when they would change nothing.
resolveTrackChanges(action: "approve" | "reject", moveToNext?: boolean): CommandresolveAllTrackChanges
Accept or reject every suggestion in the document at once.
resolveAllTrackChanges(action: "approve" | "reject"): CommandTrack Changes Marks
Tracked inline edits are stored as marks from @stesura/core/schema:
insertion: pending inserted text, rendered as<ins>.deletion: pending deleted text, kept in the document and rendered as<del>.modification: a pending inline mark change.typeis"addMark"(newValueholds the added mark’s JSON) or"removeMark"(previousValueholds the removed one).
Each mark carries id, date, userId and userName. Block-level changes live on node attributes instead: trackChanges (block insertion or deletion) and trackChangesModification (attribute changes).
Next Steps
- Commands: Specialized — Footnotes, numbering, code blocks, images, and more
- Schema — Section node attributes reference
- Track Changes — Full track-changes reference