@@ -323,8 +323,7 @@ export class GlSearchInput extends GlElement {
323323 @state ( ) private autocompleteOpen = false ;
324324 @state ( ) private autocompleteItems : SearchCompletionItem [ ] = [ ] ;
325325 @state ( ) private cursorOperator ?: SearchCompletionOperator ;
326- private autocompleteStartPos = 0 ;
327- private autocompleteEndPos = 0 ;
326+ private cursorPosition : [ number , number ] = [ 0 , 0 ] ;
328327
329328 @query ( 'gl-autocomplete' ) private autocomplete ?: GlAutocomplete ;
330329
@@ -333,6 +332,10 @@ export class GlSearchInput extends GlElement {
333332 // Track last search to avoid re-searching on Enter when query hasn't changed
334333 private _lastSearch : SearchQuery | undefined = undefined ;
335334
335+ private get inputFocused ( ) : boolean {
336+ return this . renderRoot instanceof ShadowRoot ? this . renderRoot . activeElement === this . input : false ;
337+ }
338+
336339 private get label ( ) {
337340 return this . filter ? 'Filter' : 'Search' ;
338341 }
@@ -415,7 +418,7 @@ export class GlSearchInput extends GlElement {
415418
416419 // When searching state changes in NL mode, ensure autocomplete is open to show progress
417420 if ( changedProperties . has ( 'searching' ) && this . naturalLanguage ) {
418- this . autocompleteOpen = true ;
421+ this . autocompleteOpen = this . inputFocused ;
419422 }
420423
421424 super . updated ( changedProperties ) ;
@@ -489,7 +492,7 @@ export class GlSearchInput extends GlElement {
489492 if ( this . naturalLanguage ) {
490493 this . autocompleteItems = [ ] ;
491494 this . cursorOperator = undefined ;
492- this . autocompleteOpen = true ;
495+ this . autocompleteOpen = this . inputFocused ;
493496 return ;
494497 }
495498
@@ -508,10 +511,9 @@ export class GlSearchInput extends GlElement {
508511 this . autocompleteItems = [ naturalLanguageSearchAutocompleteCommand , ...operators ] ;
509512
510513 this . cursorOperator = undefined ;
511- this . autocompleteStartPos = 0 ;
512- this . autocompleteEndPos = 0 ;
513- this . autocompleteOpen = true ;
514+ this . cursorPosition = [ 0 , 0 ] ;
514515 this . autocomplete ?. resetSelection ( ) ;
516+ this . autocompleteOpen = this . inputFocused ;
515517 return ;
516518 }
517519
@@ -559,10 +561,9 @@ export class GlSearchInput extends GlElement {
559561 this . cursorOperator = completeValue . description
560562 ? { ...metadata , description : completeValue . description , example : undefined }
561563 : metadata ;
562- this . autocompleteStartPos = start ;
563- this . autocompleteEndPos = end ;
564- this . autocompleteOpen = true ;
564+ this . cursorPosition = [ start , end ] ;
565565 this . autocomplete ?. resetSelection ( ) ;
566+ this . autocompleteOpen = this . inputFocused ;
566567 return ;
567568 }
568569
@@ -587,20 +588,18 @@ export class GlSearchInput extends GlElement {
587588 matches . sort ( ( a , b ) => ( b . score ?? 0 ) - ( a . score ?? 0 ) ) ;
588589 this . autocompleteItems = matches ;
589590 this . cursorOperator = metadata ; // Show operator description
590- this . autocompleteStartPos = start + opPart . length ;
591- this . autocompleteEndPos = end ;
592- this . autocompleteOpen = true ;
591+ this . cursorPosition = [ start + opPart . length , end ] ;
593592 this . autocomplete ?. resetSelection ( ) ;
593+ this . autocompleteOpen = this . inputFocused ;
594594 return ;
595595 }
596596
597597 // Default: show operator help text
598598 this . autocompleteItems = [ ] ;
599599 this . cursorOperator = metadata ;
600- this . autocompleteStartPos = start ;
601- this . autocompleteEndPos = end ;
602- this . autocompleteOpen = true ;
600+ this . cursorPosition = [ start , end ] ;
603601 this . autocomplete ?. resetSelection ( ) ;
602+ this . autocompleteOpen = this . inputFocused ;
604603 return ;
605604 }
606605 }
@@ -627,8 +626,7 @@ export class GlSearchInput extends GlElement {
627626 } ) satisfies SearchCompletionItem ,
628627 ) ;
629628 this . cursorOperator = metadata ; // Show operator description
630- this . autocompleteStartPos = start + longForm . length ;
631- this . autocompleteEndPos = end ;
629+ this . cursorPosition = [ start + longForm . length , end ] ;
632630 this . autocompleteOpen = true ;
633631 this . autocomplete ?. resetSelection ( ) ;
634632 return ;
@@ -637,8 +635,7 @@ export class GlSearchInput extends GlElement {
637635 // Default: show operator help text
638636 this . autocompleteItems = [ ] ;
639637 this . cursorOperator = metadata ;
640- this . autocompleteStartPos = start ;
641- this . autocompleteEndPos = end ;
638+ this . cursorPosition = [ start , end ] ;
642639 this . autocompleteOpen = true ;
643640 this . autocomplete ?. resetSelection ( ) ;
644641 return ;
@@ -686,8 +683,7 @@ export class GlSearchInput extends GlElement {
686683 if ( ! this . naturalLanguage ) {
687684 this . autocompleteItems = [ naturalLanguageSearchAutocompleteCommand ] ;
688685 this . cursorOperator = undefined ;
689- this . autocompleteStartPos = start ;
690- this . autocompleteEndPos = end ;
686+ this . cursorPosition = [ start , end ] ;
691687 this . autocompleteOpen = true ;
692688 this . autocomplete ?. resetSelection ( ) ;
693689 } else {
@@ -707,8 +703,7 @@ export class GlSearchInput extends GlElement {
707703
708704 this . autocompleteItems = newItems ;
709705 this . cursorOperator = undefined ;
710- this . autocompleteStartPos = start ;
711- this . autocompleteEndPos = end ;
706+ this . cursorPosition = [ start , end ] ;
712707 this . autocompleteOpen = true ;
713708 this . autocomplete ?. resetSelection ( ) ;
714709 }
@@ -739,60 +734,54 @@ export class GlSearchInput extends GlElement {
739734 const value = this . value ;
740735
741736 // Determine what to insert:
742- // - If it's a value completion, insert just the value (autocompleteStartPos is already after the operator)
737+ // - If it's a value completion, insert just the value (cursorPosition[0] is already after the operator)
743738 // - Otherwise, insert the operator
744739 const insertText = 'value' in selected . item ? selected . item . value : operator ;
745740
746- // Replace the entire token (from autocompleteStartPos to autocompleteEndPos ) with the selected text
741+ // Replace the entire token (from cursorPosition[0] to cursorPosition[1] ) with the selected text
747742 // This ensures we don't leave partial text when cursor is in the middle of a token
748743 const newValue =
749- value . substring ( 0 , this . autocompleteStartPos ) + insertText + value . substring ( this . autocompleteEndPos ) ;
744+ value . substring ( 0 , this . cursorPosition [ 0 ] ) + insertText + value . substring ( this . cursorPosition [ 1 ] ) ;
750745
751746 // Update the input value directly
752747 this . input . value = newValue ;
753748 this . _value = newValue ;
754749
755750 // Position cursor after the inserted text
756- const cursorPos = this . autocompleteStartPos + insertText . length ;
751+ const cursorPos = this . cursorPosition [ 0 ] + insertText . length ;
757752 this . input . focus ( ) ;
758753 this . input . selectionStart = cursorPos ;
759754 this . input . selectionEnd = cursorPos ;
760755
761756 // Update autocomplete in the next frame to ensure input is updated
762- window . requestAnimationFrame ( ( ) => {
763- this . updateAutocomplete ( ) ;
764- } ) ;
757+ window . requestAnimationFrame ( ( ) => this . updateAutocomplete ( ) ) ;
765758 }
766759
767760 private handleMatchAll ( _e : Event ) {
768761 this . matchAll = ! this . matchAll ;
769- // Only trigger search if there's a query value
770762 if ( this . value ) {
771- this . onSearchChanged ( true ) ; // Force search when options change
763+ this . onSearchChanged ( true ) ;
772764 }
773765 }
774766
775767 private handleMatchCase ( _e : Event ) {
776768 this . matchCase = ! this . matchCase ;
777- // Only trigger search if there's a query value
778769 if ( this . value ) {
779- this . onSearchChanged ( true ) ; // Force search when options change
770+ this . onSearchChanged ( true ) ;
780771 }
781772 }
782773
783774 private handleMatchRegex ( _e : Event ) {
784775 this . matchRegex = ! this . matchRegex ;
785- // Only trigger search if there's a query value
786776 if ( this . value ) {
787- this . onSearchChanged ( true ) ; // Force search when options change
777+ this . onSearchChanged ( true ) ;
788778 }
789779 }
790780
791781 private handleMatchWholeWord ( _e : Event ) {
792782 this . matchWholeWord = ! this . matchWholeWord ;
793- // Only trigger search if there's a query value
794783 if ( this . value ) {
795- this . onSearchChanged ( true ) ; // Force search when options change
784+ this . onSearchChanged ( true ) ;
796785 }
797786 }
798787
0 commit comments