@angular/material 17.0.0-next.0 → 17.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/_index.scss +2 -2
  2. package/button/_button-base.scss +3 -3
  3. package/button/_button-theme-private.scss +3 -2
  4. package/button/_button-theme.scss +18 -25
  5. package/button/_fab-theme.scss +31 -49
  6. package/button/_icon-button-theme.scss +19 -26
  7. package/button/index.d.ts +22 -31
  8. package/card/_card-theme.scss +27 -38
  9. package/checkbox/_checkbox-theme.scss +28 -45
  10. package/core/_core-theme.scss +24 -39
  11. package/core/mdc-helpers/_mdc-helpers.scss +19 -22
  12. package/core/option/_optgroup-theme.scss +13 -23
  13. package/core/option/_option-theme.scss +23 -37
  14. package/core/ripple/_ripple-theme.scss +6 -10
  15. package/core/selection/pseudo-checkbox/_pseudo-checkbox-theme.scss +17 -24
  16. package/core/style/_private.scss +3 -3
  17. package/core/style/_sass-utils.scss +7 -0
  18. package/core/theming/_inspection.scss +87 -60
  19. package/core/theming/_m2-inspection.scss +211 -0
  20. package/core/theming/_theming.scss +59 -6
  21. package/core/tokens/m2/mat/_card.scss +15 -21
  22. package/core/tokens/m2/mat/_form-field.scss +21 -25
  23. package/core/tokens/m2/mat/_optgroup.scss +12 -17
  24. package/core/tokens/m2/mat/_option.scss +16 -28
  25. package/core/tokens/m2/mat/_paginator.scss +16 -18
  26. package/core/tokens/m2/mat/_radio.scss +7 -10
  27. package/core/tokens/m2/mat/_slide-toggle.scss +9 -17
  28. package/core/tokens/m2/mat/_slider.scss +5 -5
  29. package/core/tokens/m2/mdc/_checkbox.scss +21 -20
  30. package/core/tokens/m2/mdc/_elevated-card.scss +6 -9
  31. package/core/tokens/m2/mdc/_extended-fab.scss +8 -17
  32. package/core/tokens/m2/mdc/_fab.scss +6 -7
  33. package/core/tokens/m2/mdc/_filled-text-field.scss +16 -22
  34. package/core/tokens/m2/mdc/_icon-button.scss +1 -1
  35. package/core/tokens/m2/mdc/_linear-progress.scss +9 -10
  36. package/core/tokens/m2/mdc/_list.scss +44 -42
  37. package/core/tokens/m2/mdc/_outlined-card.scss +7 -10
  38. package/core/tokens/m2/mdc/_outlined-text-field.scss +14 -20
  39. package/core/tokens/m2/mdc/_radio.scss +11 -11
  40. package/core/tokens/m2/mdc/_slider.scss +16 -23
  41. package/core/tokens/m2/mdc/_switch.scss +16 -19
  42. package/core/typography/_definition.scss +258 -0
  43. package/core/typography/_property-getters.scss +63 -0
  44. package/core/typography/_typography-utils.scss +9 -69
  45. package/core/typography/_typography.scss +10 -343
  46. package/core/typography/_versioning.scss +86 -0
  47. package/datepicker/index.d.ts +3 -3
  48. package/dialog/_dialog-theme.scss +10 -0
  49. package/esm2022/autocomplete/autocomplete.mjs +1 -1
  50. package/esm2022/button/button-base.mjs +32 -27
  51. package/esm2022/button/button.mjs +6 -6
  52. package/esm2022/button/fab.mjs +23 -31
  53. package/esm2022/button/icon-button.mjs +6 -6
  54. package/esm2022/button/testing/button-harness.mjs +3 -3
  55. package/esm2022/core/version.mjs +1 -1
  56. package/esm2022/datepicker/calendar.mjs +1 -1
  57. package/esm2022/datepicker/datepicker-base.mjs +2 -2
  58. package/esm2022/datepicker/datepicker-toggle.mjs +1 -1
  59. package/esm2022/datepicker/month-view.mjs +2 -2
  60. package/esm2022/datepicker/multi-year-view.mjs +2 -2
  61. package/esm2022/datepicker/year-view.mjs +2 -2
  62. package/esm2022/dialog/dialog-container.mjs +2 -2
  63. package/esm2022/form-field/form-field.mjs +3 -3
  64. package/esm2022/paginator/paginator.mjs +1 -1
  65. package/esm2022/select/select.mjs +3 -3
  66. package/esm2022/slider/slider-input.mjs +19 -9
  67. package/esm2022/slider/slider.mjs +2 -2
  68. package/esm2022/snack-bar/simple-snack-bar.mjs +1 -1
  69. package/fesm2022/autocomplete.mjs.map +1 -1
  70. package/fesm2022/button/testing.mjs +2 -2
  71. package/fesm2022/button/testing.mjs.map +1 -1
  72. package/fesm2022/button.mjs +59 -61
  73. package/fesm2022/button.mjs.map +1 -1
  74. package/fesm2022/core.mjs +1 -1
  75. package/fesm2022/core.mjs.map +1 -1
  76. package/fesm2022/datepicker.mjs +6 -6
  77. package/fesm2022/datepicker.mjs.map +1 -1
  78. package/fesm2022/dialog.mjs +2 -2
  79. package/fesm2022/dialog.mjs.map +1 -1
  80. package/fesm2022/form-field.mjs +2 -2
  81. package/fesm2022/form-field.mjs.map +1 -1
  82. package/fesm2022/paginator.mjs +1 -1
  83. package/fesm2022/paginator.mjs.map +1 -1
  84. package/fesm2022/select.mjs +2 -2
  85. package/fesm2022/select.mjs.map +1 -1
  86. package/fesm2022/slider.mjs +20 -10
  87. package/fesm2022/slider.mjs.map +1 -1
  88. package/fesm2022/snack-bar.mjs +1 -1
  89. package/fesm2022/snack-bar.mjs.map +1 -1
  90. package/form-field/_form-field-density.scss +3 -4
  91. package/form-field/_form-field-focus-overlay.scss +1 -1
  92. package/form-field/_form-field-theme.scss +24 -34
  93. package/input/_input-theme.scss +11 -23
  94. package/list/_list-theme.scss +26 -41
  95. package/package.json +2 -2
  96. package/paginator/_paginator-theme.scss +15 -24
  97. package/prebuilt-themes/deeppurple-amber.css +1 -1
  98. package/prebuilt-themes/indigo-pink.css +1 -1
  99. package/prebuilt-themes/pink-bluegrey.css +1 -1
  100. package/prebuilt-themes/purple-green.css +1 -1
  101. package/progress-bar/_progress-bar-theme.scss +17 -24
  102. package/progress-spinner/_progress-spinner-theme.scss +3 -3
  103. package/radio/_radio-theme.scss +23 -38
  104. package/schematics/ng-add/index.js +1 -1
  105. package/schematics/ng-add/index.mjs +1 -1
  106. package/slide-toggle/_slide-toggle-theme.scss +23 -40
  107. package/slider/_slider-theme.scss +25 -42
  108. package/snack-bar/_snack-bar-theme.scss +2 -2
  109. package/button-toggle/_button-toggle-variables.scss +0 -16
  110. package/paginator/_paginator-variables.scss +0 -15
