diff --git a/src/material-experimental/mdc-select/select.html b/src/material-experimental/mdc-select/select.html index d0492b26de7c..9a97b630dde6 100644 --- a/src/material-experimental/mdc-select/select.html +++ b/src/material-experimental/mdc-select/select.html @@ -19,6 +19,7 @@ cdkConnectedOverlayLockPosition cdkConnectedOverlayHasBackdrop cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop" + [cdkConnectedOverlayPanelClass]="_overlayPanelClass" [cdkConnectedOverlayScrollStrategy]="_scrollStrategy" [cdkConnectedOverlayOrigin]="_preferredOverlayOrigin || fallbackOverlayOrigin" [cdkConnectedOverlayOpen]="panelOpen" diff --git a/src/material-experimental/mdc-select/select.spec.ts b/src/material-experimental/mdc-select/select.spec.ts index d98eb49e532f..fd90951b73df 100644 --- a/src/material-experimental/mdc-select/select.spec.ts +++ b/src/material-experimental/mdc-select/select.spec.ts @@ -3732,21 +3732,26 @@ describe('MDC-based MatSelect', () => { }); - it('should be able to provide default values through an injection token', () => { + it('should be able to provide default values through an injection token', fakeAsync(() => { configureMatSelectTestingModule([NgModelSelect], [{ provide: MAT_SELECT_CONFIG, useValue: { disableOptionCentering: true, - typeaheadDebounceInterval: 1337 + typeaheadDebounceInterval: 1337, + overlayPanelClass: 'test-panel-class', } as MatSelectConfig }]); const fixture = TestBed.createComponent(NgModelSelect); fixture.detectChanges(); const select = fixture.componentInstance.select; + select.open(); + fixture.detectChanges(); + flush(); expect(select.disableOptionCentering).toBe(true); expect(select.typeaheadDebounceInterval).toBe(1337); - }); + expect(document.querySelector('.cdk-overlay-pane')?.classList).toContain('test-panel-class'); + })); it('should not not throw if the select is inside an ng-container with ngIf', fakeAsync(() => { configureMatSelectTestingModule([SelectInNgContainer]); diff --git a/src/material/select/select.html b/src/material/select/select.html index 785edff07848..f6c93d004dca 100644 --- a/src/material/select/select.html +++ b/src/material/select/select.html @@ -19,6 +19,7 @@ cdkConnectedOverlayLockPosition cdkConnectedOverlayHasBackdrop cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop" + [cdkConnectedOverlayPanelClass]="_overlayPanelClass" [cdkConnectedOverlayScrollStrategy]="_scrollStrategy" [cdkConnectedOverlayOrigin]="origin" [cdkConnectedOverlayOpen]="panelOpen" diff --git a/src/material/select/select.spec.ts b/src/material/select/select.spec.ts index 58549ae57ac8..dd985c16e1b2 100644 --- a/src/material/select/select.spec.ts +++ b/src/material/select/select.spec.ts @@ -4583,21 +4583,26 @@ describe('MatSelect', () => { }); - it('should be able to provide default values through an injection token', () => { + it('should be able to provide default values through an injection token', fakeAsync(() => { configureMatSelectTestingModule([NgModelSelect], [{ provide: MAT_SELECT_CONFIG, useValue: { disableOptionCentering: true, - typeaheadDebounceInterval: 1337 + typeaheadDebounceInterval: 1337, + overlayPanelClass: 'test-panel-class', } as MatSelectConfig }]); const fixture = TestBed.createComponent(NgModelSelect); fixture.detectChanges(); const select = fixture.componentInstance.select; + select.open(); + fixture.detectChanges(); + flush(); expect(select.disableOptionCentering).toBe(true); expect(select.typeaheadDebounceInterval).toBe(1337); - }); + expect(document.querySelector('.cdk-overlay-pane')?.classList).toContain('test-panel-class'); + })); it('should not not throw if the select is inside an ng-container with ngIf', fakeAsync(() => { configureMatSelectTestingModule([SelectInNgContainer]); diff --git a/src/material/select/select.ts b/src/material/select/select.ts index b87ec57168b7..a83d6313cf08 100644 --- a/src/material/select/select.ts +++ b/src/material/select/select.ts @@ -179,6 +179,9 @@ export interface MatSelectConfig { /** Time to wait in milliseconds after the last keystroke before moving focus to an item. */ typeaheadDebounceInterval?: number; + + /** Class or list of classes to be applied to the menu's overlay panel. */ + overlayPanelClass?: string | string[]; } /** Injection token that can be used to provide the default options the select module. */ @@ -311,6 +314,8 @@ export abstract class _MatSelectBase extends _MatSelectMixinBase implements A /** Strategy that will be used to handle scrolling while the select panel is open. */ _scrollStrategy: ScrollStrategy; + _overlayPanelClass: string | string[] = this._defaultOptions?.overlayPanelClass || ''; + /** Whether the select is focused. */ get focused(): boolean { return this._focused || this._panelOpen; @@ -373,7 +378,7 @@ export abstract class _MatSelectBase extends _MatSelectMixinBase implements A set disableOptionCentering(value: boolean) { this._disableOptionCentering = coerceBooleanProperty(value); } - private _disableOptionCentering: boolean = false; + private _disableOptionCentering = this._defaultOptions?.disableOptionCentering ?? false; /** * Function to compare the option values with the selected values. The first argument @@ -422,7 +427,7 @@ export abstract class _MatSelectBase extends _MatSelectMixinBase implements A set typeaheadDebounceInterval(value: number) { this._typeaheadDebounceInterval = coerceNumberProperty(value); } - private _typeaheadDebounceInterval: number; + private _typeaheadDebounceInterval = this._defaultOptions?.typeaheadDebounceInterval ?? 0; /** * Function used to sort the values in a select in multiple mode. @@ -489,7 +494,7 @@ export abstract class _MatSelectBase extends _MatSelectMixinBase implements A @Attribute('tabindex') tabIndex: string, @Inject(MAT_SELECT_SCROLL_STRATEGY) scrollStrategyFactory: any, private _liveAnnouncer: LiveAnnouncer, - @Optional() @Inject(MAT_SELECT_CONFIG) defaults?: MatSelectConfig) { + @Optional() @Inject(MAT_SELECT_CONFIG) private _defaultOptions?: MatSelectConfig) { super(elementRef, _defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl); @@ -505,16 +510,6 @@ export abstract class _MatSelectBase extends _MatSelectMixinBase implements A // Force setter to be called in case id was not specified. this.id = this.id; - - if (defaults) { - if (defaults.disableOptionCentering != null) { - this.disableOptionCentering = defaults.disableOptionCentering; - } - - if (defaults.typeaheadDebounceInterval != null) { - this.typeaheadDebounceInterval = defaults.typeaheadDebounceInterval; - } - } } ngOnInit() { diff --git a/tools/public_api_guard/material/select.d.ts b/tools/public_api_guard/material/select.d.ts index d5f54035b08e..1375d4105fe8 100644 --- a/tools/public_api_guard/material/select.d.ts +++ b/tools/public_api_guard/material/select.d.ts @@ -8,6 +8,7 @@ export declare abstract class _MatSelectBase extends _MatSelectMixinBase impl _onChange: (value: any) => void; _onTouched: () => void; readonly _openedStream: Observable; + _overlayPanelClass: string | string[]; _panelDoneAnimatingStream: Subject; protected _parentFormField: MatFormField; abstract _positions: ConnectedPosition[]; @@ -56,7 +57,7 @@ export declare abstract class _MatSelectBase extends _MatSelectMixinBase impl get value(): any; set value(newValue: any); readonly valueChange: EventEmitter; - 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); + 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); protected _canOpen(): boolean; _getAriaActiveDescendant(): string | null; protected abstract _getChangeEvent(value: any): C; @@ -145,6 +146,7 @@ export declare class MatSelectChange { export interface MatSelectConfig { disableOptionCentering?: boolean; + overlayPanelClass?: string | string[]; typeaheadDebounceInterval?: number; }