diff --git a/packages/block-editor/src/components/rich-text/format-toolbar-container.js b/packages/block-editor/src/components/rich-text/format-toolbar-container.js index 24a931dc791754..94610af8fcda1a 100644 --- a/packages/block-editor/src/components/rich-text/format-toolbar-container.js +++ b/packages/block-editor/src/components/rich-text/format-toolbar-container.js @@ -17,28 +17,32 @@ import BlockControls from '../block-controls'; import FormatToolbar from './format-toolbar'; import { store as blockEditorStore } from '../../store'; -function InlineSelectionToolbar( { value, anchorRef, activeFormats } ) { +function InlineSelectionToolbar( { + value, + editableContentRef, + activeFormats, +} ) { const lastFormat = activeFormats[ activeFormats.length - 1 ]; const lastFormatType = lastFormat?.type; const settings = useSelect( ( select ) => select( richTextStore ).getFormatType( lastFormatType ), [ lastFormatType ] ); - const selectionRef = useAnchorRef( { - ref: anchorRef, + const popoverAnchor = useAnchorRef( { + ref: editableContentRef, value, settings, } ); - return ; + return ; } -function InlineToolbar( { anchorRef } ) { +function InlineToolbar( { popoverAnchor } ) { return ( @@ -51,14 +55,14 @@ function InlineToolbar( { anchorRef } ) { ); } -const FormatToolbarContainer = ( { inline, anchorRef, value } ) => { +const FormatToolbarContainer = ( { inline, editableContentRef, value } ) => { const hasInlineToolbar = useSelect( ( select ) => select( blockEditorStore ).getSettings().hasInlineToolbar, [] ); if ( inline ) { - return ; + return ; } if ( hasInlineToolbar ) { @@ -70,7 +74,7 @@ const FormatToolbarContainer = ( { inline, anchorRef, value } ) => { return ( diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 21c004b225f6c5..ae0942349b90c8 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -354,7 +354,7 @@ function RichTextWrapper( { isSelected && hasFormats && ( ) } diff --git a/packages/components/src/autocomplete/autocompleter-ui.js b/packages/components/src/autocomplete/autocompleter-ui.js index c909aa6a4a5783..c25dcfb4030189 100644 --- a/packages/components/src/autocomplete/autocompleter-ui.js +++ b/packages/components/src/autocomplete/autocompleter-ui.js @@ -35,7 +35,7 @@ export function getAutoCompleterUI( autocompleter ) { contentRef, } ) { const [ items ] = useItems( filterValue ); - const anchorRef = useAnchorRef( { ref: contentRef, value } ); + const popoverAnchor = useAnchorRef( { ref: contentRef, value } ); useLayoutEffect( () => { onChangeOptions( items ); @@ -54,7 +54,7 @@ export function getAutoCompleterUI( autocompleter ) { onClose={ onReset } position="top right" className="components-autocomplete__popover" - anchorRef={ anchorRef } + anchor={ popoverAnchor } >
element within the HEX input. This caches the last truthy value of the selection anchor reference. */ - const anchorRef = useCachedTruthy( + const popoverAnchor = useCachedTruthy( useAnchorRef( { ref: contentRef, value, settings } ) ); @@ -152,7 +152,7 @@ export default function InlineColorUI( { diff --git a/packages/rich-text/src/component/use-anchor-ref.js b/packages/rich-text/src/component/use-anchor-ref.js index 4be4fdd93096a7..d601174ad379d7 100644 --- a/packages/rich-text/src/component/use-anchor-ref.js +++ b/packages/rich-text/src/component/use-anchor-ref.js @@ -12,11 +12,17 @@ import { getActiveFormat } from '../get-active-format'; /** @typedef {import('../register-format-type').RichTextFormatType} RichTextFormatType */ /** @typedef {import('../create').RichTextValue} RichTextValue */ +/** + * @typedef {Object} VirtualAnchorElement + * @property {Function} getBoundingClientRect A function returning a DOMRect + * @property {Document} ownerDocument The element's ownerDocument + */ + /** * This hook, to be used in a format type's Edit component, returns the active - * element that is formatted, or the selection range if no format is active. - * The returned value is meant to be used for positioning UI, e.g. by passing it - * to the `Popover` component. + * element that is formatted, or a virtual element for the selection range if + * no format is active. The returned value is meant to be used for positioning + * UI, e.g. by passing it to the `Popover` component. * * @param {Object} $1 Named parameters. * @param {RefObject} $1.ref React ref of the element @@ -24,7 +30,7 @@ import { getActiveFormat } from '../get-active-format'; * @param {RichTextValue} $1.value Value to check for selection. * @param {RichTextFormatType} $1.settings The format type's settings. * - * @return {Element|Range} The active element or selection range. + * @return {Element|VirtualAnchorElement|undefined|null} The active element or selection range. */ export function useAnchorRef( { ref, value, settings = {} } ) { const { tagName, className, name } = settings; @@ -44,7 +50,12 @@ export function useAnchorRef( { ref, value, settings = {} } ) { const range = selection.getRangeAt( 0 ); if ( ! activeFormat ) { - return range; + return { + ownerDocument: range.startContainer.ownerDocument, + getBoundingClientRect() { + return range.getBoundingClientRect(); + }, + }; } let element = range.startContainer;