Skip to content

Commit ec02d44

Browse files
committed
test: integrate code-block copy regression into existing copy test suite
Address PR review: - Drop standalone codeBlockMarkdown.test.ts; add `codeBlockFullContent` and `codeBlockPartialSelection` cases to copyTestInstances.ts and snapshot text/plain markdown for all copy test instances via a new `Copy tests (Markdown)` describe block (mirrors the export test pattern). - Trim verbose comments in copyExtension and serializeBlocksExternalHTML. - copyPasteEquality executor now passes the actual markdown payload as the text/plain MIME instead of a literal "text" placeholder, so paste handlers that prefer text/plain (e.g. inside code blocks) round-trip correctly. - Update mixedInParagraph snapshots: prettify's `ignore: ["code"]` preserves trailing whitespace inside `<code>` spans, which is the actual HTML output.
1 parent 80587a4 commit ec02d44

30 files changed

Lines changed: 214 additions & 138 deletions

packages/core/src/api/clipboard/toClipboard/copyExtension.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,13 @@ function fragmentToExternalHTML<
2727
selectedFragment: Fragment,
2828
editor: BlockNoteEditor<BSchema, I, S>,
2929
) {
30-
const isWithinTable = view.state.selection instanceof CellSelection;
31-
32-
// Whether the selection is inline-only inside a single block whose content
33-
// can be cleanly represented as standalone HTML (i.e. not a code block).
34-
// For such "transparent" parents we strip the wrapper so pasting plain text
35-
// into another app doesn't get a `<p>` around it. For code blocks we keep
36-
// the wrapper so the block's own `toExternalHTML` runs.
3730
let isWithinBlockContent = false;
31+
const isWithinTable = view.state.selection instanceof CellSelection;
3832

3933
if (!isWithinTable) {
34+
// Checks whether block ancestry should be included when creating external
35+
// HTML. If the selection is within a block content node, the block ancestry
36+
// is excluded as we only care about the inline content.
4037
const fragmentWithoutParents = view.state.doc.slice(
4138
view.state.selection.from,
4239
view.state.selection.to,
@@ -48,22 +45,13 @@ function fragmentToExternalHTML<
4845
children.push(fragmentWithoutParents.child(i));
4946
}
5047

51-
const isFullyInline =
48+
isWithinBlockContent =
5249
children.find(
5350
(child) =>
5451
child.type.isInGroup("bnBlock") ||
5552
child.type.name === "blockGroup" ||
5653
child.type.spec.group === "blockContent",
5754
) === undefined;
58-
59-
// Only use the inline-only path when the parent block isn't a code-content
60-
// block. Code blocks need their `<pre><code>` wrapper to keep `\n` as
61-
// literal newlines (instead of `<br>`) and to make the markdown converter
62-
// emit a fenced block instead of escaping each newline as `\`.
63-
const parentIsCode =
64-
view.state.selection.$from.parent.type.spec.code === true;
65-
66-
isWithinBlockContent = isFullyInline && !parentIsCode;
6755
if (isWithinBlockContent) {
6856
selectedFragment = fragmentWithoutParents;
6957
}
@@ -152,7 +140,18 @@ export function selectedFragmentToHTML<
152140
editor,
153141
);
154142

155-
const markdown = cleanHTMLToMarkdown(externalHTML);
143+
// Code blocks are treated differently for copying: text/plain is the raw
144+
// selected text instead of markdown.
145+
const { $from, $to } = view.state.selection;
146+
const parentBlockType = $from.parent.type.name;
147+
const parentBlockSpec = editor.blockImplementations[parentBlockType as any];
148+
const isPurelyInsideCodeBlock =
149+
$from.sameParent($to) &&
150+
parentBlockSpec?.implementation.meta?.code === true;
151+
152+
const markdown = isPurelyInsideCodeBlock
153+
? view.state.doc.textBetween($from.pos, $to.pos)
154+
: cleanHTMLToMarkdown(externalHTML);
156155

157156
return { clipboardHTML, externalHTML, markdown };
158157
}

packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,6 @@ export function serializeInlineContentExternalHTML<
4545
if (!blockContent) {
4646
throw new Error("blockContent is required");
4747
} else if (typeof blockContent === "string") {
48-
// Pass `blockType` so `inlineContentToNodes` keeps `\n` as text for
49-
// code-content blocks instead of splitting into `hardBreak` nodes —
50-
// otherwise the exported HTML for a code block contains `<br>` separators
51-
// inside `<pre><code>` instead of literal newlines. Mirrors the internal
52-
// HTML serializer, which already plumbs this through.
5348
nodes = inlineContentToNodes(
5449
[blockContent],
5550
editor.pmSchema,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const a = 1;
2+
<br />
3+
const b = 2;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
onst a = 1;
2+
<br />
3+
const b = 2
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Paragraph 1
2+
3+
# Heading 1
4+
5+
1. Numbered List Item 1
6+
7+
* Bullet List Item 1
8+
* [ ] Check List Item 1
9+
* Toggle List Item 1
10+
11+
```text
12+
console.log("Hello World");
13+
```
14+
15+
| | |
16+
| ------------ | ------------ |
17+
| Table Cell 1 | Table Cell 2 |
18+
| Table Cell 3 | Table Cell 4 |
19+
20+
21+
22+
***
23+
24+
Paragraph 2
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Paragraph 1
2+
3+
## Heading 1
4+
5+
2. Numbered List Item 1
6+
7+
* Bullet List Item 1
8+
* [x] Check List Item 1
9+
* Toggle List Item 1
10+
11+
```typescript
12+
console.log("Hello World");
13+
```
14+
15+
| | |
16+
| ------------ | ------------ |
17+
| Table Cell 1 | Table Cell 2 |
18+
| Table Cell 3 | Table Cell 4 |
19+
20+
<figure><img alt="1280px-Placeholder_view_vector.svg.png" src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Placeholder_view_vector.svg/1280px-Placeholder_view_vector.svg.png"><figcaption>Placeholder</figcaption></figure>
21+
22+
***
23+
24+
Paragraph 2
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Paragraph 1
2+
3+
Nested Paragraph 1
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Nested Paragraph 1
2+
3+
Nested Paragraph 2
4+
5+
Nested Paragraph 3
6+
7+
Paragraph 2
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Nested Paragraph 1
2+
3+
Nested Paragraph 2
4+
5+
Nested Paragraph 3
6+
7+
Paragraph 2
8+
9+
Nested Paragraph 4
10+
11+
Nested Paragraph 5
12+
13+
Nested Paragraph 6
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const a = 1;
2+
const b = 2;

0 commit comments

Comments
 (0)