diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js index a069f01781044..0f441be40cf21 100644 --- a/editor/components/block-list/block.js +++ b/editor/components/block-list/block.js @@ -64,6 +64,7 @@ import { isSelectionEnabled, isTyping, getBlockMode, + shouldBlockFocusNext, } from '../../store/selectors'; const { BACKSPACE, ESCAPE, DELETE, ENTER, UP, RIGHT, DOWN, LEFT } = keycodes; @@ -460,7 +461,7 @@ export class BlockListBlock extends Component { { isValid && mode === 'visual' && ( ( { isFirstMultiSelected: isFirstMultiSelectedBlock( state, uid ), isHovered: isBlockHovered( state, uid ) && ! isMultiSelecting( state ), focus: getBlockFocus( state, uid ), + shouldFocusNext: shouldBlockFocusNext( state, uid ), isTyping: isTyping( state ), order: getBlockIndex( state, uid ), meta: getEditedPostAttribute( state, 'meta' ), diff --git a/editor/store/reducer.js b/editor/store/reducer.js index daf74870dd195..b41f925768662 100644 --- a/editor/store/reducer.js +++ b/editor/store/reducer.js @@ -369,6 +369,7 @@ export function blockSelection( state = { focus: null, isMultiSelecting: false, isEnabled: true, + next: null, }, action ) { switch ( action.type ) { case 'CLEAR_SELECTED_BLOCK': @@ -427,14 +428,13 @@ export function blockSelection( state = { start: action.uid, end: action.uid, focus: action.config || {}, + next: null, }; case 'INSERT_BLOCKS': return { ...state, - start: action.blocks[ 0 ].uid, - end: action.blocks[ 0 ].uid, - focus: {}, - isMultiSelecting: false, + // We must wait for Editable to initialise. + next: action.blocks[ 0 ].uid, }; case 'REPLACE_BLOCKS': if ( ! action.blocks || ! action.blocks.length || action.uids.indexOf( state.start ) === -1 ) { diff --git a/editor/store/selectors.js b/editor/store/selectors.js index ad8bf075bdedf..9aae9df3580e7 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -776,6 +776,18 @@ export function getBlockFocus( state, uid ) { return state.blockSelection.focus; } +/** + * Returns true if the specified block should focus next. + * + * @param {Object} state Global application state. + * @param {string} uid Block unique ID. + * + * @returns {boolean} Whether the block should focus next. + */ +export function blockShouldFocusNext( state, uid ) { + return state.blockSelection.next === uid; +} + /** * Whether in the process of multi-selecting or not. * diff --git a/editor/store/test/reducer.js b/editor/store/test/reducer.js index 8fc34271bda20..56a4c67eb846a 100644 --- a/editor/store/test/reducer.js +++ b/editor/store/test/reducer.js @@ -780,6 +780,7 @@ describe( 'state', () => { focus: {}, isMultiSelecting: false, isEnabled: true, + next: null, } ); } ); @@ -892,7 +893,7 @@ describe( 'state', () => { } ], } ); - expect( state3 ).toEqual( { start: 'ribs', end: 'ribs', focus: {}, isMultiSelecting: false } ); + expect( state3 ).toEqual( { start: 'ribs', end: 'chicken', next: 'ribs' } ); } ); it( 'should not update the state if the block moved is already selected', () => { @@ -918,18 +919,19 @@ describe( 'state', () => { focus: { editable: 'citation' }, isMultiSelecting: false, isEnabled: true, + next: null, } ); } ); it( 'should update the focus and merge the existing state', () => { - const original = deepFreeze( { start: 'ribs', end: 'ribs', focus: {}, isMultiSelecting: true } ); + const original = deepFreeze( { start: 'ribs', end: 'ribs', focus: {}, isMultiSelecting: true, next: null } ); const state = blockSelection( original, { type: 'UPDATE_FOCUS', uid: 'ribs', config: { editable: 'citation' }, } ); - expect( state ).toEqual( { start: 'ribs', end: 'ribs', focus: { editable: 'citation' }, isMultiSelecting: true } ); + expect( state ).toEqual( { start: 'ribs', end: 'ribs', focus: { editable: 'citation' }, isMultiSelecting: true, next: null } ); } ); it( 'should replace the selected block', () => {