How to create a new node

So really simple question, how can I create a new node inside simple action? I’ve tried create and createAndFill and whatever, but for some reason it always ends up producing two nodes instead of one. I am baffled.

export function createNewWordNode(state: EditorState, dispatch: (tr: Transaction) => void) {
  const {$from, $to} = state.selection
  let empty = schema.nodes.word.createAndFill(null)
  if (empty) {
    const tr = state.tr.insert($to.pos, empty)
    dispatch(tr)
    return true
  }
  return false
}

Also other simple questions after this if I might add here:

  • How can I immediately set the selection to this newly created node?
  • Also how can I force ProseMirror to add <br> element by default to empty block nodes? Not doing it for me right now.

I have no idea why that would create two nodes (unless your schema requires them to occur in pairs).

You can call setSelection on your transaction

It will, if the block node is a textblock (contains inline content).

Yes, I am probably doing something very wrong but I don’t know what. Very confusing.

So because I couldn’t get CodePen working I instead decided to dedicate a whole repo for this https://github.com/TeemuKoivisto/prosemirror-react-typescript-example It was somehow impossible to require the required core libraries in CodePen eg prosemirror-state using a CDN version eg https://cdn.jsdelivr.net/npm/prosemirror-state@1.2.3/dist/index.min.js Something something about Uncaught ReferenceError: exports is not defined

About the other things, I tried the setSelection but apparently did something wrong. I’ll try again at some point. The <br> element thing, well, as I am nesting inline inside the block node eg p > span I guess there won’t be any <br>s added if it’s empty? Well the whole thing breaks down if you do that as you can’t even select an empty inline node, the cursor will just skip the whole thing.

Well just as a follow-up, the problem was that while I was inserting the paragraph all right, it seems you always have to insert it at the end of the current one to break it into its own line. Because reasons, I guess. It kinda inserts the new paragraph so that it pushes the old paragraph’s last part to a completely new paragraph. Or something.

  const {$from, $to} = state.selection
  const empty = schema.nodes.underline.createAndFill()
  const endOfBlock = $from.end()
  if (empty) {
    const tr = state.tr.insert(endOfBlock + 1, empty)
    dispatch(tr)
  }
  return false

like so. Removing return true at the end of the dispatch fixed the duplication of paragraphs, dunno why. Why is that? I have so many silly questions, so sorry about that.

The true indicates that this command handled the key (or whatever it was that triggered it). Commands are allowed to ‘pass’ on actually doing anything when they don’t apply. You either had another command bound to the same key, which was taking effect, or saw the browser’s native behavior happen after your command ran.