diff --git a/packages/block-editor/src/components/block-patterns-list/index.js b/packages/block-editor/src/components/block-patterns-list/index.js
index bebeb1f44184cd..7bd74051c03b30 100644
--- a/packages/block-editor/src/components/block-patterns-list/index.js
+++ b/packages/block-editor/src/components/block-patterns-list/index.js
@@ -9,10 +9,8 @@ import classnames from 'classnames';
import { useState, forwardRef } from '@wordpress/element';
import {
VisuallyHidden,
- __unstableComposite as Composite,
- __unstableUseCompositeState as useCompositeState,
- __unstableCompositeItem as CompositeItem,
Tooltip,
+ privateApis as componentsPrivateApis,
__experimentalHStack as HStack,
} from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';
@@ -22,10 +20,17 @@ import { Icon, symbol } from '@wordpress/icons';
/**
* Internal dependencies
*/
+import { unlock } from '../../lock-unlock';
import BlockPreview from '../block-preview';
import InserterDraggableBlocks from '../inserter-draggable-blocks';
import BlockPatternsPaging from '../block-patterns-paging';
+const {
+ CompositeV2: Composite,
+ CompositeItemV2: CompositeItem,
+ useCompositeStoreV2: useCompositeStore,
+} = unlock( componentsPrivateApis );
+
const WithToolTip = ( { showTooltip, title, children } ) => {
if ( showTooltip ) {
return { children };
@@ -34,11 +39,11 @@ const WithToolTip = ( { showTooltip, title, children } ) => {
};
function BlockPattern( {
+ id,
isDraggable,
pattern,
onClick,
onHover,
- composite,
showTooltip,
} ) {
const [ isDragging, setIsDragging ] = useState( false );
@@ -54,6 +59,7 @@ function BlockPattern( {
>
{ ( { draggable, onDragStart, onDragEnd } ) => (
{
@@ -75,16 +81,7 @@ function BlockPattern( {
title={ pattern.title }
>
{
onClick( pattern, blocks );
onHover?.( null );
@@ -96,9 +93,24 @@ function BlockPattern( {
onHover?.( pattern );
} }
onMouseLeave={ () => onHover?.( null ) }
- aria-label={ pattern.title }
- aria-describedby={
- pattern.description ? descriptionId : undefined
+ render={
+
}
>
{
+ // This is necessary for if/when we filter the block patterns;
+ // we can potentially remove the currently active item, so we
+ // check to see if the active item is still present, and if not,
+ // reset the it to be the first available block.
+
+ const currentIds = items.map( ( item ) => item.id );
+ if ( ! currentIds.includes( activeId ) ) {
+ // We can't rely on the order of `currentIds` here, because
+ // `blockPatterns` may not be in the same order the blocks were
+ // originally registered in. So we filter the blocks by what's
+ // visible, and take the first item in that list instead.
+ const firstPattern = blockPatterns.filter( ( pattern ) =>
+ currentIds.includes( pattern.name )
+ )[ 0 ];
+ composite.setActiveId( firstPattern?.name );
+ }
+ },
+ } );
+
+ const activeId = composite.useState( 'activeId' );
+
return (
+ }
>
{ blockPatterns.map( ( pattern ) => {
const isShown = shownPatterns.includes( pattern );
return isShown ? (
) : (
@@ -185,4 +224,4 @@ function BlockPatternList(
);
}
-export default forwardRef( BlockPatternList );
+export default forwardRef( BlockPatternsList );
diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab.js b/packages/block-editor/src/components/inserter/block-patterns-tab.js
index 2dba8e08fa7476..56ef0fbec70dc0 100644
--- a/packages/block-editor/src/components/inserter/block-patterns-tab.js
+++ b/packages/block-editor/src/components/inserter/block-patterns-tab.js
@@ -28,7 +28,7 @@ import { speak } from '@wordpress/a11y';
* Internal dependencies
*/
import usePatternsState from './hooks/use-patterns-state';
-import BlockPatternList from '../block-patterns-list';
+import BlockPatternsList from '../block-patterns-list';
import PatternsExplorerModal from './block-patterns-explorer/explorer';
import MobileTabNavigation from './mobile-tab-navigation';
import usePatternsPaging from './hooks/use-patterns-paging';
@@ -332,7 +332,7 @@ export function BlockPatternsCategoryPanel( {
{ currentCategoryPatterns.length > 0 && (
- {
return await page.waitForXPath(
- `//*[@role='option' and contains(., '${ searchTerm }')]`
+ `//*[@class="block-editor-inserter__panel-content"]//*[self::button or self::*[@role="button"]][contains(., '${ searchTerm }')]`
);
};
waitForNoResults = async () => {
diff --git a/packages/e2e-tests/specs/editor/various/allowed-patterns.test.js b/packages/e2e-tests/specs/editor/various/allowed-patterns.test.js
index 449306f06d18d2..f0d1c2aa503e07 100644
--- a/packages/e2e-tests/specs/editor/various/allowed-patterns.test.js
+++ b/packages/e2e-tests/specs/editor/various/allowed-patterns.test.js
@@ -12,7 +12,7 @@ import {
const checkPatternExistence = async ( name, available = true ) => {
await searchForPattern( name );
const patternElement = await page.waitForXPath(
- `//div[@role = 'option']//div[contains(text(), '${ name }')]`,
+ `//div[@role = 'button']//div[contains(text(), '${ name }')]`,
{ timeout: 5000, visible: available, hidden: ! available }
);
const patternExists = !! patternElement;