diff --git a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts index fa9ba7f40169..2872bfaa00f1 100644 --- a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts +++ b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts @@ -2124,6 +2124,39 @@ describe('MDC-based MatAutocomplete', () => { })); }); + describe('with panel classes in the default options', () => { + it('should apply them if provided as string', fakeAsync(() => { + const fixture = createComponent(SimpleAutocomplete, [ + {provide: MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, + useValue: {overlayPanelClass: 'default1'}} + ]); + + fixture.detectChanges(); + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + + const panelClassList = + overlayContainerElement.querySelector('.cdk-overlay-pane')!.classList; + expect(panelClassList).toContain('default1'); + })); + + it('should apply them if provided as array', fakeAsync(() => { + const fixture = createComponent(SimpleAutocomplete, [ + {provide: MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, + useValue: {overlayPanelClass: ['default1', 'default2']}} + ]); + + fixture.detectChanges(); + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + + const panelClassList = + overlayContainerElement.querySelector('.cdk-overlay-pane')!.classList; + expect(panelClassList).toContain('default1'); + expect(panelClassList).toContain('default2'); + })); + }); + describe('misc', () => { it('should allow basic use without any forms directives', () => { diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index a77584b1a327..1f3eac997526 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -49,7 +49,11 @@ import {MAT_FORM_FIELD, MatFormField} from '@angular/material/form-field'; import {defer, fromEvent, merge, Observable, of as observableOf, Subject, Subscription} from 'rxjs'; import {delay, filter, map, switchMap, take, tap} from 'rxjs/operators'; -import {_MatAutocompleteBase} from './autocomplete'; +import { + _MatAutocompleteBase, + MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, + MatAutocompleteDefaultOptions +} from './autocomplete'; import {_MatAutocompleteOriginBase} from './autocomplete-origin'; @@ -208,7 +212,9 @@ export abstract class _MatAutocompleteTriggerBase implements ControlValueAccesso @Optional() private _dir: Directionality, @Optional() @Inject(MAT_FORM_FIELD) @Host() private _formField: MatFormField, @Optional() @Inject(DOCUMENT) private _document: any, - private _viewportRuler: ViewportRuler) { + private _viewportRuler: ViewportRuler, + @Optional() @Inject(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS) + private _defaults?: MatAutocompleteDefaultOptions) { this._scrollStrategy = scrollStrategy; } @@ -638,7 +644,8 @@ export abstract class _MatAutocompleteTriggerBase implements ControlValueAccesso positionStrategy: this._getOverlayPosition(), scrollStrategy: this._scrollStrategy(), width: this._getPanelWidth(), - direction: this._dir + direction: this._dir, + panelClass: this._defaults?.overlayPanelClass, }); } diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index dab9d60bae45..ce049e941de5 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -2119,6 +2119,39 @@ describe('MatAutocomplete', () => { })); }); + describe('with panel classes in the default options', () => { + it('should apply them if provided as string', fakeAsync(() => { + const fixture = createComponent(SimpleAutocomplete, [ + {provide: MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, + useValue: {overlayPanelClass: 'default1'}} + ]); + + fixture.detectChanges(); + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + + const panelClassList = + overlayContainerElement.querySelector('.cdk-overlay-pane')!.classList; + expect(panelClassList).toContain('default1'); + })); + + it('should apply them if provided as array', fakeAsync(() => { + const fixture = createComponent(SimpleAutocomplete, [ + {provide: MAT_AUTOCOMPLETE_DEFAULT_OPTIONS, + useValue: {overlayPanelClass: ['default1', 'default2']}} + ]); + + fixture.detectChanges(); + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + + const panelClassList = + overlayContainerElement.querySelector('.cdk-overlay-pane')!.classList; + expect(panelClassList).toContain('default1'); + expect(panelClassList).toContain('default2'); + })); + }); + describe('misc', () => { it('should allow basic use without any forms directives', () => { diff --git a/src/material/autocomplete/autocomplete.ts b/src/material/autocomplete/autocomplete.ts index ce9dc5fe58bf..014634d60177 100644 --- a/src/material/autocomplete/autocomplete.ts +++ b/src/material/autocomplete/autocomplete.ts @@ -75,6 +75,9 @@ const _MatAutocompleteMixinBase: CanDisableRippleCtor & typeof MatAutocompleteBa export interface MatAutocompleteDefaultOptions { /** Whether the first option should be highlighted when an autocomplete panel is opened. */ autoActiveFirstOption?: boolean; + + /** Class or list of classes to be applied to the autocomplete's overlay panel. */ + overlayPanelClass?: string | string[]; } /** Injection token to be used to override the default options for `mat-autocomplete`. */ diff --git a/tools/public_api_guard/material/autocomplete.d.ts b/tools/public_api_guard/material/autocomplete.d.ts index 9ca5788e36ac..8fc572211c7f 100644 --- a/tools/public_api_guard/material/autocomplete.d.ts +++ b/tools/public_api_guard/material/autocomplete.d.ts @@ -57,7 +57,7 @@ export declare abstract class _MatAutocompleteTriggerBase implements ControlValu get panelClosingActions(): Observable; get panelOpen(): boolean; position: 'auto' | 'above' | 'below'; - constructor(_element: ElementRef, _overlay: Overlay, _viewContainerRef: ViewContainerRef, _zone: NgZone, _changeDetectorRef: ChangeDetectorRef, scrollStrategy: any, _dir: Directionality, _formField: MatFormField, _document: any, _viewportRuler: ViewportRuler); + constructor(_element: ElementRef, _overlay: Overlay, _viewContainerRef: ViewContainerRef, _zone: NgZone, _changeDetectorRef: ChangeDetectorRef, scrollStrategy: any, _dir: Directionality, _formField: MatFormField, _document: any, _viewportRuler: ViewportRuler, _defaults?: MatAutocompleteDefaultOptions | undefined); _handleFocus(): void; _handleInput(event: KeyboardEvent): void; _handleKeydown(event: KeyboardEvent): void; @@ -73,7 +73,7 @@ export declare abstract class _MatAutocompleteTriggerBase implements ControlValu writeValue(value: any): void; static ngAcceptInputType_autocompleteDisabled: BooleanInput; static ɵdir: i0.ɵɵDirectiveDefWithMeta<_MatAutocompleteTriggerBase, never, never, { "autocomplete": "matAutocomplete"; "position": "matAutocompletePosition"; "connectedTo": "matAutocompleteConnectedTo"; "autocompleteAttribute": "autocomplete"; "autocompleteDisabled": "matAutocompleteDisabled"; }, {}, never>; - static ɵfac: i0.ɵɵFactoryDef<_MatAutocompleteTriggerBase, [null, null, null, null, null, null, { optional: true; }, { optional: true; host: true; }, { optional: true; }, null]>; + static ɵfac: i0.ɵɵFactoryDef<_MatAutocompleteTriggerBase, [null, null, null, null, null, null, { optional: true; }, { optional: true; host: true; }, { optional: true; }, null, { optional: true; }]>; } export declare const AUTOCOMPLETE_OPTION_HEIGHT = 48; @@ -114,6 +114,7 @@ export interface MatAutocompleteActivatedEvent { export interface MatAutocompleteDefaultOptions { autoActiveFirstOption?: boolean; + overlayPanelClass?: string | string[]; } export declare class MatAutocompleteModule {