Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 25 additions & 47 deletions packages/block-library/src/column/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* External dependencies
*/
import classnames from 'classnames';
import { forEach, find, difference } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -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,
Expand All @@ -55,6 +43,7 @@ function ColumnEdit( {
<RangeControl
label={ __( 'Percentage width' ) }
value={ width || '' }
initialPosition={ 0 }
Copy link
Contributor

Choose a reason for hiding this comment

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

When is this visible?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should be visible when a column has no explicit width set.

onChange={ updateWidth }
min={ 0 }
max={ 100 }
Expand Down Expand Up @@ -113,44 +102,33 @@ export default compose(
'core/block-editor'
);

// Constrain or expand siblings to account for gain or loss of
// total columns area.
const columns = getBlocks( getBlockRootClientId( clientId ) );
const adjacentColumns = getAdjacentBlocks( columns, clientId );

// The occupied width is calculated as the sum of the new width
// and the total width of blocks _not_ in the adjacent set.
const occupiedWidth =
width +
getTotalColumnsWidth(
difference( columns, [
find( columns, { clientId } ),
...adjacentColumns,
] )
);
// Update column width.
updateBlockAttributes( clientId, { width } );

// Compute _all_ next column widths, in case the updated column
// is in the middle of a set of columns which don't yet have
// any explicit widths assigned (include updates to those not
// part of the adjacent blocks).
const nextColumnWidths = {
...getColumnWidths( columns, columns.length ),
[ clientId ]: toWidthPrecision( width ),
...getRedistributedColumnWidths(
adjacentColumns,
100 - occupiedWidth,
columns.length
),
};
const rootClientId = getBlockRootClientId( clientId );
const columns = getBlocks( rootClientId );
// Get all explicit, positive, column widths.
const columnWidths = columns.map( ( columnWidth ) => {
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: '' } );
}
);
} );
},
};
} )
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/columns/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "core/columns",
"category": "layout",
"attributes": {
"columnsTemplate": {
"type": "string"
},
"verticalAlignment": {
"type": "string"
},
Expand Down
63 changes: 62 additions & 1 deletion packages/block-library/src/columns/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 ) => {
Expand All @@ -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 (
<>
<BlockControls>
Expand All @@ -91,7 +152,7 @@ function ColumnsEditContainer( {
</InspectorControls>
{ InspectorControlsColorPanel }
<BackgroundColor>
<div className={ classes }>
<div ref={ wrapperRef } className={ classes }>
<InnerBlocks
templateLock="all"
allowedBlocks={ ALLOWED_BLOCKS }
Expand Down
97 changes: 25 additions & 72 deletions packages/block-library/src/columns/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,36 @@

> .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 {
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions packages/block-library/src/columns/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function save( { attributes } ) {
const {
verticalAlignment,
backgroundColor,
columnsTemplate,
customBackgroundColor,
} = attributes;

Expand All @@ -28,6 +29,7 @@ export default function save( { attributes } ) {

const style = {
backgroundColor: backgroundClass ? undefined : customBackgroundColor,
'--columns-template': columnsTemplate,
};

return (
Expand Down
Loading