From 672b5aaa26f9ee1867106c7f845aab84b1e59173 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 8 Feb 2024 16:03:24 +0400 Subject: [PATCH] Columns: Batch vertical alignment updates (#58801) * Columns: Use hooks instead of HoC * Columns: Batch vertical alignment updates Co-authored-by: Mamaduka Co-authored-by: t-hamano --- packages/block-library/src/columns/edit.js | 200 ++++++++++----------- 1 file changed, 90 insertions(+), 110 deletions(-) diff --git a/packages/block-library/src/columns/edit.js b/packages/block-library/src/columns/edit.js index 73824bf4da1154..95e0ba43efb438 100644 --- a/packages/block-library/src/columns/edit.js +++ b/packages/block-library/src/columns/edit.js @@ -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, @@ -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 { @@ -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, @@ -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 ( <> @@ -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 ) => { @@ -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 ; };