[lexical-playground] Bug Fix: Normalize collapsible content children#8539
Conversation
|
Hi @rohan-patnaik! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at [email protected]. Thanks! |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
The issue's repro link starts with a |
|
The title and description of this PR doesn't match the pull request template https://raw.githubusercontent.com/facebook/lexical/refs/heads/main/.github/pull_request_template.md |
|
@etrepum thanks for pointing that out. I updated the title and PR body to follow the template format. Could you please take another look and let me know if this reads correctly now? |
…nt-inline-children
|
Title and description look good, no need to update the branch unless there's a conflict. As a first time contributor this will require a maintainer to approve the CI checks to run again which will slow down your review. |
| const $wrapInlineContentChildren = (node: CollapsibleContentNode) => { | ||
| if (node.isEmpty()) { | ||
| node.append($createParagraphNode()); | ||
| return; | ||
| } | ||
|
|
||
| let paragraph: ReturnType<typeof $createParagraphNode> | null = null; | ||
|
|
||
| for (const child of node.getChildren()) { | ||
| if ($isBlockElementNode(child)) { |
There was a problem hiding this comment.
$isBlockElementNode checks only ElementNode, although there are block decorators too
I also think it makes sense to export $wrapInlineNodes to lexical/utils and reuse it
https://github.com/facebook/lexical/blob/main/packages/lexical/src/LexicalSelection.ts#L3328-L3366
There was a problem hiding this comment.
Thanks, that makes sense. I updated this in ec9e073: moved the inline wrapping helper into LexicalUtils, re-exported it through lexical / @lexical/utils, and reused it in the collapsible transform.
I also added a reg test covering the case you called out: block decorator children stay unwrapped, while inline content is still wrapped into paragraphs.
Checked locally too:
vitest --project unit --run packages/lexical-playground/__tests__/unit/CollapsibleContainerNode.test.tstsc --noEmit
There was a problem hiding this comment.
I think the $wrapInlineContentChildren wrapper is not needed, it checks exactly the same thing as $wrapInlineNodes
There was a problem hiding this comment.
ok I guess I agree that the pre-check duplicates what $wrapInlineNodes already does.
The only extra behavior in $wrapInlineContentChildren is the empty content case, where we add a paragraph. $wrapInlineNodes([]) would return no children, so removing that handling would regress the empty-content repro.
Would you prefer that I keep a very small wrapper for the empty case and always call $wrapInlineNodes, or inline that logic directly in the transform?
| ); | ||
| } | ||
|
|
||
| export function $wrapInlineNodes(nodes: LexicalNode[]) { |
There was a problem hiding this comment.
This new export should have documentation, an explicit return type, and ideally some tests. I know this is code just copied from elsewhere but the LineBreakNode special case seems a bit suspicious. Not sure that's really the correct behavior in all cases. I'm not sure that it's correct for [LineBreakNode, TextNode] to be indistinguishable from [TextNode] after wrapping.
There was a problem hiding this comment.
That makes sense. I removed the new public export in e53545c and kept this PR scoped to the collapsible fix instead.
The wrapping logic is now local to the playground collapsible transform, and the net PR diff is back to the collapsible extension plus its regression tests. This keeps the empty-content fix and the block-decorator coverage without adding a new utility API.
| return; | ||
| } | ||
|
|
||
| let paragraph: ReturnType<typeof $createParagraphNode> | null = null; |
There was a problem hiding this comment.
| let paragraph: ReturnType<typeof $createParagraphNode> | null = null; | |
| let paragraph: ElementNode | null = null; |
| } | ||
|
|
||
| if (paragraph === null) { | ||
| paragraph = $createParagraphNode(); |
There was a problem hiding this comment.
| paragraph = $createParagraphNode(); | |
| paragraph = child.createParentNode(); |
|
@etrepum thanks, I pushed 90cdb1a with the wrapping cleanup. Used Checked locally:
|
Description
This PR fixes the collapsible playground crash when invalid inline or empty content is placed directly under
CollapsibleContentNode.CollapsibleContentNodeis a shadow root, so its children need to be block elements. The content transform now wraps direct inline children in paragraphs, leaves existing block children unchanged, and normalizes empty content with a paragraph so the repro state stays editable.Closes #8530
Test plan
Before
The issue repro could load a
collapsible-contentnode with no block child. After dirtying that content node, later editor operations could throw because the content node did not have a valid block structure.After
corepack pnpm exec vitest --project unit --run packages/lexical-playground/__tests__/unit/CollapsibleContainerNode.test.tscorepack pnpm exec eslint packages/lexical-playground/src/plugins/CollapsibleExtension/index.ts packages/lexical-playground/__tests__/unit/CollapsibleContainerNode.test.tscorepack pnpm exec prettier --check packages/lexical-playground/src/plugins/CollapsibleExtension/index.ts packages/lexical-playground/__tests__/unit/CollapsibleContainerNode.test.ts