Skip to content

Commit e14ad0b

Browse files
fix: keep marks when merging blocks (#256)
* fix: keep marks when merge blocks solves #255 * Added tests for backspace handling --------- Co-authored-by: Matthew Lipski <[email protected]>
1 parent 535a1b5 commit e14ad0b

11 files changed

+685
-4
lines changed

packages/core/src/extensions/Blocks/nodes/BlockContainer.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,19 @@ export const BlockContainer = Node.create<IBlock>({
281281
}
282282

283283
// Deletes next block and adds its text content to the nearest previous block.
284-
// TODO: Use slices.
284+
285285
if (dispatch) {
286-
state.tr.deleteRange(startPos, startPos + contentNode.nodeSize);
287-
state.tr.insertText(contentNode.textContent, prevBlockEndPos - 1);
286+
dispatch(
287+
state.tr
288+
.deleteRange(startPos, startPos + contentNode.nodeSize)
289+
.replace(
290+
prevBlockEndPos - 1,
291+
startPos,
292+
new Slice(contentNode.content, 0, 0)
293+
)
294+
.scrollIntoView()
295+
);
296+
288297
state.tr.setSelection(
289298
new TextSelection(state.doc.resolve(prevBlockEndPos - 1))
290299
);

tests/end-to-end/keyboardhandlers/keyboardhandlers.test.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
H_TWO_BLOCK_SELECTOR,
77
} from "../../utils/const";
88
import { compareDocToSnapshot, focusOnEditor } from "../../utils/editor";
9-
import { insertHeading } from "../../utils/copypaste";
9+
import { insertHeading, insertParagraph } from "../../utils/copypaste";
1010

1111
test.describe.configure({ mode: "serial" });
1212

@@ -72,4 +72,58 @@ test.describe("Check Keyboard Handlers' Behaviour", () => {
7272

7373
await compareDocToSnapshot(page, "enterPreservesNestedBlocks.json");
7474
});
75+
test("Check Backspace at the start of a block", async ({ page }) => {
76+
await focusOnEditor(page);
77+
await insertHeading(page, 1);
78+
79+
await page.keyboard.press("ArrowUp");
80+
await page.keyboard.press("Control+ArrowLeft");
81+
await page.keyboard.press("Backspace");
82+
83+
await compareDocToSnapshot(page, "backspaceStartOfBlock.json");
84+
});
85+
test("Check Backspace preserves marks", async ({ page }) => {
86+
await focusOnEditor(page);
87+
await insertParagraph(page);
88+
await insertParagraph(page);
89+
90+
await page.keyboard.press("ArrowUp");
91+
await page.keyboard.press("Control+ArrowLeft");
92+
93+
for (let i = 0; i < 2; i++) {
94+
await page.keyboard.press("ArrowRight");
95+
}
96+
97+
for (let i = 0; i < 5; i++) {
98+
await page.keyboard.press("Shift+ArrowRight");
99+
}
100+
101+
await page.locator(ITALIC_BUTTON_SELECTOR).click();
102+
await page.waitForTimeout(500);
103+
104+
await page.keyboard.press("ArrowLeft");
105+
await page.keyboard.press("Control+ArrowLeft");
106+
await page.keyboard.press("Backspace");
107+
108+
await compareDocToSnapshot(page, "backspacePreservesMarks.json");
109+
});
110+
test("Check Backspace preserves nested blocks", async ({ page }) => {
111+
await focusOnEditor(page);
112+
await insertParagraph(page);
113+
await insertParagraph(page);
114+
await page.keyboard.press("Tab");
115+
await insertParagraph(page);
116+
await page.keyboard.press("Tab");
117+
await page.keyboard.press("Tab");
118+
await insertParagraph(page);
119+
120+
for (let i = 0; i < 3; i++) {
121+
await page.keyboard.press("ArrowUp");
122+
}
123+
124+
await page.keyboard.press("Control+ArrowLeft");
125+
await page.keyboard.press("Backspace");
126+
127+
await compareDocToSnapshot(page, "backspacePreservesNestedBlocks.json");
128+
});
75129
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"type": "doc",
3+
"content": [
4+
{
5+
"type": "blockGroup",
6+
"content": [
7+
{
8+
"type": "blockContainer",
9+
"attrs": {
10+
"id": "0",
11+
"textColor": "default",
12+
"backgroundColor": "default"
13+
},
14+
"content": [
15+
{
16+
"type": "paragraph",
17+
"attrs": {
18+
"textAlignment": "left"
19+
},
20+
"content": [
21+
{
22+
"type": "text",
23+
"text": "ParagraphPa"
24+
},
25+
{
26+
"type": "text",
27+
"marks": [
28+
{
29+
"type": "italic"
30+
}
31+
],
32+
"text": "ragra"
33+
},
34+
{
35+
"type": "text",
36+
"text": "ph"
37+
}
38+
]
39+
}
40+
]
41+
},
42+
{
43+
"type": "blockContainer",
44+
"attrs": {
45+
"id": "2",
46+
"textColor": "default",
47+
"backgroundColor": "default"
48+
},
49+
"content": [
50+
{
51+
"type": "paragraph",
52+
"attrs": {
53+
"textAlignment": "left"
54+
}
55+
}
56+
]
57+
}
58+
]
59+
}
60+
]
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"type": "doc",
3+
"content": [
4+
{
5+
"type": "blockGroup",
6+
"content": [
7+
{
8+
"type": "blockContainer",
9+
"attrs": {
10+
"id": "0",
11+
"textColor": "default",
12+
"backgroundColor": "default"
13+
},
14+
"content": [
15+
{
16+
"type": "paragraph",
17+
"attrs": {
18+
"textAlignment": "left"
19+
},
20+
"content": [
21+
{
22+
"type": "text",
23+
"text": "ParagraphPa"
24+
},
25+
{
26+
"type": "text",
27+
"marks": [
28+
{
29+
"type": "italic"
30+
}
31+
],
32+
"text": "ragra"
33+
},
34+
{
35+
"type": "text",
36+
"text": "ph"
37+
}
38+
]
39+
}
40+
]
41+
},
42+
{
43+
"type": "blockContainer",
44+
"attrs": {
45+
"id": "2",
46+
"textColor": "default",
47+
"backgroundColor": "default"
48+
},
49+
"content": [
50+
{
51+
"type": "paragraph",
52+
"attrs": {
53+
"textAlignment": "left"
54+
}
55+
}
56+
]
57+
}
58+
]
59+
}
60+
]
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"type": "doc",
3+
"content": [
4+
{
5+
"type": "blockGroup",
6+
"content": [
7+
{
8+
"type": "blockContainer",
9+
"attrs": {
10+
"id": "0",
11+
"textColor": "default",
12+
"backgroundColor": "default"
13+
},
14+
"content": [
15+
{
16+
"type": "paragraph",
17+
"attrs": {
18+
"textAlignment": "left"
19+
},
20+
"content": [
21+
{
22+
"type": "text",
23+
"text": "ParagraphPa"
24+
},
25+
{
26+
"type": "text",
27+
"marks": [
28+
{
29+
"type": "italic"
30+
}
31+
],
32+
"text": "ragra"
33+
},
34+
{
35+
"type": "text",
36+
"text": "ph"
37+
}
38+
]
39+
}
40+
]
41+
},
42+
{
43+
"type": "blockContainer",
44+
"attrs": {
45+
"id": "2",
46+
"textColor": "default",
47+
"backgroundColor": "default"
48+
},
49+
"content": [
50+
{
51+
"type": "paragraph",
52+
"attrs": {
53+
"textAlignment": "left"
54+
}
55+
}
56+
]
57+
}
58+
]
59+
}
60+
]
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
{
2+
"type": "doc",
3+
"content": [
4+
{
5+
"type": "blockGroup",
6+
"content": [
7+
{
8+
"type": "blockContainer",
9+
"attrs": {
10+
"id": "0",
11+
"textColor": "default",
12+
"backgroundColor": "default"
13+
},
14+
"content": [
15+
{
16+
"type": "paragraph",
17+
"attrs": {
18+
"textAlignment": "left"
19+
},
20+
"content": [
21+
{
22+
"type": "text",
23+
"text": "ParagraphParagraph"
24+
}
25+
]
26+
}
27+
]
28+
},
29+
{
30+
"type": "blockContainer",
31+
"attrs": {
32+
"id": "2",
33+
"textColor": "default",
34+
"backgroundColor": "default"
35+
},
36+
"content": [
37+
{
38+
"type": "paragraph",
39+
"attrs": {
40+
"textAlignment": "left"
41+
},
42+
"content": [
43+
{
44+
"type": "text",
45+
"text": "Paragraph"
46+
}
47+
]
48+
},
49+
{
50+
"type": "blockGroup",
51+
"content": [
52+
{
53+
"type": "blockContainer",
54+
"attrs": {
55+
"id": "3",
56+
"textColor": "default",
57+
"backgroundColor": "default"
58+
},
59+
"content": [
60+
{
61+
"type": "paragraph",
62+
"attrs": {
63+
"textAlignment": "left"
64+
},
65+
"content": [
66+
{
67+
"type": "text",
68+
"text": "Paragraph"
69+
}
70+
]
71+
}
72+
]
73+
}
74+
]
75+
}
76+
]
77+
},
78+
{
79+
"type": "blockContainer",
80+
"attrs": {
81+
"id": "4",
82+
"textColor": "default",
83+
"backgroundColor": "default"
84+
},
85+
"content": [
86+
{
87+
"type": "paragraph",
88+
"attrs": {
89+
"textAlignment": "left"
90+
}
91+
}
92+
]
93+
}
94+
]
95+
}
96+
]
97+
}

0 commit comments

Comments
 (0)