diff --git a/src/dev-app/BUILD.bazel b/src/dev-app/BUILD.bazel index 049f6f0fc5c1..5c8cbb90881b 100644 --- a/src/dev-app/BUILD.bazel +++ b/src/dev-app/BUILD.bazel @@ -1,5 +1,5 @@ load("@build_bazel_rules_nodejs//:index.bzl", "pkg_web") -load("//tools:defaults.bzl", "devmode_esbuild", "esbuild_config", "http_server", "ng_module", "sass_binary") +load("//tools:defaults.bzl", "devmode_esbuild", "esbuild_config", "http_server", "ng_module", "sass_binary", "sass_library") load("//src/components-examples:config.bzl", "ALL_EXAMPLES") load("//tools/angular:index.bzl", "LINKER_PROCESSED_FW_PACKAGES") @@ -105,6 +105,14 @@ devmode_esbuild( ], ) +sass_library( + name = "color-api-back-compat", + srcs = glob(["**/_*.scss"]), + deps = [ + "//src/material:sass_lib", + ], +) + sass_binary( name = "theme", src = "theme.scss", @@ -119,6 +127,7 @@ sass_binary( name = "theme_m3", src = "theme-m3.scss", deps = [ + ":color-api-back-compat", "//src/material:sass_lib", "//src/material-experimental:sass_lib", "//src/material/core:theming_scss_lib", diff --git a/src/dev-app/_color-api-back-compat.scss b/src/dev-app/_color-api-back-compat.scss new file mode 100644 index 000000000000..ec2486cc6798 --- /dev/null +++ b/src/dev-app/_color-api-back-compat.scss @@ -0,0 +1,96 @@ +@use '@angular/material' as mat; + +@mixin color-variant-styles($theme, $color-variant) { + @include mat.option-color($theme, $color-variant: $color-variant); + @include mat.progress-spinner-color($theme, $color-variant: $color-variant); + @include mat.pseudo-checkbox-color($theme, $color-variant: $color-variant); + @include mat.stepper-color($theme, $color-variant: $color-variant); + + &.mat-icon { + @include mat.icon-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-checkbox { + @include mat.checkbox-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-slider { + @include mat.slider-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-tab-group, + &.mat-mdc-tab-nav-bar { + @include mat.tabs-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-slide-toggle { + @include mat.slide-toggle-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-form-field { + @include mat.select-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-radio-button { + @include mat.radio-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-progress-bar { + @include mat.progress-bar-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-form-field { + @include mat.form-field-color($theme, $color-variant: $color-variant); + } + + &.mat-datepicker-content { + @include mat.datepicker-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-button-base { + @include mat.button-color($theme, $color-variant: $color-variant); + } + + &.mat-mdc-standard-chip { + @include mat.chips-color($theme, $color-variant: $color-variant); + } + + .mdc-list-item__start, + .mdc-list-item__end { + @include mat.checkbox-color($theme, $color-variant: $color-variant); + @include mat.radio-color($theme, $color-variant: $color-variant); + } + + // M3 dropped support for warn/error color FABs. + @if $color-variant != error { + &.mat-mdc-fab, + &.mat-mdc-mini-fab { + @include mat.fab-color($theme, $color-variant: $color-variant); + } + } +} + +// TODO(mmalerba): Consider adding this as a back-compat API for users who want it, rather than just +// a demo thing. +@mixin color-variants-back-compat($theme) { + .mat-primary { + @include color-variant-styles($theme, primary); + } + .mat-badge { + @include mat.badge-color($theme, $color-variant: primary); + } + + .mat-accent { + @include color-variant-styles($theme, tertiary); + } + .mat-badge-accent { + @include mat.badge-color($theme, $color-variant: tertiary); + } + + .mat-warn { + @include color-variant-styles($theme, error); + } + .mat-badge-warn { + @include mat.badge-color($theme, $color-variant: error); + } +} diff --git a/src/dev-app/dev-app/dev-app-layout.html b/src/dev-app/dev-app/dev-app-layout.html index 62bbfa434256..17688a632475 100644 --- a/src/dev-app/dev-app/dev-app-layout.html +++ b/src/dev-app/dev-app/dev-app-layout.html @@ -45,6 +45,14 @@

Angular Material Demos

+ @if (state.m3Enabled) { + + } diff --git a/src/dev-app/select/select-demo.ts b/src/dev-app/select/select-demo.ts index ffa817bd84f9..61f2da697ebd 100644 --- a/src/dev-app/select/select-demo.ts +++ b/src/dev-app/select/select-demo.ts @@ -71,7 +71,6 @@ export class SelectDemo { pokemonTheme: ThemePalette = 'primary'; compareByValue = true; selectFormControl = new FormControl('', Validators.required); - m3ForceSecondary = true; sandwichBread = ''; sandwichMeat = ''; diff --git a/src/dev-app/theme-m3.scss b/src/dev-app/theme-m3.scss index 0246d022ed41..553b87b8036e 100644 --- a/src/dev-app/theme-m3.scss +++ b/src/dev-app/theme-m3.scss @@ -1,283 +1,93 @@ -@use 'sass:map'; @use '@angular/material' as mat; @use '@angular/material-experimental' as matx; - -@mixin color-variant-styles($theme, $color-variant) { - @include mat.option-color($theme, $color-variant: $color-variant); - @include mat.progress-spinner-color($theme, $color-variant: $color-variant); - @include mat.pseudo-checkbox-color($theme, $color-variant: $color-variant); - @include mat.stepper-color($theme, $color-variant: $color-variant); - - &.mat-icon { - @include mat.icon-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-checkbox { - @include mat.checkbox-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-slider { - @include mat.slider-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-tab-group, - &.mat-mdc-tab-nav-bar { - @include mat.tabs-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-slide-toggle { - @include mat.slide-toggle-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-form-field { - @include mat.select-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-radio-button { - @include mat.radio-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-progress-bar { - @include mat.progress-bar-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-form-field { - @include mat.form-field-color($theme, $color-variant: $color-variant); - } - - &.mat-datepicker-content { - @include mat.datepicker-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-button-base { - @include mat.button-color($theme, $color-variant: $color-variant); - } - - &.mat-mdc-standard-chip { - @include mat.chips-color($theme, $color-variant: $color-variant); - } - - .mdc-list-item__start, - .mdc-list-item__end { - @include mat.checkbox-color($theme, $color-variant: $color-variant); - @include mat.radio-color($theme, $color-variant: $color-variant); - } - - // M3 dropped support for warn/error color FABs. - @if $color-variant != error { - &.mat-mdc-fab, - &.mat-mdc-mini-fab { - @include mat.fab-color($theme, $color-variant: $color-variant); - } - } +@use './color-api-back-compat'; + +// Plus imports for other components in your app. + +// Disable legacy API compatibility, since dev-app is fully migrated to theme inspection API. +mat.$theme-legacy-inspection-api-compatibility: false; + +// Create a theme with the specified color type and density. +@function create-theme($type: light, $density: 0) { + @return matx.define-theme(( + color: ( + theme-type: $type, + primary: matx.$m3-green-palette, + tertiary: matx.$m3-violet-palette, + ), + density: ( + scale: $density + ), + )); } -// TODO(mmalerba): Consider adding this as a back-compat API for users who want it, rather than just -// a demo thing. -@mixin color-variants-back-compat($theme) { - .mat-primary { - @include color-variant-styles($theme, primary); - } - .mat-badge { - @include mat.badge-color($theme, $color-variant: primary); - } +// Define the default (light) theme. +$light-theme: create-theme($type: light); - .mat-accent { - @include color-variant-styles($theme, tertiary); - } - .mat-badge-accent { - @include mat.badge-color($theme, $color-variant: tertiary); - } - - .mat-warn { - @include color-variant-styles($theme, error); - } - .mat-badge-warn { - @include mat.badge-color($theme, $color-variant: error); - } -} - -// Add an indicator to make it clear that the app is styled with the experimental M3 theme. -dev-app { - &::before { - content: 'Using experimental M3 theme, only components that support M3 will work'; - display: inline-block; - position: fixed; - z-index: 100; - bottom: 0; - left: 50%; - transform: translateX(-50%); - padding: 8px; - border-radius: 8px 8px 0 0; - background: red; - color: white; - } -} +// Create our dark theme. +$dark-theme: create-theme($type: dark); -// Emit Angular Material core styles. +// Include the common styles for Angular Material. We include this here so that you only +// have to load a single css file for Angular Material in your app. +// **Be sure that you only ever include this mixin once!** @include mat.core(); -// Base theme configuration for our M3 theme. -$m3-base-config: ( - color: ( - primary: matx.$m3-green-palette, - tertiary: matx.$m3-violet-palette, - ), -); - -// Our M3 light theme. -$light-theme: matx.define-theme($m3-base-config); - -// Our M3 dark theme. -$dark-theme: matx.define-theme(map.set($m3-base-config, color, theme-type, dark)); - -// Emit default theme styles. +// Include the default theme styles. html { - @include mat.autocomplete-theme($light-theme); - @include mat.badge-theme($light-theme); - @include mat.bottom-sheet-theme($light-theme); - @include mat.button-theme($light-theme); - @include mat.button-toggle-theme($light-theme); - @include mat.card-theme($light-theme); - @include mat.checkbox-theme($light-theme); - @include mat.chips-theme($light-theme); - @include mat.core-theme($light-theme); - @include mat.datepicker-theme($light-theme); - @include mat.dialog-theme($light-theme); - @include mat.divider-theme($light-theme); - @include mat.expansion-theme($light-theme); - @include mat.fab-theme($light-theme); - @include mat.form-field-theme($light-theme); - @include mat.grid-list-theme($light-theme); - @include mat.icon-button-theme($light-theme); - @include mat.icon-theme($light-theme); - @include mat.input-theme($light-theme); - @include mat.list-theme($light-theme); - @include mat.menu-theme($light-theme); - @include mat.paginator-theme($light-theme); - @include mat.progress-bar-theme($light-theme); - @include mat.progress-spinner-theme($light-theme); - @include mat.radio-theme($light-theme); - @include mat.select-theme($light-theme); - @include mat.sidenav-theme($light-theme); - @include mat.slide-toggle-theme($light-theme); - @include mat.slider-theme($light-theme); - @include mat.snack-bar-theme($light-theme); - @include mat.sort-theme($light-theme); - @include mat.stepper-theme($light-theme); - @include mat.table-theme($light-theme); - @include mat.tabs-theme($light-theme); - @include mat.toolbar-theme($light-theme); - @include mat.tooltip-theme($light-theme); - @include mat.tree-theme($light-theme); + @include mat.all-component-themes($light-theme); + // TODO(mmalerba): Support M3 for experimental components. + // @include matx.column-resize-theme($light-theme); + // @include matx.popover-edit-theme($light-theme); } -@include color-variants-back-compat($light-theme); +// TODO(mmalerba): Support M3 for typography hierarchy. +// @include mat.typography-hierarchy($light-theme); -.demo-force-secondary { - @include mat.option-color($light-theme, $color-variant: secondary); +.demo-strong-focus { + // Note: we can theme the indicators directly through `strong-focus-indicators` as well. + // Use the theme so we have some coverage over the entire API surface. + @include mat.strong-focus-indicators(); + @include mat.strong-focus-indicators-theme($light-theme); } -// Emit dark theme styles. +// Include the alternative theme styles inside of a block with a CSS class. You can make this +// CSS class whatever you want. In this example, any component inside of an element with +// `.demo-unicorn-dark-theme` will be affected by this alternate dark theme instead of the +// default theme. .demo-unicorn-dark-theme { - // TODO(mmalerba): choose colors from the theming API. - background: black; - color: white; + // Include the dark theme color styles. + @include mat.all-component-colors($dark-theme); + // TODO(mmalerba): Support M3 for experimental components. + // @include matx.column-resize-color($dark-theme); + // @include matx.popover-edit-color($dark-theme); - @include mat.autocomplete-color($dark-theme); - @include mat.badge-color($dark-theme); - @include mat.bottom-sheet-color($dark-theme); - @include mat.button-color($dark-theme); - @include mat.button-toggle-color($dark-theme); - @include mat.card-color($dark-theme); - @include mat.checkbox-color($dark-theme); - @include mat.chips-color($dark-theme); - @include mat.core-color($dark-theme); - @include mat.datepicker-color($dark-theme); - @include mat.dialog-color($dark-theme); - @include mat.divider-color($dark-theme); - @include mat.expansion-color($dark-theme); - @include mat.fab-color($dark-theme); - @include mat.form-field-color($dark-theme); - @include mat.grid-list-color($dark-theme); - @include mat.icon-button-color($dark-theme); - @include mat.icon-color($dark-theme); - @include mat.input-color($dark-theme); - @include mat.list-color($dark-theme); - @include mat.menu-color($dark-theme); - @include mat.paginator-color($dark-theme); - @include mat.progress-bar-color($dark-theme); - @include mat.progress-spinner-color($dark-theme); - @include mat.radio-color($dark-theme); - @include mat.select-color($dark-theme); - @include mat.sidenav-color($dark-theme); - @include mat.slide-toggle-color($dark-theme); - @include mat.slider-color($dark-theme); - @include mat.snack-bar-color($dark-theme); - @include mat.sort-color($dark-theme); - @include mat.stepper-color($dark-theme); - @include mat.table-color($dark-theme); - @include mat.tabs-color($dark-theme); - @include mat.toolbar-color($dark-theme); - @include mat.tooltip-color($dark-theme); - @include mat.tree-color($dark-theme); - - @include color-variants-back-compat($dark-theme); - - .demo-force-secondary { - @include mat.option-color($dark-theme, $color-variant: secondary); + // Include the dark theme colors for focus indicators. + &.demo-strong-focus { + @include mat.strong-focus-indicators-color($dark-theme); } } -.demo-toolbar { - margin-left: 8px; -} - -.demo-config-buttons { - gap: 8px; +// Create classes for all density scales which are supported by all MDC-based components. +// The classes are applied conditionally based on the selected density in the dev-app layout +// component. +$density-scales: (-1, -2, -3, -4, minimum, maximum); +@each $scale in $density-scales { + .demo-density-#{$scale} { + $density-theme: create-theme($density: $scale); + @include mat.all-component-densities($density-theme); + } } -// Emit density styles for each scale. -@each $scale in (maximum, 0, -1, -2, -3, -4, minimum) { - $scale-theme: matx.define-theme(map.set($m3-base-config, density, scale, $scale)); +// Enable back-compat CSS for color="..." API. +.demo-color-api-back-compat { + @include color-api-back-compat.color-variants-back-compat($light-theme); - .demo-density-#{$scale} { - @include mat.autocomplete-density($scale-theme); - @include mat.badge-density($scale-theme); - @include mat.bottom-sheet-density($scale-theme); - @include mat.button-density($scale-theme); - @include mat.button-toggle-density($scale-theme); - @include mat.card-density($scale-theme); - @include mat.checkbox-density($scale-theme); - @include mat.chips-density($scale-theme); - @include mat.core-density($scale-theme); - @include mat.datepicker-density($scale-theme); - @include mat.dialog-density($scale-theme); - @include mat.divider-density($scale-theme); - @include mat.expansion-density($scale-theme); - @include mat.fab-density($scale-theme); - @include mat.form-field-density($scale-theme); - @include mat.grid-list-density($scale-theme); - @include mat.icon-button-density($scale-theme); - @include mat.icon-density($scale-theme); - @include mat.input-density($scale-theme); - @include mat.list-density($scale-theme); - @include mat.menu-density($scale-theme); - @include mat.paginator-density($scale-theme); - @include mat.progress-bar-density($scale-theme); - @include mat.progress-spinner-density($scale-theme); - @include mat.radio-density($scale-theme); - @include mat.select-density($scale-theme); - @include mat.sidenav-density($scale-theme); - @include mat.slide-toggle-density($scale-theme); - @include mat.slider-density($scale-theme); - @include mat.snack-bar-density($scale-theme); - @include mat.sort-density($scale-theme); - @include mat.stepper-density($scale-theme); - @include mat.table-density($scale-theme); - @include mat.tabs-density($scale-theme); - @include mat.toolbar-density($scale-theme); - @include mat.tooltip-density($scale-theme); - @include mat.tree-density($scale-theme); + &.demo-unicorn-dark-theme { + @include color-api-back-compat.color-variants-back-compat($dark-theme); } } + +// In M3 buttons are smaller than their touch target at zero-density. +.demo-config-buttons button { + margin: 4px; +} diff --git a/src/material/core/theming/_inspection.scss b/src/material/core/theming/_inspection.scss index 2b966d7206e9..6dc55b1816bc 100644 --- a/src/material/core/theming/_inspection.scss +++ b/src/material/core/theming/_inspection.scss @@ -285,7 +285,7 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac } $result: (); @each $system in $systems { - $result: map.deep-merge($result, map.get($theme, $_internals, '#{$system}-tokens')); + $result: map.deep-merge($result, map.get($theme, $_internals, '#{$system}-tokens') or ()); } @return $result; } diff --git a/src/material/core/theming/_m2-inspection.scss b/src/material/core/theming/_m2-inspection.scss index 005e274ec65b..7bd55cbab051 100644 --- a/src/material/core/theming/_m2-inspection.scss +++ b/src/material/core/theming/_m2-inspection.scss @@ -123,7 +123,8 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac } $palette: map.get($colors, $palette-name); @if not $palette { - @error 'Unrecognized palette name:' $palette-name; + @error $palette-name $args $theme; + @error #{'Unrecognized palette name:'} $palette-name; } @return theming.get-color-from-palette($palette, $args...); } diff --git a/src/material/core/tokens/m2/_index.scss b/src/material/core/tokens/m2/_index.scss index deff7b14c658..8e34e08a1402 100644 --- a/src/material/core/tokens/m2/_index.scss +++ b/src/material/core/tokens/m2/_index.scss @@ -68,6 +68,7 @@ @use './mdc/switch' as tokens-mdc-switch; @use './mdc/tab' as tokens-mdc-tab; @use './mdc/tab-indicator' as tokens-mdc-tab-indicator; +@use '../../theming/inspection'; /// Gets the tokens for the given theme, m2 tokens module, and theming system. /// @param {Map} $theme The Angular Material theme object to generate token values from. @@ -81,11 +82,11 @@ @return meta.call( meta.get-function(get-#{$system}-tokens, $module: $module)); } - @if not map.get($theme, $system) { + @if not inspection.theme-has($theme, $system) { @return (); } @return meta.call( - meta.get-function(get-#{$system}-tokens, $module: $module), map.get($theme, $system)); + meta.get-function(get-#{$system}-tokens, $module: $module), $theme); } /// Gets the fully qualified tokens map for the given theme and m2 tokens module.