@@ -30,6 +30,8 @@ interface MarkdownInputProps extends Omit<TextareaProps, 'onChange'> {
30
30
visible : boolean
31
31
}
32
32
33
+ const emptyArray : [ ] = [ ] // constant reference to avoid re-running effects
34
+
33
35
export const MarkdownInput = forwardRef < HTMLTextAreaElement , MarkdownInputProps > (
34
36
(
35
37
{
@@ -55,33 +57,62 @@ export const MarkdownInput = forwardRef<HTMLTextAreaElement, MarkdownInputProps>
55
57
forwardedRef ,
56
58
) => {
57
59
const [ suggestions , setSuggestions ] = useState < Suggestions | null > ( null )
60
+ const [ event , setEvent ] = useState < ShowSuggestionsEvent | null > ( null )
58
61
59
62
const { trigger : emojiTrigger , calculateSuggestions : calculateEmojiSuggestions } = useEmojiSuggestions (
60
- emojiSuggestions ?? [ ] ,
63
+ emojiSuggestions ?? emptyArray ,
61
64
)
62
65
const { trigger : mentionsTrigger , calculateSuggestions : calculateMentionSuggestions } = useMentionSuggestions (
63
- mentionSuggestions ?? [ ] ,
66
+ mentionSuggestions ?? emptyArray ,
64
67
)
65
68
const { trigger : referencesTrigger , calculateSuggestions : calculateReferenceSuggestions } = useReferenceSuggestions (
66
- referenceSuggestions ?? [ ] ,
69
+ referenceSuggestions ?? emptyArray ,
67
70
)
68
71
69
72
const triggers = useMemo (
70
73
( ) => [ mentionsTrigger , referencesTrigger , emojiTrigger ] ,
71
74
[ mentionsTrigger , referencesTrigger , emojiTrigger ] ,
72
75
)
73
76
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
83
82
}
84
83
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
+
85
116
const ref = useRef < HTMLTextAreaElement > ( null )
86
117
useRefObjectAsForwardedRef ( forwardedRef , ref )
87
118
@@ -99,8 +130,8 @@ export const MarkdownInput = forwardRef<HTMLTextAreaElement, MarkdownInputProps>
99
130
< InlineAutocomplete
100
131
triggers = { triggers }
101
132
suggestions = { suggestions }
102
- onShowSuggestions = { e => onShowSuggestions ( e ) }
103
- onHideSuggestions = { ( ) => setSuggestions ( null ) }
133
+ onShowSuggestions = { setEvent }
134
+ onHideSuggestions = { onHideSuggestions }
104
135
sx = { { flex : 'auto' } }
105
136
tabInsertsSuggestions
106
137
>
0 commit comments