mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(overlay): replace OverlayContainer themeClass w/ addClass/removeClass methods (#6975)
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');
```
This commit is contained in:
+2
-5
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -109,10 +109,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user