diff --git a/src/material/core/_core-theme.scss b/src/material/core/_core-theme.scss
index 7883579a8923..0a7c013f203f 100644
--- a/src/material/core/_core-theme.scss
+++ b/src/material/core/_core-theme.scss
@@ -1,12 +1,10 @@
@use './theming/theming';
@use './theming/inspection';
@use './theming/validation';
-@use './style/private';
@use './ripple/ripple-theme';
@use './option/option-theme';
@use './option/optgroup-theme';
@use './selection/pseudo-checkbox/pseudo-checkbox-theme';
-@use './style/elevation';
@use './style/sass-utils';
@use './typography/typography';
@use './tokens/token-utils';
@@ -41,6 +39,10 @@ $_has-inserted-loaded-marker: false;
@include option-theme.base($theme);
@include optgroup-theme.base($theme);
@include pseudo-checkbox-theme.base($theme);
+ @include sass-utils.current-selector-or-root() {
+ @include token-utils.create-token-values(tokens-mat-app.$prefix,
+ tokens-mat-app.get-unthemable-tokens());
+ }
}
// The marker is a concrete style no matter which Material version we're targeting.
@@ -60,18 +62,6 @@ $_has-inserted-loaded-marker: false;
@include token-utils.create-token-values(tokens-mat-app.$prefix,
tokens-mat-app.get-color-tokens($theme));
}
-
- // Provides external CSS classes for each elevation value. Each CSS class is formatted as
- // `mat-elevation-z$zValue` where `$zValue` corresponds to the z-space to which the element is
- // elevated.
- @for $zValue from 0 through 24 {
- $selector: elevation.$prefix + $zValue;
- // We need the `mat-mdc-elevation-specific`, because some MDC mixins
- // come with elevation baked in and we don't have a way of removing it.
- .#{$selector}, .mat-mdc-elevation-specific.#{$selector} {
- @include private.private-theme-elevation($zValue, $theme);
- }
- }
}
}
diff --git a/src/material/core/_core.scss b/src/material/core/_core.scss
index c6e3056cf53d..ef7bb5287080 100644
--- a/src/material/core/_core.scss
+++ b/src/material/core/_core.scss
@@ -2,6 +2,7 @@
@use './tokens/m2/mat/app' as tokens-mat-app;
@use './tokens/token-utils';
@use './ripple/ripple';
+@use './style/elevation';
@use './focus-indicators/private';
@use './mdc-helpers/mdc-helpers';
@@ -18,13 +19,26 @@
// Wrapper element that provides the theme background when the
// user's content isn't inside of a `mat-sidenav-container`.
@at-root {
- .mat-app-background {
- @include mdc-helpers.disable-mdc-fallback-declarations {
- @include token-utils.use-tokens(tokens-mat-app.$prefix, tokens-mat-app.get-token-slots()) {
- // Note: we need to emit fallback values here to avoid errors in internal builds.
+ // Note: we need to emit fallback values here to avoid errors in internal builds.
+ @include mdc-helpers.disable-mdc-fallback-declarations {
+ @include token-utils.use-tokens(tokens-mat-app.$prefix, tokens-mat-app.get-token-slots()) {
+ .mat-app-background {
@include token-utils.create-token-slot(background-color, background-color, transparent);
@include token-utils.create-token-slot(color, text-color, inherit);
}
+
+ // Provides external CSS classes for each elevation value. Each CSS class is formatted as
+ // `mat-elevation-z$zValue` where `$zValue` corresponds to the z-space to which the element
+ // is elevated.
+ @for $zValue from 0 through 24 {
+ $selector: elevation.$prefix + $zValue;
+ // We need the `mat-mdc-elevation-specific`, because some MDC mixins
+ // come with elevation baked in and we don't have a way of removing it.
+ .#{$selector}, .mat-mdc-elevation-specific.#{$selector} {
+ @include token-utils.create-token-slot(box-shadow, 'elevation-shadow-level-#{$zValue}',
+ none);
+ }
+ }
}
}
}
diff --git a/src/material/core/tokens/m2/mat/_app.scss b/src/material/core/tokens/m2/mat/_app.scss
index c82a8b4d1ec2..2443e7f10a6f 100644
--- a/src/material/core/tokens/m2/mat/_app.scss
+++ b/src/material/core/tokens/m2/mat/_app.scss
@@ -1,3 +1,5 @@
+@use '@material/elevation/elevation-theme' as mdc-elevation;
+@use 'sass:map';
@use '../../token-utils';
@use '../../../theming/inspection';
@use '../../../style/sass-utils';
@@ -13,10 +15,19 @@ $prefix: (mat, app);
// Tokens that can be configured through Angular Material's color theming API.
@function get-color-tokens($theme) {
- @return (
+ $tokens: (
background-color: inspection.get-theme-color($theme, background, background),
text-color: inspection.get-theme-color($theme, foreground, text),
);
+
+ @for $zValue from 0 through 24 {
+ $elevation-color: inspection.get-theme-color($theme, foreground, elevation);
+ $shadow: mdc-elevation.elevation-box-shadow($zValue,
+ if($elevation-color == null, elevation.$color, $elevation-color));
+ $tokens: map.set($tokens, 'elevation-shadow-level-#{$zValue}', $shadow);
+ }
+
+ @return $tokens;
}
// Tokens that can be configured through Angular Material's typography theming API.
diff --git a/src/material/core/tokens/m2/mat/_menu.scss b/src/material/core/tokens/m2/mat/_menu.scss
index 79c9155eeb26..e3b04cfe5fb5 100644
--- a/src/material/core/tokens/m2/mat/_menu.scss
+++ b/src/material/core/tokens/m2/mat/_menu.scss
@@ -18,6 +18,9 @@ $prefix: (mat, menu);
item-trailing-spacing: 16px,
item-with-icon-leading-spacing: 16px,
item-with-icon-trailing-spacing: 16px,
+ // Note that this uses a value, rather than a computed box-shadow, because we use
+ // the value at runtime to determine which shadow to set based on the menu's depth.
+ base-elevation-level: 8,
);
}
diff --git a/src/material/core/tokens/m3/mat/_app.scss b/src/material/core/tokens/m3/mat/_app.scss
index 879fdc9570ad..e54826db04c5 100644
--- a/src/material/core/tokens/m3/mat/_app.scss
+++ b/src/material/core/tokens/m3/mat/_app.scss
@@ -1,4 +1,5 @@
@use 'sass:map';
+@use '@material/elevation' as mdc-elevation;
@use '../../token-utils';
// The prefix used to generate the fully qualified name for tokens in this file.
@@ -10,10 +11,18 @@ $prefix: (mat, app);
/// @param {Map} $token-slots Possible token slots
/// @return {Map} A set of custom tokens for the app
@function get-tokens($systems, $exclude-hardcoded, $token-slots) {
+ $shadow-color: map.get($systems, md-sys-color, shadow);
$tokens: (
background-color: map.get($systems, md-sys-color, background),
text-color: map.get($systems, md-sys-color, on-background),
);
+ @if ($shadow-color) {
+ @for $zValue from 0 through 24 {
+ $shadow: mdc-elevation.elevation-box-shadow($zValue, $shadow-color);
+ $tokens: map.set($tokens, 'elevation-shadow-level-#{$zValue}', $shadow);
+ }
+ }
+
@return token-utils.namespace-tokens($prefix, $tokens, $token-slots);
}
diff --git a/src/material/core/tokens/m3/mat/_menu.scss b/src/material/core/tokens/m3/mat/_menu.scss
index bbb36c889c4f..ddc173329e55 100644
--- a/src/material/core/tokens/m3/mat/_menu.scss
+++ b/src/material/core/tokens/m3/mat/_menu.scss
@@ -35,6 +35,9 @@ $prefix: (mat, menu);
item-with-icon-leading-spacing: token-utils.hardcode(12px, $exclude-hardcoded),
item-with-icon-trailing-spacing: token-utils.hardcode(12px, $exclude-hardcoded),
container-color: map.get($systems, md-sys-color, surface-container),
+ // Note that this uses a value, rather than a computed box-shadow, because we use
+ // the value at runtime to determine which shadow to set based on the menu's depth.
+ base-elevation-level: token-utils.hardcode(2, $exclude-hardcoded),
)
);
diff --git a/src/material/menu/menu.spec.ts b/src/material/menu/menu.spec.ts
index 7e538385988d..2de78b8f76e0 100644
--- a/src/material/menu/menu.spec.ts
+++ b/src/material/menu/menu.spec.ts
@@ -606,7 +606,7 @@ describe('MDC-based MatMenu', () => {
const panel = overlayContainerElement.querySelector('.mat-mdc-menu-panel')!;
expect(panel.classList).toContain('custom-one');
- expect(panel.classList).toContain('mat-elevation-z8');
+ expect(panel.classList).toContain('mat-elevation-z2');
fixture.componentInstance.panelClass = 'custom-two';
fixture.detectChanges();
@@ -615,8 +615,8 @@ describe('MDC-based MatMenu', () => {
expect(panel.classList).toContain('custom-two');
expect(panel.classList).toContain('mat-mdc-elevation-specific');
expect(panel.classList)
- .withContext('Expected mat-elevation-z8 not to be removed')
- .toContain('mat-elevation-z8');
+ .withContext('Expected mat-elevation-z2 not to be removed')
+ .toContain('mat-elevation-z2');
}));
it('should set the "menu" role on the overlay panel', fakeAsync(() => {
@@ -2369,17 +2369,17 @@ describe('MDC-based MatMenu', () => {
expect(menus[0].classList).toContain('mat-mdc-elevation-specific');
expect(menus[0].classList)
.withContext('Expected root menu to have base elevation.')
- .toContain('mat-elevation-z8');
+ .toContain('mat-elevation-z2');
expect(menus[1].classList).toContain('mat-mdc-elevation-specific');
expect(menus[1].classList)
.withContext('Expected first sub-menu to have base elevation + 1.')
- .toContain('mat-elevation-z9');
+ .toContain('mat-elevation-z3');
expect(menus[2].classList).toContain('mat-mdc-elevation-specific');
expect(menus[2].classList)
.withContext('Expected second sub-menu to have base elevation + 2.')
- .toContain('mat-elevation-z10');
+ .toContain('mat-elevation-z4');
}));
it('should update the elevation when the same menu is opened at a different depth', fakeAsync(() => {
@@ -2398,7 +2398,7 @@ describe('MDC-based MatMenu', () => {
expect(lastMenu.classList).toContain('mat-mdc-elevation-specific');
expect(lastMenu.classList)
.withContext('Expected menu to have the base elevation plus two.')
- .toContain('mat-elevation-z10');
+ .toContain('mat-elevation-z4');
(overlay.querySelector('.cdk-overlay-backdrop')! as HTMLElement).click();
fixture.detectChanges();
@@ -2417,10 +2417,10 @@ describe('MDC-based MatMenu', () => {
expect(lastMenu.classList).toContain('mat-mdc-elevation-specific');
expect(lastMenu.classList)
.not.withContext('Expected menu not to maintain old elevation.')
- .toContain('mat-elevation-z10');
+ .toContain('mat-elevation-z4');
expect(lastMenu.classList)
.withContext('Expected menu to have the proper updated elevation.')
- .toContain('mat-elevation-z8');
+ .toContain('mat-elevation-z2');
}));
it('should not change focus origin if origin not specified for trigger', fakeAsync(() => {
@@ -2461,7 +2461,7 @@ describe('MDC-based MatMenu', () => {
expect(menuClasses)
.withContext('Expected user elevation to be maintained')
.toContain('mat-elevation-z24');
- expect(menuClasses).not.toContain('mat-elevation-z8', 'Expected no stacked elevation.');
+ expect(menuClasses).not.toContain('mat-elevation-z2', 'Expected no stacked elevation.');
}));
it('should close all of the menus when the root is closed programmatically', fakeAsync(() => {
@@ -2762,7 +2762,7 @@ const SIMPLE_MENU_TEMPLATE = `
- @for (item of extraItems; track item) {
+ @for (item of extraItems; track $index) {
}
@@ -2949,7 +2949,7 @@ class NestedMenuCustomElevation {
template: `
- @for (item of items; track item) {
+ @for (item of items; track $index) {
- @for (item of items; track item) {
+ @for (item of items; track $index) {
}
@@ -3092,7 +3092,7 @@ class SimpleMenuWithRepeater {
- @for (item of items; track item) {
+ @for (item of items; track $index) {
}
diff --git a/src/material/menu/menu.ts b/src/material/menu/menu.ts
index c2e0716ec0fe..b625f64727e2 100644
--- a/src/material/menu/menu.ts
+++ b/src/material/menu/menu.ts
@@ -120,7 +120,7 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnI
private _firstItemFocusRef?: AfterRenderRef;
private _previousElevation: string;
private _elevationPrefix = 'mat-elevation-z';
- private _baseElevation = 8;
+ private _baseElevation: number | null = null;
/** All items inside the menu. Includes items nested inside another menu. */
@ContentChildren(MatMenuItem, {descendants: true}) _allItems: QueryList;
@@ -470,6 +470,17 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnI
* @param depth Number of parent menus that come before the menu.
*/
setElevation(depth: number): void {
+ // The base elevation depends on which version of the spec
+ // we're running so we have to resolve it at runtime.
+ if (this._baseElevation === null) {
+ const styles =
+ typeof getComputedStyle === 'function'
+ ? getComputedStyle(this._elementRef.nativeElement)
+ : null;
+ const value = styles?.getPropertyValue('--mat-menu-base-elevation-level') || '8';
+ this._baseElevation = parseInt(value);
+ }
+
// The elevation starts at the base and increases by one for each level.
// Capped at 24 because that's the maximum elevation defined in the Material design spec.
const elevation = Math.min(this._baseElevation + depth, 24);
diff --git a/src/material/schematics/ng-generate/table/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template b/src/material/schematics/ng-generate/table/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template
index f0c7c4669975..fba358b44012 100644
--- a/src/material/schematics/ng-generate/table/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template
+++ b/src/material/schematics/ng-generate/table/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template
@@ -1,4 +1,4 @@
-