@@ -1,5 +1,5 @@
1
- @use 'sass:map';
2
1
  @use '../../theming/theming';
2
+ @use '../../theming/inspection';
3
3
 
4
4
  @mixin _psuedo-checkbox-styles-with-color($text-color, $background) {
5
5
  .mat-pseudo-checkbox-checked,
@@ -19,15 +19,13 @@
19
19
  }
20
20
  }
21
21
 
22
- @mixin color($config-or-theme) {
23
- $config: theming.get-color-config($config-or-theme);
24
- $is-dark-theme: map.get($config, is-dark);
25
-
26
- $primary: theming.get-color-from-palette(map.get($config, primary));
27
- $accent: theming.get-color-from-palette(map.get($config, accent));
28
- $warn: theming.get-color-from-palette(map.get($config, warn));
29
- $background: theming.get-color-from-palette(map.get($config, background), background);
30
- $secondary-text: theming.get-color-from-palette(map.get($config, foreground), secondary-text);
22
+ @mixin color($theme) {
23
+ $is-dark-theme: inspection.get-theme-type($theme) == dark;
24
+ $primary: inspection.get-theme-color($theme, primary);
25
+ $accent: inspection.get-theme-color($theme, accent);
26
+ $warn: inspection.get-theme-color($theme, warn);
27
+ $background: inspection.get-theme-color($theme, background, background);
28
+ $secondary-text: inspection.get-theme-color($theme, foreground, secondary-text);
31
29
 
32
30
  // NOTE(traviskaufman): While the spec calls for translucent blacks/whites for disabled colors,
33
31
  // this does not work well with elements layered on top of one another. To get around this we
@@ -74,25 +72,20 @@
74
72
  }
75
73
  }
