File size: 2,349 Bytes
b152fd5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import { createRootEditorSubscription$, realmPlugin } from "@mdxeditor/editor";
import { COMMAND_PRIORITY_CRITICAL, PASTE_COMMAND } from "lexical";
import { looksLikeMarkdownPaste } from "./markdownPaste";
import { normalizeMarkdown } from "./normalize-markdown";

/**
 * MDXEditor/Lexical plugin that intercepts paste events and normalizes
 * markdown content before the editor processes it. Fixes issues with
 * extra leading spaces when pasting from terminals or consoles.
 */
export const pasteNormalizationPlugin = realmPlugin({
  init(realm) {
    realm.pub(createRootEditorSubscription$, [
      (editor) => {
        let skipNext = false;

        return editor.registerCommand(
          PASTE_COMMAND,
          (event) => {
            if (skipNext) {
              skipNext = false;
              return false;
            }

            const clipboardData =
              event instanceof ClipboardEvent ? event.clipboardData : null;
            if (!clipboardData) return false;

            const text = clipboardData.getData("text/plain");
            if (!text) return false;

            // If there's HTML content, the source app already formatted it —
            // let the default paste handler deal with rich content as-is.
            if (clipboardData.getData("text/html")) return false;

            // Markdown-looking pastes are handled by MarkdownEditor.tsx via
            // insertMarkdown(), so the plugin only owns the plain-text fallback.
            if (looksLikeMarkdownPaste(text)) return false;

            const cleaned = normalizeMarkdown(text);
            if (cleaned === text) return false;

            // Prevent the original paste from being processed
            if (event instanceof ClipboardEvent) {
              event.preventDefault();
            }

            // Re-dispatch with cleaned data so MDXEditor's handler processes it
            const dt = new DataTransfer();
            dt.setData("text/plain", cleaned);
            const newEvent = new ClipboardEvent("paste", {
              clipboardData: dt,
              bubbles: true,
              cancelable: true,
            });

            skipNext = true;
            editor.dispatchCommand(PASTE_COMMAND, newEvent);
            return true;
          },
          COMMAND_PRIORITY_CRITICAL,
        );
      },
    ]);
  },
});