Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the block popover position as we scroll the container #41402

Merged
merged 1 commit into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export default function BlockPopover( {
// Observe movement for block animations (especially horizontal).
__unstableObserveElement={ selectedElement }
__unstableForcePosition
__unstableShift
{ ...props }
className={ classnames(
'block-editor-block-popover',
Expand Down
64 changes: 39 additions & 25 deletions packages/components/src/popover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ const Popover = (
__unstableSlotName = SLOT_NAME,
__unstableObserveElement,
__unstableForcePosition,
__unstableShift = false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like switching this to default to false caused a small regression for the Tooltip component which relies on the shift behaviour to prevent the Tooltip from causing the editor to overflow. I've opened up a separate PR to opt-in to the __unstableShift for the Tooltip in #41524

...contentProps
},
ref
Expand All @@ -134,26 +135,29 @@ const Popover = (
? positionToPlacement( position )
: placement;

/**
* Offsets the the position of the popover when the anchor is inside an iframe.
*/
const frameOffset = useMemo( () => {
let ownerDocument = document;
const ownerDocument = useMemo( () => {
if ( anchorRef?.top ) {
ownerDocument = anchorRef?.top.ownerDocument;
return anchorRef?.top.ownerDocument;
} else if ( anchorRef?.startContainer ) {
ownerDocument = anchorRef.startContainer.ownerDocument;
return anchorRef.startContainer.ownerDocument;
} else if ( anchorRef?.current ) {
ownerDocument = anchorRef.current.ownerDocument;
return anchorRef.current.ownerDocument;
} else if ( anchorRef ) {
// This one should be deprecated.
ownerDocument = anchorRef.ownerDocument;
return anchorRef.ownerDocument;
} else if ( anchorRect && anchorRect?.ownerDocument ) {
ownerDocument = anchorRect.ownerDocument;
return anchorRect.ownerDocument;
} else if ( getAnchorRect ) {
ownerDocument = getAnchorRect()?.ownerDocument ?? document;
return getAnchorRect()?.ownerDocument ?? document;
}

return document;
}, [ anchorRef, anchorRect, getAnchorRect ] );

/**
* Offsets the the position of the popover when the anchor is inside an iframe.
*/
const frameOffset = useMemo( () => {
const { defaultView } = ownerDocument;
const { frameElement } = defaultView;

Expand All @@ -171,7 +175,7 @@ const Popover = (
};
},
};
}, [ anchorRef, anchorRect, getAnchorRect ] );
}, [ ownerDocument ] );

const middlewares = [
frameOffset,
Expand All @@ -190,12 +194,13 @@ const Popover = (
} );
},
} ),
,
shift( {
crossAxis: true,
limiter: limitShift(),
padding: 1, // Necessary to avoid flickering at the edge of the viewport.
} ),
__unstableShift
? shift( {
crossAxis: true,
limiter: limitShift(),
padding: 1, // Necessary to avoid flickering at the edge of the viewport.
} )
: undefined,
hasArrow ? arrow( { element: arrowRef } ) : undefined,
].filter( ( m ) => !! m );
const anchorRefFallback = useRef( null );
Expand Down Expand Up @@ -271,13 +276,12 @@ const Popover = (
usedRef = {
getBoundingClientRect() {
const rect = getAnchorRect();
return {
...rect,
x: rect.x ?? rect.left,
y: rect.y ?? rect.top,
height: rect.height ?? rect.bottom - rect.top,
width: rect.width ?? rect.right - rect.left,
};
return new window.DOMRect(
rect.x ?? rect.left,
rect.y ?? rect.top,
rect.width ?? rect.right - rect.left,
rect.height ?? rect.bottom - rect.top
);
},
};
} else if ( anchorRefFallback.current ) {
Expand Down Expand Up @@ -310,6 +314,16 @@ const Popover = (
};
}, [ __unstableObserveElement ] );

// If we're using getAnchorRect, we need to update the position as we scroll the iframe.
useLayoutEffect( () => {
if ( ownerDocument === document ) {
return;
}

ownerDocument.addEventListener( 'scroll', update );
return () => ownerDocument.removeEventListener( 'scroll', update );
}, [ ownerDocument ] );

/** @type {false | string} */
const animateClassName =
!! animate &&
Expand Down