Skip to Content
CommandsCommands: Core

Commands: Core

Generic commands for marks, node types, content insertion and attributes.

All commands follow the ProseMirror signature (state, dispatch?, view?) => boolean. Calling without dispatch is a dry run that returns whether the command would apply.

import { toggleBold, setMark, insertContent } from "@stesura/core/commands";

Marks

toggleMark

Toggle a mark on the selection. With a bare cursor inside a word the whole word is toggled; at a word boundary the mark is stored for the next keystroke. On a range the mark is added if any part is missing it, and removed if it is present everywhere. Returns false when markType is undefined or the mark cannot apply.

toggleMark(markType: MarkType | undefined, attrs?: Attrs | null, options?: ToggleMarkOptions): Command

Options:

  • expandSelectionToWord (default true): a bare cursor inside a word toggles the whole word.
  • enterInlineAtoms (default true): false skips the content of inline atoms fully covered by the range.
  • onlyToggleOnAttrsMatch (default true): a mark with different attrs counts as missing, so toggling replaces it rather than removing it.
  • removeWhenPresent and includeWhitespace are accepted but currently ignored.

toggleMarkOnEntireWord

toggleMark by mark name with expandSelectionToWord on. Returns false when the mark is not in the schema.

toggleMarkOnEntireWord(markName: string, attrs?: Attrs | null): Command

setMark

Apply a mark, merging attributes into any existing mark of that type. If the merge leaves only null attrs, the mark is removed. A cursor inside a word marks the whole word; at a word boundary the mark is stored.

setMark(typeOrName: string | MarkType | undefined, attributes?: Attrs): Command

unsetMark

Remove a mark from the selection and from the stored marks.

unsetMark(typeOrName: string | MarkType | undefined, options?: { extendEmptyMarkRange?: boolean }): Command

extendEmptyMarkRange makes a bare cursor remove the mark across its whole contiguous range (e.g. unlink the entire link under the caret).

Convenience Mark Toggles

Built on toggleMarkOnEntireWord:

toggleBold: Command // strong; refused while an equation is selected toggleItalic: Command // em; refused while an equation is selected toggleUnderline: Command // underline toggleStrike: Command // strikethrough toggleSubscript: Command // subscript toggleSuperscript: Command // superscript toggleCode: Command // code; refuses to APPLY where the selection touches a link (removal still works)

Nodes

setNode

Turn the selected blocks into a textblock type. When the selection sits in one parent, that parent’s attrs are carried over. If the type can’t be set directly, the blocks are first lifted out of their wrappers, in the same transaction. Non-textblock types return false.

setNode(typeOrName: string | NodeType, attributes?: Attrs): Command

toggleNode

Switch the selected blocks to typeOrName, or back to toggleTypeOrName when they already are that type. When the selection sits in one parent, its attrs carry over to the new node, so overwrite any attr that must not be inherited in attributes.

toggleNode( typeOrName: string | NodeType, toggleTypeOrName: string | NodeType, attributes?: Attrs ): Command

toggleHeading

Toggle the selected blocks between heading at level and paragraph. The styleId is set to Heading<level> on the way up and reset to Normal on the way down. Returns false for a missing level.

toggleHeading(level: number | undefined): Command

insertOrWrapNode

Insert a node of the given type, or wrap the selection in it. Block types wrap the selected blocks, or at a bare cursor insert an instance holding a placeholder paragraph. Inline types wrap the selected inline content, or insert an instance holding placeholder text, which is then selected. Returns false when the type is not in the schema, can’t hold the content, or (inline) the selection crosses a block boundary.

insertOrWrapNode(nodeName: string, attributes?: Attrs): Command

deleteNode

Delete the node at a document position. Returns false when pos is null or holds no node.

deleteNode(pos: number | null): Command

Content Insertion

insertContent

Insert a node, a fragment, or HTML/JSON content (parsed against the schema) at the selection, leaving the caret after it. Plain text keeps the current marks. Block content inserted into an empty textblock replaces that block. Refused inside code blocks.

insertContent(value: Content | Node | Fragment): Command

insertSymbol

Insert a literal character at the selection, keeping the current marks.

insertSymbol(symbol: string): Command

Attributes

updateAttributes

Set attributes on every node or mark of the given type in the selection, plus the innermost enclosing node of that type. On a collapsed selection a matching stored mark is updated too. Keys the type does not declare, and values that are already equal, are skipped. A no-op update returns false.

A value can be a resolver (current, node?) => next, for attrs whose new value depends on the old one.

updateAttributes({ attributes: Record<string, unknown | ((current: unknown, node?: Node) => unknown)>, typeOrName: string | NodeType | MarkType }): Command

updateAttributeAt

Set a single attribute on the node at a known position. Returns false when no node sits at pos, or when type is given and doesn’t match.

updateAttributeAt({ attribute: string, value: unknown, pos: number, type?: string | NodeType }): Command

resetAttributes

Reset the named attributes to their schema defaults on every node or mark of the given type in the selection.

resetAttributes({ attributes: string | string[], typeOrName: string | NodeType | MarkType }): Command

Formatting

clearFormatting

Remove every mark from the selection except the track-changes marks (insertion, deletion, modification), so pending suggestions survive. Selected equations are cleared too. Refused inside code blocks.

clearFormatting(options?: { expandSelectionToWord?: boolean; // default true: a bare cursor clears the surrounding word clearTextBlockFormatting?: boolean; // also reset the paragraph/heading's indent, alignment, // background, borders, line height, tab stops and spacing resetStyleToNormal?: boolean; // also set styleId to Normal (a heading becomes a paragraph); // only applies with clearTextBlockFormatting }): Command

Composing Commands

composeCommands runs several commands against one transaction, so the group undoes in a single step and each command sees what the previous ones wrote:

import { composeCommands, setTextAlign, setSpacing, toggleBold } from "@stesura/core/commands"; const formatAsTitle = composeCommands( toggleBold, setTextAlign("center"), setSpacing({ before: 24, after: 12 }) ); formatAsTitle(view.state, view.dispatch);

See Composing Commands for sequenceCommands and the limits that apply to a composed group.

Helpers

All from @stesura/core/helpers.

State Inspection

isMarkActive, isNodeActive, getAttributes, getMarkAttributes, getNodeAttributes, getNodeType, getMarkType: read the active marks and nodes, and resolve type names against the schema.

Document Inspection

docChanged, getChangedRanges, findNode, findNodes, findChildrenInRange, forEachNode: walk and diff documents.

Transaction Classification

isHistoryTransaction(tr): boolean isCollabTransaction(tr): boolean isRemoteCollabTransaction(tr): boolean isCollabOrHistoryTransaction(tr): boolean

Utilities

isTextSelection, isWholeTableSelected, posToDOMRect, unWrap, createNodeFromContent, selectionToInsertionEnd: selection and DOM utilities.

Next Steps

Last updated on