@@ -30,6 +30,8 @@ interface MarkdownInputProps extends Omit<TextareaProps, 'onChange'> {
3030 visible : boolean
3131}
3232
33+ const emptyArray : [ ] = [ ] // constant reference to avoid re-running effects
34+
3335export const MarkdownInput = forwardRef < HTMLTextAreaElement , MarkdownInputProps > (
3436 (
3537 {
@@ -55,33 +57,62 @@ export const MarkdownInput = forwardRef<HTMLTextAreaElement, MarkdownInputProps>
5557 forwardedRef ,
5658 ) => {
5759 const [ suggestions , setSuggestions ] = useState < Suggestions | null > ( null )
60+ const [ event , setEvent ] = useState < ShowSuggestionsEvent | null > ( null )
5861
5962 const { trigger : emojiTrigger , calculateSuggestions : calculateEmojiSuggestions } = useEmojiSuggestions (
60- emojiSuggestions ?? [ ] ,
63+ emojiSuggestions ?? emptyArray ,
6164 )
6265 const { trigger : mentionsTrigger , calculateSuggestions : calculateMentionSuggestions } = useMentionSuggestions (
63- mentionSuggestions ?? [ ] ,
66+ mentionSuggestions ?? emptyArray ,
6467 )
6568 const { trigger : referencesTrigger , calculateSuggestions : calculateReferenceSuggestions } = useReferenceSuggestions (
66- referenceSuggestions ?? [ ] ,
69+ referenceSuggestions ?? emptyArray ,
6770 )
6871
6972 const triggers = useMemo (
7073 ( ) => [ mentionsTrigger , referencesTrigger , emojiTrigger ] ,
7174 [ mentionsTrigger , referencesTrigger , emojiTrigger ] ,
7275 )
7376
74- const onShowSuggestions = async ( event : ShowSuggestionsEvent ) => {
75- setSuggestions ( 'loading' )
76- if ( event . trigger . triggerChar === emojiTrigger . triggerChar ) {
77- setSuggestions ( await calculateEmojiSuggestions ( event . query ) )
78- } else if ( event . trigger . triggerChar === mentionsTrigger . triggerChar ) {
79- setSuggestions ( await calculateMentionSuggestions ( event . query ) )
80- } else if ( event . trigger . triggerChar === referencesTrigger . triggerChar ) {
81- setSuggestions ( await calculateReferenceSuggestions ( event . query ) )
82- }
77+ const lastEventRef = useRef < ShowSuggestionsEvent | null > ( null )
78+
79+ const onHideSuggestions = ( ) => {
80+ setEvent ( null )
81+ setSuggestions ( null ) // the effect would do this anyway, but this allows React to batch the update
8382 }
8483
84+ // running the calculation in an effect (rather than in the onShowSuggestions handler) allows us
85+ // to automatically recalculate if the suggestions change while the menu is open
86+ useEffect ( ( ) => {
87+ if ( ! event ) {
88+ setSuggestions ( null )
89+ return
90+ }
91+
92+ // (prettier vs. eslint conflict)
93+ // eslint-disable-next-line @typescript-eslint/no-extra-semi
94+ ; ( async function ( ) {
95+ lastEventRef . current = event
96+ setSuggestions ( 'loading' )
97+ if ( event . trigger . triggerChar === emojiTrigger . triggerChar ) {
98+ setSuggestions ( await calculateEmojiSuggestions ( event . query ) )
99+ } else if ( event . trigger . triggerChar === mentionsTrigger . triggerChar ) {
100+ setSuggestions ( await calculateMentionSuggestions ( event . query ) )
101+ } else if ( event . trigger . triggerChar === referencesTrigger . triggerChar ) {
102+ setSuggestions ( await calculateReferenceSuggestions ( event . query ) )
103+ }
104+ } ) ( )
105+ } , [
106+ event ,
107+ calculateEmojiSuggestions ,
108+ calculateMentionSuggestions ,
109+ calculateReferenceSuggestions ,
110+ // The triggers never actually change because they are statically defined
111+ emojiTrigger ,
112+ mentionsTrigger ,
113+ referencesTrigger ,
114+ ] )
115+
85116 const ref = useRef < HTMLTextAreaElement > ( null )
86117 useRefObjectAsForwardedRef ( forwardedRef , ref )
87118
@@ -99,8 +130,8 @@ export const MarkdownInput = forwardRef<HTMLTextAreaElement, MarkdownInputProps>
99130 < InlineAutocomplete
100131 triggers = { triggers }
101132 suggestions = { suggestions }
102- onShowSuggestions = { e => onShowSuggestions ( e ) }
103- onHideSuggestions = { ( ) => setSuggestions ( null ) }
133+ onShowSuggestions = { setEvent }
134+ onHideSuggestions = { onHideSuggestions }
104135 sx = { { flex : 'auto' } }
105136 tabInsertsSuggestions
106137 >
0 commit comments