Hi everyone,
We’re trying to figure out how best to insert content into a document. When the user is editing a node, we would like to provide an option for them to insert a new node into the parent of the node they are editing.
For example, consider this simplified schema:
const mySchema = new Schema({
nodes: {
doc: { content: "html" },
html: { content: "title body?", toDOM: () => ["html", {}, 0] },
title: { content: "text*", toDOM: () => ["title", {}, 0] },
body: { content: "(ul|p)*", toDOM: () => ["body", {}, 0] },
ul: { content: "li*", toDOM: () => ["ul", {}, 0] },
li: { content: "p*", toDOM: () => ["li", {}, 0] },
p: { content: "text*", toDOM: () => ["p", {}, 0] },
text: { inline: true },
},
});
Let’s say the cursor is deep inside a <p>
(paragraph) within a <li>
inside a <ul>
, we would like that when the user presses Enter to be able to insert a new <p>
tag after the </ul>
, at the parent level, e.g. inside the <body>
tag.
<html>
<title>Example of image mixed with block nodes</title>
<body>
<p>Text in the body node</p>
<ul>
<li>
<p>Text in the li node</p> <!-- NOTE: The cursor is placed within this <p> tag -->
</li>
</ul>
</body>
</html>
We’re trying to implement this via a custom keymap:
const enterKeyPlugin = keymap({
Enter: (state, dispatch) => {
const { $from } = state.selection;
const { schema } = state;
if (!dispatch) return true;
const paragraph = schema.nodes.p.createAndFill();
if (!paragraph) return false;
const tr = state.tr.insert($from.after(), paragraph);
const resolvedPos = tr.doc.resolve($from.after() + 1);
const selection = TextSelection.near(resolvedPos);
dispatch(tr.setSelection(selection).scrollIntoView());
return true; // prevent default
},
});
When we try to insert a <p>
tag after the nested paragraph in the <ul>
(list), we find that it is being joined as a child to the <li>
tag, and unfortunately we can’t seem to escape that and place the new <p>
in the <body>
Our question:
-
How do we correctly find the position in the parent node (e.g.
body
) to insert new content when we are in a deeply nested selection? -
What’s the best way to “climb up” from the current position to find the correct ancestor and insert after it?
This comes up for us in several scenarios — like exiting a list and inserting a paragraph after it, or inserting sibling nodes at higher structural levels.
Thanks in advance for any advice!
Sample code example https://codesandbox.io/p/devbox/confident-hooks-forked-5pm7q7?workspaceId=ws_GkHAzkZJBA2J7JZx2YhuSS