Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/lexical-link/src/LexicalAutoLinkExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ export function registerAutoLink(
editor.registerNodeTransform(TextNode, (textNode: TextNode) => {
const parent = textNode.getParentOrThrow();
const previous = textNode.getPreviousSibling();
if ($isAutoLinkNode(parent) && !parent.getIsUnlinked()) {
if ($isAutoLinkNode(parent)) {
handleLinkEdit(parent, matchers, onChange);
} else if (
!$isLinkNode(parent) &&
Expand Down
204 changes: 202 additions & 2 deletions packages/lexical-playground/__tests__/e2e/AutoLinks.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
focusEditor,
html,
initialize,
LEGACY_EVENTS,
pasteFromClipboard,
pressInsertLinkButton,
test,
Expand Down Expand Up @@ -734,8 +735,7 @@ test.describe.parallel('Auto Links', () => {
);

await click(page, 'span:has-text("http://www.example.com")');

pressInsertLinkButton(page);
await pressInsertLinkButton(page);

await assertHTML(
page,
Expand All @@ -753,6 +753,206 @@ test.describe.parallel('Auto Links', () => {
);
});

test('Unlinked the autolink should not destruct if add non-spacing text in front or right after it', async ({
page,
isPlainText,
}) => {
test.skip(isPlainText || LEGACY_EVENTS);
Comment on lines +756 to +760
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a result, the current changes in this PR do not bring anything new to this scenario. It already fails in prod in legacy_events mode, so I added a condition to skip the test #8165 (comment)

Tests directly related to the new behavior are written below.


await focusEditor(page);
await page.keyboard.type('http://example.com');
await assertHTML(
page,
html`
<p dir="auto">
<a href="http://example.com">
<span data-lexical-text="true">http://example.com</span>
</a>
</p>
`,
undefined,
{ignoreClasses: true},
);

await focusEditor(page);
await click(page, 'a[href="http://example.com"]');
await click(page, 'div.link-editor div.link-trash');
await assertHTML(
page,
html`
<p dir="auto">
<span>
<span data-lexical-text="true">http://example.com</span>
</span>
</p>
`,
undefined,
{ignoreClasses: true},
);

// Add non-url text after the link
await moveToLineEnd(page);
await page.keyboard.type('!');
await assertHTML(
page,
html`
<p dir="auto">
<span>
<span data-lexical-text="true">http://example.com</span>
</span>
<span data-lexical-text="true">!</span>
</p>
`,
undefined,
{ignoreClasses: true},
);

await page.keyboard.press('Backspace');

// Add non-url text before the link
await moveToLineBeginning(page);
await page.keyboard.type('!');
await assertHTML(
page,
html`
<p dir="auto">
<span data-lexical-text="true">!</span>
<span>
<span data-lexical-text="true">http://example.com</span>
</span>
</p>
`,
undefined,
{ignoreClasses: true},
);
await page.keyboard.press('Backspace');
await assertHTML(
page,
html`
<p dir="auto">
<span>
<span data-lexical-text="true">http://example.com</span>
</span>
</p>
`,
undefined,
{ignoreClasses: true},
);
});

test('Can destruct unlinked the autolink if add an invalid character inside', async ({
page,
isPlainText,
}) => {
test.skip(isPlainText);

await focusEditor(page);
await page.keyboard.type('http://example.com');
await assertHTML(
page,
html`
<p dir="auto">
<a href="http://example.com">
<span data-lexical-text="true">http://example.com</span>
</a>
</p>
`,
undefined,
{ignoreClasses: true},
);

await focusEditor(page);
await click(page, 'a[href="http://example.com"]');
await click(page, 'div.link-editor div.link-trash');
await assertHTML(
page,
html`
<p dir="auto">
<span>
<span data-lexical-text="true">http://example.com</span>
</span>
</p>
`,
undefined,
{ignoreClasses: true},
);

// break autolink
await moveToLineEnd(page);
await page.keyboard.press('ArrowLeft');
await page.keyboard.type('[');
// plain text without wrapper
await assertHTML(
page,
html`
<p dir="auto">
<span data-lexical-text="true">http://example.co[m</span>
</p>
`,
undefined,
{ignoreClasses: true},
);
});

test('Can destruct unlinked the autolink if add emoji inside', async ({
page,
isPlainText,
}) => {
test.skip(isPlainText);

await focusEditor(page);
await page.keyboard.type('http://example.com');
await assertHTML(
page,
html`
<p dir="auto">
<a href="http://example.com">
<span data-lexical-text="true">http://example.com</span>
</a>
</p>
`,
undefined,
{ignoreClasses: true},
);

await focusEditor(page);
await click(page, 'a[href="http://example.com"]');
await click(page, 'div.link-editor div.link-trash');
await assertHTML(
page,
html`
<p dir="auto">
<span>
<span data-lexical-text="true">http://example.com</span>
</span>
</p>
`,
undefined,
{ignoreClasses: true},
);

// type emoji
await moveToLineEnd(page);
await page.keyboard.press('ArrowLeft');
await page.keyboard.type(':)');
// ':', ')' — is valid chars for link but inserting an emoji
// should break the link by splitting it into two text nodes
await assertHTML(
page,
html`
<p dir="auto">
<span data-lexical-text="true">http://example.co</span>
<span class="emoji happysmile" data-lexical-text="true">
<span class="emoji-inner">🙂</span>
</span>
<span data-lexical-text="true">m</span>
</p>
`,
undefined,
{ignoreClasses: true},
);
});

test('Pressing Enter inside an AutoLinkNode does not insert extra paragraph', async ({
page,
isPlainText,
Expand Down
Loading