From 89087af29f54a18a5d4914e703309ac735d8e915 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 19 Jun 2018 16:51:26 -0400 Subject: [PATCH] Block List: Remove createInnerBlockList utility / context --- core-blocks/test/helpers/index.js | 1 - editor/components/block-edit/context.js | 1 + editor/components/block-edit/index.js | 24 +---- editor/components/block-list/block.js | 27 +---- editor/components/block-preview/index.js | 55 ++++------ editor/components/inner-blocks/index.js | 102 ++++++++++++++---- editor/utils/block-list.js | 127 ----------------------- 7 files changed, 105 insertions(+), 232 deletions(-) delete mode 100644 editor/utils/block-list.js diff --git a/core-blocks/test/helpers/index.js b/core-blocks/test/helpers/index.js index 53cc1187ffe051..7231a3fd0fe099 100644 --- a/core-blocks/test/helpers/index.js +++ b/core-blocks/test/helpers/index.js @@ -31,7 +31,6 @@ export const blockEditRender = ( name, settings ) => { attributes={ block.attributes } setAttributes={ noop } user={ {} } - createInnerBlockList={ noop } /> ); }; diff --git a/editor/components/block-edit/context.js b/editor/components/block-edit/context.js index a1f413b94ad583..ee64a062f44331 100644 --- a/editor/components/block-edit/context.js +++ b/editor/components/block-edit/context.js @@ -13,6 +13,7 @@ const { Consumer, Provider } = createContext( { isSelected: false, focusedElement: null, setFocusedElement: noop, + uid: null, } ); export { Provider as BlockEditContextProvider }; diff --git a/editor/components/block-edit/index.js b/editor/components/block-edit/index.js index a0ab798ef575bf..f309e93d47a874 100644 --- a/editor/components/block-edit/index.js +++ b/editor/components/block-edit/index.js @@ -8,7 +8,7 @@ import { noop, get } from 'lodash'; */ import { withSelect } from '@wordpress/data'; import { Component, compose } from '@wordpress/element'; -import { withContext, withAPIData } from '@wordpress/components'; +import { withAPIData } from '@wordpress/components'; /** * Internal dependencies @@ -27,15 +27,9 @@ export class BlockEdit extends Component { } getChildContext() { - const { - id: uid, - user, - createInnerBlockList, - } = this.props; + const { user } = this.props; return { - uid, - BlockList: createInnerBlockList( uid ), canUserUseUnfilteredHTML: get( user.data, [ 'capabilities', 'unfiltered_html', @@ -52,18 +46,13 @@ export class BlockEdit extends Component { } ); } - static getDerivedStateFromProps( { name, isSelected }, prevState ) { - if ( - name === prevState.name && - isSelected === prevState.isSelected - ) { - return null; - } + static getDerivedStateFromProps( props ) { + const { id, name, isSelected } = props; return { - ...prevState, name, isSelected, + uid: id, }; } @@ -77,8 +66,6 @@ export class BlockEdit extends Component { } BlockEdit.childContextTypes = { - uid: noop, - BlockList: noop, canUserUseUnfilteredHTML: noop, }; @@ -89,5 +76,4 @@ export default compose( [ withAPIData( ( { postType } ) => ( { user: `/wp/v2/users/me?post_type=${ postType }&context=edit`, } ) ), - withContext( 'createInnerBlockList' )(), ] )( BlockEdit ); diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js index 88059e82124908..ec2cff73cd2a82 100644 --- a/editor/components/block-list/block.js +++ b/editor/components/block-list/block.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { get, reduce, size, castArray, first, last, noop } from 'lodash'; +import { get, reduce, size, castArray, first, last } from 'lodash'; import tinymce from 'tinymce'; /** @@ -50,7 +50,6 @@ import IgnoreNestedEvents from './ignore-nested-events'; import InserterWithShortcuts from '../inserter-with-shortcuts'; import Inserter from '../inserter'; import withHoverAreas from './with-hover-areas'; -import { createInnerBlockList } from '../../utils/block-list'; const { BACKSPACE, DELETE, ENTER } = keycodes; @@ -75,7 +74,6 @@ export class BlockListBlock extends Component { this.onDragStart = this.onDragStart.bind( this ); this.onDragEnd = this.onDragEnd.bind( this ); this.selectOnOpen = this.selectOnOpen.bind( this ); - this.createInnerBlockList = this.createInnerBlockList.bind( this ); this.hadTouchStart = false; this.state = { @@ -85,25 +83,6 @@ export class BlockListBlock extends Component { }; } - createInnerBlockList( uid ) { - return createInnerBlockList( uid ); - } - - /** - * Provides context for descendent components for use in block rendering. - * - * @return {Object} Child context. - */ - getChildContext() { - // Blocks may render their own BlockEdit, in which case we must provide - // a mechanism for them to create their own InnerBlockList. BlockEdit - // is defined in `@wordpress/blocks`, so to avoid a circular dependency - // we inject this function via context. - return { - createInnerBlockList: this.createInnerBlockList, - }; - } - componentDidMount() { if ( this.props.isSelected ) { this.focusTabbable(); @@ -696,10 +675,6 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps ) => { }; } ); -BlockListBlock.childContextTypes = { - createInnerBlockList: noop, -}; - export default compose( applyWithSelect, applyWithDispatch, diff --git a/editor/components/block-preview/index.js b/editor/components/block-preview/index.js index 104e885ce67442..a5aae1cbdc3d46 100644 --- a/editor/components/block-preview/index.js +++ b/editor/components/block-preview/index.js @@ -7,56 +7,37 @@ import { noop } from 'lodash'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { Component } from '@wordpress/element'; import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies */ import BlockEdit from '../block-edit'; -import { createInnerBlockList } from '../../utils/block-list'; import './style.scss'; /** * Block Preview Component: It renders a preview given a block name and attributes. * - * @param {Object} props Component props. - * @return {WPElement} Rendered element. + * @param {Object} props Component props. + * + * @return {WPElement} Rendered element. */ -class BlockPreview extends Component { - getChildContext() { - // Blocks may render their own BlockEdit, in which case we must provide - // a mechanism for them to create their own InnerBlockList. BlockEdit - // is defined in `@wordpress/blocks`, so to avoid a circular dependency - // we inject this function via context. - return { - createInnerBlockList, - }; - } - - render() { - const { name, attributes } = this.props; - - const block = createBlock( name, attributes ); - - return ( -
-
{ __( 'Preview' ) }
-
- -
+function BlockPreview( { name, attributes } ) { + const block = createBlock( name, attributes ); + + return ( +
+
{ __( 'Preview' ) }
+
+
- ); - } +
+ ); } -BlockPreview.childContextTypes = { - createInnerBlockList: noop, -}; - export default BlockPreview; diff --git a/editor/components/inner-blocks/index.js b/editor/components/inner-blocks/index.js index 04399b3dcbe615..8bc74b886c200a 100644 --- a/editor/components/inner-blocks/index.js +++ b/editor/components/inner-blocks/index.js @@ -1,6 +1,7 @@ /** * External dependencies */ +import { isEqual, pick } from 'lodash'; import classnames from 'classnames'; /** @@ -8,43 +9,100 @@ import classnames from 'classnames'; */ import { withContext } from '@wordpress/components'; import { withViewportMatch } from '@wordpress/viewport'; -import { compose } from '@wordpress/element'; -import { withSelect } from '@wordpress/data'; +import { Component, compose } from '@wordpress/element'; +import { withSelect, withDispatch } from '@wordpress/data'; +import { synchronizeBlocksWithTemplate } from '@wordpress/blocks'; /** * Internal dependencies */ import './style.scss'; +import BlockList from '../block-list'; +import { withBlockEditContext } from '../block-edit/context'; -function InnerBlocks( { - BlockList, - layouts, - allowedBlocks, - template, - isSmallScreen, - isSelectedBlockInRoot, -} ) { - const classes = classnames( 'editor-inner-blocks', { - 'has-overlay': isSmallScreen && ! isSelectedBlockInRoot, - } ); - - return ( -
- -
- ); +class InnerBlocks extends Component { + componentWillReceiveProps( nextProps ) { + this.updateNestedSettings( { + supportedBlocks: nextProps.allowedBlocks, + } ); + } + + componentDidMount() { + this.updateNestedSettings( { + supportedBlocks: this.props.allowedBlocks, + } ); + this.insertTemplateBlocks( this.props.template ); + } + + insertTemplateBlocks( template ) { + const { block, insertBlocks } = this.props; + if ( template && ! block.innerBlocks.length ) { + // synchronizeBlocksWithTemplate( [], template ) parses the template structure, + // and returns/creates the necessary blocks to represent it. + insertBlocks( synchronizeBlocksWithTemplate( [], template ) ); + } + } + + updateNestedSettings( newSettings ) { + if ( ! isEqual( this.props.blockListSettings, newSettings ) ) { + this.props.updateNestedSettings( newSettings ); + } + } + + render() { + const { + uid, + layouts, + allowedBlocks, + template, + isSmallScreen, + isSelectedBlockInRoot, + } = this.props; + + const classes = classnames( 'editor-inner-blocks', { + 'has-overlay': isSmallScreen && ! isSelectedBlockInRoot, + } ); + + return ( +
+ +
+ ); + } } InnerBlocks = compose( [ - withContext( 'BlockList' )(), - withContext( 'uid' )(), + withBlockEditContext( ( context ) => pick( context, [ 'uid' ] ) ), withViewportMatch( { isSmallScreen: '< medium' } ), withSelect( ( select, ownProps ) => { - const { isBlockSelected, hasSelectedInnerBlock } = select( 'core/editor' ); + const { + isBlockSelected, + hasSelectedInnerBlock, + getBlock, + getBlockListSettings, + } = select( 'core/editor' ); const { uid } = ownProps; return { isSelectedBlockInRoot: isBlockSelected( uid ) || hasSelectedInnerBlock( uid ), + block: getBlock( uid ), + blockListSettings: getBlockListSettings( uid ), + }; + } ), + withDispatch( ( dispatch, ownProps ) => { + const { insertBlocks, updateBlockListSettings } = dispatch( 'core/editor' ); + const { uid } = ownProps; + + return { + insertBlocks( blocks ) { + dispatch( insertBlocks( blocks, undefined, uid ) ); + }, + updateNestedSettings( settings ) { + dispatch( updateBlockListSettings( uid, settings ) ); + }, }; } ), ] )( InnerBlocks ); diff --git a/editor/utils/block-list.js b/editor/utils/block-list.js deleted file mode 100644 index 2bbfe34cdc326e..00000000000000 --- a/editor/utils/block-list.js +++ /dev/null @@ -1,127 +0,0 @@ -/** - * External dependencies - */ -import { isEqual, noop, omit } from 'lodash'; - -/** - * WordPress dependencies - */ -import { Component, compose } from '@wordpress/element'; -import { - synchronizeBlocksWithTemplate, -} from '@wordpress/blocks'; -import { withSelect, withDispatch } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import BlockList from '../components/block-list'; - -/** - * An object of cached BlockList components - * - * @type {Object} - */ -const INNER_BLOCK_LIST_CACHE = {}; - -/** - * Returns a BlockList component which is already pre-bound to render with a - * given UID as its rootUID prop. It is necessary to cache these components - * because otherwise the rendering of a nested BlockList will cause ancestor - * blocks to re-mount, leading to an endless cycle of remounting inner blocks. - * - * @param {string} uid Block UID to use as root UID of - * BlockList component. - * @param {Function} renderBlockMenu Render function for block menu of - * nested BlockList. - * - * @return {Component} Pre-bound BlockList component - */ -export function createInnerBlockList( uid, renderBlockMenu = noop ) { - if ( ! INNER_BLOCK_LIST_CACHE[ uid ] ) { - const InnerBlockListComponent = class extends Component { - componentWillReceiveProps( nextProps ) { - this.updateNestedSettings( { - supportedBlocks: nextProps.allowedBlocks, - } ); - } - - componentWillUnmount() { - // If, after decrementing the tracking count, there are no - // remaining instances of the component, remove from cache. - if ( ! INNER_BLOCK_LIST_CACHE[ uid ][ 1 ]-- ) { - delete INNER_BLOCK_LIST_CACHE[ uid ]; - } - } - - componentDidMount() { - INNER_BLOCK_LIST_CACHE[ uid ][ 1 ]++; - this.updateNestedSettings( { - supportedBlocks: this.props.allowedBlocks, - } ); - this.insertTemplateBlocks( this.props.template ); - } - - insertTemplateBlocks( template ) { - const { block, insertBlocks } = this.props; - if ( template && ! block.innerBlocks.length ) { - // synchronizeBlocksWithTemplate( [], template ) parses the template structure, - // and returns/creates the necessary blocks to represent it. - insertBlocks( synchronizeBlocksWithTemplate( [], template ) ); - } - } - - updateNestedSettings( newSettings ) { - if ( ! isEqual( this.props.blockListSettings, newSettings ) ) { - this.props.updateNestedSettings( newSettings ); - } - } - - render() { - return ( - - ); - } - }; - - const InnerBlockListComponentContainer = compose( - withSelect( ( select ) => { - const { getBlock, getBlockListSettings } = select( 'core/editor' ); - return { - block: getBlock( uid ), - blockListSettings: getBlockListSettings( uid ), - }; - } ), - withDispatch( ( dispatch ) => { - const { insertBlocks, updateBlockListSettings } = dispatch( 'core/editor' ); - return { - insertBlocks( blocks ) { - dispatch( insertBlocks( blocks, undefined, uid ) ); - }, - updateNestedSettings( settings ) { - dispatch( updateBlockListSettings( uid, settings ) ); - }, - }; - } ), - )( InnerBlockListComponent ); - - INNER_BLOCK_LIST_CACHE[ uid ] = [ - InnerBlockListComponentContainer, - 0, // A counter tracking active mounted instances: - ]; - } - - return INNER_BLOCK_LIST_CACHE[ uid ][ 0 ]; -}