Skip to content

Simplify structural style setup #29620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 25, 2024
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
4 changes: 4 additions & 0 deletions src/cdk/overlay/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ ng_module(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
assets = [
":overlay-prebuilt.css",
],
deps = [
"//src:dev_mode_types",
"//src/cdk/bidi",
"//src/cdk/coercion",
"//src/cdk/keycodes",
"//src/cdk/platform",
"//src/cdk/portal",
"//src/cdk/private",
"//src/cdk/scrolling",
"@npm//@angular/common",
"@npm//@angular/core",
Expand Down
28 changes: 15 additions & 13 deletions src/cdk/overlay/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,24 @@ $backdrop-animation-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default;
-webkit-tap-highlight-color: transparent;
transition: opacity $backdrop-animation-duration $backdrop-animation-timing-function;
opacity: 0;
}

.cdk-overlay-backdrop-showing {
opacity: 1;

&.cdk-overlay-backdrop-showing {
opacity: 1;

// Note that we can't import and use the `high-contrast` mixin from `_a11y.scss`, because
// this file will be copied to the top-level `cdk` package when putting together the files
// for npm. Any relative import paths we use here will become invalid once the file is copied.
.cdk-high-contrast-active & {
// In high contrast mode the rgba background will become solid
// so we need to fall back to making it opaque using `opacity`.
opacity: 0.6;
}
// Note that we can't import and use the `high-contrast` mixin from `_a11y.scss`, because
// this file will be copied to the top-level `cdk` package when putting together the files
// for npm. Any relative import paths we use here will become invalid once the file is copied.
.cdk-high-contrast-active & {
// In high contrast mode the rgba background will become solid
// so we need to fall back to making it opaque using `opacity`.
opacity: 0.6;
}
}

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

.cdk-overlay-transparent-backdrop {
Expand All @@ -105,7 +106,8 @@ $backdrop-animation-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default;
// capturing the user's mouse scroll events. Since we also can't use something like
// `rgba(0, 0, 0, 0)`, we work around the inconsistency by not setting the background at
// all and using `opacity` to make the element transparent.
&.cdk-overlay-backdrop-showing {
&.cdk-overlay-backdrop-showing,
.cdk-high-contrast-active & {
opacity: 0;
visibility: visible;
}
Expand Down
1 change: 1 addition & 0 deletions src/cdk/overlay/fullscreen-overlay-container.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('FullscreenOverlayContainer', () => {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
fakeDocument = {
body: document.body,
head: document.head,
fullscreenElement: document.createElement('div'),
fullscreenEnabled: true,
addEventListener: (eventName: string, listener: EventListener) => {
Expand Down
29 changes: 28 additions & 1 deletion src/cdk/overlay/overlay-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,34 @@
*/

import {DOCUMENT} from '@angular/common';
import {Inject, Injectable, OnDestroy} from '@angular/core';
import {
Inject,
Injectable,
OnDestroy,
Component,
ChangeDetectionStrategy,
ViewEncapsulation,
inject,
} from '@angular/core';
import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
import {Platform, _isTestEnvironment} from '@angular/cdk/platform';

@Component({
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
standalone: true,
styleUrl: 'overlay-prebuilt.css',
host: {'cdk-overlay-style-loader': ''},
})
export class _CdkOverlayStyleLoader {}

/** Container inside which all overlays will render. */
@Injectable({providedIn: 'root'})
export class OverlayContainer implements OnDestroy {
protected _containerElement: HTMLElement;
protected _document: Document;
protected _styleLoader = inject(_CdkPrivateStyleLoader);

constructor(
@Inject(DOCUMENT) document: any,
Expand All @@ -34,6 +54,8 @@ export class OverlayContainer implements OnDestroy {
* @returns the container element
*/
getContainerElement(): HTMLElement {
this._loadStyles();

if (!this._containerElement) {
this._createContainer();
}
Expand Down Expand Up @@ -84,4 +106,9 @@ export class OverlayContainer implements OnDestroy {
this._document.body.appendChild(container);
this._containerElement = container;
}

/** Loads the structural styles necessary for the overlay to work. */
protected _loadStyles(): void {
this._styleLoader.load(_CdkOverlayStyleLoader);
}
}
9 changes: 8 additions & 1 deletion src/cdk/overlay/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ import {
ANIMATION_MODULE_TYPE,
Optional,
EnvironmentInjector,
inject,
} from '@angular/core';
import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
import {OverlayKeyboardDispatcher} from './dispatchers/overlay-keyboard-dispatcher';
import {OverlayOutsideClickDispatcher} from './dispatchers/overlay-outside-click-dispatcher';
import {OverlayConfig} from './overlay-config';
import {OverlayContainer} from './overlay-container';
import {_CdkOverlayStyleLoader, OverlayContainer} from './overlay-container';
import {OverlayRef} from './overlay-ref';
import {OverlayPositionBuilder} from './position/overlay-position-builder';
import {ScrollStrategyOptions} from './scroll/index';
Expand All @@ -45,6 +47,7 @@ let nextUniqueId = 0;
@Injectable({providedIn: 'root'})
export class Overlay {
private _appRef: ApplicationRef;
private _styleLoader = inject(_CdkPrivateStyleLoader);

constructor(
/** Scrolling strategies that can be used when creating an overlay. */
Expand All @@ -68,6 +71,10 @@ export class Overlay {
* @returns Reference to the created overlay.
*/
create(config?: OverlayConfig): OverlayRef {
// This is done in the overlay container as well, but we have it here
// since it's common to mock out the overlay container in tests.
this._styleLoader.load(_CdkOverlayStyleLoader);

const host = this._createHostElement();
const pane = this._createPaneElement(host);
const portalOutlet = this._createPortalOutlet(pane);
Expand Down
16 changes: 10 additions & 6 deletions src/cdk/private/style-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
EnvironmentInjector,
inject,
Injectable,
Injector,
Type,
} from '@angular/core';

Expand All @@ -34,25 +35,28 @@ const appsWithLoaders = new WeakMap<
*/
@Injectable({providedIn: 'root'})
export class _CdkPrivateStyleLoader {
private _appRef = inject(ApplicationRef);
private _appRef: ApplicationRef | undefined;
private _injector = inject(Injector);
private _environmentInjector = inject(EnvironmentInjector);

/**
* Loads a set of styles.
* @param loader Component which will be instantiated to load the styles.
*/
load(loader: Type<unknown>): void {
let data = appsWithLoaders.get(this._appRef);
// Resolve the app ref lazily to avoid circular dependency errors if this is called too early.
const appRef = (this._appRef = this._appRef || this._injector.get(ApplicationRef));
let data = appsWithLoaders.get(appRef);

// If we haven't loaded for this app before, we have to initialize it.
if (!data) {
data = {loaders: new Set(), refs: []};
appsWithLoaders.set(this._appRef, data);
appsWithLoaders.set(appRef, data);

// When the app is destroyed, we need to clean up all the related loaders.
this._appRef.onDestroy(() => {
appsWithLoaders.get(this._appRef)?.refs.forEach(ref => ref.destroy());
appsWithLoaders.delete(this._appRef);
appRef.onDestroy(() => {
appsWithLoaders.get(appRef)?.refs.forEach(ref => ref.destroy());
appsWithLoaders.delete(appRef);
});
}

Expand Down
4 changes: 4 additions & 0 deletions src/cdk/text-field/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ ng_module(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
assets = [
":text-field-prebuilt.css",
],
deps = [
"//src/cdk/coercion",
"//src/cdk/platform",
"//src/cdk/private",
"@npm//@angular/core",
"@npm//rxjs",
],
Expand Down
6 changes: 6 additions & 0 deletions src/cdk/text-field/autofill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ import {
Directive,
ElementRef,
EventEmitter,
inject,
Injectable,
NgZone,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
import {coerceElement} from '@angular/cdk/coercion';
import {EMPTY, Observable, Subject} from 'rxjs';
import {_CdkTextFieldStyleLoader} from './text-field-style-loader';

/** An event that is emitted when the autofill state of an input changes. */
export type AutofillEvent = {
Expand All @@ -44,6 +47,7 @@ const listenerOptions = normalizePassiveListenerOptions({passive: true});
*/
@Injectable({providedIn: 'root'})
export class AutofillMonitor implements OnDestroy {
private _styleLoader = inject(_CdkPrivateStyleLoader);
private _monitoredElements = new Map<Element, MonitoredElementInfo>();

constructor(
Expand All @@ -70,6 +74,8 @@ export class AutofillMonitor implements OnDestroy {
return EMPTY;
}

this._styleLoader.load(_CdkTextFieldStyleLoader);

const element = coerceElement(elementOrRef);
const info = this._monitoredElements.get(element);

Expand Down
8 changes: 6 additions & 2 deletions src/cdk/text-field/autosize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ import {
Optional,
Inject,
booleanAttribute,
inject,
} from '@angular/core';
import {DOCUMENT} from '@angular/common';
import {Platform} from '@angular/cdk/platform';
import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
import {auditTime, takeUntil} from 'rxjs/operators';
import {fromEvent, Subject} from 'rxjs';
import {DOCUMENT} from '@angular/common';
import {_CdkTextFieldStyleLoader} from './text-field-style-loader';

/** Directive to automatically resize a textarea to fit its content. */
@Directive({
Expand Down Expand Up @@ -124,8 +127,9 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
/** @breaking-change 11.0.0 make document required */
@Optional() @Inject(DOCUMENT) document?: any,
) {
const styleLoader = inject(_CdkPrivateStyleLoader);
styleLoader.load(_CdkTextFieldStyleLoader);
this._document = document;

this._textareaElement = this._elementRef.nativeElement as HTMLTextAreaElement;
}

Expand Down
20 changes: 20 additions & 0 deletions src/cdk/text-field/text-field-style-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core';

/** Component used to load the structural styles of the text field. */
@Component({
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
styleUrl: 'text-field-prebuilt.css',
standalone: true,
host: {'cdk-text-field-style-loader': ''},
})
export class _CdkTextFieldStyleLoader {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component, inject} from '@angular/core';
import {Overlay} from '@angular/cdk/overlay';
import {Overlay, OverlayContainer} from '@angular/cdk/overlay';
import {ScrollingModule} from '@angular/cdk/scrolling';

@Component({
Expand All @@ -11,4 +11,9 @@ import {ScrollingModule} from '@angular/cdk/scrolling';
})
export class BlockScrollStrategyE2E {
scrollStrategy = inject(Overlay).scrollStrategies.block();

constructor() {
// This loads the structural styles for the test.
inject(OverlayContainer).getContainerElement();
}
}
8 changes: 8 additions & 0 deletions src/material/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ ng_module(
":option/option.css",
":option/optgroup.css",
":internal-form-field/internal-form-field.css",
":ripple/ripple-structure.css",
] + glob(["**/*.html"]),
deps = [
"//src:dev_mode_types",
Expand All @@ -33,6 +34,7 @@ ng_module(
"//src/cdk/coercion",
"//src/cdk/keycodes",
"//src/cdk/platform",
"//src/cdk/private",
"@npm//@angular/animations",
"@npm//@angular/core",
"@npm//@angular/forms",
Expand Down Expand Up @@ -94,6 +96,12 @@ sass_binary(
deps = [":core_scss_lib"],
)

sass_binary(
name = "ripple_structure_scss",
src = "ripple/ripple-structure.scss",
deps = [":core_scss_lib"],
)

# M3 themes
sass_binary(
name = "azure_blue_prebuilt",
Expand Down
5 changes: 0 additions & 5 deletions src/material/core/_core.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
@use '@angular/cdk';
@use './tokens/m2/mat/app' as tokens-mat-app;
@use './tokens/token-utils';
@use './ripple/ripple';
@use './style/elevation';
@use './focus-indicators/private';

Expand All @@ -15,11 +14,7 @@
--mat-app-on-surface: initial;
}

@include ripple.ripple();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!!

@include cdk.a11y-visually-hidden();
@include cdk.overlay();
@include cdk.text-field-autosize();
@include cdk.text-field-autofill();
@include private.structural-styling('mat');
@include private.structural-styling('mat-mdc');

Expand Down
1 change: 1 addition & 0 deletions src/material/core/private/ripple-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
defaultRippleAnimationConfig,
} from '../ripple';
import {Platform, _getEventTarget} from '@angular/cdk/platform';
import {_CdkPrivateStyleLoader} from '@angular/cdk/private';

/** The options for the MatRippleLoader's event listeners. */
const eventListenerOptions = {capture: true};
Expand Down
2 changes: 1 addition & 1 deletion src/material/core/ripple/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {MatRipple} from './ripple';

export * from './ripple';
export * from './ripple-ref';
export * from './ripple-renderer';
export {RippleRenderer, RippleTarget, defaultRippleAnimationConfig} from './ripple-renderer';

@NgModule({
imports: [MatCommonModule, MatRipple],
Expand Down
Loading
Loading