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");
-}