diff --git a/packages/components/src/popover/README.md b/packages/components/src/popover/README.md index 6dfd1f6bdd7243..d4990aacd8d7de 100644 --- a/packages/components/src/popover/README.md +++ b/packages/components/src/popover/README.md @@ -151,8 +151,17 @@ Set this to hide the arrow which visually indicates what the popover is anchored - Required: No - Default: `true` +### anchor + +The element that should be used by the `Popover` as its anchor. It can either be an `Element` or, alternatively, a `VirtualElement` — ie. an object with the `getBoundingClientRect` function and the `ownerDocument` properties defined. + +- Type: `Element | VirtualElement` +- Required: No + ### anchorRect +**Deprecated**. Please use the `anchor` prop instead. + A custom `DOMRect` object at which to position the popover. `anchorRect` is used when the position (custom `DOMRect` object) of the popover needs to be fixed at one location all the time. - Type: `DOMRect` @@ -160,6 +169,8 @@ A custom `DOMRect` object at which to position the popover. `anchorRect` is used ### getAnchorRect +**Deprecated**. Please use the `anchor` prop instead. + A callback function which is used to override the anchor value computation algorithm. `anchorRect` will take precedence over this prop, if both are passed together. If you need the `DOMRect` object i.e., the position of popover to be calculated on every time, the popover re-renders, then use `getAnchorRect`. diff --git a/packages/components/src/popover/index.js b/packages/components/src/popover/index.js index eb3607e5b305c5..1742ae16aabfd9 100644 --- a/packages/components/src/popover/index.js +++ b/packages/components/src/popover/index.js @@ -154,6 +154,7 @@ const Popover = ( placement: placementProp = 'bottom-start', offset: offsetProp = 0, focusOnMount = 'firstElement', + anchor, anchorRef, anchorRect, getAnchorRect, @@ -188,6 +189,30 @@ const Popover = ( resize = ! __unstableForcePosition; } + if ( anchorRef !== undefined ) { + deprecated( '`anchorRef` prop in Popover component', { + since: '6.1', + version: '6.3', + alternative: '`anchor` prop', + } ); + } + + if ( anchorRect !== undefined ) { + deprecated( '`anchorRect` prop in Popover component', { + since: '6.1', + version: '6.3', + alternative: '`anchor` prop', + } ); + } + + if ( getAnchorRect !== undefined ) { + deprecated( '`getAnchorRect` prop in Popover component', { + since: '6.1', + version: '6.3', + alternative: '`anchor` prop', + } ); + } + const arrowRef = useRef( null ); const [ fallbackReferenceElement, setFallbackReferenceElement ] = @@ -335,6 +360,7 @@ const Popover = ( // recompute the reference element (real or virtual) and its owner document. useLayoutEffect( () => { const resultingReferenceOwnerDoc = getReferenceOwnerDocument( { + anchor, anchorRef, anchorRect, getAnchorRect, @@ -342,6 +368,7 @@ const Popover = ( fallbackDocument: document, } ); const resultingReferenceElement = getReferenceElement( { + anchor, anchorRef, anchorRect, getAnchorRect, @@ -352,6 +379,7 @@ const Popover = ( setReferenceOwnerDocument( resultingReferenceOwnerDoc ); }, [ + anchor, anchorRef, anchorRef?.top, anchorRef?.bottom, diff --git a/packages/components/src/popover/utils.js b/packages/components/src/popover/utils.js index c17fdd00623d23..7563108377ef1e 100644 --- a/packages/components/src/popover/utils.js +++ b/packages/components/src/popover/utils.js @@ -107,6 +107,8 @@ export const getFrameOffset = ( document ) => { }; export const getReferenceOwnerDocument = ( { + // @ts-ignore + anchor, // @ts-ignore anchorRef, // @ts-ignore @@ -126,7 +128,9 @@ export const getReferenceOwnerDocument = ( { // with the `getBoundingClientRect()` function (like real elements). // See https://floating-ui.com/docs/virtual-elements for more info. let resultingReferenceOwnerDoc; - if ( anchorRef?.top ) { + if ( anchor ) { + resultingReferenceOwnerDoc = anchor.ownerDocument; + } else if ( anchorRef?.top ) { resultingReferenceOwnerDoc = anchorRef?.top.ownerDocument; } else if ( anchorRef?.startContainer ) { resultingReferenceOwnerDoc = anchorRef.startContainer.ownerDocument; @@ -147,6 +151,8 @@ export const getReferenceOwnerDocument = ( { }; export const getReferenceElement = ( { + // @ts-ignore + anchor, // @ts-ignore anchorRef, // @ts-ignore @@ -159,7 +165,9 @@ export const getReferenceElement = ( { /** @type {import('@floating-ui/react-dom').ReferenceType | undefined} */ let referenceElement; - if ( anchorRef?.top ) { + if ( anchor ) { + referenceElement = anchor; + } else if ( anchorRef?.top ) { // Create a virtual element for the ref. The expectation is that // if anchorRef.top is defined, then anchorRef.bottom is defined too. // Seems to be used by the block toolbar, when multiple blocks are selected