Hello,
I thought I would be able to manage with just learning TipTap but turns out I can’t, so I spent this morning reading the ProseMirror docs, and I’m not sure how to approach things.
My goal is to have an editor that let’s me dynamically change from 2 types of content:
- Page: if > 250 char
- First node must be heading level 1
- Second node must be heading level 2.
- Note: if < 250 char
- anything goes.
- Prevent h1 to be used besides the first node
- Prevent h2 to be used besides the second node
Before reading ProseMirror docs and learning what it can be done my approach was:
- extension
- use it’s storage to store current type
- when doc size > 250 change type
- check if node 1 and 2 are paragraph, heading 1/2, if not just create the node.
- calculate the range of node 1 and 2, which took me a while to figure out how to do, I ended up doing this:
const fetchedNodeFrom = fetchedNode.from - editor.$doc.node.resolve(fetchedNode.from).depth;
which I don’t even know it’s the right way to do it. - replace node 1 and 2 with it’s own content using insertContentAt
editor.commands.insertContentAt(
{ from: fetchedNodeFrom, to: fetchedNode.to },
`<${type}>${fetchedNode.textContent}</${type}>`,
{
updateSelection: false,
parseOptions: {
preserveWhitespace: "full",
},
},
);
- continually monitor those node 1 and 2 for changes in which case enforce them again.
- continually monitor if size < 250 to do the reverse operation.
It works surprisingly well as of now, but I guess this approach is not reasonable and will be a pain to maintain, so how should I actually do this?
- Initially I thought about having 2 schemas
- >250: in which I define heading 1 and heading 2 as 2 different node types, and only allow one to exist
- < 250: in which I don’t allow h1/h2
- dynamically change from one to the other with something like this
Do you think this is the right approach?
If so, How do I enforce heading 1 and 2 to only appear as the first 2 nodes?
Thank you,
Adrian.
EDIT: I tried transactions a few days ago among many other things in order to transform the node 1 and 2 but I couldn’t initially, but after carefully reading the guide and trying again I think I managed to at least improve that part.
let transaction = editor.state.tr;
const firstNodeFrom =
firstNode.from - editor.$doc.node.resolve(firstNode.from).depth;
const firstNodeTo = firstNode.to;
const secondNodeFrom =
secondNode.from - editor.$doc.node.resolve(secondNode.from).depth;
const secondNodeTo = secondNode.to;
const headingLevel1 = editor.schema.nodes.heading.create(
{ level: 1 },
firstNode.content,
);
transaction = transaction.replaceWith(
firstNodeFrom,
firstNodeTo,
headingLevel1,
);
const headingLevel2 = editor.schema.nodes.heading.create(
{ level: 2 },
secondNode.content,
);
transaction = transaction.replaceWith(
secondNodeFrom,
secondNodeTo,
headingLevel2,
);
editor.state.applyTransaction(transaction);
editor.view.dispatch(transaction);
Something like this.