diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js index f906372bfa815..825deb9f5b436 100644 --- a/packages/block-editor/src/components/block-list/index.js +++ b/packages/block-editor/src/components/block-list/index.js @@ -211,7 +211,9 @@ function Items( { 'disabled' && __unstableGetEditorMode() !== 'zoom-out' : rootClientId === selectedBlockClientId || - ( ! rootClientId && ! selectedBlockClientId ) ), + ( ! rootClientId && + ! selectedBlockClientId && + ! _order.length ) ), }; }, [ rootClientId, hasAppender, hasCustomAppender ] diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index 74dffb35fcd27..0b36ef6da01d1 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -19,6 +19,7 @@ import { store as blocksStore } from '@wordpress/blocks'; */ import { store as editPostStore } from '../../store'; import { unlock } from '../../lock-unlock'; +import { usePaddingAppender } from './use-padding-appender'; const { EditorCanvas } = unlock( editorPrivateApis ); @@ -53,6 +54,8 @@ export default function VisualEditor( { styles } ) { [] ); + const paddingAppenderRef = usePaddingAppender(); + let paddingBottom; // Add a constant padding for the typewritter effect. When typing at the @@ -91,6 +94,7 @@ export default function VisualEditor( { styles } ) { // We should auto-focus the canvas (title) on load. // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus={ ! isWelcomeGuideVisible } + contentRef={ paddingAppenderRef } /> ); diff --git a/packages/edit-post/src/components/visual-editor/use-padding-appender.js b/packages/edit-post/src/components/visual-editor/use-padding-appender.js new file mode 100644 index 0000000000000..c091443495740 --- /dev/null +++ b/packages/edit-post/src/components/visual-editor/use-padding-appender.js @@ -0,0 +1,66 @@ +/** + * WordPress dependencies + */ +import { useRegistry } from '@wordpress/data'; +import { useRefEffect } from '@wordpress/compose'; +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { isUnmodifiedDefaultBlock } from '@wordpress/blocks'; + +export function usePaddingAppender() { + const registry = useRegistry(); + return useRefEffect( + ( node ) => { + function onMouseDown( event ) { + if ( event.target !== node ) { + return; + } + + const { ownerDocument } = node; + const { defaultView } = ownerDocument; + + const paddingBottom = defaultView.parseInt( + defaultView.getComputedStyle( node ).paddingBottom, + 10 + ); + + if ( ! paddingBottom ) { + return; + } + + // only handle clicks under the last child + const lastChild = node.lastElementChild; + if ( ! lastChild ) { + return; + } + + const lastChildRect = lastChild.getBoundingClientRect(); + if ( event.clientY < lastChildRect.bottom ) { + return; + } + + event.preventDefault(); + + const blockOrder = registry + .select( blockEditorStore ) + .getBlockOrder( '' ); + const lastBlockClientId = blockOrder[ blockOrder.length - 1 ]; + const lastBlock = registry + .select( blockEditorStore ) + .getBlock( lastBlockClientId ); + const { selectBlock, insertDefaultBlock } = + registry.dispatch( blockEditorStore ); + + if ( isUnmodifiedDefaultBlock( lastBlock ) ) { + selectBlock( lastBlockClientId ); + } else { + insertDefaultBlock(); + } + } + node.addEventListener( 'mousedown', onMouseDown ); + return () => { + node.removeEventListener( 'mousedown', onMouseDown ); + }; + }, + [ registry ] + ); +} diff --git a/packages/editor/src/components/editor-canvas/index.js b/packages/editor/src/components/editor-canvas/index.js index 363d52b124aa0..5b45f42be92a9 100644 --- a/packages/editor/src/components/editor-canvas/index.js +++ b/packages/editor/src/components/editor-canvas/index.js @@ -39,8 +39,6 @@ const { useFlashEditableBlocks, } = unlock( blockEditorPrivateApis ); -const noop = () => {}; - /** * These post types have a special editor where they don't allow you to fill the title * and they don't apply the layout styles. @@ -95,6 +93,7 @@ function EditorCanvas( { styles, disableIframe = false, iframeProps, + contentRef, children, } ) { const { @@ -308,9 +307,10 @@ function EditorCanvas( { const localRef = useRef(); const typewriterRef = useTypewriter(); - const contentRef = useMergeRefs( [ + contentRef = useMergeRefs( [ localRef, - renderingMode === 'post-only' ? typewriterRef : noop, + contentRef, + renderingMode === 'post-only' ? typewriterRef : null, useFlashEditableBlocks( { isEnabled: renderingMode === 'template-locked', } ), diff --git a/test/e2e/specs/editor/plugins/custom-post-types.spec.js b/test/e2e/specs/editor/plugins/custom-post-types.spec.js index 01dde03650ef7..9aabe4e7454f9 100644 --- a/test/e2e/specs/editor/plugins/custom-post-types.spec.js +++ b/test/e2e/specs/editor/plugins/custom-post-types.spec.js @@ -72,9 +72,7 @@ test.describe( 'Test Custom Post Types', () => { page, } ) => { await admin.createNewPost( { postType: 'leg_block_in_tpl' } ); - await editor.canvas - .locator( 'role=button[name="Add default block"i]' ) - .click(); + await editor.insertBlock( { name: 'core/paragraph' } ); await page.keyboard.type( 'Hello there' ); await expect.poll( editor.getBlocks ).toMatchObject( [ diff --git a/test/e2e/specs/editor/various/copy-cut-paste.spec.js b/test/e2e/specs/editor/various/copy-cut-paste.spec.js index ec0cbab9ca809..a4055af481394 100644 --- a/test/e2e/specs/editor/various/copy-cut-paste.spec.js +++ b/test/e2e/specs/editor/various/copy-cut-paste.spec.js @@ -64,9 +64,7 @@ test.describe( 'Copy/cut/paste', () => { await page.evaluate( () => { window.wp.data.dispatch( 'core/block-editor' ).clearSelectedBlock(); } ); - await editor.canvas - .locator( 'role=button[name="Add default block"i]' ) - .click(); + await editor.insertBlock( { name: 'core/paragraph' } ); await pageUtils.pressKeys( 'primary+v' ); expect( await editor.getEditedPostContent() ).toMatchSnapshot(); } ); @@ -85,9 +83,7 @@ test.describe( 'Copy/cut/paste', () => { await page.evaluate( () => { window.wp.data.dispatch( 'core/block-editor' ).clearSelectedBlock(); } ); - await editor.canvas - .locator( 'role=button[name="Add default block"i]' ) - .click(); + await editor.insertBlock( { name: 'core/paragraph' } ); await pageUtils.pressKeys( 'primary+v' ); expect( await editor.getEditedPostContent() ).toMatchSnapshot(); } ); diff --git a/test/e2e/specs/editor/various/inserting-blocks.spec.js b/test/e2e/specs/editor/various/inserting-blocks.spec.js index 8d7f996597224..b3da80c12ab09 100644 --- a/test/e2e/specs/editor/various/inserting-blocks.spec.js +++ b/test/e2e/specs/editor/various/inserting-blocks.spec.js @@ -26,6 +26,27 @@ test.describe( 'Inserting blocks (@firefox, @webkit)', () => { await requestUtils.deleteAllPatternCategories(); } ); + test( 'inserts a default block on bottom padding click', async ( { + admin, + editor, + } ) => { + await admin.createNewPost(); + await editor.insertBlock( { name: 'core/image' } ); + const body = editor.canvas.locator( 'body' ); + const box = await body.boundingBox(); + await body.click( { + position: { + x: box.width / 2, + y: box.height - 10, + }, + } ); + + expect( await editor.getBlocks() ).toMatchObject( [ + { name: 'core/image' }, + { name: 'core/paragraph' }, + ] ); + } ); + test( 'inserts blocks by dragging and dropping from the global inserter', async ( { admin, page, diff --git a/test/e2e/specs/editor/various/keyboard-navigable-blocks.spec.js b/test/e2e/specs/editor/various/keyboard-navigable-blocks.spec.js index 51b08359d1269..6a7125d04f7a6 100644 --- a/test/e2e/specs/editor/various/keyboard-navigable-blocks.spec.js +++ b/test/e2e/specs/editor/various/keyboard-navigable-blocks.spec.js @@ -107,14 +107,6 @@ test.describe( 'Order of block keyboard navigation', () => { .focus(); } ); - await pageUtils.pressKeys( 'shift+Tab' ); - await KeyboardNavigableBlocks.expectLabelToHaveFocus( 'Add block' ); - - await pageUtils.pressKeys( 'shift+Tab' ); - await KeyboardNavigableBlocks.expectLabelToHaveFocus( - 'Add default block' - ); - await pageUtils.pressKeys( 'shift+Tab' ); await KeyboardNavigableBlocks.expectLabelToHaveFocus( 'Paragraph Block. Row 2. 1'