diff --git a/packages/block-editor/src/components/block-list/block-popover.js b/packages/block-editor/src/components/block-list/block-popover.js index cb563c3319f21..8f04a3571aa73 100644 --- a/packages/block-editor/src/components/block-list/block-popover.js +++ b/packages/block-editor/src/components/block-list/block-popover.js @@ -128,11 +128,15 @@ function BlockPopover( { className="block-editor-block-list__block-popover" __unstableSticky={ showEmptyBlockSideInserter ? false : popoverIsSticky } __unstableSlotName="block-toolbar" + __unstableBoundaryParent // Allow subpixel positioning for the block movement animation. __unstableAllowVerticalSubpixelPosition={ moverDirection !== 'horizontal' && node } __unstableAllowHorizontalSubpixelPosition={ moverDirection === 'horizontal' && node } onBlur={ () => setIsToolbarForced( false ) } shouldAnchorIncludePadding + // Popover calculates the width once. Trigger a reset by remounting + // the component. + key={ shouldShowContextualToolbar } > { ( shouldShowContextualToolbar || isToolbarForced ) && (
{ @@ -273,6 +274,12 @@ const Popover = ( { contentRect.current = contentRef.current.getBoundingClientRect(); } + let boundaryElement; + + if ( __unstableBoundaryParent ) { + boundaryElement = containerRef.current.closest( '.popover-slot' ).parentNode; + } + const { popoverTop, popoverLeft, @@ -280,7 +287,14 @@ const Popover = ( { yAxis, contentHeight, contentWidth, - } = computePopoverPosition( anchor, contentRect.current, position, __unstableSticky, anchorRef ); + } = computePopoverPosition( + anchor, + contentRect.current, + position, + __unstableSticky, + anchorRef, + boundaryElement + ); if ( typeof popoverTop === 'number' && typeof popoverLeft === 'number' ) { if ( subpixels && __unstableAllowVerticalSubpixelPosition ) { @@ -374,6 +388,7 @@ const Popover = ( { __unstableSticky, __unstableAllowVerticalSubpixelPosition, __unstableAllowHorizontalSubpixelPosition, + __unstableBoundaryParent, ] ); useFocusContentOnMount( focusOnMount, contentRef ); @@ -511,6 +526,6 @@ const Popover = ( { const PopoverContainer = Popover; PopoverContainer.Slot = ( { name = SLOT_NAME } ) => - ; + ; export default PopoverContainer; diff --git a/packages/components/src/popover/utils.js b/packages/components/src/popover/utils.js index 971ec4919d1c9..05ebfc7896be7 100644 --- a/packages/components/src/popover/utils.js +++ b/packages/components/src/popover/utils.js @@ -19,10 +19,11 @@ const HEIGHT_OFFSET = 10; // used by the arrow and a bit of empty space * scroll container edge when part of the anchor * leaves view. * @param {string} chosenYAxis yAxis to be used. + * @param {Element} boundaryElement * * @return {Object} Popover xAxis position and constraints. */ -export function computePopoverXAxisPosition( anchorRect, contentSize, xAxis, corner, sticky, chosenYAxis ) { +export function computePopoverXAxisPosition( anchorRect, contentSize, xAxis, corner, sticky, chosenYAxis, boundaryElement ) { const { width } = contentSize; const isRTL = document.documentElement.dir === 'rtl'; @@ -101,6 +102,11 @@ export function computePopoverXAxisPosition( anchorRect, contentSize, xAxis, cor popoverLeft = rightAlignment.popoverLeft; } + if ( boundaryElement ) { + const boundaryRect = boundaryElement.getBoundingClientRect(); + popoverLeft = Math.min( popoverLeft, boundaryRect.right - width ); + } + return { xAxis: chosenXAxis, popoverLeft, @@ -222,14 +228,22 @@ export function computePopoverYAxisPosition( anchorRect, contentSize, yAxis, cor * scroll container edge when part of the anchor * leaves view. * @param {Element} anchorRef The anchor element. + * @param {Element} boundaryElement * * @return {Object} Popover position and constraints. */ -export function computePopoverPosition( anchorRect, contentSize, position = 'top', sticky, anchorRef ) { +export function computePopoverPosition( + anchorRect, + contentSize, + position = 'top', + sticky, + anchorRef, + boundaryElement +) { const [ yAxis, xAxis = 'center', corner ] = position.split( ' ' ); const yAxisPosition = computePopoverYAxisPosition( anchorRect, contentSize, yAxis, corner, sticky, anchorRef ); - const xAxisPosition = computePopoverXAxisPosition( anchorRect, contentSize, xAxis, corner, sticky, yAxisPosition.yAxis ); + const xAxisPosition = computePopoverXAxisPosition( anchorRect, contentSize, xAxis, corner, sticky, yAxisPosition.yAxis, boundaryElement ); return { ...xAxisPosition,