@@ -3113,6 +3113,7 @@ describe('MatSelect', () => {
31133113 BasicSelect ,
31143114 MultiSelect ,
31153115 SelectWithGroups ,
3116+ SelectWithIndirectDescendantGroups ,
31163117 ] ) ) ) ;
31173118
31183119 beforeEach ( ( inject ( [ ViewportRuler ] , ( vr : ViewportRuler ) => {
@@ -3293,6 +3294,45 @@ describe('MatSelect', () => {
32933294 checkTriggerAlignedWithOption ( 7 , groupFixture . componentInstance . select ) ;
32943295 } ) ) ;
32953296
3297+ it ( 'should account for indirect preceding label groups when aligning the option' ,
3298+ fakeAsync ( ( ) => {
3299+ // Test is off-by-one on edge for some reason, but verified that it looks correct through
3300+ // manual testing.
3301+ if ( platform . EDGE ) {
3302+ return ;
3303+ }
3304+
3305+ fixture . destroy ( ) ;
3306+
3307+ let groupFixture = TestBed . createComponent ( SelectWithIndirectDescendantGroups ) ;
3308+ groupFixture . detectChanges ( ) ;
3309+ trigger = groupFixture . debugElement . query ( By . css ( '.mat-select-trigger' ) ) ! . nativeElement ;
3310+ formField = groupFixture . debugElement . query ( By . css ( 'mat-form-field' ) ) ! . nativeElement ;
3311+
3312+ formField . style . position = 'fixed' ;
3313+ formField . style . top = '200px' ;
3314+ formField . style . left = '100px' ;
3315+
3316+ // Select an option in the third group, which has a couple of group labels before it.
3317+ groupFixture . componentInstance . control . setValue ( 'vulpix-7' ) ;
3318+ groupFixture . detectChanges ( ) ;
3319+
3320+ trigger . click ( ) ;
3321+ groupFixture . detectChanges ( ) ;
3322+ flush ( ) ;
3323+
3324+ const scrollContainer = document . querySelector ( '.cdk-overlay-pane .mat-select-panel' ) ! ;
3325+
3326+ // The selected option should be scrolled to the center of the panel.
3327+ // This will be its original offset from the scrollTop - half the panel height + half the
3328+ // option height. 10 (option index + 3 group labels before it) * 48 (option height) = 480
3329+ // 480 (offset from scrollTop) - 256/2 + 48/2 = 376px
3330+ expect ( Math . floor ( scrollContainer . scrollTop ) )
3331+ . toBe ( 376 , `Expected overlay panel to be scrolled to center the selected option.` ) ;
3332+
3333+ checkTriggerAlignedWithOption ( 7 , groupFixture . componentInstance . select ) ;
3334+ } ) ) ;
3335+
32963336 } ) ;
32973337
32983338 describe ( 'limited space to open vertically' , ( ) => {
@@ -4814,6 +4854,29 @@ class SelectWithGroups {
48144854 @ViewChildren ( MatOption ) options : QueryList < MatOption > ;
48154855}
48164856
4857+ @Component ( {
4858+ selector : 'select-with-indirect-groups' ,
4859+ // Note that we need the blank `ngSwitch` in order to have
4860+ // a directive between `mat-select` and `mat-optgroup`.
4861+ template : `
4862+ <mat-form-field>
4863+ <mat-select placeholder="Pokemon" [formControl]="control">
4864+ <ng-container [ngSwitch]="true">
4865+ <mat-optgroup *ngFor="let group of pokemonTypes" [label]="group.name"
4866+ [disabled]="group.disabled">
4867+ <mat-option *ngFor="let pokemon of group.pokemon" [value]="pokemon.value">
4868+ {{ pokemon.viewValue }}
4869+ </mat-option>
4870+ </mat-optgroup>
4871+ <mat-option value="mime-11">Mr. Mime</mat-option>
4872+ </ng-container>
4873+ </mat-select>
4874+ </mat-form-field>
4875+ `
4876+ } )
4877+ class SelectWithIndirectDescendantGroups extends SelectWithGroups {
4878+ }
4879+
48174880@Component ( {
48184881 selector : 'select-with-groups' ,
48194882 template : `
0 commit comments