Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix table of contents for headings in tables and collapsible sections #5946

Merged
merged 6 commits into from
May 1, 2024

Conversation

KatsiarynaDzibrova
Copy link
Contributor

Fixes following issues with table of contents:

  • The order in table of contents is wrong for heading inside tables and collapsible sections.
  • The heading is duplicated when resizing parent table cell

Now on each heading update dfs is used to get all headings and create a new TOC from scratch. It might take more time, but the change shouldn't be noticeable

Before:
toc-before

After:
toc-after

Copy link

vercel bot commented Apr 23, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
lexical ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 29, 2024 3:43pm
lexical-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 29, 2024 3:43pm

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Apr 23, 2024
);
const headingNodes = dfsNodes.map(
(dfsNode) => dfsNode.node as HeadingNode,
);
Copy link
Collaborator

@ivailop7 ivailop7 Apr 23, 2024

Choose a reason for hiding this comment

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

You can reduce from 2 loops to 1 loop using reduce or flatmap. Syntax should be something along those lines:

const headingNodes = $dfs().reduce((acc, {node}) => $isHeadingNode(node) ? [...acc, node] : acc, [])

this also unpacks the dfs node, to use the object under it's 'node', thus why it's in curly braces, so you don't have to reference dfsNode.node everywhere. You can read on this here:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you. Added the change

Copy link
Collaborator

@ivailop7 ivailop7 left a comment

Choose a reason for hiding this comment

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

A small speedup comment from me. @zurfyx @acy, happy with this approach?

ivailop7
ivailop7 previously approved these changes Apr 24, 2024
(acc, {node}) => ($isHeadingNode(node) ? [...acc, node] : acc),
[] as HeadingNode[],
);
currentTableOfContents = $newTableOfContents(headingNodes);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can do an extra performance optimization - we store the list, and we only replace it with the output from dfs on create, update for a headingNode, but on delete, we just delete from the map. What do you thing?

Copy link
Member

@zurfyx zurfyx left a comment

Choose a reason for hiding this comment

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

Have we measured performance? Running a full $dfs every time that a HeadingNode is mutated might be fairly inefficient, that why the previous version uses mutated nodes. For reference, the reconciler doesn't look at all nodes either, instead it traverses through the dirty nodes, I would take the reconciler as an example for optimizing this plugin.

@KatsiarynaDzibrova
Copy link
Contributor Author

Made the following changes:

  1. Explicitly checking if the heading is already in TOC to avoid duplicates
  2. Replaced dfs with listener on root updates, which updates all child headings
  3. Find previous heading for a new heading only when it's updated
    The performance should be much better now as we only visit updated nodes

@zurfyx feel free to take a look

@@ -222,6 +222,29 @@ function $getDepth(node: LexicalNode): number {
return depth;
}

export function $getPreviousNode(
Copy link
Collaborator

Choose a reason for hiding this comment

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

It lacks a comment description, also confused by the naming getPreviousNode, yet in the first if statement, it gets the last child, which is not 'previous' to my understanding.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Still unsure if this should be in utils or encapsulated in the TOC plugin file. Thoughts @zurfyx ?

@ivailop7 ivailop7 merged commit 3f61e33 into facebook:main May 1, 2024
46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants