diff --git a/ui/src/components/MarkdownBody.tsx b/ui/src/components/MarkdownBody.tsx index d9a2afb6..b996629a 100644 --- a/ui/src/components/MarkdownBody.tsx +++ b/ui/src/components/MarkdownBody.tsx @@ -4,7 +4,6 @@ import remarkGfm from "remark-gfm"; import { parseProjectMentionHref } from "@paperclipai/shared"; import { cn } from "../lib/utils"; import { useTheme } from "../context/ThemeContext"; -import { normalizeMarkdownArtifacts } from "../lib/markdown"; interface MarkdownBodyProps { children: string; @@ -115,7 +114,6 @@ function MermaidDiagramBlock({ source, darkMode }: { source: string; darkMode: b export function MarkdownBody({ children, className }: MarkdownBodyProps) { const { theme } = useTheme(); - const normalizedMarkdown = normalizeMarkdownArtifacts(children); return (
- {normalizedMarkdown} + {children}
); diff --git a/ui/src/components/MarkdownEditor.tsx b/ui/src/components/MarkdownEditor.tsx index 507308a1..85b67c32 100644 --- a/ui/src/components/MarkdownEditor.tsx +++ b/ui/src/components/MarkdownEditor.tsx @@ -29,7 +29,6 @@ import { } from "@mdxeditor/editor"; import { buildProjectMentionHref, parseProjectMentionHref } from "@paperclipai/shared"; import { cn } from "../lib/utils"; -import { normalizeMarkdownArtifacts } from "../lib/markdown"; /* ---- Mention types ---- */ @@ -204,7 +203,7 @@ export const MarkdownEditor = forwardRef }: MarkdownEditorProps, forwardedRef) { const containerRef = useRef(null); const ref = useRef(null); - const latestValueRef = useRef(normalizeMarkdownArtifacts(value)); + const latestValueRef = useRef(value); const [uploadError, setUploadError] = useState(null); const [isDragOver, setIsDragOver] = useState(false); const dragDepthRef = useRef(0); @@ -282,10 +281,9 @@ export const MarkdownEditor = forwardRef }, [hasImageUpload]); useEffect(() => { - const normalizedValue = normalizeMarkdownArtifacts(value); - if (normalizedValue !== latestValueRef.current) { - ref.current?.setMarkdown(normalizedValue); - latestValueRef.current = normalizedValue; + if (value !== latestValueRef.current) { + ref.current?.setMarkdown(value); + latestValueRef.current = value; } }, [value]); @@ -556,15 +554,11 @@ export const MarkdownEditor = forwardRef > { - const normalizedNext = normalizeMarkdownArtifacts(next); - latestValueRef.current = normalizedNext; - if (normalizedNext !== next) { - ref.current?.setMarkdown(normalizedNext); - } - onChange(normalizedNext); + latestValueRef.current = next; + onChange(next); }} onBlur={() => onBlur?.()} className={cn("paperclip-mdxeditor", !bordered && "paperclip-mdxeditor--borderless")} diff --git a/ui/src/lib/markdown.test.ts b/ui/src/lib/markdown.test.ts deleted file mode 100644 index a455ea1f..00000000 --- a/ui/src/lib/markdown.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { normalizeMarkdownArtifacts } from "./markdown"; - -describe("normalizeMarkdownArtifacts", () => { - it("normalizes escaped unordered list markers and space entities", () => { - const input = "Here is a list:\n\n\\* foo \n\\- bar "; - const output = normalizeMarkdownArtifacts(input); - expect(output).toBe("Here is a list:\n\n* foo \n- bar "); - }); - - it("does not rewrite escaped markers inside fenced code blocks", () => { - const input = "```md\n\\* keep literal \n\\- keep literal \n```"; - expect(normalizeMarkdownArtifacts(input)).toBe(input); - }); - - it("keeps escaped non-list syntax intact", () => { - const input = "\\*not-a-list"; - expect(normalizeMarkdownArtifacts(input)).toBe(input); - }); -}); diff --git a/ui/src/lib/markdown.ts b/ui/src/lib/markdown.ts deleted file mode 100644 index ab485319..00000000 --- a/ui/src/lib/markdown.ts +++ /dev/null @@ -1,47 +0,0 @@ -const FENCE_RE = /^\s*(`{3,}|~{3,})/; -const SPACE_ENTITY_RE = / /gi; -const ESCAPED_UNORDERED_LIST_RE = /^(\s{0,3})\\([*+-])([ \t]+)/; - -/** - * Normalize markdown artifacts emitted by rich-text serialization so - * plain markdown list syntax remains usable in Paperclip editors. - */ -export function normalizeMarkdownArtifacts(markdown: string): string { - if (!markdown) return markdown; - - const lines = markdown.split(/\r?\n/); - let inFence = false; - let fenceMarker: "`" | "~" | null = null; - let fenceLength = 0; - let changed = false; - - const normalized = lines.map((line) => { - const fenceMatch = FENCE_RE.exec(line); - if (fenceMatch) { - const marker = fenceMatch[1]; - if (!inFence) { - inFence = true; - fenceMarker = marker[0] as "`" | "~"; - fenceLength = marker.length; - } else if (marker[0] === fenceMarker && marker.length >= fenceLength) { - inFence = false; - fenceMarker = null; - fenceLength = 0; - } - return line; - } - - if (inFence) return line; - - let next = line; - if (next.includes(" ")) { - next = next.replace(SPACE_ENTITY_RE, " "); - } - const unescaped = next.replace(ESCAPED_UNORDERED_LIST_RE, "$1$2$3"); - if (unescaped !== line) changed = true; - return unescaped; - }); - - if (!changed) return markdown; - return normalized.join("\n"); -}