diff --git a/packages/block-library/src/column/edit.js b/packages/block-library/src/column/edit.js index f200ba2bd02ec1..6711f118ff9ad2 100644 --- a/packages/block-library/src/column/edit.js +++ b/packages/block-library/src/column/edit.js @@ -2,7 +2,6 @@ * External dependencies */ import classnames from 'classnames'; -import { forEach, find, difference } from 'lodash'; /** * WordPress dependencies @@ -18,17 +17,6 @@ import { withDispatch, withSelect } from '@wordpress/data'; import { compose } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; -/** - * Internal dependencies - */ -import { - toWidthPrecision, - getTotalColumnsWidth, - getColumnWidths, - getAdjacentBlocks, - getRedistributedColumnWidths, -} from '../columns/utils'; - function ColumnEdit( { attributes, className, @@ -55,6 +43,7 @@ function ColumnEdit( { { + if ( ! columnWidth || columnWidth < 0 ) { + return null; + } + return columnWidth; + } ); + // Check if sum of all column widths exceeds 100. (We are using 'fr' units but treating them as percentages.) + const resetAdjacentColumns = + columnWidths.reduce( + ( total, columnWidth ) => total + columnWidth + ) > 100; - forEach( - nextColumnWidths, - ( nextColumnWidth, columnClientId ) => { - updateBlockAttributes( columnClientId, { - width: nextColumnWidth, - } ); + // If total widths exceed 100, reset adjacent column widths. + columns.forEach( ( column ) => { + if ( + ( resetAdjacentColumns || ! column.attributes.width ) && + column.clientId !== clientId + ) { + updateBlockAttributes( column.clientId, { width: '' } ); } - ); + } ); }, }; } ) diff --git a/packages/block-library/src/columns/block.json b/packages/block-library/src/columns/block.json index 022d64285361e9..75f017fa36c083 100644 --- a/packages/block-library/src/columns/block.json +++ b/packages/block-library/src/columns/block.json @@ -2,6 +2,9 @@ "name": "core/columns", "category": "layout", "attributes": { + "columnsTemplate": { + "type": "string" + }, "verticalAlignment": { "type": "string" }, diff --git a/packages/block-library/src/columns/edit.js b/packages/block-library/src/columns/edit.js index 98c4aac327c6c4..d40c3aef1fb8a8 100644 --- a/packages/block-library/src/columns/edit.js +++ b/packages/block-library/src/columns/edit.js @@ -19,6 +19,7 @@ import { } from '@wordpress/block-editor'; import { withDispatch, useDispatch, useSelect } from '@wordpress/data'; import { createBlock } from '@wordpress/blocks'; +import { useRef, useEffect } from '@wordpress/element'; /** * Internal dependencies @@ -44,11 +45,13 @@ const ALLOWED_BLOCKS = [ 'core/column' ]; function ColumnsEditContainer( { attributes, className, + setAttributes, updateAlignment, updateColumns, clientId, } ) { const { verticalAlignment } = attributes; + const wrapperRef = useRef(); const { count } = useSelect( ( select ) => { @@ -70,6 +73,64 @@ function ColumnsEditContainer( { [ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, } ); + const { childColumnsWidths } = useSelect( + ( select ) => { + const { getBlockOrder, getBlockAttributes } = select( + 'core/block-editor' + ); + const childColumns = getBlockOrder( clientId ); + + return { + childColumnsWidths: childColumns.map( + ( block ) => getBlockAttributes( block ).width + ), + }; + }, + [ clientId ] + ); + + let gridTemplateColumns = ``; + // Remove any negative widths. + const cleanedWidths = childColumnsWidths.map( ( width ) => { + if ( ! width || width < 0 ) { + return null; + } + return width; + } ); + const colsWithoutWidth = cleanedWidths.filter( ( width ) => ! width ) + .length; + + // We're not checking if total col width is > 100 because there's no way of deciding which columns to reset at this point. + // This logic will work like percentage widths (taking into account the grid-gap) for all columns with total width <= 100. + // For columns with total width > 100, the fr units work as a fraction of whatever the total is, so the layout never breaks. + const leftoverWidth = Math.abs( + 100 - cleanedWidths.reduce( ( total, column ) => total + column ) + ); + + cleanedWidths.forEach( ( width ) => { + if ( ! width ) { + // Set columns without explicit width to a fraction of the remaining width. + gridTemplateColumns += `${ leftoverWidth / colsWithoutWidth }fr `; + } else { + gridTemplateColumns += `${ width }fr `; + } + } ); + + useEffect( () => { + setAttributes( { columnsTemplate: gridTemplateColumns } ); + }, [] ); + + const wrapper = wrapperRef.current; + if ( wrapper ) { + const layoutWrapper = wrapper.querySelector( + '.block-editor-block-list__layout' + ); + layoutWrapper.style.setProperty( + '--columns-template', + gridTemplateColumns + ); + } + return ( <> @@ -91,7 +152,7 @@ function ColumnsEditContainer( { { InspectorControlsColorPanel } -
+
.block-editor-inner-blocks > .block-editor-block-list__layout { display: flex; - - // Responsiveness: Allow wrapping on mobile. flex-wrap: wrap; + margin-bottom: $default-block-margin; @include break-medium() { flex-wrap: nowrap; } + + @supports (display: grid) { + --columns-template: 1fr; + display: grid; + column-gap: $grid-size-large * 2; + @include break-medium() { + grid-template-columns: var(--columns-template); + } + } + + > [data-type="core/column"] { + margin: 0; + + @include break-medium() { + + [data-type="core/column"] { + margin-left: $grid-size-large * 2; + + @supports (display: grid) { + margin-left: 0; + } + } + } + } + // Set full heights on Columns to enable vertical alignment preview > [data-type="core/column"], > [data-type="core/column"] .block-core-columns { @@ -45,83 +68,13 @@ // 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%; - - // Beyond mobile, allow 2 columns. - @include break-small() { - flex-basis: calc(50% - (#{$grid-size-large})); - flex-grow: 0; - margin-left: 0; - margin-right: 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-size-large * 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-size-large * 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; - } } } } -/** - * 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; - } -} - /** * Vertical Alignment Preview * note: specificity is important here to ensure individual diff --git a/packages/block-library/src/columns/save.js b/packages/block-library/src/columns/save.js index 41d0f8d26e0e70..3940f5184ddfaa 100644 --- a/packages/block-library/src/columns/save.js +++ b/packages/block-library/src/columns/save.js @@ -12,6 +12,7 @@ export default function save( { attributes } ) { const { verticalAlignment, backgroundColor, + columnsTemplate, customBackgroundColor, } = attributes; @@ -28,6 +29,7 @@ export default function save( { attributes } ) { const style = { backgroundColor: backgroundClass ? undefined : customBackgroundColor, + '--columns-template': columnsTemplate, }; return ( diff --git a/packages/block-library/src/columns/style.scss b/packages/block-library/src/columns/style.scss index 899414c24f4071..fb023e75e0165f 100644 --- a/packages/block-library/src/columns/style.scss +++ b/packages/block-library/src/columns/style.scss @@ -1,9 +1,8 @@ + .wp-block-columns { display: flex; - margin-bottom: $default-block-margin; - - // Responsiveness: Allow wrapping on mobile. flex-wrap: wrap; + margin-bottom: $default-block-margin; @include break-medium() { flex-wrap: nowrap; @@ -15,43 +14,39 @@ } .wp-block-column { - flex-grow: 1; - - @media (max-width: #{ ($break-small - 1) }) { - // Responsiveness: Show at most one columns on mobile. This must be - // important since the Column assigns its own width as an inline style. - flex-basis: 100% !important; - } - - // 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. - @include break-small() { - - // Beyond mobile, allow 2 columns. - flex-basis: calc(50% - #{$grid-size-large}); - flex-grow: 0; - - // Add space between the multiple columns. Themes can customize this if they wish to work differently. - // Only apply this beyond the mobile breakpoint, as there's only a single column on mobile. - &:nth-child(even) { + @include break-medium() { + + .wp-block-column { margin-left: $grid-size-large * 2; } } +} - @include break-medium() { +@supports (display: grid) { + .wp-block-columns { + --columns-template: 1fr; - // When columns are in a single row, add space before all except the first. - &:not(:first-child) { - margin-left: $grid-size-large * 2; + display: grid; + column-gap: $grid-size-large * 2; + + @include break-medium() { + grid-template-columns: var(--columns-template); + } + } + + .wp-block-column { + @include break-medium() { + + .wp-block-column { + margin-left: 0; + } } } } + /** * All Columns Alignment */ diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/templates.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/templates.test.js.snap index f089390857781a..bdd9fc44da5bd3 100644 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/templates.test.js.snap +++ b/packages/e2e-tests/specs/editor/plugins/__snapshots__/templates.test.js.snap @@ -13,8 +13,8 @@ exports[`templates Using a CPT with a predefined template Should add a custom po

- -
+ +
\\"\\"/
@@ -39,8 +39,8 @@ exports[`templates Using a CPT with a predefined template Should respect user ed

- -
+ +
\\"\\"/
diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap index 4ee1d7710bbe18..166b5682c31fad 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap @@ -11,8 +11,8 @@ exports[`Navigating the block hierarchy should appear and function even without `; exports[`Navigating the block hierarchy should navigate block hierarchy using only the keyboard 1`] = ` -" -
+" +

First column

@@ -31,8 +31,8 @@ exports[`Navigating the block hierarchy should navigate block hierarchy using on `; exports[`Navigating the block hierarchy should navigate using the block hierarchy dropdown menu 1`] = ` -" -
+" +

First column

diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap index 01dc6c0b68269a..48cbf79db7c8c7 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap @@ -5,8 +5,8 @@ exports[`Writing Flow Should navigate inner blocks with arrow keys 1`] = `

First paragraph

- -
+ +

1st col