Skip to content

Commit d7bea15

Browse files
committed
refactor(material/badge): switch to tokens theming API
Reworks the badge to use the tokens-based theming API.
1 parent 89ade6a commit d7bea15

File tree

2 files changed

+157
-118
lines changed

2 files changed

+157
-118
lines changed

src/material/badge/_badge-theme.scss

Lines changed: 79 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
// This contains all of the styles for the badge
2-
// rather than just the color/theme because of
3-
// no style sheet support for directives.
41
@use 'sass:color';
52
@use 'sass:map';
6-
@use 'sass:meta';
73
@use 'sass:math';
84
@use '@angular/cdk';
95

106
@use '../core/theming/theming';
117
@use '../core/typography/typography';
12-
@use '../core/typography/typography-utils';
8+
@use '../core/tokens/m2/mat/badge' as tokens-mat-badge;
9+
@use '../core/tokens/token-utils';
10+
@use '../core/style/sass-utils';
1311

12+
// TODO(crisbeto): some of these variables aren't used anymore and should be deleted.
1413
$font-size: 12px;
1514
$font-weight: 600;
1615
$default-size: 22px !default;
@@ -19,78 +18,65 @@ $large-size: $default-size + 6;
1918
$_badge-structure-emitted: false !default;
2019

2120
// Mixin for building offset given different sizes
22-
@mixin _badge-size($size) {
21+
@mixin _badge-size($size, $font-size-token) {
2322
// This mixin isn't used in the context of a theme so we can disable the ampersand check.
2423
// stylelint-disable material/no-ampersand-beyond-selector-start
2524
.mat-badge-content {
2625
width: $size;
2726
height: $size;
2827
line-height: $size;
29-
}
3028

31-
&.mat-badge-above {
32-
.mat-badge-content {
33-
top: math.div(-$size, 2);
29+
@if ($font-size-token) {
30+
@include token-utils.use-tokens(tokens-mat-badge.$prefix,
31+
tokens-mat-badge.get-token-slots()) {
32+
@include token-utils.create-token-slot(font-size, $font-size-token);
33+
}
3434
}
3535
}
3636

37-
&.mat-badge-below {
38-
.mat-badge-content {
39-
bottom: math.div(-$size, 2);
40-
}
37+
&.mat-badge-above .mat-badge-content {
38+
top: math.div(-$size, 2);
4139
}
4240

43-
&.mat-badge-before {
44-
.mat-badge-content {
45-
left: -$size;
46-
}
41+
&.mat-badge-below .mat-badge-content {
42+
bottom: math.div(-$size, 2);
4743
}
4844

49-
[dir='rtl'] &.mat-badge-before {
50-
.mat-badge-content {
51-
left: auto;
52-
right: -$size;
53-
}
45+
&.mat-badge-before .mat-badge-content {
46+
left: -$size;
5447
}
5548

56-
&.mat-badge-after {
57-
.mat-badge-content {
58-
right: -$size;
59-
}
49+
[dir='rtl'] &.mat-badge-before .mat-badge-content {
50+
left: auto;
51+
right: -$size;
6052
}
6153

62-
[dir='rtl'] &.mat-badge-after {
63-
.mat-badge-content {
64-
right: auto;
65-
left: -$size;
66-
}
54+
&.mat-badge-after .mat-badge-content {
55+
right: -$size;
56+
}
57+
58+
[dir='rtl'] &.mat-badge-after .mat-badge-content {
59+
right: auto;
60+
left: -$size;
6761
}
6862

6963
&.mat-badge-overlap {
70-
&.mat-badge-before {
71-
.mat-badge-content {
72-
left: math.div(-$size, 2);
73-
}
64+
&.mat-badge-before .mat-badge-content {
65+
left: math.div(-$size, 2);
7466
}
7567

76-
[dir='rtl'] &.mat-badge-before {
77-
.mat-badge-content {
78-
left: auto;
79-
right: math.div(-$size, 2);
80-
}
68+
[dir='rtl'] &.mat-badge-before .mat-badge-content {
69+
left: auto;
70+
right: math.div(-$size, 2);
8171
}
8272

83-
&.mat-badge-after {
84-
.mat-badge-content {
85-
right: math.div(-$size, 2);
86-
}
73+
&.mat-badge-after .mat-badge-content {
74+
right: math.div(-$size, 2);
8775
}
8876

89-
[dir='rtl'] &.mat-badge-after {
90-
.mat-badge-content {
91-
right: auto;
92-
left: math.div(-$size, 2);
93-
}
77+
[dir='rtl'] &.mat-badge-after .mat-badge-content {
78+
right: auto;
79+
left: math.div(-$size, 2);
9480
}
9581
}
9682
// stylelint-enable
@@ -101,19 +87,13 @@ $_badge-structure-emitted: false !default;
10187
@mixin _badge-structure {
10288
.mat-badge {
10389
position: relative;
104-
}
105-
106-
// The badge should make sure its host is overflow visible so that the badge content
107-
// can be rendered outside of the element. Some components such as <mat-icon> explicitly
108-
// style `overflow: hidden` so this requires extra specificity so that it does not
109-
// depend on style load order.
110-
.mat-badge.mat-badge {
111-
overflow: visible;
112-
}
11390

114-
.mat-badge-hidden {
115-
.mat-badge-content {
116-
display: none;
91+
// The badge should make sure its host is overflow visible so that the badge content
92+
// can be rendered outside of the element. Some components such as <mat-icon> explicitly
93+
// style `overflow: hidden` so this requires extra specificity so that it does not
94+
// depend on style load order.
95+
&.mat-badge {
96+
overflow: visible;
11797
}
11898
}
11999

@@ -128,6 +108,30 @@ $_badge-structure-emitted: false !default;
128108
white-space: nowrap;
129109
text-overflow: ellipsis;
130110
pointer-events: none;
111+
112+
@include token-utils.use-tokens(tokens-mat-badge.$prefix, tokens-mat-badge.get-token-slots()) {
113+
@include token-utils.create-token-slot(background-color, background-color);
114+
@include token-utils.create-token-slot(color, text-color);
115+
@include token-utils.create-token-slot(font-family, text-font);
116+
@include token-utils.create-token-slot(font-size, text-size);
117+
@include token-utils.create-token-slot(font-weight, text-weight);
118+
}
119+
120+
@include cdk.high-contrast(active, off) {
121+
outline: solid 1px;
122+
border-radius: 0;
123+
}
124+
}
125+
126+
.mat-badge-disabled .mat-badge-content {
127+
@include token-utils.use-tokens(tokens-mat-badge.$prefix, tokens-mat-badge.get-token-slots()) {
128+
@include token-utils.create-token-slot(background-color, disabled-state-background-color);
129+
@include token-utils.create-token-slot(color, disabled-state-text-color);
130+
}
131+
}
132+
133+
.mat-badge-hidden .mat-badge-content {
134+
display: none;
131135
}
132136

133137
.ng-animate-disabled .mat-badge-content,
@@ -143,89 +147,46 @@ $_badge-structure-emitted: false !default;
143147
}
144148

145149
.mat-badge-small {
146-
@include _badge-size($small-size);
150+
@include _badge-size($small-size, small-size-text-size);
147151
}
148152

149153
.mat-badge-medium {
150-
@include _badge-size($default-size);
154+
@include _badge-size($default-size, null);
151155
}
152156

153157
.mat-badge-large {
154-
@include _badge-size($large-size);
158+
@include _badge-size($large-size, large-size-text-size);
155159
}
156160
}
157161

158162
@mixin color($config-or-theme) {
159163
$config: theming.get-color-config($config-or-theme);
160164
$accent: map.get($config, accent);
161165
$warn: map.get($config, warn);
162-
$primary: map.get($config, primary);
163-
$background: map.get($config, background);
164-
$foreground: map.get($config, foreground);
165166

166-
.mat-badge-content {
167-
color: theming.get-color-from-palette($primary, default-contrast);
168-
background: theming.get-color-from-palette($primary);
169-
170-
@include cdk.high-contrast(active, off) {
171-
outline: solid 1px;
172-
border-radius: 0;
173-
}
167+
@include sass-utils.current-selector-or-root() {
168+
@include token-utils.create-token-values(tokens-mat-badge.$prefix,
169+
tokens-mat-badge.get-color-tokens($config));
174170
}
175171

176172
.mat-badge-accent {
177-
.mat-badge-content {
178-
background: theming.get-color-from-palette($accent);
179-
color: theming.get-color-from-palette($accent, default-contrast);
180-
}
173+
@include token-utils.create-token-values(tokens-mat-badge.$prefix,
174+
tokens-mat-badge.private-get-color-palette-color-tokens($accent));
181175
}
182176

183177
.mat-badge-warn {
184-
.mat-badge-content {
185-
color: theming.get-color-from-palette($warn, default-contrast);
186-
background: theming.get-color-from-palette($warn);
187-
}
188-
}
189-
190-
.mat-badge-disabled {
191-
.mat-badge-content {
192-
$app-background: theming.get-color-from-palette($background, 'background');
193-
$badge-color: theming.get-color-from-palette($foreground, disabled-button);
194-
195-
// The disabled color usually has some kind of opacity, but because the badge is overlayed
196-
// on top of something else, it won't look good if it's opaque. If it is a color *type*,
197-
// we convert it into a solid color by taking the opacity from the rgba value and using
198-
// the value to determine the percentage of the background to put into foreground when
199-
// mixing the colors together.
200-
@if (meta.type-of($badge-color) == color and meta.type-of($app-background) == color) {
201-
$badge-opacity: opacity($badge-color);
202-
background: color.mix($app-background, rgba($badge-color, 1), (1 - $badge-opacity) * 100%);
203-
}
204-
@else {
205-
background: $badge-color;
206-
}
207-
208-
color: theming.get-color-from-palette($foreground, disabled-text);
209-
}
178+
@include token-utils.create-token-values(tokens-mat-badge.$prefix,
179+
tokens-mat-badge.private-get-color-palette-color-tokens($warn));
210180
}
211181
}
212182

213183
@mixin typography($config-or-theme) {
214184
$config: typography.private-typography-to-2014-config(
215185
theming.get-typography-config($config-or-theme));
216-
.mat-badge-content {
217-
font-weight: $font-weight;
218-
font-size: $font-size;
219-
font-family: typography-utils.font-family($config);
220-
}
221-
222-
.mat-badge-small .mat-badge-content {
223-
// Set the font size to 75% of the original.
224-
font-size: $font-size * 0.75;
225-
}
226186

227-
.mat-badge-large .mat-badge-content {
228-
font-size: $font-size * 2;
187+
@include sass-utils.current-selector-or-root() {
188+
@include token-utils.create-token-values(tokens-mat-badge.$prefix,
189+
tokens-mat-badge.get-typography-tokens($config));
229190
}
230191
}
231192

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
@use 'sass:meta';
2+
@use 'sass:map';
3+
@use 'sass:color';
4+
@use '../../token-utils';
5+
@use '../../../typography/typography-utils';
6+
@use '../../../theming/theming';
7+
@use '../../../style/sass-utils';
8+
9+
// The prefix used to generate the fully qualified name for tokens in this file.
10+
$prefix: (mat, badge);
11+
12+
// Tokens that can't be configured through Angular Material's current theming API,
13+
// but may be in a future version of the theming API.
14+
@function get-unthemable-tokens() {
15+
@return ();
16+
}
17+
18+
// Tokens that can be configured through Angular Material's color theming API.
19+
@function get-color-tokens($config) {
20+
$foreground: map.get($config, foreground);
21+
$background: map.get($config, background);
22+
$primary-color-tokens: private-get-color-palette-color-tokens(map.get($config, primary));
23+
$app-background: theming.get-color-from-palette($background, 'background');
24+
$disabled-background: theming.get-color-from-palette($foreground, disabled-button);
25+
26+
// The disabled color usually has some kind of opacity, but because the badge is overlayed
27+
// on top of something else, it won't look good if it's opaque. If it is a color *type*,
28+
// we convert it into a solid color by taking the opacity from the rgba value and using
29+
// the value to determine the percentage of the background to put into foreground when
30+
// mixing the colors together.
31+
@if (meta.type-of($disabled-background) == color and meta.type-of($app-background) == color) {
32+
$badge-opacity: opacity($disabled-background);
33+
$disabled-background: color.mix($app-background,
34+
rgba($disabled-background, 1), (1 - $badge-opacity) * 100%);
35+
}
36+
37+
@return map.merge($primary-color-tokens, (
38+
disabled-state-background-color: $disabled-background,
39+
disabled-state-text-color: theming.get-color-from-palette($foreground, disabled-text),
40+
));
41+
}
42+
43+
// Generates the tokens used to theme the badge based on a palette.
44+
@function private-get-color-palette-color-tokens($palette) {
45+
@return (
46+
background-color: theming.get-color-from-palette($palette),
47+
text-color: theming.get-color-from-palette($palette, default-contrast),
48+
);
49+
}
50+
51+
// Tokens that can be configured through Angular Material's typography theming API.
52+
@function get-typography-tokens($config) {
53+
$base-size: 12px;
54+
55+
@return (
56+
text-font: typography-utils.font-family($config),
57+
text-size: $base-size,
58+
text-weight: 600,
59+
small-size-text-size: $base-size * 0.75,
60+
large-size-text-size: $base-size * 2,
61+
);
62+
}
63+
64+
// Tokens that can be configured through Angular Material's density theming API.
65+
@function get-density-tokens($config) {
66+
@return ();
67+
}
68+
69+
// Combines the tokens generated by the above functions into a single map with placeholder values.
70+
// This is used to create token slots.
71+
@function get-token-slots() {
72+
@return sass-utils.deep-merge-all(
73+
get-unthemable-tokens(),
74+
get-color-tokens(token-utils.$placeholder-color-config),
75+
get-typography-tokens(token-utils.$placeholder-typography-config),
76+
get-density-tokens(token-utils.$placeholder-density-config)
77+
);
78+
}

0 commit comments

Comments
 (0)