diff --git a/packages/block-editor/src/components/button-block-appender/index.js b/packages/block-editor/src/components/button-block-appender/index.js
index 7fd751165f5b45..1cbbb5980903a2 100644
--- a/packages/block-editor/src/components/button-block-appender/index.js
+++ b/packages/block-editor/src/components/button-block-appender/index.js
@@ -6,8 +6,8 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { Button, Icon } from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
+import { Button, Icon, Tooltip } from '@wordpress/components';
+import { _x, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
@@ -21,17 +21,31 @@ function ButtonBlockAppender( { rootClientId, className } ) {
(
-
- ) }
+ renderToggle={ ( { onToggle, disabled, isOpen, blockTitle, hasSingleBlockType } ) => {
+ let label;
+ if ( hasSingleBlockType ) {
+ // translators: %s: the name of the block when there is only one
+ label = sprintf( _x( 'Add %s', 'directly add the only allowed block' ), blockTitle );
+ } else {
+ label = _x( 'Add block', 'Generic label for block inserter button' );
+ }
+ const isToggleButton = ! hasSingleBlockType;
+ return (
+
+
+
+ );
+ } }
isAppender
/>
>
diff --git a/packages/block-editor/src/components/default-block-appender/test/__snapshots__/index.js.snap b/packages/block-editor/src/components/default-block-appender/test/__snapshots__/index.js.snap
index 9a09dae0d47674..08a0f7df9efe74 100644
--- a/packages/block-editor/src/components/default-block-appender/test/__snapshots__/index.js.snap
+++ b/packages/block-editor/src/components/default-block-appender/test/__snapshots__/index.js.snap
@@ -29,7 +29,7 @@ exports[`DefaultBlockAppender should append a default block when input focused 1
rows={1}
value="Start writing or type / to choose a block"
/>
-
@@ -53,7 +53,7 @@ exports[`DefaultBlockAppender should match snapshot 1`] = `
rows={1}
value="Start writing or type / to choose a block"
/>
-
@@ -77,7 +77,7 @@ exports[`DefaultBlockAppender should optionally show without prompt 1`] = `
rows={1}
value=""
/>
-
diff --git a/packages/block-editor/src/components/inserter/index.js b/packages/block-editor/src/components/inserter/index.js
index 5abb1ae4ef9230..b9fd9dead4b377 100644
--- a/packages/block-editor/src/components/inserter/index.js
+++ b/packages/block-editor/src/components/inserter/index.js
@@ -1,29 +1,46 @@
+/**
+ * External dependencies
+ */
+import { get } from 'lodash';
/**
* WordPress dependencies
*/
-import { __ } from '@wordpress/i18n';
+import { __, _x, sprintf } from '@wordpress/i18n';
import { Dropdown, IconButton } from '@wordpress/components';
import { Component } from '@wordpress/element';
-import { withSelect } from '@wordpress/data';
+import { withDispatch, withSelect } from '@wordpress/data';
import { compose, ifCondition } from '@wordpress/compose';
+import {
+ createBlock,
+ getBlockType,
+} from '@wordpress/blocks';
/**
* Internal dependencies
*/
import InserterMenu from './menu';
-const defaultRenderToggle = ( { onToggle, disabled, isOpen } ) => (
-
-);
+const defaultRenderToggle = ( { onToggle, disabled, isOpen, blockTitle, hasSingleBlockType } ) => {
+ let label;
+ if ( hasSingleBlockType ) {
+ // translators: %s: the name of the block when there is only one
+ label = sprintf( _x( 'Add %s', 'directly add the only allowed block' ), blockTitle );
+ } else {
+ label = _x( 'Add block', 'Generic label for block inserter button' );
+ }
+ return (
+
+ );
+};
class Inserter extends Component {
constructor() {
@@ -56,10 +73,12 @@ class Inserter extends Component {
renderToggle( { onToggle, isOpen } ) {
const {
disabled,
+ blockTitle,
+ hasSingleBlockType,
renderToggle = defaultRenderToggle,
} = this.props;
- return renderToggle( { onToggle, isOpen, disabled } );
+ return renderToggle( { onToggle, isOpen, disabled, blockTitle, hasSingleBlockType } );
}
/**
@@ -86,8 +105,10 @@ class Inserter extends Component {
}
render() {
- const { position } = this.props;
-
+ const { position, hasSingleBlockType, insertOnlyAllowedBlock } = this.props;
+ if ( hasSingleBlockType ) {
+ return this.renderToggle( { onToggle: insertOnlyAllowedBlock } );
+ }
return (
{
- const { hasInserterItems } = select( 'core/block-editor' );
+ const {
+ hasInserterItems,
+ __experimentalGetAllowedBlocks,
+ } = select( 'core/block-editor' );
+
+ const allowedBlocks = __experimentalGetAllowedBlocks( rootClientId );
+ const hasSingleBlockType = allowedBlocks && ( get( allowedBlocks, [ 'length' ], 0 ) === 1 );
+ let allowedBlockType = false;
+ if ( hasSingleBlockType ) {
+ allowedBlockType = getBlockType( allowedBlocks );
+ }
return {
hasItems: hasInserterItems( rootClientId ),
+ hasSingleBlockType,
+ blockTitle: allowedBlockType ? allowedBlockType.title : '',
+ allowedBlockType,
+ };
+ } ),
+ withDispatch( ( dispatch, ownProps, { select } ) => {
+ return {
+ insertOnlyAllowedBlock() {
+ const { rootClientId, clientId, isAppender, destinationRootClientId } = ownProps;
+ const {
+ hasSingleBlockType,
+ allowedBlockType,
+ } = ownProps;
+
+ if ( ! hasSingleBlockType ) {
+ return;
+ }
+
+ function getInsertionIndex() {
+ const {
+ getBlockIndex,
+ getBlockSelectionEnd,
+ getBlockOrder,
+ } = select( 'core/block-editor' );
+
+ // If the clientId is defined, we insert at the position of the block.
+ if ( clientId ) {
+ return getBlockIndex( clientId, destinationRootClientId );
+ }
+
+ // If there a selected block, we insert after the selected block.
+ const end = getBlockSelectionEnd();
+ if ( ! isAppender && end ) {
+ return getBlockIndex( end, destinationRootClientId ) + 1;
+ }
+
+ // Otherwise, we insert at the end of the current rootClientId
+ return getBlockOrder( destinationRootClientId ).length;
+ }
+
+ const {
+ insertBlock,
+ } = dispatch( 'core/block-editor' );
+
+ const blockToInsert = createBlock( allowedBlockType.name );
+ insertBlock(
+ blockToInsert,
+ getInsertionIndex(),
+ rootClientId
+ );
+ },
};
} ),
ifCondition( ( { hasItems } ) => hasItems ),
diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js
index a0fd75a3a7b816..76bec295096bc3 100644
--- a/packages/block-editor/src/store/selectors.js
+++ b/packages/block-editor/src/store/selectors.js
@@ -1310,6 +1310,22 @@ export const hasInserterItems = createSelector(
],
);
+/**
+ * Returns the list of allowed inserter blocks for inner blocks children
+ *
+ * @param {Object} state Editor state.
+ * @param {?string} rootClientId Optional root client ID of block list.
+ *
+ * @return {Array?} The list of allowed block types or false.
+ */
+export const __experimentalGetAllowedBlocks = ( state, rootClientId = null ) => {
+ if ( ! rootClientId ) {
+ return false;
+ }
+ const { allowedBlocks } = getBlockListSettings( state, rootClientId );
+ return allowedBlocks;
+};
+
/**
* Returns the Block List settings of a block, if any exist.
*