Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions guides/theming.md
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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
Expand Down
17 changes: 17 additions & 0 deletions src/cdk/overlay/overlay-container.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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. */
Expand Down
26 changes: 1 addition & 25 deletions src/cdk/overlay/overlay-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,14 @@ 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);
}
}

/**
* 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
Expand All @@ -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;
}
Expand Down
44 changes: 0 additions & 44 deletions src/cdk/overlay/overlay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions src/demo-app/demo-app/demo-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}