-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Refactor useAnchorRef
and related components to work with the new Popover anchor
prop
#43713
Changes from all commits
1fdf043
82cfb4c
4717042
8b57ffc
05c5486
b179e5b
1bc3b66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 <InlineToolbar anchorRef={ selectionRef } />; | ||
return <InlineToolbar popoverAnchor={ popoverAnchor } />; | ||
} | ||
|
||
function InlineToolbar( { anchorRef } ) { | ||
function InlineToolbar( { popoverAnchor } ) { | ||
return ( | ||
<Popover | ||
position="top center" | ||
focusOnMount={ false } | ||
anchorRef={ anchorRef } | ||
anchor={ popoverAnchor } | ||
className="block-editor-rich-text__inline-format-toolbar" | ||
__unstableSlotName="block-toolbar" | ||
> | ||
|
@@ -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 <InlineToolbar anchorRef={ anchorRef } />; | ||
return <InlineToolbar popoverAnchor={ editableContentRef.current } />; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Other change: because |
||
} | ||
|
||
if ( hasInlineToolbar ) { | ||
|
@@ -70,7 +74,7 @@ const FormatToolbarContainer = ( { inline, anchorRef, value } ) => { | |
|
||
return ( | ||
<InlineSelectionToolbar | ||
anchorRef={ anchorRef } | ||
editableContentRef={ editableContentRef } | ||
value={ value } | ||
activeFormats={ activeFormats } | ||
/> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,19 +12,25 @@ 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<HTMLElement>} $1.ref React ref of the element | ||
* containing the editable content. | ||
* @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(); | ||
}, | ||
}; | ||
Comment on lines
+53
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the main change of the PR: this hook now returns a A Couple of notes:
|
||
} | ||
|
||
let element = range.startContainer; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other notable change in this PR: I decided to rename
anchorRef
toeditableContentRef
in this file, as it is better representing what that variable is for.editableContentRef
is expected to be a "standard" React ref, ie. an object with thecurrent
property.It looks like the
FormatToolbarContainer
is not exported from the package anyway, so I think this change is ok.