From f2ac84d441ee4f7e9afdf0c173a73bdac42dec05 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:03:59 +0100 Subject: [PATCH 01/14] Add tabindex 0 to all disabled elements in rich text --- packages/block-editor/src/components/rich-text/index.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 7236e74b2f6d68..0aa1bdc9a427e5 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -339,6 +339,7 @@ export function RichTextWrapper( } const TagName = tagName; + const tabIndex = props.tabIndex === 0 ? null : props.tabIndex; return ( <> { isSelected && ( @@ -438,11 +439,7 @@ export function RichTextWrapper( // select blocks when Shift Clicking into an element with // tabIndex because Safari will focus the element. However, // Safari will correctly ignore nested contentEditable elements. - tabIndex={ - props.tabIndex === 0 && ! shouldDisableEditing - ? null - : props.tabIndex - } + tabIndex={ shouldDisableEditing ? 0 : tabIndex } data-wp-block-attribute-key={ identifier } /> From 1c730c4621244cfbea047216235372441b618129 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:03:59 +0100 Subject: [PATCH 02/14] Insert block when use enter in disabled rich text --- .../src/components/rich-text/use-enter.js | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/use-enter.js b/packages/block-editor/src/components/rich-text/use-enter.js index 6b40a82d72d4b2..ffb5e9b368cc77 100644 --- a/packages/block-editor/src/components/rich-text/use-enter.js +++ b/packages/block-editor/src/components/rich-text/use-enter.js @@ -5,8 +5,12 @@ import { useRef } from '@wordpress/element'; import { useRefEffect } from '@wordpress/compose'; import { ENTER } from '@wordpress/keycodes'; import { insert, remove } from '@wordpress/rich-text'; -import { getBlockTransforms, findTransform } from '@wordpress/blocks'; -import { useDispatch, useRegistry } from '@wordpress/data'; +import { + createBlock, + getBlockTransforms, + findTransform, +} from '@wordpress/blocks'; +import { useDispatch, useRegistry, useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -16,20 +20,33 @@ import { splitValue } from './split-value'; export function useEnter( props ) { const registry = useRegistry(); - const { __unstableMarkAutomaticChange } = useDispatch( blockEditorStore ); + const { insertBlock, __unstableMarkAutomaticChange } = + useDispatch( blockEditorStore ); + const { + getBlockIndex, + getBlockName, + getBlockRootClientId, + getSelectedBlockClientId, + } = useSelect( blockEditorStore ); const propsRef = useRef( props ); propsRef.current = props; return useRefEffect( ( element ) => { function onKeyDown( event ) { - if ( event.target.contentEditable !== 'true' ) { + if ( event.defaultPrevented ) { return; } - if ( event.defaultPrevented ) { + if ( event.keyCode !== ENTER ) { return; } - if ( event.keyCode !== ENTER ) { + if ( event.target.contentEditable !== 'true' ) { + const clientId = getSelectedBlockClientId(); + insertBlock( + createBlock( getBlockName( clientId ), {} ), + getBlockIndex( clientId ) + 1, + getBlockRootClientId( clientId ) + ); return; } From 83037ed2bbb6efb21b2293a66e57cc436ddfc7e6 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:03:59 +0100 Subject: [PATCH 03/14] Take default block into account --- .../src/components/rich-text/use-enter.js | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/use-enter.js b/packages/block-editor/src/components/rich-text/use-enter.js index ffb5e9b368cc77..d9215a996a74af 100644 --- a/packages/block-editor/src/components/rich-text/use-enter.js +++ b/packages/block-editor/src/components/rich-text/use-enter.js @@ -9,6 +9,7 @@ import { createBlock, getBlockTransforms, findTransform, + store as blocksStore, } from '@wordpress/blocks'; import { useDispatch, useRegistry, useSelect } from '@wordpress/data'; @@ -20,14 +21,16 @@ import { splitValue } from './split-value'; export function useEnter( props ) { const registry = useRegistry(); - const { insertBlock, __unstableMarkAutomaticChange } = + const { insertBlock, insertDefaultBlock, __unstableMarkAutomaticChange } = useDispatch( blockEditorStore ); const { + canInsertBlockType, getBlockIndex, getBlockName, getBlockRootClientId, getSelectedBlockClientId, } = useSelect( blockEditorStore ); + const { getDefaultBlockName } = useSelect( blocksStore ); const propsRef = useRef( props ); propsRef.current = props; return useRefEffect( ( element ) => { @@ -42,11 +45,23 @@ export function useEnter( props ) { if ( event.target.contentEditable !== 'true' ) { const clientId = getSelectedBlockClientId(); - insertBlock( - createBlock( getBlockName( clientId ), {} ), - getBlockIndex( clientId ) + 1, + const canInsertDefaultBlock = canInsertBlockType( + getDefaultBlockName(), getBlockRootClientId( clientId ) ); + if ( canInsertDefaultBlock ) { + insertDefaultBlock( + {}, + getBlockRootClientId( clientId ), + getBlockIndex( clientId ) + 1 + ); + } else { + insertBlock( + createBlock( getBlockName( clientId ), {} ), + getBlockIndex( clientId ) + 1, + getBlockRootClientId( clientId ) + ); + } return; } From 11d471f5dfc6d7cfdee5c155a4d27e1ef06fd6d5 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 04/14] Add e2e tests when pressing enter in bound blocks --- .../editor/various/block-bindings.spec.js | 246 +++++++++++++----- 1 file changed, 184 insertions(+), 62 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js index ca19c06beff01a..9fd44e9eead1e0 100644 --- a/test/e2e/specs/editor/various/block-bindings.spec.js +++ b/test/e2e/specs/editor/various/block-bindings.spec.js @@ -47,7 +47,7 @@ test.describe( 'Block bindings', () => { } ); test.describe( 'Paragraph', () => { - test( 'Should show the value of the custom field', async ( { + test( 'should show the value of the custom field', async ( { editor, } ) => { await editor.insertBlock( { @@ -72,7 +72,7 @@ test.describe( 'Block bindings', () => { ); } ); - test( 'Should lock the appropriate controls with a registered source', async ( { + test( 'should lock the appropriate controls with a registered source', async ( { editor, page, } ) => { @@ -118,7 +118,7 @@ test.describe( 'Block bindings', () => { ); } ); - test( 'Should lock the appropriate controls when source is not defined', async ( { + test( 'should lock the appropriate controls when source is not defined', async ( { editor, page, } ) => { @@ -166,7 +166,7 @@ test.describe( 'Block bindings', () => { } ); test.describe( 'Heading', () => { - test( 'Should show the key of the custom field', async ( { + test( 'should show the key of the custom field', async ( { editor, } ) => { await editor.insertBlock( { @@ -189,7 +189,7 @@ test.describe( 'Block bindings', () => { await expect( headingBlock ).toHaveText( 'text_custom_field' ); } ); - test( 'Should lock the appropriate controls with a registered source', async ( { + test( 'should lock the appropriate controls with a registered source', async ( { editor, page, } ) => { @@ -235,7 +235,7 @@ test.describe( 'Block bindings', () => { ); } ); - test( 'Should lock the appropriate controls when source is not defined', async ( { + test( 'should lock the appropriate controls when source is not defined', async ( { editor, page, } ) => { @@ -283,7 +283,7 @@ test.describe( 'Block bindings', () => { } ); test.describe( 'Button', () => { - test( 'Should show the key of the custom field when text is bound', async ( { + test( 'should show the key of the custom field when text is bound', async ( { editor, } ) => { await editor.insertBlock( { @@ -313,7 +313,7 @@ test.describe( 'Block bindings', () => { await expect( buttonBlock ).toHaveText( 'text_custom_field' ); } ); - test( 'Should lock text controls when text is bound to a registered source', async ( { + test( 'should lock text controls when text is bound to a registered source', async ( { editor, page, } ) => { @@ -375,7 +375,7 @@ test.describe( 'Block bindings', () => { ).toBeVisible(); } ); - test( 'Should lock text controls when text is bound to an undefined source', async ( { + test( 'should lock text controls when text is bound to an undefined source', async ( { editor, page, } ) => { @@ -437,7 +437,7 @@ test.describe( 'Block bindings', () => { ).toBeVisible(); } ); - test( 'Should lock url controls when url is bound to a registered source', async ( { + test( 'should lock url controls when url is bound to a registered source', async ( { editor, page, } ) => { @@ -497,7 +497,7 @@ test.describe( 'Block bindings', () => { ).toBeHidden(); } ); - test( 'Should lock url controls when url is bound to an undefined source', async ( { + test( 'should lock url controls when url is bound to an undefined source', async ( { editor, page, } ) => { @@ -557,7 +557,7 @@ test.describe( 'Block bindings', () => { ).toBeHidden(); } ); - test( 'Should lock url and text controls when both are bound', async ( { + test( 'should lock url and text controls when both are bound', async ( { editor, page, } ) => { @@ -630,7 +630,7 @@ test.describe( 'Block bindings', () => { } ); test.describe( 'Image', () => { - test( 'Should show the upload form when url is not bound', async ( { + test( 'should show the upload form when url is not bound', async ( { editor, } ) => { await editor.insertBlock( { name: 'core/image' } ); @@ -643,7 +643,7 @@ test.describe( 'Block bindings', () => { ).toBeVisible(); } ); - test( 'Should NOT show the upload form when url is bound to a registered source', async ( { + test( 'should NOT show the upload form when url is bound to a registered source', async ( { editor, } ) => { await editor.insertBlock( { @@ -671,7 +671,7 @@ test.describe( 'Block bindings', () => { ).toBeHidden(); } ); - test( 'Should NOT show the upload form when url is bound to an undefined source', async ( { + test( 'should NOT show the upload form when url is bound to an undefined source', async ( { editor, } ) => { await editor.insertBlock( { @@ -699,7 +699,7 @@ test.describe( 'Block bindings', () => { ).toBeHidden(); } ); - test( 'Should lock url controls when url is bound to a registered source', async ( { + test( 'should lock url controls when url is bound to a registered source', async ( { editor, page, } ) => { @@ -768,7 +768,7 @@ test.describe( 'Block bindings', () => { expect( titleValue ).toBe( 'default title value' ); } ); - test( 'Should lock url controls when url is bound to an undefined source', async ( { + test( 'should lock url controls when url is bound to an undefined source', async ( { editor, page, } ) => { @@ -837,7 +837,7 @@ test.describe( 'Block bindings', () => { expect( titleValue ).toBe( 'default title value' ); } ); - test( 'Should disable alt textarea when alt is bound to a registered source', async ( { + test( 'should disable alt textarea when alt is bound to a registered source', async ( { editor, page, } ) => { @@ -900,7 +900,7 @@ test.describe( 'Block bindings', () => { expect( titleValue ).toBe( 'default title value' ); } ); - test( 'Should disable alt textarea when alt is bound to an undefined source', async ( { + test( 'should disable alt textarea when alt is bound to an undefined source', async ( { editor, page, } ) => { @@ -963,7 +963,7 @@ test.describe( 'Block bindings', () => { expect( titleValue ).toBe( 'default title value' ); } ); - test( 'Should disable title input when title is bound to a registered source', async ( { + test( 'should disable title input when title is bound to a registered source', async ( { editor, page, } ) => { @@ -1026,7 +1026,7 @@ test.describe( 'Block bindings', () => { expect( titleValue ).toBe( 'text_custom_field' ); } ); - test( 'Should disable title input when title is bound to an undefined source', async ( { + test( 'should disable title input when title is bound to an undefined source', async ( { editor, page, } ) => { @@ -1168,7 +1168,7 @@ test.describe( 'Block bindings', () => { await admin.createNewPost( { title: 'Test bindings' } ); } ); test.describe( 'Paragraph', () => { - test( 'Should show the value of the custom field when exists', async ( { + test( 'should show the value of the custom field when exists', async ( { editor, page, } ) => { @@ -1210,7 +1210,7 @@ test.describe( 'Block bindings', () => { ); } ); - test( "Should show the value of the key when custom field doesn't exists", async ( { + test( "should show the value of the key when custom field doesn't exist", async ( { editor, page, } ) => { @@ -1312,50 +1312,125 @@ test.describe( 'Block bindings', () => { 'fallback value' ); } ); + + test( 'should add empty paragraph block when pressing enter', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { + content: 'paragraph default content', + metadata: { + bindings: { + content: { + source: 'core/post-meta', + args: { key: 'text_custom_field' }, + }, + }, + }, + }, + } ); + const paragraphBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Paragraph', + } ); + await paragraphBlock.click(); + await page.keyboard.press( 'Enter' ); + const initialParagraph = ( await editor.getBlocks() )[ 0 ]; + const newEmptyParagraph = ( await editor.getBlocks() )[ 1 ]; + // First block should be the original block. + expect( initialParagraph.name ).toBe( 'core/paragraph' ); + expect( initialParagraph.attributes.content ).toBe( + 'Value of the text_custom_field' + ); + // Second block should be an empty paragraph block. + expect( newEmptyParagraph.name ).toBe( 'core/paragraph' ); + expect( newEmptyParagraph.attributes.content ).toBe( '' ); + } ); } ); - test( 'Heading - should show the value of the custom field', async ( { - editor, - page, - } ) => { - await editor.insertBlock( { - name: 'core/heading', - attributes: { - anchor: 'heading-binding', - content: 'heading default content', - metadata: { - bindings: { - content: { - source: 'core/post-meta', - args: { key: 'text_custom_field' }, + test.describe( 'Heading', () => { + test( 'should show the value of the custom field', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'core/heading', + attributes: { + anchor: 'heading-binding', + content: 'heading default content', + metadata: { + bindings: { + content: { + source: 'core/post-meta', + args: { key: 'text_custom_field' }, + }, }, }, }, - }, + } ); + const headingBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Heading', + } ); + await expect( headingBlock ).toHaveText( + 'Value of the text_custom_field' + ); + // Heading is not editable. + await expect( headingBlock ).toHaveAttribute( + 'contenteditable', + 'false' + ); + + // Check the frontend shows the value of the custom field. + const postId = await editor.publishPost(); + await page.goto( `/?p=${ postId }` ); + await expect( + page.locator( '#heading-binding' ) + ).toBeVisible(); + await expect( page.locator( '#heading-binding' ) ).toHaveText( + 'Value of the text_custom_field' + ); } ); - const headingBlock = editor.canvas.getByRole( 'document', { - name: 'Block: Heading', + + test( 'should add empty paragraph block when pressing enter', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'core/heading', + attributes: { + anchor: 'heading-binding', + content: 'heading default content', + metadata: { + bindings: { + content: { + source: 'core/post-meta', + args: { key: 'text_custom_field' }, + }, + }, + }, + }, + } ); + const headingBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Heading', + } ); + await headingBlock.click(); + await page.keyboard.press( 'Enter' ); + const initialHeading = ( await editor.getBlocks() )[ 0 ]; + const newEmptyParagraph = ( await editor.getBlocks() )[ 1 ]; + // First block should be the original block. + expect( initialHeading.name ).toBe( 'core/heading' ); + expect( initialHeading.attributes.content ).toBe( + 'Value of the text_custom_field' + ); + // Second block should be an empty paragraph block. + expect( newEmptyParagraph.name ).toBe( 'core/paragraph' ); + expect( newEmptyParagraph.attributes.content ).toBe( '' ); } ); - await expect( headingBlock ).toHaveText( - 'Value of the text_custom_field' - ); - // Heading is not editable. - await expect( headingBlock ).toHaveAttribute( - 'contenteditable', - 'false' - ); - - // Check the frontend shows the value of the custom field. - const postId = await editor.publishPost(); - await page.goto( `/?p=${ postId }` ); - await expect( page.locator( '#heading-binding' ) ).toBeVisible(); - await expect( page.locator( '#heading-binding' ) ).toHaveText( - 'Value of the text_custom_field' - ); } ); test.describe( 'Button', () => { - test( 'Should show the value of the custom field when text is bound', async ( { + test( 'should show the value of the custom field when text is bound', async ( { editor, page, } ) => { @@ -1411,7 +1486,7 @@ test.describe( 'Block bindings', () => { ); } ); - test( 'Should use the value of the custom field when url is bound', async ( { + test( 'should use the value of the custom field when url is bound', async ( { editor, page, } ) => { @@ -1449,7 +1524,7 @@ test.describe( 'Block bindings', () => { ); } ); - test( 'Should use the values of the custom fields when text and url are bound', async ( { + test( 'should use the values of the custom fields when text and url are bound', async ( { editor, page, } ) => { @@ -1492,6 +1567,53 @@ test.describe( 'Block bindings', () => { '#url-custom-field' ); } ); + + test( 'should add empty button block when pressing enter', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'core/buttons', + innerBlocks: [ + { + name: 'core/button', + attributes: { + anchor: 'button-text-binding', + text: 'button default text', + url: '#default-url', + metadata: { + bindings: { + text: { + source: 'core/post-meta', + args: { key: 'text_custom_field' }, + }, + }, + }, + }, + }, + ], + } ); + const buttonBlock = editor.canvas + .getByRole( 'document', { + name: 'Block: Button', + exact: true, + } ) + .getByRole( 'textbox' ); + await buttonBlock.click(); + await page.keyboard.press( 'Enter' ); + const initialButton = ( await editor.getBlocks() )[ 0 ] + .innerBlocks[ 0 ]; + const newEmptyButton = ( await editor.getBlocks() )[ 0 ] + .innerBlocks[ 1 ]; + // First block should be the original block. + expect( initialButton.name ).toBe( 'core/button' ); + expect( initialButton.attributes.text ).toBe( + 'Value of the text_custom_field' + ); + // Second block should be an empty paragraph block. + expect( newEmptyButton.name ).toBe( 'core/button' ); + expect( newEmptyButton.attributes.text ).toBe( '' ); + } ); } ); test.describe( 'Image', () => { @@ -1518,7 +1640,7 @@ test.describe( 'Block bindings', () => { } ); await page.reload(); } ); - test( 'Should show the value of the custom field when url is bound', async ( { + test( 'should show the value of the custom field when url is bound', async ( { editor, page, BlockBindingsUtils, @@ -1569,7 +1691,7 @@ test.describe( 'Block bindings', () => { ); } ); - test( 'Should show value of the custom field in the alt textarea when alt is bound', async ( { + test( 'should show value of the custom field in the alt textarea when alt is bound', async ( { editor, page, BlockBindingsUtils, @@ -1635,7 +1757,7 @@ test.describe( 'Block bindings', () => { ); } ); - test( 'Should show value of the custom field in the title input when title is bound', async ( { + test( 'should show value of the custom field in the title input when title is bound', async ( { editor, page, BlockBindingsUtils, From 50b8be95c5f87f7e5dcfb4d90668b449f12761cf Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 05/14] Revert initial implementation --- .../src/components/rich-text/index.js | 7 ++- .../src/components/rich-text/use-enter.js | 44 +++---------------- 2 files changed, 11 insertions(+), 40 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 0aa1bdc9a427e5..7236e74b2f6d68 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -339,7 +339,6 @@ export function RichTextWrapper( } const TagName = tagName; - const tabIndex = props.tabIndex === 0 ? null : props.tabIndex; return ( <> { isSelected && ( @@ -439,7 +438,11 @@ export function RichTextWrapper( // select blocks when Shift Clicking into an element with // tabIndex because Safari will focus the element. However, // Safari will correctly ignore nested contentEditable elements. - tabIndex={ shouldDisableEditing ? 0 : tabIndex } + tabIndex={ + props.tabIndex === 0 && ! shouldDisableEditing + ? null + : props.tabIndex + } data-wp-block-attribute-key={ identifier } /> diff --git a/packages/block-editor/src/components/rich-text/use-enter.js b/packages/block-editor/src/components/rich-text/use-enter.js index d9215a996a74af..6b40a82d72d4b2 100644 --- a/packages/block-editor/src/components/rich-text/use-enter.js +++ b/packages/block-editor/src/components/rich-text/use-enter.js @@ -5,13 +5,8 @@ import { useRef } from '@wordpress/element'; import { useRefEffect } from '@wordpress/compose'; import { ENTER } from '@wordpress/keycodes'; import { insert, remove } from '@wordpress/rich-text'; -import { - createBlock, - getBlockTransforms, - findTransform, - store as blocksStore, -} from '@wordpress/blocks'; -import { useDispatch, useRegistry, useSelect } from '@wordpress/data'; +import { getBlockTransforms, findTransform } from '@wordpress/blocks'; +import { useDispatch, useRegistry } from '@wordpress/data'; /** * Internal dependencies @@ -21,47 +16,20 @@ import { splitValue } from './split-value'; export function useEnter( props ) { const registry = useRegistry(); - const { insertBlock, insertDefaultBlock, __unstableMarkAutomaticChange } = - useDispatch( blockEditorStore ); - const { - canInsertBlockType, - getBlockIndex, - getBlockName, - getBlockRootClientId, - getSelectedBlockClientId, - } = useSelect( blockEditorStore ); - const { getDefaultBlockName } = useSelect( blocksStore ); + const { __unstableMarkAutomaticChange } = useDispatch( blockEditorStore ); const propsRef = useRef( props ); propsRef.current = props; return useRefEffect( ( element ) => { function onKeyDown( event ) { - if ( event.defaultPrevented ) { + if ( event.target.contentEditable !== 'true' ) { return; } - if ( event.keyCode !== ENTER ) { + if ( event.defaultPrevented ) { return; } - if ( event.target.contentEditable !== 'true' ) { - const clientId = getSelectedBlockClientId(); - const canInsertDefaultBlock = canInsertBlockType( - getDefaultBlockName(), - getBlockRootClientId( clientId ) - ); - if ( canInsertDefaultBlock ) { - insertDefaultBlock( - {}, - getBlockRootClientId( clientId ), - getBlockIndex( clientId ) + 1 - ); - } else { - insertBlock( - createBlock( getBlockName( clientId ), {} ), - getBlockIndex( clientId ) + 1, - getBlockRootClientId( clientId ) - ); - } + if ( event.keyCode !== ENTER ) { return; } From 68ddf58b10ead37a642d50f2f2da99555309afde Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 06/14] Use `insertAfterBlock` instead of `insertDefaultBlock`. --- .../use-block-props/use-selected-block-event-handlers.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-selected-block-event-handlers.js b/packages/block-editor/src/components/block-list/use-block-props/use-selected-block-event-handlers.js index bf4fc55879448a..c9edd195d0b7e2 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/use-selected-block-event-handlers.js +++ b/packages/block-editor/src/components/block-list/use-block-props/use-selected-block-event-handlers.js @@ -22,7 +22,8 @@ import { store as blockEditorStore } from '../../../store'; export function useEventHandlers( { clientId, isSelected } ) { const { getBlockRootClientId, getBlockIndex } = useSelect( blockEditorStore ); - const { insertDefaultBlock, removeBlock } = useDispatch( blockEditorStore ); + const { insertAfterBlock, insertDefaultBlock, removeBlock } = + useDispatch( blockEditorStore ); return useRefEffect( ( node ) => { @@ -57,11 +58,7 @@ export function useEventHandlers( { clientId, isSelected } ) { event.preventDefault(); if ( keyCode === ENTER ) { - insertDefaultBlock( - {}, - getBlockRootClientId( clientId ), - getBlockIndex( clientId ) + 1 - ); + insertAfterBlock( clientId ); } else { removeBlock( clientId ); } From 7c0ad6f0320d06849a65ff6da81434dcead23bd8 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 07/14] Remove unnecessary `insertDefaultBlock` --- .../use-block-props/use-selected-block-event-handlers.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-selected-block-event-handlers.js b/packages/block-editor/src/components/block-list/use-block-props/use-selected-block-event-handlers.js index c9edd195d0b7e2..01cc462e507ecf 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/use-selected-block-event-handlers.js +++ b/packages/block-editor/src/components/block-list/use-block-props/use-selected-block-event-handlers.js @@ -22,8 +22,7 @@ import { store as blockEditorStore } from '../../../store'; export function useEventHandlers( { clientId, isSelected } ) { const { getBlockRootClientId, getBlockIndex } = useSelect( blockEditorStore ); - const { insertAfterBlock, insertDefaultBlock, removeBlock } = - useDispatch( blockEditorStore ); + const { insertAfterBlock, removeBlock } = useDispatch( blockEditorStore ); return useRefEffect( ( node ) => { @@ -87,7 +86,7 @@ export function useEventHandlers( { clientId, isSelected } ) { isSelected, getBlockRootClientId, getBlockIndex, - insertDefaultBlock, + insertAfterBlock, removeBlock, ] ); From feb7bb088e3e7d56984584c33449312e295a9501 Mon Sep 17 00:00:00 2001 From: Mario Santos <34552881+SantosGuillamot@users.noreply.github.com> Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 08/14] Destructure innerBlocks array in tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Greg Ziółkowski --- test/e2e/specs/editor/various/block-bindings.spec.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js index 9fd44e9eead1e0..28e32b1a2c81dc 100644 --- a/test/e2e/specs/editor/various/block-bindings.spec.js +++ b/test/e2e/specs/editor/various/block-bindings.spec.js @@ -1601,10 +1601,8 @@ test.describe( 'Block bindings', () => { .getByRole( 'textbox' ); await buttonBlock.click(); await page.keyboard.press( 'Enter' ); - const initialButton = ( await editor.getBlocks() )[ 0 ] - .innerBlocks[ 0 ]; - const newEmptyButton = ( await editor.getBlocks() )[ 0 ] - .innerBlocks[ 1 ]; + const [ initialButton, newEmptyButton ] = ( await editor.getBlocks() )[ 0 ] + .innerBlocks; // First block should be the original block. expect( initialButton.name ).toBe( 'core/button' ); expect( initialButton.attributes.text ).toBe( From 5747b7fb8adaaf366a3f5c3a186b4a3b0ad96663 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 09/14] Prettify tests --- test/e2e/specs/editor/various/block-bindings.spec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js index 28e32b1a2c81dc..53336ee914e8d7 100644 --- a/test/e2e/specs/editor/various/block-bindings.spec.js +++ b/test/e2e/specs/editor/various/block-bindings.spec.js @@ -1601,8 +1601,9 @@ test.describe( 'Block bindings', () => { .getByRole( 'textbox' ); await buttonBlock.click(); await page.keyboard.press( 'Enter' ); - const [ initialButton, newEmptyButton ] = ( await editor.getBlocks() )[ 0 ] - .innerBlocks; + const [ initialButton, newEmptyButton ] = ( + await editor.getBlocks() + )[ 0 ].innerBlocks; // First block should be the original block. expect( initialButton.name ).toBe( 'core/button' ); expect( initialButton.attributes.text ).toBe( From 4b7d66af871094897594ff927b144a68f360632d Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 10/14] Remove unnecessary select in tests --- .../specs/editor/various/block-bindings.spec.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js index 53336ee914e8d7..cded5078d48d92 100644 --- a/test/e2e/specs/editor/various/block-bindings.spec.js +++ b/test/e2e/specs/editor/various/block-bindings.spec.js @@ -1331,10 +1331,6 @@ test.describe( 'Block bindings', () => { }, }, } ); - const paragraphBlock = editor.canvas.getByRole( 'document', { - name: 'Block: Paragraph', - } ); - await paragraphBlock.click(); await page.keyboard.press( 'Enter' ); const initialParagraph = ( await editor.getBlocks() )[ 0 ]; const newEmptyParagraph = ( await editor.getBlocks() )[ 1 ]; @@ -1411,10 +1407,6 @@ test.describe( 'Block bindings', () => { }, }, } ); - const headingBlock = editor.canvas.getByRole( 'document', { - name: 'Block: Heading', - } ); - await headingBlock.click(); await page.keyboard.press( 'Enter' ); const initialHeading = ( await editor.getBlocks() )[ 0 ]; const newEmptyParagraph = ( await editor.getBlocks() )[ 1 ]; @@ -1593,13 +1585,13 @@ test.describe( 'Block bindings', () => { }, ], } ); - const buttonBlock = editor.canvas + await editor.canvas .getByRole( 'document', { name: 'Block: Button', exact: true, } ) - .getByRole( 'textbox' ); - await buttonBlock.click(); + .getByRole( 'textbox' ) + .click(); await page.keyboard.press( 'Enter' ); const [ initialButton, newEmptyButton ] = ( await editor.getBlocks() From d93e586017df1032c9ccb1bb415c8d1647bf2dd9 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 11/14] Destructuring blocks in tests --- test/e2e/specs/editor/various/block-bindings.spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js index cded5078d48d92..c5f74d94d02449 100644 --- a/test/e2e/specs/editor/various/block-bindings.spec.js +++ b/test/e2e/specs/editor/various/block-bindings.spec.js @@ -1332,8 +1332,8 @@ test.describe( 'Block bindings', () => { }, } ); await page.keyboard.press( 'Enter' ); - const initialParagraph = ( await editor.getBlocks() )[ 0 ]; - const newEmptyParagraph = ( await editor.getBlocks() )[ 1 ]; + const [ initialParagraph, newEmptyParagraph ] = + await editor.getBlocks(); // First block should be the original block. expect( initialParagraph.name ).toBe( 'core/paragraph' ); expect( initialParagraph.attributes.content ).toBe( @@ -1408,8 +1408,8 @@ test.describe( 'Block bindings', () => { }, } ); await page.keyboard.press( 'Enter' ); - const initialHeading = ( await editor.getBlocks() )[ 0 ]; - const newEmptyParagraph = ( await editor.getBlocks() )[ 1 ]; + const [ initialHeading, newEmptyParagraph ] = + await editor.getBlocks(); // First block should be the original block. expect( initialHeading.name ).toBe( 'core/heading' ); expect( initialHeading.attributes.content ).toBe( From 09f67bf168a2d497ebd72d136e53df6a809ec3c4 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 12/14] Revert "Remove unnecessary select in tests" This reverts commit 63ffff87ca048a218567772710dcc45affcfd2aa. --- .../specs/editor/various/block-bindings.spec.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js index c5f74d94d02449..400c264b742ed4 100644 --- a/test/e2e/specs/editor/various/block-bindings.spec.js +++ b/test/e2e/specs/editor/various/block-bindings.spec.js @@ -1331,6 +1331,10 @@ test.describe( 'Block bindings', () => { }, }, } ); + const paragraphBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Paragraph', + } ); + await paragraphBlock.click(); await page.keyboard.press( 'Enter' ); const [ initialParagraph, newEmptyParagraph ] = await editor.getBlocks(); @@ -1407,6 +1411,10 @@ test.describe( 'Block bindings', () => { }, }, } ); + const headingBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Heading', + } ); + await headingBlock.click(); await page.keyboard.press( 'Enter' ); const [ initialHeading, newEmptyParagraph ] = await editor.getBlocks(); @@ -1585,13 +1593,13 @@ test.describe( 'Block bindings', () => { }, ], } ); - await editor.canvas + const buttonBlock = editor.canvas .getByRole( 'document', { name: 'Block: Button', exact: true, } ) - .getByRole( 'textbox' ) - .click(); + .getByRole( 'textbox' ); + await buttonBlock.click(); await page.keyboard.press( 'Enter' ); const [ initialButton, newEmptyButton ] = ( await editor.getBlocks() From 290273c9ea9f7ce6105cac085d613f0978fa0a76 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:04:00 +0100 Subject: [PATCH 13/14] Remove unnecessary select in tests --- .../specs/editor/various/block-bindings.spec.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js index 400c264b742ed4..c5f74d94d02449 100644 --- a/test/e2e/specs/editor/various/block-bindings.spec.js +++ b/test/e2e/specs/editor/various/block-bindings.spec.js @@ -1331,10 +1331,6 @@ test.describe( 'Block bindings', () => { }, }, } ); - const paragraphBlock = editor.canvas.getByRole( 'document', { - name: 'Block: Paragraph', - } ); - await paragraphBlock.click(); await page.keyboard.press( 'Enter' ); const [ initialParagraph, newEmptyParagraph ] = await editor.getBlocks(); @@ -1411,10 +1407,6 @@ test.describe( 'Block bindings', () => { }, }, } ); - const headingBlock = editor.canvas.getByRole( 'document', { - name: 'Block: Heading', - } ); - await headingBlock.click(); await page.keyboard.press( 'Enter' ); const [ initialHeading, newEmptyParagraph ] = await editor.getBlocks(); @@ -1593,13 +1585,13 @@ test.describe( 'Block bindings', () => { }, ], } ); - const buttonBlock = editor.canvas + await editor.canvas .getByRole( 'document', { name: 'Block: Button', exact: true, } ) - .getByRole( 'textbox' ); - await buttonBlock.click(); + .getByRole( 'textbox' ) + .click(); await page.keyboard.press( 'Enter' ); const [ initialButton, newEmptyButton ] = ( await editor.getBlocks() From 6bbe7a93b92b31730555b013eb423d351dec1727 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Fri, 1 Mar 2024 11:57:38 +0100 Subject: [PATCH 14/14] Adapt tests to latest changes --- .../editor/various/block-bindings.spec.js | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/test/e2e/specs/editor/various/block-bindings.spec.js b/test/e2e/specs/editor/various/block-bindings.spec.js index c5f74d94d02449..8cd3423290e3fa 100644 --- a/test/e2e/specs/editor/various/block-bindings.spec.js +++ b/test/e2e/specs/editor/various/block-bindings.spec.js @@ -1333,15 +1333,14 @@ test.describe( 'Block bindings', () => { } ); await page.keyboard.press( 'Enter' ); const [ initialParagraph, newEmptyParagraph ] = - await editor.getBlocks(); - // First block should be the original block. - expect( initialParagraph.name ).toBe( 'core/paragraph' ); - expect( initialParagraph.attributes.content ).toBe( + await editor.canvas + .locator( '[data-type="core/paragraph"]' ) + .all(); + await expect( initialParagraph ).toHaveText( 'Value of the text_custom_field' ); - // Second block should be an empty paragraph block. - expect( newEmptyParagraph.name ).toBe( 'core/paragraph' ); - expect( newEmptyParagraph.attributes.content ).toBe( '' ); + await expect( newEmptyParagraph ).toHaveText( '' ); + await expect( newEmptyParagraph ).toBeEditable(); } ); } ); @@ -1408,16 +1407,24 @@ test.describe( 'Block bindings', () => { }, } ); await page.keyboard.press( 'Enter' ); + // Can't use `editor.getBlocks` because it doesn't return the meta value shown in the editor. const [ initialHeading, newEmptyParagraph ] = - await editor.getBlocks(); + await editor.canvas.locator( '[data-block]' ).all(); // First block should be the original block. - expect( initialHeading.name ).toBe( 'core/heading' ); - expect( initialHeading.attributes.content ).toBe( + await expect( initialHeading ).toHaveAttribute( + 'data-type', + 'core/heading' + ); + await expect( initialHeading ).toHaveText( 'Value of the text_custom_field' ); // Second block should be an empty paragraph block. - expect( newEmptyParagraph.name ).toBe( 'core/paragraph' ); - expect( newEmptyParagraph.attributes.content ).toBe( '' ); + await expect( newEmptyParagraph ).toHaveAttribute( + 'data-type', + 'core/paragraph' + ); + await expect( newEmptyParagraph ).toHaveText( '' ); + await expect( newEmptyParagraph ).toBeEditable(); } ); } ); @@ -1593,17 +1600,16 @@ test.describe( 'Block bindings', () => { .getByRole( 'textbox' ) .click(); await page.keyboard.press( 'Enter' ); - const [ initialButton, newEmptyButton ] = ( - await editor.getBlocks() - )[ 0 ].innerBlocks; + const [ initialButton, newEmptyButton ] = await editor.canvas + .locator( '[data-type="core/button"]' ) + .all(); // First block should be the original block. - expect( initialButton.name ).toBe( 'core/button' ); - expect( initialButton.attributes.text ).toBe( + await expect( initialButton ).toHaveText( 'Value of the text_custom_field' ); // Second block should be an empty paragraph block. - expect( newEmptyButton.name ).toBe( 'core/button' ); - expect( newEmptyButton.attributes.text ).toBe( '' ); + await expect( newEmptyButton ).toHaveText( '' ); + await expect( newEmptyButton ).toBeEditable(); } ); } );