Skip to content

Commit

Permalink
Use appender map and context
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin940726 committed Oct 6, 2020
1 parent ebe7c91 commit c314041
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 58 deletions.
15 changes: 15 additions & 0 deletions packages/block-editor/src/components/block-list-appender/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { createContext, useContext } from '@wordpress/element';
import { withSelect } from '@wordpress/data';
import { getDefaultBlockName } from '@wordpress/blocks';

Expand All @@ -16,6 +17,9 @@ import { getDefaultBlockName } from '@wordpress/blocks';
import DefaultBlockAppender from '../default-block-appender';
import ButtonBlockAppender from '../button-block-appender';

// A Context to store the map of the appender map.
export const AppenderContext = createContext();

function stopPropagation( event ) {
event.stopPropagation();
}
Expand All @@ -30,6 +34,8 @@ function BlockListAppender( {
selectedBlockClientId,
tagName: TagName = 'div',
} ) {
const appenderMap = useContext( AppenderContext );

if ( isLocked || CustomAppender === false ) {
return null;
}
Expand Down Expand Up @@ -94,6 +100,15 @@ function BlockListAppender( {
'wp-block',
className
) }
ref={ ( ref ) => {
if ( ref ) {
// Set the reference of the "Appender" with `rootClientId` as key.
appenderMap.set( rootClientId || '', ref );
} else {
// If it un-mounts, cleanup the map.
appenderMap.delete( rootClientId || '' );
}
} }
>
{ appender }
</TagName>
Expand Down
106 changes: 57 additions & 49 deletions packages/block-editor/src/components/block-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ import { useRef, forwardRef } from '@wordpress/element';
* Internal dependencies
*/
import BlockListBlock from './block';
import BlockListAppender from '../block-list-appender';
import BlockListAppender, { AppenderContext } from '../block-list-appender';
import RootContainer from './root-container';
import useBlockDropZone from '../use-block-drop-zone';

/**
* A map to store the reference of each "Appenders" rendered with `rootClientId` as key.
*/
const appenderMap = new Map();

/**
* If the block count exceeds the threshold, we disable the reordering animation
* to avoid laginess.
Expand Down Expand Up @@ -82,57 +87,60 @@ function BlockList(
dropTargetIndex === blockClientIds.length && isDraggingBlocks;

return (
<Container
{ ...__experimentalPassedProps }
ref={ element }
className={ classnames(
'block-editor-block-list__layout',
className,
__experimentalPassedProps.className
) }
>
{ blockClientIds.map( ( clientId, index ) => {
const isBlockInSelection = hasMultiSelection
? multiSelectedBlockClientIds.includes( clientId )
: selectedBlockClientId === clientId;
<AppenderContext.Provider value={ appenderMap }>
<Container
{ ...__experimentalPassedProps }
ref={ element }
className={ classnames(
'block-editor-block-list__layout',
className,
__experimentalPassedProps.className
) }
>
{ blockClientIds.map( ( clientId, index ) => {
const isBlockInSelection = hasMultiSelection
? multiSelectedBlockClientIds.includes( clientId )
: selectedBlockClientId === clientId;

const isDropTarget =
dropTargetIndex === index && isDraggingBlocks;
const isDropTarget =
dropTargetIndex === index && isDraggingBlocks;

return (
<AsyncModeProvider
key={ clientId }
value={ ! isBlockInSelection }
>
<BlockListBlock
rootClientId={ rootClientId }
clientId={ clientId }
// This prop is explicitely computed and passed down
// to avoid being impacted by the async mode
// otherwise there might be a small delay to trigger the animation.
index={ index }
enableAnimation={ enableAnimation }
className={ classnames( {
'is-drop-target': isDropTarget,
'is-dropping-horizontally':
isDropTarget &&
orientation === 'horizontal',
} ) }
/>
</AsyncModeProvider>
);
} ) }
<BlockListAppender
tagName={ __experimentalAppenderTagName }
rootClientId={ rootClientId }
renderAppender={ renderAppender }
className={ classnames( {
'is-drop-target': isAppenderDropTarget,
'is-dropping-horizontally':
isAppenderDropTarget && orientation === 'horizontal',
return (
<AsyncModeProvider
key={ clientId }
value={ ! isBlockInSelection }
>
<BlockListBlock
rootClientId={ rootClientId }
clientId={ clientId }
// This prop is explicitely computed and passed down
// to avoid being impacted by the async mode
// otherwise there might be a small delay to trigger the animation.
index={ index }
enableAnimation={ enableAnimation }
className={ classnames( {
'is-drop-target': isDropTarget,
'is-dropping-horizontally':
isDropTarget &&
orientation === 'horizontal',
} ) }
/>
</AsyncModeProvider>
);
} ) }
/>
</Container>
<BlockListAppender
tagName={ __experimentalAppenderTagName }
rootClientId={ rootClientId }
renderAppender={ renderAppender }
className={ classnames( {
'is-drop-target': isAppenderDropTarget,
'is-dropping-horizontally':
isAppenderDropTarget &&
orientation === 'horizontal',
} ) }
/>
</Container>
</AppenderContext.Provider>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { useState, useRef, useMemo } from '@wordpress/element';
import { useState, useRef, useMemo, useContext } from '@wordpress/element';
import { Popover } from '@wordpress/components';
import { placeCaretAtVerticalEdge } from '@wordpress/dom';

Expand All @@ -17,6 +17,7 @@ import { placeCaretAtVerticalEdge } from '@wordpress/dom';
import Inserter from '../inserter';
import { getClosestTabbable } from '../writing-flow';
import { getBlockDOMNode } from '../../utils/dom';
import { AppenderContext } from '../block-list-appender';

function InsertionPointInserter( {
clientId,
Expand Down Expand Up @@ -105,20 +106,17 @@ function InsertionPointPopover( {
containerRef,
showInsertionPoint,
} ) {
const appenderMap = useContext( AppenderContext );
const element = useMemo( () => {
if ( clientId ) {
return getBlockDOMNode( clientId );
}

// Can't find the element, might be at the end of the block list, or inside an empty block list.
// We instead try to place the indicator at the end of the list, where the "Appender" usually lives.
const rootElement = getBlockDOMNode( rootClientId );
const blocks = rootElement?.querySelectorAll( '.wp-block' );

if ( blocks ) {
return blocks[ blocks.length - 1 ];
}
}, [ clientId, rootClientId ] );
// We instead try to find the "Appender" and place the indicator above it.
// `rootClientId` could be null or undefined when there's no parent block, we normalize it to an empty string.
return appenderMap.get( rootClientId || '' );
}, [ clientId, rootClientId, appenderMap ] );

return (
<Popover
Expand Down

0 comments on commit c314041

Please sign in to comment.