@@ -243,6 +243,7 @@ class ReactTextareaAutocomplete extends React.Component<
243
243
}
244
244
245
245
if ( oldValue !== value && this . lastValueBubbledEvent !== value ) {
246
+ this . lastTrigger = 0 ;
246
247
this . _changeHandler ( ) ;
247
248
}
248
249
}
@@ -361,6 +362,11 @@ class ReactTextareaAutocomplete extends React.Component<
361
362
dataLoading : false
362
363
} ,
363
364
( ) => {
365
+ const insertedTrigger = this . tokenRegExpEnding . exec ( newTokenString ) ;
366
+ const insertedTriggerModifier = insertedTrigger
367
+ ? insertedTrigger [ 0 ] . length
368
+ : 1 ;
369
+ this . lastTrigger = newCaretPosition - insertedTriggerModifier ;
364
370
this . textareaRef . value = newValue ;
365
371
this . _changeHandler ( ) ;
366
372
@@ -532,6 +538,22 @@ class ReactTextareaAutocomplete extends React.Component<
532
538
. map ( a => `\\${ a } ` )
533
539
. join ( "|" ) } )((?:(?!\\1)[^\\s])*$)`
534
540
) ;
541
+
542
+ this . tokenRegExpEnding = new RegExp (
543
+ `(${ Object . keys ( trigger )
544
+ // the sort is important for multi-char combos as "/kick", "/"
545
+ . sort ( ( a , b ) => {
546
+ if ( a < b ) {
547
+ return 1 ;
548
+ }
549
+ if ( a > b ) {
550
+ return - 1 ;
551
+ }
552
+ return 0 ;
553
+ } )
554
+ . map ( a => `\\${ a } ` )
555
+ . join ( "|" ) } )$`
556
+ ) ;
535
557
} ;
536
558
537
559
/**
@@ -622,11 +644,28 @@ class ReactTextareaAutocomplete extends React.Component<
622
644
value
623
645
} ) ;
624
646
625
- let tokenMatch = this . tokenRegExp . exec ( value . slice ( 0 , selectionEnd ) ) ;
647
+ const cleanLastTrigger = ( ) => {
648
+ this . lastTrigger = selectionEnd - 1 ;
649
+ } ;
650
+
651
+ if ( selectionEnd <= this . lastTrigger ) {
652
+ cleanLastTrigger ( ) ;
653
+ }
654
+
655
+ const affectedTextareaValue = value . slice ( this . lastTrigger , selectionEnd ) ;
656
+
657
+ let tokenMatch = this . tokenRegExp . exec ( affectedTextareaValue ) ;
626
658
let lastToken = tokenMatch && tokenMatch [ 0 ] ;
627
659
628
660
let currentTrigger = ( tokenMatch && tokenMatch [ 1 ] ) || null ;
629
661
662
+ // with this approach we want to know if the user just inserted a new trigger sequence
663
+ const isNewTrigger = this . tokenRegExpEnding . exec ( affectedTextareaValue ) ;
664
+
665
+ if ( isNewTrigger ) {
666
+ cleanLastTrigger ( ) ;
667
+ }
668
+
630
669
/*
631
670
if we lost the trigger token or there is no following character we want to close
632
671
the autocomplete
@@ -650,9 +689,8 @@ class ReactTextareaAutocomplete extends React.Component<
650
689
*/
651
690
if (
652
691
currentTrigger &&
653
- value [ tokenMatch . index - 1 ] &&
654
- ( trigger [ currentTrigger ] . afterWhitespace &&
655
- ! value [ tokenMatch . index - 1 ] . match ( / \s / ) )
692
+ trigger [ currentTrigger ] . afterWhitespace &&
693
+ value [ selectionEnd - 2 ] !== " "
656
694
) {
657
695
this . _closeAutocomplete ( ) ;
658
696
return ;
@@ -797,6 +835,11 @@ class ReactTextareaAutocomplete extends React.Component<
797
835
798
836
lastValueBubbledEvent : string ;
799
837
838
+ tokenRegExpEnding : RegExp ;
839
+
840
+ // Last trigger index, to know when user selected the item and we should stop showing the autocomplete
841
+ lastTrigger : number = 0 ;
842
+
800
843
render ( ) {
801
844
const {
802
845
loadingComponent : Loader ,
0 commit comments