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

Fix block selection issues in safari by avoiding conditional event handlers #30968

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ import { store as blockEditorStore } from '../../../store';
*/
export function useEventHandlers( clientId ) {
const onSelectionStart = useContext( SelectionStart );
const { isSelected, rootClientId, index } = useSelect(
const { isBlockSelected, rootClientId, index } = useSelect(
( select ) => {
const {
isBlockSelected,
isBlockSelected: _isBlockSelected,
getBlockRootClientId,
getBlockIndex,
} = select( blockEditorStore );

return {
isSelected: isBlockSelected( clientId ),
isBlockSelected: _isBlockSelected,
rootClientId: getBlockRootClientId( clientId ),
index: getBlockIndex( clientId ),
Copy link
Member

Choose a reason for hiding this comment

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

For all of these selectors, we could really use #31078. All of the results are only used in callbacks so it's pointless to call them here.

};
Expand All @@ -48,30 +48,26 @@ export function useEventHandlers( clientId ) {

return useRefEffect(
( node ) => {
if ( ! isSelected ) {
/**
* Marks the block as selected when focused and not already
* selected. This specifically handles the case where block does not
* set focus on its own (via `setFocus`), typically if there is no
* focusable input in the block.
*
* @param {FocusEvent} event Focus event.
*/
function onFocus( event ) {
// If an inner block is focussed, that block is resposible for
// setting the selected block.
if ( ! isInsideRootBlock( node, event.target ) ) {
return;
}

selectBlock( clientId );
/**
* Marks the block as selected when focused and not already
* selected. This specifically handles the case where block does not
* set focus on its own (via `setFocus`), typically if there is no
* focusable input in the block.
*
* @param {FocusEvent} event Focus event.
*/
function onFocus( event ) {
if ( isBlockSelected( clientId ) ) {
return;
}

node.addEventListener( 'focusin', onFocus );
// If an inner block is focussed, that block is resposible for
// setting the selected block.
if ( ! isInsideRootBlock( node, event.target ) ) {
return;
}

return () => {
node.removeEventListener( 'focusin', onFocus );
};
selectBlock( clientId );
}

/**
Expand All @@ -86,6 +82,10 @@ export function useEventHandlers( clientId ) {
function onKeyDown( event ) {
const { keyCode, target } = event;

if ( ! isBlockSelected( clientId ) ) {
return;
}

if (
keyCode !== ENTER &&
keyCode !== BACKSPACE &&
Expand All @@ -108,6 +108,10 @@ export function useEventHandlers( clientId ) {
}

function onMouseLeave( { buttons } ) {
if ( ! isBlockSelected( clientId ) ) {
return;
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if it's a good idea to add this event handler to every block? It's only necessary for the selected block, there's no need to track mouse leaving for all the other blocks. Maybe there's barely a difference in performance though.

}

// The primary button must be pressed to initiate selection.
// See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
if ( buttons === 1 ) {
Expand All @@ -122,21 +126,27 @@ export function useEventHandlers( clientId ) {
* @param {DragEvent} event Drag event.
*/
function onDragStart( event ) {
if ( ! isBlockSelected( clientId ) ) {
return;
}

event.preventDefault();
}

node.addEventListener( 'focusin', onFocus );
node.addEventListener( 'keydown', onKeyDown );
node.addEventListener( 'mouseleave', onMouseLeave );
node.addEventListener( 'dragstart', onDragStart );

return () => {
node.removeEventListener( 'focusin', onFocus );
node.removeEventListener( 'mouseleave', onMouseLeave );
node.removeEventListener( 'keydown', onKeyDown );
node.removeEventListener( 'dragstart', onDragStart );
};
},
[
isSelected,
isBlockSelected,
rootClientId,
index,
onSelectionStart,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,8 @@ function BlockNavigationDropdown(
isEnabled={ isEnabled }
/>
) }
renderContent={ ( { onClose } ) => (
renderContent={ () => (
<BlockNavigation
onSelect={ onClose }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is actually a bug in trunk that is highlighted by this PR. (In a failing e2e test, focus was moving back to "inner block" after the parent was selected)

__experimentalFeatures={ __experimentalFeatures }
/>
) }
Expand Down
3 changes: 3 additions & 0 deletions packages/e2e-tests/specs/editor/blocks/list.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ describe( 'List', () => {
await clickBlockAppender();
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '* ' );
// Not entirely certain why this timeout is needed.
// eslint-disable-next-line no-restricted-syntax
await page.waitFor( 1000 );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ellatrix any ideas here? I suspect the test to be unstable in trunk too, just less visible but I don't understand how this PR impacts this since it's pretty consistent here.

Copy link
Member

Choose a reason for hiding this comment

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

I'll look into it

await page.keyboard.press( 'ArrowUp' );
await page.keyboard.press( 'ArrowDown' );
await page.keyboard.press( 'Backspace' );
Expand Down