import { Plugin } from 'prosemirror-state'; import { Slice, Fragment, Node as PMNode } from 'prosemirror-model'; /** Flattens a multi-block document into a single paragraph, keeping marks. */ export function flattenToSingleParagraph(doc: PMNode): PMNode { if (doc.childCount <= 1) return doc; const schema = doc.type.schema; const inline: PMNode[] = []; doc.descendants(node => { if (node.isInline) { if (node.type === schema.nodes.hard_break) return false; inline.push(node); return false; } return true; }); return schema.nodes.doc.create(null, schema.nodes.paragraph.create(null, inline)); } /** * Constrains the document to a single paragraph: Enter is inert, pasted * multi-block content is flattened to one line, and any transaction that * would still produce extra blocks is rejected. */ export function singleLinePlugin(): Plugin { return new Plugin({ filterTransaction(tr) { return !tr.docChanged || tr.doc.childCount <= 1; }, props: { handleKeyDown(_view, event) { return event.key === 'Enter'; }, transformPasted(slice) { const inline: PMNode[] = []; slice.content.descendants(node => { if (node.isInline) { inline.push(node); return false; } return true; }); return new Slice(Fragment.from(inline), 0, 0); }, }, }); }