How to create a NodeType Instance to write the content?

Hi, I have been trying to write a latex equation programmatically using the ProseMirror Math plugin, (GitHub - benrbray/prosemirror-math: Schema and plugins for "first-class" math support in ProseMirror!).

This is the command I am using(prosemirror-math/src/commands/insert-math-cmd.ts at master · benrbray/prosemirror-math · GitHub), But however, I don’t know how to pass the NodeType Instance to that function.

  addLatex() {
// this.editor.schema.nodes.math_inline = "{S}_{dp}={n}_A.{n}_B.\mathit{\exp}\left(-{wd}^2\right); Sc= median\left\{{S}_{dp}\right\}"
const nodeSchema = this.editor.schema.node(schema.nodes.math_inline);
nodeSchema.textContent = "{S}_{dp}={n}_A.{n}_B.\mathit{\exp}\left(-{wd}^2\right); Sc= median\left\{{S}_{dp}\right\}";
this.editor.commands
        .insertMathInline(nodeSchema)
        .exec();
  }
  insertMathInline(nodeType:NodeType): this {
    insertMathCmd(nodeType)(this.state, this.dispatch);
    return this;
  }
const mathInline: NodeSpec = {
  group: "inline math",
  content: "text*",        // important!
  inline: true,            // important!
  atom: true,              // important!
  toDOM: () => ["math-inline", { class: "math-node" }, 0],
  parseDOM: [{
    tag: "math-inline"   // important!
  },// ...defaultInlineMathParseRules
]
};

const mathDisplay: NodeSpec = {
  group: "block math",
  content: "text*",        // important!
  atom: true,              // important!
  code: true,              // important!
  toDOM: () => ["math-display", { class: "math-node" }, 0],
  parseDOM: [{
    tag: "math-display"  // important!
  }, //...defaultBlockMathParseRules
]

};


const nodes = {
  doc,
  text,
  paragraph,
  blockquote,
  horizontal_rule: horizontalRule,
  heading,
  hard_break: hardBreak,
  code_block: codeBlock,
  image,
  list_item: listItem,
  ordered_list: orderedList,
  bullet_list: bulletList,
  math_inline: mathInline,
  math_display: mathDisplay
};

Node types should be available under schema.nodes[nodeName]

Thanks, @marijn for helping me out,

But how to populate the string(’\sqrt{3}’) which I want to display in the editor. Actually, I am framing it like this. But the NodeType is applying in the editor without the input string content.

 addLatex() {
    const nodeType: NodeType = this.editor.schema.nodes.math_inline;
    nodeType.create({ content: "\sqrt{3}" })
    this.editor.commands
      .insertMathInline(nodeType)
      .exec();
  }

Actual One: image

Expected One: image

Going by the node spec, it has text content, and no content attribute, so you want something like nodeType.create(null, [schema.text("\sqrt{3}")])

It doesn’t help me out @marijn :cry:

  addLatex() {
    const nodeType: NodeType = schema.nodes.math_inline;
    nodeType.create(null, [schema.text("\sqrt{3}")]);
    this.editor.commands
      .insertMathInline(nodeType)
      .exec();
  }

I don’t know how insertMathInline works, but calling nodeType.create and throwing away the result is definitely not going to do something (it’s a pure function, returning a node).

BTW This is the insertMathInline function which will call the insertMathCmd function

  insertMathInline(nodeType:NodeType): this {
    insertMathCmd(nodeType)(this.state, this.dispatch);
    return this;
  }
import { Command } from "prosemirror-commands";
import { NodeType } from "prosemirror-model";
import { EditorState, NodeSelection, Transaction } from "prosemirror-state";

////////////////////////////////////////////////////////////////////////////////

/**
 * Returns a new command that can be used to inserts a new math node at the
 * users current document position, provided that the document schema actually
 * allows a math node to be placed there.
 * 
 * @param mathNodeType An instance for either your math_inline or math_display
 *     NodeType.  Must belong to the same schema that your EditorState uses!
 **/
export function insertMathCmd(mathNodeType: NodeType): Command {
	return function(state:EditorState, dispatch:((tr:Transaction)=>void)|undefined){
		let { $from } = state.selection, index = $from.index();
		if (!$from.parent.canReplaceWith(index, index, mathNodeType)) {
			return false;
		}
		if (dispatch){
			let tr = state.tr.replaceSelectionWith(mathNodeType.create({}));
			tr = tr.setSelection(NodeSelection.create(tr.doc, $from.pos));
			dispatch(tr);
		}
		return true;
	}
}

You’re confused between the difference between a NodeType and a Node, but are pretty close to a working solution.

What you need to do is modify the insertMathCmd to accept initial content, and then within that function use the NodeType to create a Node with that content:

+ export function insertMathCmd(mathNodeType: NodeType, initialText = null): Command {
- export function insertMathCmd(mathNodeType: NodeType): Command {
	return function(state:EditorState, dispatch:((tr:Transaction)=>void)|undefined){
		let { $from } = state.selection, index = $from.index();
		if (!$from.parent.canReplaceWith(index, index, mathNodeType)) {
			return false;
		}
		if (dispatch){
+           // schema.text does not allow empty strings
+           let mathNode = initialText ? mathNodeType.create({}, [state.schema.text(initialText)]) : mathNodeType.create({})
+			let tr = state.tr.replaceSelectionWith(mathNode);
-			let tr = state.tr.replaceSelectionWith(mathNodeType.create({}));
			tr = tr.setSelection(NodeSelection.create(tr.doc, $from.pos));
			dispatch(tr);
		}
		return true;
	}
}

Then you can use insertMathCmd like so:

  addInlineLatex() {
    const mathInline: NodeType = schema.nodes.math_inline;
    this.editor.commands
      .insertMathInline(mathInline, "\sqrt{3}")
      .exec();
  }

Note that prosemirror-math comes with two NodeTypes: math_inline and math_display. That’s why insertMathCmd takes in NodeType as an argument.

You saved me @bhl! :+1: :+1: :+1: As I am new to the ProseMirror library, I am not sure what I am doing wrong! I did not follow this topic today, because I figured out a dirty workaround yesterday, Eventually, I have seen your PR to the base branch & opened the link to know why this PR has been made today, Then Surprise… The perfect solution has been given for my Post! :hugs: :hugs: :hugs: also thanks, @marijn for responding to me earlier!