-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 ), | ||
}; | ||
|
@@ -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 ); | ||
} | ||
|
||
/** | ||
|
@@ -86,6 +82,10 @@ export function useEventHandlers( clientId ) { | |
function onKeyDown( event ) { | ||
const { keyCode, target } = event; | ||
|
||
if ( ! isBlockSelected( clientId ) ) { | ||
return; | ||
} | ||
|
||
if ( | ||
keyCode !== ENTER && | ||
keyCode !== BACKSPACE && | ||
|
@@ -108,6 +108,10 @@ export function useEventHandlers( clientId ) { | |
} | ||
|
||
function onMouseLeave( { buttons } ) { | ||
if ( ! isBlockSelected( clientId ) ) { | ||
return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 ) { | ||
|
@@ -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, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,9 +80,8 @@ function BlockNavigationDropdown( | |
isEnabled={ isEnabled } | ||
/> | ||
) } | ||
renderContent={ ( { onClose } ) => ( | ||
renderContent={ () => ( | ||
<BlockNavigation | ||
onSelect={ onClose } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 } | ||
/> | ||
) } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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' ); | ||
|
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.
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.