Fix adding links from the autocompleter#10500
Conversation
| resetState( event ) { | ||
| // URLInput's autocomplete list can trigger onClickOutside on the link container's popover. | ||
| // Return early here if the click originated from one of the autocomplete suggestions. | ||
| if ( hasIn( event, [ 'target', 'classList' ] ) && includes( event.target.classList, 'editor-url-input__suggestion' ) ) { |
There was a problem hiding this comment.
It'd be nice to be able to avoid checking the class here, but I'm short of other ideas beyond having LinkContainer manage a ref to the URLInput's popover.
There was a problem hiding this comment.
Yes this is a bit unfortunate.
|
|
Hi @iseulde - the change was added in the RichText refactor: Before that, there wasn't an I'll have a look at adding a case to the e2e links test. |
61cd065 to
537b18d
Compare
|
Why are the link suggestions not in the same popover? That's a bit strange. |
|
@iseulde - Not sure, the input is a separate component, and I imagine it's based on other autocomplete implementations. I'll try to think of some other ways to fix this today. |
…riginate from the autocomplete popover
…n they originate from the autocomplete popover" This reverts commit 17d4cf8.
537b18d to
cd0c1e0
Compare
|
Hey @iseulde I've changed the implementation to use a ref now instead of checking class names. I did take a look at if it would be possible to un-nest the suggestions from their popover, but it was a bit too involved. |
| // so onClickOutside fails to detect that a click on a suggestion occured in the | ||
| // LinkContainer. Detect clicks on autocomplete suggestions using a ref here, and | ||
| // return early if so. | ||
| if ( hasIn( this, [ 'autocompleteRef', 'contains' ] ) && this.autocompleteRef.contains( event.target ) ) { |
There was a problem hiding this comment.
If the user attempted to click outside of the popover when the autocomplete list hadn't been displayed, this.autocompleteRef would be unset. Checking for contains seems to be the safest option.
There was a problem hiding this comment.
Using hasIn like this makes me think that this condition is a browser compatibility check for Node.contains(). This isn't necessary since Node.contains() works in all modern browsers.
I think a clearer way to convey what's happening is to simply check for the presence of the ref.
| if ( hasIn( this, [ 'autocompleteRef', 'contains' ] ) && this.autocompleteRef.contains( event.target ) ) { | |
| if ( this.autocompleteRef && this.autocompleteRef.contains( event.target ) ) { |
|
Using ref.contains sounds better! |
| // so onClickOutside fails to detect that a click on a suggestion occured in the | ||
| // LinkContainer. Detect clicks on autocomplete suggestions using a ref here, and | ||
| // return early if so. | ||
| if ( hasIn( this, [ 'autocompleteRef', 'contains' ] ) && this.autocompleteRef.contains( event.target ) ) { |
There was a problem hiding this comment.
Using hasIn like this makes me think that this condition is a browser compatibility check for Node.contains(). This isn't necessary since Node.contains() works in all modern browsers.
I think a clearer way to convey what's happening is to simply check for the presence of the ref.
| if ( hasIn( this, [ 'autocompleteRef', 'contains' ] ) && this.autocompleteRef.contains( event.target ) ) { | |
| if ( this.autocompleteRef && this.autocompleteRef.contains( event.target ) ) { |
| this.resetState = this.resetState.bind( this ); | ||
| this.bindAutocompleteRef = this.bindAutocompleteRef.bind( this ); | ||
|
|
||
| this.autocompleteRef = createRef(); |
There was a problem hiding this comment.
It's confusing, I think, to see a mix of createRef() refs and callback refs.
This line here is redundant since bindAutocompleteRef will overwrite this.autocompleteRef when the component is mounted.
The quick way to address this is to delete this line.
| this.autocompleteRef = createRef(); |
A nicer approach, I think, would be to update URLInput to use createRef() refs. Then, LinkEditor can simply override the ref by passing a prop.
class URLInput extends Component {
constructor( { autocompleteRef } ) {
super( ...arguments );
this.autocompleteRef = autocompleteRef || createRef();
}
render() {
...
return (
...
<div
className="editor-url-input__suggestions"
...
ref={ this.autocompleteRef }
>
...
);
}
}
noisysocks
left a comment
There was a problem hiding this comment.
Love it! Thanks for adding tests.
|
Awesome, thanks @talldan for the heads up and doing the fix. Let's see how the release process goes :) |
* Use a ref to detect clicks in the autocomplete suggestion list * Add e2e tests to test for regression of link autocomplete issue
Fixes #10496
Description
When adding links from the autocompletion list, the
onClickOutsidehandler on the LinkContainer popover was being triggered, causing the link not to be set and triggering closure of the popover.This fix adds a clause at the start of the
onClickOutsidehandler, detecting if the click originated from a autocomplete entry and returning early if so.How has this been tested?
Types of changes
Bug fix (non-breaking change which fixes an issue)
Checklist: