mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-08-28 14:06:36 +00:00
feat(editor): parse markdown on paste so paste matches load
@tiptap/markdown only parses markdown for initial content / insertContent, never for the clipboard — so pasting block markdown (headings, lists, tables, quotes, fences) landed as literal text while only StarterKit's inline mark paste-rules fired, and `_`/`__` formatted on paste even though load keeps them literal. Add a MarkdownPaste extension that routes plain-text pastes through the same faithful markdown layer as load, so the two are consistent. Rich sources keep ProseMirror's own fidelity: an in-editor copy (data-pm-slice) and web/Office HTML (block tags) fall through to the default path, and pastes inside code stay literal. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4e11fd96a4
commit
3b3c4cf7bd
@@ -0,0 +1,43 @@
|
||||
import { Extension } from '@tiptap/core';
|
||||
import { Plugin, PluginKey } from '@tiptap/pm/state';
|
||||
|
||||
// @tiptap/markdown parses markdown for load/insertContent but never for the clipboard, so a paste of block
|
||||
// markdown (# ## - 1. | >) would land as literal text (only StarterKit's inline mark paste-rules fire).
|
||||
// Route plain-text pastes through the same markdown layer as load; defer to ProseMirror's own path for rich
|
||||
// sources — an in-editor copy (carries `data-pm-slice`) or web/Office HTML (block tags) — so their fidelity
|
||||
// survives, and keep pastes inside code literal.
|
||||
const RICH_HTML_BLOCK = /<(?:h[1-6]|ul|ol|li|table|thead|tbody|tr|td|th|blockquote|pre|img|hr)\b/i;
|
||||
|
||||
export const MarkdownPaste = Extension.create({
|
||||
addProseMirrorPlugins() {
|
||||
const { editor } = this;
|
||||
|
||||
return [
|
||||
new Plugin({
|
||||
key: new PluginKey('markdownPaste'),
|
||||
props: {
|
||||
handlePaste(view, event) {
|
||||
const text = event.clipboardData?.getData('text/plain') ?? '';
|
||||
|
||||
if (!text.trim()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const html = event.clipboardData?.getData('text/html') ?? '';
|
||||
|
||||
if (html.includes('data-pm-slice') || RICH_HTML_BLOCK.test(html)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (view.state.selection.$from.parent.type.spec.code || editor.isActive('code')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return editor.commands.insertContent(text, { contentType: 'markdown' });
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
},
|
||||
name: 'markdownPaste',
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import { Placeholder } from '@tiptap/extensions';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
|
||||
import { createMarkdownLayer, MarkdownTable } from './editor-markdown';
|
||||
import { MarkdownPaste } from './editor-paste';
|
||||
import { TagHighlight } from './editor-tag-highlight';
|
||||
import { VariableHighlight } from './editor-variable-highlight';
|
||||
|
||||
@@ -25,4 +26,5 @@ export const createMarkdownExtensions = (placeholder?: string) => [
|
||||
TagHighlight,
|
||||
Placeholder.configure({ emptyEditorClass: 'is-editor-empty', placeholder }),
|
||||
...createMarkdownLayer(),
|
||||
MarkdownPaste,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user