diff --git a/packages/block-editor/src/components/inserter/index.js b/packages/block-editor/src/components/inserter/index.js index 4b842b4b7b3c5..37ac654d14c98 100644 --- a/packages/block-editor/src/components/inserter/index.js +++ b/packages/block-editor/src/components/inserter/index.js @@ -1,11 +1,21 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; +import { + get, +} from 'lodash'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { Dropdown, IconButton } from '@wordpress/components'; +import { Dropdown, IconButton, Button, Icon } 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, +} from '@wordpress/blocks'; /** * Internal dependencies @@ -83,7 +93,23 @@ class Inserter extends Component { } render() { - const { position } = this.props; + const { position, hasOneAllowedItem, createIfOne } = this.props; + let toggle = null; + if ( hasOneAllowedItem ) { + toggle = () => { + return ( + + ); + }; + } else { + toggle = this.renderToggle; + } return ( ); @@ -102,10 +128,62 @@ class Inserter extends Component { export default compose( [ withSelect( ( select, { rootClientId } ) => { - const { hasInserterItems } = select( 'core/block-editor' ); + const { hasInserterItems, hasOneAllowedItem } = select( 'core/block-editor' ); return { hasItems: hasInserterItems( rootClientId ), + hasOneAllowedItem: hasOneAllowedItem( rootClientId ), + }; + } ), + withDispatch( ( dispatch, ownProps, { select } ) => { + // eslint-disable-next-line no-restricted-syntax + function getInsertionIndex() { + const { + getBlockIndex, + getBlockSelectionEnd, + getBlockOrder, + } = select( 'core/block-editor' ); + const { clientId, destinationRootClientId, isAppender } = ownProps; + + // 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 { rootClientId } = ownProps; + + // eslint-disable-next-line no-restricted-syntax + function createIfOne( ) { + const { + insertBlock, + } = dispatch( 'core/block-editor' ); + const { + getBlockListSettings, + } = select( 'core/block-editor' ); + const parentBlockListSettings = getBlockListSettings( rootClientId ); + const parentAllowedBlocks = get( parentBlockListSettings, [ 'allowedBlocks' ] ); + if ( parentAllowedBlocks.length > 1 ) { + return false; + } + const insertedBlock = createBlock( parentAllowedBlocks[ 0 ] ); + insertBlock( + insertedBlock, + getInsertionIndex(), + rootClientId + ); + } + + return { + createIfOne, }; } ), ifCondition( ( { hasItems } ) => hasItems ), diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 5e8771ff94935..24958dcd2b41d 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1328,6 +1328,29 @@ export const hasInserterItems = createSelector( ], ); +/** + * Determines whether there is only one item that may be inserted. + * @param {Object} state Editor state. + * @param {?string} rootClientId Optional root client ID of block list. + * + * @return {boolean} True if there is one item available, false if zero or more than one. + */ +export const hasOneAllowedItem = createSelector( + ( state, rootClientId = null ) => { + if ( rootClientId ) { + const parentBlockListSettings = getBlockListSettings( state, rootClientId ); + return ( !! get( parentBlockListSettings, [ 'allowedBlocks' ] ) && + get( parentBlockListSettings, [ 'allowedBlocks' ] ).length === 1 ); + } + + return false; + }, + ( state, rootClientId ) => [ + state, + rootClientId, + ], +); + /** * Returns the Block List settings of a block, if any exist. *