diff --git a/edit-post/components/visual-editor/style.scss b/edit-post/components/visual-editor/style.scss index e85bdfaba91f8..2622a974f115d 100644 --- a/edit-post/components/visual-editor/style.scss +++ b/edit-post/components/visual-editor/style.scss @@ -53,11 +53,13 @@ // This is a focus style shown for blocks that need an indicator even when in an isEditing state // like for example an image block that receives arrowkey focus. -.edit-post-visual-editor .editor-block-list__block:not( .is-selected ) .editor-block-list__block-edit { - box-shadow: 0 0 0 0 $white, 0 0 0 0 $dark-gray-900; - transition: .1s box-shadow .05s; +.edit-post-visual-editor .editor-block-list__block:not( .is-selected ) { + .editor-block-list__block-edit { + box-shadow: 0 0 0 0 $white, 0 0 0 0 $dark-gray-900; + transition: .1s box-shadow .05s; + } - &:focus { + &:focus .editor-block-list__block-edit { box-shadow: 0 0 0 1px $white, 0 0 0 3px $dark-gray-900; } } diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js index b5e07ea72dc35..c2628584b10df 100644 --- a/editor/components/block-list/block.js +++ b/editor/components/block-list/block.js @@ -174,6 +174,8 @@ export class BlockListBlock extends Component { // eslint-disable-next-line react/no-find-dom-node node = findDOMNode( node ); + this.wrapperNode = node; + this.props.blockRef( node, this.props.uid ); } @@ -191,7 +193,11 @@ export class BlockListBlock extends Component { focusTabbable() { const { initialPosition } = this.props; - if ( this.node.contains( document.activeElement ) ) { + // Focus is captured by the wrapper node, so while focus transition + // should only consider tabbables within editable display, since it + // may be the wrapper itself or a side control which triggered the + // focus event, don't unnecessary transition to an inner tabbable. + if ( this.wrapperNode.contains( document.activeElement ) ) { return; } @@ -347,20 +353,10 @@ export class BlockListBlock extends Component { * 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 A focus event - * * @return {void} */ - onFocus( event ) { - // Firefox-specific: Firefox will redirect focus of an already-focused - // node to its parent, but assign a property before doing so. If that - // property exists, ensure that it is the node, or abort. - const { explicitOriginalTarget } = event.nativeEvent; - if ( explicitOriginalTarget && explicitOriginalTarget !== this.node ) { - return; - } - - if ( event.target === this.node && ! this.props.isSelected ) { + onFocus() { + if ( ! this.props.isSelected && ! this.props.isMultiSelected ) { this.props.onSelect(); } } @@ -399,7 +395,12 @@ export class BlockListBlock extends Component { } else { this.props.onSelectionStart( this.props.uid ); - if ( ! this.props.isSelected ) { + // Allow user to escape out of a multi-selection to a singular + // selection of a block via click. This is handled here since + // onFocus excludes blocks involved in a multiselection, as + // focus can be incurred by starting a multiselection (focus + // moved to first block's multi-controls). + if ( this.props.isMultiSelected ) { this.props.onSelect(); } } @@ -565,13 +566,14 @@ export class BlockListBlock extends Component { className={ wrapperClassName } data-type={ block.name } onTouchStart={ this.onTouchStart } + onFocus={ this.onFocus } onClick={ this.onClick } + tabIndex="0" childHandledEvents={ [ 'onKeyPress', 'onDragStart', 'onMouseDown', 'onKeyDown', - 'onFocus', ] } { ...wrapperProps } > @@ -604,9 +606,7 @@ export class BlockListBlock extends Component { onDragStart={ this.preventDrag } onMouseDown={ this.onPointerDown } onKeyDown={ this.onKeyDown } - onFocus={ this.onFocus } - className={ BlockListBlock.className } - tabIndex="0" + className="editor-block-list__block-edit" aria-label={ blockLabel } data-block={ block.uid } > @@ -744,8 +744,6 @@ const mapDispatchToProps = ( dispatch, ownProps ) => ( { }, } ); -BlockListBlock.className = 'editor-block-list__block-edit'; - BlockListBlock.childContextTypes = { BlockList: noop, canUserUseUnfilteredHTML: noop, diff --git a/editor/components/block-list/layout.js b/editor/components/block-list/layout.js index 6238cf58d7350..9626788808110 100644 --- a/editor/components/block-list/layout.js +++ b/editor/components/block-list/layout.js @@ -25,6 +25,7 @@ import { Component } from '@wordpress/element'; import './style.scss'; import BlockListBlock from './block'; import BlockInsertionPoint from './insertion-point'; +import IgnoreNestedEvents from './ignore-nested-events'; import BlockSelectionClearer from '../block-selection-clearer'; import DefaultBlockAppender from '../default-block-appender'; import { @@ -233,11 +234,13 @@ class BlockListLayout extends Component { renderBlockMenu={ renderBlockMenu } /> ) ) } - + + + ); } diff --git a/editor/components/block-mover/index.js b/editor/components/block-mover/index.js index 8c3f68153757b..9ce135330950d 100644 --- a/editor/components/block-mover/index.js +++ b/editor/components/block-mover/index.js @@ -18,7 +18,6 @@ import { compose } from '@wordpress/element'; import './style.scss'; import { getBlockMoverLabel } from './mover-label'; import { getBlockIndex, getBlock } from '../../store/selectors'; -import { selectBlock } from '../../store/actions'; /** * Module constants @@ -94,10 +93,6 @@ export function BlockMover( { onMoveUp, onMoveDown, isFirst, isLast, uids, block function createOnMove( type, dispatch, ownProps ) { return () => { const { uids, rootUID } = ownProps; - if ( uids.length === 1 ) { - dispatch( selectBlock( first( uids ) ) ); - } - dispatch( { type, uids, rootUID } ); }; } diff --git a/editor/components/navigable-toolbar/index.js b/editor/components/navigable-toolbar/index.js index 05ee1e41483cb..52cb5f0e15e7f 100644 --- a/editor/components/navigable-toolbar/index.js +++ b/editor/components/navigable-toolbar/index.js @@ -39,7 +39,7 @@ class NavigableToolbar extends Component { // Is there a better way to focus the selected block // TODO: separate focused/selected block state and use Redux actions instead - const selectedBlock = document.querySelector( '.editor-block-list__block.is-selected .editor-block-list__block-edit' ); + const selectedBlock = document.querySelector( '.editor-block-list__block.is-selected' ); if ( !! selectedBlock ) { event.stopPropagation(); selectedBlock.focus(); diff --git a/editor/components/writing-flow/index.js b/editor/components/writing-flow/index.js index 59f7568cf1231..2e91cea7b3024 100644 --- a/editor/components/writing-flow/index.js +++ b/editor/components/writing-flow/index.js @@ -58,7 +58,7 @@ class WritingFlow extends Component { } getEditables( target ) { - const outer = target.closest( '.editor-block-list__block-edit' ); + const outer = target.closest( '.editor-block-list__block' ); if ( ! outer || target === outer ) { return [ target ]; } @@ -74,7 +74,7 @@ class WritingFlow extends Component { node.nodeName === 'INPUT' || node.nodeName === 'TEXTAREA' || node.contentEditable === 'true' || - node.classList.contains( 'editor-block-list__block-edit' ) + node.classList.contains( 'editor-block-list__block' ) ) ); } @@ -128,25 +128,6 @@ class WritingFlow extends Component { return editables.length > 0 && index === edgeIndex; } - /** - * Function called to ensure the block parent of the target node is selected. - * - * @param {DOMElement} target - */ - selectParentBlock( target ) { - if ( ! target ) { - return; - } - - const parentBlock = target.hasAttribute( 'data-block' ) ? target : target.closest( '[data-block]' ); - if ( - parentBlock && - ( ! this.props.selectedBlockUID || parentBlock.getAttribute( 'data-block' ) !== this.props.selectedBlockUID ) - ) { - this.props.onSelectBlock( parentBlock.getAttribute( 'data-block' ) ); - } - } - onKeyDown( event ) { const { selectedBlockUID, selectionStart, hasMultiSelection } = this.props; @@ -184,12 +165,10 @@ class WritingFlow extends Component { } else if ( isVertical && isVerticalEdge( target, isReverse, isShift ) ) { const closestTabbable = this.getClosestTabbable( target, isReverse ); placeCaretAtVerticalEdge( closestTabbable, isReverse, this.verticalRect ); - this.selectParentBlock( closestTabbable ); event.preventDefault(); } else if ( isHorizontal && isHorizontalEdge( target, isReverse, isShift ) ) { const closestTabbable = this.getClosestTabbable( target, isReverse ); placeCaretAtHorizontalEdge( closestTabbable, isReverse ); - this.selectParentBlock( closestTabbable ); event.preventDefault(); } }