feat(overlay): allow theming overlay-based components (#2967)

Fixes #2662.
This commit is contained in:
Kristiyan Kostadinov
2017-02-27 02:44:33 +01:00
committed by Kara
parent 8482bbf636
commit cbd42f0ef4
3 changed files with 75 additions and 0 deletions
+18
View File
@@ -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.
+23
View File
@@ -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;
}
+34
View File
@@ -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: '<p>Pizza</p>'})
@@ -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<void> {
element.classList.add('fake-positioned');