Skip to content

Commit 3a52948

Browse files
authored
[Breaking Change][lexical][lexical-utils]: Bug Fix: Handle canBeEmpty in $splitNodes (#7342)
1 parent a1d3750 commit 3a52948

File tree

16 files changed

+475
-64
lines changed

16 files changed

+475
-64
lines changed

package-lock.json

+12-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174
"lint-staged": "^11.1.0",
175175
"minimist": "^1.2.5",
176176
"npm-run-all": "^4.1.5",
177-
"prettier": "^2.3.2",
177+
"prettier": "^2.8.8",
178178
"prettier-plugin-hermes-parser": "^0.26.0",
179179
"prettier-plugin-organize-attributes": "^0.0.5",
180180
"prettier-plugin-tailwindcss": "^0.4.1",

packages/lexical-headless/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function createHeadlessEditor(
3333
'blur',
3434
] as const;
3535

36-
unsupportedMethods.forEach((method: typeof unsupportedMethods[number]) => {
36+
unsupportedMethods.forEach((method: (typeof unsupportedMethods)[number]) => {
3737
editor[method] = () => {
3838
throw new Error(`${method} is not supported in headless mode`);
3939
};

packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs

+143-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import {
1616
assertHTML,
1717
assertSelection,
18+
click,
1819
copyToClipboard,
1920
focusEditor,
2021
html,
@@ -26,6 +27,11 @@ import {
2627
withExclusiveClipboardAccess,
2728
} from '../utils/index.mjs';
2829

30+
async function toggleBulletList(page) {
31+
await click(page, '.block-controls');
32+
await click(page, '.dropdown .icon.bullet-list');
33+
}
34+
2935
test.describe('HorizontalRule', () => {
3036
test.beforeEach(({isCollab, page}) => initialize({isCollab, page}));
3137
test(
@@ -209,7 +215,7 @@ test.describe('HorizontalRule', () => {
209215
});
210216
});
211217

212-
test('Will add a horizontal rule and split a TextNode across 2 paragraphs if the carat is in the middle of the TextNode, moving selection to the start of the new ParagraphNode.', async ({
218+
test('Will add a horizontal rule and split a TextNode across 2 paragraphs if the caret is in the middle of the TextNode, moving selection to the start of the new ParagraphNode.', async ({
213219
page,
214220
isPlainText,
215221
}) => {
@@ -277,6 +283,142 @@ test.describe('HorizontalRule', () => {
277283
});
278284
});
279285

286+
test('Will add a horizontal rule and split a TextNode across 2 ListItemNode if the caret is in the middle of the TextNode, moving selection to the start of the new ParagraphNode', async ({
287+
page,
288+
isPlainText,
289+
}) => {
290+
test.skip(isPlainText);
291+
await focusEditor(page);
292+
await toggleBulletList(page);
293+
294+
await page.keyboard.type('Test');
295+
296+
await assertSelection(page, {
297+
anchorOffset: 4,
298+
anchorPath: [0, 0, 0, 0],
299+
focusOffset: 4,
300+
focusPath: [0, 0, 0, 0],
301+
});
302+
303+
await assertHTML(
304+
page,
305+
html`
306+
<ul class="PlaygroundEditorTheme__ul">
307+
<li
308+
class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__ltr"
309+
dir="ltr"
310+
value="1">
311+
<span data-lexical-text="true">Test</span>
312+
</li>
313+
</ul>
314+
`,
315+
);
316+
317+
await moveLeft(page, 2);
318+
319+
await assertSelection(page, {
320+
anchorOffset: 2,
321+
anchorPath: [0, 0, 0, 0],
322+
focusOffset: 2,
323+
focusPath: [0, 0, 0, 0],
324+
});
325+
326+
await selectFromInsertDropdown(page, '.horizontal-rule');
327+
328+
await waitForSelector(page, 'hr');
329+
330+
await assertHTML(
331+
page,
332+
html`
333+
<ul class="PlaygroundEditorTheme__ul">
334+
<li
335+
class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__ltr"
336+
dir="ltr"
337+
value="1">
338+
<span data-lexical-text="true">Te</span>
339+
</li>
340+
</ul>
341+
<hr
342+
class="PlaygroundEditorTheme__hr"
343+
contenteditable="false"
344+
data-lexical-decorator="true" />
345+
<ul class="PlaygroundEditorTheme__ul">
346+
<li
347+
class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__ltr"
348+
dir="ltr"
349+
value="1">
350+
<span data-lexical-text="true">st</span>
351+
</li>
352+
</ul>
353+
`,
354+
);
355+
356+
await assertSelection(page, {
357+
anchorOffset: 0,
358+
anchorPath: [2, 0, 0, 0],
359+
focusOffset: 0,
360+
focusPath: [2, 0, 0, 0],
361+
});
362+
});
363+
364+
test('Will add a horizontal rule and split a TextNode across 2 ListItemNode if the caret is in an empty ListItemNode, moving selection to the start of the new ListItemNode (#6849)', async ({
365+
page,
366+
isPlainText,
367+
}) => {
368+
test.skip(isPlainText);
369+
await focusEditor(page);
370+
await toggleBulletList(page);
371+
372+
await assertSelection(page, {
373+
anchorOffset: 0,
374+
anchorPath: [0, 0],
375+
focusOffset: 0,
376+
focusPath: [0, 0],
377+
});
378+
379+
await assertHTML(
380+
page,
381+
html`
382+
<ul class="PlaygroundEditorTheme__ul">
383+
<li class="PlaygroundEditorTheme__listItem" value="1">
384+
<br />
385+
</li>
386+
</ul>
387+
`,
388+
);
389+
390+
await selectFromInsertDropdown(page, '.horizontal-rule');
391+
392+
await waitForSelector(page, 'hr');
393+
394+
await assertHTML(
395+
page,
396+
html`
397+
<ul class="PlaygroundEditorTheme__ul">
398+
<li class="PlaygroundEditorTheme__listItem" value="1">
399+
<br />
400+
</li>
401+
</ul>
402+
<hr
403+
class="PlaygroundEditorTheme__hr"
404+
contenteditable="false"
405+
data-lexical-decorator="true" />
406+
<ul class="PlaygroundEditorTheme__ul">
407+
<li class="PlaygroundEditorTheme__listItem" value="1">
408+
<br />
409+
</li>
410+
</ul>
411+
`,
412+
);
413+
414+
await assertSelection(page, {
415+
anchorOffset: 0,
416+
anchorPath: [2, 0],
417+
focusOffset: 0,
418+
focusPath: [2, 0],
419+
});
420+
});
421+
280422
test('Can copy and paste a horizontal rule', async ({page, isPlainText}) => {
281423
test.skip(isPlainText);
282424

packages/lexical-playground/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"katex": "^0.16.10",
3030
"lexical": "0.27.2",
3131
"lodash-es": "^4.17.21",
32-
"prettier": "^3.4.2",
32+
"prettier": "^2.8.8",
3333
"react": "^18.2.0",
3434
"react-dom": "^18.2.0",
3535
"react-error-boundary": "^3.1.4",

packages/lexical-table/src/LexicalTableCellNode.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const TableCellHeaderStates = {
4141
};
4242

4343
export type TableCellHeaderState =
44-
typeof TableCellHeaderStates[keyof typeof TableCellHeaderStates];
44+
(typeof TableCellHeaderStates)[keyof typeof TableCellHeaderStates];
4545

4646
export type SerializedTableCellNode = Spread<
4747
{

packages/lexical-utils/flow/LexicalUtils.js.flow

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import type {
1515
CaretDirection,
1616
SiblingCaret,
1717
RootMode,
18+
SplitAtPointCaretNextOptions,
19+
PointCaret,
1820
} from 'lexical';
1921
declare export function addClassNamesToElement(
2022
element: HTMLElement,
@@ -102,7 +104,9 @@ declare export function $restoreEditorState(
102104
editorState: EditorState,
103105
): void;
104106

107+
105108
declare export function $insertNodeToNearestRoot<T: LexicalNode>(node: T): T;
109+
declare export function $insertNodeToNearestRootAtCaret<T: LexicalNode>(node: T, caret: PointCaret<CaretDirection>, options?: SplitAtPointCaretNextOptions): T;
106110

107111
declare export function $wrapNodeInElement(
108112
node: LexicalNode,

packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ describe('LexicalUtils#insertNodeToNearestRoot', () => {
8686
'<test-decorator></test-decorator>' +
8787
'<p><br></p>',
8888
initialHtml: '<p>Hello world</p>',
89-
selectionOffset: 12, // Selection on text node after "Hello" world
89+
selectionOffset: 'Hello world'.length, // Selection on text node after "Hello" world
9090
selectionPath: [0, 0],
9191
},
9292
{
@@ -96,7 +96,7 @@ describe('LexicalUtils#insertNodeToNearestRoot', () => {
9696
'<test-decorator></test-decorator>' +
9797
'<p><span style="white-space: pre-wrap;">Hello world</span></p>',
9898
initialHtml: '<p>Hello world</p>',
99-
selectionOffset: 0, // Selection on text node after "Hello" world
99+
selectionOffset: 0, // Selection on text node before "Hello" world
100100
selectionPath: [0, 0],
101101
},
102102
{
@@ -175,7 +175,7 @@ describe('LexicalUtils#insertNodeToNearestRoot', () => {
175175
);
176176
$setSelection(selection);
177177

178-
$insertNodeToNearestRoot($createTestDecoratorNode());
178+
$insertNodeToNearestRoot($createTestDecoratorNode().setIsInline(false));
179179

180180
// Cleaning up list value attributes as it's not really needed in this test
181181
// and it clutters expected output

0 commit comments

Comments
 (0)