Reset empty block to paragraph on enter

When the cursor is in an empty heading block, I would like pressing “Enter” to reset it to a paragraph instead of advancing to a new line after the empty heading. A subsequent “Enter” would perform that usual action. I have been looking at the prosemirror-commands source for guidance, but am still learning and having trouble grokking the concepts. How might the implementation of such an action look?

When the cursor is in an empty heading block,

You can get the parent of the current selection by using state.selection.$from.parent. Check it is a heading block by accessing the node’s type: node.type == state.schema.nodes.heading, and then check if its empty: node.textContent.length == 0.

I would like pressing “Enter” to reset it to a paragraph instead of advancing to a new line after the empty heading.

Use tr.setBlockType to convert the heading to a paragraph node. The difficulty here will be using the state.selection.$from.parent to find the from and to positions of the heading block.

Put together, the command should roughly look like:

export function HeadingToParagraph(state, dispatch) {
  if (!state.selection.empty) return false;
  let $from = state.selection.$from
  if ($from.parent.type != state.schema.nodes.heading || $from.parent.textContent.length) return false;
  // get bounds of heading block
  let from = $from.pos - $from.parentOffset, to = from + $from.parent.nodeSize;
  if (dispatch) dispatch(state.tr.setBlockType(from, to, state.schema.nodes.heading, {});
  return true;
}

Then you want to attach it to an “Enter” key handler via prosemirror-keymap.

1 Like

If you only need to set one parent block, I think you can also use setBlockType (part of prosemirror-commands module) instead of tr.setBlockType and avoid getting the bounds of the heading block.