Proper way of creating new doc from selection

Imagine user selected some text in document. I want to be able to create new document from this selection and want this document to be valid against schema. What api should I use, if there is any? Is this task solvable for generic schema at all? Task looks not easy, as user may have cubersome rules in schema. Should I create empty nodes to satisfy schema constraints, or what?

My schema is close to “prosemirror-schema-basic”, plus lists and plus some custom nodes.

I’ve tried state.doc.cut and state.doc.slice, but both have issues and can produce invalid doc. Also I’ve looked into clipboard.ts module of prosemirror-view package, and took some code from there as an inspiration. But still afraid that I’m missing correct approach.

You could take a slice of the selection, and then create an empty document and insert that slice into it, letting Transform.replace handle the fitting and implicit-node-insertion for you.

1 Like

Hi @struhtanov - did you get this to work?

I’ve been attempting a variety of approaches, but I keep ending up with an empty paste (no change to the empty doc).

Example:

// Get the selection slice from the current editor
const selectionSlice = editor.state.selection.content();

// Create a new, empty editor state & apply the replace transaction
const emptyState = EditorState.create({ schema });
const updatedEditor = emptyState.apply(emptyState.tr.replace(0, 2, selectionSlice));

I’ve tried using replace & replaceRange with various from & to points (0->1, 1->1, 1->2, 2->2), without success.

I’ve tried to trace through the replace code, but I’m getting confused by the Fitter logic. So thought I should check if I’m doing something simple incorrect.

Thanks

Hi. I’ve followed suggestion above from “marijn” and it worked for me. Here is code snippet:

export const createNewDocBySlice = (state: EditorState, schema: Schema) => {
  const slice = state.selection.content();
  const doc = schema.node("doc", null, [schema.node("paragraph", null, [])]);
  const transform = new Transform(doc);
  const result = transform.replaceRange(0, 2, slice);
  const content = result.doc.content;
  return schema.nodes.doc.createChecked({}, content);
};

Thanks @struhtanov! Turns out my issue was that I was using a static, stripped back version of the schema. Passing in the schema from the current editor solved it - seeing your code gave me the hint, I appreciate it!