I have the following problem: I have a node mathPanel
. I want to find a dom
of that node to display bubble menu below it. I tried to use both Tiptap and my own method as follows:
/* My nodeWithPos */
let nodeWithPos = findNode(editor, 'mathPanel');
let element = editor.view.nodeDOM(nodeWithPos?.pos!) as HTMLElement;
/* Tiptap nodeWithPos */
const tiptapNodeWithPos = editor.$node('mathPanel');
let tiptapElement = tiptapNodeWithPos?.element!;
There is only mathPanel
node in my doc
and my method returns pos=0
while Tiptap ones returns pos: 1
, and in that case, my method wins because element
corresponds to the mathPanel
dom, while Tiptap returns dom
of mathPanelName
element (first child of mathPanel
node). I tried state.doc.nodeAt
and again my method returns the problem node.
Here is my method:
/**
Searches for a node within the current selection. If direction is not null, it looks backward and/or forward too.
*/
export function findNode(
editor: any,
nodeType: string,
direction: -1 | 1 | 'both' | null = null
): NodeWithPos | null {
let view = editor.view;
const { state } = view;
const { selection } = state;
/* support for CellSelections */
const { ranges } = selection;
const from = Math.min(...ranges.map((range) => range.$from.pos));
const to = Math.max(...ranges.map((range) => range.$to.pos));
let foundNode: Node | null = null;
let foundPos: number | null = null;
editor.view.state.doc.nodesBetween(from, to, (node, pos) => {
if (foundNode) return false;
if (node.type.name === nodeType) {
foundPos = pos;
foundNode = node;
}
});
if (!foundNode && (direction === 'both' || direction === 1)) {
editor.view.state.doc.nodesBetween(
to,
state.doc.content.size,
(node, pos) => {
if (foundNode) return false;
if (node.type.name === nodeType) {
foundPos = pos;
foundNode = node;
}
}
);
}
if (!foundNode && (direction === 'both' || direction === -1)) {
editor.view.state.doc.nodesBetween(0, from, (node, pos) => {
if (foundNode) return false;
if (node.type.name === nodeType) {
foundPos = pos;
foundNode = node;
}
});
}
if (foundNode) {
return { node: foundNode, pos: foundPos! };
}
return null;
}
And here is Tiptap code:
I don’t understand what drives that difference. I think that my results make more sense, i.e. the node pos
indeed corresponds to the dom
and node
at that position.