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;