fix: strip trailing whitespace-only paragraphs from pasted content (#2050)

This commit is contained in:
Olivier Lambert
2026-03-28 23:26:47 +01:00
committed by GitHub
parent 642c92f779
commit a42ac3d450
@@ -1,7 +1,7 @@
// adapted from: https://github.com/aguingand/tiptap-markdown/blob/main/src/extensions/tiptap/clipboard.js - MIT
import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { DOMParser } from "@tiptap/pm/model";
import { DOMParser, Fragment, Slice } from "@tiptap/pm/model";
import { find } from "linkifyjs";
import { markdownToHtml } from "@docmost/editor-ext";
@@ -40,7 +40,7 @@ export const MarkdownClipboard = Extension.create({
const { tr } = view.state;
const { from, to } = view.state.selection;
const html = markdownToHtml(text);
const html = markdownToHtml(text.replace(/\n+$/, ""));
const contentNodes = DOMParser.fromSchema(
this.editor.schema,
@@ -53,6 +53,37 @@ export const MarkdownClipboard = Extension.create({
view.dispatch(tr);
return true;
},
// Strip trailing whitespace-only paragraphs from pasted content.
// Terminals (GNOME Terminal, etc.) often include trailing
// whitespace in their HTML clipboard data, which ProseMirror
// parses as an extra paragraph. Inside a list item this creates
// an orphan empty line that breaks the list structure.
transformPasted: (slice) => {
let { content, openStart, openEnd } = slice;
// Remove trailing paragraphs that contain only whitespace
while (content.childCount > 1) {
const lastChild = content.lastChild;
if (
lastChild?.type.name === "paragraph" &&
lastChild.textContent.trim() === ""
) {
const children = [];
for (let i = 0; i < content.childCount - 1; i++) {
children.push(content.child(i));
}
content = Fragment.from(children);
} else {
break;
}
}
if (content !== slice.content) {
return new Slice(content, openStart, Math.max(openEnd, 1));
}
return slice;
},
clipboardTextParser: (text, context, plainText) => {
const link = find(text, {
defaultProtocol: "http",
@@ -64,7 +95,7 @@ export const MarkdownClipboard = Extension.create({
return null;
}
const parsed = markdownToHtml(text);
const parsed = markdownToHtml(text.replace(/\n+$/, ""));
return DOMParser.fromSchema(this.editor.schema).parseSlice(
elementFromString(parsed),
{