How to move the cursor to the first position of a node?

Excuse me if this is very obvious, but I’ve been trying to figure this out for hours looking at the docs, examples, and searching for posts in this forum but I’m nowhere near a solution.

Maybe there is a better way, but the only way I’ve found to actually move the cursor is using:

dispatch(state.tr.setSelection(TextSelection.create(state.doc, 123)));

123 is an absolute position in the document, so in consequence to move the cursor to the first position of a node I’d need to find the absolute position of such node.

Since nodes don’t have an index or absolute position property I tried resolving position of a node at its index 0:

const resolvedPos = someNode.resolve(0);

Problem is the resolved position doesn’t include the absolute position of the node either. resolvedPos.pos returns 0 too and there doesn’t seem to be any other property indicating the absolute position that would allow me to use TextSelection.create().

So what would be the appropriate approach to solve this?

Don’t treat node objects as identifiers of document positions—they aren’t. The library uses value semantics for nodes, so you could have the same node object in your document multiple times. And nodes certainly don’t carry information about their position. Use positions (resolved or not) to identify document positions.

But @marijn where is the absolute document position in a resolved position?

pos returns the local position in the node, which in my case is 0.

I’ve tried using NodeSelection too but neither of the positions ($from, $to, etc) have an absolute position in the document. And if I do:

const selection = new NodeSelection(resolvedPos);
dispatch(state.tr.setSelection(selection.$from));

I get the error:

Cannot read property ‘doc’ of undefined

Only if you resolved in a specific node. You should almost always resolve relative to the document.

Is there an example on how to do that somewhere or is this explained anywhere in the documentation?

@marijn in this post you seem to suggest that the content should be used to get a node and find its absolute position in the doc:

So I tried traversing the document nodes from the view:

for (const child of view.docView.children) {
  if (child.node.content === someStateNode.content) return child.posAtStart;
}

Obviously this doesn’t work.

Is there some util function in ProseMirror to compare content of nodes?

If comparing the content is not the right approach, then what would be?

Edit:

Since this content thing seemed pretty inefficient and hackish I found I can actually get the absolute document position of a cursor with $someCursor.parentOffset.

So now the trick is to actually create a cursor that falls on the node in question. In my case I could simply use findCutBefore($cursor) which would put the cursor at the end of the previous node and then substract the nodeSize from that.

Here is the full solution:

let $beforeCursor = findCutBefore($cursor);
const pos = $beforeCursor.parentOffset - $beforeCursor.nodeBefore.nodeSize;
dispatch(state.tr.setSelection(TextSelection.create(state.doc, pos)));

This does the trick, at least in my use case.