diff --git a/packages/block-editor/src/components/inserter/media-tab/media-tab.js b/packages/block-editor/src/components/inserter/media-tab/media-tab.js
index c5f462210fa4a4..2f3985aef569cb 100644
--- a/packages/block-editor/src/components/inserter/media-tab/media-tab.js
+++ b/packages/block-editor/src/components/inserter/media-tab/media-tab.js
@@ -16,6 +16,7 @@ import { useMediaCategories } from './hooks';
import { getBlockAndPreviewFromMedia } from './utils';
import MobileTabNavigation from '../mobile-tab-navigation';
import CategoryTabs from '../category-tabs';
+import InserterNoResults from '../no-results';
const ALLOWED_MEDIA_TYPES = [ 'image', 'video', 'audio' ];
@@ -48,6 +49,10 @@ function MediaTab( {
[ mediaCategories ]
);
+ if ( ! categories.length ) {
+ return
;
+ }
+
return (
<>
{ ! isMobile && (
diff --git a/packages/block-editor/src/components/inserter/menu.js b/packages/block-editor/src/components/inserter/menu.js
index 33737c16bcb50f..672f625465117f 100644
--- a/packages/block-editor/src/components/inserter/menu.js
+++ b/packages/block-editor/src/components/inserter/menu.js
@@ -11,28 +11,25 @@ import {
useState,
useCallback,
useMemo,
- useImperativeHandle,
useRef,
+ useLayoutEffect,
} from '@wordpress/element';
import { VisuallyHidden, SearchControl, Popover } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
-import { useSelect } from '@wordpress/data';
import { useDebouncedInput } from '@wordpress/compose';
/**
* Internal dependencies
*/
-import { unlock } from '../../lock-unlock';
import Tips from './tips';
import InserterPreviewPanel from './preview-panel';
import BlockTypesTab from './block-types-tab';
import BlockPatternsTab from './block-patterns-tab';
import { PatternCategoryPreviewPanel } from './block-patterns-tab/pattern-category-preview-panel';
-import { MediaTab, MediaCategoryPanel, useMediaCategories } from './media-tab';
+import { MediaTab, MediaCategoryPanel } from './media-tab';
import InserterSearchResults from './search-results';
import useInsertionPoint from './hooks/use-insertion-point';
import InserterTabs from './tabs';
-import { store as blockEditorStore } from '../../store';
import { useZoomOut } from '../../hooks/use-zoom-out';
const NOOP = () => {};
@@ -59,7 +56,7 @@ function InserterMenu(
const [ patternFilter, setPatternFilter ] = useState( 'all' );
const [ selectedMediaCategory, setSelectedMediaCategory ] =
useState( null );
- const [ selectedTab, setSelectedTab ] = useState( null );
+ const [ selectedTab, setSelectedTab ] = useState( 'blocks' );
const [ destinationRootClientId, onInsertBlocks, onToggleInsertionPoint ] =
useInsertionPoint( {
@@ -69,18 +66,6 @@ function InserterMenu(
insertionIndex: __experimentalInsertionIndex,
shouldFocusBlock,
} );
- const { showPatterns } = useSelect(
- ( select ) => {
- const { hasAllowedPatterns } = unlock( select( blockEditorStore ) );
- return {
- showPatterns: hasAllowedPatterns( destinationRootClientId ),
- };
- },
- [ destinationRootClientId ]
- );
-
- const mediaCategories = useMediaCategories( destinationRootClientId );
- const showMedia = mediaCategories.length > 0;
const onInsert = useCallback(
( blocks, meta, shouldForceFocusBlock ) => {
@@ -135,29 +120,86 @@ function InserterMenu(
! delayedFilterValue &&
selectedPatternCategory;
- const showMediaPanel =
- selectedTab === 'media' &&
- ! delayedFilterValue &&
- selectedMediaCategory;
+ const showMediaPanel = selectedTab === 'media' && selectedMediaCategory;
- const blocksTab = useMemo(
- () => (
+ const inserterSearch = useMemo( () => {
+ if ( selectedTab === 'media' ) {
+ return null;
+ }
+ return (
<>
-
- {
+ if ( hoveredItem ) {
+ setHoveredItem( null );
+ }
+ setFilterValue( value );
+ } }
+ value={ filterValue }
+ label={ __( 'Search for blocks and patterns' ) }
+ placeholder={ __( 'Search' ) }
+ />
+ { !! delayedFilterValue && (
+
-
- { showInserterHelpPanel && (
-
-
- { __( 'A tip for using the block editor' ) }
-
-
-
+ ) }
+ >
+ );
+ }, [
+ selectedTab,
+ hoveredItem,
+ setHoveredItem,
+ setFilterValue,
+ filterValue,
+ delayedFilterValue,
+ onSelect,
+ onHover,
+ onHoverPattern,
+ shouldFocusBlock,
+ clientId,
+ rootClientId,
+ __experimentalInsertionIndex,
+ isAppender,
+ ] );
+
+ const blocksTab = useMemo(
+ () => (
+ <>
+ { inserterSearch }
+ { ! delayedFilterValue && (
+ <>
+
+
+
+ { showInserterHelpPanel && (
+
+
+ { __( 'A tip for using the block editor' ) }
+
+
+
+ ) }
+ >
) }
>
),
@@ -167,28 +209,35 @@ function InserterMenu(
onHover,
showMostUsedBlocks,
showInserterHelpPanel,
+ inserterSearch,
+ delayedFilterValue,
]
);
const patternsTab = useMemo(
() => (
-
- { showPatternPanel && (
-
+ { inserterSearch }
+ { ! delayedFilterValue && (
+
+ onSelectCategory={ onClickPatternCategory }
+ selectedCategory={ selectedPatternCategory }
+ >
+ { showPatternPanel && (
+
+ ) }
+
) }
-
+ >
),
[
destinationRootClientId,
@@ -198,6 +247,8 @@ function InserterMenu(
patternFilter,
selectedPatternCategory,
showPatternPanel,
+ inserterSearch,
+ delayedFilterValue,
]
);
@@ -236,15 +287,6 @@ function InserterMenu(
[ blocksTab, mediaTab, patternsTab ]
);
- const searchRef = useRef();
- useImperativeHandle( ref, () => ( {
- focusSearch: () => {
- searchRef.current.focus();
- },
- } ) );
-
- const showAsTabs = ! delayedFilterValue && ( showPatterns || showMedia );
-
// When the pattern panel is showing, we want to use zoom out mode
useZoomOut( showPatternPanel );
@@ -256,62 +298,31 @@ function InserterMenu(
setSelectedTab( value );
};
+ // Focus first active tab, if any
+ const tabsRef = useRef();
+ useLayoutEffect( () => {
+ if ( tabsRef.current ) {
+ window.requestAnimationFrame( () => {
+ tabsRef.current
+ .querySelector( '[role="tab"][aria-selected="true"]' )
+ ?.focus();
+ } );
+ }
+ }, [] );
+
return (
-
-
{
- if ( hoveredItem ) {
- setHoveredItem( null );
- }
- setFilterValue( value );
- } }
- value={ filterValue }
- label={ __( 'Search for blocks and patterns' ) }
- placeholder={ __( 'Search' ) }
- ref={ searchRef }
+
+
- { !! delayedFilterValue && (
-
-
-
- ) }
- { showAsTabs && (
-
- ) }
- { ! delayedFilterValue && ! showAsTabs && (
-
- { blocksTab }
-
- ) }
{ showInserterHelpPanel && hoveredItem && (
+
{ tabs.map( ( tab ) => (
@@ -69,4 +61,4 @@ function InserterTabs( {
);
}
-export default InserterTabs;
+export default forwardRef( InserterTabs );
diff --git a/packages/edit-widgets/src/components/layout/style.scss b/packages/edit-widgets/src/components/layout/style.scss
index 1aed3d3eefc86f..a10665f7cafe7d 100644
--- a/packages/edit-widgets/src/components/layout/style.scss
+++ b/packages/edit-widgets/src/components/layout/style.scss
@@ -18,6 +18,10 @@
// Leave space for the close button
height: calc(100% - #{$button-size} - #{$grid-unit-10});
+ .block-editor-inserter__tab {
+ display: none;
+ }
+
@include break-medium() {
height: 100%;
}
diff --git a/packages/edit-widgets/src/components/secondary-sidebar/inserter-sidebar.js b/packages/edit-widgets/src/components/secondary-sidebar/inserter-sidebar.js
index b01481748ee887..2374b35ad2d699 100644
--- a/packages/edit-widgets/src/components/secondary-sidebar/inserter-sidebar.js
+++ b/packages/edit-widgets/src/components/secondary-sidebar/inserter-sidebar.js
@@ -8,7 +8,7 @@ import {
useViewportMatch,
__experimentalUseDialog as useDialog,
} from '@wordpress/compose';
-import { useCallback, useEffect, useRef } from '@wordpress/element';
+import { useCallback, useRef } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
@@ -31,13 +31,10 @@ export default function InserterSidebar() {
const TagName = ! isMobileViewport ? VisuallyHidden : 'div';
const [ inserterDialogRef, inserterDialogProps ] = useDialog( {
onClose: closeInserter,
- focusOnMount: null,
+ focusOnMount: true,
} );
const libraryRef = useRef();
- useEffect( () => {
- libraryRef.current.focusSearch();
- }, [] );
return (
setIsInserterOpened( false ),
- focusOnMount: null,
+ focusOnMount: true,
} );
const libraryRef = useRef();
- useEffect( () => {
- libraryRef.current.focusSearch();
- }, [] );
return (
{
} );
test( 'should insert a block pattern', async ( { page, editor } ) => {
- await page.click(
- 'role=region[name="Editor top bar"i] >> role=button[name="Toggle block inserter"i]'
- );
+ await page.getByLabel( 'Toggle block inserter' ).click();
+ await page.getByRole( 'tab', { name: 'Patterns' } ).click();
await page.fill(
'role=region[name="Block Library"i] >> role=searchbox[name="Search for blocks and patterns"i]',
'Social links with a shared background color'
diff --git a/test/e2e/specs/editor/various/inserting-blocks.spec.js b/test/e2e/specs/editor/various/inserting-blocks.spec.js
index 6e19fd31a71b05..c277b056a323ce 100644
--- a/test/e2e/specs/editor/various/inserting-blocks.spec.js
+++ b/test/e2e/specs/editor/various/inserting-blocks.spec.js
@@ -598,6 +598,7 @@ test.describe( 'Inserting blocks (@firefox, @webkit)', () => {
.getByRole( 'searchbox', {
name: 'Search for blocks and patterns',
} )
+ .first()
.fill( 'Verse' );
await page.getByRole( 'button', { name: 'Browse All' } ).click();
@@ -607,9 +608,10 @@ test.describe( 'Inserting blocks (@firefox, @webkit)', () => {
.getByRole( 'searchbox', {
name: 'Search for blocks and patterns',
} )
+ .first()
).toHaveValue( 'Verse' );
await expect(
- page.getByRole( 'listbox', { name: 'Blocks' } )
+ page.getByRole( 'listbox', { name: 'Blocks' } ).first()
).toHaveCount( 1 );
} );
diff --git a/test/performance/specs/post-editor.spec.js b/test/performance/specs/post-editor.spec.js
index c8010c79b15508..b82d3a31d4cb69 100644
--- a/test/performance/specs/post-editor.spec.js
+++ b/test/performance/specs/post-editor.spec.js
@@ -418,9 +418,11 @@ test.describe( 'Post Editor Performance', () => {
const globalInserterToggle = page.getByRole( 'button', {
name: 'Toggle block inserter',
} );
-
// Open Inserter.
await globalInserterToggle.click();
+
+ await page.getByRole( 'searchbox' ).click();
+
await perfUtils.expectExpandedState( globalInserterToggle, 'true' );
const samples = 10;