From 44657e2624cd66f6f9c20413572c0e68f6994cb1 Mon Sep 17 00:00:00 2001 From: Zach Arend Date: Thu, 17 Nov 2022 17:19:32 -0800 Subject: [PATCH] fix(material/autocomplete): apply theme of parent form field to panel (#25983) Apply the theme of the autocomplete's parent form field to its panel. Fix issue where theme color only applies to the input, and does not affect the panel. --- .../autocomplete/autocomplete-demo.html | 26 +++++++++++++------ src/dev-app/autocomplete/autocomplete-demo.ts | 10 +++++++ .../autocomplete/autocomplete-trigger.ts | 1 + .../autocomplete/autocomplete.spec.ts | 26 +++++++++++++++++-- src/material/autocomplete/autocomplete.ts | 17 ++++++++++++ .../public_api_guard/material/autocomplete.md | 2 ++ 6 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/dev-app/autocomplete/autocomplete-demo.html b/src/dev-app/autocomplete/autocomplete-demo.html index 35c345def16b..13ef205b7868 100644 --- a/src/dev-app/autocomplete/autocomplete-demo.html +++ b/src/dev-app/autocomplete/autocomplete-demo.html @@ -6,16 +6,16 @@
Reactive value: {{ stateCtrl.value | json }}
Reactive dirty: {{ stateCtrl.dirty }}
- + State - - - {{ state.name }} - ({{ state.code }}) - - + + + {{ state.name }} + ({{ state.code }}) + + @@ -23,6 +23,11 @@ + @@ -33,7 +38,7 @@
Template-driven dirty: {{ modelDir ? modelDir.dirty : false }}
- + State @@ -50,6 +55,11 @@ + diff --git a/src/dev-app/autocomplete/autocomplete-demo.ts b/src/dev-app/autocomplete/autocomplete-demo.ts index addac2539932..a64d9b87a03d 100644 --- a/src/dev-app/autocomplete/autocomplete-demo.ts +++ b/src/dev-app/autocomplete/autocomplete-demo.ts @@ -15,6 +15,7 @@ import {MatCardModule} from '@angular/material/card'; import {MatInputModule} from '@angular/material/input'; import {Observable} from 'rxjs'; import {map, startWith} from 'rxjs/operators'; +import {ThemePalette} from '@angular/material/core'; export interface State { code: string; @@ -52,6 +53,15 @@ export class AutocompleteDemo { tdDisabled = false; + reactiveStatesTheme: ThemePalette = 'primary'; + templateStatesTheme: ThemePalette = 'primary'; + + availableThemes = [ + {value: 'primary', name: 'Primary'}, + {value: 'accent', name: 'Accent'}, + {value: 'warn', name: 'Warn'}, + ]; + @ViewChild(NgModel) modelDir: NgModel; groupedStates: StateGroup[]; diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index e87871d23ab4..fb3e45afef4b 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -666,6 +666,7 @@ export abstract class _MatAutocompleteTriggerBase this.autocomplete._setVisibility(); this.autocomplete._isOpen = this._overlayAttached = true; + this.autocomplete._setColor(this._formField?.color); // We need to do an extra `panelOpen` check in here, because the // autocomplete won't be shown if there are no options. diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index 2e855bef18f5..caba31899329 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -945,6 +945,28 @@ describe('MDC-based MatAutocomplete', () => { }); }); + describe('with theming', () => { + let fixture: ComponentFixture; + + beforeEach(() => { + fixture = createComponent(SimpleAutocomplete); + fixture.detectChanges(); + }); + + it('should transfer the theme to the autocomplete panel', () => { + fixture.componentInstance.theme = 'warn'; + fixture.detectChanges(); + + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + + const panel = overlayContainerElement.querySelector( + '.mat-mdc-autocomplete-panel', + )! as HTMLElement; + expect(panel.classList).toContain('mat-warn'); + }); + }); + describe('keyboard events', () => { let fixture: ComponentFixture; let input: HTMLInputElement; @@ -3393,7 +3415,7 @@ describe('MDC-based MatAutocomplete', () => { }); const SIMPLE_AUTOCOMPLETE_TEMPLATE = ` - + State - @@ -3431,6 +3452,7 @@ class SimpleAutocomplete implements OnDestroy { ariaLabel: string; ariaLabelledby: string; panelClass = 'class-one class-two'; + theme: string; openedSpy = jasmine.createSpy('autocomplete opened spy'); closedSpy = jasmine.createSpy('autocomplete closed spy'); diff --git a/src/material/autocomplete/autocomplete.ts b/src/material/autocomplete/autocomplete.ts index 1098da961b9e..01fe3576ab02 100644 --- a/src/material/autocomplete/autocomplete.ts +++ b/src/material/autocomplete/autocomplete.ts @@ -34,6 +34,7 @@ import { CanDisableRipple, _MatOptionBase, _MatOptgroupBase, + ThemePalette, } from '@angular/material/core'; import {ActiveDescendantKeyManager} from '@angular/cdk/a11y'; import {BooleanInput, coerceBooleanProperty, coerceStringArray} from '@angular/cdk/coercion'; @@ -122,6 +123,14 @@ export abstract class _MatAutocompleteBase } _isOpen: boolean = false; + /** @docs-private Sets the theme color of the panel. */ + _setColor(value: ThemePalette) { + this._color = value; + this._setThemeClasses(this._classList); + } + /** @docs-private theme color of the panel */ + private _color: ThemePalette; + // The @ViewChild query for TemplateRef here needs to be static because some code paths // lead to the overlay being created before change detection has finished for this component. // Notably, another component may trigger `focus` on the autocomplete-trigger. @@ -206,6 +215,7 @@ export abstract class _MatAutocompleteBase } this._setVisibilityClasses(this._classList); + this._setThemeClasses(this._classList); this._elementRef.nativeElement.className = ''; } _classList: {[key: string]: boolean} = {}; @@ -296,6 +306,13 @@ export abstract class _MatAutocompleteBase classList[this._visibleClass] = this.showPanel; classList[this._hiddenClass] = !this.showPanel; } + + /** Sets the theming classes on a classlist based on the theme of the panel. */ + private _setThemeClasses(classList: {[key: string]: boolean}) { + classList['mat-primary'] = this._color === 'primary'; + classList['mat-warn'] = this._color === 'warn'; + classList['mat-accent'] = this._color === 'accent'; + } } @Component({ diff --git a/tools/public_api_guard/material/autocomplete.md b/tools/public_api_guard/material/autocomplete.md index 9f295af2b441..2c6f092ee75e 100644 --- a/tools/public_api_guard/material/autocomplete.md +++ b/tools/public_api_guard/material/autocomplete.md @@ -38,6 +38,7 @@ import { QueryList } from '@angular/core'; import { ScrollStrategy } from '@angular/cdk/overlay'; import { SimpleChanges } from '@angular/core'; import { TemplateRef } from '@angular/core'; +import { ThemePalette } from '@angular/material/core'; import { ViewContainerRef } from '@angular/core'; import { ViewportRuler } from '@angular/cdk/scrolling'; @@ -123,6 +124,7 @@ export abstract class _MatAutocompleteBase extends _MatAutocompleteMixinBase imp readonly optionSelected: EventEmitter; panel: ElementRef; panelWidth: string | number; + _setColor(value: ThemePalette): void; _setScrollTop(scrollTop: number): void; _setVisibility(): void; showPanel: boolean;