Skip to content

Conversation

@kean
Copy link
Contributor

@kean kean commented Oct 22, 2025

What?

How?

(see comments)

Testing Instructions

  • Verify that the selected block is inserted after the currently selected block. If the selected block is an empty paragraph, replace it with a newly created block.
  • Verify that when you open and close the inserter, it restores the focus

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

@kean kean force-pushed the task/insert-block branch from f5a1435 to a971b45 Compare October 22, 2025 18:20
// 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()
Copy link
Contributor Author

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 ) => {
Copy link
Contributor Author

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.

@kean kean requested a review from dcalhoun October 22, 2025 18:29
@kean kean force-pushed the task/insert-block branch from d332b04 to e714b40 Compare October 22, 2025 18:30
Base automatically changed from task/show-blocks-in-grid to trunk October 23, 2025 16:53
@kean kean force-pushed the task/insert-block branch from 848d34d to 932ffc4 Compare October 23, 2025 16:58
Copy link
Member

@dcalhoun dcalhoun left a 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.

@kean
Copy link
Contributor Author

kean commented Oct 24, 2025

I'm putting it back into draft. I've research the existing inserters and they all use the reusable useInsertionPoint and useBlockTypesState methods to determine what blocks to show and how to insert them. We should tap into it. There is no point in merging the intermediate solution.

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 window.editor).

cc @dcalhoun – let me know if it sounds like a plan.

@dcalhoun
Copy link
Member

@kean overall, that makes sense to me.

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 window.editor).

Avoiding window.editor is attractive. I do not follow what the replacement would resemble. Could you provide pseudo code to help me understand please?

@kean
Copy link
Contributor Author

kean commented Oct 24, 2025

I made a significant progress by using useInsertionPoint and useBlockTypesState. With these hooks, the native side doesn't need to know and implement very little.

Scenarios

Top-Level Insertion

  • Insert a block in empty core/paragraph – the paragraph gets replaced with the selected block ✅
  • Insert a block in an arbitrary “empty” position in the editor – gets inserted at the selected position ✅
  • Insert a block when the title is selected - shows an error “Block X can’t be inserted” ⛔️

Composite Blocks

  • Insert a supported block (core/list-item) in core/list – the list item is added ✅
  • Insert an unsupported block (core/image) in core/list – gets inserted after the block ✅
  • Insert a supported block (core/list) in core/quote – gets inserted in the block ✅

Contextual Blocks

  • Insert a block that supports a subset of child blocks (core/list) and open the inserter – blocks that support this parent (core/list-item) are displayed in a dedicated section at the top ✅
  • Insert a block that supports a subset of child blocks (core/list) in a composite block (core/quote) and open the inserter – blocks that support this parent (core/list-item) are displayed in a dedicated section at the top ✅

Known Issues

Recording

Screen.Recording.2025-10-24.at.4.24.04.PM.mov

Current Limitations

The main challenges I encountered:

  • Both useInsertionPoint and useBlockTypesState are private functions that are not exposed even via @wordpress/private-apis. It looks like we'll need to update the core to mitigate it.
  • Both are hooks, so I had to create an empty React component to use them. I'm not sure if there are any performance implications to it. It seems to re-compute often.

I'll might need some help with it. I'm going to wrap up for today.

Could you provide pseudo code to help me understand please?

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.

@kean kean force-pushed the task/insert-block branch from c75dc74 to 103d411 Compare October 27, 2025 19:04
@kean
Copy link
Contributor Author

kean commented Oct 27, 2025

I made a couple of small changes:

I think it's now in a mergeable state with a caveat that we need to figure out the best way to use private APIs.

I also logged an additional issue: CMM-903: Performance: Inserter recomputes the list of blocks on every change in the editor.

Copy link
Member

@dcalhoun dcalhoun left a comment

Choose a reason for hiding this comment

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

Works well from my testing. Code looks good too. I left a few suggestions for your consideration.

kean and others added 2 commits October 29, 2025 15:19
* Add support for block variants

* Rename BlockType

* Capitlize ID

* Update src/components/native-block-inserter-button/index.jsx

Co-authored-by: David Calhoun <github@davidcalhoun.me>

* Native Inserter: Improve ordering of blocks and more (#206)

* Add a note about serializeBlocksForNative

* Remove now redundant core/missing check

* Move ordering to the JS land

* Further refactoring

* Pass displayName for Text

* Localize categories

* Extend most used blocks

* Add gbk-most-used as a separate section

* Add support for disabling blocks

* Collapse long sections

* Update the order of embeds

* Fix linter errors

---------

Co-authored-by: David Calhoun <github@davidcalhoun.me>
@kean kean enabled auto-merge (squash) October 29, 2025 19:23
@kean kean merged commit b2a3304 into trunk Oct 29, 2025
11 checks passed
@kean kean deleted the task/insert-block branch October 29, 2025 19:25
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.

3 participants