Skip to content

Commit

Permalink
Columns: Batch vertical alignment updates (#58801)
Browse files Browse the repository at this point in the history
* Columns: Use hooks instead of HoC
* Columns: Batch vertical alignment updates

Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: t-hamano <[email protected]>
  • Loading branch information
3 people authored Feb 8, 2024
1 parent 3f8a858 commit 672b5aa
Showing 1 changed file with 90 additions and 110 deletions.
200 changes: 90 additions & 110 deletions packages/block-library/src/columns/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
useBlockProps,
store as blockEditorStore,
} from '@wordpress/block-editor';
import { withDispatch, useDispatch, useSelect } from '@wordpress/data';
import { useDispatch, useSelect, useRegistry } from '@wordpress/data';
import {
createBlock,
createBlocksFromInnerBlocksTemplate,
Expand All @@ -40,15 +40,8 @@ import {
toWidthPrecision,
} from './utils';

function ColumnsEditContainer( {
attributes,
setAttributes,
updateAlignment,
updateColumns,
clientId,
} ) {
function ColumnsEditContainer( { attributes, setAttributes, clientId } ) {
const { isStackedOnMobile, verticalAlignment, templateLock } = attributes;

const { count, canInsertColumnBlock, minCount } = useSelect(
( select ) => {
const {
Expand Down Expand Up @@ -83,6 +76,11 @@ function ColumnsEditContainer( {
[ clientId ]
);

const registry = useRegistry();
const { getBlocks, getBlockOrder } = useSelect( blockEditorStore );
const { updateBlockAttributes, replaceInnerBlocks } =
useDispatch( blockEditorStore );

const classes = classnames( {
[ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment,
[ `is-not-stacked-on-mobile` ]: ! isStackedOnMobile,
Expand All @@ -97,6 +95,88 @@ function ColumnsEditContainer( {
templateLock,
} );

/**
* Update all child Column blocks with a new vertical alignment setting
* based on whatever alignment is passed in. This allows change to parent
* to overide anything set on a individual column basis.
*
* @param {string} newVerticalAlignment The vertical alignment setting.
*/
function updateAlignment( newVerticalAlignment ) {
const innerBlockClientIds = getBlockOrder( clientId );

// Update own and child Column block vertical alignments.
// This is a single action; the batching prevents creating multiple history records.
registry.batch( () => {
setAttributes( { verticalAlignment: newVerticalAlignment } );
updateBlockAttributes( innerBlockClientIds, {
verticalAlignment: newVerticalAlignment,
} );
} );
}

/**
* Updates the column count, including necessary revisions to child Column
* blocks to grant required or redistribute available space.
*
* @param {number} previousColumns Previous column count.
* @param {number} newColumns New column count.
*/
function updateColumns( previousColumns, newColumns ) {
let innerBlocks = getBlocks( clientId );
const hasExplicitWidths = hasExplicitPercentColumnWidths( innerBlocks );

// Redistribute available width for existing inner blocks.
const isAddingColumn = newColumns > previousColumns;

if ( isAddingColumn && hasExplicitWidths ) {
// If adding a new column, assign width to the new column equal to
// as if it were `1 / columns` of the total available space.
const newColumnWidth = toWidthPrecision( 100 / newColumns );

// Redistribute in consideration of pending block insertion as
// constraining the available working width.
const widths = getRedistributedColumnWidths(
innerBlocks,
100 - newColumnWidth
);

innerBlocks = [
...getMappedColumnWidths( innerBlocks, widths ),
...Array.from( {
length: newColumns - previousColumns,
} ).map( () => {
return createBlock( 'core/column', {
width: `${ newColumnWidth }%`,
} );
} ),
];
} else if ( isAddingColumn ) {
innerBlocks = [
...innerBlocks,
...Array.from( {
length: newColumns - previousColumns,
} ).map( () => {
return createBlock( 'core/column' );
} ),
];
} else if ( newColumns < previousColumns ) {
// The removed column will be the last of the inner blocks.
innerBlocks = innerBlocks.slice(
0,
-( previousColumns - newColumns )
);
if ( hasExplicitWidths ) {
// Redistribute as if block is already removed.
const widths = getRedistributedColumnWidths( innerBlocks, 100 );

innerBlocks = getMappedColumnWidths( innerBlocks, widths );
}
}

replaceInnerBlocks( clientId, innerBlocks );
}

return (
<>
<BlockControls>
Expand Down Expand Up @@ -152,104 +232,6 @@ function ColumnsEditContainer( {
);
}

const ColumnsEditContainerWrapper = withDispatch(
( dispatch, ownProps, registry ) => ( {
/**
* Update all child Column blocks with a new vertical alignment setting
* based on whatever alignment is passed in. This allows change to parent
* to overide anything set on a individual column basis.
*
* @param {string} verticalAlignment the vertical alignment setting
*/
updateAlignment( verticalAlignment ) {
const { clientId, setAttributes } = ownProps;
const { updateBlockAttributes } = dispatch( blockEditorStore );
const { getBlockOrder } = registry.select( blockEditorStore );

// Update own alignment.
setAttributes( { verticalAlignment } );

// Update all child Column Blocks to match.
const innerBlockClientIds = getBlockOrder( clientId );
innerBlockClientIds.forEach( ( innerBlockClientId ) => {
updateBlockAttributes( innerBlockClientId, {
verticalAlignment,
} );
} );
},

/**
* Updates the column count, including necessary revisions to child Column
* blocks to grant required or redistribute available space.
*
* @param {number} previousColumns Previous column count.
* @param {number} newColumns New column count.
*/
updateColumns( previousColumns, newColumns ) {
const { clientId } = ownProps;
const { replaceInnerBlocks } = dispatch( blockEditorStore );
const { getBlocks } = registry.select( blockEditorStore );

let innerBlocks = getBlocks( clientId );
const hasExplicitWidths =
hasExplicitPercentColumnWidths( innerBlocks );

// Redistribute available width for existing inner blocks.
const isAddingColumn = newColumns > previousColumns;

if ( isAddingColumn && hasExplicitWidths ) {
// If adding a new column, assign width to the new column equal to
// as if it were `1 / columns` of the total available space.
const newColumnWidth = toWidthPrecision( 100 / newColumns );

// Redistribute in consideration of pending block insertion as
// constraining the available working width.
const widths = getRedistributedColumnWidths(
innerBlocks,
100 - newColumnWidth
);

innerBlocks = [
...getMappedColumnWidths( innerBlocks, widths ),
...Array.from( {
length: newColumns - previousColumns,
} ).map( () => {
return createBlock( 'core/column', {
width: `${ newColumnWidth }%`,
} );
} ),
];
} else if ( isAddingColumn ) {
innerBlocks = [
...innerBlocks,
...Array.from( {
length: newColumns - previousColumns,
} ).map( () => {
return createBlock( 'core/column' );
} ),
];
} else if ( newColumns < previousColumns ) {
// The removed column will be the last of the inner blocks.
innerBlocks = innerBlocks.slice(
0,
-( previousColumns - newColumns )
);
if ( hasExplicitWidths ) {
// Redistribute as if block is already removed.
const widths = getRedistributedColumnWidths(
innerBlocks,
100
);

innerBlocks = getMappedColumnWidths( innerBlocks, widths );
}
}

replaceInnerBlocks( clientId, innerBlocks );
},
} )
)( ColumnsEditContainer );

function Placeholder( { clientId, name, setAttributes } ) {
const { blockType, defaultVariation, variations } = useSelect(
( select ) => {
Expand Down Expand Up @@ -303,9 +285,7 @@ const ColumnsEdit = ( props ) => {
select( blockEditorStore ).getBlocks( clientId ).length > 0,
[ clientId ]
);
const Component = hasInnerBlocks
? ColumnsEditContainerWrapper
: Placeholder;
const Component = hasInnerBlocks ? ColumnsEditContainer : Placeholder;

return <Component { ...props } />;
};
Expand Down

0 comments on commit 672b5aa

Please sign in to comment.