Skip to Content
API Referencecorecore/plugins

@stesura/core/plugins

ProseMirror plugins that make up the editor runtime, and the plugin keys for reading their state.

stesuraPlugins(schema, editorId, configuration?, options?) returns the full set: basePlugins (infrastructure) followed by customPlugins (features). Set an entry to false in options to leave that plugin out, e.g. { history: false } when a collab provider supplies its own undo/redo. configPlugin and viewModeInteractionsPlugin are always included; stesuraKeymapPlugin is not part of the set.

Functions & values

basePlugins

Infrastructure plugins: the config plugin (editor identity), history, gap/drop cursor, table editing, doc styling and math.

Each entry except the config plugin can be switched off by name, e.g. { history: false } when a collab provider supplies its own undo/redo.

Parameters:
NameTypeDefault
schemaSchema<any, any>
editorIdstring
configurationConfigPluginProps
propsBasePluginsProps
Returns:
Plugin<any>[]

clipboardSerializerFor

The schema’s default serializer, with text boxes in their clipboard form.

Parameters:
NameTypeDefault
schemaSchema<any, any>
Returns:
DOMSerializer

closeMathEditor

Closes the source editor, leaving the equation selected.

Parameters:
NameTypeDefault
stateEditorState
dispatch(tr: Transaction) => void
viewEditorView
Returns:
boolean

codeHighlightPluginKey

State: the code-block syntax highlighting decorations and their cache.

NameTypeDefault
get(state: EditorState) => Plugin<CodeHighlightPluginState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => CodeHighlightPluginState | undefined

Get the plugin’s state from an editor state.

computedStylePastePlugin

Strips the source page’s computed style from a browser copy before the parse.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

computedStylePastePluginKey

Identifies the web-copy base-style stripper.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

configPlugin

Holds the editor id and config in plugin state, so anything with an EditorState can resolve editor identity.

Root editors also create their stores and register them on mount, removing them on unmount. Sub-editors (parentEditorId set) create nothing; getEditorStores falls through to the parent’s stores.

Parameters:
NameTypeDefault
__0ConfigPluginProps & { editorId: string; }
Returns:
Plugin<ConfigPluginState>

configPluginKey

State: the editor id and configuration — how any code holding an EditorState resolves editor identity.

NameTypeDefault
get(state: EditorState) => Plugin<ConfigPluginState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => ConfigPluginState | undefined

Get the plugin’s state from an editor state.

customPlugins

Feature plugins: numbering, TOC, images, stylesheets, spacing, tables, search, paste handling and the rest of the editing behaviour.

Each entry can be switched off by name. Throws without field (the editor id).

Parameters:
NameTypeDefault
propsCustomPluginsProps
Returns:
Plugin<any>[]

docStylingPlugin

Mirrors the docBgColor doc attr (and its contrasting “auto” text color) as CSS variables on .editor-container, since the doc node has no toDOM. Set above .ProseMirror so footnote and header/footer sub-editors inherit them. Main editor only.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

findFloatingBox

The box with boxId in doc.

Parameters:
NameTypeDefault
docNode
boxIdstring
Returns:
SubEditorRegion | null

floatingBoxClipboardPlugin

Copies text boxes in a form the HTML parser keeps inside their paragraph, and line heights in a form other apps read.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

floatingBoxClipboardPluginKey

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

floatingBoxEdgeKeymap

Keeps the caret inside the box: arrows stop at its edges, document jumps go to its ends.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

floatingBoxEditorBindingPlugin

Pushes main-editor changes into the open text box editor. Mount on the main editor.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

floatingBoxEditorBindingPluginKey

MUST keep its label: the sub-editor exclusion list matches on it.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

floatingBoxKind

The text box sub-editor kind: the box’s blocks in an editor mounted inside the box’s node view (docs/executed/floating-objects-plan.md, section 3).

The exclusions are the notes’ plus the box itself (no box in a box, D5) and the nodes rendered through node views (D4): the static render could not match their live height. A box holding one of those does not open.

NameTypeDefault
kindstring

Human-readable kind name, used in log messages (“headerFooter”, “footnote”, …).

pluginKeyPluginKey<any>

The binding plugin’s key. MUST keep its existing string label — sub-editor plugin exclusion lists and host plugin filtering match on it.

registrySubEditorRegistry<FloatingBoxEditorKey>

Registry of currently mounted sub-editors of this kind.

wrapperNamestring

Inner wrapper node name; its spec is the main section’s, so section CSS vars and plugins keep working. E.g. “section_footer_header”, “section”.

regionNodeNamestring

The main-doc node this kind binds to (“header_footer_content”, “footnote_body”, …). The inner section_content takes ITS content expression, so the two can never drift; buildSubEditorSchema also asserts the derived schema can hold everything this node allows.

