Skip to content

Commit

Permalink
Block editor: move block focus listener to block props hook (#27463)
Browse files Browse the repository at this point in the history
* Block editor: move block focus listener to block props hook

* Fixes

* Fix reusable blocks
  • Loading branch information
ellatrix authored Dec 3, 2020
1 parent bff5eac commit 79865f1
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 62 deletions.
38 changes: 36 additions & 2 deletions packages/block-editor/src/components/block-list/block-wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
},
[ isSelected ]
);
const { insertDefaultBlock, removeBlock } = useDispatch(
const { insertDefaultBlock, removeBlock, selectBlock } = useDispatch(
'core/block-editor'
);
const [ isHovered, setHovered ] = useState( false );
Expand Down Expand Up @@ -184,7 +184,29 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {

useEffect( () => {
if ( ! isSelected ) {
return;
/**
* 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( ref.current, event.target ) ) {
return;
}

selectBlock( clientId );
}

ref.current.addEventListener( 'focus', onFocus, true );

return () => {
ref.current.removeEventListener( 'focus', onFocus, true );
};
}

/**
Expand Down Expand Up @@ -228,12 +250,24 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
}
}

/**
* Prevents default dragging behavior within a block. To do: we must
* handle this in the future and clean up the drag target.
*
* @param {DragEvent} event Drag event.
*/
function onDragStart( event ) {
event.preventDefault();
}

ref.current.addEventListener( 'keydown', onKeyDown );
ref.current.addEventListener( 'mouseleave', onMouseLeave );
ref.current.addEventListener( 'dragstart', onDragStart );

return () => {
ref.current.removeEventListener( 'mouseleave', onMouseLeave );
ref.current.removeEventListener( 'keydown', onKeyDown );
ref.current.removeEventListener( 'dragstart', onDragStart );
};
}, [ isSelected, onSelectionStart, insertDefaultBlock, removeBlock ] );

Expand Down
57 changes: 0 additions & 57 deletions packages/block-editor/src/components/block-list/root-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,75 +7,20 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { createContext, forwardRef, useState } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';

/**
* Internal dependencies
*/
import useMultiSelection from './use-multi-selection';
import { getBlockClientId } from '../../utils/dom';
import useInsertionPoint from './insertion-point';
import BlockPopover from './block-popover';

/** @typedef {import('@wordpress/element').WPSyntheticEvent} WPSyntheticEvent */

export const Context = createContext();
export const BlockNodes = createContext();
export const SetBlockNodes = createContext();

function selector( select ) {
const { getSelectedBlockClientId, hasMultiSelection } = select(
'core/block-editor'
);

return {
selectedBlockClientId: getSelectedBlockClientId(),
hasMultiSelection: hasMultiSelection(),
};
}

/**
* Prevents default dragging behavior within a block.
* To do: we must handle this in the future and clean up the drag target.
* Previously dragging was prevented for multi-selected, but this is no longer
* needed.
*
* @param {WPSyntheticEvent} event Synthetic drag event.
*/
function onDragStart( event ) {
// Ensure we target block content, not block controls.
if ( getBlockClientId( event.target ) ) {
event.preventDefault();
}
}

function RootContainer( { children, className }, ref ) {
const { selectedBlockClientId, hasMultiSelection } = useSelect(
selector,
[]
);
const { selectBlock } = useDispatch( 'core/block-editor' );
const onSelectionStart = useMultiSelection( ref );

/**
* 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 {WPSyntheticEvent} event
*/
function onFocus( event ) {
if ( hasMultiSelection ) {
return;
}

const clientId = getBlockClientId( event.target );

if ( clientId && clientId !== selectedBlockClientId ) {
selectBlock( clientId );
}
}

const [ blockNodes, setBlockNodes ] = useState( {} );
const insertionPoint = useInsertionPoint( ref );

Expand All @@ -86,8 +31,6 @@ function RootContainer( { children, className }, ref ) {
<div
ref={ ref }
className={ classnames( className, 'is-root-container' ) }
onFocus={ onFocus }
onDragStart={ onDragStart }
>
<SetBlockNodes.Provider value={ setBlockNodes }>
<Context.Provider value={ onSelectionStart }>
Expand Down
18 changes: 15 additions & 3 deletions packages/block-library/src/block/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export default function ReusableBlockEdit( {
[ ref, clientId ]
);

const { clearSelectedBlock } = useDispatch( 'core/block-editor' );
const { editEntityRecord, saveEditedEntityRecord } = useDispatch( 'core' );
const { __experimentalSetEditingReusableBlock } = useDispatch(
reusableBlocksStore
Expand Down Expand Up @@ -118,16 +119,27 @@ export default function ReusableBlockEdit( {
);
}

/**
* Clear the selected block when focus moves to the reusable block list.
* These blocks are in different stores and only one block should be
* selected at a time.
*/
function onFocus() {
clearSelectedBlock();
}

let element = (
<BlockEditorProvider
value={ blocks }
onInput={ onInput }
onChange={ onChange }
settings={ settings }
>
<WritingFlow>
<BlockList />
</WritingFlow>
<div className="block-editor-block-list__block" onFocus={ onFocus }>
<WritingFlow>
<BlockList />
</WritingFlow>
</div>
</BlockEditorProvider>
);

Expand Down

0 comments on commit 79865f1

Please sign in to comment.