diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index cccebd02de640f..a9b28f618daf5f 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -644,18 +644,34 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => { setAttributes( newAttributes ) { const { name, clientId } = ownProps; const type = getBlockType( name ); - updateBlockAttributes( clientId, newAttributes ); - const metaAttributes = reduce( - newAttributes, - ( result, value, key ) => { - if ( get( type, [ 'attributes', key, 'source' ] ) === 'meta' ) { - result[ type.attributes[ key ].meta ] = value; - } - - return result; - }, - {} - ); + + function isMetaAttribute( key ) { + return get( type, [ 'attributes', key, 'source' ] ) === 'meta'; + } + + // Partition new attributes to delegate update behavior by source. + // + // TODO: A consolidated approach to external attributes sourcing + // should be devised to avoid specific handling for meta, enable + // additional attributes sources. + // + // See: https://github.com/WordPress/gutenberg/issues/2759 + const { + blockAttributes, + metaAttributes, + } = reduce( newAttributes, ( result, value, key ) => { + if ( isMetaAttribute( key ) ) { + result.metaAttributes[ type.attributes[ key ].meta ] = value; + } else { + result.blockAttributes[ key ] = value; + } + + return result; + }, { blockAttributes: {}, metaAttributes: {} } ); + + if ( size( blockAttributes ) ) { + updateBlockAttributes( clientId, blockAttributes ); + } if ( size( metaAttributes ) ) { const { getSettings } = select( 'core/block-editor' ); diff --git a/packages/e2e-tests/specs/plugins/meta-attribute-block.test.js b/packages/e2e-tests/specs/plugins/meta-attribute-block.test.js index 5de9ea1f6c619b..0e87fdeefea616 100644 --- a/packages/e2e-tests/specs/plugins/meta-attribute-block.test.js +++ b/packages/e2e-tests/specs/plugins/meta-attribute-block.test.js @@ -8,6 +8,7 @@ import { getEditedPostContent, insertBlock, saveDraft, + pressKeyTimes, } from '@wordpress/e2e-test-utils'; describe( 'Block with a meta attribute', () => { @@ -25,7 +26,16 @@ describe( 'Block with a meta attribute', () => { it( 'Should persist the meta attribute properly', async () => { await insertBlock( 'Test Meta Attribute Block' ); - await page.keyboard.type( 'Meta Value' ); + await page.keyboard.type( 'Value' ); + + // Regression Test: Previously the caret would wrongly reset to the end + // of any input for meta-sourced attributes, due to syncing behavior of + // meta attribute updates. + // + // See: https://github.com/WordPress/gutenberg/issues/15739 + await pressKeyTimes( 'ArrowLeft', 5 ); + await page.keyboard.type( 'Meta ' ); + await saveDraft(); await page.reload();