-
Notifications
You must be signed in to change notification settings - Fork 3
Native Inserter: Implement block insertion #199
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: trunk
Are you sure you want to change the base?
Conversation
f5a1435 to
a971b45
Compare
| // Capture the selected block ID before showing the inserter | ||
| // (the editor will lose focus when the modal appears) | ||
| Task { @MainActor in | ||
| let selectedBlockID = await getSelectedBlockID() |
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.
The alternative was to memorize the selectedBlockID inside the editor, but I thought it would be more flexible to provide the native side with a capability to get the ID of the currently selected block and a way to insert block at any position.
| if ( isInserterOpened ) { | ||
| setIsInserterOpened( false ); | ||
| } | ||
| onTouchEnd={ ( e ) => { |
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.
Button with onTouchEnd is what works on mobile without losing focus.
d332b04 to
e714b40
Compare
848d34d to
932ffc4
Compare
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.
Thank you for putting this together. It tested relatively well for me. I left a few comments for us to consider. Curious of your thoughts.
| if ( isInserterOpened ) { | ||
| setIsInserterOpened( false ); | ||
| } | ||
| onTouchEnd={ ( e ) => { |
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.
The usage of onTouchEnd does introduce one downside (there may be others I yet to notice): you cannot cancel the interaction by dragging your finger away from the button.
My perception is that is simply the nature of onTouchEnd, its callback is triggered regardless of the position of the user's finger when it is triggered. Contrastingly, the onClick callback is only triggered when a full "click" occurs, which requires the end of the interaction to be atop the target button element.
We may be able to add logic to track and compare the touch start and end positions, or the element beneath the latter. Or Claude mentioned we could potentially use onClick and pair it with onMouseDown invoking preventDefault() to prevent focus changes.
While the onTouchEnd approach may work for a GutenbergKit-specific button, I'm concerned it may not be an avenue we could use for other buttons rendered within Gutenberg components—e.g., dropdown menu toggles and items.
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.
you cannot cancel the interaction by dragging your finger away from the button.
I noticed that too yesterday. I'll try different option. ideally, it should behave like native buttons and cancel action.
or Claude mentioned we could potentially use onClick and pair it with onMouseDown invoking preventDefault() to prevent focus changes.
I tried that yesterday, but was not satisfied with the result for some reason – I'll give it another go.
| if ( targetBlockClientId ) { | ||
| const selectedBlock = getBlock( targetBlockClientId ); | ||
|
|
||
| // If the selected block is an empty paragraph, replace it |
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.
It's functionality like this that make the native inserter concerning. How many are there that we may need to reimplement and maintain?
I noticed one missing that relates to the current block (similar to the noted composite blocks). For example, when inside a List (technically focused on a List Item), the inserter should display List Item as a top item. Additionally, selecting other block types that cannot be placed in a List block results in a new block inserted after the currently selected List.
Simulator.Screen.Recording.-.iPhone.17.-.2025-10-23.at.12.31.26.mov
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.
How many are there that we may need to reimplement and maintain?
This is probably the main risk. The inserter, if you remove the media and tests, is ~2500 lines of JS. Most of it is related to UI and search – not business logic. I'll spend some time reading through it tomorrow to see what else we might be missing. I'm concerned there are some unknowns, but, in principle, it seems to be just isolated enough from the rest of the editor, and we could always expose the APIs that we need.
I'm happy to consider alternatives, but so far, it still seems like the one thing worth doing to push the envelope on mobile. If we are not providing first-class integration for media, we are not doing enough, and this seems like the only technical solution.
For example, when inside a List (technically focused on a List Item), the inserter should display List Item as a top item.
I'm tracking it in the existing ticket CMM-866: Add support for dynamic blocks – depending on selection.
Additionally, selecting other block types that cannot be placed in a List block results in a new block inserted after the currently selected List.
The web does the same. I've also tested it with core/table previously and thought it was a bug, but it was the standard Gutenberg behavior.
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.
Additionally, selecting other block types that cannot be placed in a List block results in a new block inserted after the currently selected List.
The web does the same. I've also tested it with
core/tablepreviously and thought it was a bug, but it was the standard Gutenberg behavior.
Sorry, I meant to convey that standard functionality does not work with the native inserter. The video in my previous comment shows the working functionality with the web inserter.
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.
Oh, I got what you mean now. It does work with core/table and the native inserter – the selected incompatible block is appended below the table. It does not work with core/list – nothing happens. I'll look into it in the scope of this PR without creating a ticket.
|
I'm putting it back into draft. I've research the existing inserters and they all use the reusable I will also look into a way to better architect the interaction between web and native. On a high level, I want to create all the requires context by the inserter, including the callbacks, and pass it a a separate JS object to the native side that it could invoke (as opposed to defining these methods on cc @dcalhoun – let me know if it sounds like a plan. |
|
@kean overall, that makes sense to me.
Avoiding |
|
I made a significant progress by using ScenariosTop-Level Insertion
Composite Blocks
Contextual Blocks
Known Issues
RecordingScreen.Recording.2025-10-24.at.4.24.04.PM.movCurrent LimitationsThe main challenges I encountered:
I'll might need some help with it. I'm going to wrap up for today.
I decided to keep to simple. If there is more than one scenario where we need a generalized solution, then maybe it would be a good time to consider it. |
What?
Closes CMM-867: Add support for inserting selected blocks at the selection point.
How?
(see comments)
Testing Instructions
Note: there may be other scenarios I'm not thinking of, including some of the composite blocks like "Gallery" or "Columns". For "Columns", I already opened CMM-880.
Screenshots or screencast
Screen.Recording.2025-10-22.at.9.12.53.AM.mov