contentExprstring | ((base: Schema<any, any>) => string)

Override for the inner section_content expression. Leave unset (no built-in kind sets it): the region node’s own expression keeps the schemas in step. An override must be at least as strict as the region node, or inner edits produce steps the main doc rejects.

filterOutNodesstring[]

Node names stripped from the base schema when deriving the inner schema.

validateContentAgainststring

Inner node whose spec validates the initial content in createSubEditorState (default “section_content”). Notes use their body node type.

findRegion(state: EditorState, key: FloatingBoxEditorKey) => SubEditorRegion | null

Locate the bound region in a main-editor state.

wrapperAttrs(state: EditorState, key: FloatingBoxEditorKey) => Attrs | undefined

The inner wrapper’s attrs for a key, as useSubEditor seeds them (the owning section’s, for headers and footers). When set, the binding re-seeds an open sub-editor whose wrapper no longer matches, so commands that size against the wrapper (insertTable) see a page setup change made while it is open.

isRegionNode(node: Node, key: FloatingBoxEditorKey) => boolean

Recognize the region node of a given key among removed nodes, so the binding can react when the region disappears (e.g. a remote user deletes the note whose body is being edited). Omit when removal is handled elsewhere (the header/footer panel watches the main state itself).

onRegionRemoved(key: FloatingBoxEditorKey, state: EditorState) => void

Called (outside the render cycle) after the binding unregisters an editor whose region was removed. Feature-level cleanup: close the panel, toast.

onForwardRegionMissing(key: FloatingBoxEditorKey) => void

Called when inner→outer forwarding can’t find the region in the main doc (defensive — normally the binding’s removal path fires first).

prepareOuterTr(tr: Transaction) => void

Stamp kind-specific metas on the outer transaction built from inner steps (headers/footers add enableHeaderFooterEdits for the guard plugin). fromSubEditor and skipTrackChanges are always set by the machinery.

extraExcludedPluginsstring[]

Plugin key labels to exclude from the sub-editor ON TOP of the shared base list.

extraPlugins(schema: Schema<any, any>) => Plugin<any>[]

Kind-specific plugins, placed AHEAD of the host’s filtered plugins so they win for the same key binding — headers/footers use this to suppress document-wide keys (Mod-A, Mod-F).

editorId(key: FloatingBoxEditorKey, mainEditorId: string) => string

The sub-editor’s editorId (store scoping, toolbar routing). MUST include mainEditorId: the store registry is page-global, so a bare key would cross-wire two editors open on the same note.

matchesSearchRegion(region: SearchMatchRegion, key: FloatingBoxEditorKey) => boolean

True when a classified search-match region belongs to the sub-editor key.

viewSpec((view: EditorView) => PluginView) | undefined

Plugin view spec for the binding plugin on the MAIN editor. Notes use it to turn a NodeSelection into a TextSelection when a panel opens (the anchor may be deleted concurrently).

floatingBoxWrapperAttrs

The section attrs a box’s inner wrapper takes, for the sub-editor’s first state.

Parameters:
NameTypeDefault
stateEditorState
boxIdstring
Returns:
Attrs | undefined

formatPainterPlugin

Holds the formatting picked up by enableFormatPainter and applies it where the user next clicks, or on Enter (A11Y-20).

A single click on the toolbar button arms it for one use (once), a double click until dismissed. Escape (with focus anywhere), typing, or an unrelated toolbar interaction dismisses it. Owns the marker cursor while armed.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<FormatPainterPluginState>

formatPainterPluginKey

State: the captured formatting and whether the painter is armed.

NameTypeDefault
get(state: EditorState) => Plugin<FormatPainterPluginState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => FormatPainterPluginState | undefined

Get the plugin’s state from an editor state.

gapCursorClassPlugin

Sets GAP_CURSOR_ACTIVE_CLASS on the editor root so CSS can hide the text caret. Replaces .ProseMirror-focused:has(.ProseMirror-gapcursor) *, a universal subject on :has() that was re-evaluated on every DOM insertion.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

getAllowedImageTypes

The image types the policy lets users insert: what pickers offer.

Parameters:
NameTypeDefault
stateEditorState
Returns:
readonly SniffedImageType[]

getImageUploadPolicy

The policy in force for a state; undefined means inline fallbacks are allowed.

Parameters:
NameTypeDefault
stateEditorState
Returns:
ImageUploadPolicy | undefined

getMathEditorState

Whether the source editor is open, and for which equation.

Parameters:
NameTypeDefault
stateEditorState
Returns:
MathEditorState

headerFooterGuardPlugin

