Skip to content

fix(web-pkg): paste text/plain in plain text editor to keep markdown syntax - #3526

Open
AlexAndBear wants to merge 2 commits into
mainfrom
fix/plain-text-editor-paste
Open

AlexAndBear wants to merge 2 commits into
mainfrom
fix/plain-text-editor-paste

Conversation

@AlexAndBear

@AlexAndBear AlexAndBear commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Description

Copying content from the markdown editor and pasting it into a plain text file (e.g. .txt) stripped the markdown syntax (#, **, - , code fences, …), even though the clipboard's text/plain payload contained proper markdown.

ProseMirror prefers the text/html clipboard payload over text/plain. The plain text editor is a tiptap editor with a reduced schema (no headings, lists, marks, …), so the html got parsed into that schema and everything it couldn't represent was dropped. Nested list items even ended up at the end of the document.

This adds a plainTextClipboard extension to the plain text strategy:

What Why
Paste always uses text/plain (falls back to the default handling if there is none) Keeps the pasted text as-is instead of parsing html into the reduced schema
clipboardTextSerializer uses Tiptap's getTextBetween / getTextSerializersFromSchema helpers with blockSeparator: '\n' (same as saving the file) Tiptap's core serializer uses blank lines as block separators, which would double every line break when copying within the plain text editor
clipboardTextParser maps every line to a paragraph, keeping empty ones ProseMirror's default collapses consecutive line breaks, dropping empty lines

While testing, it turned out that both the new paste handler and the existing one in markdownClipboard.ts also pasted into read-only editors: ProseMirror runs handleDOMEvents before its own editable check. Both handlers now bail out when the editor isn't editable.

Copy, paste, load and save now all follow the same "one paragraph per line" rule. Tiptap and ProseMirror don't offer an option to prefer text/plain on paste or to keep empty lines, so those two parts stay custom.

Related Issue

  • Fixes: no issue, reported internally

How Has This Been Tested?

  • test environment: local dev setup (pnpm vite + docker backend), Chrome / Chromium via Playwright, unit tests via Vitest
  • test case 1: copy all from a .md file with Cmd+A/Cmd+C, paste into a .txt file with Cmd+V → markdown syntax is kept 1:1 (headings, marks, links, nested lists, ordered lists, quotes, code fences, tables)
  • test case 2: Cmd+Z after paste reverts it in one step
  • test case 3: copy & paste within a .txt file → empty lines are kept, no doubled line breaks
  • test case 4: paste a single word into the middle of a line → inserted inline, no new paragraph
  • test case 5: html-only clipboard → default paste handling still works
  • test case 6: clipboard with html and text from a web page → text payload is used
  • test case 7: \r\n and \r line endings are split correctly
  • test case 8: paste over a multi-line selection replaces it correctly
  • test case 9: hard breaks (Shift+Enter) are copied as \n
  • test case 10: saved file content equals the copied text
  • test case 11: pasting from .txt into .md is unchanged (markdown gets parsed)
  • test case 12: select text in a read-only .txt / .md editor and press Cmd+V → content stays unchanged
  • unit tests: pnpm test:unit --run packages/web-pkg/tests/unit/editor

Types of changes

  • Bugfix
  • Enhancement (a change that doesn't break existing code or deployments)
  • Breaking change (a modification that affects current functionality)
  • Technical debt (addressing code that needs refactoring or improvements)
  • Tests (adding or improving tests)
  • Documentation (updates or additions to documentation)
  • Maintenance (like dependency updates or tooling adjustments)

@AlexAndBear AlexAndBear self-assigned this Oct 1, 2026
@AlexAndBear
AlexAndBear requested a review from kulmann October 1, 2026 19:19
@AlexAndBear
AlexAndBear force-pushed the fix/plain-text-editor-paste branch from 3f40857 to f98e701 Compare October 1, 2026 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant