diff --git a/packages/block-editor/src/components/block-list/block-wrapper.js b/packages/block-editor/src/components/block-list/block-wrapper.js
new file mode 100644
index 00000000000000..c4c8f374024aa2
--- /dev/null
+++ b/packages/block-editor/src/components/block-list/block-wrapper.js
@@ -0,0 +1,223 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+import { first, last, omit } from 'lodash';
+import { animated } from 'react-spring/web.cjs';
+
+/**
+ * WordPress dependencies
+ */
+import { useRef, useEffect, useLayoutEffect, useContext, forwardRef } from '@wordpress/element';
+import { focus, isTextField, placeCaretAtHorizontalEdge } from '@wordpress/dom';
+import { BACKSPACE, DELETE, ENTER } from '@wordpress/keycodes';
+import { __, sprintf } from '@wordpress/i18n';
+import { useSelect, useDispatch } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import { isInsideRootBlock } from '../../utils/dom';
+import useMovingAnimation from './moving-animation';
+import { Context, BlockNodes } from './root-container';
+import { BlockContext } from './block';
+
+const BlockComponent = forwardRef( ( {
+ children,
+ tagName = 'div',
+ __unstableIsHtml,
+ ...props
+}, wrapper ) => {
+ const onSelectionStart = useContext( Context );
+ const [ , setBlockNodes ] = useContext( BlockNodes );
+ const {
+ clientId,
+ rootClientId,
+ isSelected,
+ isFirstMultiSelected,
+ isLastMultiSelected,
+ isMultiSelecting,
+ isNavigationMode,
+ isPartOfMultiSelection,
+ enableAnimation,
+ index,
+ className,
+ isLocked,
+ name,
+ mode,
+ blockTitle,
+ } = useContext( BlockContext );
+ const { initialPosition } = useSelect( ( select ) => {
+ if ( ! isSelected ) {
+ return {};
+ }
+
+ return {
+ initialPosition: select( 'core/block-editor' )
+ .getSelectedBlocksInitialCaretPosition(),
+ };
+ }, [ isSelected ] );
+ const {
+ removeBlock,
+ insertDefaultBlock,
+ } = useDispatch( 'core/block-editor' );
+ const fallbackRef = useRef();
+
+ wrapper = wrapper || fallbackRef;
+
+ // Provide the selected node, or the first and last nodes of a multi-
+ // selection, so it can be used to position the contextual block toolbar.
+ // We only provide what is necessary, and remove the nodes again when they
+ // are no longer selected.
+ useLayoutEffect( () => {
+ if ( isSelected || isFirstMultiSelected || isLastMultiSelected ) {
+ const node = wrapper.current;
+ setBlockNodes( ( nodes ) => ( { ...nodes, [ clientId ]: node } ) );
+ return () => {
+ setBlockNodes( ( nodes ) => omit( nodes, clientId ) );
+ };
+ }
+ }, [ isSelected, isFirstMultiSelected, isLastMultiSelected ] );
+
+ // translators: %s: Type of block (i.e. Text, Image etc)
+ const blockLabel = sprintf( __( 'Block: %s' ), blockTitle );
+
+ // Handing the focus of the block on creation and update
+
+ /**
+ * When a block becomes selected, transition focus to an inner tabbable.
+ *
+ * @param {boolean} ignoreInnerBlocks Should not focus inner blocks.
+ */
+ const focusTabbable = ( ignoreInnerBlocks ) => {
+ // Focus is captured by the wrapper node, so while focus transition
+ // should only consider tabbables within editable display, since it
+ // may be the wrapper itself or a side control which triggered the
+ // focus event, don't unnecessary transition to an inner tabbable.
+ if ( wrapper.current.contains( document.activeElement ) ) {
+ return;
+ }
+
+ // Find all tabbables within node.
+ const textInputs = focus.tabbable
+ .find( wrapper.current )
+ .filter( isTextField )
+ // Exclude inner blocks
+ .filter( ( node ) => ! ignoreInnerBlocks || isInsideRootBlock( wrapper.current, node ) );
+
+ // If reversed (e.g. merge via backspace), use the last in the set of
+ // tabbables.
+ const isReverse = -1 === initialPosition;
+ const target = ( isReverse ? last : first )( textInputs ) || wrapper.current;
+
+ placeCaretAtHorizontalEdge( target, isReverse );
+ };
+
+ // Focus the selected block's wrapper or inner input on mount and update
+ const isMounting = useRef( true );
+
+ useEffect( () => {
+ if ( ! isMultiSelecting && ! isNavigationMode && isSelected ) {
+ focusTabbable( ! isMounting.current );
+ }
+
+ isMounting.current = false;
+ }, [
+ isSelected,
+ isMultiSelecting,
+ isNavigationMode,
+ ] );
+
+ // Block Reordering animation
+ const animationStyle = useMovingAnimation(
+ wrapper,
+ isSelected || isPartOfMultiSelection,
+ isSelected || isFirstMultiSelected,
+ enableAnimation,
+ index
+ );
+
+ /**
+ * Interprets keydown event intent to remove or insert after block if key
+ * event occurs on wrapper node. This can occur when the block has no text
+ * fields of its own, particularly after initial insertion, to allow for
+ * easy deletion and continuous writing flow to add additional content.
+ *
+ * @param {KeyboardEvent} event Keydown event.
+ */
+ const onKeyDown = ( event ) => {
+ const { keyCode, target } = event;
+
+ if ( props.onKeyDown ) {
+ props.onKeyDown( event );
+ }
+
+ if ( keyCode !== ENTER && keyCode !== BACKSPACE && keyCode !== DELETE ) {
+ return;
+ }
+
+ if ( target !== wrapper.current || isTextField( target ) ) {
+ return;
+ }
+
+ event.preventDefault();
+
+ if ( keyCode === ENTER ) {
+ insertDefaultBlock( {}, rootClientId, index + 1 );
+ } else {
+ removeBlock( clientId );
+ }
+ };
+
+ const onMouseLeave = ( { which, buttons } ) => {
+ // The primary button must be pressed to initiate selection. Fall back
+ // to `which` if the standard `buttons` property is falsy. There are
+ // cases where Firefox might always set `buttons` to `0`.
+ // See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
+ // See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which
+ if ( ( buttons || which ) === 1 ) {
+ onSelectionStart( clientId );
+ }
+ };
+
+ const htmlSuffix = mode === 'html' && ! __unstableIsHtml ? '-visual' : '';
+ const blockElementId = `block-${ clientId }${ htmlSuffix }`;
+ const Animated = animated[ tagName ];
+
+ return (
+
+ { children }
+
+ );
+} );
+
+const elements = [ 'p', 'div' ];
+
+const ExtendedBlockComponent = elements.reduce( ( acc, element ) => {
+ acc[ element ] = forwardRef( ( props, ref ) => {
+ return ;
+ } );
+ return acc;
+}, BlockComponent );
+
+export const Block = ExtendedBlockComponent;
diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js
index 3fb84e824f1082..18818d8b8edd8e 100644
--- a/packages/block-editor/src/components/block-list/block.js
+++ b/packages/block-editor/src/components/block-list/block.js
@@ -2,30 +2,20 @@
* External dependencies
*/
import classnames from 'classnames';
-import { first, last, omit } from 'lodash';
-import { animated } from 'react-spring/web.cjs';
/**
* WordPress dependencies
*/
-import {
- useRef,
- useEffect,
- useLayoutEffect,
- useState,
- useContext,
-} from '@wordpress/element';
-import { focus, isTextField, placeCaretAtHorizontalEdge } from '@wordpress/dom';
-import { BACKSPACE, DELETE, ENTER } from '@wordpress/keycodes';
+import { useState, createContext, useMemo } from '@wordpress/element';
import {
getBlockType,
getSaveElement,
isReusableBlock,
isUnmodifiedDefaultBlock,
getUnregisteredTypeHandlerName,
+ hasBlockSupport,
} from '@wordpress/blocks';
import { withFilters } from '@wordpress/components';
-import { __, sprintf } from '@wordpress/i18n';
import { withDispatch, withSelect, useSelect } from '@wordpress/data';
import { withViewportMatch } from '@wordpress/viewport';
import { compose, pure, ifCondition } from '@wordpress/compose';
@@ -38,15 +28,16 @@ import BlockInvalidWarning from './block-invalid-warning';
import BlockCrashWarning from './block-crash-warning';
import BlockCrashBoundary from './block-crash-boundary';
import BlockHtml from './block-html';
-import { isInsideRootBlock } from '../../utils/dom';
-import useMovingAnimation from './moving-animation';
-import { Context, BlockNodes } from './root-container';
+import { Block } from './block-wrapper';
+
+export const BlockContext = createContext();
function BlockListBlock( {
mode,
isFocusMode,
isLocked,
clientId,
+ rootClientId,
isSelected,
isMultiSelected,
isPartOfMultiSelection,
@@ -60,23 +51,18 @@ function BlockListBlock( {
name,
isValid,
attributes,
- initialPosition,
wrapperProps,
setAttributes,
onReplace,
onInsertBlocksAfter,
onMerge,
- onRemove,
- onInsertDefaultBlockAfter,
toggleSelection,
- animateOnChange,
+ index,
enableAnimation,
isNavigationMode,
isMultiSelecting,
hasSelectedUI = true,
} ) {
- const onSelectionStart = useContext( Context );
- const [ , setBlockNodes ] = useContext( BlockNodes );
// In addition to withSelect, we should favor using useSelect in this component going forward
// to avoid leaking new props to the public API (editor.BlockListBlock filter)
const { isDraggingBlocks } = useSelect( ( select ) => {
@@ -85,135 +71,16 @@ function BlockListBlock( {
};
}, [] );
- // Reference of the wrapper
- const wrapper = useRef( null );
-
- // Provide the selected node, or the first and last nodes of a multi-
- // selection, so it can be used to position the contextual block toolbar.
- // We only provide what is necessary, and remove the nodes again when they
- // are no longer selected.
- useLayoutEffect( () => {
- if ( isSelected || isFirstMultiSelected || isLastMultiSelected ) {
- const node = wrapper.current;
- setBlockNodes( ( nodes ) => ( { ...nodes, [ clientId ]: node } ) );
- return () => {
- setBlockNodes( ( nodes ) => omit( nodes, clientId ) );
- };
- }
- }, [ isSelected, isFirstMultiSelected, isLastMultiSelected ] );
-
// Handling the error state
const [ hasError, setErrorState ] = useState( false );
const onBlockError = () => setErrorState( true );
const blockType = getBlockType( name );
- // translators: %s: Type of block (i.e. Text, Image etc)
- const blockLabel = sprintf( __( 'Block: %s' ), blockType.title );
-
- // Handing the focus of the block on creation and update
-
- /**
- * When a block becomes selected, transition focus to an inner tabbable.
- *
- * @param {boolean} ignoreInnerBlocks Should not focus inner blocks.
- */
- const focusTabbable = ( ignoreInnerBlocks ) => {
- // Focus is captured by the wrapper node, so while focus transition
- // should only consider tabbables within editable display, since it
- // may be the wrapper itself or a side control which triggered the
- // focus event, don't unnecessary transition to an inner tabbable.
- if ( wrapper.current.contains( document.activeElement ) ) {
- return;
- }
-
- // Find all tabbables within node.
- const textInputs = focus.tabbable
- .find( wrapper.current )
- .filter( isTextField )
- // Exclude inner blocks
- .filter(
- ( node ) =>
- ! ignoreInnerBlocks ||
- isInsideRootBlock( wrapper.current, node )
- );
-
- // If reversed (e.g. merge via backspace), use the last in the set of
- // tabbables.
- const isReverse = -1 === initialPosition;
- const target = ( isReverse ? last : first )( textInputs );
-
- if ( ! target ) {
- wrapper.current.focus();
- return;
- }
-
- placeCaretAtHorizontalEdge( target, isReverse );
- };
-
- // Focus the selected block's wrapper or inner input on mount and update
- const isMounting = useRef( true );
-
- useEffect( () => {
- if ( ! isMultiSelecting && ! isNavigationMode && isSelected ) {
- focusTabbable( ! isMounting.current );
- }
-
- isMounting.current = false;
- }, [ isSelected, isMultiSelecting, isNavigationMode ] );
-
- // Block Reordering animation
- const animationStyle = useMovingAnimation(
- wrapper,
- isSelected || isPartOfMultiSelection,
- isSelected || isFirstMultiSelected,
- enableAnimation,
- animateOnChange
+ const lightBlockWrapper = hasBlockSupport(
+ blockType,
+ 'lightBlockWrapper',
+ false
);
-
- // Other event handlers
-
- /**
- * Interprets keydown event intent to remove or insert after block if key
- * event occurs on wrapper node. This can occur when the block has no text
- * fields of its own, particularly after initial insertion, to allow for
- * easy deletion and continuous writing flow to add additional content.
- *
- * @param {KeyboardEvent} event Keydown event.
- */
- const onKeyDown = ( event ) => {
- const { keyCode, target } = event;
-
- switch ( keyCode ) {
- case ENTER:
- if ( target === wrapper.current ) {
- // Insert default block after current block if enter and event
- // not already handled by descendant.
- onInsertDefaultBlockAfter();
- event.preventDefault();
- }
- break;
- case BACKSPACE:
- case DELETE:
- if ( target === wrapper.current ) {
- // Remove block on backspace.
- onRemove( clientId );
- event.preventDefault();
- }
- break;
- }
- };
-
- const onMouseLeave = ( { which, buttons } ) => {
- // The primary button must be pressed to initiate selection. Fall back
- // to `which` if the standard `buttons` property is falsy. There are
- // cases where Firefox might always set `buttons` to `0`.
- // See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
- // See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which
- if ( ( buttons || which ) === 1 ) {
- onSelectionStart( clientId );
- }
- };
-
const isUnregisteredBlock = name === getUnregisteredTypeHandlerName();
// If the block is selected and we're typing the block should not appear.
@@ -230,7 +97,7 @@ function BlockListBlock( {
isDraggingBlocks && ( isSelected || isPartOfMultiSelection );
// Determine whether the block has props to apply to the wrapper.
- if ( blockType.getEditWrapperProps ) {
+ if ( ! lightBlockWrapper && blockType.getEditWrapperProps ) {
wrapperProps = {
...wrapperProps,
...blockType.getEditWrapperProps( attributes ),
@@ -260,8 +127,6 @@ function BlockListBlock( {
className
);
- const blockElementId = `block-${ clientId }`;
-
// We wrap the BlockEdit component in a div that hides it when editing in
// HTML mode. This allows us to render all of the ancillary pieces
// (InspectorControls, etc.) which are inside `BlockEdit` but not
@@ -292,47 +157,59 @@ function BlockListBlock( {
blockEdit =
{ blockEdit }
;
}
+ const value = {
+ clientId,
+ rootClientId,
+ isSelected,
+ isFirstMultiSelected,
+ isLastMultiSelected,
+ isMultiSelecting,
+ isNavigationMode,
+ isPartOfMultiSelection,
+ enableAnimation,
+ index,
+ className: wrapperClassName,
+ isLocked,
+ name,
+ mode,
+ blockTitle: blockType.title,
+ };
+ const memoizedValue = useMemo( () => value, Object.values( value ) );
+
return (
-
+
- { isValid && blockEdit }
- { isValid && mode === 'html' && (
-
+ { isValid && lightBlockWrapper && (
+ <>
+ { blockEdit }
+ { mode === 'html' && (
+
+
+
+ ) }
+ >
+ ) }
+ { isValid && ! lightBlockWrapper && (
+
+ { blockEdit }
+ { mode === 'html' && (
+
+ ) }
+
+ ) }
+ { ! isValid && (
+
+
+ { getSaveElement( blockType, attributes ) }
+
) }
- { ! isValid && [
- ,
-
- { getSaveElement( blockType, attributes ) }
-
,
- ] }
- { !! hasError && }
-
+ { !! hasError && (
+
+
+
+ ) }
+
);
}
@@ -347,7 +224,6 @@ const applyWithSelect = withSelect(
isTyping,
getBlockMode,
isSelectionEnabled,
- getSelectedBlocksInitialCaretPosition,
getSettings,
hasSelectedInnerBlock,
getTemplateLock,
@@ -388,9 +264,6 @@ const applyWithSelect = withSelect(
mode: getBlockMode( clientId ),
isSelectionEnabled: isSelectionEnabled(),
- initialPosition: isSelected
- ? getSelectedBlocksInitialCaretPosition()
- : null,
isEmptyDefaultBlock:
name && isUnmodifiedDefaultBlock( { name, attributes } ),
isLocked: !! templateLock,
@@ -416,8 +289,6 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => {
const {
updateBlockAttributes,
insertBlocks,
- insertDefaultBlock,
- removeBlock,
mergeBlocks,
replaceBlocks,
toggleSelection,
@@ -433,21 +304,12 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => {
const { rootClientId } = ownProps;
insertBlocks( blocks, index, rootClientId );
},
- onInsertDefaultBlockAfter() {
- const { clientId, rootClientId } = ownProps;
- const { getBlockIndex } = select( 'core/block-editor' );
- const index = getBlockIndex( clientId, rootClientId );
- insertDefaultBlock( {}, rootClientId, index + 1 );
- },
onInsertBlocksAfter( blocks ) {
const { clientId, rootClientId } = ownProps;
const { getBlockIndex } = select( 'core/block-editor' );
const index = getBlockIndex( clientId, rootClientId );
insertBlocks( blocks, index + 1, rootClientId );
},
- onRemove( clientId ) {
- removeBlock( clientId );
- },
onMerge( forward ) {
const { clientId } = ownProps;
const { getPreviousBlockClientId, getNextBlockClientId } = select(
diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js
index 8bf433d083fe45..02fc6d6806fb04 100644
--- a/packages/block-editor/src/components/block-list/index.js
+++ b/packages/block-editor/src/components/block-list/index.js
@@ -107,7 +107,7 @@ function BlockList( {
// This prop is explicitely computed and passed down
// to avoid being impacted by the async mode
// otherwise there might be a small delay to trigger the animation.
- animateOnChange={ index }
+ index={ index }
enableAnimation={ enableAnimation }
hasSelectedUI={
__experimentalUIParts.hasSelectedUI
diff --git a/packages/block-editor/src/components/block-list/insertion-point.js b/packages/block-editor/src/components/block-list/insertion-point.js
index 1ce81ac1199a24..ec159de131e4e2 100644
--- a/packages/block-editor/src/components/block-list/insertion-point.js
+++ b/packages/block-editor/src/components/block-list/insertion-point.js
@@ -127,12 +127,10 @@ export default function InsertionPoint( {
const isReverse = clientY < targetRect.top + targetRect.height / 2;
const blockNode = getBlockDOMNode( inserterClientId );
const container = isReverse ? containerRef.current : blockNode;
- const closest = getClosestTabbable( blockNode, true, container );
+ const closest = getClosestTabbable( blockNode, true, container ) || blockNode;
const rect = new window.DOMRect( clientX, clientY, 0, 16 );
- if ( closest ) {
- placeCaretAtVerticalEdge( closest, isReverse, rect, false );
- }
+ placeCaretAtVerticalEdge( closest, isReverse, rect, false );
}
// Hide the inserter above the selected block and during multi-selection.
diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js
index 07cff82c8e8b32..1a7c7fff816b74 100644
--- a/packages/block-editor/src/components/index.js
+++ b/packages/block-editor/src/components/index.js
@@ -61,6 +61,7 @@ export { default as __experimentalBlockSettingsMenuPluginsExtension } from './bl
export { default as __experimentalInserterMenuExtension } from './inserter-menu-extension';
export { default as BlockInspector } from './block-inspector';
export { default as BlockList } from './block-list';
+export { Block as __experimentalBlock } from './block-list/block-wrapper';
export { default as BlockMover } from './block-mover';
export { default as BlockPreview } from './block-preview';
export { default as BlockSelectionClearer } from './block-selection-clearer';
diff --git a/packages/block-editor/src/components/observe-typing/index.js b/packages/block-editor/src/components/observe-typing/index.js
index ae7cddfeb80aec..a4f948c13c3575 100644
--- a/packages/block-editor/src/components/observe-typing/index.js
+++ b/packages/block-editor/src/components/observe-typing/index.js
@@ -17,6 +17,7 @@ import {
ENTER,
BACKSPACE,
ESCAPE,
+ TAB,
} from '@wordpress/keycodes';
import { withSafeTimeout } from '@wordpress/compose';
@@ -111,7 +112,10 @@ function ObserveTyping( { children, setTimeout: setSafeTimeout } ) {
* @param {KeyboardEvent} event Keypress or keydown event to interpret.
*/
function stopTypingOnEscapeKey( event ) {
- if ( isTyping && event.keyCode === ESCAPE ) {
+ if (
+ isTyping &&
+ ( event.keyCode === ESCAPE || event.keyCode === TAB )
+ ) {
stopTyping();
}
}
diff --git a/packages/block-editor/src/utils/dom.js b/packages/block-editor/src/utils/dom.js
index 3fb25425678ab8..a12ffc276b16eb 100644
--- a/packages/block-editor/src/utils/dom.js
+++ b/packages/block-editor/src/utils/dom.js
@@ -91,7 +91,7 @@ export function getBlockClientId( node ) {
node = node.parentElement;
}
- const blockNode = node.closest( '.wp-block' );
+ const blockNode = node.closest( '.block-editor-block-list__block' );
if ( ! blockNode ) {
return;
diff --git a/packages/block-library/src/paragraph/edit.js b/packages/block-library/src/paragraph/edit.js
index 944a3952dd6162..5926fb276ff8d9 100644
--- a/packages/block-library/src/paragraph/edit.js
+++ b/packages/block-library/src/paragraph/edit.js
@@ -16,6 +16,7 @@ import {
RichText,
withFontSizes,
__experimentalUseColors,
+ __experimentalBlock as Block,
} from '@wordpress/block-editor';
import { createBlock } from '@wordpress/blocks';
import { compose } from '@wordpress/compose';
@@ -150,7 +151,7 @@ function ParagraphBlock( {
{
await insertBlock( blockTitle );
expect(
await getInnerHTML(
- `[data-type="${ blockName }"] [data-type="core/paragraph"] p`
+ `[data-type="${ blockName }"] [data-type="core/paragraph"]`
)
).toEqual( blockTitle );
} );
diff --git a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js
index 843131dbe5070a..db4da0574ebc12 100644
--- a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js
+++ b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js
@@ -72,7 +72,7 @@ describe( 'cpt locking', () => {
it( 'should not error when deleting the cotents of a paragraph', async () => {
await page.click(
- '.block-editor-block-list__block[data-type="core/paragraph"] p'
+ '.block-editor-block-list__block[data-type="core/paragraph"]'
);
const textToType = 'Paragraph';
await page.keyboard.type( 'Paragraph' );
diff --git a/packages/e2e-tests/specs/editor/plugins/hooks-api.test.js b/packages/e2e-tests/specs/editor/plugins/hooks-api.test.js
index 07f018c528cf24..75d240ffd3f322 100644
--- a/packages/e2e-tests/specs/editor/plugins/hooks-api.test.js
+++ b/packages/e2e-tests/specs/editor/plugins/hooks-api.test.js
@@ -34,7 +34,7 @@ describe( 'Using Hooks API', () => {
await clickBlockAppender();
await page.keyboard.type( 'First paragraph' );
const paragraphContent = await page.$eval(
- 'div[data-type="core/paragraph"] p',
+ 'div[data-type="core/paragraph"]',
( element ) => element.textContent
);
expect( paragraphContent ).toEqual( 'First paragraph' );
diff --git a/packages/e2e-tests/specs/editor/various/block-mover.test.js b/packages/e2e-tests/specs/editor/various/block-mover.test.js
index 09f6ba41a2a82a..3b936f212aba0b 100644
--- a/packages/e2e-tests/specs/editor/various/block-mover.test.js
+++ b/packages/e2e-tests/specs/editor/various/block-mover.test.js
@@ -18,6 +18,10 @@ describe( 'block mover', () => {
// Select a block so the block mover is rendered.
await page.focus( '.block-editor-block-list__block' );
+ // Move the mouse to show the block toolbar
+ await page.mouse.move( 0, 0 );
+ await page.mouse.move( 10, 10 );
+
const blockMover = await page.$$( '.block-editor-block-mover' );
// There should be a block mover.
expect( blockMover ).toHaveLength( 1 );
@@ -31,6 +35,10 @@ describe( 'block mover', () => {
// Select a block so the block mover has the possibility of being rendered.
await page.focus( '.block-editor-block-list__block' );
+ // Move the mouse to show the block toolbar
+ await page.mouse.move( 0, 0 );
+ await page.mouse.move( 10, 10 );
+
// Ensure no block mover exists when only one block exists on the page.
const blockMover = await page.$$( '.block-editor-block-mover' );
expect( blockMover ).toHaveLength( 0 );
diff --git a/packages/e2e-tests/specs/editor/various/editor-modes.test.js b/packages/e2e-tests/specs/editor/various/editor-modes.test.js
index f6f6a9ae10997b..15d767cd6cc2c9 100644
--- a/packages/e2e-tests/specs/editor/various/editor-modes.test.js
+++ b/packages/e2e-tests/specs/editor/various/editor-modes.test.js
@@ -18,7 +18,7 @@ describe( 'Editing modes (visual/HTML)', () => {
it( 'should switch between visual and HTML modes', async () => {
// This block should be in "visual" mode by default.
let visualBlock = await page.$$(
- '.block-editor-block-list__layout .block-editor-block-list__block .rich-text'
+ '.block-editor-block-list__layout .block-editor-block-list__block.rich-text'
);
expect( visualBlock ).toHaveLength( 1 );
@@ -52,7 +52,7 @@ describe( 'Editing modes (visual/HTML)', () => {
// This block should be in "visual" mode by default.
visualBlock = await page.$$(
- '.block-editor-block-list__layout .block-editor-block-list__block .rich-text'
+ '.block-editor-block-list__layout .block-editor-block-list__block.rich-text'
);
expect( visualBlock ).toHaveLength( 1 );
} );
diff --git a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js
index 815528f8c0e7ba..7226e0750e5726 100644
--- a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js
+++ b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js
@@ -31,9 +31,6 @@ const tabThroughParagraphBlock = async ( paragraphText ) => {
await tabThroughBlockMoverControl();
await tabThroughBlockToolbar();
- await page.keyboard.press( 'Tab' );
- await expect( await getActiveLabel() ).toBe( 'Block: Paragraph' );
-
await page.keyboard.press( 'Tab' );
await expect( await getActiveLabel() ).toBe( 'Paragraph block' );
await expect(
diff --git a/packages/e2e-tests/specs/editor/various/preview.test.js b/packages/e2e-tests/specs/editor/various/preview.test.js
index 3a495a1189dfdc..e973c1b44f87d6 100644
--- a/packages/e2e-tests/specs/editor/various/preview.test.js
+++ b/packages/e2e-tests/specs/editor/various/preview.test.js
@@ -14,7 +14,6 @@ import {
publishPost,
saveDraft,
clickOnMoreMenuItem,
- pressKeyWithModifier,
} from '@wordpress/e2e-test-utils';
/** @typedef {import('puppeteer').Page} Page */
@@ -278,13 +277,13 @@ describe( 'Preview with Custom Fields enabled', () => {
// Return to editor and modify the title and content.
await editorPage.bringToFront();
await editorPage.click( '.editor-post-title__input' );
- await pressKeyWithModifier( 'primary', 'a' );
- await editorPage.keyboard.press( 'Delete' );
- await editorPage.keyboard.type( 'title 2' );
+ await editorPage.keyboard.press( 'End' );
+ await editorPage.keyboard.press( 'Backspace' );
+ await editorPage.keyboard.type( '2' );
await editorPage.keyboard.press( 'Tab' );
- await pressKeyWithModifier( 'primary', 'a' );
- await editorPage.keyboard.press( 'Delete' );
- await editorPage.keyboard.type( 'content 2' );
+ await editorPage.keyboard.press( 'End' );
+ await editorPage.keyboard.press( 'Backspace' );
+ await editorPage.keyboard.type( '2' );
// Open the preview page.
await waitForPreviewNavigation( previewPage );
diff --git a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js
index b453bbc0aeeeed..794e8018691f61 100644
--- a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js
+++ b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js
@@ -181,7 +181,7 @@ describe( 'Reusable blocks', () => {
// Check that its content is up to date
const text = await page.$eval(
- '.block-editor-block-list__block[data-type="core/paragraph"] p',
+ '.block-editor-block-list__block[data-type="core/paragraph"]',
( element ) => element.innerText
);
expect( text ).toMatch( 'Oh! Hello there!' );
diff --git a/packages/e2e-tests/specs/editor/various/undo.test.js b/packages/e2e-tests/specs/editor/various/undo.test.js
index ed70af98bdaa2a..c37cba5b95f750 100644
--- a/packages/e2e-tests/specs/editor/various/undo.test.js
+++ b/packages/e2e-tests/specs/editor/various/undo.test.js
@@ -22,9 +22,16 @@ const getSelection = async () => {
return {};
}
- const editables = Array.from(
- selectedBlock.querySelectorAll( '[contenteditable]' )
- );
+ let editables;
+
+ if ( selectedBlock.getAttribute( 'contenteditable' ) ) {
+ editables = [ selectedBlock ];
+ } else {
+ editables = Array.from(
+ selectedBlock.querySelectorAll( '[contenteditable]' )
+ );
+ }
+
const editableIndex = editables.indexOf( document.activeElement );
const selection = window.getSelection();