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

[SuperEditor] Add toggleable headers (Resolves #2276) #2404

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

angelosilvestre
Copy link
Collaborator

[SuperEditor] Add toggleable headers. Resolves #2276

This PR adds the ability to group nodes together under header nodes or list item nodes, where each group can be collapsed/expanded by tapping on a button near it.

The groups are created upon initialization, when adding or removing a node, and when changing a node that couldn’t start a group to a node that can start a group. For example, typing "# " at the beginning of a paragraph converts it to a header node and creates a new group.

Navigating using the arrow keys skips nodes inside a collapsed group. For example, pressing ARROW DOWN skips nodes that are inside a collapsed group.

The user cannot start or end a selection inside a collapsed group. Also, if the selection starts or ends within a group and the user collapses the group, the selection is adjusted to avoid starting or ending inside the collapsed group.

Node grouping is customizable and apps can implement their own grouping logic, if desirable.

Implementation

A GroupBuilder interface was added with the methods required to grouping nodes:

canStartGroup: to signal the document layout that the current node can start a group, for example, when it is a level one header.

canAddToGroup: to signal the document layout that a node can be added to an existing group.

build: to create the widget for this group.

SuperEditor will take a list of GroupBuilders as a constructor parameter.

Previously, all components were organized into a vertical list of components inside the SingleColumnDocumentLayout. Now, whenever a GroupBuilder returns true for canStartGroup, the document layout will call canAddToGroup to each node below it, until canAddToGroup returns false. After gathering all nodes that are part of the group, SingleColumnDocumentLayout calls build on the GroupBuilder to create a widget subtree for that group.

To handle the key navigation, at the current state of this PR, it was added an isComponentVisible method to the DocumentLayout interface, so the layout can report that a component is not currently visible. This is yet subject to change, depending on how we expose an API to programmatically collapse/expand/check state of a group.

This PR adds HeaderGroupBuilder and ListItemGroupBuilder with default behavior for headers and list items. All customization can be done using constructor parameters for these builders. For example, customizing the toggle button, restricting the maximum number of children of a group, etc.

ToggleableGroup is the default widget used for headers and list items, which includes a default button that fades in when the mouse enters, fades out when the mouse leaves, animates upon tap. It also includes a vertical line below the button, that also fades in/out. The widget can optionally animate the expanding/collapsing of a group.

A change that might be regrettable is that I changed _SingleColumnDocumentLayoutState to be public, so I can access information about groups inside tests. Once we figure out a public API for that this can be reverted.

Remaining work

  • Define a public API to allow apps to expand/collapse groups programmatically and obtain information about the groups.
  • Modify the behavior for when the user presses enter at the end of the header of a collapsed group. This action should expand the group. This change depends of the API to expand/collapse groups.
  • Add mobile support. On mobile we might not have enough room to display a button near the content, so we need to find another way for that. Also, on mobile the buttons must be always visible (or at least when the caret sits within the node) because, of course, there is no mouse to hover over the button to make it appear.
Screen.Recording.2024-11-11.at.16.23.53.mov

@angelosilvestre
Copy link
Collaborator Author

@matthew-carroll I still haven't figured out an ideal API to expand/collapse groups, but can you do a first pass review on this PR?

@matthew-carroll
Copy link
Contributor

@angelosilvestre do you think we should hold off on this work until we figure out tree based documents? Or do you think most of the work would be interchangeable and it's worth the effort right now?

#2403

@angelosilvestre
Copy link
Collaborator Author

@matthew-carroll I'm not entirely sure.

We also want to make it possible for clients to create the concept of "banners", which are decorated boxes that contain any number of other nodes.

We could probably find a way to implement that with the API introduced by this PR. This PR is basically a way to extract trees from the list of nodes. This probably won't work for tables, but for more simpler requirements this might work.

Also, the ToggleableGroup widget introduced by this PR would be also usable with a tree structure. I guess it would worth to move this PR forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[SuperEditor] - Toggleable headers
2 participants