diff --git a/app/soapbox/features/compose/editor/plugins/autosuggest-plugin.tsx b/app/soapbox/features/compose/editor/plugins/autosuggest-plugin.tsx index 1c77fc8b3..6bd2b31b5 100644 --- a/app/soapbox/features/compose/editor/plugins/autosuggest-plugin.tsx +++ b/app/soapbox/features/compose/editor/plugins/autosuggest-plugin.tsx @@ -7,11 +7,14 @@ */ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; +import { mergeRegister } from '@lexical/utils'; import clsx from 'clsx'; import { $getSelection, $isRangeSelection, $isTextNode, + COMMAND_PRIORITY_LOW, + KEY_ESCAPE_COMMAND, LexicalEditor, RangeSelection, } from 'lexical'; @@ -358,8 +361,8 @@ const AutosuggestPlugin = ({ }; const renderSuggestion = (suggestion: AutoSuggestion, i: number) => { - let inner; - let key; + let inner: string | JSX.Element; + let key: React.Key; if (typeof suggestion === 'object') { inner = ; @@ -447,6 +450,35 @@ const AutosuggestPlugin = ({ if (suggestions && suggestions.size > 0) setSuggestionsHidden(false); }, [suggestions]); + useEffect(() => { + if (resolution !== null && !suggestionsHidden && !suggestions.isEmpty()) { + const handleClick = (event: MouseEvent) => { + const target = event.target as HTMLElement; + + if (!editor._rootElement?.contains(target) && !anchorElementRef.current.contains(target)) { + setResolution(null); + } + }; + document.addEventListener('click', handleClick); + + return () => document.removeEventListener('click', handleClick); + } + }, [resolution, suggestionsHidden, suggestions.isEmpty()]); + + useEffect(() => mergeRegister( + editor.registerCommand( + KEY_ESCAPE_COMMAND, + (payload) => { + const event = payload; + event.preventDefault(); + event.stopImmediatePropagation(); + setResolution(null); + return true; + }, + COMMAND_PRIORITY_LOW, + ), + ), [editor]); + return resolution === null || editor === null ? null : (