[lexical-text] Bug Fix: for handling multiple matches on hashtags (#6056)

This commit is contained in:
wnhlee
2024-05-10 11:07:09 +09:00
committed by GitHub
parent 6a33ccfb7d
commit 3fc9fb616b
3 changed files with 127 additions and 1 deletions

View File

@ -14,9 +14,11 @@ import {
import { import {
assertHTML, assertHTML,
assertSelection, assertSelection,
click,
focusEditor, focusEditor,
html, html,
initialize, initialize,
pasteFromClipboard,
pressToggleBold, pressToggleBold,
repeat, repeat,
test, test,
@ -383,4 +385,119 @@ test.describe('Hashtags', () => {
`, `,
); );
}); });
test('Can handle hashtags following multiple invalid hashtags', async ({
page,
}) => {
await focusEditor(page);
await page.keyboard.type('#hello');
await page.keyboard.press('Space');
await page.keyboard.type('#world');
await page.keyboard.type('#invalid');
await page.keyboard.type('#invalid');
await page.keyboard.type('#invalid');
await page.keyboard.press('Space');
await page.keyboard.type('#valid');
await page.keyboard.press('Space');
await page.keyboard.type('#valid');
await page.keyboard.type('#invalid');
await page.keyboard.press('Space');
await page.keyboard.type('#valid');
await waitForSelector(page, '.PlaygroundEditorTheme__hashtag');
await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#hello
</span>
<span data-lexical-text="true"></span>
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#world
</span>
<span data-lexical-text="true">#invalid#invalid#invalid</span>
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#valid
</span>
<span data-lexical-text="true"></span>
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#valid
</span>
<span data-lexical-text="true">#invalid</span>
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#valid
</span>
</p>
`,
);
});
test('Should not break when pasting multiple matches', async ({
page,
isPlainText,
}) => {
test.skip(isPlainText);
await focusEditor(page);
const clipboard = {'text/html': '#hello#world'};
await pasteFromClipboard(page, clipboard);
await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#hello
</span>
<span data-lexical-text="true">#world</span>
</p>
`,
);
});
test('Should not break while importing and exporting multiple matches', async ({
page,
}) => {
await focusEditor(page);
await page.keyboard.type('```markdown #hello#invalid #a #b');
await click(page, '.action-button .markdown');
await click(page, '.action-button .markdown');
await click(page, '.action-button .markdown');
await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#hello
</span>
<span data-lexical-text="true">#invalid</span>
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#a
</span>
<span data-lexical-text="true"></span>
<span class="PlaygroundEditorTheme__hashtag" data-lexical-text="true">
#b
</span>
</p>
`,
);
});
}); });

View File

@ -14,6 +14,7 @@ import {
LexicalNode, LexicalNode,
TextNode, TextNode,
} from 'lexical'; } from 'lexical';
import invariant from 'shared/invariant';
export type EntityMatch = {end: number; start: number}; export type EntityMatch = {end: number; start: number};
@ -151,6 +152,13 @@ export function registerLexicalTextEntity<T extends TextNode>(
match.end + prevMatchLengthToSkip, match.end + prevMatchLengthToSkip,
); );
} }
invariant(
nodeToReplace !== undefined,
'%s should not be undefined. You may want to check splitOffsets passed to the splitText.',
'nodeToReplace',
);
const replacementNode = createNode(nodeToReplace); const replacementNode = createNode(nodeToReplace);
replacementNode.setFormat(nodeToReplace.getFormat()); replacementNode.setFormat(nodeToReplace.getFormat());
nodeToReplace.replace(replacementNode); nodeToReplace.replace(replacementNode);

View File

@ -163,5 +163,6 @@
"161": "Unexpected dirty selection to be null", "161": "Unexpected dirty selection to be null",
"162": "Root element not registered", "162": "Root element not registered",
"163": "node is not a ListNode", "163": "node is not a ListNode",
"164": "Root element count less than 0" "164": "Root element count less than 0",
"165": "%s should not be undefined. You may want to check splitOffsets passed to the splitText."
} }