Improve editor paste handling#358
Conversation
Reviewer's GuideEnhances editor paste behavior by detecting unfenced Mermaid diagrams in plain-text paste, splitting complex HTML/clipboard content into multiple paragraph blocks with preserved inline formatting, scoping select-all behavior for titles and code blocks, and rendering Mermaid code blocks as diagrams instead of visible code text. Sequence diagram for plain-text Mermaid paste detectionsequenceDiagram
actor User
participant Editor
participant WithPasted as handlePlainTextPaste
participant FragmentParser as parsePlainTextFragments
participant MermaidDetector as parseFragmentChunk
participant MermaidFragment as parseMermaidFragment
User->>Editor: paste plain text
Editor->>WithPasted: handlePlainTextPaste(text)
WithPasted->>FragmentParser: parsePlainTextFragments(text)
FragmentParser->>MermaidDetector: parseFragmentChunk(chunks, index)
MermaidDetector->>MermaidFragment: parseMermaidFragment(chunks, startIndex)
MermaidFragment-->>MermaidDetector: PasteFragmentMatch(CodeBlock mermaid)
MermaidDetector-->>FragmentParser: PasteFragmentMatch
FragmentParser-->>WithPasted: ParsedBlock[]
WithPasted->>Editor: insertParsedBlocks(editor, blocks)
Flow diagram for rendering Mermaid code blocks as diagramsflowchart TD
A[CodeBlock render] --> B{language === mermaid}
B -- No --> C["Render <code>{children}</code>"]
B -- Yes --> D[Set isMermaid]
D --> E["Render <code> with hidden styles"]
D --> F[Render MermaidChat node]
C & E & F --> G[User sees diagram or code]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The new
parseParagraphsignature returningParsedBlock | ParsedBlock[]complicates usage and forces call sites/tests to handle unions; consider either always returning an array or extracting the paragraph-splitting behavior into a separate helper so the core API stays consistent. - In
parsePlainTextFragments, you first scanchunks.somewithparseFragmentChunkand then immediately re-runparseFragmentChunkin the main loop, effectively doing the fragment parsing work twice; you could fold the initial detection into the main loop and track whether any fragment was seen to avoid redundant parsing. - There are multiple places removing the BOM (
\uFEFF) from text (e.g.,removeInvisiblePasteMarkers,handleMultiLinePlainText); reusing the helper everywhere would make the behavior consistent and reduce duplication.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `parseParagraph` signature returning `ParsedBlock | ParsedBlock[]` complicates usage and forces call sites/tests to handle unions; consider either always returning an array or extracting the paragraph-splitting behavior into a separate helper so the core API stays consistent.
- In `parsePlainTextFragments`, you first scan `chunks.some` with `parseFragmentChunk` and then immediately re-run `parseFragmentChunk` in the main loop, effectively doing the fragment parsing work twice; you could fold the initial detection into the main loop and track whether any fragment was seen to avoid redundant parsing.
- There are multiple places removing the BOM (`\uFEFF`) from text (e.g., `removeInvisiblePasteMarkers`, `handleMultiLinePlainText`); reusing the helper everywhere would make the behavior consistent and reduce duplication.
## Individual Comments
### Comment 1
<location path="src/components/editor/parsers/block-converters.ts" line_range="51-55" />
<code_context>
+ 'ul',
+]);
+
+function parseInlineStyle(style: string): Record<string, string> {
+ const styles: Record<string, string> = {};
+
+ style.split(';').forEach((part) => {
+ const [key, value] = part.split(':');
+
+ if (key && value) {
</code_context>
<issue_to_address>
**issue (bug_risk):** Limit the split on CSS declarations to handle values containing `:`.
`part.split(':')` discards everything after the first colon, so values containing `:` (e.g. URLs, data URIs, or `content: '12:34'`) are truncated. To preserve the full value while still extracting the property name, limit the split to two parts, e.g.:
```ts
const [key, value] = part.split(':', 2); // or part.split(/:(.+)/)
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| function parseInlineStyle(style: string): Record<string, string> { | ||
| const styles: Record<string, string> = {}; | ||
|
|
||
| style.split(';').forEach((part) => { | ||
| const [key, value] = part.split(':'); |
There was a problem hiding this comment.
issue (bug_risk): Limit the split on CSS declarations to handle values containing :.
part.split(':') discards everything after the first colon, so values containing : (e.g. URLs, data URIs, or content: '12:34') are truncated. To preserve the full value while still extracting the property name, limit the split to two parts, e.g.:
const [key, value] = part.split(':', 2); // or part.split(/:(.+)/)
Summary
Tests
Summary by Sourcery
Improve paste handling and selection behavior in the editor and title input, and render Mermaid code blocks as diagrams instead of raw code.
New Features:
Enhancements:
Tests: