From c0d99f089e0009b84fe383bc53591cbec48b5a4b Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 23 Apr 2024 18:41:23 +1000 Subject: [PATCH 01/13] Fix resizing items to top and left with GridItemResizer --- .../src/components/block-popover/cover.js | 23 +++++++++-- .../grid-visualizer/grid-item-resizer.js | 39 +++++++++++++++++-- .../block-editor/src/hooks/layout-child.js | 1 + 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/components/block-popover/cover.js b/packages/block-editor/src/components/block-popover/cover.js index 6d2d5b8ce1ac0..02c31ca1f2dfe 100644 --- a/packages/block-editor/src/components/block-popover/cover.js +++ b/packages/block-editor/src/components/block-popover/cover.js @@ -10,7 +10,14 @@ import { __unstableUseBlockElement as useBlockElement } from '../block-list/use- import BlockPopover from '.'; function BlockPopoverCover( - { clientId, bottomClientId, children, shift = false, ...props }, + { + clientId, + bottomClientId, + children, + shift = false, + additionalStyles, + ...props + }, ref ) { bottomClientId ??= clientId; @@ -26,7 +33,10 @@ function BlockPopoverCover( { ...props } > { selectedElement && clientId === bottomClientId ? ( - + { children } ) : ( @@ -36,7 +46,11 @@ function BlockPopoverCover( ); } -function CoverContainer( { selectedElement, children } ) { +function CoverContainer( { + selectedElement, + additionalStyles = {}, + children, +} ) { const [ width, setWidth ] = useState( selectedElement.offsetWidth ); const [ height, setHeight ] = useState( selectedElement.offsetHeight ); @@ -54,8 +68,9 @@ function CoverContainer( { selectedElement, children } ) { position: 'absolute', width, height, + ...additionalStyles, }; - }, [ width, height ] ); + }, [ width, height, additionalStyles ] ); return
{ children }
; } diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index 33d677910a712..c0918ee2a525c 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { ResizableBox } from '@wordpress/components'; +import { useState } from '@wordpress/element'; /** * Internal dependencies @@ -10,8 +11,34 @@ import { __unstableUseBlockElement as useBlockElement } from '../block-list/use- import BlockPopoverCover from '../block-popover/cover'; import { getComputedCSS } from './utils'; -export function GridItemResizer( { clientId, onChange } ) { +export function GridItemResizer( { clientId, rootClientId, onChange } ) { const blockElement = useBlockElement( clientId ); + const rootBlockElement = useBlockElement( rootClientId ); + + const [ resizeDirection, setResizeDirection ] = useState( null ); + + const justification = { + right: 'flex-start', + left: 'flex-end', + }; + + const alignment = { + top: 'flex-end', + bottom: 'flex-start', + }; + + const styles = { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + ...( justification[ resizeDirection ] && { + justifyContent: justification[ resizeDirection ], + } ), + ...( alignment[ resizeDirection ] && { + alignItems: alignment[ resizeDirection ], + } ), + }; + if ( ! blockElement ) { return null; } @@ -20,6 +47,7 @@ export function GridItemResizer( { clientId, onChange } ) { className="block-editor-grid-item-resizer" clientId={ clientId } __unstablePopoverSlot="block-toolbar" + additionalStyles={ styles } > { + setResizeDirection( direction ); + } } onResizeStop={ ( event, direction, boxElement ) => { const gridElement = blockElement.parentElement; const columnGap = parseFloat( diff --git a/packages/block-editor/src/hooks/layout-child.js b/packages/block-editor/src/hooks/layout-child.js index 4fa641bff203a..df883981c696b 100644 --- a/packages/block-editor/src/hooks/layout-child.js +++ b/packages/block-editor/src/hooks/layout-child.js @@ -152,6 +152,7 @@ function ChildLayoutControlsPure( { clientId, style, setAttributes } ) { { setAttributes( { style: { From 333eefc1bbd4841bf8f053c91e2dab87e405a836 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 24 Apr 2024 14:33:28 +1000 Subject: [PATCH 02/13] Add min and max heights and get parent directly. --- .../grid-visualizer/grid-item-resizer.js | 17 +++++++++++------ packages/block-editor/src/hooks/layout-child.js | 1 - 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index c0918ee2a525c..9a8278d75f330 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -11,12 +11,15 @@ import { __unstableUseBlockElement as useBlockElement } from '../block-list/use- import BlockPopoverCover from '../block-popover/cover'; import { getComputedCSS } from './utils'; -export function GridItemResizer( { clientId, rootClientId, onChange } ) { +export function GridItemResizer( { clientId, onChange } ) { const blockElement = useBlockElement( clientId ); - const rootBlockElement = useBlockElement( rootClientId ); - + const rootBlockElement = blockElement.parentElement; const [ resizeDirection, setResizeDirection ] = useState( null ); + if ( ! blockElement ) { + return null; + } + const justification = { right: 'flex-start', left: 'flex-end', @@ -39,9 +42,9 @@ export function GridItemResizer( { clientId, rootClientId, onChange } ) { } ), }; - if ( ! blockElement ) { - return null; - } + const gridHeight = rootBlockElement.offsetHeight; + const blockMinHeight = blockElement.offsetHeight; + return ( { setResizeDirection( direction ); } } diff --git a/packages/block-editor/src/hooks/layout-child.js b/packages/block-editor/src/hooks/layout-child.js index df883981c696b..4fa641bff203a 100644 --- a/packages/block-editor/src/hooks/layout-child.js +++ b/packages/block-editor/src/hooks/layout-child.js @@ -152,7 +152,6 @@ function ChildLayoutControlsPure( { clientId, style, setAttributes } ) { { setAttributes( { style: { From f434924f1da85d10baa0126ed969f28db7f10ee0 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 29 Apr 2024 14:21:05 +1000 Subject: [PATCH 03/13] Fix bounding element logic --- .../grid-visualizer/grid-item-resizer.js | 49 ++++++++++++++++--- .../src/components/grid-visualizer/style.scss | 7 +++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index 9a8278d75f330..b70fc6283e5fa 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { ResizableBox } from '@wordpress/components'; -import { useState } from '@wordpress/element'; +import { useState, useRef } from '@wordpress/element'; /** * Internal dependencies @@ -16,6 +16,14 @@ export function GridItemResizer( { clientId, onChange } ) { const rootBlockElement = blockElement.parentElement; const [ resizeDirection, setResizeDirection ] = useState( null ); + /* + * Resizer dummy is an empty div that exists only so we can + * get the bounding client rect of the resizer element. This is + * necessary because the resizer exists outside of the iframe, so + * its bounding client rect isn't the same as the block element's. + */ + const resizerDummyRef = useRef( null ); + if ( ! blockElement ) { return null; } @@ -42,8 +50,35 @@ export function GridItemResizer( { clientId, onChange } ) { } ), }; - const gridHeight = rootBlockElement.offsetHeight; - const blockMinHeight = blockElement.offsetHeight; + /* + * The bounding element is equivalent to the root block element, but + * its bounding client rect is modified to account for the resizer + * being outside of the editor iframe. + */ + const boundingElement = { + offsetWidth: rootBlockElement.offsetWidth, + offsetHeight: rootBlockElement.offsetHeight, + getBoundingClientRect: () => { + const rootBlockClientRect = + rootBlockElement.getBoundingClientRect(); + const resizerTop = + resizerDummyRef.current?.getBoundingClientRect()?.top; + // Fallback value of 60 to account for editor top bar height. + const heightDifference = resizerTop + ? resizerTop - blockElement.getBoundingClientRect().top + : 60; + return { + bottom: rootBlockClientRect.bottom + heightDifference, + height: rootBlockElement.offsetHeight, + left: rootBlockClientRect.left, + right: rootBlockClientRect.right, + top: rootBlockClientRect.top + heightDifference, + width: rootBlockClientRect.width, + x: rootBlockClientRect.x, + y: rootBlockClientRect.y + heightDifference, + }; + }, + }; return ( { setResizeDirection( direction ); } } @@ -119,6 +152,10 @@ export function GridItemResizer( { clientId, onChange } ) { } ); } } /> +
); } diff --git a/packages/block-editor/src/components/grid-visualizer/style.scss b/packages/block-editor/src/components/grid-visualizer/style.scss index 45140e59c7af9..a50b5552c25a7 100644 --- a/packages/block-editor/src/components/grid-visualizer/style.scss +++ b/packages/block-editor/src/components/grid-visualizer/style.scss @@ -31,3 +31,10 @@ pointer-events: all !important; } } + +.block-editor-grid-item-resizer__dummy { + position: absolute; + width: 100%; + height: 100%; + z-index: -1; +} From 0a6f97b1df8f581a0f9eebaf0fe9d49ee9cc9763 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 29 Apr 2024 15:57:10 +1000 Subject: [PATCH 04/13] Fix resizing logic --- .../src/components/grid-visualizer/grid-item-resizer.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index b70fc6283e5fa..bd1cd0b98ceb0 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -13,7 +13,7 @@ import { getComputedCSS } from './utils'; export function GridItemResizer( { clientId, onChange } ) { const blockElement = useBlockElement( clientId ); - const rootBlockElement = blockElement.parentElement; + const rootBlockElement = blockElement?.parentElement; const [ resizeDirection, setResizeDirection ] = useState( null ); /* @@ -106,6 +106,11 @@ export function GridItemResizer( { clientId, onChange } ) { bounds={ boundingElement } boundsByDirection onResizeStart={ ( event, direction ) => { + /* + * The container justification and alignment need to be set + * according to the direction the resizer is being dragged in, + * so that it resizes in the right direction. + */ setResizeDirection( direction ); } } onResizeStop={ ( event, direction, boxElement ) => { From 84f1cb75b6312c7b3e5ce64718e355bf320a09ab Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 6 May 2024 14:07:38 +1000 Subject: [PATCH 05/13] Resize only to side that's not an edge --- .../grid-visualizer/grid-item-resizer.js | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index bd1cd0b98ceb0..71c96049245bc 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -50,6 +50,9 @@ export function GridItemResizer( { clientId, onChange } ) { } ), }; + const blockClientRect = blockElement.getBoundingClientRect(); + const rootBlockClientRect = rootBlockElement.getBoundingClientRect(); + /* * The bounding element is equivalent to the root block element, but * its bounding client rect is modified to account for the resizer @@ -59,13 +62,11 @@ export function GridItemResizer( { clientId, onChange } ) { offsetWidth: rootBlockElement.offsetWidth, offsetHeight: rootBlockElement.offsetHeight, getBoundingClientRect: () => { - const rootBlockClientRect = - rootBlockElement.getBoundingClientRect(); const resizerTop = resizerDummyRef.current?.getBoundingClientRect()?.top; // Fallback value of 60 to account for editor top bar height. const heightDifference = resizerTop - ? resizerTop - blockElement.getBoundingClientRect().top + ? resizerTop - blockClientRect.top : 60; return { bottom: rootBlockClientRect.bottom + heightDifference, @@ -80,6 +81,15 @@ export function GridItemResizer( { clientId, onChange } ) { }, }; + /* + * Only enable resizing to a side if that side is not on the + * edge of the grid. + */ + const enableTop = blockClientRect.top > rootBlockClientRect.top; + const enableBottom = blockClientRect.bottom < rootBlockClientRect.bottom; + const enableLeft = blockClientRect.left > rootBlockClientRect.left; + const enableRight = blockClientRect.right < rootBlockClientRect.right; + return ( Date: Mon, 6 May 2024 15:12:04 +1000 Subject: [PATCH 06/13] Fix handles becoming sticky --- .../grid-visualizer/grid-item-resizer.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index 71c96049245bc..22c25a1946341 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -122,6 +122,22 @@ export function GridItemResizer( { clientId, onChange } ) { * so that it resizes in the right direction. */ setResizeDirection( direction ); + + /* + * The mouseup event on the resize handle doesn't trigger if the mouse + * isn't directly above the handle, so we try to detect if it happens + * outside the grid and dispatch a mouseup event on the handle. + */ + const rootElementParent = rootBlockElement.parentElement; + rootElementParent.addEventListener( + 'mouseup', + () => { + event.target.dispatchEvent( + new Event( 'mouseup', { bubbles: true } ) + ); + }, + true + ); } } onResizeStop={ ( event, direction, boxElement ) => { const gridElement = blockElement.parentElement; From 19e8ae2622c62f03300b0230d0105a0a8033175d Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 8 May 2024 11:13:50 +1000 Subject: [PATCH 07/13] Try popover ref --- .../components/grid-visualizer/grid-item-resizer.js | 10 +++------- .../src/components/grid-visualizer/style.scss | 6 ------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index 22c25a1946341..99c1908f2c4a4 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -22,7 +22,7 @@ export function GridItemResizer( { clientId, onChange } ) { * necessary because the resizer exists outside of the iframe, so * its bounding client rect isn't the same as the block element's. */ - const resizerDummyRef = useRef( null ); + const resizerRef = useRef( null ); if ( ! blockElement ) { return null; @@ -62,8 +62,7 @@ export function GridItemResizer( { clientId, onChange } ) { offsetWidth: rootBlockElement.offsetWidth, offsetHeight: rootBlockElement.offsetHeight, getBoundingClientRect: () => { - const resizerTop = - resizerDummyRef.current?.getBoundingClientRect()?.top; + const resizerTop = resizerRef.current?.getBoundingClientRect()?.top; // Fallback value of 60 to account for editor top bar height. const heightDifference = resizerTop ? resizerTop - blockClientRect.top @@ -96,6 +95,7 @@ export function GridItemResizer( { clientId, onChange } ) { clientId={ clientId } __unstablePopoverSlot="block-toolbar" additionalStyles={ styles } + __unstableContentRef={ resizerRef } > -
); } diff --git a/packages/block-editor/src/components/grid-visualizer/style.scss b/packages/block-editor/src/components/grid-visualizer/style.scss index a50b5552c25a7..9d5d306eadaa7 100644 --- a/packages/block-editor/src/components/grid-visualizer/style.scss +++ b/packages/block-editor/src/components/grid-visualizer/style.scss @@ -32,9 +32,3 @@ } } -.block-editor-grid-item-resizer__dummy { - position: absolute; - width: 100%; - height: 100%; - z-index: -1; -} From 6957c76feb53735857dc8fbc01e1e7f07974208a Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 10 May 2024 14:34:03 +1000 Subject: [PATCH 08/13] Handle resizing up and left by combining block rect and box rect --- .../grid-visualizer/grid-item-resizer.js | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index 99c1908f2c4a4..c99894c8e335b 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -155,28 +155,22 @@ export function GridItemResizer( { clientId, onChange } ) { getComputedCSS( gridElement, 'grid-template-rows' ), rowGap ); + const rect = new window.DOMRect( + blockElement.offsetLeft + boxElement.offsetLeft, + blockElement.offsetTop + boxElement.offsetTop, + boxElement.offsetWidth, + boxElement.offsetHeight + ); const columnStart = - getClosestTrack( - gridColumnTracks, - blockElement.offsetLeft - ) + 1; + getClosestTrack( gridColumnTracks, rect.left ) + 1; const rowStart = - getClosestTrack( - gridRowTracks, - blockElement.offsetTop - ) + 1; + getClosestTrack( gridRowTracks, rect.top ) + 1; const columnEnd = - getClosestTrack( - gridColumnTracks, - blockElement.offsetLeft + boxElement.offsetWidth, - 'end' - ) + 1; + getClosestTrack( gridColumnTracks, rect.right, 'end' ) + + 1; const rowEnd = - getClosestTrack( - gridRowTracks, - blockElement.offsetTop + boxElement.offsetHeight, - 'end' - ) + 1; + getClosestTrack( gridRowTracks, rect.bottom, 'end' ) + + 1; onChange( { columnSpan: columnEnd - columnStart + 1, rowSpan: rowEnd - rowStart + 1, From 4bc0167dcfd462e14a452cb74f8d41d33035e70b Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 10 May 2024 15:41:03 +1000 Subject: [PATCH 09/13] Refresh handles after resize --- .../grid-visualizer/grid-item-resizer.js | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index c99894c8e335b..5d66b9f9cf9cf 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { ResizableBox } from '@wordpress/components'; -import { useState, useRef } from '@wordpress/element'; +import { useState, useRef, useEffect } from '@wordpress/element'; /** * Internal dependencies @@ -14,7 +14,40 @@ import { getComputedCSS } from './utils'; export function GridItemResizer( { clientId, onChange } ) { const blockElement = useBlockElement( clientId ); const rootBlockElement = blockElement?.parentElement; + + const blockClientRect = blockElement?.getBoundingClientRect() || {}; + const rootBlockClientRect = rootBlockElement?.getBoundingClientRect() || {}; + const [ resizeDirection, setResizeDirection ] = useState( null ); + const [ enableSide, setEnableSide ] = useState( { + top: false, + bottom: false, + left: false, + right: false, + } ); + + useEffect( () => { + const observer = new window.ResizeObserver( () => { + setEnableSide( { + top: blockClientRect.top > rootBlockClientRect.top, + bottom: blockClientRect.bottom < rootBlockClientRect.bottom, + left: blockClientRect.left > rootBlockClientRect.left, + right: blockClientRect.right < rootBlockClientRect.right, + } ); + } ); + observer.observe( blockElement ); + return () => observer.disconnect(); + }, [ + blockClientRect.bottom, + blockClientRect.left, + blockClientRect.right, + blockClientRect.top, + blockElement, + rootBlockClientRect.bottom, + rootBlockClientRect.left, + rootBlockClientRect.right, + rootBlockClientRect.top, + ] ); /* * Resizer dummy is an empty div that exists only so we can @@ -50,9 +83,6 @@ export function GridItemResizer( { clientId, onChange } ) { } ), }; - const blockClientRect = blockElement.getBoundingClientRect(); - const rootBlockClientRect = rootBlockElement.getBoundingClientRect(); - /* * The bounding element is equivalent to the root block element, but * its bounding client rect is modified to account for the resizer @@ -80,15 +110,6 @@ export function GridItemResizer( { clientId, onChange } ) { }, }; - /* - * Only enable resizing to a side if that side is not on the - * edge of the grid. - */ - const enableTop = blockClientRect.top > rootBlockClientRect.top; - const enableBottom = blockClientRect.bottom < rootBlockClientRect.bottom; - const enableLeft = blockClientRect.left > rootBlockClientRect.left; - const enableRight = blockClientRect.right < rootBlockClientRect.right; - return ( Date: Fri, 10 May 2024 15:47:20 +1000 Subject: [PATCH 10/13] Update comment --- .../src/components/grid-visualizer/grid-item-resizer.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index 5d66b9f9cf9cf..7d8dd55a5d6fb 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -50,10 +50,9 @@ export function GridItemResizer( { clientId, onChange } ) { ] ); /* - * Resizer dummy is an empty div that exists only so we can - * get the bounding client rect of the resizer element. This is - * necessary because the resizer exists outside of the iframe, so - * its bounding client rect isn't the same as the block element's. + * This ref is necessary get the bounding client rect of the resizer, + * because it exists outside of the iframe, so its bounding client + * rect isn't the same as the block element's. */ const resizerRef = useRef( null ); From 69368e41a4b7a8163c31cad0a4e810f6a7325d8e Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 10 May 2024 16:03:58 +1000 Subject: [PATCH 11/13] Avoid useEffect firing twice --- .../grid-visualizer/grid-item-resizer.js | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index 7d8dd55a5d6fb..f9826f859cd36 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -15,9 +15,6 @@ export function GridItemResizer( { clientId, onChange } ) { const blockElement = useBlockElement( clientId ); const rootBlockElement = blockElement?.parentElement; - const blockClientRect = blockElement?.getBoundingClientRect() || {}; - const rootBlockClientRect = rootBlockElement?.getBoundingClientRect() || {}; - const [ resizeDirection, setResizeDirection ] = useState( null ); const [ enableSide, setEnableSide ] = useState( { top: false, @@ -28,6 +25,9 @@ export function GridItemResizer( { clientId, onChange } ) { useEffect( () => { const observer = new window.ResizeObserver( () => { + const blockClientRect = blockElement?.getBoundingClientRect() || {}; + const rootBlockClientRect = + rootBlockElement?.getBoundingClientRect() || {}; setEnableSide( { top: blockClientRect.top > rootBlockClientRect.top, bottom: blockClientRect.bottom < rootBlockClientRect.bottom, @@ -37,17 +37,7 @@ export function GridItemResizer( { clientId, onChange } ) { } ); observer.observe( blockElement ); return () => observer.disconnect(); - }, [ - blockClientRect.bottom, - blockClientRect.left, - blockClientRect.right, - blockClientRect.top, - blockElement, - rootBlockClientRect.bottom, - rootBlockClientRect.left, - rootBlockClientRect.right, - rootBlockClientRect.top, - ] ); + }, [ blockElement, rootBlockElement ] ); /* * This ref is necessary get the bounding client rect of the resizer, @@ -91,6 +81,9 @@ export function GridItemResizer( { clientId, onChange } ) { offsetWidth: rootBlockElement.offsetWidth, offsetHeight: rootBlockElement.offsetHeight, getBoundingClientRect: () => { + const blockClientRect = blockElement?.getBoundingClientRect() || {}; + const rootBlockClientRect = + rootBlockElement?.getBoundingClientRect() || {}; const resizerTop = resizerRef.current?.getBoundingClientRect()?.top; // Fallback value of 60 to account for editor top bar height. const heightDifference = resizerTop From 795d6619e2b22369088c858459afd799c5fbed93 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 10 May 2024 16:06:28 +1000 Subject: [PATCH 12/13] Avoid blockElement and rootBlockElement ever being null, combine rootBlockElement and gridElement --- .../grid-visualizer/grid-item-resizer.js | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index f9826f859cd36..240c505b533ec 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -15,6 +15,26 @@ export function GridItemResizer( { clientId, onChange } ) { const blockElement = useBlockElement( clientId ); const rootBlockElement = blockElement?.parentElement; + if ( ! blockElement || ! rootBlockElement ) { + return null; + } + + return ( + + ); +} + +function GridItemResizerInner( { + clientId, + blockElement, + rootBlockElement, + onChange, +} ) { const [ resizeDirection, setResizeDirection ] = useState( null ); const [ enableSide, setEnableSide ] = useState( { top: false, @@ -25,9 +45,9 @@ export function GridItemResizer( { clientId, onChange } ) { useEffect( () => { const observer = new window.ResizeObserver( () => { - const blockClientRect = blockElement?.getBoundingClientRect() || {}; + const blockClientRect = blockElement.getBoundingClientRect(); const rootBlockClientRect = - rootBlockElement?.getBoundingClientRect() || {}; + rootBlockElement.getBoundingClientRect(); setEnableSide( { top: blockClientRect.top > rootBlockClientRect.top, bottom: blockClientRect.bottom < rootBlockClientRect.bottom, @@ -81,9 +101,9 @@ export function GridItemResizer( { clientId, onChange } ) { offsetWidth: rootBlockElement.offsetWidth, offsetHeight: rootBlockElement.offsetHeight, getBoundingClientRect: () => { - const blockClientRect = blockElement?.getBoundingClientRect() || {}; + const blockClientRect = blockElement.getBoundingClientRect(); const rootBlockClientRect = - rootBlockElement?.getBoundingClientRect() || {}; + rootBlockElement.getBoundingClientRect(); const resizerTop = resizerRef.current?.getBoundingClientRect()?.top; // Fallback value of 60 to account for editor top bar height. const heightDifference = resizerTop @@ -153,19 +173,24 @@ export function GridItemResizer( { clientId, onChange } ) { ); } } onResizeStop={ ( event, direction, boxElement ) => { - const gridElement = blockElement.parentElement; const columnGap = parseFloat( - getComputedCSS( gridElement, 'column-gap' ) + getComputedCSS( rootBlockElement, 'column-gap' ) ); const rowGap = parseFloat( - getComputedCSS( gridElement, 'row-gap' ) + getComputedCSS( rootBlockElement, 'row-gap' ) ); const gridColumnTracks = getGridTracks( - getComputedCSS( gridElement, 'grid-template-columns' ), + getComputedCSS( + rootBlockElement, + 'grid-template-columns' + ), columnGap ); const gridRowTracks = getGridTracks( - getComputedCSS( gridElement, 'grid-template-rows' ), + getComputedCSS( + rootBlockElement, + 'grid-template-rows' + ), rowGap ); const rect = new window.DOMRect( From 20315d678e924e1daa3889a3139ea3ba84aeff8e Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 10 May 2024 16:30:00 +1000 Subject: [PATCH 13/13] Remove event listener on resize stop. --- .../components/grid-visualizer/grid-item-resizer.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js index 240c505b533ec..bc82cb9d8efc0 100644 --- a/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js +++ b/packages/block-editor/src/components/grid-visualizer/grid-item-resizer.js @@ -122,6 +122,9 @@ function GridItemResizerInner( { }, }; + // Controller to remove event listener on resize stop. + const controller = new AbortController(); + return ( { @@ -169,7 +173,7 @@ function GridItemResizerInner( { new Event( 'mouseup', { bubbles: true } ) ); }, - true + { signal: controller.signal, capture: true } ); } } onResizeStop={ ( event, direction, boxElement ) => { @@ -213,6 +217,8 @@ function GridItemResizerInner( { columnSpan: columnEnd - columnStart + 1, rowSpan: rowEnd - rowStart + 1, } ); + // Removes event listener added in onResizeStart. + controller.abort(); } } />