Blocks edits to the headers/footers hidden in the main editor unless the transaction carries the enableHeaderFooterEdits meta, and keeps the selection out of them.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

headerFooterRegion

Region key for one header/footer part of a section.

Parameters:
NameTypeDefault
sectionIndexnumber
kind"header" | "footer"
variantstring
Returns:
string

headerFooterSyncPluginKey

Key of @stesura/pagination’s header/footer sync plugin; its meta says which header/footer is open for editing.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

headingInputRulesPlugin

Typing a space after a heading prefix (”#”..”########”, “h1”..“h8”, case-insensitive) that is a paragraph’s entire content turns it into that heading level and deletes the prefix.

An immediate backspace restores the prefix and a “Normal” paragraph in one transaction (one undo step).

Parameters:
This function does not accept any parameters.
Returns:
Plugin<HeadingInputRuleState | null>

highlightCounterNodesPlugin

Selecting a counter (a click, as in Word, or the highlightCounterNodes meta) highlights every counter of the same list instance and level. While active, mark steps on the selected counter are widened to those counters; marks outside the allowlist are reverted.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<HighlightCounterNodesState>

highlightPlugin

Keeps the highlighter armed after a double click on the highlight button, painting persistedColor on mouseup or Enter until dismissed.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<{ persistedColor: null; }>

highlightPluginKey

State: the armed highlighter color, if any.

NameTypeDefault
get(state: EditorState) => Plugin<HighlightPluginState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => HighlightPluginState | undefined

Get the plugin’s state from an editor state.

imagePlugin

Upload placeholders plus the paste/drop handlers that start image uploads.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<DecorationSet>

imagePluginKey

State: in-flight image upload placeholders.

NameTypeDefault
get(state: EditorState) => Plugin<DecorationSet> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => DecorationSet | undefined

Get the plugin’s state from an editor state.

imageUploadPolicy

Declares the editor’s image upload policy. Mounts whose documents travel (collab, server persistence) pass allowInlineImages: false so that, with no upload strategy installed, dropped/pasted images are refused rather than embedded as base64, which bloats every commit and can exceed payload caps. Without this plugin, inline base64 fallbacks are allowed.

Parameters:
NameTypeDefault
policyImageUploadPolicy
Returns:
Plugin<ImageUploadPolicy>

imageUploadPolicyKey

State: the editor’s image upload policy (see imageUploadPolicy).

NameTypeDefault
get(state: EditorState) => Plugin<ImageUploadPolicy> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => ImageUploadPolicy | undefined

Get the plugin’s state from an editor state.

invisibleCharacters

Shows pilcrows, dots and arrows for paragraph marks, spaces and tabs by toggling data-show-invisible on the editor element; the glyphs come from CSS and the lazily loaded SpaceDot fonts.

Atom-final blocks get a real widget instead of the CSS ::after (see pilcrow-decorations.ts). The widget set is kept regardless of show: it is also the caret’s anchor after the atom, and only its glyph is gated in CSS.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<InvisibleCharactersState>

invisibleCharactersPluginKey

State: whether the pilcrow / space / tab markers are shown, plus the pilcrow widgets.

NameTypeDefault
get(state: EditorState) => Plugin<InvisibleCharactersState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => InvisibleCharactersState | undefined

Get the plugin’s state from an editor state.

languagePlugin

The language store’s plugin, which also puts the document’s language on the editor root, for the blocks without an entry.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<DerivedState<string>>

languagePluginKey

State: the root lang tag plus decorations for blocks that deviate from it.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

lowlightPlugin

Syntax highlighting for code blocks, backed by lowlight (highlight.js).

NameTypeDefault
specPluginSpec<CodeHighlightPluginState>

The plugin’s spec object .

propsEditorProps<Plugin<CodeHighlightPluginState>>

The props  exported by this plugin.

getState(state: EditorState) => CodeHighlightPluginState | undefined

Extract the plugin’s state field from an editor state.

mathEditorEnterCmd

Enter / F2 on a selected equation opens its source editor.

Bound in the main keymap ahead of the generic Enter handling, which would otherwise insert a paragraph after the selected node.

Parameters:
NameTypeDefault
stateEditorState
dispatch(tr: Transaction) => void
viewEditorView
Returns:
boolean

mathEditorPlugin

Tracks which equation’s source editor is open. The position is remapped per transaction and dropped once it no longer points at an equation.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<MathEditorState>

mathEditorPluginKey

State: which equation, if any, has its floating LaTeX source editor open.

NameTypeDefault
get(state: EditorState) => Plugin<MathEditorState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => MathEditorState | undefined

Get the plugin’s state from an editor state.

mathPlugins

Math editing: mathEditorPlugin plus input rules ($...$ → inline math, $$ + space → display math). Returns [] for schemas without the math nodes.

Deliberately NOT upstream’s mathPlugin: its MathView nodeviews (nested EditorView, destroy() removing its own DOM) crash under react-prosemirror, which owns nodeview DOM. Our math nodes are atoms rendered by React nodeviews (KaTeX only); the LaTeX source is edited in a floating editor (editor-react/src/floating-menus/math-menu). mathSelectPlugin is skipped too — it styles a selection inside the source, which is no longer in the doc.

Parameters:
NameTypeDefault
schemaSchema<any, any>
Returns:
Plugin<any>[]

numberingInputRulesPlugin

Typing a space after a known prefix at the very start of an unnumbered numbered-type block, with nothing after the caret, numbers it and deletes the prefix (“1. ” → numbered, ”* ” → bullet).

An immediate backspace (caret right after the counter) restores the typed text in one transaction (one undo step), and the rule stays off in that block until the caret leaves it.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<NumberingInputRuleState>

numberingPlugin

Numbering plugin wired with track-changes hooks. Public surface for now; once the hook API is settled, this will be replaced with an export that lets callers pass their own hook factory (e.g. so users without the track-changes package can opt out by passing nothing).

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

numberingPluginKey

The counter-evaluating numbering plugin. Stateless (a view that publishes the doc-global numbering context plus an appendTransaction that rewrites counter nodes) — the key exists so transactions can be tagged and the plugin excluded from sub-editors.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

numberingPropsPlugin

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

numberingPropsPluginKey

Props-only slice (caret teleport) — mounted in sub-editor views, which exclude the evaluating plugin.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

openMathEditor

Opens the source editor for the selected equation.

Deliberately keeps the NodeSelection: the equation stays visibly selected while its source is being edited, and closing needs no selection restore.

Parameters:
NameTypeDefault
stateEditorState
dispatch(tr: Transaction) => void
viewEditorView
Returns:
boolean

openMathEditorAt

Opens the source editor for the equation at pos (a click on the render).

Parameters:
NameTypeDefault
posnumber
Returns:
Command

openMathEditorTarget

The equation the source editor is open for, with its position.

Parameters:
NameTypeDefault
stateEditorState
Returns:
{ node: Node; pos: number; } | null

paginationPluginKey

State: page breaks, measurements and dirty sections. Owned by @stesura/pagination.

NameTypeDefault
get(state: EditorState) => Plugin<PaginationPluginState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => PaginationPluginState | undefined

Get the plugin’s state from an editor state.

pendingLinkPlugin

Tracks and decorates the range of a link being created, until the selection changes. Also opens links on Ctrl/Cmd+click.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<PendingLinkPluginState>

pendingLinkPluginKey

State: the link being created or edited, before it is committed to the doc.

NameTypeDefault
get(state: EditorState) => Plugin<PendingLinkPluginState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => PendingLinkPluginState | undefined

Get the plugin’s state from an editor state.

searchPlugin

Holds the active search query and range, and decorates its matches.

While a search is active, decorations are mapped through incoming steps rather than recomputed, so typing stays cheap; a debounced rescan then picks up matches the edit may have created.

Parameters:
NameTypeDefault
options{ initialQuery?: SearchQuery; initialRange?: { from: number; to: number; }; }
Returns:
Plugin<any>

searchPluginKey

State: the search query, range and match decorations.

NameTypeDefault
get(state: EditorState) => Plugin<SearchState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => SearchState | undefined

Get the plugin’s state from an editor state.

SearchQuery

A search query and its options (case sensitivity, whole word, regex, literal escapes), with the match and replacement logic built on top of them.

NameTypeDefault
caseSensitiveboolean
literalboolean
regexpboolean
replacestring
validboolean
wholeWordboolean
skipDeletionsboolean
ignoreAccentsboolean
preserveCaseboolean
approximateboolean
maxEditsnumber | undefined
replaceMarksreadonly Mark[]
formatOnlyboolean
filter((state: EditorState, result: SearchResult) => boolean) | null
implQueryImpl
matchSource(source: string) => string
with(changes: Partial<SearchQueryConfig>) => SearchQuery
eq(other: SearchQuery) => boolean
findNext(state: EditorState, from?: number, to?: number) => SearchResult | null
findAll(state: EditorState, from?: number, to?: number) => SearchResult[]
findPrev(state: EditorState, from?: number, to?: number) => SearchResult | null
checkResult(state: EditorState, result: SearchResult) => boolean
unquote(string: string) => string
getReplacements(state: EditorState, result: SearchResult) => { from: number; to: number; insert: Slice; }[]
replaceIn(tr: Transaction, state: EditorState, result: SearchResult) => void
withReplaceMarks(marks: readonly Mark[]) => readonly Mark[]

sectionUnwrapPastePlugin

Flattens pasted section structure into its body content and drops headers/footers.

Copying across sections puts whole section nodes on the clipboard; left alone, slice fitting splits the target section and duplicates headers/footers mid-document. Like Google Docs we never paste section structure; sections enter a doc via DOCX import only.

Only the slice’s top level is checked: sections can only be children of doc.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

selectAfterMath

Closes the source editor and moves on: the caret lands right after an inline equation, or at the start of the block following a display one.

NOT Selection.near: forward from the end of section_content it walks into the section FOOTER’s paragraph, and a raw TextSelection at the position after a block node is not inside any textblock. When nothing suitable follows a display equation it stays selected — the same result as closing.

Parameters:
NameTypeDefault
posnumber
Returns:
Command

selectionHighlightPlugin

Paints a non-empty text selection while the native highlight is gone: when the editor is blurred (e.g. focus in a toolbar or dialog) and editable, and always in view mode, where PM’s selectionToDOM writeback dies whenever chrome takes focus. Overlapping the native ::selection there doubles the alpha, deliberately. Node and cell selections are skipped: node views and .selectedCell paint their own.

Inline atoms (pictures, placeholders, math, …) the selection covers get .pm-in-selection at all times, which no ::selection reaches; recomputed only when the doc or the selection’s range changes.

Painted with the CSS Custom Highlight API: an inline decoration wraps every selected text node in a span, so after Ctrl+A the first transaction once focus left (a toolbar command) re-created every text node of the document, seconds on a long one. Where the API is missing, the .selection decoration, which lags a focus change by one transaction (focus dispatches nothing). Inline atoms keep that decoration with the API too; a focus change dispatches for them, and only when the selection holds one.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<AtomsInSelection>

setMathSource

Replaces the LaTeX source of the equation at pos. False when unchanged.

Writes the MINIMAL step (common prefix/suffix untouched) so collab merges and track-changes attribution see fine-grained edits; replacing the whole formula per keystroke would make every edit conflict with every other.

Parameters:
NameTypeDefault
posnumber
sourcestring
Returns:
Command

setPilcrowWidgetFactory

Installs the renderer-specific widget factory. @stesura/editor-react calls it at module load, before any state exists: a state created earlier keeps an empty set until its document changes. Without a factory no widgets are produced (the CSS ::after still covers blocks that are not atom-final).

Parameters:
NameTypeDefault
factoryPilcrowWidgetFactory
Returns:
void

spacingPlugin

The spacing plugin: the spacingStore’s plugin.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<DerivedState<SpacingEntry>>

stesuraPlugins

All Stesura plugins: basePlugins followed by customPlugins. A layout: "flow" config adds flowLayoutGuardPlugin and drops doc styling.

Parameters:
NameTypeDefault
schemaSchema<any, any>
editorIdstring
configurationConfigPluginProps
optionsStesuraPluginsOptions
Returns:
Plugin<any>[]

stripTrackChangesMarksFromSlice

Sanitizes a pasted slice (see sanitizeFragment). Returns the ORIGINAL slice instance when nothing changed. Open depths are clamped, since dropped nodes can invalidate them.

Parameters:
NameTypeDefault
sliceSlice
deletionMarkType
insertionMarkType
modificationMarkType
Returns:
Slice

styleNumberingInstanceId

The instance a style-numbered paragraph belongs to. Derived, not minted, so a whole style family is one continuous list per story (Word semantics); a restart replaces it with an explicit per-paragraph instanceId.

Parameters:
NameTypeDefault
listRefstring
regionstring
Returns:
string

styleSheetPlugin

Resolves the doc’s stylesheet and:

  1. publishes it (and the raw overrides) to the editor’s stores;
  2. writes its CSS into a <style> element scoped by editor id;
  3. heals blocks pointing at a style the sheet doesn’t have.

Throws on mount without an editor id, or one containing selector syntax.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

styleSheetPluginKey

State: the resolved stylesheet and the doc’s raw overrides.

NameTypeDefault
get(state: EditorState) => Plugin<StyleSheetState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => StyleSheetState | undefined

Get the plugin’s state from an editor state.

tableCellSelectionPreserver

Keeps a CellSelection alive when right-clicking inside it (for context menus).

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

tableDragHandlePlugin

Drag and drop for id-carrying nodes (tables). Works with any node view that has a [data-drag-handle] element inside its [data-pm-node-view] root, and either that root or a descendant carrying the node’s id. Ctrl/Cmd-drop copies.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<TableDragState>

tableDragHandlePluginKey

State: the in-flight row/column drag.

NameTypeDefault
get(state: EditorState) => Plugin<TableDragState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => TableDragState | undefined

Get the plugin’s state from an editor state.

tableEmptyRowGuardPlugin

Removes empty rows from tables (left behind when all cells of two rows are merged vertically), shrinking the rowspans that crossed them.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

tableHeaderCellsPlugin

Keeps each cell’s isHeader attr in step with its table’s headerRowCount (the cell starts in a header row; a merge never promotes a cell). A cell’s toDOM cannot see its table, so the flag is stamped onto the cells for the serializer, nodeview and exporters (A11Y-21).

Unlike the structural table guards it also runs on collab/history transactions: a pure derivation converges, and skipping them would leave peers rendering plain cells after a remote headerRowCount change.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

tableResizingPlugin

Column and row resizing by dragging cell borders, zoom-corrected.

An inner border trades width between its two columns, keeping the table’s total. An outer edge resizes its column alone and snaps to the section’s content edges; which outer edges are draggable depends on table alignment. A row dragged down to cellMinHeight or below resets to auto height.

Parameters:
NameTypeDefault
optionsTableResizingOptions
Returns:
Plugin<ResizeState>

tableSizingPlugin

Keeps every table’s column grid (colwidth) consistent with its width (docs/executed/table-sizing-plan.md §5). Doc-derived, idempotent, appended to the triggering transaction (one undo event; collab peers re-running it append nothing):

  • T1, a table inserted (paste, DOCX import, AI, a move): a table with a column of unknown width is fitted to the width it lays out in, an inserted fixed/pct table is held to its width (I1), and a pasted autofit table is fitted to its block. Rows (or a cell paste) giving a fixed/pct table more columns widen it instead: its width follows the grid (Word).
  • T2, a column resized or a cell replaced: nested tables fit their host (D3), a nested pct table follows it.
  • T3, a section’s attrs changed (page size, margins, columns) and T5, a block’s spanColumns: the section’s pct tables follow their new width, header and footer ones included (they live in the main doc, D10).
  • T4, a table’s width set: that table is held to it.

The rescale skips track changes (D12): it records derived widths, not edits. Undo and redo restore exactly: their steps trigger nothing.

Ordering: must run AFTER prosemirror-tables’ tableEditing(), whose fixTables repairs ragged Word tables. A still-invalid table is skipped and re-fitted on the pass after the repair transaction; one the hold skipped is held on a later pass of its dispatch that finds it repaired (TC-189).

Parameters:
This function does not accept any parameters.
Returns:
Plugin<boolean>

tabStopsPlugin

Lays tab characters out against Word’s tab stops (DOCX-97): each \t is an inline box sized so the text after it lands on the next stop — its own or its style’s, then the default interval — by the stop’s alignment, with the stop’s leader drawn in the gap.

Widths come from the rendered text, so they are measured after each render and applied as decorations; a tab not yet measured renders as the browser draws it. A render re-measures only the blocks that changed.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<DecorationSet>

tabStopsPluginKey

NameTypeDefault
get(state: EditorState) => Plugin<DecorationSet> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => DecorationSet | undefined

Get the plugin’s state from an editor state.

themePastePlugin

Re-resolves pasted theme refs under this document’s theme, as Word does when keeping source formatting: themed text from a document with another theme takes this one’s colours. Unthemed colours paste as they are.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

themePastePluginKey

Identifies the pasted theme-colour re-resolver.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

TOCplugin

Rebuilds the anchor registry (TOC store) when a transaction touches an anchor, coalesced to a microtask rather than debounced, so the TOC DOM settles in the same frame as the doc and pagination measures it once.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

tocPluginKey

Identifies the TOC plugin; the anchor registry itself lives in the editor’s stores.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

trackChangesKey

State: whether suggestions are shown and being recorded. Lives here rather than in @stesura/track-changes so core and comments can read it without depending on that package.

NameTypeDefault
get(state: EditorState) => Plugin<TrackChangesState> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => TrackChangesState | undefined

Get the plugin’s state from an editor state.

trackChangesStripPastePlugin

Strips track-changes state from every pasted or dropped slice, and widens a copy’s cells as accepting a pending column delete would (widenCopiedColumns).

The parse rules must accept <ins>/<del> and data-track-changes-* attrs for clipboard round trips, which lets forged HTML author someone else’s suggestion without the dispatch modifier. The gate is in core so it holds without the track-changes plugin, and in transformPasted because handlePaste never runs on drop (SEC-42). The JSON/collab path skips parsing and is the server’s to enforce.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

typographyPlugin

Replaces typed patterns with their typographic equivalents when followed by a space (-- → —, ... → …, -> → →, (c) → ©, 1/2 → ½, smileys). ---- + space as a paragraph’s whole content becomes a horizontal rule. An immediate backspace reverts a text replacement.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<TypographyState | null>

uniqueIdPlugin

Keeps node ids unique (one document-wide namespace) across edits. Load-time healing is createNormalizeTransaction’s job, not this plugin’s.

Provenance rules:

  • a node inserted by the transaction whose id existed in the old doc and still exists elsewhere is a copy → it gets a fresh id; if the id is now unique it was a move and keeps its identity. Sections too: the earlier section keeps the id its header/footer bindings and pagination caches key off;
  • brand-new ids inserted more than once go through the ref-aware sweep (applyIdCorrections) shared with load-time healing.

Participation is schema-driven: any node whose spec declares an id attr (all blocks, via the uniqueId global attribute, plus inline nodes declaring id in their own spec, e.g. image_anchored).

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

viewModeInteractionsPlugin

Interaction fixes that only apply in view mode. The hooks run regardless of view.editable (plugin props bypass ProseMirror’s editable gate), which is exactly why they’re needed:

  • dragstart: dragging an existing text selection fires a real HTML5 drag even on a non-editable view — dropping back in is blocked by the mode gate, but dragging content OUT of a read-only document is not. Block it.
  • keydown: ProseMirror runs no keymap on a non-editable view, so the positioned object cycle (Tab, Shift-Tab, Alt-F10, Escape) is bound here. Tab with no object selected still leaves the document.
  • handleClick: on a non-editable view Chromium creates no caret on click, so ProseMirror keeps the previous selection — the fallback highlight would show a stale range. Collapse to the clicked position (matches what Firefox does natively).
Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

widenCopiedColumns

slice, copied from selection, with each cell of a table it cuts at the width accepting that table’s pending column deletes gives its column in the source (TC-198). A copy inside a table holds rows or cells, no table, so the paste, which drops the struck cells, can’t widen what’s left; a table the slice holds whole is the paste’s to widen (TC-190). The original instance when nothing changed.

Parameters:
NameTypeDefault
sliceSlice
selectionSelection
Returns:
Slice

wordPasteHandlerPlugin

Normalizes HTML pasted from desktop Microsoft Word before ProseMirror parses it: converts equations to math nodes, rebuilds lists (Word pastes numbers as literal text), maps indentation/spacing onto the formatting global attributes, and strips Office junk. Non-Word HTML passes through.

A pasted list matching no existing config gets a new one, registered in doc.attrs.listConfigs by appendTransaction once the paste lands (the transform cannot dispatch). Currently the only transformPastedHTML plugin.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

wordPasteHandlerPluginKey

Identifies the Word paste handler.

NameTypeDefault
get(state: EditorState) => Plugin<any> | undefined

Get the active plugin with this key, if any, from an editor state.

getState(state: EditorState) => any

Get the plugin’s state from an editor state.

wrapSelectionWithPlugin

Typing a wrapping symbol over a selection wraps it instead of replacing it (selecting “Hello” and typing [ yields [Hello]); the selection is kept.

Parameters:
This function does not accept any parameters.
Returns:
Plugin<any>

Types

CodeHighlightPluginState

NameTypeDefault
cacheDecorationCache
decorationsDecorationSet | undefined
promisesPromise<void>[]

ConfigPluginProps

NameTypeDefault
configConfigPluginConfig
toastText(message: ToastMessage) => string

Resolves a toast key to display text. editor-react installs one from the mount’s locale — hosts only need this when they mount core on their own, and without it onToast receives the bare key as its description.

defaultsPartial<EditorStoreDefaults>
extensionStoresRecord<string, PreinitializedWritableAtom<unknown>>
parentEditorIdstring

Marks a sub-editor: store access delegates to this parent, and no stores are created.

PilcrowWidgetFactory

Builds the marker decoration at a block’s content end.

Injected because only a React widget places it correctly. A plain Decoration.widget(pos, domFactory) is rendered by react-prosemirror’s NativeWidgetView inside a bare editable <span> wrapper, which is what the WidgetViewDesc binds to; contentEditable="false" lands on the inner element only. react-prosemirror’s scanFor consults ignoreForSelection only at contentEditable="false" elements, so it descends into the wrapper: clicking past the atom parks an oversized caret there and the next keystroke resolves to the start of the section.

widget(pos, Component) from @stesura/react-prosemirror renders with no wrapper, so the factory lives in @stesura/editor-react.

Parameters:
NameTypeDefault
posnumber
Returns:
Decoration

SearchState

NameTypeDefault
enabledboolean
querySearchQuery
range{ from: number; to: number; } | null
matchesMatchSet

Every match, in document order.

decoDecorationSet

Their highlights: all of them up to HIGHLIGHT_LIMIT, the active one past it.

StesuraPluginsOptions

NameTypeDefault
historyfalse | { [key: string]: boolean; }
tableEditingfalse | { [key: string]: boolean; }
gapCursorfalse | { [key: string]: boolean; }
dropCursorfalse | { [key: string]: boolean; }
docStylingfalse | { [key: string]: boolean; }
mathPluginsfalse | { [key: string]: boolean; }
uniqueIdPluginfalse | { [key: string]: boolean; }
numberingPluginfalse | { [key: string]: boolean; }
seqPluginfalse

Caption numbers (seq_field); registered after numbering, whose counters chapter prefixes read.

highlightCounterNodesPluginfalse | { [key: string]: boolean; }
TOCpluginfalse | { [key: string]: boolean; }
imagePluginfalse | { [key: string]: boolean; }
selectionHighlightPluginfalse | { [key: string]: boolean; }
formatPainterPluginfalse | { [key: string]: boolean; }
searchPluginfalse | { [key: string]: boolean; }
spacingPluginfalse | { [key: string]: boolean; }
styleSheetPluginboolean
highlightPluginfalse | { [key: string]: boolean; }
tableResizingPluginfalse | { [key: string]: boolean; }
tableSizingPluginfalse | { [key: string]: boolean; }
tableEmptyRowGuardPluginfalse | { [key: string]: boolean; }
tableHeaderCellsPluginfalse | { [key: string]: boolean; }
tableStylesPluginfalse

Resolves table styles per cell for the live cell view (getCellFormat).

pendingLinkPluginfalse | { [key: string]: boolean; }
placeholderPluginfalse

Placeholder typing-over, double-click editing, paste and selection rules.

wrapSelectionWithPluginfalse | { [key: string]: boolean; }
typographyPluginfalse | { [key: string]: boolean; }
linkifyPluginfalse

Autolink typed/pasted URLs (Word’s autoformat).

headingInputRulesPluginfalse | { [key: string]: boolean; }
calloutInputRulesPluginfalse

> at a paragraph start wraps it in a quote callout.

tableDragHandlePluginfalse | { [key: string]: boolean; }
tableCellSelectionPreserverfalse | { [key: string]: boolean; }
invisibleCharactersfalse | { [key: string]: boolean; }
tabStopsPluginfalse

Lays tab characters out against paragraph tab stops.

languagePluginfalse | { [key: string]: boolean; }
sectionUnwrapPastePluginfalse | { [key: string]: boolean; }
trackChangesStripPastePluginfalse | { [key: string]: boolean; }
wordPasteHandlerPluginfalse | { [key: string]: boolean; }
computedStylePastePluginfalse | { [key: string]: boolean; }
themePastePluginfalse
pasteModePluginfalse

Word’s paste options: Keep Source / Merge Formatting / Keep Text Only, and the paste-options button.

definitionsPastePluginfalse

Copy carries the styles, lists and note bodies the content uses; paste imports what the destination lacks.

singleBlockPastePluginfalse

Pasted blocks become inline content where the container holds a single block.

directFormattingPluginfalse

Clears direct formatting the schema turns off (stesuraSchema({ directFormatting })). Inert otherwise.

lowlightPluginfalse | { [key: string]: boolean; }
headerFooterGuardPluginfalse | { [key: string]: boolean; }
floatingBoxClipboardPluginfalse

Copies text boxes as phrasing elements carrying their content as JSON.

floatingBoxEditorBindingPluginfalse

Syncs main-editor changes into an open text box editor.

Other exports

ExportTypeDescription
GAP_CURSOR_ACTIVE_CLASS"pm-gapcursor-active"Root class set while the selection is a gap cursor.
NUMBERING_REGION_BODY"body"Counter-stream regions — Word’s “stories”. Numbering DEFINITIONS are document-global; the counters that run off them are per story: the body, all footnotes together, all endnotes together, and each header/footer part.
NUMBERING_REGION_ENDNOTES"endnotes"
NUMBERING_REGION_FOOTNOTES"footnotes"
OVERSIZED_CLAMPS_POKE"oversizedClampsPoke"Payload-less meta key meant to signal that the oversized-node clamp set changed. Currently neither dispatched nor read anywhere.
PAGINATION_CLEAR_ALL_META"clearAllPaginationCaches"Meta key (true) that invalidates every section’s pagination cache, e.g. after a DOCX import. Lives in core so callers need not import pagination.
PAGINATION_DIRTY_NODES_META"paginationDirtyNodes"Meta key carrying node ids (string[]) whose rendered size changed without a doc change, e.g. a nodeview whose async data grew its DOM. Pagination re-measures only those nodes, never wiping the cache.
PILCROW_CLASS"pm-pilcrow"Class the CSS hangs the marker’s styling off.
Last updated on