diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 4e6cc0a134ed9..9a3f207b6be01 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -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, diff --git a/packages/block-editor/src/components/block-list/block-wrapper.js b/packages/block-editor/src/components/block-list/block-wrapper.js index bcd5d4c38929f..ff54e2f7e4278 100644 --- a/packages/block-editor/src/components/block-list/block-wrapper.js +++ b/packages/block-editor/src/components/block-list/block-wrapper.js @@ -48,6 +48,7 @@ const BlockComponent = forwardRef( name, mode, blockTitle, + wrapperProps, } = useContext( BlockContext ); const { initialPosition } = useSelect( ( select ) => { @@ -203,6 +204,7 @@ const BlockComponent = forwardRef( // Overrideable props. aria-label={ blockLabel } role="group" + { ...wrapperProps } { ...props } id={ blockElementId } ref={ wrapper } diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index a18d1b4e68b02..a78254858437e 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -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 =
{ blockEdit }
; } @@ -163,6 +163,7 @@ function BlockListBlock( { name, mode, blockTitle: blockType.title, + wrapperProps, }; const memoizedValue = useMemo( () => value, Object.values( value ) ); diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js index 02fc6d6806fb0..cbc95d7714c76 100644 --- a/packages/block-editor/src/components/block-list/index.js +++ b/packages/block-editor/src/components/block-list/index.js @@ -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 @@ -23,21 +23,18 @@ import useBlockDropZone from '../block-drop-zone'; */ const BLOCK_ANIMATION_THRESHOLD = 200; -const forceSyncUpdates = ( WrappedComponent ) => ( props ) => { - return ( - - - - ); -}; - -function BlockList( { - className, - rootClientId, - isDraggable, - renderAppender, - __experimentalUIParts = {}, -} ) { +function BlockList( + { + className, + rootClientId, + isDraggable, + renderAppender, + __experimentalUIParts = {}, + __experimentalTagName = 'div', + __experimentalPassedProps = {}, + }, + ref +) { function selector( select ) { const { getBlockOrder, @@ -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, @@ -82,10 +78,12 @@ function BlockList( { return ( @@ -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(); + return ( + + + + ); +} ); diff --git a/packages/block-editor/src/components/block-list/style.scss b/packages/block-editor/src/components/block-list/style.scss index e1403df41d364..69739edde7753 100644 --- a/packages/block-editor/src/components/block-list/style.scss +++ b/packages/block-editor/src/components/block-list/style.scss @@ -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; } } diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index c8a54479d420d..55f2890e8d8da 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -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, @@ -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 = ( + + ); + + if ( props.__experimentalTagName ) { + return blockList; + } + return ( -
- { ! templateInProcess && ( - - ) } +
+ { blockList }
); } } -InnerBlocks = compose( [ +const ComposedInnerBlocks = compose( [ withViewportMatch( { isSmallScreen: '< medium' } ), withBlockEditContext( ( context ) => pick( context, [ 'clientId' ] ) ), withSelect( ( select, ownProps ) => { @@ -228,15 +244,22 @@ InnerBlocks = compose( [ } ), ] )( InnerBlocks ); +const ForwardedInnerBlocks = forwardRef( ( props, ref ) => { + const fallbackRef = useRef(); + return ( + + ); +} ); + // Expose default appender placeholders as components. -InnerBlocks.DefaultBlockAppender = DefaultBlockAppender; -InnerBlocks.ButtonBlockAppender = ButtonBlockAppender; +ForwardedInnerBlocks.DefaultBlockAppender = DefaultBlockAppender; +ForwardedInnerBlocks.ButtonBlockAppender = ButtonBlockAppender; -InnerBlocks.Content = withBlockContentContext( ( { BlockContent } ) => ( - -) ); +ForwardedInnerBlocks.Content = withBlockContentContext( + ( { BlockContent } ) => +); /** * @see https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/inner-blocks/README.md */ -export default InnerBlocks; +export default ForwardedInnerBlocks; diff --git a/packages/block-editor/src/components/inner-blocks/style.scss b/packages/block-editor/src/components/inner-blocks/style.scss index 4aaf47d696335..084da1dcd6ee2 100644 --- a/packages/block-editor/src/components/inner-blocks/style.scss +++ b/packages/block-editor/src/components/inner-blocks/style.scss @@ -1,6 +1,6 @@ // 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; @@ -8,7 +8,7 @@ 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"); } } diff --git a/packages/block-editor/src/utils/dom.js b/packages/block-editor/src/utils/dom.js index a12ffc276b16e..1ea7c881b494d 100644 --- a/packages/block-editor/src/utils/dom.js +++ b/packages/block-editor/src/utils/dom.js @@ -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' ) + ); } /** diff --git a/packages/block-library/src/column/edit.js b/packages/block-library/src/column/edit.js index 979d01115c741..73f11aa5f9e3e 100644 --- a/packages/block-library/src/column/edit.js +++ b/packages/block-library/src/column/edit.js @@ -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'; @@ -30,8 +31,10 @@ function ColumnEdit( { [ `is-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, } ); + const hasWidth = Number.isFinite( width ); + return ( -
+ <> } + __experimentalTagName={ Block.div } + __experimentalPassedProps={ { + className: classes, + style: hasWidth ? { flexBasis: width + '%' } : undefined, + } } /> -
+ ); } diff --git a/packages/block-library/src/column/index.js b/packages/block-library/src/column/index.js index 7ed663db38558..3df7bbde1dcf6 100644 --- a/packages/block-library/src/column/index.js +++ b/packages/block-library/src/column/index.js @@ -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, }, edit, save, diff --git a/packages/block-library/src/columns/edit.js b/packages/block-library/src/columns/edit.js index 6746a95e09a88..c4e4047980446 100644 --- a/packages/block-library/src/columns/edit.js +++ b/packages/block-library/src/columns/edit.js @@ -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'; @@ -103,12 +104,15 @@ function ColumnsEditContainer( { { InspectorControlsColorPanel } -
- -
+
@@ -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 - /> + + <__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 + /> + ); }; diff --git a/packages/block-library/src/columns/editor.scss b/packages/block-library/src/columns/editor.scss index df8ae911d90a4..73231a940dd83 100644 --- a/packages/block-library/src/columns/editor.scss +++ b/packages/block-library/src/columns/editor.scss @@ -1,177 +1,38 @@ -// These margins make sure that nested blocks stack/overlay with the parent block chrome -// This is sort of an experiment at making sure the editor looks as much like the end result as possible -// Potentially the rules here can apply to all nested blocks and enable stacking, in which case it should be moved elsewhere -// When using CSS grid, margins do not collapse on the container. -.wp-block-columns .block-editor-block-list__layout { - // This max-width is used to constrain the main editor column, it should not cascade into columns - .block-editor-block-list__block { - max-width: none; - } +// This max-width is used to constrain the main editor column, it should not +// cascade into columns. +.wp-block-columns .wp-block { + max-width: none; } -.wp-block-columns { - display: block; - - > .block-editor-inner-blocks > .block-editor-block-list__layout { - display: flex; - - // Responsiveness: Allow wrapping on mobile. - flex-wrap: wrap; - - @include break-medium() { - flex-wrap: nowrap; - } - // Set full heights on Columns to enable vertical alignment preview - > [data-type="core/column"], - > [data-type="core/column"] .block-core-columns { - display: flex; - flex-direction: column; - - // This flex rule fixes an issue in IE11. - flex: 1 1 auto; - - // IE11 does not support `position: sticky`, so we use it here to serve correct Flex rules to modern browsers. - @supports (position: sticky) { - flex: 1; - } - } - - // Adjust the individual column block. - > [data-type="core/column"] { - - // On mobile, only a single column is shown, so match adjacent block paddings. - padding-left: 0; - padding-right: 0; - margin-left: -$block-padding; - margin-right: -$block-padding; - - // Zero out margins. - margin-top: 0; - margin-bottom: 0; - - // Prevent the columns from growing wider than their distributed sizes. - min-width: 0; - - // Prevent long unbroken words from overflowing. - word-break: break-word; // For back-compat. - overflow-wrap: break-word; // New standard. - - // Responsiveness: Show at most one columns on mobile. - flex-basis: 100%; - - // Between mobile and large viewports, allow 2 columns. - @include break-small() { - flex-basis: calc(50% - (#{$grid-unit-20})); - flex-grow: 0; - margin-left: 0; - margin-right: 0; - } - - // At large viewports, show all columns horizontally. - @include break-medium() { - // Available space should be divided equally amongst columns - // without an assigned width. This is achieved by assigning a - // flex basis that is consistent (equal), would not cause the - // sum total of column widths to exceed 100%, and which would - // cede to a column with an assigned width. The `flex-grow` - // allows columns to maximally and equally occupy space - // remaining after subtracting the space occupied by columns - // with explicit widths (if any exist). - flex-basis: 0; - flex-grow: 1; - - // Columns with an explicitly-assigned width should maintain - // their `flex-basis` width and not grow. - &[data-has-explicit-width] { - flex-grow: 0; - } - } - - // Add space between columns. Themes can customize this if they wish to work differently. - // This has to match the same padding applied in style.scss. - // Only apply this beyond the mobile breakpoint, as there's only a single column on mobile. - @include break-small() { - &:nth-child(even) { - margin-left: calc(#{$grid-unit-20 * 2}); - } - } - - // When columns are in a single row, add space before all except the first. - @include break-medium() { - &:not(:first-child) { - margin-left: calc(#{$grid-unit-20 * 2}); - } - } - - // Remove Block "padding" so individual Column is flush with parent Columns - &::before { - left: 0; - right: 0; - } - - // The Columns block is a flex-container, therefore it nullifies margin collapsing. - // Therefore, blocks inside this will appear to create a double margin. - // We compensate for this using negative margins. - > .block-core-columns > .block-editor-inner-blocks { - margin-top: -$default-block-margin; - margin-bottom: -$default-block-margin; - } - } - } +// Ideally this shouldn't be necessary. There should be no default margins in +// the editor. +.editor-styles-wrapper .block-editor-block-list__block.wp-block-column, +.editor-styles-wrapper .block-editor-block-list__block.wp-block-columns { + margin-top: 0; + margin-bottom: 0; } -/** - * Columns act as as a "passthrough container" - * and therefore has its vertical margins/padding removed via negative margins - * therefore we need to compensate for this here by doubling the spacing on the - * vertical to ensure there is equal visual spacing around the inserter. Note there - * is no formal API for a "passthrough" Block so this is an edge case overide - */ -[data-type="core/columns"] { - - .block-list-appender { - margin-top: $block-padding*2; - margin-bottom: $block-padding*2; +// To do: remove horizontal margin override by the editor. +@include break-small() { + .editor-styles-wrapper + .block-editor-block-list__block.wp-block-column:nth-child(even) { + margin-left: $grid-unit-20 * 2; } } -/** - * Vertical Alignment Preview - * note: specificity is important here to ensure individual - * * columns alignment is prioritised over parent column alignment - * - */ -.are-vertically-aligned-top .block-core-columns, -div.block-core-columns.is-vertically-aligned-top { - justify-content: flex-start; -} - -.are-vertically-aligned-center .block-core-columns, -div.block-core-columns.is-vertically-aligned-center { - justify-content: center; -} - -.are-vertically-aligned-bottom .block-core-columns, -div.block-core-columns.is-vertically-aligned-bottom { - justify-content: flex-end; +@include break-medium() { + .editor-styles-wrapper + .block-editor-block-list__block.wp-block-column:not(:first-child) { + margin-left: $grid-unit-20 * 2; + } } -/** - * Make single Column overlay not extend past boundaries of parent - */ -.block-core-columns > .block-editor-inner-blocks.has-overlay::after { - left: 0; - right: 0; +// This is the style used on the front-end, which ideally should be loaded in +// the editor too. +.wp-block-column > *:first-child { + margin-top: 0 !important; } -// Fullwide: show margin left/right to ensure there's room for the side UI. -// This is not a 1:1 preview with the front-end where these margins would presumably be zero. -[data-type="core/columns"][data-align="full"] .wp-block-columns { - padding-left: $block-padding; - padding-right: $block-padding; - - @include break-small() { - padding-left: $block-container-side-padding; - padding-right: $block-container-side-padding; - } +.wp-block-column > *:last-child { + margin-bottom: 0 !important; } diff --git a/packages/block-library/src/columns/index.js b/packages/block-library/src/columns/index.js index ff932b86e9846..8d94dcd82ea4e 100644 --- a/packages/block-library/src/columns/index.js +++ b/packages/block-library/src/columns/index.js @@ -26,6 +26,7 @@ export const settings = { supports: { align: [ 'wide', 'full' ], html: false, + lightBlockWrapper: true, }, variations, example: { diff --git a/packages/block-library/src/columns/style.scss b/packages/block-library/src/columns/style.scss index 2c5d57220c547..9760af1ca0ff4 100644 --- a/packages/block-library/src/columns/style.scss +++ b/packages/block-library/src/columns/style.scss @@ -56,7 +56,7 @@ // Columns with an explicitly-assigned width should maintain their // `flex-basis` width and not grow. - &[style] { + &[style*="flex-basis"] { flex-grow: 0; }