Skip to content

Commit 25966fe

Browse files
committed
fix(cdk/overlay): avoid having to manually load structural styles
Changes the overlay so it loads its structural styles automatically, instead of requiring the user to do it. BREAKING CHANGE: * The overlay stays are now loaded slightly later than before which can change their specificity. You may have to update any overlay style overrides.
1 parent 50e8f94 commit 25966fe

File tree

8 files changed

+66
-17
lines changed

8 files changed

+66
-17
lines changed

src/cdk/overlay/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ ng_module(
1818
["**/*.ts"],
1919
exclude = ["**/*.spec.ts"],
2020
),
21+
assets = [
22+
":overlay-prebuilt.css",
23+
],
2124
deps = [
2225
"//src:dev_mode_types",
2326
"//src/cdk/bidi",
2427
"//src/cdk/coercion",
2528
"//src/cdk/keycodes",
2629
"//src/cdk/platform",
2730
"//src/cdk/portal",
31+
"//src/cdk/private",
2832
"//src/cdk/scrolling",
2933
"@npm//@angular/common",
3034
"@npm//@angular/core",

src/cdk/overlay/_index.scss

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,23 +76,24 @@ $backdrop-animation-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default;
7676
-webkit-tap-highlight-color: transparent;
7777
transition: opacity $backdrop-animation-duration $backdrop-animation-timing-function;
7878
opacity: 0;
79+
}
80+
81+
.cdk-overlay-backdrop-showing {
82+
opacity: 1;
7983

80-
&.cdk-overlay-backdrop-showing {
81-
opacity: 1;
82-
83-
// Note that we can't import and use the `high-contrast` mixin from `_a11y.scss`, because
84-
// this file will be copied to the top-level `cdk` package when putting together the files
85-
// for npm. Any relative import paths we use here will become invalid once the file is copied.
86-
.cdk-high-contrast-active & {
87-
// In high contrast mode the rgba background will become solid
88-
// so we need to fall back to making it opaque using `opacity`.
89-
opacity: 0.6;
90-
}
84+
// Note that we can't import and use the `high-contrast` mixin from `_a11y.scss`, because
85+
// this file will be copied to the top-level `cdk` package when putting together the files
86+
// for npm. Any relative import paths we use here will become invalid once the file is copied.
87+
.cdk-high-contrast-active & {
88+
// In high contrast mode the rgba background will become solid
89+
// so we need to fall back to making it opaque using `opacity`.
90+
opacity: 0.6;
9191
}
9292
}
9393

9494
.cdk-overlay-dark-backdrop {
95-
background: $overlay-backdrop-color;
95+
// Add a CSS variable to make this easier to override.
96+
background: var(--cdk-overlay-backdrop-dark-color, $overlay-backdrop-color);
9697
}
9798

9899
.cdk-overlay-transparent-backdrop {
@@ -105,7 +106,8 @@ $backdrop-animation-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default;
105106
// capturing the user's mouse scroll events. Since we also can't use something like
106107
// `rgba(0, 0, 0, 0)`, we work around the inconsistency by not setting the background at
107108
// all and using `opacity` to make the element transparent.
108-
&.cdk-overlay-backdrop-showing {
109+
&.cdk-overlay-backdrop-showing,
110+
.cdk-high-contrast-active & {
109111
opacity: 0;
110112
visibility: visible;
111113
}

src/cdk/overlay/fullscreen-overlay-container.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ describe('FullscreenOverlayContainer', () => {
2626
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
2727
fakeDocument = {
2828
body: document.body,
29+
head: document.head,
2930
fullscreenElement: document.createElement('div'),
3031
fullscreenEnabled: true,
3132
addEventListener: (eventName: string, listener: EventListener) => {

src/cdk/overlay/overlay-container.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,34 @@
77
*/
88

99
import {DOCUMENT} from '@angular/common';
10-
import {Inject, Injectable, OnDestroy} from '@angular/core';
10+
import {
11+
Inject,
12+
Injectable,
13+
OnDestroy,
14+
Component,
15+
ChangeDetectionStrategy,
16+
ViewEncapsulation,
17+
inject,
18+
} from '@angular/core';
19+
import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
1120
import {Platform, _isTestEnvironment} from '@angular/cdk/platform';
1221

22+
@Component({
23+
template: '',
24+
changeDetection: ChangeDetectionStrategy.OnPush,
25+
encapsulation: ViewEncapsulation.None,
26+
standalone: true,
27+
styleUrl: 'overlay-prebuilt.css',
28+
host: {'cdk-overlay-style-loader': ''},
29+
})
30+
export class _CdkOverlayStyleLoader {}
31+
1332
/** Container inside which all overlays will render. */
1433
@Injectable({providedIn: 'root'})
1534
export class OverlayContainer implements OnDestroy {
1635
protected _containerElement: HTMLElement;
1736
protected _document: Document;
37+
protected _styleLoader = inject(_CdkPrivateStyleLoader);
1838

1939
constructor(
2040
@Inject(DOCUMENT) document: any,
@@ -34,6 +54,8 @@ export class OverlayContainer implements OnDestroy {
3454
* @returns the container element
3555
*/
3656
getContainerElement(): HTMLElement {
57+
this._loadStyles();
58+
3759
if (!this._containerElement) {
3860
this._createContainer();
3961
}
@@ -84,4 +106,9 @@ export class OverlayContainer implements OnDestroy {
84106
this._document.body.appendChild(container);
85107
this._containerElement = container;
86108
}
109+
110+
/** Loads the structural styles necessary for the overlay to work. */
111+
protected _loadStyles(): void {
112+
this._styleLoader.load(_CdkOverlayStyleLoader);
113+
}
87114
}

src/cdk/overlay/overlay.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ import {
1919
ANIMATION_MODULE_TYPE,
2020
Optional,
2121
EnvironmentInjector,
22+
inject,
2223
} from '@angular/core';
24+
import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
2325
import {OverlayKeyboardDispatcher} from './dispatchers/overlay-keyboard-dispatcher';
2426
import {OverlayOutsideClickDispatcher} from './dispatchers/overlay-outside-click-dispatcher';
2527
import {OverlayConfig} from './overlay-config';
26-
import {OverlayContainer} from './overlay-container';
28+
import {_CdkOverlayStyleLoader, OverlayContainer} from './overlay-container';
2729
import {OverlayRef} from './overlay-ref';
2830
import {OverlayPositionBuilder} from './position/overlay-position-builder';
2931
import {ScrollStrategyOptions} from './scroll/index';
@@ -45,6 +47,7 @@ let nextUniqueId = 0;
4547
@Injectable({providedIn: 'root'})
4648
export class Overlay {
4749
private _appRef: ApplicationRef;
50+
private _styleLoader = inject(_CdkPrivateStyleLoader);
4851

4952
constructor(
5053
/** Scrolling strategies that can be used when creating an overlay. */
@@ -68,6 +71,10 @@ export class Overlay {
6871
* @returns Reference to the created overlay.
6972
*/
7073
create(config?: OverlayConfig): OverlayRef {
74+
// This is done in the overlay container as well, but we have it here
75+
// since it's common to mock out the overlay container in tests.
76+
this._styleLoader.load(_CdkOverlayStyleLoader);
77+
7178
const host = this._createHostElement();
7279
const pane = this._createPaneElement(host);
7380
const portalOutlet = this._createPortalOutlet(pane);

src/e2e-app/components/block-scroll-strategy/block-scroll-strategy-e2e.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Component, inject} from '@angular/core';
2-
import {Overlay} from '@angular/cdk/overlay';
2+
import {Overlay, OverlayContainer} from '@angular/cdk/overlay';
33
import {ScrollingModule} from '@angular/cdk/scrolling';
44

55
@Component({
@@ -11,4 +11,9 @@ import {ScrollingModule} from '@angular/cdk/scrolling';
1111
})
1212
export class BlockScrollStrategyE2E {
1313
scrollStrategy = inject(Overlay).scrollStrategies.block();
14+
15+
constructor() {
16+
// This loads the structural styles for the test.
17+
inject(OverlayContainer).getContainerElement();
18+
}
1419
}

src/material/core/_core.scss

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
}
1616

1717
@include cdk.a11y-visually-hidden();
18-
@include cdk.overlay();
1918
@include cdk.text-field-autosize();
2019
@include cdk.text-field-autofill();
2120
@include private.structural-styling('mat');

tools/public_api_guard/cdk/overlay.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
```ts
66

7+
import { _CdkPrivateStyleLoader } from '@angular/cdk/private';
78
import { CdkScrollable } from '@angular/cdk/scrolling';
89
import { ComponentFactoryResolver } from '@angular/core';
910
import { ComponentPortal } from '@angular/cdk/portal';
@@ -303,11 +304,14 @@ export class OverlayContainer implements OnDestroy {
303304
// (undocumented)
304305
protected _document: Document;
305306
getContainerElement(): HTMLElement;
307+
protected _loadStyles(): void;
306308
// (undocumented)
307309
ngOnDestroy(): void;
308310
// (undocumented)
309311
protected _platform: Platform;
310312
// (undocumented)
313+
protected _styleLoader: _CdkPrivateStyleLoader;
314+
// (undocumented)
311315
static ɵfac: i0.ɵɵFactoryDeclaration<OverlayContainer, never>;
312316
// (undocumented)
313317
static ɵprov: i0.ɵɵInjectableDeclaration<OverlayContainer>;

0 commit comments

Comments
 (0)