From 3e6d57d80f556704f3e4a828061992c7012e925a Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 6 Feb 2017 22:15:14 +0100 Subject: [PATCH 1/2] feat(overlay): allow theming overlay-based components Allows for a `themeClass` to be passed to overlay-based components which don't usually inherit their parent theme, because they're outside the DOM order. Fixes #2662. --- guides/theming.md | 18 ++++++++++++ src/lib/core/overlay/overlay-container.ts | 23 +++++++++++++++ src/lib/core/overlay/overlay.spec.ts | 34 +++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/guides/theming.md b/guides/theming.md index 78a5e59861c6..dda1b2272954 100644 --- a/guides/theming.md +++ b/guides/theming.md @@ -44,6 +44,24 @@ Finally, if your app's content **is not** placed inside of a `md-sidenav-contain need to add the `mat-app-background` class to your wrapper element (for example the `body`). This ensures that the proper theme background is applied to your page. +#### Theming overlay-based components +Since certain components (e.g. `dialog`) are inside of a global overlay container, your theme may +not be applied to them. In order to define the theme, that will be used for overlay components, you +have to specify it on the global `OverlayContainer` instance: + +```ts +import {OverlayContainer} from '@angular/material'; + +@NgModule({ + // misc config goes here +}) +export class YourAppModule { + constructor(overlayContainer: OverlayContainer) { + overlayContainer.themeClass = 'your-theme'; + } +} +``` + ### Defining a custom theme When you want more customization than a pre-built theme offers, you can create your own theme file. diff --git a/src/lib/core/overlay/overlay-container.ts b/src/lib/core/overlay/overlay-container.ts index 4e54646c8f4b..7b46fd1be3f3 100644 --- a/src/lib/core/overlay/overlay-container.ts +++ b/src/lib/core/overlay/overlay-container.ts @@ -9,6 +9,24 @@ import {Injectable, Optional, SkipSelf} from '@angular/core'; export class OverlayContainer { 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) { + this._containerElement.classList.remove(this._themeClass); + + if (value) { + this._containerElement.classList.add(value); + } + } + + this._themeClass = value; + } + /** * This method returns the overlay container element. It will lazily * create the element the first time it is called to facilitate using @@ -27,6 +45,11 @@ export class OverlayContainer { protected _createContainer(): void { 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/lib/core/overlay/overlay.spec.ts b/src/lib/core/overlay/overlay.spec.ts index 6c750c26748a..328809e4d272 100644 --- a/src/lib/core/overlay/overlay.spec.ts +++ b/src/lib/core/overlay/overlay.spec.ts @@ -272,6 +272,34 @@ 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(); + })); + + 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'); + }); +}); /** Simple component for testing ComponentPortal. */ @Component({template: '

Pizza

'}) @@ -297,6 +325,12 @@ const TEST_COMPONENTS = [PizzaMsg, TestComponentWithTemplatePortals]; }) class OverlayTestModule { } +/** Component for testing the overlay container theming. */ +@NgModule({ + imports: [OverlayModule, PortalModule], +}) +class OverlayContainerThemingTestModule { } + class FakePositionStrategy implements PositionStrategy { apply(element: Element): Promise { element.classList.add('fake-positioned'); From ac4cb2b87a5b651c278352610d5e19e5367f0f32 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Tue, 21 Feb 2017 23:11:06 +0100 Subject: [PATCH 2/2] chore: comma --- guides/theming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/theming.md b/guides/theming.md index dda1b2272954..7e3c86e48543 100644 --- a/guides/theming.md +++ b/guides/theming.md @@ -46,7 +46,7 @@ ensures that the proper theme background is applied to your page. #### Theming overlay-based components Since certain components (e.g. `dialog`) are inside of a global overlay container, your theme may -not be applied to them. In order to define the theme, that will be used for overlay components, you +not be applied to them. In order to define the theme that will be used for overlay components, you have to specify it on the global `OverlayContainer` instance: ```ts