diff --git a/packages/block-library/src/paragraph/edit.js b/packages/block-library/src/paragraph/edit.js index c6a2988a3d064..b48d3f0ee837a 100644 --- a/packages/block-library/src/paragraph/edit.js +++ b/packages/block-library/src/paragraph/edit.js @@ -23,6 +23,11 @@ import { import { createBlock } from '@wordpress/blocks'; import { formatLtr } from '@wordpress/icons'; +/** + * Internal dependencies + */ +import { useExitOnEnterAtEnd } from './use-enter'; + const name = 'core/paragraph'; function ParagraphRTLControl( { direction, setDirection } ) { @@ -57,6 +62,7 @@ function ParagraphBlock( { const { align, content, direction, dropCap, placeholder } = attributes; const isDropCapFeatureEnabled = useSetting( 'typography.dropCap' ); const blockProps = useBlockProps( { + ref: useExitOnEnterAtEnd( { clientId, content } ), className: classnames( { 'has-drop-cap': dropCap, [ `has-text-align-${ align }` ]: align, diff --git a/packages/block-library/src/paragraph/use-enter.js b/packages/block-library/src/paragraph/use-enter.js new file mode 100644 index 0000000000000..7b259d29d78c2 --- /dev/null +++ b/packages/block-library/src/paragraph/use-enter.js @@ -0,0 +1,72 @@ +/** + * WordPress dependencies + */ +import { useRef } from '@wordpress/element'; +import { useRefEffect } from '@wordpress/compose'; +import { ENTER } from '@wordpress/keycodes'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { hasBlockSupport } from '@wordpress/blocks'; + +export function useExitOnEnterAtEnd( props ) { + const { moveBlocksToPosition } = useDispatch( blockEditorStore ); + const { + getBlockRootClientId, + getBlockIndex, + getBlockOrder, + getBlockName, + } = useSelect( blockEditorStore ); + const propsRef = useRef( props ); + propsRef.current = props; + return useRefEffect( ( element ) => { + function onKeyDown( event ) { + if ( event.defaultPrevented ) { + return; + } + + if ( event.keyCode !== ENTER ) { + return; + } + + const { content, clientId } = propsRef.current; + + // The paragraph should be empty. + if ( content.length ) { + return; + } + + const wrapperClientId = getBlockRootClientId( clientId ); + + if ( + ! hasBlockSupport( + getBlockName( wrapperClientId ), + '__experimentalExitOnEnterAtEnd', + false + ) + ) { + return; + } + + const order = getBlockOrder( wrapperClientId ); + + // It should be the last block. + if ( order.indexOf( clientId ) !== order.length - 1 ) { + return; + } + + event.preventDefault(); + + moveBlocksToPosition( + [ clientId ], + wrapperClientId, + getBlockRootClientId( wrapperClientId ), + getBlockIndex( wrapperClientId ) + 1 + ); + } + + element.addEventListener( 'keydown', onKeyDown ); + return () => { + element.removeEventListener( 'keydown', onKeyDown ); + }; + }, [] ); +} diff --git a/packages/block-library/src/quote/block.json b/packages/block-library/src/quote/block.json index 28eb25f93d21b..9c19e44d32beb 100644 --- a/packages/block-library/src/quote/block.json +++ b/packages/block-library/src/quote/block.json @@ -30,6 +30,7 @@ "supports": { "anchor": true, "__experimentalSlashInserter": true, + "__experimentalExitOnEnterAtEnd": true, "typography": { "fontSize": true, "lineHeight": true,