From 16a718a4bf359c53f0fb9c3626b08e2434a6fd7d Mon Sep 17 00:00:00 2001 From: Jorge Date: Wed, 7 Nov 2018 12:16:22 +0000 Subject: [PATCH] Add mechanism to avoid forced child selection on blocks with templates. (#10696) Currently, if a block contains a template when we insert that block the block that gets focused is one of the child blocks specified in the template. We don't offer a way to disable this behavior. This current behavior makes sense in most cases (e.g: columns) but for some cases, we may want to keep the focus on the parent. E.g. In PR #9416 @afercia pointed some a11y concerns in automatically selecting the child block on the InnerBlocks area. Blocks may have their own edition area and an InnerBlocks are at the end. Automatically selecting a block in the InnerBlocks area, has some accessible concerns has the parent block edition area may be unnoticeable for screen reader users. This PR adds a flag to the InnerBlocks component that allows blocks to disable the behavior of automatically selecting the children. In order for this flag to be possible another flag was added in insertBlock(s) action that allows for blocks to be inserted without a selection update happening. --- docs/data/data-core-editor.md | 8 +++---- .../src/components/inner-blocks/README.md | 7 ++++++ .../src/components/inner-blocks/index.js | 4 ++-- packages/editor/src/store/actions.js | 23 ++++++++++--------- packages/editor/src/store/reducer.js | 20 +++++++++------- packages/editor/src/store/test/actions.js | 2 ++ packages/editor/src/store/test/reducer.js | 19 +++++++++++++++ 7 files changed, 58 insertions(+), 25 deletions(-) diff --git a/docs/data/data-core-editor.md b/docs/data/data-core-editor.md index 267184d78113e5..5b823d1893d0db 100644 --- a/docs/data/data-core-editor.md +++ b/docs/data/data-core-editor.md @@ -1532,8 +1532,8 @@ inserted, optionally at a specific index respective a root block list. * block: Block object to insert. * index: Index at which block should be inserted. - * rootClientId: Optional root client ID of block list on which - to insert. + * rootClientId: Optional root client ID of block list on which to insert. + * updateSelection: If true block selection will be updated. If false, block selection will not change. Defaults to true. ### insertBlocks @@ -1544,8 +1544,8 @@ be inserted, optionally at a specific index respective a root block list. * blocks: Block objects to insert. * index: Index at which block should be inserted. - * rootClientId: Optional root client ID of block list on - which to insert. + * rootClientId: Optional root cliente ID of block list on which to insert. + * updateSelection: If true block selection will be updated. If false, block selection will not change. Defaults to true. ### showInsertionPoint diff --git a/packages/editor/src/components/inner-blocks/README.md b/packages/editor/src/components/inner-blocks/README.md index 494fb750fb74ca..040b0d463861cf 100644 --- a/packages/editor/src/components/inner-blocks/README.md +++ b/packages/editor/src/components/inner-blocks/README.md @@ -90,6 +90,13 @@ const TEMPLATE = [ [ 'core/columns', {}, [ The previous example creates an InnerBlocks area containing two columns one with an image and the other with a paragraph. +### `templateInsertUpdatesSelection` +* **Type:** `Boolean` +* **Default:** `true` + +If true when child blocks in the template are inserted the selection is updated. +If false the selection should not be updated when child blocks specified in the template are inserted. + ### `templateLock` * **Type:** `String|Boolean` diff --git a/packages/editor/src/components/inner-blocks/index.js b/packages/editor/src/components/inner-blocks/index.js index c9252e912b5df1..21831632211819 100644 --- a/packages/editor/src/components/inner-blocks/index.js +++ b/packages/editor/src/components/inner-blocks/index.js @@ -142,7 +142,7 @@ InnerBlocks = compose( [ insertBlocks, updateBlockListSettings, } = dispatch( 'core/editor' ); - const { block, clientId } = ownProps; + const { block, clientId, templateInsertUpdatesSelection = true } = ownProps; return { replaceInnerBlocks( blocks ) { @@ -150,7 +150,7 @@ InnerBlocks = compose( [ if ( clientIds.length ) { replaceBlocks( clientIds, blocks ); } else { - insertBlocks( blocks, undefined, clientId ); + insertBlocks( blocks, undefined, clientId, templateInsertUpdatesSelection ); } }, updateNestedSettings( settings ) { diff --git a/packages/editor/src/store/actions.js b/packages/editor/src/store/actions.js index 7d5c0d71ee2d1c..a77b27add51c28 100644 --- a/packages/editor/src/store/actions.js +++ b/packages/editor/src/store/actions.js @@ -295,35 +295,36 @@ export function moveBlockToPosition( clientId, fromRootClientId, toRootClientId, * Returns an action object used in signalling that a single block should be * inserted, optionally at a specific index respective a root block list. * - * @param {Object} block Block object to insert. - * @param {?number} index Index at which block should be inserted. - * @param {?string} rootClientId Optional root client ID of block list on which - * to insert. + * @param {Object} block Block object to insert. + * @param {?number} index Index at which block should be inserted. + * @param {?string} rootClientId Optional root client ID of block list on which to insert. + * @param {?boolean} updateSelection If true block selection will be updated. If false, block selection will not change. Defaults to true. * * @return {Object} Action object. */ -export function insertBlock( block, index, rootClientId ) { - return insertBlocks( [ block ], index, rootClientId ); +export function insertBlock( block, index, rootClientId, updateSelection = true ) { + return insertBlocks( [ block ], index, rootClientId, updateSelection ); } /** * Returns an action object used in signalling that an array of blocks should * be inserted, optionally at a specific index respective a root block list. * - * @param {Object[]} blocks Block objects to insert. - * @param {?number} index Index at which block should be inserted. - * @param {?string} rootClientId Optional root client ID of block list on - * which to insert. + * @param {Object[]} blocks Block objects to insert. + * @param {?number} index Index at which block should be inserted. + * @param {?string} rootClientId Optional root cliente ID of block list on which to insert. + * @param {?boolean} updateSelection If true block selection will be updated. If false, block selection will not change. Defaults to true. * * @return {Object} Action object. */ -export function insertBlocks( blocks, index, rootClientId ) { +export function insertBlocks( blocks, index, rootClientId, updateSelection = true ) { return { type: 'INSERT_BLOCKS', blocks: castArray( blocks ), index, rootClientId, time: Date.now(), + updateSelection, }; } diff --git a/packages/editor/src/store/reducer.js b/packages/editor/src/store/reducer.js index e95b010dc94d91..9ea2259b2c7919 100644 --- a/packages/editor/src/store/reducer.js +++ b/packages/editor/src/store/reducer.js @@ -705,14 +705,18 @@ export function blockSelection( state = { end: action.clientId, initialPosition: action.initialPosition, }; - case 'INSERT_BLOCKS': - return { - ...state, - start: action.blocks[ 0 ].clientId, - end: action.blocks[ 0 ].clientId, - initialPosition: null, - isMultiSelecting: false, - }; + case 'INSERT_BLOCKS': { + if ( action.updateSelection ) { + return { + ...state, + start: action.blocks[ 0 ].clientId, + end: action.blocks[ 0 ].clientId, + initialPosition: null, + isMultiSelecting: false, + }; + } + return state; + } case 'REMOVE_BLOCKS': if ( ! action.clientIds || ! action.clientIds.length || action.clientIds.indexOf( state.start ) === -1 ) { return state; diff --git a/packages/editor/src/store/test/actions.js b/packages/editor/src/store/test/actions.js index 4358054f8573b4..b071dc78204fb1 100644 --- a/packages/editor/src/store/test/actions.js +++ b/packages/editor/src/store/test/actions.js @@ -188,6 +188,7 @@ describe( 'actions', () => { index, rootClientId: 'testclientid', time: expect.any( Number ), + updateSelection: true, } ); } ); } ); @@ -204,6 +205,7 @@ describe( 'actions', () => { index, rootClientId: 'testclientid', time: expect.any( Number ), + updateSelection: true, } ); } ); } ); diff --git a/packages/editor/src/store/test/reducer.js b/packages/editor/src/store/test/reducer.js index 7d75ce2c55b4fe..005fd9127690fd 100644 --- a/packages/editor/src/store/test/reducer.js +++ b/packages/editor/src/store/test/reducer.js @@ -1567,6 +1567,7 @@ describe( 'state', () => { clientId: 'ribs', name: 'core/freeform', } ], + updateSelection: true, } ); expect( state3 ).toEqual( { @@ -1577,6 +1578,24 @@ describe( 'state', () => { } ); } ); + it( 'should not select inserted block if updateSelection flag is false', () => { + const original = deepFreeze( { start: 'a', end: 'b' } ); + + const state3 = blockSelection( original, { + type: 'INSERT_BLOCKS', + blocks: [ { + clientId: 'ribs', + name: 'core/freeform', + } ], + updateSelection: false, + } ); + + expect( state3 ).toEqual( { + start: 'a', + end: 'b', + } ); + } ); + it( 'should not update the state if the block moved is already selected', () => { const original = deepFreeze( { start: 'ribs', end: 'ribs' } ); const state = blockSelection( original, {