@@ -24,10 +24,11 @@ import { UserResponse } from 'stream-chat';
2424import { ChannelService } from '../../channel.service' ;
2525import { TextareaInterface } from '../textarea.interface' ;
2626import { ChatClientService } from '../../chat-client.service' ;
27- import { debounceTime } from 'rxjs/operators' ;
27+ import { debounceTime , filter } from 'rxjs/operators' ;
2828import { TransliterationService } from '../../transliteration.service' ;
2929import { EmojiInputService } from '../emoji-input.service' ;
3030import { CustomTemplatesService } from '../../custom-templates.service' ;
31+ import { MessageInputConfigService } from '../message-input-config.service' ;
3132
3233/**
3334 * The `AutocompleteTextarea` component is used by the [`MessageInput`](./MessageInputComponent.mdx) component to display the input HTML element where users can type their message.
@@ -137,13 +138,21 @@ export class AutocompleteTextareaComponent
137138 private transliterationService : TransliterationService ,
138139 private emojiInputService : EmojiInputService ,
139140 private customTemplatesService : CustomTemplatesService ,
140- private cdRef : ChangeDetectorRef
141+ private cdRef : ChangeDetectorRef ,
142+ private messageInputConfigService : MessageInputConfigService
141143 ) {
142- this . searchTerm$ . pipe ( debounceTime ( 300 ) ) . subscribe ( ( searchTerm ) => {
143- if ( searchTerm . startsWith ( this . mentionTriggerChar ) ) {
144- void this . updateMentionOptions ( searchTerm ) ;
145- }
146- } ) ;
144+ this . searchTerm$
145+ . pipe (
146+ filter ( ( searchTerm ) => searchTerm . length !== 1 ) ,
147+ debounceTime ( 300 )
148+ )
149+ . subscribe ( ( searchTerm ) => {
150+ if ( searchTerm . startsWith ( this . mentionTriggerChar ) ) {
151+ void this . updateMentionOptions ( searchTerm ) ;
152+ } else {
153+ void this . updateCustomAutocompleteOptions ( searchTerm ) ;
154+ }
155+ } ) ;
147156 this . subscriptions . push (
148157 this . channelService . activeChannel$ . subscribe ( ( channel ) => {
149158 const commands = channel ?. getConfig ( ) ?. commands || [ ] ;
@@ -155,6 +164,7 @@ export class AutocompleteTextareaComponent
155164 this . mentionedUsers = [ ] ;
156165 this . userMentions . next ( [ ...this . mentionedUsers ] ) ;
157166 void this . updateMentionOptions ( this . searchTerm$ . getValue ( ) ) ;
167+ void this . updateCustomAutocompleteOptions ( this . searchTerm$ . getValue ( ) ) ;
158168 } )
159169 ) ;
160170 this . subscriptions . push (
@@ -183,20 +193,60 @@ export class AutocompleteTextareaComponent
183193 this . userMentionConfig ,
184194 this . slashCommandConfig ,
185195 ] ;
196+ this . subscriptions . push (
197+ this . messageInputConfigService . customAutocompletes$ . subscribe (
198+ ( customConfigs ) => {
199+ const builtInItems =
200+ this . autocompleteConfig . mentions ?. filter (
201+ ( m ) =>
202+ m === this . userMentionConfig || m === this . slashCommandConfig
203+ ) ?? [ ] ;
204+ const transformedCustomConfigs = customConfigs . map ( ( c ) => {
205+ const copy : Mentions = {
206+ items : c . options . map ( ( o ) => ( {
207+ ...o ,
208+ templateRef : c . templateRef ,
209+ } ) ) ,
210+ triggerChar : c . triggerCharacter ,
211+ dropUp : true ,
212+ labelKey : this . autocompleteKey ,
213+ returnTrigger : true ,
214+ allowSpace : c . allowSpace ,
215+ mentionFilter : (
216+ searchString : string ,
217+ items : { autocompleteLabel : string } [ ]
218+ ) => this . filter ( searchString , items ) ,
219+ mentionSelect : ( item , triggerChar ) =>
220+ this . itemSelectedFromAutocompleteList (
221+ item as MentionAutcompleteListItem ,
222+ triggerChar
223+ ) ,
224+ } ;
225+
226+ return copy ;
227+ } ) ;
228+
229+ this . autocompleteConfig . mentions = [
230+ ...builtInItems ,
231+ ...transformedCustomConfigs ,
232+ ] ;
233+ this . autocompleteConfig = { ...this . autocompleteConfig } ;
234+ }
235+ )
236+ ) ;
186237 }
187238
188239 ngOnChanges ( changes : SimpleChanges ) : void {
189240 if ( changes . areMentionsEnabled ) {
190- if ( this . areMentionsEnabled ) {
191- this . autocompleteConfig . mentions = [
192- this . userMentionConfig ,
193- this . slashCommandConfig ,
194- ] ;
195- this . autocompleteConfig = { ...this . autocompleteConfig } ;
196- } else {
197- this . autocompleteConfig . mentions = [ this . slashCommandConfig ] ;
198- this . autocompleteConfig = { ...this . autocompleteConfig } ;
199- }
241+ this . autocompleteConfig . mentions =
242+ this . autocompleteConfig ?. mentions ?. filter ( ( c ) => {
243+ if ( c !== this . userMentionConfig ) {
244+ return true ;
245+ } else {
246+ return this . areMentionsEnabled ;
247+ }
248+ } ) ?? [ ] ;
249+ this . autocompleteConfig = { ...this . autocompleteConfig } ;
200250 }
201251 if ( changes . mentionScope ) {
202252 void this . updateMentionOptions ( this . searchTerm$ . getValue ( ) ) ;
@@ -258,11 +308,14 @@ export class AutocompleteTextareaComponent
258308 }
259309
260310 autcompleteSearchTermChanged ( searchTerm : string ) {
261- if ( searchTerm === this . mentionTriggerChar ) {
262- void this . updateMentionOptions ( ) ;
263- } else {
264- this . searchTerm$ . next ( searchTerm ) ;
311+ if ( searchTerm . length === 1 ) {
312+ if ( searchTerm === this . mentionTriggerChar ) {
313+ void this . updateMentionOptions ( ) ;
314+ } else {
315+ void this . updateCustomAutocompleteOptions ( searchTerm ) ;
316+ }
265317 }
318+ this . searchTerm$ . next ( searchTerm ) ;
266319 }
267320
268321 inputChanged ( ) {
@@ -326,8 +379,7 @@ export class AutocompleteTextareaComponent
326379 ) ;
327380 this . userMentionConfig . items = items ;
328381 this . autocompleteConfig . mentions = [
329- this . userMentionConfig ,
330- this . slashCommandConfig ,
382+ ...( this . autocompleteConfig ?. mentions ?? [ ] ) ,
331383 ] ;
332384 this . autocompleteConfig = { ...this . autocompleteConfig } ;
333385 this . cdRef . detectChanges ( ) ;
@@ -346,4 +398,31 @@ export class AutocompleteTextareaComponent
346398 this . mentionedUsers = updatedMentionedUsers ;
347399 }
348400 }
401+
402+ private async updateCustomAutocompleteOptions ( searchTerm : string ) {
403+ if (
404+ this . messageInputConfigService . customAutocompletes$ . getValue ( ) . length ===
405+ 0
406+ ) {
407+ return ;
408+ }
409+ const customMentionConfig = this . autocompleteConfig . mentions ?. find (
410+ ( c ) => c . triggerChar && searchTerm . startsWith ( c . triggerChar )
411+ ) ;
412+ const customAutocompleteConfig = customMentionConfig
413+ ? this . messageInputConfigService . customAutocompletes$
414+ . getValue ( )
415+ . find ( ( c ) => c . triggerCharacter === customMentionConfig ?. triggerChar )
416+ : undefined ;
417+ if ( customMentionConfig && customAutocompleteConfig ?. updateOptions ) {
418+ const newOptions = await customAutocompleteConfig . updateOptions (
419+ searchTerm . replace ( customMentionConfig . triggerChar || '' , '' )
420+ ) ;
421+ customMentionConfig . items = newOptions . map ( ( o ) => ( {
422+ ...o ,
423+ templateRef : customAutocompleteConfig . templateRef ,
424+ } ) ) ;
425+ this . autocompleteConfig = { ...this . autocompleteConfig } ;
426+ }
427+ }
349428}
0 commit comments