diff --git a/packages/editor/src/components/block-actions/index.js b/packages/editor/src/components/block-actions/index.js index 590d932a626f9..b90325b0affd5 100644 --- a/packages/editor/src/components/block-actions/index.js +++ b/packages/editor/src/components/block-actions/index.js @@ -33,7 +33,6 @@ export default compose( [ withSelect( ( select, props ) => { const { getBlocksByClientId, - getBlockIndex, getTemplateLock, getBlockRootClientId, } = select( 'core/editor' ); @@ -45,8 +44,6 @@ export default compose( [ const rootClientId = getBlockRootClientId( props.clientIds[ 0 ] ); return { - firstSelectedIndex: getBlockIndex( first( castArray( props.clientIds ) ), rootClientId ), - lastSelectedIndex: getBlockIndex( last( castArray( props.clientIds ) ), rootClientId ), isLocked: !! getTemplateLock( rootClientId ), blocks, canDuplicate, @@ -54,13 +51,11 @@ export default compose( [ extraProps: props, }; } ), - withDispatch( ( dispatch, props ) => { + withDispatch( ( dispatch, props, { select } ) => { const { clientIds, rootClientId, blocks, - firstSelectedIndex, - lastSelectedIndex, isLocked, canDuplicate, } = props; @@ -78,6 +73,8 @@ export default compose( [ return; } + const { getBlockIndex } = select( 'core/editor' ); + const lastSelectedIndex = getBlockIndex( last( castArray( clientIds ) ), rootClientId ); const clonedBlocks = blocks.map( ( block ) => cloneBlock( block ) ); insertBlocks( clonedBlocks, @@ -98,11 +95,15 @@ export default compose( [ }, onInsertBefore() { if ( ! isLocked ) { + const { getBlockIndex } = select( 'core/editor' ); + const firstSelectedIndex = getBlockIndex( first( castArray( clientIds ) ), rootClientId ); insertDefaultBlock( {}, rootClientId, firstSelectedIndex ); } }, onInsertAfter() { if ( ! isLocked ) { + const { getBlockIndex } = select( 'core/editor' ); + const lastSelectedIndex = getBlockIndex( last( castArray( clientIds ) ), rootClientId ); insertDefaultBlock( {}, rootClientId, lastSelectedIndex + 1 ); } }, diff --git a/packages/editor/src/components/block-draggable/index.js b/packages/editor/src/components/block-draggable/index.js index 27a44ce2a852b..2f7c3436819a1 100644 --- a/packages/editor/src/components/block-draggable/index.js +++ b/packages/editor/src/components/block-draggable/index.js @@ -33,8 +33,9 @@ const BlockDraggable = ( { children, clientId, rootClientId, blockElementId, ind export default withSelect( ( select, { clientId } ) => { const { getBlockIndex, getBlockRootClientId } = select( 'core/editor' ); + const rootClientId = getBlockRootClientId( clientId ); return { - index: getBlockIndex( clientId ), - rootClientId: getBlockRootClientId( clientId ), + index: getBlockIndex( clientId, rootClientId ), + rootClientId, }; } )( BlockDraggable ); diff --git a/packages/editor/src/components/block-drop-zone/index.js b/packages/editor/src/components/block-drop-zone/index.js index 3e9c0db427e58..a6f426aa6e266 100644 --- a/packages/editor/src/components/block-drop-zone/index.js +++ b/packages/editor/src/components/block-drop-zone/index.js @@ -55,8 +55,9 @@ class BlockDropZone extends Component { } getInsertIndex( position ) { - const { index } = this.props; - if ( index !== undefined ) { + const { clientId, rootClientId, getBlockIndex } = this.props; + if ( clientId !== undefined ) { + const index = getBlockIndex( clientId, rootClientId ); return position.y === 'top' ? index : index + 1; } } @@ -83,7 +84,7 @@ class BlockDropZone extends Component { } onDrop( event, position ) { - const { rootClientId: dstRootClientId, clientId: dstClientId, index: dstIndex, getClientIdsOfDescendants } = this.props; + const { rootClientId: dstRootClientId, clientId: dstClientId, getClientIdsOfDescendants, getBlockIndex } = this.props; const { srcRootClientId, srcClientId, srcIndex, type } = parseDropEvent( event ); const isBlockDropType = ( dropType ) => dropType === 'block'; @@ -101,6 +102,7 @@ class BlockDropZone extends Component { return; } + const dstIndex = dstClientId ? getBlockIndex( dstClientId, dstRootClientId ) : undefined; const positionIndex = this.getInsertIndex( position ); // If the block is kept at the same level and moved downwards, // subtract to account for blocks shifting upward to occupy its old position. @@ -154,10 +156,11 @@ export default compose( }; } ), withSelect( ( select, { rootClientId } ) => { - const { getClientIdsOfDescendants, getTemplateLock } = select( 'core/editor' ); + const { getClientIdsOfDescendants, getTemplateLock, getBlockIndex } = select( 'core/editor' ); return { isLocked: !! getTemplateLock( rootClientId ), getClientIdsOfDescendants, + getBlockIndex, }; } ), withFilters( 'editor.BlockDropZone' ) diff --git a/packages/editor/src/components/block-list-appender/index.js b/packages/editor/src/components/block-list-appender/index.js index b306c2945654f..21ac587e42cd6 100644 --- a/packages/editor/src/components/block-list-appender/index.js +++ b/packages/editor/src/components/block-list-appender/index.js @@ -54,6 +54,7 @@ function BlockListAppender( { disabled={ disabled } /> ) } + isAppender /> ); diff --git a/packages/editor/src/components/block-list/block.js b/packages/editor/src/components/block-list/block.js index 75267e71e0c0d..87d9d11795767 100644 --- a/packages/editor/src/components/block-list/block.js +++ b/packages/editor/src/components/block-list/block.js @@ -26,7 +26,7 @@ import { KeyboardShortcuts, withFilters } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { withDispatch, withSelect } from '@wordpress/data'; import { withViewportMatch } from '@wordpress/viewport'; -import { compose } from '@wordpress/compose'; +import { compose, pure } from '@wordpress/compose'; /** * Internal dependencies @@ -59,7 +59,6 @@ export class BlockListBlock extends Component { this.maybeHover = this.maybeHover.bind( this ); this.forceFocusedContextualToolbar = this.forceFocusedContextualToolbar.bind( this ); this.hideHoverEffects = this.hideHoverEffects.bind( this ); - this.insertBlocksAfter = this.insertBlocksAfter.bind( this ); this.onFocus = this.onFocus.bind( this ); this.preventDrag = this.preventDrag.bind( this ); this.onPointerDown = this.onPointerDown.bind( this ); @@ -233,10 +232,6 @@ export class BlockListBlock extends Component { } } - insertBlocksAfter( blocks ) { - this.props.onInsertBlocks( blocks, this.props.order + 1 ); - } - /** * Marks the block as selected when focused and not already selected. This * specifically handles the case where block does not set focus on its own @@ -361,7 +356,6 @@ export class BlockListBlock extends Component { { ( { hoverArea } ) => { const { - order, mode, isFocusMode, hasFixedToolbar, @@ -397,11 +391,9 @@ export class BlockListBlock extends Component { // Empty paragraph blocks should always show up as unselected. const showEmptyBlockSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock && isValid; - const showSideInserter = - ( isSelected || isHovered ) && isEmptyDefaultBlock; const shouldAppearSelected = ! isFocusMode && - ! showSideInserter && + ! showEmptyBlockSideInserter && isSelected && ! isTypingWithinBlock; const shouldAppearHovered = @@ -420,7 +412,7 @@ export class BlockListBlock extends Component { ! isFocusMode && isHovered && ! isEmptyDefaultBlock; const shouldShowContextualToolbar = ! hasFixedToolbar && - ! showSideInserter && + ! showEmptyBlockSideInserter && ( ( isSelected && ( ! isTypingWithinBlock || isCaretWithinFormattedText ) ) || isFirstMultiSelected ); @@ -474,7 +466,7 @@ export class BlockListBlock extends Component { isSelected={ isSelected } attributes={ attributes } setAttributes={ this.setAttributes } - insertBlocksAfter={ isLocked ? undefined : this.insertBlocksAfter } + insertBlocksAfter={ isLocked ? undefined : this.props.onInsertBlocksAfter } onReplace={ isLocked ? undefined : onReplace } mergeBlocks={ isLocked ? undefined : this.props.onMerge } clientId={ clientId } @@ -521,7 +513,6 @@ export class BlockListBlock extends Component { /> ) } @@ -612,6 +603,8 @@ export class BlockListBlock extends Component { @@ -634,7 +627,6 @@ const applyWithSelect = withSelect( isFirstMultiSelectedBlock, isTyping, isCaretWithinFormattedText, - getBlockIndex, getBlockMode, isSelectionEnabled, getSelectedBlocksInitialCaretPosition, @@ -663,10 +655,9 @@ const applyWithSelect = withSelect( isTypingWithinBlock: ( isSelected || isParentOfSelectedBlock ) && isTyping(), isCaretWithinFormattedText: isCaretWithinFormattedText(), - order: getBlockIndex( clientId, rootClientId ), mode: getBlockMode( clientId ), isSelectionEnabled: isSelectionEnabled(), - initialPosition: getSelectedBlocksInitialCaretPosition(), + initialPosition: isSelected ? getSelectedBlocksInitialCaretPosition() : null, isEmptyDefaultBlock: name && isUnmodifiedDefaultBlock( { name, attributes } ), isMovable: 'all' !== templateLock, @@ -715,8 +706,20 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => { insertBlocks( blocks, index, rootClientId ); }, onInsertDefaultBlockAfter() { - const { order, rootClientId } = ownProps; - insertDefaultBlock( {}, rootClientId, order + 1 ); + const { clientId, rootClientId } = ownProps; + const { + getBlockIndex, + } = select( 'core/editor' ); + const index = getBlockIndex( clientId, rootClientId ); + insertDefaultBlock( {}, rootClientId, index + 1 ); + }, + onInsertBlocksAfter( blocks ) { + const { clientId, rootClientId } = ownProps; + const { + getBlockIndex, + } = select( 'core/editor' ); + const index = getBlockIndex( clientId, rootClientId ); + insertBlocks( blocks, index + 1, rootClientId ); }, onRemove( clientId ) { removeBlock( clientId ); @@ -764,6 +767,7 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => { } ); export default compose( + pure, withViewportMatch( { isLargeViewport: 'medium' } ), applyWithSelect, applyWithDispatch, diff --git a/packages/editor/src/components/block-list/index.js b/packages/editor/src/components/block-list/index.js index 7e5a1e7eedfb1..6ab8cd3956239 100644 --- a/packages/editor/src/components/block-list/index.js +++ b/packages/editor/src/components/block-list/index.js @@ -212,7 +212,6 @@ class BlockList extends Component { > @@ -87,13 +87,12 @@ export default withSelect( ( select, { clientId, rootClientId } ) => { isBlockInsertionPointVisible, } = select( 'core/editor' ); const blockIndex = getBlockIndex( clientId, rootClientId ); - const insertIndex = blockIndex; const insertionPoint = getBlockInsertionPoint(); const showInsertionPoint = ( isBlockInsertionPointVisible() && - insertionPoint.index === insertIndex && + insertionPoint.index === blockIndex && insertionPoint.rootClientId === rootClientId ); - return { showInsertionPoint, insertIndex }; + return { showInsertionPoint }; } )( BlockInsertionPoint ); diff --git a/packages/editor/src/components/default-block-appender/index.js b/packages/editor/src/components/default-block-appender/index.js index d4b95c4d961ba..594c357064de6 100644 --- a/packages/editor/src/components/default-block-appender/index.js +++ b/packages/editor/src/components/default-block-appender/index.js @@ -67,7 +67,7 @@ export function DefaultBlockAppender( { value={ showPrompt ? value : '' } /> { hovered && } - + ); } diff --git a/packages/editor/src/components/default-block-appender/test/__snapshots__/index.js.snap b/packages/editor/src/components/default-block-appender/test/__snapshots__/index.js.snap index dc26d4405d863..c542d5b5dd65e 100644 --- a/packages/editor/src/components/default-block-appender/test/__snapshots__/index.js.snap +++ b/packages/editor/src/components/default-block-appender/test/__snapshots__/index.js.snap @@ -25,6 +25,7 @@ exports[`DefaultBlockAppender should append a default block when input focused 1 value="Start writing or type / to choose a block" /> @@ -48,6 +49,7 @@ exports[`DefaultBlockAppender should match snapshot 1`] = ` value="Start writing or type / to choose a block" /> @@ -71,6 +73,7 @@ exports[`DefaultBlockAppender should optionally show without prompt 1`] = ` value="" /> diff --git a/packages/editor/src/components/inserter/index.js b/packages/editor/src/components/inserter/index.js index 0012fbc8ddb1d..8c181f3cbd24c 100644 --- a/packages/editor/src/components/inserter/index.js +++ b/packages/editor/src/components/inserter/index.js @@ -70,13 +70,14 @@ class Inserter extends Component { * @return {WPElement} Dropdown content element. */ renderContent( { onClose } ) { - const { rootClientId, index } = this.props; + const { rootClientId, clientId, isAppender } = this.props; return ( ); } @@ -100,27 +101,15 @@ class Inserter extends Component { } export default compose( [ - withSelect( ( select, { rootClientId, index } ) => { + withSelect( ( select, { rootClientId } ) => { const { getEditedPostAttribute, - getBlockInsertionPoint, hasInserterItems, } = select( 'core/editor' ); - if ( rootClientId === undefined && index === undefined ) { - // Unless explicitly provided, the default insertion point provided - // by the store occurs immediately following the selected block. - // Otherwise, the default behavior for an undefined index is to - // append block to the end of the rootClientId context. - const insertionPoint = getBlockInsertionPoint(); - ( { rootClientId, index } = insertionPoint ); - } - return { title: getEditedPostAttribute( 'title' ), hasItems: hasInserterItems( rootClientId ), - rootClientId, - index, }; } ), ifCondition( ( { hasItems } ) => hasItems ), diff --git a/packages/editor/src/components/inserter/menu.js b/packages/editor/src/components/inserter/menu.js index 9f6dea181e14c..bae98e911b090 100644 --- a/packages/editor/src/components/inserter/menu.js +++ b/packages/editor/src/components/inserter/menu.js @@ -132,8 +132,7 @@ export class InserterMenu extends Component { const { showInsertionPoint, hideInsertionPoint } = this.props; if ( item ) { - const { rootClientId, index } = this.props; - showInsertionPoint( rootClientId, index ); + showInsertionPoint(); } else { hideInsertionPoint(); } @@ -369,24 +368,68 @@ export default compose( hideInsertionPoint, } = dispatch( 'core/editor' ); + // To avoid duplication, getInsertionPoint is extracted and used in two event handlers + // This breaks the withDispatch not containing any logic rule. + // Since it's a function only called when the event handlers are called, + // it's fine to extract it. + // eslint-disable-next-line no-restricted-syntax + function getInsertionPoint() { + const { + getBlockIndex, + getBlockRootClientId, + getBlockSelectionEnd, + getBlockOrder, + } = select( 'core/editor' ); + const { clientId, rootClientId, isAppender } = ownProps; + + // If the clientId is defined, we insert at the position of the block. + if ( clientId ) { + return { + index: getBlockIndex( clientId, rootClientId ), + rootClientId, + }; + } + + // If there a selected block, we insert after the selected block. + const end = getBlockSelectionEnd(); + if ( ! isAppender && end ) { + const selectedBlockRootClientId = getBlockRootClientId( end ) || undefined; + return { + index: getBlockIndex( end, selectedBlockRootClientId ) + 1, + rootClientId: selectedBlockRootClientId, + }; + } + + // Otherwise, we insert at the end of the current rootClientId + return { + index: getBlockOrder( rootClientId ).length, + rootClientId, + }; + } + return { fetchReusableBlocks, - showInsertionPoint, + showInsertionPoint() { + const { index, rootClientId } = getInsertionPoint(); + showInsertionPoint( rootClientId, index ); + }, hideInsertionPoint, onSelect( item ) { const { replaceBlocks, insertBlock, } = dispatch( 'core/editor' ); - const { getSelectedBlock } = select( 'core/editor' ); - const { index, rootClientId } = ownProps; + const { + getSelectedBlock, + } = select( 'core/editor' ); + const { isAppender } = ownProps; const { name, initialAttributes } = item; - const selectedBlock = getSelectedBlock(); const insertedBlock = createBlock( name, initialAttributes ); - if ( selectedBlock && isUnmodifiedDefaultBlock( selectedBlock ) ) { + if ( ! isAppender && selectedBlock && isUnmodifiedDefaultBlock( selectedBlock ) ) { replaceBlocks( selectedBlock.clientId, insertedBlock ); } else { + const { index, rootClientId } = getInsertionPoint(); insertBlock( insertedBlock, index, rootClientId ); }