76
74
 
77
- @mixin typography($config-or-theme) {}
75
+ @mixin typography($theme) {}
78
76
 
79
- @mixin _density($config-or-theme) {}
77
+ @mixin _density($theme) {}
80
78
 
81
- @mixin theme($theme-or-color-config) {
82
- $theme: theming.private-legacy-get-theme($theme-or-color-config);
79
+ @mixin theme($theme) {
83
80
  @include theming.private-check-duplicate-theme-styles($theme, 'mat-pseudo-checkbox') {
84
- $color: theming.get-color-config($theme);
85
- $density: theming.get-density-config($theme);
86
- $typography: theming.get-typography-config($theme);
87
-
88
- @if $color != null {
89
- @include color($color);
81
+ @if inspection.theme-has($theme, color) {
82
+ @include color($theme);
90
83
  }
91
- @if $density != null {
92
- @include _density($density);
84
+ @if inspection.theme-has($theme, density) {
85
+ @include _density($theme);
93
86
  }
94
- @if $typography != null {
95
- @include typography($typography);
87
+ @if inspection.theme-has($theme, typography) {
88
+ @include typography($theme);
96
89
  }
97
90
  }
98
91
  }
@@ -1,9 +1,9 @@
1
1
  @use 'sass:map';
2
2
  @use './elevation';
3
+ @use '../theming/inspection';
3
4
 
4
- @mixin private-theme-elevation($zValue, $config) {
5
- $foreground: map.get($config, foreground);
6
- $elevation-color: map.get($foreground, elevation);
5
+ @mixin private-theme-elevation($zValue, $theme) {
6
+ $elevation-color: inspection.get-theme-color($theme, foreground, elevation);
7
7
  $elevation-color-or-default: if($elevation-color == null, elevation.$color, $elevation-color);
8
8
 
9
9
  @include elevation.elevation($zValue, $elevation-color-or-default);
@@ -1,3 +1,4 @@
1
+ @use 'sass:color';
1
2
  @use 'sass:map';
2
3
  @use 'sass:meta';
3
4
 
@@ -47,3 +48,9 @@
47
48
  @function coerce-to-list($value) {
48
49
  @return if(meta.type-of($value) != 'list', ($value,), $value);
49
50
  }
51
+
52
+ /// A version of the Sass `color.change` function that is safe ot use with CSS variables.
53
+ @function safe-color-change($color, $args...) {
54
+ $args: meta.keywords($args);
55
+ @return if(meta.type-of($color) == 'color', color.change($color, $args...), $color);
56
+ }
@@ -1,8 +1,7 @@
1
- // This file contains functions used to inspect Angular Material theme objects.
2
-
3
1
  @use 'sass:list';
4
2
  @use 'sass:map';
5
3
  @use '../style/validation';
4
+ @use './m2-inspection';
6
5
 
7
6
  $_internals: _mat-theming-internals-do-not-access;
8
7
 
@@ -48,15 +47,19 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac
48
47
  /// @param {Map} $theme The theme
49
48
  /// @return {String} The type of theme (either `light` or `dark`).
50
49
  @function get-theme-type($theme) {
51
- $err: _validate-theme-object($theme);
52
- @if $err {
53
- // TODO(mmalerba): implement for old style theme objects.
54
- @error #{'get-theme-type does not support legacy theme objects.'};
50
+ $version: get-theme-version($theme);
51
+ @if $version == 0 {
52
+ @return m2-inspection.get-theme-type($theme);
55
53
  }
56
- @if not theme-has($theme, color) {
57
- @error 'Color information is not available on this theme.';
54
+ @else if $version == 1 {
55
+ @if not theme-has($theme, color) {
56
+ @error 'Color information is not available on this theme.';
57
+ }
58
+ @return map.get($theme, $_internals, theme-type) or light;
59
+ }
60
+ @else {
61
+ @error #{'Unrecognized theme version:'} $version;
58
62
  }
59
- @return map.get($theme, $_internals, theme-type) or light;
60
63
  }
61
64
 
62
65
  /// Gets a color from a theme object. This function can take 2 or 3 arguments. If 2 arguments are
@@ -70,14 +73,26 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac
70
73
  /// interpreted as a palette name).
71
74
  /// @return {Color} The requested theme color.
72
75
  @function get-theme-color($theme, $args...) {
76
+ $version: get-theme-version($theme);
73
77
  $args-count: list.length($args);
74
- @if $args-count == 1 {
75
- @return _get-theme-role-color($theme, $args...);
78
+ @if $args-count != 1 and $args-count != 2 {
79
+ @error #{'Expected 2 or 3 arguments. Got:'} $args-count + 1;
76
80
  }
77
- @else if $args-count == 2 {
78
- @return _get-theme-palette-color($theme, $args...);
81
+
82
+ @if $version == 0 {
83
+ @return m2-inspection.get-theme-color($theme, $args...);
84
+ }
85
+ @else if $version == 1 {
86
+ @if $args-count == 1 {
87
+ @return _get-theme-role-color($theme, $args...);
88
+ }
89
+ @else if $args-count == 2 {
90
+ @return _get-theme-palette-color($theme, $args...);
91
+ }
92
+ }
93
+ @else {
94
+ @error #{'Unrecognized theme version:'} $version;
79
95
  }
80
- @error #{'Expected 2 or 3 arguments. Got:'} $args-count + 1;
81
96
  }
82
97
 
83
98
  /// Gets a role color from a theme object.
@@ -136,45 +151,53 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac
136
151
  /// (font, font-family, font-size, font-weight, line-height, or letter-spacing).
137
152
  /// @return {*} The value of the requested font property.
138
153
  @function get-theme-typography($theme, $typescale, $property: font) {
139
- $err: _validate-theme-object($theme);
140
- @if $err {
141
- // TODO(mmalerba): implement for old style theme objects.
142
- @error #{'get-theme-typography does not support legacy theme objects.'};
143
- }
144
- @if not theme-has($theme, typography) {
145
- @error 'Typography information is not available on this theme.';
146
- }
147
- @if not list.index($_m3-typescales, $typescale) {
148
- @error #{'Valid typescales are: #{$_m3-typescales}. Got:'} $typescale;
149
- }
150
- @if not list.index($_typography-properties, $property) {
151
- @error #{'Valid typography properties are: #{$_typography-properties}. Got:'} $property;
152
- }
153
- $property-key: map.get((
154
- font: '',
155
- font-family: '-font',
156
- line-height: '-line-height',
157
- font-size: '-size',
158
- letter-spacing: '-tracking',
159
- font-weight: '-weight'
160
- ), $property);
161
- $token-name: '#{$typescale}#{$property-key}';
162
- @return map.get($theme, $_internals, typography-tokens, (mdc, typography), $token-name);
154
+ $version: get-theme-version($theme);
155
+ @if $version == 0 {
156
+ @return m2-inspection.get-theme-typography($theme, $typescale, $property);
157
+ }
158
+ @else if $version == 1 {
159
+ @if not theme-has($theme, typography) {
160
+ @error 'Typography information is not available on this theme.';
161
+ }
162
+ @if not list.index($_m3-typescales, $typescale) {
163
+ @error #{'Valid typescales are: #{$_m3-typescales}. Got:'} $typescale;
164
+ }
165
+ @if not list.index($_typography-properties, $property) {
166
+ @error #{'Valid typography properties are: #{$_typography-properties}. Got:'} $property;
167
+ }
168
+ $property-key: map.get((
169
+ font: '',
170
+ font-family: '-font',
171
+ line-height: '-line-height',
172
+ font-size: '-size',
173
+ letter-spacing: '-tracking',
174
+ font-weight: '-weight'
175
+ ), $property);
176
+ $token-name: '#{$typescale}#{$property-key}';
177
+ @return map.get($theme, $_internals, typography-tokens, (mdc, typography), $token-name);
178
+ }
179
+ @else {
180
+ @error #{'Unrecognized theme version:'} $version;
181
+ }
163
182
  }
164
183
 
165
184
  /// Gets the density scale from a theme object.
166
185
  /// @param {Map} $theme The theme
167
186
  /// @return {Number} The density scale.
168
187
  @function get-theme-density($theme) {
169
- $err: _validate-theme-object($theme);
170
- @if $err {
171
- // TODO(mmalerba): implement for old style theme objects.
172
- @error #{'get-theme-density does not support legacy theme objects.'};
188
+ $version: get-theme-version($theme);
189
+ @if $version == 0 {
190
+ @return m2-inspection.get-theme-density($theme);
173
191
  }
174
- @if not theme-has($theme, density) {
175
- @error 'Density information is not available on this theme.';
192
+ @else if $version == 1 {
193
+ @if not theme-has($theme, density) {
194
+ @error 'Density information is not available on this theme.';
195
+ }
196
+ @return map.get($theme, $_internals, density-scale);
197
+ }
198
+ @else {
199
+ @error #{'Unrecognized theme version:'} $version;
176
200
  }
177
- @return map.get($theme, $_internals, density-scale);
178
201
  }
179
202
 
180
203
  /// Checks whether the theme has information about given theming system.
@@ -182,26 +205,30 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac
182
205
  /// @param {String} $system The system to check
183
206
  /// @param {Boolean} Whether the theme has information about the system.
184
207
  @function theme-has($theme, $system) {
185
- $err: _validate-theme-object($theme);
186
- @if $err {
187
- // TODO(mmalerba): implement for old style theme objects.
188
- @error #{'get-theme-density does not support legacy theme objects.'};
189
- }
190
- @if $system == base {
191
- @return map.get($theme, $_internals, base-tokens) != null;
208
+ $version: get-theme-version($theme);
209
+ @if $version == 0 {
210
+ @return m2-inspection.theme-has($theme, $system);
192
211
  }
193
- @if $system == color {
194
- @return map.get($theme, $_internals, color-tokens) != null and
212
+ @else if $version == 1 {
213
+ @if $system == base {
214
+ @return map.get($theme, $_internals, base-tokens) != null;
215
+ }
216
+ @if $system == color {
217
+ @return map.get($theme, $_internals, color-tokens) != null and
195
218
  map.get($theme, $_internals, theme-type) != null and
196
219
  map.get($theme, $_internals, palettes) != null;
220
+ }
221
+ @if $system == typography {
222
+ @return map.get($theme, $_internals, typography-tokens) != null;
223
+ }
224
+ @if $system == density {
225
+ @return map.get($theme, $_internals, density-scale) != null;
226
+ }
227
+ @error 'Valid systems are: base, color, typography, density. Got:' $system;
197
228
  }
198
- @if $system == typography {
199
- @return map.get($theme, $_internals, typography-tokens) != null;
200
- }
201
- @if $system == density {
202
- @return map.get($theme, $_internals, density-scale) != null;
229
+ @else {
230
+ @error #{'Unrecognized theme version:'} $version;
203
231
  }
204
- @error 'Valid systems are: base, color, typography, density. Got:' $system;
205
232
  }
206
233
 
207
234
  /// Gets the set of tokens from the given theme, limited to those affected by the requested theming
@@ -0,0 +1,211 @@
1
+ @use 'sass:list';
2
+ @use 'sass:map';
3
+ @use 'sass:meta';
4
+ @use './theming';
5
+ @use '../typography/property-getters' as typography-getters;
6
+ @use '../typography/versioning' as typography-versioning;
7
+
8
+ /// Key used to access the Angular Material theme internals.
9
+ $_internals: _mat-theming-internals-do-not-access;
10
+
11
+ /// Keys that indicate a config object is a color config.
12
+ $_color-keys: (
13
+ primary,
14
+ accent,
15
+ warn,
16
+ foreground,
17
+ background,
18
+ is-dark,
19
+ color, /* included for themes that incorrectly nest the color config: (color: (color: (....))) */
20
+ );
21
+
22
+ /// Keys that indicate a config object is a typography config.
23
+ $_typography-keys: (
24
+ headline-1,
25
+ headline-2,
26
+ headline-3,
27
+ headline-4,
28
+ headline-5,
29
+ headline-6,
30
+ subtitle-1,
31
+ font-famiy,
32
+ subtitle-2,
33
+ body-1,
34
+ body-2,
35
+ button,
36
+ caption,
37
+ overline,
38
+ );
39
+
40
+ /// The CSS typography properties supported by the inspection API.
41
+ $_typography-properties: (font, font-family, line-height, font-size, letter-spacing, font-weight);
42
+
43
+ /// Gets the m2-config from the theme.
44
+ @function _get-m2-config($theme) {
45
+ // It is possible for a user to pass a "density theme" that is just a number.
46
+ @if meta.type-of($theme) != 'map' {
47
+ @return $theme;
48
+ }
49
+ $internal: map.get($theme, $_internals, m2-config);
50
+ $theme: map.remove($theme, $_internals);
51
+ @return if(_is-error-theme($theme), $internal, $theme);
52
+ }
53
+
54
+ /// Checks whether the given theme contains error values.
55
+ /// @param {*} $theme The theme to check.
56
+ /// @return {Boolean} true if the theme contains error values, else false.
57
+ @function _is-error-theme($theme) {
58
+ @if meta.type-of($theme) != 'map' {
59
+ @return false;
60
+ }
61
+ @if map.get($theme, ERROR) {
62
+ @return true;
63
+ }
64
+ @return _is-error-theme(list.nth(map.values($theme), 1));
65
+ }
66
+
67
+ /// Checks whether the given theme object has any of the given keys.
68
+ /// @param {Map} $theme The theme to check
69
+ /// @param {List} $keys The keys to check for
70
+ /// @return {Boolean} Whether the theme has any of the given keys.
71
+ @function _has-any-key($theme, $keys) {
72
+ @each $key in $keys {
73
+ @if map.has-key($theme, $key) {
74
+ @return true;
75
+ }
76
+ }
77
+ @return false;
78
+ }
79
+
80
+ /// Checks whether the given theme is a density scale value.
81
+ /// @param {*} $theme The theme to check.
82
+ /// @return {Boolean} true if the theme is a density scale value, else false.
83
+ @function _is-density-value($theme) {
84
+ @return $theme == minimum or $theme == maximum or meta.type-of($theme) == 'number';
85
+ }
86
+
87
+ /// Gets the type of theme represented by a theme object (light or dark).
88
+ /// @param {Map} $theme The theme
89
+ /// @return {String} The type of theme (either `light` or `dark`).
90
+ @function get-theme-type($theme) {
91
+ $theme: _get-m2-config($theme);
92
+ @if not theme-has($theme, color) {
93
+ @error 'Color information is not available on this theme.';
94
+ }
95
+ $colors: theming.get-color-config($theme);
96
+ // Some apps seem to have mistakenly created nested color themes that somehow work with our old
97
+ // theme normalization logic. This check allows those apps to keep working.
98
+ @if theme-has($colors, color) {
99
+ $colors: theming.get-color-config($colors);
100
+ }
101
+ @return if(map.get($colors, is-dark), dark, light);
102
+ }
103
+
104
+ /// Gets a color from a theme object. This function can take 2 or 3 arguments. If 2 arguments are
105
+ /// passed, the second argument is treated as the name of a color role. If 3 arguments are passed,
106
+ /// the second argument is treated as the name of a color palette (primary, secondary, etc.) and the
107
+ /// third is treated as the palette hue (10, 50, etc.)
108
+ /// @param {Map} $theme The theme
109
+ /// @param {String} $palette-name The name of a color palette.
110
+ /// @param {Number} $hue The palette hue to get (passing this argument means the second argument is
111
+ /// interpreted as a palette name).
112
+ /// @return {Color} The requested theme color.
113
+ @function get-theme-color($theme, $palette-name, $args...) {
114
+ $theme: _get-m2-config($theme);
115
+ @if not theme-has($theme, color) {
116
+ @error 'Color information is not available on this theme.';
117
+ }
118
+ $colors: theming.get-color-config($theme);
119
+ // Some apps seem to have mistakenly created nested color themes that somehow work with our old
120
+ // theme normalization logic. This check allows those apps to keep working.
121
+ @if theme-has($colors, color) {
122
+ $colors: theming.get-color-config($colors);
123
+ }
124
+ $palette: map.get($colors, $palette-name);
125
+ @if not $palette {
126
+ @error 'Unrecognized palette name:' $palette-name;
127
+ }
128
+ @return theming.get-color-from-palette($palette, $args...);
129
+ }
130
+
131
+ /// Gets a typography value from a theme object.
132
+ /// @param {Map} $theme The theme
133
+ /// @param {String} $typescale The typescale name.
134
+ /// @param {String} $property The CSS font property to get
135
+ /// (font, font-family, font-size, font-weight, line-height, or letter-spacing).
136
+ /// @return {*} The value of the requested font property.
137
+ @function get-theme-typography($theme, $typescale, $property) {
138
+ $theme: _get-m2-config($theme);
139
+ @if not theme-has($theme, typography) {
140
+ @error 'Typography information is not available on this theme.';
141
+ }
142
+ $typography: typography-versioning.private-typography-to-2018-config(
143
+ theming.get-typography-config($theme));
144
+ @if $property == font {
145
+ $font-weight: typography-getters.font-weight($typography, $typescale);
146
+ $font-size: typography-getters.font-size($typography, $typescale);
147
+ $line-height: typography-getters.line-height($typography, $typescale);
148
+ $font-family: typography-getters.font-family($typography, $typescale);
149
+ @return ($font-weight list.slash($font-size, $line-height) $font-family);
150
+ }
151
+ @else if $property == font-family {
152
+ $result: typography-getters.font-family($typography, $typescale);
153
+ @return $result or typography-getters.font-family($typography);
154
+ }
155
+ @else if $property == font-size {
156
+ @return typography-getters.font-size($typography, $typescale);
157
+ }
158
+ @else if $property == font-weight {
159
+ @return typography-getters.font-weight($typography, $typescale);
160
+ }
161
+ @else if $property == line-height {
162
+ @return typography-getters.line-height($typography, $typescale);
163
+ }
164
+ @else if $property == letter-spacing {
165
+ @return typography-getters.letter-spacing($typography, $typescale);
166
+ }
167
+ @else {
168
+ @error #{'Valid typography properties are: #{$_typography-properties}. Got:'} $property;
169
+ }
170
+ }
171
+
172
+ /// Gets the density scale from a theme object.
173
+ /// @param {Map} $theme The theme
174
+ /// @return {Number} The density scale.
175
+ @function get-theme-density($theme) {
176
+ $theme: _get-m2-config($theme);
177
+ @if not theme-has($theme, density) {
178
+ @error 'Density information is not available on this theme.';
179
+ }
180
+ $scale: theming.get-density-config($theme);
181
+ @return theming.clamp-density($scale, -5);
182
+ }
183
+
184
+ /// Checks whether the theme has information about given theming system.
185
+ /// @param {Map} $theme The theme
186
+ /// @param {String} $system The system to check
187
+ /// @param {Boolean} Whether the theme has information about the system.
188
+ @function theme-has($theme, $system) {
189
+ $theme: _get-m2-config($theme);
190
+ @if $system == base {
191
+ @return true;
192
+ }
193
+ @if $system == color {
194
+ $color: theming.get-color-config($theme);
195
+ @return $color != null and _has-any-key($color, $_color-keys);
196
+ }
197
+ @if $system == typography {
198
+ $typography: theming.get-typography-config($theme);
199
+ @return $typography != null and _has-any-key($typography, $_typography-keys);
200
+ }
201
+ @if $system == density {
202
+ // Backwards compatibility for the case where an explicit, but invalid density is given
203
+ // (this was previously treated as density 0).
204
+ @if meta.type-of($theme) == 'map' and map.get($theme, density) {
205
+ @return true;
206
+ }
207
+ $density: theming.get-density-config($theme);
208
+ @return $density != null and _is-density-value($density);
209
+ }
210
+ @error 'Valid systems are: base, color, typography, density. Got:' $system;
211
+ }
@@ -5,6 +5,9 @@
5
5
  @use 'palette';
6
6
  @use '../density/private/compatibility';
7
7
 
8
+ // Whether to enable compatibility with legacy methods for accessing theme information.
9
+ $theme-legacy-inspection-api-compatibility: true !default;
10
+
8
11
  // Whether duplication warnings should be disabled. Warnings enabled by default.
9
12
  $theme-ignore-duplication-warnings: false !default;
10
13
 
@@ -184,10 +187,10 @@ $_emitted-base: () !default;
184
187
  // configuration for the `color` theming part.
185
188
  @if $accent != null {
186
189
  @warn $_legacy-theme-warning;
187
- @return private-create-backwards-compatibility-theme(_mat-validate-theme((
190
+ @return _internalize-theme(private-create-backwards-compatibility-theme(_mat-validate-theme((
188
191
  _is-legacy-theme: true,
189
192
  color: _mat-create-light-color-config($primary, $accent, $warn),
190
- )));
193
+ ))));
191
194
  }
192
195
  // If the map pattern is used (1), we just pass-through the configurations for individual
193
196
  // parts of the theming system, but update the `color` configuration if set. As explained
@@ -200,7 +203,8 @@ $_emitted-base: () !default;
200
203
  $warn: map.get($color-settings, warn);
201
204
  $result: map.merge($result, (color: _mat-create-light-color-config($primary, $accent, $warn)));
202
205
  }
203
- @return private-create-backwards-compatibility-theme(_mat-validate-theme($result));
206
+ @return _internalize-theme(
207
+ private-create-backwards-compatibility-theme(_mat-validate-theme($result)));
204
208
  }
205
209
 
206
210
  // TODO: Remove legacy API and rename below `$primary` to `$config`. Currently it cannot be renamed
@@ -225,10 +229,10 @@ $_emitted-base: () !default;
225
229
  // configuration for the `color` theming part.
226
230
  @if $accent != null {
227
231
  @warn $_legacy-theme-warning;
228
- @return private-create-backwards-compatibility-theme(_mat-validate-theme((
232
+ @return _internalize-theme(private-create-backwards-compatibility-theme(_mat-validate-theme((
229
233
  _is-legacy-theme: true,
230
234
  color: _mat-create-dark-color-config($primary, $accent, $warn),
231
- )));
235
+ ))));
232
236
  }
233
237
  // If the map pattern is used (1), we just pass-through the configurations for individual
234
238
  // parts of the theming system, but update the `color` configuration if set. As explained
@@ -241,7 +245,8 @@ $_emitted-base: () !default;
241
245
  $warn: map.get($color-settings, warn);
242
246
  $result: map.merge($result, (color: _mat-create-dark-color-config($primary, $accent, $warn)));
243
247
  }
244
- @return private-create-backwards-compatibility-theme(_mat-validate-theme($result));
248
+ @return _internalize-theme(
249
+ private-create-backwards-compatibility-theme(_mat-validate-theme($result)));
245
250
  }
246
251
 
247
252
  /// Gets the color configuration from the given theme or configuration.
@@ -595,3 +600,51 @@ $_internals: _mat-theming-internals-do-not-access;
595
600
  }
596
601
  @return $density-scale;
597
602
  }
603
+
604
+ /// Copies the given theme object and nests it within itself under a secret key and replaces the
605
+ /// original map keys with error values. This allows the inspection API which is aware of the secret
606
+ /// key to access the real values, but attempts to directly access the map will result in errors.
607
+ /// @param {Map} $theme The theme map.
608
+ @function _internalize-theme($theme) {
609
+ @if map.has-key($theme, $_internals) {
610
+ @return $theme;
611
+ }
612
+ $internalized-theme: (
613
+ $_internals: (
614
+ theme-version: 0,
615
+ m2-config: $theme
616
+ )
617
+ );
618
+ @if ($theme-legacy-inspection-api-compatibility) {
619
+ @return map.merge($theme, $internalized-theme);
620
+ }
621
+ $error-theme:
622
+ _replace-values-with-errors($theme, 'Theme may only be accessed via theme inspection API');
623
+ @return map.merge($error-theme, $internalized-theme);
624
+ }
625
+
626
+ /// Replaces concrete CSS values with errors in a theme object.
627
+ /// Errors are represented as a map `(ERROR: <message>)`. Because maps are not valid CSS values,
628
+ /// the Sass will not compile if the user tries to use any of the error theme values in their CSS.
629
+ /// Users will see a message about `(ERROR: <message>)` not being a valid CSS value. Using the
630
+ /// message, that winds up getting shown, we can help explain to users why they're getting the
631
+ /// error.
632
+ /// @param {*} $value The theme value to replace with errors.
633
+ /// @param {String} $message The error message to sow users.
634
+ /// @return {Map} A version of $value where concrete CSS values have been replaced with errors
635
+ @function _replace-values-with-errors($value, $message) {
636
+ $value-type: meta.type-of($value);
637
+ @if $value-type == 'map' {
638
+ @each $k, $v in $value {
639
+ $value: map.set($value, $k, _replace-values-with-errors($v, $message));
640
+ }
641
+ @return $value;
642
+ }
643
+ @else if $value-type == 'list' and list.length($value) > 0 {
644
+ @for $i from 1 through list.length() {
645
+ $value: list.set-nth($value, $i, _replace-values-with-errors(list.nth($value, $i), $message));
646
+ }
647
+ @return $value;
648
+ }
649
+ @return (ERROR: $message);
650
+ }