Skip to content

Commit 17a9ad0

Browse files
authored
feat(material/select): add a global option to specify overlay panel class (#20702)
* feat(material/select): add a global option to specify overlay panel class * fix(material/select): address comments
1 parent d8396f2 commit 17a9ad0

File tree

6 files changed

+29
-20
lines changed

6 files changed

+29
-20
lines changed

src/material-experimental/mdc-select/select.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
cdkConnectedOverlayLockPosition
2020
cdkConnectedOverlayHasBackdrop
2121
cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
22+
[cdkConnectedOverlayPanelClass]="_overlayPanelClass"
2223
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
2324
[cdkConnectedOverlayOrigin]="_preferredOverlayOrigin || fallbackOverlayOrigin"
2425
[cdkConnectedOverlayOpen]="panelOpen"

src/material-experimental/mdc-select/select.spec.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3765,21 +3765,26 @@ describe('MDC-based MatSelect', () => {
37653765

37663766
});
37673767

3768-
it('should be able to provide default values through an injection token', () => {
3768+
it('should be able to provide default values through an injection token', fakeAsync(() => {
37693769
configureMatSelectTestingModule([NgModelSelect], [{
37703770
provide: MAT_SELECT_CONFIG,
37713771
useValue: {
37723772
disableOptionCentering: true,
3773-
typeaheadDebounceInterval: 1337
3773+
typeaheadDebounceInterval: 1337,
3774+
overlayPanelClass: 'test-panel-class',
37743775
} as MatSelectConfig
37753776
}]);
37763777
const fixture = TestBed.createComponent(NgModelSelect);
37773778
fixture.detectChanges();
37783779
const select = fixture.componentInstance.select;
3780+
select.open();
3781+
fixture.detectChanges();
3782+
flush();
37793783

37803784
expect(select.disableOptionCentering).toBe(true);
37813785
expect(select.typeaheadDebounceInterval).toBe(1337);
3782-
});
3786+
expect(document.querySelector('.cdk-overlay-pane')?.classList).toContain('test-panel-class');
3787+
}));
37833788

37843789
it('should not not throw if the select is inside an ng-container with ngIf', fakeAsync(() => {
37853790
configureMatSelectTestingModule([SelectInNgContainer]);

src/material/select/select.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
cdkConnectedOverlayLockPosition
2020
cdkConnectedOverlayHasBackdrop
2121
cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
22+
[cdkConnectedOverlayPanelClass]="_overlayPanelClass"
2223
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
2324
[cdkConnectedOverlayOrigin]="origin"
2425
[cdkConnectedOverlayOpen]="panelOpen"

src/material/select/select.spec.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4610,21 +4610,26 @@ describe('MatSelect', () => {
46104610

46114611
});
46124612

4613-
it('should be able to provide default values through an injection token', () => {
4613+
it('should be able to provide default values through an injection token', fakeAsync(() => {
46144614
configureMatSelectTestingModule([NgModelSelect], [{
46154615
provide: MAT_SELECT_CONFIG,
46164616
useValue: {
46174617
disableOptionCentering: true,
4618-
typeaheadDebounceInterval: 1337
4618+
typeaheadDebounceInterval: 1337,
4619+
overlayPanelClass: 'test-panel-class',
46194620
} as MatSelectConfig
46204621
}]);
46214622
const fixture = TestBed.createComponent(NgModelSelect);
46224623
fixture.detectChanges();
46234624
const select = fixture.componentInstance.select;
4625+
select.open();
4626+
fixture.detectChanges();
4627+
flush();
46244628

46254629
expect(select.disableOptionCentering).toBe(true);
46264630
expect(select.typeaheadDebounceInterval).toBe(1337);
4627-
});
4631+
expect(document.querySelector('.cdk-overlay-pane')?.classList).toContain('test-panel-class');
4632+
}));
46284633

46294634
it('should not not throw if the select is inside an ng-container with ngIf', fakeAsync(() => {
46304635
configureMatSelectTestingModule([SelectInNgContainer]);

src/material/select/select.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ export interface MatSelectConfig {
179179

180180
/** Time to wait in milliseconds after the last keystroke before moving focus to an item. */
181181
typeaheadDebounceInterval?: number;
182+
183+
/** Class or list of classes to be applied to the menu's overlay panel. */
184+
overlayPanelClass?: string | string[];
182185
}
183186

184187
/** Injection token that can be used to provide the default options the select module. */
@@ -311,6 +314,8 @@ export abstract class _MatSelectBase<C> extends _MatSelectMixinBase implements A
311314
/** Strategy that will be used to handle scrolling while the select panel is open. */
312315
_scrollStrategy: ScrollStrategy;
313316

317+
_overlayPanelClass: string | string[] = this._defaultOptions?.overlayPanelClass || '';
318+
314319
/** Whether the select is focused. */
315320
get focused(): boolean {
316321
return this._focused || this._panelOpen;
@@ -373,7 +378,7 @@ export abstract class _MatSelectBase<C> extends _MatSelectMixinBase implements A
373378
set disableOptionCentering(value: boolean) {
374379
this._disableOptionCentering = coerceBooleanProperty(value);
375380
}
376-
private _disableOptionCentering: boolean = false;
381+
private _disableOptionCentering = this._defaultOptions?.disableOptionCentering ?? false;
377382

378383
/**
379384
* Function to compare the option values with the selected values. The first argument
@@ -422,7 +427,7 @@ export abstract class _MatSelectBase<C> extends _MatSelectMixinBase implements A
422427
set typeaheadDebounceInterval(value: number) {
423428
this._typeaheadDebounceInterval = coerceNumberProperty(value);
424429
}
425-
private _typeaheadDebounceInterval: number;
430+
private _typeaheadDebounceInterval = this._defaultOptions?.typeaheadDebounceInterval ?? 0;
426431

427432
/**
428433
* Function used to sort the values in a select in multiple mode.
@@ -489,7 +494,7 @@ export abstract class _MatSelectBase<C> extends _MatSelectMixinBase implements A
489494
@Attribute('tabindex') tabIndex: string,
490495
@Inject(MAT_SELECT_SCROLL_STRATEGY) scrollStrategyFactory: any,
491496
private _liveAnnouncer: LiveAnnouncer,
492-
@Optional() @Inject(MAT_SELECT_CONFIG) defaults?: MatSelectConfig) {
497+
@Optional() @Inject(MAT_SELECT_CONFIG) private _defaultOptions?: MatSelectConfig) {
493498
super(elementRef, _defaultErrorStateMatcher, _parentForm,
494499
_parentFormGroup, ngControl);
495500

@@ -505,16 +510,6 @@ export abstract class _MatSelectBase<C> extends _MatSelectMixinBase implements A
505510

506511
// Force setter to be called in case id was not specified.
507512
this.id = this.id;
508-
509-
if (defaults) {
510-
if (defaults.disableOptionCentering != null) {
511-
this.disableOptionCentering = defaults.disableOptionCentering;
512-
}
513-
514-
if (defaults.typeaheadDebounceInterval != null) {
515-
this.typeaheadDebounceInterval = defaults.typeaheadDebounceInterval;
516-
}
517-
}
518513
}
519514

520515
ngOnInit() {

tools/public_api_guard/material/select.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export declare abstract class _MatSelectBase<C> extends _MatSelectMixinBase impl
88
_onChange: (value: any) => void;
99
_onTouched: () => void;
1010
readonly _openedStream: Observable<void>;
11+
_overlayPanelClass: string | string[];
1112
_panelDoneAnimatingStream: Subject<string>;
1213
protected _parentFormField: MatFormField;
1314
abstract _positions: ConnectedPosition[];
@@ -56,7 +57,7 @@ export declare abstract class _MatSelectBase<C> extends _MatSelectMixinBase impl
5657
get value(): any;
5758
set value(newValue: any);
5859
readonly valueChange: EventEmitter<any>;
59-
constructor(_viewportRuler: ViewportRuler, _changeDetectorRef: ChangeDetectorRef, _ngZone: NgZone, _defaultErrorStateMatcher: ErrorStateMatcher, elementRef: ElementRef, _dir: Directionality, _parentForm: NgForm, _parentFormGroup: FormGroupDirective, _parentFormField: MatFormField, ngControl: NgControl, tabIndex: string, scrollStrategyFactory: any, _liveAnnouncer: LiveAnnouncer, defaults?: MatSelectConfig);
60+
constructor(_viewportRuler: ViewportRuler, _changeDetectorRef: ChangeDetectorRef, _ngZone: NgZone, _defaultErrorStateMatcher: ErrorStateMatcher, elementRef: ElementRef, _dir: Directionality, _parentForm: NgForm, _parentFormGroup: FormGroupDirective, _parentFormField: MatFormField, ngControl: NgControl, tabIndex: string, scrollStrategyFactory: any, _liveAnnouncer: LiveAnnouncer, _defaultOptions?: MatSelectConfig | undefined);
6061
protected _canOpen(): boolean;
6162
_getAriaActiveDescendant(): string | null;
6263
protected abstract _getChangeEvent(value: any): C;
@@ -145,6 +146,7 @@ export declare class MatSelectChange {
145146

146147
export interface MatSelectConfig {
147148
disableOptionCentering?: boolean;
149+
overlayPanelClass?: string | string[];
148150
typeaheadDebounceInterval?: number;
149151
}
150152

0 commit comments

Comments
 (0)