Skip to content

Commit

Permalink
Grid: Place new block after currently selected block when using slash…
Browse files Browse the repository at this point in the history
… inserter and splitting text (#63333)

* useGridLayoutSync: Keep layout in sync regardless of whether Grid is selected

* Don't use bulk version of updateBlockAttributes() for now. It seems broken

* Revert "Don't use bulk version of updateBlockAttributes() for now. It seems broken"

This reverts commit 9c5e811.

* useGridLayoutSync: Update placement logic to accomodate slash inserter and block splitting

Co-authored-by: noisysocks <noisysocks@git.wordpress.org>
Co-authored-by: tellthemachines <isabel_brison@git.wordpress.org>
  • Loading branch information
3 people authored Jul 11, 2024
1 parent ad04717 commit f5907ee
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 32 deletions.
93 changes: 66 additions & 27 deletions packages/block-editor/src/components/grid/use-grid-layout-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
* WordPress dependencies
*/
import { useDispatch, useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { useEffect, useMemo } from '@wordpress/element';
import { usePrevious } from '@wordpress/compose';

/**
* Internal dependencies
Expand All @@ -11,13 +12,15 @@ import { store as blockEditorStore } from '../../store';
import { GridRect } from './utils';

export function useGridLayoutSync( { clientId: gridClientId } ) {
const { gridLayout, blockOrder } = useSelect(
const { gridLayout, blockOrder, selectedBlockLayout } = useSelect(
( select ) => {
const { getBlockAttributes, getBlockOrder } =
select( blockEditorStore );
const selectedBlock = select( blockEditorStore ).getSelectedBlock();
return {
gridLayout: getBlockAttributes( gridClientId ).layout ?? {},
blockOrder: getBlockOrder( gridClientId ),
selectedBlockLayout: selectedBlock?.attributes.style?.layout,
};
},
[ gridClientId ]
Expand All @@ -27,27 +30,32 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
const { updateBlockAttributes, __unstableMarkNextChangeAsNotPersistent } =
useDispatch( blockEditorStore );

const selectedBlockRect = useMemo(
() =>
selectedBlockLayout ? new GridRect( selectedBlockLayout ) : null,
[ selectedBlockLayout ]
);

const previouslySelectedBlockRect = usePrevious( selectedBlockRect );

useEffect( () => {
const updates = {};

const { columnCount, rowCount, isManualPlacement } = gridLayout;

if ( isManualPlacement ) {
const rects = [];
if ( gridLayout.isManualPlacement ) {
const occupiedRects = [];

// Respect the position of blocks that already have a columnStart and rowStart value.
for ( const clientId of blockOrder ) {
const attributes = getBlockAttributes( clientId );
const {
columnStart,
rowStart,
columnSpan = 1,
rowSpan = 1,
} = attributes.style?.layout || {};
} = getBlockAttributes( clientId ).style?.layout ?? {};
if ( ! columnStart || ! rowStart ) {
continue;
}
rects.push(
occupiedRects.push(
new GridRect( {
columnStart,
rowStart,
Expand All @@ -65,17 +73,19 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
rowStart,
columnSpan = 1,
rowSpan = 1,
} = attributes.style?.layout || {};
} = attributes.style?.layout ?? {};
if ( columnStart && rowStart ) {
continue;
}
const [ newColumnStart, newRowStart ] = getFirstEmptyCell(
rects,
columnCount,
const [ newColumnStart, newRowStart ] = placeBlock(
occupiedRects,
gridLayout.columnCount,
columnSpan,
rowSpan
rowSpan,
previouslySelectedBlockRect?.columnEnd,
previouslySelectedBlockRect?.rowEnd
);
rects.push(
occupiedRects.push(
new GridRect( {
columnStart: newColumnStart,
rowStart: newRowStart,
Expand All @@ -96,8 +106,13 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
}

// Ensure there's enough rows to fit all blocks.
const bottomMostRow = Math.max( ...rects.map( ( r ) => r.rowEnd ) );
if ( ! rowCount || rowCount < bottomMostRow ) {
const bottomMostRow = Math.max(
...occupiedRects.map( ( r ) => r.rowEnd )
);
if (
! gridLayout.rowCount ||
gridLayout.rowCount < bottomMostRow
) {
updates[ gridClientId ] = {
layout: {
...gridLayout,
Expand All @@ -110,7 +125,7 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
for ( const clientId of blockOrder ) {
const attributes = getBlockAttributes( clientId );
const { columnStart, rowStart, ...layout } =
attributes.style?.layout || {};
attributes.style?.layout ?? {};
// Only update attributes if columnStart or rowStart are set.
if ( columnStart || rowStart ) {
updates[ clientId ] = {
Expand All @@ -123,7 +138,7 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
}

// Remove row styles in auto mode
if ( rowCount ) {
if ( gridLayout.rowCount ) {
updates[ gridClientId ] = {
layout: {
...gridLayout,
Expand All @@ -146,23 +161,47 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
gridClientId,
gridLayout,
blockOrder,
// Needed for linter:
previouslySelectedBlockRect,
// These won't change, but the linter thinks they might:
__unstableMarkNextChangeAsNotPersistent,
getBlockAttributes,
updateBlockAttributes,
] );
}

function getFirstEmptyCell( rects, columnCount, columnSpan = 1, rowSpan = 1 ) {
for ( let row = 1; ; row++ ) {
for ( let column = 1; column <= columnCount; column++ ) {
const rect = new GridRect( {
/**
* @param {GridRect[]} occupiedRects
* @param {number} gridColumnCount
* @param {number} blockColumnSpan
* @param {number} blockRowSpan
* @param {number?} startColumn
* @param {number?} startRow
*/
function placeBlock(
occupiedRects,
gridColumnCount,
blockColumnSpan,
blockRowSpan,
startColumn = 1,
startRow = 1
) {
for ( let row = startRow; ; row++ ) {
for (
let column = row === startRow ? startColumn : 1;
column <= gridColumnCount;
column++
) {
const candidateRect = new GridRect( {
columnStart: column,
rowStart: row,
columnSpan,
rowSpan,
columnSpan: blockColumnSpan,
rowSpan: blockRowSpan,
} );
if ( ! rects.some( ( r ) => r.intersectsRect( rect ) ) ) {
if (
! occupiedRects.some( ( r ) =>
r.intersectsRect( candidateRect )
)
) {
return [ column, row ];
}
}
Expand Down
8 changes: 3 additions & 5 deletions packages/block-editor/src/hooks/grid-visualizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ function GridTools( { clientId, layout } ) {
};
} );

if ( ! isSelected && ! isDragging ) {
return null;
}

return (
<>
<GridVisualizer clientId={ clientId } parentLayout={ layout } />
<GridLayoutSync clientId={ clientId } />
{ ( isSelected || isDragging ) && (
<GridVisualizer clientId={ clientId } parentLayout={ layout } />
) }
</>
);
}
Expand Down

0 comments on commit f5907ee

Please sign in to comment.