Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lighter InnerBlocks: allow blocks to render own wrappers #19910

Merged
merged 12 commits into from
Mar 2, 2020
2 changes: 1 addition & 1 deletion packages/base-styles/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ $z-layers: (

// Small screen inner blocks overlay must be displayed above drop zone,
// settings menu, and movers.
".block-editor-inner-blocks.has-overlay::after": 60,
".block-editor-block-list__layout.has-overlay::after": 60,

// The toolbar, when contextual, should be above any adjacent nested block click overlays.
".block-editor-block-contextual-toolbar": 61,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const BlockComponent = forwardRef(
name,
mode,
blockTitle,
wrapperProps,
} = useContext( BlockContext );
const { initialPosition } = useSelect(
( select ) => {
Expand Down Expand Up @@ -203,6 +204,7 @@ const BlockComponent = forwardRef(
// Overrideable props.
aria-label={ blockLabel }
role="group"
{ ...wrapperProps }
{ ...props }
id={ blockElementId }
ref={ wrapper }
Expand Down
3 changes: 2 additions & 1 deletion packages/block-editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ function BlockListBlock( {
// For aligned blocks, provide a wrapper element so the block can be
// positioned relative to the block column. This is enabled with the
// .is-block-content className.
if ( isAligned ) {
if ( ! lightBlockWrapper && isAligned ) {
blockEdit = <div className="is-block-content">{ blockEdit }</div>;
}

Expand All @@ -163,6 +163,7 @@ function BlockListBlock( {
name,
mode,
blockTitle: blockType.title,
wrapperProps,
};
const memoizedValue = useMemo( () => value, Object.values( value ) );

Expand Down
47 changes: 27 additions & 20 deletions packages/block-editor/src/components/block-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { AsyncModeProvider, useSelect } from '@wordpress/data';
import { useRef } from '@wordpress/element';
import { useRef, forwardRef } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -23,21 +23,18 @@ import useBlockDropZone from '../block-drop-zone';
*/
const BLOCK_ANIMATION_THRESHOLD = 200;

const forceSyncUpdates = ( WrappedComponent ) => ( props ) => {
return (
<AsyncModeProvider value={ false }>
<WrappedComponent { ...props } />
</AsyncModeProvider>
);
};

function BlockList( {
className,
rootClientId,
isDraggable,
renderAppender,
__experimentalUIParts = {},
} ) {
function BlockList(
{
className,
rootClientId,
isDraggable,
renderAppender,
__experimentalUIParts = {},
__experimentalTagName = 'div',
__experimentalPassedProps = {},
},
ref
) {
function selector( select ) {
const {
getBlockOrder,
Expand Down Expand Up @@ -70,8 +67,7 @@ function BlockList( {
enableAnimation,
} = useSelect( selector, [ rootClientId ] );

const Container = rootClientId ? 'div' : RootContainer;
const ref = useRef();
const Container = rootClientId ? __experimentalTagName : RootContainer;
const targetClientId = useBlockDropZone( {
element: ref,
rootClientId,
Expand All @@ -82,10 +78,12 @@ function BlockList( {

return (
<Container
{ ...__experimentalPassedProps }
ref={ ref }
className={ classnames(
'block-editor-block-list__layout',
className
className,
__experimentalPassedProps.className
) }
{ ...__experimentalContainerProps }
>
Expand Down Expand Up @@ -132,7 +130,16 @@ function BlockList( {
);
}

const ForwardedBlockList = forwardRef( BlockList );

// This component needs to always be synchronous
// as it's the one changing the async mode
// depending on the block selection.
export default forceSyncUpdates( BlockList );
export default forwardRef( ( props, ref ) => {
const fallbackRef = useRef();
ellatrix marked this conversation as resolved.
Show resolved Hide resolved
return (
<AsyncModeProvider value={ false }>
<ForwardedBlockList ref={ ref || fallbackRef } { ...props } />
</AsyncModeProvider>
);
} );
4 changes: 2 additions & 2 deletions packages/block-editor/src/components/block-list/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,14 @@
}

// Reusable blocks clickthrough overlays.
&.is-reusable > .block-editor-inner-blocks.has-overlay {
&.is-reusable > .block-editor-inner-blocks > .block-editor-block-list__layout.has-overlay {
// Remove only the top click overlay.
&::after {
display: none;
}

// Restore it for subsequent.
.block-editor-inner-blocks.has-overlay::after {
.block-editor-block-list__layout.has-overlay::after {
display: block;
}
}
Expand Down
49 changes: 36 additions & 13 deletions packages/block-editor/src/components/inner-blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { withViewportMatch } from '@wordpress/viewport';
import { Component } from '@wordpress/element';
import { Component, forwardRef, useRef } from '@wordpress/element';
import { withSelect, withDispatch } from '@wordpress/data';
import {
synchronizeBlocksWithTemplate,
Expand Down Expand Up @@ -149,26 +149,42 @@ class InnerBlocks extends Component {
clientId,
hasOverlay,
__experimentalCaptureToolbars: captureToolbars,
forwardedRef,
...props
} = this.props;
const { templateInProcess } = this.state;

const classes = classnames( 'block-editor-inner-blocks', {
if ( templateInProcess ) {
return null;
}

const classes = classnames( {
'has-overlay': enableClickThrough && hasOverlay,
'is-capturing-toolbar': captureToolbars,
} );

const blockList = (
<BlockList
{ ...props }
ref={ forwardedRef }
rootClientId={ clientId }
className={ classes }
/>
);

if ( props.__experimentalTagName ) {
return blockList;
ellatrix marked this conversation as resolved.
Show resolved Hide resolved
}

return (
<div className={ classes }>
{ ! templateInProcess && (
<BlockList rootClientId={ clientId } { ...props } />
) }
<div className="block-editor-inner-blocks" ref={ forwardedRef }>
{ blockList }
</div>
);
}
}

InnerBlocks = compose( [
const ComposedInnerBlocks = compose( [
withViewportMatch( { isSmallScreen: '< medium' } ),
withBlockEditContext( ( context ) => pick( context, [ 'clientId' ] ) ),
withSelect( ( select, ownProps ) => {
Expand Down Expand Up @@ -228,15 +244,22 @@ InnerBlocks = compose( [
} ),
] )( InnerBlocks );

const ForwardedInnerBlocks = forwardRef( ( props, ref ) => {
const fallbackRef = useRef();
return (
<ComposedInnerBlocks { ...props } forwardedRef={ ref || fallbackRef } />
);
} );

// Expose default appender placeholders as components.
InnerBlocks.DefaultBlockAppender = DefaultBlockAppender;
InnerBlocks.ButtonBlockAppender = ButtonBlockAppender;
ForwardedInnerBlocks.DefaultBlockAppender = DefaultBlockAppender;
ForwardedInnerBlocks.ButtonBlockAppender = ButtonBlockAppender;

InnerBlocks.Content = withBlockContentContext( ( { BlockContent } ) => (
<BlockContent />
) );
ForwardedInnerBlocks.Content = withBlockContentContext(
( { BlockContent } ) => <BlockContent />
);

/**
* @see https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/inner-blocks/README.md
*/
export default InnerBlocks;
export default ForwardedInnerBlocks;
4 changes: 2 additions & 2 deletions packages/block-editor/src/components/inner-blocks/style.scss
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Add clickable overlay to blocks with nesting.
// This makes it easy to select all layers of the block.
.block-editor-inner-blocks.has-overlay {
.block-editor-block-list__layout.has-overlay {
&::after {
content: "";
position: absolute;
top: -$block-padding;
right: -$block-padding;
bottom: -$block-padding;
left: -$block-padding;
z-index: z-index(".block-editor-inner-blocks.has-overlay::after");
z-index: z-index(".block-editor-block-list__layout.has-overlay::after");
}
}

Expand Down
5 changes: 4 additions & 1 deletion packages/block-editor/src/utils/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ export function isInsideRootBlock( blockElement, element ) {
* @return {boolean} Whether element contains inner blocks.
*/
export function hasInnerBlocksContext( element ) {
return !! element.querySelector( '.block-editor-block-list__layout' );
return (
element.classList.contains( 'block-editor-block-list__layout' ) ||
!! element.querySelector( '.block-editor-block-list__layout' )
);
Comment on lines 78 to +82
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are tests for this function. Probably should have been updated.

}

/**
Expand Down
14 changes: 11 additions & 3 deletions packages/block-library/src/column/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
BlockControls,
BlockVerticalAlignmentToolbar,
InspectorControls,
__experimentalBlock as Block,
} from '@wordpress/block-editor';
import { PanelBody, RangeControl } from '@wordpress/components';
import { withDispatch, withSelect } from '@wordpress/data';
Expand All @@ -30,8 +31,10 @@ function ColumnEdit( {
[ `is-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment,
} );

const hasWidth = Number.isFinite( width );

return (
<div className={ classes }>
<>
<BlockControls>
<BlockVerticalAlignmentToolbar
onChange={ updateAlignment }
Expand Down Expand Up @@ -61,11 +64,16 @@ function ColumnEdit( {
templateLock={ false }
renderAppender={
hasChildBlocks
? undefined
? false
: () => <InnerBlocks.ButtonBlockAppender />
}
__experimentalTagName={ Block.div }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't introduced here, but it's not clear to me why we limit to a predefined set of tag names, vs. some sort of factor function (createBlockComponent( tagName )) or just rendering some element like <BlockComponent tagName="div" /> here. What if I wanted a section block?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still experimental, but the intention is to add all tags.

__experimentalPassedProps={ {
className: classes,
style: hasWidth ? { flexBasis: width + '%' } : undefined,
} }
/>
</div>
</>
);
}

Expand Down
12 changes: 1 addition & 11 deletions packages/block-library/src/column/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,7 @@ export const settings = {
inserter: false,
reusable: false,
html: false,
},
getEditWrapperProps( attributes ) {
const { width } = attributes;
if ( Number.isFinite( width ) ) {
return {
style: {
flexBasis: width + '%',
},
'data-has-explicit-width': true,
};
}
lightBlockWrapper: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this experimental? Where do we document it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it should have been prefixed as well with __experimental.

},
edit,
save,
Expand Down
56 changes: 31 additions & 25 deletions packages/block-library/src/columns/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
BlockVerticalAlignmentToolbar,
__experimentalBlockVariationPicker,
__experimentalUseColors,
__experimentalBlock as Block,
} from '@wordpress/block-editor';
import { withDispatch, useDispatch, useSelect } from '@wordpress/data';
import { createBlock } from '@wordpress/blocks';
Expand Down Expand Up @@ -103,12 +104,15 @@ function ColumnsEditContainer( {
{ InspectorControlsColorPanel }
<BackgroundColor>
<TextColor>
<div className={ classes } ref={ ref }>
<InnerBlocks
allowedBlocks={ ALLOWED_BLOCKS }
__experimentalMoverDirection="horizontal"
/>
</div>
<InnerBlocks
allowedBlocks={ ALLOWED_BLOCKS }
__experimentalMoverDirection="horizontal"
ref={ ref }
__experimentalTagName={ Block.div }
__experimentalPassedProps={ {
className: classes,
} }
/>
</TextColor>
</BackgroundColor>
</>
Expand Down Expand Up @@ -255,25 +259,27 @@ const ColumnsEdit = ( props ) => {
}

return (
<__experimentalBlockVariationPicker
icon={ get( blockType, [ 'icon', 'src' ] ) }
label={ get( blockType, [ 'title' ] ) }
variations={ variations }
onSelect={ ( nextVariation = defaultVariation ) => {
if ( nextVariation.attributes ) {
props.setAttributes( nextVariation.attributes );
}
if ( nextVariation.innerBlocks ) {
replaceInnerBlocks(
props.clientId,
createBlocksFromInnerBlocksTemplate(
nextVariation.innerBlocks
)
);
}
} }
allowSkip
/>
<Block.div>
<__experimentalBlockVariationPicker
icon={ get( blockType, [ 'icon', 'src' ] ) }
label={ get( blockType, [ 'title' ] ) }
variations={ variations }
onSelect={ ( nextVariation = defaultVariation ) => {
if ( nextVariation.attributes ) {
props.setAttributes( nextVariation.attributes );
}
if ( nextVariation.innerBlocks ) {
replaceInnerBlocks(
props.clientId,
createBlocksFromInnerBlocksTemplate(
nextVariation.innerBlocks
)
);
}
} }
allowSkip
/>
</Block.div>
);
};

Expand Down
Loading