diff --git a/packages/block-editor/src/components/block-popover/inbetween.js b/packages/block-editor/src/components/block-popover/inbetween.js
index c9187afe31965..f9dd7adde42fb 100644
--- a/packages/block-editor/src/components/block-popover/inbetween.js
+++ b/packages/block-editor/src/components/block-popover/inbetween.js
@@ -237,9 +237,8 @@ function BlockPopoverInbetween( {
props.className
) }
resize={ false }
- overlay={ true }
flip={ false }
- placement="bottom-start"
+ placement="overlay"
variant="unstyled"
>
diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js
index 821868a326417..d32866a2b5ceb 100644
--- a/packages/block-editor/src/components/iframe/index.js
+++ b/packages/block-editor/src/components/iframe/index.js
@@ -240,6 +240,11 @@ function Iframe( {
return '' + renderToString( styleAssets );
}, [] );
+ // We need to counter the margin created by scaling the iframe. If the scale
+ // is e.g. 0.45, then the top + bottom margin is 0.55 (1 - scale). Just the
+ // top or bottom margin is 0.55 / 2 ((1 - scale) / 2).
+ const marginFromScaling = ( contentHeight * ( 1 - scale ) ) / 2;
+
return (
<>
{ tabIndex >= 0 && before }
@@ -249,10 +254,10 @@ function Iframe( {
...props.style,
height: expand ? contentHeight : props.style?.height,
marginTop: scale
- ? -( ( contentHeight * ( 1 - scale ) ) / 2 ) + frameSize
+ ? -marginFromScaling + frameSize
: props.style?.marginTop,
marginBottom: scale
- ? -( ( contentHeight * ( 1 - scale ) ) / 2 ) + frameSize
+ ? -marginFromScaling + frameSize
: props.style?.marginBottom,
transform: scale
? `scale( ${ scale } )`
diff --git a/packages/components/src/popover/index.tsx b/packages/components/src/popover/index.tsx
index 9910a0d2649e3..b549430cfb36a 100644
--- a/packages/components/src/popover/index.tsx
+++ b/packages/components/src/popover/index.tsx
@@ -67,6 +67,7 @@ import type {
PopoverAnchorRefTopBottom,
} from './types';
import { limitShift as customLimitShift } from './limit-shift';
+import { overlayMiddlewares } from './overlay-middlewares';
/**
* Name of slot in which popover should fill.
@@ -183,7 +184,6 @@ const UnforwardedPopover = (
resize = true,
shift = false,
variant,
- overlay = false,
// Deprecated props
__unstableForcePosition,
@@ -271,16 +271,9 @@ const UnforwardedPopover = (
const frameOffsetRef = useRef( getFrameOffset( referenceOwnerDocument ) );
const middleware = [
+ ...( placementProp === 'overlay' ? overlayMiddlewares() : [] ),
// Custom middleware which adjusts the popover's position by taking into
// account the offset of the anchor's iframe (if any) compared to the page.
- overlay
- ? {
- name: 'overlay',
- fn( { rects }: MiddlewareArguments ) {
- return rects.reference;
- },
- }
- : undefined,
{
name: 'frameOffset',
fn( { x, y }: MiddlewareArguments ) {
@@ -321,24 +314,6 @@ const UnforwardedPopover = (
},
} )
: undefined,
- overlay
- ? size( {
- apply( { rects } ) {
- const { firstElementChild } =
- refs.floating.current ?? {};
-
- // Only HTMLElement instances have the `style` property.
- if ( ! ( firstElementChild instanceof HTMLElement ) )
- return;
-
- // Reduce the height of the popover to the available space.
- Object.assign( firstElementChild.style, {
- width: `${ rects.reference.width }px`,
- height: `${ rects.reference.height }px`,
- } );
- },
- } )
- : undefined,
shift
? shiftMiddleware( {
crossAxis: true,
@@ -390,7 +365,10 @@ const UnforwardedPopover = (
placement: computedPlacement,
middlewareData: { arrow: arrowData },
} = useFloating( {
- placement: normalizedPlacementFromProps,
+ placement:
+ ( normalizedPlacementFromProps === 'overlay'
+ ? undefined
+ : normalizedPlacementFromProps ) || 'bottom',
middleware,
whileElementsMounted: ( referenceParam, floatingParam, updateParam ) =>
autoUpdate( referenceParam, floatingParam, updateParam, {
diff --git a/packages/components/src/popover/overlay-middlewares.tsx b/packages/components/src/popover/overlay-middlewares.tsx
new file mode 100644
index 0000000000000..da138af7fa331
--- /dev/null
+++ b/packages/components/src/popover/overlay-middlewares.tsx
@@ -0,0 +1,29 @@
+/**
+ * External dependencies
+ */
+import { size, MiddlewareArguments } from '@floating-ui/react-dom';
+
+export function overlayMiddlewares() {
+ return [
+ {
+ name: 'overlay',
+ fn( { rects }: MiddlewareArguments ) {
+ return rects.reference;
+ },
+ },
+ size( {
+ apply( { rects, elements } ) {
+ const { firstElementChild } = elements.floating ?? {};
+
+ // Only HTMLElement instances have the `style` property.
+ if ( ! ( firstElementChild instanceof HTMLElement ) ) return;
+
+ // Reduce the height of the popover to the available space.
+ Object.assign( firstElementChild.style, {
+ width: `${ rects.reference.width }px`,
+ height: `${ rects.reference.height }px`,
+ } );
+ },
+ } ),
+ ];
+}
diff --git a/packages/components/src/popover/types.ts b/packages/components/src/popover/types.ts
index 8cd30fbad4bba..1a65b26b9022f 100644
--- a/packages/components/src/popover/types.ts
+++ b/packages/components/src/popover/types.ts
@@ -12,8 +12,10 @@ type DomRectWithOwnerDocument = DOMRect & {
ownerDocument?: Document;
};
+type PopoverPlacement = Placement | 'overlay';
+
export type AnimatedWrapperProps = {
- placement: Placement;
+ placement: PopoverPlacement;
shouldAnimate?: boolean;
};
@@ -111,7 +113,7 @@ export type PopoverProps = {
*
* @default 'bottom-start'
*/
- placement?: Placement;
+ placement?: PopoverPlacement;
/**
* Legacy way to specify the popover's position with respect to its anchor.
* _Note: this prop is deprecated. Use the `placement` prop instead._
diff --git a/packages/components/src/popover/utils.ts b/packages/components/src/popover/utils.ts
index aafbf5bf77bc0..1f31e194260c7 100644
--- a/packages/components/src/popover/utils.ts
+++ b/packages/components/src/popover/utils.ts
@@ -105,6 +105,7 @@ const PLACEMENT_TO_ANIMATION_ORIGIN: Record<
left: { originX: 1, originY: 0.5 }, // open from middle, right
'left-start': { originX: 1, originY: 0 }, // open from top, right
'left-end': { originX: 1, originY: 1 }, // open from bottom, right
+ overlay: { originX: 0.5, originY: 0.5 }, // open from center, center
};
/**
@@ -157,13 +158,21 @@ export const getFrameOffset = (
return { x: iframeRect.left, y: iframeRect.top };
};
-export const getFrameScale = ( document?: Document ): number => {
+export const getFrameScale = (
+ document?: Document
+): {
+ x: number;
+ y: number;
+} => {
const frameElement = document?.defaultView?.frameElement as HTMLElement;
if ( ! frameElement ) {
- return 1;
+ return { x: 1, y: 1 };
}
- const transform = frameElement.style.transform;
- return parseFloat( transform.replace( /scale\((\d+\.?\d*)\)/, '$1' ) );
+ const rect = frameElement.getBoundingClientRect();
+ return {
+ x: rect.width / frameElement.offsetWidth,
+ y: rect.height / frameElement.offsetHeight,
+ };
};
export const getReferenceOwnerDocument = ( {
@@ -228,7 +237,7 @@ export const getReferenceElement = ( {
'anchorRef' | 'anchorRect' | 'getAnchorRect' | 'anchor'
> & {
fallbackReferenceElement: Element | null;
- scale: number;
+ scale: { x: number; y: number };
} ): ReferenceType | null => {
let referenceElement = null;
@@ -290,17 +299,17 @@ export const getReferenceElement = ( {
referenceElement = fallbackReferenceElement.parentElement;
}
- if ( referenceElement && scale !== 1 ) {
+ if ( referenceElement && ( scale.x !== 1 || scale.y !== 1 ) ) {
// If the popover is inside an iframe, the coordinates of the
// reference element need to be scaled to match the iframe's scale.
const rect = referenceElement.getBoundingClientRect();
referenceElement = {
getBoundingClientRect() {
return new window.DOMRect(
- rect.x * scale,
- rect.y * scale,
- rect.width * scale,
- rect.height * scale
+ rect.x * scale.x,
+ rect.y * scale.y,
+ rect.width * scale.x,
+ rect.height * scale.y
);
},
};