Skip to content

Commit

Permalink
Merge pull request #836 from WordPress/update/827-block-sticky-focus
Browse files Browse the repository at this point in the history
Avoid block unselection by focus leave
  • Loading branch information
aduth authored May 18, 2017
2 parents 4916db2 + f520429 commit f496608
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 19 deletions.
34 changes: 20 additions & 14 deletions editor/modes/visual-editor/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ class VisualEditorBlock extends wp.element.Component {
super( ...arguments );
this.bindBlockNode = this.bindBlockNode.bind( this );
this.setAttributes = this.setAttributes.bind( this );
this.maybeDeselect = this.maybeDeselect.bind( this );
this.maybeHover = this.maybeHover.bind( this );
this.maybeStartTyping = this.maybeStartTyping.bind( this );
this.removeOnBackspace = this.removeOnBackspace.bind( this );
this.removeOrDeselect = this.removeOrDeselect.bind( this );
this.mergeBlocks = this.mergeBlocks.bind( this );
this.selectAndStopPropagation = this.selectAndStopPropagation.bind( this );
this.previousOffset = null;
}

Expand Down Expand Up @@ -76,14 +76,6 @@ class VisualEditorBlock extends wp.element.Component {
}
}

maybeDeselect( event ) {
// Annoyingly React does not support focusOut and we're forced to check
// related target to ensure it's not a child when blur fires.
if ( ! event.currentTarget.contains( event.relatedTarget ) ) {
this.props.onDeselect();
}
}

maybeStartTyping() {
// We do not want to dispatch start typing if...
// - State value already reflects that we're typing (dispatch noise)
Expand All @@ -96,14 +88,21 @@ class VisualEditorBlock extends wp.element.Component {
}
}

removeOnBackspace( event ) {
removeOrDeselect( event ) {
const { keyCode, target } = event;

// Remove block on backspace
if ( 8 /* Backspace */ === keyCode && target === this.node ) {
this.props.onRemove( this.props.uid );
if ( this.props.previousBlock ) {
this.props.onFocus( this.props.previousBlock.uid, { offset: -1 } );
}
}

// Deselect on escape
if ( 27 /* Escape */ === event.keyCode ) {
this.props.onDeselect();
}
}

mergeBlocks( forward = false ) {
Expand All @@ -124,6 +123,14 @@ class VisualEditorBlock extends wp.element.Component {
}
}

selectAndStopPropagation( event ) {
this.props.onSelect();

// Visual editor infers click as intent to clear the selected block, so
// prevent bubbling when occurring on block where selection is intended
event.stopPropagation();
}

componentDidUpdate( prevProps ) {
if ( this.previousOffset ) {
window.scrollTo(
Expand Down Expand Up @@ -178,10 +185,9 @@ class VisualEditorBlock extends wp.element.Component {
return (
<div
ref={ this.bindBlockNode }
onClick={ onSelect }
onClick={ this.selectAndStopPropagation }
onFocus={ onSelect }
onBlur={ this.maybeDeselect }
onKeyDown={ this.removeOnBackspace }
onKeyDown={ this.removeOrDeselect }
onMouseEnter={ onHover }
onMouseMove={ this.maybeHover }
onMouseLeave={ onMouseLeave }
Expand Down
29 changes: 24 additions & 5 deletions editor/modes/visual-editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
import { connect } from 'react-redux';

/**
* WordPress dependencies
*/
import { __ } from 'i18n';

/**
* Internal dependencies
*/
Expand All @@ -12,18 +17,32 @@ import VisualEditorBlock from './block';
import PostTitle from '../../post-title';
import { getBlockUids } from '../../selectors';

function VisualEditor( { blocks } ) {
function VisualEditor( { blocks, clearSelectedBlock } ) {
// Disable reason: Focus transfer between blocks and key events are handled
// by focused block element. Consider unhandled click bubbling as unselect.

/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
return (
<div className="editor-visual-editor">
<div
role="region"
aria-label={ __( 'Visual Editor' ) }
onClick={ clearSelectedBlock }
className="editor-visual-editor">
<PostTitle />
{ blocks.map( ( uid ) => (
<VisualEditorBlock key={ uid } uid={ uid } />
) ) }
<Inserter position="top right" />
</div>
);
/* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
}

export default connect( ( state ) => ( {
blocks: getBlockUids( state ),
} ) )( VisualEditor );
export default connect(
( state ) => ( {
blocks: getBlockUids( state ),
} ),
( dispatch ) => ( {
clearSelectedBlock: () => dispatch( { type: 'CLEAR_SELECTED_BLOCK' } ),
} )
)( VisualEditor );
2 changes: 2 additions & 0 deletions editor/modes/visual-editor/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
margin-top: -$block-controls-height - $item-spacing;
margin-bottom: $item-spacing + 20px; // 20px is the offset from the bottom of the selected block where it stops sticking
height: $block-controls-height;
width: 0;
white-space: nowrap;

top: $header-height + $admin-bar-height-big + $item-spacing;

Expand Down
3 changes: 3 additions & 0 deletions editor/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ export function selectedBlock( state = {}, action ) {
focus: action.uid === state.uid ? state.focus : {},
};

case 'CLEAR_SELECTED_BLOCK':
return {};

case 'MOVE_BLOCK_UP':
case 'MOVE_BLOCK_DOWN':
return action.uid === state.uid
Expand Down
9 changes: 9 additions & 0 deletions editor/test/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,15 @@ describe( 'state', () => {
expect( state ).to.eql( { uid: 'kumquat', typing: false, focus: {} } );
} );

it( 'returns an empty object when clearing selected block', () => {
const original = deepFreeze( { uid: 'kumquat', typing: false, focus: {} } );
const state = selectedBlock( original, {
type: 'CLEAR_SELECTED_BLOCK',
} );

expect( state ).to.eql( {} );
} );

it( 'should not update the state if already selected and not typing', () => {
const original = deepFreeze( { uid: 'kumquat', typing: false, focus: {} } );
const state = selectedBlock( original, {
Expand Down

0 comments on commit f496608

Please sign in to comment.