From fafe4c558da3110e97379784e73a9f7606491000 Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Sun, 10 Sep 2017 13:08:19 -0700 Subject: [PATCH] feat(overlay): replace OverlayContainer themeClass w/ addClass/removeClass methods BREAKING CHANGE: Now that the Overlay is part of the cdk rather than Angular Material directly, the `themeClass` property has been removed. To add a class to the overlay for theming, you can do ```ts overlayContainer.getContainerElement().classList.add('my-theme-class'); ``` --- guides/theming.md | 7 ++-- src/cdk/overlay/overlay-container.spec.ts | 17 +++++++++ src/cdk/overlay/overlay-container.ts | 26 +------------- src/cdk/overlay/overlay.spec.ts | 44 ----------------------- src/demo-app/demo-app/demo-app.ts | 4 +-- 5 files changed, 22 insertions(+), 76 deletions(-) diff --git a/guides/theming.md b/guides/theming.md index 8e4ccc89b90e..22a103bd0380 100644 --- a/guides/theming.md +++ b/guides/theming.md @@ -169,7 +169,7 @@ Since certain components (e.g. menu, select, dialog, etc.) are inside of a globa an additional step is required for those components to be affected by the theme's css class selector (`.unicorn-dark-theme` in the example above). -To do this, you can specify a `themeClass` on the global overlay container. For the example above, +To do this, you can add the appropriate class to the global overlay container. For the example above, this would look like: ```ts import {OverlayContainer} from '@angular/material'; @@ -179,14 +179,11 @@ import {OverlayContainer} from '@angular/material'; }) export class UnicornCandyAppModule { constructor(overlayContainer: OverlayContainer) { - overlayContainer.themeClass = 'unicorn-dark-theme'; + overlayContainer.getContainerElement().classList.add('unicorn-dark-theme'); } } ``` -The `themeClass` of the `OverlayContainer` can be changed at any time to change the active theme -class. - #### Theming only certain components The `angular-material-theme` mixin will output styles for [all components in the library](https://github.com/angular/material2/blob/master/src/lib/core/theming/_all-theme.scss). If you are only using a subset of the components (or if you want to change the theme for specific diff --git a/src/cdk/overlay/overlay-container.spec.ts b/src/cdk/overlay/overlay-container.spec.ts index 06f02e7d99dc..e2b8648c4376 100644 --- a/src/cdk/overlay/overlay-container.spec.ts +++ b/src/cdk/overlay/overlay-container.spec.ts @@ -26,6 +26,10 @@ describe('OverlayContainer', () => { overlayContainer = oc; })); + afterEach(() => { + overlayContainer.ngOnDestroy(); + }); + it('should remove the overlay container element from the DOM on destruction', () => { const fixture = TestBed.createComponent(TestComponentWithTemplatePortals); @@ -43,6 +47,19 @@ describe('OverlayContainer', () => { expect(document.querySelector('.cdk-overlay-container')) .toBeNull('Expected the overlay container *not* to be in the DOM after destruction'); }); + + it('should add and remove css classes from the container element', () => { + overlayContainer.getContainerElement().classList.add('commander-shepard'); + + const containerElement = document.querySelector('.cdk-overlay-container')!; + expect(containerElement.classList.contains('commander-shepard')) + .toBe(true, 'Expected the overlay container to have class "commander-shepard"'); + + overlayContainer.getContainerElement().classList.remove('commander-shepard'); + + expect(containerElement.classList.contains('commander-shepard')) + .toBe(false, 'Expected the overlay container not to have class "commander-shepard"'); + }); }); /** Test-bed component that contains a TempatePortal and an ElementRef. */ diff --git a/src/cdk/overlay/overlay-container.ts b/src/cdk/overlay/overlay-container.ts index 048e1d1adcde..4b3422d66986 100644 --- a/src/cdk/overlay/overlay-container.ts +++ b/src/cdk/overlay/overlay-container.ts @@ -17,26 +17,6 @@ import {Injectable, Optional, SkipSelf, OnDestroy} from '@angular/core'; export class OverlayContainer implements OnDestroy { protected _containerElement: HTMLElement; - private _themeClass: string; - - /** - * Base theme to be applied to all overlay-based components. - */ - get themeClass(): string { return this._themeClass; } - set themeClass(value: string) { - if (this._containerElement) { - if (this._themeClass) { - this._containerElement.classList.remove(this._themeClass); - } - - if (value) { - this._containerElement.classList.add(value); - } - } - - this._themeClass = value; - } - ngOnDestroy() { if (this._containerElement && this._containerElement.parentNode) { this._containerElement.parentNode.removeChild(this._containerElement); @@ -44,7 +24,7 @@ export class OverlayContainer implements OnDestroy { } /** - * This method returns the overlay container element. It will lazily + * This method returns the overlay container element. It will lazily * create the element the first time it is called to facilitate using * the container in non-browser environments. * @returns the container element @@ -62,10 +42,6 @@ export class OverlayContainer implements OnDestroy { let container = document.createElement('div'); container.classList.add('cdk-overlay-container'); - if (this._themeClass) { - container.classList.add(this._themeClass); - } - document.body.appendChild(container); this._containerElement = container; } diff --git a/src/cdk/overlay/overlay.spec.ts b/src/cdk/overlay/overlay.spec.ts index 8b1e3c4e2120..e1f1cf22123c 100644 --- a/src/cdk/overlay/overlay.spec.ts +++ b/src/cdk/overlay/overlay.spec.ts @@ -469,44 +469,6 @@ describe('Overlay', () => { }); }); -describe('OverlayContainer theming', () => { - let overlayContainer: OverlayContainer; - let overlayContainerElement: HTMLElement; - - beforeEach(async(() => { - TestBed.configureTestingModule({ imports: [OverlayContainerThemingTestModule] }); - TestBed.compileComponents(); - })); - - beforeEach(inject([OverlayContainer], (o: OverlayContainer) => { - overlayContainer = o; - overlayContainerElement = overlayContainer.getContainerElement(); - })); - - afterEach(() => { - overlayContainerElement.parentNode!.removeChild(overlayContainerElement); - }); - - it('should be able to set a theme on the overlay container', () => { - overlayContainer.themeClass = 'my-theme'; - expect(overlayContainerElement.classList).toContain('my-theme'); - }); - - it('should clear any previously-set themes when a new theme is set', () => { - overlayContainer.themeClass = 'initial-theme'; - expect(overlayContainerElement.classList).toContain('initial-theme'); - - overlayContainer.themeClass = 'new-theme'; - expect(overlayContainerElement.classList).not.toContain('initial-theme'); - expect(overlayContainerElement.classList).toContain('new-theme'); - }); - - it('should not throw when switching from a blank theme', () => { - overlayContainer.themeClass = ''; - expect(() => overlayContainer.themeClass = 'new-theme').not.toThrow(); - }); -}); - /** Simple component for testing ComponentPortal. */ @Component({ selector: 'pizza', @@ -534,12 +496,6 @@ const TEST_COMPONENTS = [PizzaMsg, TestComponentWithTemplatePortals]; }) class OverlayTestModule { } -/** Component for testing the overlay container theming. */ -@NgModule({ - imports: [OverlayModule, PortalModule], -}) -class OverlayContainerThemingTestModule { } - class FakePositionStrategy implements PositionStrategy { element: HTMLElement; diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts index 6f8341a5d88e..87c80f5a8bca 100644 --- a/src/demo-app/demo-app/demo-app.ts +++ b/src/demo-app/demo-app/demo-app.ts @@ -107,10 +107,10 @@ export class DemoApp { if (this.dark) { this._renderer.addClass(this._element.nativeElement, darkThemeClass); - this._overlayContainer.themeClass = darkThemeClass; + this._overlayContainer.getContainerElement().classList.add(darkThemeClass); } else { this._renderer.removeClass(this._element.nativeElement, darkThemeClass); - this._overlayContainer.themeClass = ''; + this._overlayContainer.getContainerElement().classList.remove(darkThemeClass); } } }