Skip to content

Commit

Permalink
Force remount LinkControl when moving between links within same richt…
Browse files Browse the repository at this point in the history
…ext block (#34742)

* Force remount LinkControl within Popovers

* Use anchor ref as semi-unique value to force remount

* Use the HTML string of the anchor onto which the linkcontrol is attached as the remount key

* Use custom key based unique ID generator
  • Loading branch information
getdave authored and noisysocks committed Nov 10, 2021
1 parent 393c2b5 commit b5afbff
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
8 changes: 8 additions & 0 deletions packages/format-library/src/link/inline.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { useSelect } from '@wordpress/data';
*/
import { createLinkFormat, isValidHref, getFormatBoundary } from './utils';
import { link as settings } from './index';
import useLinkInstanceKey from './use-link-instance-key';

function InlineLinkUI( {
isActive,
Expand Down Expand Up @@ -184,6 +185,12 @@ function InlineLinkUI( {

const anchorRef = useAnchorRef( { ref: contentRef, value, settings } );

// Generate a string based key that is unique to this anchor reference.
// This is used to force re-mount the LinkControl component to avoid
// potential stale state bugs caused by the component not being remounted
// See https://github.com/WordPress/gutenberg/pull/34742.
const forceRemountKey = useLinkInstanceKey( anchorRef );

// The focusOnMount prop shouldn't evolve during render of a Popover
// otherwise it causes a render of the content.
const focusOnMount = useRef( addingLink ? 'firstElement' : false );
Expand Down Expand Up @@ -222,6 +229,7 @@ function InlineLinkUI( {
position="bottom center"
>
<LinkControl
key={ forceRemountKey }
value={ linkValue }
onChange={ onChangeLink }
onRemove={ removeLink }
Expand Down
31 changes: 31 additions & 0 deletions packages/format-library/src/link/use-link-instance-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Weakly referenced map allows unused ids to be garbage collected.
const weakMap = new WeakMap();

// Incrementing zero-based ID value
let id = -1;

const prefix = 'link-control-instance';

function getKey( _id ) {
return `${ prefix }-${ _id }`;
}

/**
* Builds a unique link control key for the given object reference.
*
* @param {Object} instance an unique object reference specific to this link control instance.
* @return {string} the unique key to use for this link control.
*/
function useLinkInstanceKey( instance ) {
if ( weakMap.has( instance ) ) {
return getKey( weakMap.get( instance ) );
}

id += 1;

weakMap.set( instance, id );

return getKey( id );
}

export default useLinkInstanceKey;

0 comments on commit b5afbff

Please sign in to comment.