-
+
);
// Disable reason (no-autofocus): The inserter menu is a modal display, not one which
@@ -118,32 +119,24 @@ function InserterMenu( {
onKeyDown={ onKeyDown }
>
-
- { showPatterns && (
-
- { ( tab ) => {
- if ( tab.name === 'blocks' ) {
- return blocksTab;
- }
- return patternsTab;
- } }
-
- ) }
- { ! showPatterns && blocksTab }
+ { /* the following div is necessary to fix the sticky position of the search form */ }
+
+
+ { showPatterns && (
+
+ { ( tab ) => {
+ if ( tab.name === 'blocks' ) {
+ return blocksTab;
+ }
+ return patternsTab;
+ } }
+
+ ) }
+ { ! showPatterns && blocksTab }
+
{ showInserterHelpPanel && hoveredItem && (
diff --git a/packages/block-editor/src/components/inserter/quick-inserter.js b/packages/block-editor/src/components/inserter/quick-inserter.js
new file mode 100644
index 00000000000000..bd0489e1812b29
--- /dev/null
+++ b/packages/block-editor/src/components/inserter/quick-inserter.js
@@ -0,0 +1,218 @@
+/**
+ * WordPress dependencies
+ */
+import { useState, useMemo, useEffect } from '@wordpress/element';
+import { __, _n, sprintf } from '@wordpress/i18n';
+import {
+ VisuallyHidden,
+ Button,
+ withSpokenMessages,
+} from '@wordpress/components';
+import { useSelect } from '@wordpress/data';
+import { LEFT, RIGHT, UP, DOWN, BACKSPACE, ENTER } from '@wordpress/keycodes';
+
+/**
+ * Internal dependencies
+ */
+import BlockTypesList from '../block-types-list';
+import BlockPatternsList from '../block-patterns-list';
+import InserterSearchForm from './search-form';
+import InserterPanel from './panel';
+import InserterNoResults from './no-results';
+import useInsertionPoint from './hooks/use-insertion-point';
+import usePatternsState from './hooks/use-patterns-state';
+import useBlockTypesState from './hooks/use-block-types-state';
+import { searchBlockItems, searchItems } from './search-items';
+
+const SEARCH_THRESHOLD = 6;
+const SHOWN_BLOCK_TYPES = 6;
+const SHOWN_BLOCK_PATTERNS = 2;
+
+const preventArrowKeysPropagation = ( event ) => {
+ if (
+ [ LEFT, DOWN, RIGHT, UP, BACKSPACE, ENTER ].includes( event.keyCode )
+ ) {
+ // Stop the key event from propagating up to ObserveTyping.startTypingInTextField.
+ event.stopPropagation();
+ }
+};
+const stopKeyPropagation = ( event ) => event.stopPropagation();
+
+function QuickInserterList( {
+ blockTypes,
+ blockPatterns,
+ onSelectBlockType,
+ onSelectBlockPattern,
+ onHover,
+} ) {
+ const shownBlockTypes = useMemo(
+ () => blockTypes.slice( 0, SHOWN_BLOCK_TYPES ),
+ [ blockTypes ]
+ );
+ const shownBlockPatterns = useMemo(
+ () => blockPatterns.slice( 0, SHOWN_BLOCK_PATTERNS ),
+ [ blockTypes ]
+ );
+ return (
+
+ { ! shownBlockTypes.length && ! shownBlockPatterns.length && (
+
+ ) }
+
+ { !! shownBlockTypes.length && (
+
{ __( 'Blocks' ) }
+ }
+ >
+
+
+ ) }
+
+ { !! shownBlockTypes.length && !! shownBlockPatterns.length && (
+
+ ) }
+
+ { !! shownBlockPatterns.length && (
+
{ __( 'Blocks' ) }
+ }
+ >
+
+
+
+
+ ) }
+
+ );
+}
+
+function QuickInserter( {
+ rootClientId,
+ clientId,
+ isAppender,
+ selectBlockOnInsert,
+ debouncedSpeak,
+} ) {
+ const [ filterValue, setFilterValue ] = useState( '' );
+ const [
+ destinationRootClientId,
+ onInsertBlocks,
+ onToggleInsertionPoint,
+ ] = useInsertionPoint( {
+ rootClientId,
+ clientId,
+ isAppender,
+ selectBlockOnInsert,
+ } );
+ const [
+ blockTypes,
+ blockTypeCategories,
+ blockTypeCollections,
+ onSelectBlockType,
+ ] = useBlockTypesState( destinationRootClientId, onInsertBlocks );
+ const [ patterns, , onSelectBlockPattern ] = usePatternsState(
+ onInsertBlocks
+ );
+ const showPatterns =
+ ! destinationRootClientId && patterns.length && !! filterValue;
+ const showSearch =
+ ( showPatterns && patterns.length > SEARCH_THRESHOLD ) ||
+ blockTypes.length > SEARCH_THRESHOLD;
+
+ const filteredBlockTypes = useMemo( () => {
+ return searchBlockItems(
+ blockTypes,
+ blockTypeCategories,
+ blockTypeCollections,
+ filterValue
+ );
+ }, [ filterValue, blockTypes, blockTypeCategories, blockTypeCollections ] );
+
+ const filteredBlockPatterns = useMemo(
+ () => searchItems( patterns, filterValue ),
+ [ filterValue, patterns ]
+ );
+
+ const setInsererIsOpened = useSelect(
+ ( select ) =>
+ select( 'core/block-editor' ).getSettings()
+ .__experimentalSetIsInserterOpened,
+ []
+ );
+
+ useEffect( () => {
+ if ( setInsererIsOpened ) {
+ setInsererIsOpened( false );
+ }
+ }, [ setInsererIsOpened ] );
+
+ // Announce search results on change
+ useEffect( () => {
+ if ( ! filterValue ) {
+ return;
+ }
+ const count = filteredBlockTypes.length + filteredBlockPatterns.length;
+ const resultsFoundMessage = sprintf(
+ /* translators: %d: number of results. */
+ _n( '%d result found.', '%d results found.', count ),
+ count
+ );
+ debouncedSpeak( resultsFoundMessage );
+ }, [ filterValue, debouncedSpeak ] );
+
+ // Disable reason (no-autofocus): The inserter menu is a modal display, not one which
+ // is always visible, and one which already incurs this behavior of autoFocus via
+ // Popover's focusOnMount.
+ // Disable reason (no-static-element-interactions): Navigational key-presses within
+ // the menu are prevented from triggering WritingFlow and ObserveTyping interactions.
+ /* eslint-disable jsx-a11y/no-autofocus, jsx-a11y/no-static-element-interactions */
+ return (
+
+ { showSearch && (
+ {
+ setFilterValue( value );
+ } }
+ />
+ ) }
+
+
+
+ { setInsererIsOpened && (
+ setInsererIsOpened( true ) }
+ aria-label={ __(
+ 'Browse all. This will open the main inserter panel in the editor toolbar.'
+ ) }
+ >
+ { __( 'Browse all' ) }
+
+ ) }
+
+ );
+ /* eslint-enable jsx-a11y/no-autofocus, jsx-a11y/no-static-element-interactions */
+}
+
+export default withSpokenMessages( QuickInserter );
diff --git a/packages/block-editor/src/components/inserter/search-form.js b/packages/block-editor/src/components/inserter/search-form.js
index 6c1f140a98ac7f..bae5092d95ecac 100644
--- a/packages/block-editor/src/components/inserter/search-form.js
+++ b/packages/block-editor/src/components/inserter/search-form.js
@@ -3,11 +3,13 @@
*/
import { useInstanceId } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
-import { VisuallyHidden } from '@wordpress/components';
-import { Icon, search } from '@wordpress/icons';
+import { VisuallyHidden, Button } from '@wordpress/components';
+import { Icon, search, closeSmall } from '@wordpress/icons';
+import { useRef } from '@wordpress/element';
-function InserterSearchForm( { onChange } ) {
+function InserterSearchForm( { onChange, value } ) {
const instanceId = useInstanceId( InserterSearchForm );
+ const searchInput = useRef();
// Disable reason (no-autofocus): The inserter menu is a modal display, not one which
// is always visible, and one which already incurs this behavior of autoFocus via
@@ -22,6 +24,7 @@ function InserterSearchForm( { onChange } ) {
{ __( 'Search for a block' ) }
onChange( event.target.value ) }
autoComplete="off"
+ value={ value || '' }
/>
-
+
+ { !! value && (
+ {
+ onChange( '' );
+ searchInput.current.focus();
+ } }
+ />
+ ) }
+ { ! value && }
+
);
/* eslint-enable jsx-a11y/no-autofocus */
diff --git a/packages/block-editor/src/components/inserter/style.scss b/packages/block-editor/src/components/inserter/style.scss
index 65a9816e262273..ed456aaf782bf9 100644
--- a/packages/block-editor/src/components/inserter/style.scss
+++ b/packages/block-editor/src/components/inserter/style.scss
@@ -101,13 +101,27 @@ $block-inserter-tabs-height: 44px;
&::placeholder {
color: $dark-gray-400;
}
+
+ &::-webkit-search-decoration,
+ &::-webkit-search-cancel-button,
+ &::-webkit-search-results-button,
+ &::-webkit-search-results-decoration {
+ -webkit-appearance: none;
+ }
}
}
.block-editor-inserter__search-icon {
position: absolute;
- top: $grid-unit-20 + ($grid-unit-60 - $icon-size) / 2;
- right: $grid-unit-20 + ($grid-unit-60 - $icon-size) / 2;
+ top: 0;
+ right: $grid-unit-10 + ($grid-unit-60 - $icon-size) / 2;
+ bottom: 0;
+ display: flex;
+ align-items: center;
+
+ > svg {
+ margin: $grid-unit-10;
+ }
}
.block-editor-inserter__tabs {
@@ -248,32 +262,49 @@ $block-inserter-tabs-height: 44px;
flex-shrink: 0;
}
-.block-editor-inserter__patterns-item {
- border-radius: $radius-block-ui;
- cursor: pointer;
- margin-top: $grid-unit-20;
- transition: all 0.05s ease-in-out;
- position: relative;
- border: $border-width solid transparent;
+.block-editor-inserter__quick-inserter {
+ width: $block-inserter-width;
+}
- &:hover {
- border: $border-width solid var(--wp-admin-theme-color);
+.block-editor-inserter__quick-inserter-results {
+ padding-bottom: $grid-unit-20;
+
+ .block-editor-inserter__panel-header {
+ height: 0;
+ padding: 0;
+ float: left;
}
+}
- &:focus {
- box-shadow: inset 0 0 0 1px $white, 0 0 0 $border-width-focus var(--wp-admin-theme-color);
+.block-editor-inserter__quick-inserter-patterns {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-gap: $grid-unit-10;
+}
- // Windows High Contrast mode will show this outline, but not the box-shadow.
- outline: 2px solid transparent;
- }
+.block-editor-inserter__quick-inserter-separator {
+ border-top: $border-width solid $light-gray-500;
+}
- &.is-placeholder {
- min-height: 100px;
+.block-editor-inserter__popover.is-quick > .components-popover__content > div {
+ @include break-medium {
+ padding: 0;
}
}
-.block-editor-inserter__patterns-item-title {
- padding: $grid-unit-05;
- font-size: 12px;
- text-align: center;
+.block-editor-inserter__quick-inserter-expand.components-button {
+ display: block;
+ background: $dark-gray-primary;
+ color: $white;
+ width: 100%;
+ height: ($button-size + $grid-unit-10);
+ border-radius: 0;
+
+ &:hover {
+ color: $white;
+ }
+
+ &:focus:not(:disabled) {
+ box-shadow: inset 0 0 0 $border-width-focus $dark-gray-primary, inset 0 0 0 2px $white;
+ }
}
diff --git a/packages/block-editor/src/components/inserter/tabs.js b/packages/block-editor/src/components/inserter/tabs.js
new file mode 100644
index 00000000000000..11393b2a703728
--- /dev/null
+++ b/packages/block-editor/src/components/inserter/tabs.js
@@ -0,0 +1,29 @@
+/**
+ * WordPress dependencies
+ */
+import { TabPanel } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+function InserterTabs( { children } ) {
+ return (
+
+ { children }
+
+ );
+}
+
+export default InserterTabs;
diff --git a/packages/block-editor/src/components/inserter/test/block-list.js b/packages/block-editor/src/components/inserter/test/block-types-tab.js
similarity index 98%
rename from packages/block-editor/src/components/inserter/test/block-list.js
rename to packages/block-editor/src/components/inserter/test/block-types-tab.js
index 9d4f8134f6c6e1..80dc1b1ec6ad6c 100644
--- a/packages/block-editor/src/components/inserter/test/block-list.js
+++ b/packages/block-editor/src/components/inserter/test/block-types-tab.js
@@ -11,7 +11,7 @@ import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
-import { InserterBlockList as BaseInserterBlockList } from '../block-list';
+import { BlockTypesTab } from '../block-types-tab';
import items, { categories, collections } from './fixtures';
import useBlockTypesState from '../hooks/use-block-types-state';
@@ -36,9 +36,7 @@ jest.mock( '@wordpress/data/src/components/use-dispatch', () => {
const debouncedSpeak = jest.fn();
function InserterBlockList( props ) {
- return (
-
- );
+ return
;
}
const initializeAllClosedMenuState = ( propOverrides ) => {
diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss
index f7648056f036c2..1ddb4f39f2fdd0 100644
--- a/packages/block-editor/src/style.scss
+++ b/packages/block-editor/src/style.scss
@@ -18,6 +18,7 @@
@import "./components/block-mover/style.scss";
@import "./components/block-navigation/style.scss";
@import "./components/block-parent-selector/style.scss";
+@import "./components/block-patterns-list/style.scss";
@import "./components/block-preview/style.scss";
@import "./components/block-settings-menu/style.scss";
@import "./components/block-styles/style.scss";
diff --git a/packages/e2e-test-utils/src/get-all-block-inserter-item-titles.js b/packages/e2e-test-utils/src/get-all-block-inserter-item-titles.js
index b9bc3b058a0c1c..903761a848c6d1 100644
--- a/packages/e2e-test-utils/src/get-all-block-inserter-item-titles.js
+++ b/packages/e2e-test-utils/src/get-all-block-inserter-item-titles.js
@@ -12,7 +12,7 @@ export async function getAllBlockInserterItemTitles() {
const inserterItemTitles = await page.evaluate( () => {
return Array.from(
document.querySelectorAll(
- '.block-editor-inserter__block-list .block-editor-block-types-list__item-title'
+ '.block-editor-block-types-list__item-title'
)
).map( ( inserterItem ) => {
return inserterItem.innerText;
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 454476b108ff38..5ab8f91bfa8766 100644
--- a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js
+++ b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js
@@ -110,14 +110,14 @@ describe( 'cpt locking', () => {
'.wp-block-column .block-editor-button-block-appender'
);
await page.type( '.block-editor-inserter__search-input', 'image' );
- await page.keyboard.press( 'Tab' );
+ await pressKeyTimes( 'Tab', 2 );
await page.keyboard.press( 'Enter' );
await page.click( '.edit-post-header-toolbar__inserter-toggle' );
await page.type(
'.block-editor-inserter__search-input',
'gallery'
);
- await page.keyboard.press( 'Tab' );
+ await pressKeyTimes( 'Tab', 2 );
await page.keyboard.press( 'Enter' );
expect( await page.$( '.wp-block-gallery' ) ).not.toBeNull();
} );
diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js
index 137ac319a6800a..182f224d0976f4 100644
--- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js
+++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js
@@ -11,7 +11,8 @@ import {
closeGlobalBlockInserter,
} from '@wordpress/e2e-test-utils';
-const INSERTER_RESULTS_SELECTOR = '.block-editor-inserter__block-list';
+const INSERTER_RESULTS_SELECTOR =
+ '.block-editor-inserter__quick-inserter-results';
const QUOTE_INSERT_BUTTON_SELECTOR = '//button[.="Quote"]';
const APPENDER_SELECTOR = '.my-custom-awesome-appender';
const DYNAMIC_APPENDER_SELECTOR = 'my-dynamic-blocks-appender';
diff --git a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js
index eceecaaf95ae82..fe4ad65d21c786 100644
--- a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js
+++ b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js
@@ -30,7 +30,7 @@ describe( 'Navigating the block hierarchy', () => {
await page.keyboard.press( 'Tab' ); // Tab to inserter.
await page.keyboard.press( 'Enter' ); // Activate inserter.
await page.keyboard.type( 'Paragraph' );
- await pressKeyTimes( 'Tab', 3 ); // Tab to paragraph result.
+ await pressKeyTimes( 'Tab', 2 ); // Tab to paragraph result.
await page.keyboard.press( 'Enter' ); // Insert paragraph.
await page.keyboard.type( 'First column' );
@@ -66,7 +66,7 @@ describe( 'Navigating the block hierarchy', () => {
await page.keyboard.press( 'Tab' ); // Tab to inserter.
await page.keyboard.press( 'Enter' ); // Activate inserter.
await page.keyboard.type( 'Paragraph' );
- await pressKeyTimes( 'Tab', 3 ); // Tab to paragraph result.
+ await pressKeyTimes( 'Tab', 2 ); // Tab to paragraph result.
await page.keyboard.press( 'Enter' ); // Insert paragraph.
await page.keyboard.type( 'Third column' );
@@ -82,7 +82,7 @@ describe( 'Navigating the block hierarchy', () => {
await page.keyboard.press( 'Tab' ); // Tab to inserter.
await page.keyboard.press( 'Enter' ); // Activate inserter.
await page.keyboard.type( 'Paragraph' );
- await pressKeyTimes( 'Tab', 3 ); // Tab to paragraph result.
+ await pressKeyTimes( 'Tab', 2 ); // Tab to paragraph result.
await page.keyboard.press( 'Enter' ); // Insert paragraph.
await page.keyboard.type( 'First column' );
@@ -109,7 +109,7 @@ describe( 'Navigating the block hierarchy', () => {
await page.keyboard.press( 'Tab' ); // Tab to inserter.
await page.keyboard.press( 'Enter' ); // Activate inserter.
await page.keyboard.type( 'Paragraph' );
- await pressKeyTimes( 'Tab', 3 ); // Tab to paragraph result.
+ await pressKeyTimes( 'Tab', 2 ); // Tab to paragraph result.
await page.keyboard.press( 'Enter' ); // Insert paragraph.
await page.keyboard.type( 'Third column' );
diff --git a/packages/e2e-tests/specs/editor/various/writing-flow.test.js b/packages/e2e-tests/specs/editor/various/writing-flow.test.js
index d9a3b5c255df15..905e85ba9d016a 100644
--- a/packages/e2e-tests/specs/editor/various/writing-flow.test.js
+++ b/packages/e2e-tests/specs/editor/various/writing-flow.test.js
@@ -29,7 +29,7 @@ const addParagraphsAndColumnsDemo = async () => {
await page.click( ':focus .block-editor-button-block-appender' );
await page.waitForSelector( ':focus.block-editor-inserter__search-input' );
await page.keyboard.type( 'Paragraph' );
- await pressKeyTimes( 'Tab', 3 ); // Tab to paragraph result.
+ await pressKeyTimes( 'Tab', 2 ); // Tab to paragraph result.
await page.keyboard.press( 'Enter' ); // Insert paragraph.
await page.keyboard.type( '1st col' ); // If this text is too long, it may wrap to a new line and cause test failure. That's why we're using "1st" instead of "First" here.
@@ -40,7 +40,7 @@ const addParagraphsAndColumnsDemo = async () => {
await page.click( ':focus .block-editor-button-block-appender' );
await page.waitForSelector( ':focus.block-editor-inserter__search-input' );
await page.keyboard.type( 'Paragraph' );
- await pressKeyTimes( 'Tab', 3 ); // Tab to paragraph result.
+ await pressKeyTimes( 'Tab', 2 ); // Tab to paragraph result.
await page.keyboard.press( 'Enter' ); // Insert paragraph.
await page.keyboard.type( '2nd col' ); // If this text is too long, it may wrap to a new line and cause test failure. That's why we're using "2nd" instead of "Second" here.
diff --git a/packages/edit-post/src/components/header/header-toolbar/index.js b/packages/edit-post/src/components/header/header-toolbar/index.js
index 80bd41351abca3..6c178f193ba162 100644
--- a/packages/edit-post/src/components/header/header-toolbar/index.js
+++ b/packages/edit-post/src/components/header/header-toolbar/index.js
@@ -2,7 +2,7 @@
* WordPress dependencies
*/
import { useViewportMatch } from '@wordpress/compose';
-import { useSelect } from '@wordpress/data';
+import { useSelect, useDispatch } from '@wordpress/data';
import { __, _x } from '@wordpress/i18n';
import {
BlockToolbar,
@@ -21,10 +21,12 @@ import {
} from '@wordpress/components';
import { plus } from '@wordpress/icons';
-function HeaderToolbar( { onToggleInserter, isInserterOpen } ) {
+function HeaderToolbar() {
+ const { setIsInserterOpened } = useDispatch( 'core/edit-post' );
const {
hasFixedToolbar,
isInserterEnabled,
+ isInserterOpened,
isTextModeEnabled,
previewDeviceType,
} = useSelect( ( select ) => {
@@ -45,6 +47,7 @@ function HeaderToolbar( { onToggleInserter, isInserterOpen } ) {
hasInserterItems(
getBlockRootClientId( getBlockSelectionEnd() )
),
+ isInserterOpened: select( 'core/edit-post' ).isInserterOpened(),
isTextModeEnabled:
select( 'core/edit-post' ).getEditorMode() === 'text',
previewDeviceType: select(
@@ -72,8 +75,8 @@ function HeaderToolbar( { onToggleInserter, isInserterOpen } ) {
as={ Button }
className="edit-post-header-toolbar__inserter-toggle"
isPrimary
- isPressed={ isInserterOpen }
- onClick={ onToggleInserter }
+ isPressed={ isInserterOpened }
+ onClick={ () => setIsInserterOpened( ! isInserterOpened ) }
disabled={ ! isInserterEnabled }
icon={ plus }
label={ _x(
diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js
index d4b52b0aa7cebc..6603eddf5ff7d7 100644
--- a/packages/edit-post/src/components/header/index.js
+++ b/packages/edit-post/src/components/header/index.js
@@ -17,11 +17,7 @@ import MoreMenu from './more-menu';
import PostPublishButtonOrToggle from './post-publish-button-or-toggle';
import { default as DevicePreview } from '../device-preview';
-function Header( {
- onToggleInserter,
- isInserterOpen,
- setEntitiesSavedStatesCallback,
-} ) {
+function Header( { setEntitiesSavedStatesCallback } ) {
const { hasActiveMetaboxes, isPublishSidebarOpened, isSaving } = useSelect(
( select ) => ( {
hasActiveMetaboxes: select( 'core/edit-post' ).hasMetaBoxes(),
@@ -39,10 +35,7 @@ function Header( {
-
+
{ ! isPublishSidebarOpened && (
diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js
index 13cd1009ae1676..5f606745b3940d 100644
--- a/packages/edit-post/src/components/layout/index.js
+++ b/packages/edit-post/src/components/layout/index.js
@@ -56,12 +56,13 @@ const interfaceLabels = {
};
function Layout() {
- const [ isInserterOpen, setIsInserterOpen ] = useState( false );
const isMobileViewport = useViewportMatch( 'medium', '<' );
const isHugeViewport = useViewportMatch( 'huge', '>=' );
- const { openGeneralSidebar, closeGeneralSidebar } = useDispatch(
- 'core/edit-post'
- );
+ const {
+ openGeneralSidebar,
+ closeGeneralSidebar,
+ setIsInserterOpened,
+ } = useDispatch( 'core/edit-post' );
const {
mode,
isFullscreenActive,
@@ -73,6 +74,7 @@ function Layout() {
nextShortcut,
hasBlockSelected,
showMostUsedBlocks,
+ isInserterOpened,
} = useSelect( ( select ) => {
return {
hasFixedToolbar: select( 'core/edit-post' ).isFeatureActive(
@@ -89,6 +91,7 @@ function Layout() {
showMostUsedBlocks: select( 'core/edit-post' ).isFeatureActive(
'mostUsedBlocks'
),
+ isInserterOpened: select( 'core/edit-post' ).isInserterOpened(),
mode: select( 'core/edit-post' ).getEditorMode(),
isRichEditingEnabled: select( 'core/editor' ).getEditorSettings()
.richEditingEnabled,
@@ -116,14 +119,14 @@ function Layout() {
// Inserter and Sidebars are mutually exclusive
useEffect( () => {
if ( sidebarIsOpened && ! isHugeViewport ) {
- setIsInserterOpen( false );
+ setIsInserterOpened( false );
}
}, [ sidebarIsOpened, isHugeViewport ] );
useEffect( () => {
- if ( isInserterOpen && ! isHugeViewport ) {
+ if ( isInserterOpened && ! isHugeViewport ) {
closeGeneralSidebar();
}
- }, [ isInserterOpen, isHugeViewport ] );
+ }, [ isInserterOpened, isHugeViewport ] );
// Local state for save panel.
// Note 'thruthy' callback implies an open panel.
@@ -157,10 +160,6 @@ function Layout() {
labels={ interfaceLabels }
header={
- setIsInserterOpen( ! isInserterOpen )
- }
setEntitiesSavedStatesCallback={
setEntitiesSavedStatesCallback
}
@@ -168,13 +167,13 @@ function Layout() {
}
leftSidebar={
mode === 'visual' &&
- isInserterOpen && (
+ isInserterOpened && (
- setIsInserterOpen( false )
+ setIsInserterOpened( false )
}
/>
@@ -186,7 +185,7 @@ function Layout() {
showInserterHelpPanel
onSelect={ () => {
if ( isMobileViewport ) {
- setIsInserterOpen( false );
+ setIsInserterOpened( false );
}
} }
/>
diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js
index ba930a0e4b2f63..a700d5ea42647a 100644
--- a/packages/edit-post/src/editor.js
+++ b/packages/edit-post/src/editor.js
@@ -46,6 +46,7 @@ class Editor extends Component {
blockTypes,
preferredStyleVariations,
__experimentalLocalAutosaveInterval,
+ __experimentalSetIsInserterOpened,
updatePreferredStyleVariations
) {
settings = {
@@ -57,6 +58,9 @@ class Editor extends Component {
hasFixedToolbar,
focusMode,
__experimentalLocalAutosaveInterval,
+
+ // This is marked as experimental to give time for the quick inserter to mature.
+ __experimentalSetIsInserterOpened,
};
// Omit hidden block types if exists and non-empty.
@@ -91,6 +95,7 @@ class Editor extends Component {
blockTypes,
preferredStyleVariations,
__experimentalLocalAutosaveInterval,
+ setIsInserterOpened,
updatePreferredStyleVariations,
...props
} = this.props;
@@ -107,6 +112,7 @@ class Editor extends Component {
blockTypes,
preferredStyleVariations,
__experimentalLocalAutosaveInterval,
+ setIsInserterOpened,
updatePreferredStyleVariations
);
@@ -166,9 +172,13 @@ export default compose( [
};
} ),
withDispatch( ( dispatch ) => {
- const { updatePreferredStyleVariations } = dispatch( 'core/edit-post' );
+ const {
+ updatePreferredStyleVariations,
+ setIsInserterOpened,
+ } = dispatch( 'core/edit-post' );
return {
updatePreferredStyleVariations,
+ setIsInserterOpened,
};
} ),
] )( Editor );
diff --git a/packages/edit-post/src/store/actions.js b/packages/edit-post/src/store/actions.js
index b76b017a85e129..df9123616c2cf2 100644
--- a/packages/edit-post/src/store/actions.js
+++ b/packages/edit-post/src/store/actions.js
@@ -284,3 +284,16 @@ export function __experimentalSetPreviewDeviceType( deviceType ) {
deviceType,
};
}
+
+/**
+ * Returns an action object used to open/close the inserter.
+ *
+ * @param {boolean} value A boolean representing whether the inserter should be opened or closed.
+ * @return {Object} Action object.
+ */
+export function setIsInserterOpened( value ) {
+ return {
+ type: 'SET_IS_INSERTER_OPENED',
+ value,
+ };
+}
diff --git a/packages/edit-post/src/store/reducer.js b/packages/edit-post/src/store/reducer.js
index 6f77bb46e0937b..934de97aa73c08 100644
--- a/packages/edit-post/src/store/reducer.js
+++ b/packages/edit-post/src/store/reducer.js
@@ -238,6 +238,20 @@ export function deviceType( state = 'Desktop', action ) {
return state;
}
+/**
+ * Reducer tracking whether the inserter is open.
+ *
+ * @param {boolean} state
+ * @param {Object} action
+ */
+function isInserterOpened( state = false, action ) {
+ switch ( action.type ) {
+ case 'SET_IS_INSERTER_OPENED':
+ return action.value;
+ }
+ return state;
+}
+
const metaBoxes = combineReducers( {
isSaving: isSavingMetaBoxes,
locations: metaBoxLocations,
@@ -250,4 +264,5 @@ export default combineReducers( {
publishSidebarActive,
removedPanels,
deviceType,
+ isInserterOpened,
} );
diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js
index 8b95f0a048b250..68dcc83671ed00 100644
--- a/packages/edit-post/src/store/selectors.js
+++ b/packages/edit-post/src/store/selectors.js
@@ -313,3 +313,14 @@ export function isSavingMetaBoxes( state ) {
export function __experimentalGetPreviewDeviceType( state ) {
return state.deviceType;
}
+
+/**
+ * Returns true if the inserter is opened.
+ *
+ * @param {Object} state Global application state.
+ *
+ * @return {boolean} Whether the inserter is opened.
+ */
+export function isInserterOpened( state ) {
+ return state.isInserterOpened;
+}
diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js
index 57cfb4af84da4d..7afca35eaf9c8e 100644
--- a/packages/editor/src/components/provider/index.js
+++ b/packages/editor/src/components/provider/index.js
@@ -125,6 +125,7 @@ class EditorProvider extends Component {
'__experimentalGlobalStylesUserEntityId',
'__experimentalGlobalStylesBase',
'__experimentalPreferredStyleVariations',
+ '__experimentalSetIsInserterOpened',
'alignWide',
'allowedBlockTypes',
'availableLegacyWidgets',