[lexical-link] Bug Fix: AutoLinkNode.insertNewAfter keeps the node's own properties - #8996
Merged
Merged
Conversation
…own properties
## Description
`LinkNode.insertNewAfter` produces the trailing half of a split with
`$copyNode`, which runs `constructor.clone(node)` followed by
`afterCloneFrom(node)`:
```ts
insertNewAfter(_: RangeSelection, restoreSelection = true): null | ElementNode {
const linkNode = $copyNode(this);
this.insertAfter(linkNode, restoreSelection);
return linkNode;
}
```
`AutoLinkNode` overrode it with a hand-rolled constructor call that enumerated
four properties:
```ts
const linkNode = $createAutoLinkNode(this.__url, {
isUnlinked: this.__isUnlinked,
rel: this.__rel,
target: this.__target,
title: this.__title,
});
```
Everything else the clone contract carries was dropped:
- `__format`, `__indent`, `__style`, `__dir`, `__textFormat`, `__textStyle`,
carried by `ElementNode.afterCloneFrom`;
- `__state` — the entire NodeState, i.e. every `createState`/`$setState` value,
carried by `LexicalNode.afterCloneFrom`;
- the concrete class: `$copyNode` goes through `node.constructor.clone`, while
`$createAutoLinkNode` hardcodes `new AutoLinkNode(...)`, so a subclass of
`AutoLinkNode` came back as a base `AutoLinkNode`.
The production path is `$splitNodeAtPoint`
(`packages/lexical/src/LexicalSelection.ts`, `node.insertNewAfter(insertPoint)`),
so splitting an autolink while inserting or pasting produced a trailing half
that had silently lost its node state and element props — while the identical
operation on a plain `LinkNode` preserved them.
The override is also redundant: `AutoLinkNode.afterCloneFrom` already carries
`__isUnlinked`, and `LinkNode.afterCloneFrom` carries url/rel/target/title. So
the fix is to delete it and inherit the correct implementation.
## Test plan
Three new cases in
`packages/lexical-link/src/__tests__/unit/LexicalAutoLinkNode.test.ts`. The
third is a control that passes before and after — it pins the four attributes
the override did handle, so removing it cannot regress them.
The existing `AutoLinkNode.insertNewAfter does not create new paragraph` test
asserts only node type and sibling counts, all of which still hold.
### Before
```
$ npx vitest run packages/lexical-link/src/__tests__/unit/LexicalAutoLinkNode.test.ts
× keeps the element style, text style and text format 6ms
× keeps the NodeState 2ms
✓ keeps the link attributes (control) 1ms
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯
AssertionError: expected '' to be 'color: red' // Object.is equality
AssertionError: expected '' to be 'carried' // Object.is equality
Tests 2 failed | 29 passed (31)
```
### After
```
$ npx vitest run packages/lexical-link packages/lexical-playground packages/lexical/src
Test Files 88 passed (88)
Tests 1773 passed | 1 skipped (1774)
```
`npx tsc -p tsconfig.json --noEmit` and `npx eslint` on the changed file are
both clean.
Note: this touches `LexicalLinkNode.ts`, as does facebook#8993, but a different method
(`AutoLinkNode.insertNewAfter` vs the `$toggleLink` NodeSelection branch). The
two apply cleanly in either order.
LeSingh1
requested review from
acywatson,
etrepum,
fantactuka,
ivailop7,
potatowagon and
zurfyx
as code owners
August 9, 2026 01:52
|
@LeSingh1 is attempting to deploy a commit to the Meta Open Source Team on Vercel. A member of the Team first needs to authorize it. |
etrepum
approved these changes
Aug 9, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
LinkNode.insertNewAfterproduces the trailing half of a split with$copyNode, which runsconstructor.clone(node)followed byafterCloneFrom(node):AutoLinkNodeoverrode it with a hand-rolled constructor call that enumeratedfour properties:
Everything else the clone contract carries was dropped:
__format,__indent,__style,__dir,__textFormat,__textStyle,carried by
ElementNode.afterCloneFrom;__state— the entire NodeState, i.e. everycreateState/$setStatevalue,carried by
LexicalNode.afterCloneFrom;$copyNodegoes throughnode.constructor.clone, while$createAutoLinkNodehardcodesnew AutoLinkNode(...), so a subclass ofAutoLinkNodecame back as a baseAutoLinkNode.The production path is
$splitNodeAtPoint(
packages/lexical/src/LexicalSelection.ts,node.insertNewAfter(insertPoint)),so splitting an autolink while inserting or pasting produced a trailing half
that had silently lost its node state and element props — while the identical
operation on a plain
LinkNodepreserved them.The override is also redundant:
AutoLinkNode.afterCloneFromalready carries__isUnlinked, andLinkNode.afterCloneFromcarries url/rel/target/title. Sothe fix is to delete it and inherit the correct implementation.
Test plan
Three new cases in
packages/lexical-link/src/__tests__/unit/LexicalAutoLinkNode.test.ts. Thethird is a control that passes before and after — it pins the four attributes
the override did handle, so removing it cannot regress them.
The existing
AutoLinkNode.insertNewAfter does not create new paragraphtestasserts only node type and sibling counts, all of which still hold.
Before
After
npx tsc -p tsconfig.json --noEmitandnpx eslinton the changed file areboth clean.
Note: this touches
LexicalLinkNode.ts, as does #8993, but a different method(
AutoLinkNode.insertNewAftervs the$toggleLinkNodeSelection branch). Thetwo apply cleanly in either order.