Skip to content

Commit 81e08d4

Browse files
committed
refactor(material/stepper): switch to tokens API (#27386)
Reworks the stepper to use the tokens theming API. (cherry picked from commit 2683084)
1 parent 35f9260 commit 81e08d4

File tree

5 files changed

+327
-159
lines changed

5 files changed

+327
-159
lines changed

src/material/core/tokens/_token-utils.scss

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ $_component-prefix: null;
8484
}
8585
}
8686

87+
// Returns the name of a token including the current prefix. Intended to be used in calculations
88+
// involving tokens. `create-token-slot` should be used when outputting tokens.
89+
@function get-token-variable($token) {
90+
@if $_component-prefix == null or $_tokens == null {
91+
@error '`get-token-variable` must be used within `use-tokens`';
92+
}
93+
@if not map.has-key($_tokens, $token) {
94+
@error 'Token #{$token} does not exist. Configured tokens are: #{map.keys($_tokens)}';
95+
}
96+
97+
@return mdc-custom-properties.create-varname('#{$_component-prefix}-#{$token}');
98+
}
99+
87100
@mixin create-token-values($prefix, $tokens) {
88101
@include _configure-token-prefix($prefix...) {
89102
@include mdc-keys.declare-custom-properties($tokens, $_component-prefix);
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
@use 'sass:map';
2+
@use '../../token-utils';
3+
@use '../../../theming/theming';
4+
@use '../../../typography/typography-utils';
5+
@use '../../../style/sass-utils';
6+
7+
// The prefix used to generate the fully qualified name for tokens in this file.
8+
$prefix: (mat, stepper);
9+
10+
// Tokens that can't be configured through Angular Material's current theming API,
11+
// but may be in a future version of the theming API.
12+
@function get-unthemable-tokens() {
13+
@return ();
14+
}
15+
16+
// Tokens that can be configured through Angular Material's color theming API.
17+
@function get-color-tokens($config) {
18+
$foreground: map.get($config, foreground);
19+
$background: map.get($config, background);
20+
$primary: map.get($config, primary);
21+
$warn: map.get($config, warn);
22+
23+
@return map.merge(private-get-color-palette-color-tokens($primary), (
24+
// Background for stepper container.
25+
container-color: theming.get-color-from-palette($background, card),
26+
// Color of the line indicator connecting the steps.
27+
line-color: theming.get-color-from-palette($foreground, divider),
28+
// Background color of the header while hovered.
29+
header-hover-state-layer-color: theming.get-color-from-palette($background, hover),
30+
// Background color of the header while focused.
31+
header-focus-state-layer-color: theming.get-color-from-palette($background, hover),
32+
// Color of the text inside the step header.
33+
header-label-text-color: theming.get-color-from-palette($foreground, secondary-text),
34+
// Color for the "optional" label in the step header.
35+
header-optional-label-text-color: theming.get-color-from-palette($foreground, secondary-text),
36+
// Color of the header text when a step is selected.
37+
header-selected-state-label-text-color: theming.get-color-from-palette($foreground, text),
38+
// Color of the header text when a step is in an error state.
39+
header-error-state-label-text-color: theming.get-color-from-palette($warn, text),
40+
// Background color of the header icon.
41+
header-icon-background-color: theming.get-color-from-palette($foreground, secondary-text),
42+
// Foreground color of the header icon in the error state.
43+
header-error-state-icon-foreground-color: theming.get-color-from-palette($warn, text),
44+
// Background color of the header icon in the error state.
45+
header-error-state-icon-background-color: transparent,
46+
));
47+
}
48+
49+
// Tokens that can be configured through Angular Material's typography theming API.
50+
@function get-typography-tokens($config) {
51+
@return (
52+
// Font family of the entire stepper.
53+
container-text-font: typography-utils.font-family($config),
54+
// Font family of the text inside the step header.
55+
header-label-text-font: typography-utils.font-family($config, body-1) or
56+
typography-utils.font-family($config),
57+
// Size of the text inside the step header.
58+
header-label-text-size: typography-utils.font-size($config, body-1),
59+
// Weight of the text inside the step header.
60+
header-label-text-weight: typography-utils.font-weight($config, body-1),
61+
// Color of the header text when a step is in an error state.
62+
header-error-state-label-text-size: typography-utils.font-size($config, body-2),
63+
// Size of the header text in the selected state.
64+
header-selected-state-label-text-size: typography-utils.font-size($config, body-2),
65+
// Weight of the header text in the selected state.
66+
header-selected-state-label-text-weight: typography-utils.font-weight($config, body-2),
67+
);
68+
}
69+
70+
// Tokens that can be configured through Angular Material's density theming API.
71+
@function get-density-tokens($config) {
72+
$scale: theming.clamp-density($config, -4);
73+
$height-config: (
74+
0: 72px,
75+
-1: 68px,
76+
-2: 64px,
77+
-3: 60px,
78+
-4: 42px,
79+
);
80+
81+
@return (
82+
header-height: map.get($height-config, $scale),
83+
);
84+
}
85+
86+
// Generates the tokens used to theme the stepper based on a palette.
87+
@function private-get-color-palette-color-tokens($palette) {
88+
$active-state-foreground: theming.get-color-from-palette($palette, default-contrast);
89+
$active-state-background: theming.get-color-from-palette($palette);
90+
91+
@return (
92+
// Foreground color of the header icon.
93+
header-icon-foreground-color: theming.get-color-from-palette($palette, default-contrast),
94+
// Background color of the header icon in the selected state.
95+
header-selected-state-icon-background-color: $active-state-background,
96+
// Foreground color of the header icon in the selected state.
97+
header-selected-state-icon-foreground-color: $active-state-foreground,
98+
// Background color of the header icon in the selected state.
99+
header-done-state-icon-background-color: $active-state-background,
100+
// Foreground color of the header icon in the selected state.
101+
header-done-state-icon-foreground-color: $active-state-foreground,
102+
// Background color of the header icon in the editing state.
103+
header-edit-state-icon-background-color: $active-state-background,
104+
// Foreground color of the header icon in the editing state.
105+
header-edit-state-icon-foreground-color: $active-state-foreground,
106+
);
107+
}
108+
109+
// Combines the tokens generated by the above functions into a single map with placeholder values.
110+
// This is used to create token slots.
111+
@function get-token-slots() {
112+
@return sass-utils.deep-merge-all(
113+
get-unthemable-tokens(),
114+
get-color-tokens(token-utils.$placeholder-color-config),
115+
get-typography-tokens(token-utils.$placeholder-typography-config),
116+
get-density-tokens(token-utils.$placeholder-density-config)
117+
);
118+
}

src/material/stepper/_stepper-theme.scss

Lines changed: 18 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -2,142 +2,38 @@
22
@use 'sass:math';
33
@use '../core/theming/theming';
44
@use '../core/typography/typography';
5-
@use '../core/typography/typography-utils';
65
@use '../core/density/private/compatibility';
6+
@use '../core/style/sass-utils';
7+
@use '../core/tokens/token-utils';
8+
@use '../core/tokens/m2/mat/stepper' as tokens-mat-stepper;
79
@use './stepper-variables';
810

911
@mixin color($config-or-theme) {
1012
$config: theming.get-color-config($config-or-theme);
11-
$foreground: map.get($config, foreground);
12-
$background: map.get($config, background);
13-
$primary: map.get($config, primary);
14-
$accent: map.get($config, accent);
15-
$warn: map.get($config, warn);
1613

17-
.mat-step-header {
18-
&.cdk-keyboard-focused,
19-
&.cdk-program-focused,
20-
&:hover:not([aria-disabled]),
21-
&:hover[aria-disabled='false'] {
22-
background-color: theming.get-color-from-palette($background, hover);
23-
}
24-
25-
&:hover[aria-disabled='true'] {
26-
cursor: default;
27-
}
14+
@include sass-utils.current-selector-or-root() {
15+
@include token-utils.create-token-values(tokens-mat-stepper.$prefix,
16+
tokens-mat-stepper.get-color-tokens($config));
2817

29-
// On touch devices the :hover state will linger on the element after a tap.
30-
// Reset it via `@media` after the declaration, because the media query isn't
31-
// supported by all browsers yet.
32-
@media (hover: none) {
33-
&:hover {
34-
background: none;
35-
}
18+
.mat-step-header.mat-accent {
19+
@include token-utils.create-token-values(tokens-mat-stepper.$prefix,
20+
tokens-mat-stepper.private-get-color-palette-color-tokens(map.get($config, accent)));
3621
}
3722

38-
.mat-step-label,
39-
.mat-step-optional {
40-
// TODO(josephperrott): Update to using a corrected disabled-text contrast
41-
// instead of secondary-text.
42-
color: theming.get-color-from-palette($foreground, secondary-text);
23+
.mat-step-header.mat-warn {
24+
@include token-utils.create-token-values(tokens-mat-stepper.$prefix,
25+
tokens-mat-stepper.private-get-color-palette-color-tokens(map.get($config, warn)));
4326
}
44-
45-
.mat-step-icon {
46-
// TODO(josephperrott): Update to using a corrected disabled-text contrast
47-
// instead of secondary-text.
48-
background-color: theming.get-color-from-palette($foreground, secondary-text);
49-
color: theming.get-color-from-palette($primary, default-contrast);
50-
}
51-
52-
.mat-step-icon-selected,
53-
.mat-step-icon-state-done,
54-
.mat-step-icon-state-edit {
55-
background-color: theming.get-color-from-palette($primary);
56-
color: theming.get-color-from-palette($primary, default-contrast);
57-
}
58-
59-
&.mat-accent {
60-
.mat-step-icon {
61-
color: theming.get-color-from-palette($accent, default-contrast);
62-
}
63-
64-
.mat-step-icon-selected,
65-
.mat-step-icon-state-done,
66-
.mat-step-icon-state-edit {
67-
background-color: theming.get-color-from-palette($accent);
68-
color: theming.get-color-from-palette($accent, default-contrast);
69-
}
70-
}
71-
72-
&.mat-warn {
73-
.mat-step-icon {
74-
color: theming.get-color-from-palette($warn, default-contrast);
75-
}
76-
77-
.mat-step-icon-selected,
78-
.mat-step-icon-state-done,
79-
.mat-step-icon-state-edit {
80-
background-color: theming.get-color-from-palette($warn);
81-
color: theming.get-color-from-palette($warn, default-contrast);
82-
}
83-
}
84-
85-
.mat-step-icon-state-error {
86-
background-color: transparent;
87-
color: theming.get-color-from-palette($warn, text);
88-
}
89-
90-
.mat-step-label.mat-step-label-active {
91-
color: theming.get-color-from-palette($foreground, text);
92-
}
93-
94-
.mat-step-label.mat-step-label-error {
95-
color: theming.get-color-from-palette($warn, text);
96-
}
97-
}
98-
99-
.mat-stepper-horizontal, .mat-stepper-vertical {
100-
background-color: theming.get-color-from-palette($background, card);
101-
}
102-
103-
.mat-stepper-vertical-line::before {
104-
border-left-color: theming.get-color-from-palette($foreground, divider);
105-
}
106-
107-
.mat-horizontal-stepper-header::before,
108-
.mat-horizontal-stepper-header::after,
109-
.mat-stepper-horizontal-line {
110-
border-top-color: theming.get-color-from-palette($foreground, divider);
11127
}
11228
}
11329

11430
@mixin typography($config-or-theme) {
11531
$config: typography.private-typography-to-2014-config(
11632
theming.get-typography-config($config-or-theme));
117-
.mat-stepper-vertical, .mat-stepper-horizontal {
118-
font-family: typography-utils.font-family($config);
119-
}
120-
121-
.mat-step-label {
122-
font: {
123-
size: typography-utils.font-size($config, body-1);
124-
weight: typography-utils.font-weight($config, body-1);
125-
};
126-
}
127-
128-
.mat-step-sub-label-error {
129-
font-weight: normal;
130-
}
131-
132-
.mat-step-label-error {
133-
font-size: typography-utils.font-size($config, body-2);
134-
}
13533

136-
.mat-step-label-selected {
137-
font: {
138-
size: typography-utils.font-size($config, body-2);
139-
weight: typography-utils.font-weight($config, body-2);
140-
};
34+
@include sass-utils.current-selector-or-root() {
35+
@include token-utils.create-token-values(tokens-mat-stepper.$prefix,
36+
tokens-mat-stepper.get-typography-tokens($config));
14137
}
14238
}
14339

@@ -147,34 +43,9 @@
14743
$density-scale, height);
14844
$vertical-padding: math.div($height - stepper-variables.$label-header-height, 2);
14945

150-
@include compatibility.private-density-legacy-compatibility() {
151-
.mat-horizontal-stepper-header {
152-
height: $height;
153-
}
154-
155-
.mat-stepper-label-position-bottom .mat-horizontal-stepper-header,
156-
.mat-vertical-stepper-header {
157-
padding: $vertical-padding stepper-variables.$side-gap;
158-
}
159-
160-
// Ensures that the vertical lines for the step content exceed into the step
161-
// headers with a given distance (`$mat-stepper-line-gap`) to the step icon.
162-
.mat-stepper-vertical-line::before {
163-
top: stepper-variables.$line-gap - $vertical-padding;
164-
bottom: stepper-variables.$line-gap - $vertical-padding;
165-
}
166-
167-
// Ensures that the horizontal lines for the step header are centered vertically.
168-
.mat-stepper-label-position-bottom .mat-horizontal-stepper-header {
169-
&::after, &::before {
170-
top: $vertical-padding + math.div(stepper-variables.$label-header-height, 2);
171-
}
172-
}
173-
174-
// Ensures that the horizontal line for the step content is aligned centered vertically.
175-
.mat-stepper-label-position-bottom .mat-stepper-horizontal-line {
176-
top: $vertical-padding + math.div(stepper-variables.$label-header-height, 2);
177-
}
46+
@include sass-utils.current-selector-or-root() {
47+
@include token-utils.create-token-values(tokens-mat-stepper.$prefix,
48+
tokens-mat-stepper.get-density-tokens($density-scale));
17849
}
17950
}
18051

0 commit comments

Comments
 (0)