diff --git a/app/soapbox/components/autosuggest_textarea.js b/app/soapbox/components/autosuggest_textarea.js index 060e817e8..baaf3e8b0 100644 --- a/app/soapbox/components/autosuggest_textarea.js +++ b/app/soapbox/components/autosuggest_textarea.js @@ -50,8 +50,6 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { autoFocus: PropTypes.bool, onFocus: PropTypes.func, onBlur: PropTypes.func, - clickableAreaRef: PropTypes.object, - getClickableArea: PropTypes.func.isRequired, }; static defaultProps = { @@ -109,8 +107,6 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { if (suggestions.size > 0 && !suggestionsHidden) { e.preventDefault(); this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) }); - } else { - this.setState({ lastToken: null }); } break; @@ -118,8 +114,6 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { if (suggestions.size > 0 && !suggestionsHidden) { e.preventDefault(); this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) }); - } else { - this.setState({ lastToken: null }); } break; @@ -165,27 +159,19 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { this.textarea.focus(); } - isClickInside = (e) => { - return [ - this.props.getClickableArea(), - document.querySelector('.autosuggest-textarea__textarea'), - ].some(element => element && element.contains(e.target)); - } + shouldComponentUpdate(nextProps, nextState) { + // Skip updating when only the lastToken changes so the + // cursor doesn't jump around due to re-rendering unnecessarily + const lastTokenUpdated = this.state.lastToken !== nextState.lastToken; + const valueUpdated = this.props.value !== nextProps.value; - handleClick = (e) => { - if (this.isClickInside(e)) { - this.setState({ lastToken: null }); + if (lastTokenUpdated && !valueUpdated) { + return false; + } else { + return super.shouldComponentUpdate(nextProps, nextState); } } - componentDidMount() { - document.addEventListener('click', this.handleClick, true); - } - - componentWillUnmount() { - document.removeEventListener('click', this.handleClick, true); - } - componentDidUpdate(prevProps, prevState) { const { suggestions } = this.props; if (suggestions !== prevProps.suggestions && suggestions.size > 0 && prevState.suggestionsHidden && prevState.focused) { diff --git a/app/soapbox/features/compose/components/compose_form.js b/app/soapbox/features/compose/components/compose_form.js index 39647c923..0f3f45f41 100644 --- a/app/soapbox/features/compose/components/compose_form.js +++ b/app/soapbox/features/compose/components/compose_form.js @@ -160,11 +160,6 @@ class ComposeForm extends ImmutablePureComponent { this.props.onChangeSpoilerText(e.target.value); } - doFocus = () => { - if (!this.autosuggestTextarea) return; - this.autosuggestTextarea.textarea.focus(); - } - setCursor = (start, end = start) => { if (!this.autosuggestTextarea) return; this.autosuggestTextarea.textarea.setSelectionRange(start, end); @@ -219,8 +214,22 @@ class ComposeForm extends ImmutablePureComponent { } } + maybeUpdateCursor = prevProps => { + const shouldUpdate = [ + // Autosuggest has been updated and + // the cursor position explicitly set + this.props.focusDate !== prevProps.focusDate, + typeof this.props.caretPosition === 'number', + ].every(Boolean); + + if (shouldUpdate) { + this.setCursor(this.props.caretPosition); + } + } + componentDidUpdate(prevProps) { this.maybeUpdateFocus(prevProps); + this.maybeUpdateCursor(prevProps); } render() { @@ -286,7 +295,6 @@ class ComposeForm extends ImmutablePureComponent { onSuggestionSelected={this.onSuggestionSelected} onPaste={onPaste} autoFocus={shouldAutoFocus} - getClickableArea={this.getClickableArea} > { !condensed &&