Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
Prevent focus steal on clicking the inserter #18379
The problem was that the inserter sometimes stole focus from the currently selected block depending on which appender it used. The insertion point appender handled it correctly:
I have copied the same technique to all the other situations by creating a new appender exposed by
How has this been tested?
Types of changes
All the appenders need to have their focus event stopped from propagating and their tab index set to -1.
Changes to navigation:
I have been unable to keep the movers from stealing the focus of RichText using the same event technique from above, so as a solution (temporary?) I found the
I also think it looks better :) @karmatosed what do you think?
We should get to the bottom of the focus issue, not work around it by hacking element positioning.
I have redone this PR and used the same technique which the insertion point uses to prevent stealing focus: stop propagation of the focus event and set tab index to -1.
I will set the same behavior for the movers in the same PR, I have also renamed it as it is no longer about the navigation block.
talldan left a comment
I'm curious as to why it required so many changes across various files, I would've thought there would be only one appender used in the block.
It required so many changes because I kept discovering new places that stole focus :)) of course, like you suggested, there is indeed just one place to update. I did just that and added an explanatory comment copied over from the insertion point component.
talldan left a comment •
I may have to add the focus preservation behaviour conditionally if the focus is on the same parent block ... Thinking ...
I does fire but these appenders (social, group) also show the inserter which disappears because the block gets focused.
We'll see how E2E feels about this, b/c who knows what may be broken by this approach.
Kinda intricate but now it works. The only visual glitch is the inserter menu jumping a bit:
getdave left a comment •
Problem: the menu block has an appender. When a menu item is selected and one clicks the appender, the menu item is deselected because the appender steals the focus, and the appender moves away from under the mouse and does not receive the focus, so nothing happens. You then have to click the appender again to insert a new menu item.
Research: the appender steals the focus in many other situations as well, and this double click issue is also present in the social links block. Also for example in the columns block clicking the appender without the block selected selects the block, clicking the appender again opens the inserter menu. However in the group block clicking the appender without the block selected opens the inserter directly.
Observation: the insertion point appender does not remove the selection of the currently selected block.
Solution: apply the technique used for the insertion point of focus preservation, selectively and optionally when we want the flow to be smoother, such as for the navigation block or the social links block.
Other ways tried: trying to solve this for all the inserter/appender instances messed with the default selection mechanisms in various places (reusable blocks for example, or dynamic allowed blocks) and many tests failed. The core problem is that when we prevent the focus being set on the appender it also doesn't bubble up so the parent block of the appender is also not focused, and hence not selected. Manually selecting it is complicated.
We opted to solve it on a case by case fashion and we're starting with the
The fix is small and comprehensible, that said, I'm still not sure it's the best path forward. I wonder what's the root issue here. I guess it's related to this observation.
I'd personally prefer if we find a consistent way to fix this for all inserters.
@youknowriad fixing it for all inserters is very complicated and the problem isn't really Gutenberg's it's some bad browser behaviour.
I would love to have something merged to make the Navigation and Social Links feel better sooner, as the interaction is very clunky with that double click.
I have attempted general fixes using the same approach (the only one that seems to work) but it interferes with default block selection, so i becomes much more complicated and harder to test.
Could we come back to it and have this fix for the navigation block 1st?
This finally works and it has a perfectly elegant solution, thanks to @noisysocks 's great efforts into investigating Firefox quirks. Here is an explanation by the man himself:
So there’s two separate fixes to two separate but similar bugs: one where ButtonBlockAppender needs to be clicked twice and one where Inserter::defaultRenderToggle needs to be clicked twice
Cause: The default browser behaviour is that the mousedown on the button triggers a focus event which propagates up until it reaches the Navigation block’s BlockList component. This component then changes the currently selected block to be the Navigation block meaning that the appender is remounted and no longer clicked.
Fix: preventDefault() on the mousedown prevents the default browser behaviour of triggering a focus event. click (when focused) and focus (when selected via keyboard) still fire as normal
Cause: Here, the default browser behaviour differs. In Chrome, the mousedown triggers a focus event on the appender button as it should and then the click event follows. In Firefox, though, the mousedown triggers a focus event on the .edit-post-visual-editor element. I can’t for the life of me figure out why this happens. This focus event causes BlockSelectionClearer to clear the block selection meaning that the appender is remounted and no longer clicked.
Fix: preventDefault() on the mousedown event prevents the default browser focus event of triggering a focus event, but we still want the appender button to to be focused or else pressing Esc in the inserter will not return focus to the appender. Thus, we preventDefault() and manually focus the appender button.
I found this in latest shipping master, then worked through the commit history:
Here's how it looks when it works:
Not sure which bit of code caused this.