-
-
Notifications
You must be signed in to change notification settings - Fork 560
feat: Toggle blocks #1707
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
base: main
Are you sure you want to change the base?
feat: Toggle blocks #1707
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
@blocknote/ariakit
@blocknote/code-block
@blocknote/core
@blocknote/mantine
@blocknote/react
@blocknote/server-util
@blocknote/shadcn
@blocknote/xl-ai
@blocknote/xl-docx-exporter
@blocknote/xl-multi-column
@blocknote/xl-odt-exporter
@blocknote/xl-pdf-exporter
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I'm more interested in seeing here is how we can add this to existing block types (such as headings with a prop) rather than as a separate element like this implements.
packages/core/src/blocks/ToggleHeadingBlockContent/ToggleHeadingBlockContent.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Still need to dive a bit deeper in the code but in general looks great.
Let's make the UX a bit more polished. When comparing with other products (e.g. Notion), this catches my attention:
let's make the arrow similar to notion (the rounded caret doesn't work well with the font), and same size regardless of heading sizeCan you pay extra attention to alignment and margins? These are some of the most impactful design concepts. For example, the nested content should be vertically aligned with the parent content (if it helps, remove the vertical border on the left)empty toggle list should have a placeholder "Toggle" (same as Notion)dragging a collapsed toggle to a different position expands it's state- Nice to have: dropping blocks in an empty toggle
Others:
Toggle heading doesn't appear in formatting toolbar dropdownWe need to design an API of where to store "collapsed state" for the current userTyping in an empty toggle collapses the arrow (but does show the children placeholder)key down in an empty toggle doesn't work. In general, make sure to test keyboard handling- nice to have (but probably not trivial?): cmd+shift+arrow skip over collapsed blocks
Note about enter handling - when hitting enter within a togglable block, Notion does one of 2 things:
Since the BlockNote API currently doesn't have a way of splitting blocks in this way ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does isToggleable have to show up on every element now? Can it not just be assumed false if undefined? Or, do we always render "default values"?
packages/core/src/blocks/HeadingBlockContent/HeadingBlockContent.ts
Outdated
Show resolved
Hide resolved
{ | ||
onItemClick: () => { | ||
insertOrUpdateBlock(editor, { | ||
type: "heading", | ||
props: { level: 1, isToggleable: true }, | ||
}); | ||
}, | ||
key: "toggle_heading", | ||
...editor.dictionary.slash_menu.toggle_heading, | ||
}, | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to disable toggleable headings but not headings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, you could just do getDefaultSlashMenuItems(...).filter((item) => !item.key.startsWith("toggle_heading"))
right? So pretty much the same way you'd filter out any other items from the menu. Or do you mean in the schema itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant from the schema
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, in that case not really but I think it's ok for now, seems like something that will get fixed either way when converting default blocks to use the custom blocks API.
Toggle wrapper element/component
This PR adds a new component,
ToggleWrapper
, as well as a vanilla HTML element implementation of it,createToggleWrapper
. These can be used to wrap existing blocks, or create new ones and allow the user to toggle showing/hiding their children.The toggle wrapper renders a button to the left of the block to show/hide the children. Additionally, if children are shown but none exist, a button is rendered to prompt the user to add a block. Because the toggled state is only in the view, toggling the visibility of children only happens client-side when using collaboration.
A
toggledState
object can also be passed to the toggle wrapper, which includes aget
andset
function to be able to preserve the state on re-render and reload. By default, this is done using local storage.Schema changes
This PR also adds toggle headings and toggle list items to the default editor schema.
The toggle headings are implemented by adding an
isToggleable
prop, and rendering the block in a toggle wrapper when this is set totrue
.The toggle list item is a new, separate block, which always renders a paragraph in a toggle wrapper. Like the other list items though, hitting Enter in one creates a new block of the same type, which is why I made it a separate block rather than adding
isToggleable
to the existing paragraph or list item blocks. Additionally, the block is exported differently to formats like docx, as the content gets prepended with a ">".TODO
Currently some
xl-ai
tests are failing, and these have been temporarily disabled.Closes #196
Closes #549
Closes #910