@@ -534,63 +534,66 @@ export class GlTreeGenerator extends GlElement {
534534 }
535535
536536 override render ( ) : unknown {
537- if ( ! this . treeItems ?. length ) {
538- if ( this . _filterText && this . _model ?. length ) {
539- return html `${ this . renderFilterBar ( ) }
540- < div class ="no-results "> No results found</ div > ` ;
541- }
542- return nothing ;
543- }
537+ const hasItems = Boolean ( this . treeItems ?. length ) ;
538+ const showNoResults = ! hasItems && this . _filterText && this . _model ?. length ;
539+
540+ if ( ! hasItems && ! showNoResults ) return nothing ;
544541
545542 // Container-focused approach: the scrollable div is the focusable element
546543 // Use aria-activedescendant to indicate which tree item is active for screen readers
547544 const activeDescendant = this . _focusedItemPath ? `tree-item-${ this . _focusedItemPath } ` : undefined ;
548545
549- // Use keyed directive to force virtualizer re-creation when model changes
550- // This prevents stale DOM node references in the repeat directive
546+ // Keep a single top-level template across the has-results/no-results transition so Lit
547+ // patches in place — swapping top-level templates would tear down the filter input and
548+ // lose focus while the user is still typing.
551549 return html `
552550 ${ this . renderFilterBar ( ) }
553- < div
554- ${ ref ( this . scrollableRef ) }
555- class ="scrollable "
556- tabindex ="0 "
557- role ="tree "
558- aria-label =${ this . ariaLabel }
559- aria-multiselectable ="false"
560- aria-activedescendant=${ activeDescendant || nothing }
561- @keydown=${ this . handleContainerKeydown }
562- @focus=${ this . handleContainerFocus }
563- @blur=${ this . handleContainerBlur }
564- >
565- ${ keyed (
566- this . _virtualizerKey ,
567- html `< lit-virtualizer
568- class ="scrollable "
569- ${ ref ( this . virtualizerRef ) }
570- .items =${ this . treeItems }
571- .keyFunction =${ ( item : TreeModelFlat ) => item . path }
572- .layout=${ flow ( { direction : 'vertical' } ) }
573- .renderItem=${ ( node : TreeModelFlat ) => this . renderTreeItem ( node ) }
574- scroller
575- > </ lit-virtualizer > ` ,
576- ) }
577- </ div >
578- ${ this . _hoverOpen && this . _hoveredTooltip
579- ? html `< gl-popover
580- ?open =${ this . _hoverOpen }
581- .anchor =${ this . _hoveredAnchor }
582- .placement=${ this . tooltipAnchorRight ? 'right-start' : 'bottom' }
583- trigger="manual"
584- hoist
585- .distance=${ 4 }
586- @mouseenter=${ ( ) => clearTimeout ( this . _unhoverTimer ) }
587- @mouseleave=${ ( ) => this . onTreeItemUnhover ( ) }
588- >
589- < div slot ="content " class ="hover-content ">
590- < gl-markdown density ="compact " .markdown =${ this . _hoveredTooltip ?? '' } > </ gl-markdown >
551+ ${ showNoResults
552+ ? html `< div class ="no-results "> No results found</ div > `
553+ : html `< div
554+ ${ ref ( this . scrollableRef ) }
555+ class ="scrollable "
556+ tabindex ="0 "
557+ role ="tree "
558+ aria-label =${ this . ariaLabel }
559+ aria-multiselectable ="false"
560+ aria-activedescendant=${ activeDescendant || nothing }
561+ @keydown=${ this . handleContainerKeydown }
562+ @focus=${ this . handleContainerFocus }
563+ @blur=${ this . handleContainerBlur }
564+ >
565+ ${ keyed (
566+ this . _virtualizerKey ,
567+ html `< lit-virtualizer
568+ class ="scrollable "
569+ ${ ref ( this . virtualizerRef ) }
570+ .items =${ this . treeItems }
571+ .keyFunction =${ ( item : TreeModelFlat ) => item . path }
572+ .layout=${ flow ( { direction : 'vertical' } ) }
573+ .renderItem=${ ( node : TreeModelFlat ) => this . renderTreeItem ( node ) }
574+ scroller
575+ > </ lit-virtualizer > ` ,
576+ ) }
591577 </ div >
592- </ gl-popover > `
593- : nothing }
578+ ${ this . _hoverOpen && this . _hoveredTooltip
579+ ? html `< gl-popover
580+ ?open =${ this . _hoverOpen }
581+ .anchor =${ this . _hoveredAnchor }
582+ .placement=${ this . tooltipAnchorRight ? 'right-start' : 'bottom' }
583+ trigger="manual"
584+ hoist
585+ .distance=${ 4 }
586+ @mouseenter=${ ( ) => clearTimeout ( this . _unhoverTimer ) }
587+ @mouseleave=${ ( ) => this . onTreeItemUnhover ( ) }
588+ >
589+ < div slot ="content " class ="hover-content ">
590+ < gl-markdown
591+ density ="compact "
592+ .markdown =${ this . _hoveredTooltip ?? '' }
593+ > </ gl-markdown >
594+ </ div >
595+ </ gl-popover > `
596+ : nothing } `}
594597 ` ;
595598 }
596599
0 commit comments