Skip to content

Commit 0c4f947

Browse files
authored
refactor(material/datepicker): switch to tokens API (#27503)
Reworks the datepicker to use tokens for theming.
1 parent 88f6648 commit 0c4f947

File tree

10 files changed

+463
-210
lines changed

10 files changed

+463
-210
lines changed

src/dev-app/datepicker/datepicker-demo.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ <h2>Range picker</h2>
215215
<mat-date-range-picker
216216
[touchUi]="touch"
217217
[disabled]="datepickerDisabled"
218+
[color]="color"
218219
#range1Picker>
219220
<mat-date-range-picker-actions *ngIf="showActions">
220221
<button mat-button matDateRangePickerCancel>Cancel</button>

src/material/core/theming/tests/theming-api.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,15 @@ describe('theming api', () => {
9898
)
9999
));
100100
101-
// Updates the "icon" foreground color to "canary".
101+
// Updates the "icon" foreground color to hotpink.
102102
$color: map-get($theme, color);
103103
$theme: map-merge($color,
104-
(foreground: map-merge(map-get($color, foreground), (icon: "canary"))));
104+
(foreground: map-merge(map-get($color, foreground), (icon: hotpink))));
105105
106106
@include angular-material-theme($theme);
107107
`);
108108

109-
expect(result).toContain(': "canary"');
109+
expect(result).toContain(': hotpink');
110110
});
111111

112112
it('should warn if default density styles are duplicated', () => {
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
@use 'sass:color';
2+
@use 'sass:map';
3+
@use 'sass:meta';
4+
@use 'sass:math';
5+
@use '../../token-utils';
6+
@use '../../../theming/theming';
7+
@use '../../../typography/typography-utils';
8+
@use '../../../style/sass-utils';
9+
10+
// The prefix used to generate the fully qualified name for tokens in this file.
11+
$prefix: (mat, datepicker);
12+
13+
$_selected-fade-amount: 0.6;
14+
$_today-fade-amount: 0.2;
15+
16+
// Utility that produces a range background color from a specific color.
17+
@function private-get-range-background-color($color) {
18+
@return rgba($color, 0.2);
19+
}
20+
21+
// Utility that produces the overlap selected color from an overlap color.
22+
@function private-get-default-overlap-selected-color($overlap-color) {
23+
@return color.adjust($overlap-color, $lightness: -30%);
24+
}
25+
26+
// Default range comparison color.
27+
$private-default-comparison-color: private-get-range-background-color(#f9ab00);
28+
29+
// Default range overlap color.
30+
$private-default-overlap-color: #a8dab5;
31+
32+
// Tokens that can't be configured through Angular Material's current theming API,
33+
// but may be in a future version of the theming API.
34+
@function get-unthemable-tokens() {
35+
@return ();
36+
}
37+
38+
// Tokens that can be configured through Angular Material's color theming API.
39+
@function get-color-tokens($config) {
40+
$foreground: map.get($config, foreground);
41+
$background: map.get($config, background);
42+
$primary: map.get($config, primary);
43+
$inactive-icon-color: theming.get-color-from-palette($foreground, icon);
44+
$text-color: theming.get-color-from-palette($foreground, text);
45+
$secondary-text-color: theming.get-color-from-palette($foreground, secondary-text);
46+
$disabled-text-color: theming.get-color-from-palette($foreground, disabled-text);
47+
$divider-color: theming.get-color-from-palette($foreground, divider);
48+
$hint-text-color: theming.get-color-from-palette($foreground, hint-text);
49+
$preview-outline-color: $divider-color;
50+
$today-disabled-outline-color: null;
51+
52+
$primary-color: theming.get-color-from-palette(map.get($config, primary));
53+
$range-tokens: get-range-color-tokens(private-get-range-background-color($primary-color));
54+
$calendar-tokens: private-get-calendar-color-palette-color-tokens($config, primary);
55+
$toggle-tokens: private-get-toggle-color-palette-color-tokens($config, primary);
56+
57+
// The divider color is set under the assumption that it'll be used
58+
// for a solid border, but because we're using a dashed border for the
59+
// preview range, we need to bump its opacity to ensure that it's visible.
60+
@if meta.type-of($preview-outline-color) == color {
61+
$preview-outline-opacity: math.min(opacity($preview-outline-color) * 2, 1);
62+
$preview-outline-color: rgba($preview-outline-color, $preview-outline-opacity);
63+
}
64+
65+
@if (meta.type-of($hint-text-color) == color) {
66+
$today-disabled-outline-color: color.adjust($hint-text-color, $alpha: -$_today-fade-amount);
67+
}
68+
@else {
69+
$today-disabled-outline-color: $disabled-text-color;
70+
}
71+
72+
@return sass-utils.merge-all($calendar-tokens, $toggle-tokens, $range-tokens, (
73+
toggle-icon-color: $inactive-icon-color,
74+
calendar-body-label-text-color: $secondary-text-color,
75+
calendar-period-button-icon-color: $inactive-icon-color,
76+
calendar-navigation-button-icon-color: $inactive-icon-color,
77+
calendar-header-divider-color: $divider-color,
78+
calendar-header-text-color: $secondary-text-color,
79+
80+
// Note: though it's not text, the border is a hint about the fact
81+
// that this is today's date, so we use the hint color.
82+
calendar-date-today-outline-color: $hint-text-color,
83+
calendar-date-today-disabled-state-outline-color: $today-disabled-outline-color,
84+
calendar-date-text-color: $text-color,
85+
calendar-date-outline-color: transparent,
86+
calendar-date-disabled-state-text-color: $disabled-text-color,
87+
calendar-date-preview-state-outline-color: $preview-outline-color,
88+
89+
range-input-separator-color: $text-color,
90+
range-input-disabled-state-separator-color: $disabled-text-color,
91+
range-input-disabled-state-text-color: $disabled-text-color,
92+
93+
calendar-container-background-color: theming.get-color-from-palette($background, card),
94+
calendar-container-text-color: $text-color,
95+
));
96+
}
97+
98+
// Tokens that can be configured through Angular Material's typography theming API.
99+
@function get-typography-tokens($config) {
100+
$fallback-font: typography-utils.font-family($config);
101+
102+
@return (
103+
// TODO(crisbeto): the typography tokens for other components set every typography dimension of
104+
// an element (e.g. size, weight, line height, letter spacing). These tokens only set the values
105+
// that were set in the previous theming API to reduce the amount of subtle screenshot
106+
// differences. We should look into introducing the other tokens in a follow-up.
107+
calendar-text-font: $fallback-font,
108+
calendar-text-size: 13px, // TODO(crisbeto): this doesn't appear to affect anything
109+
110+
calendar-body-label-text-size: typography-utils.font-size($config, button),
111+
calendar-body-label-text-weight: typography-utils.font-weight($config, button),
112+
113+
calendar-period-button-text-size: typography-utils.font-size($config, button),
114+
calendar-period-button-text-weight: typography-utils.font-weight($config, button),
115+
116+
calendar-header-text-size: 11px,
117+
calendar-header-text-weight: typography-utils.font-weight($config, body-1),
118+
);
119+
}
120+
121+
// Gets the tokens map that can be used to override the range colors.
122+
@function get-range-color-tokens(
123+
$range-color,
124+
$comparison-color: $private-default-comparison-color,
125+
$overlap-color: $private-default-overlap-color,
126+
$overlap-selected-color: private-get-default-overlap-selected-color($overlap-color)) {
127+
128+
@return (
129+
calendar-date-in-range-state-background-color: $range-color,
130+
calendar-date-in-comparison-range-state-background-color: $comparison-color,
131+
calendar-date-in-overlap-range-state-background-color: $overlap-color,
132+
calendar-date-in-overlap-range-selected-state-background-color: $overlap-selected-color,
133+
);
134+
}
135+
136+
@function private-get-calendar-color-palette-color-tokens($config, $palette-name) {
137+
$foreground: map.get($config, foreground);
138+
$palette: map.get($config, $palette-name);
139+
$palette-color: theming.get-color-from-palette($palette);
140+
$default-contrast: theming.get-color-from-palette($palette, default-contrast);
141+
$active-background-color: theming.get-color-from-palette($palette, 0.3);
142+
$active-disabled-color: null;
143+
144+
@if (meta.type-of($palette-color) == color) {
145+
$active-disabled-color: color.adjust($palette-color, $alpha: -$_selected-fade-amount);
146+
}
147+
@else {
148+
$active-disabled-color: theming.get-color-from-palette($foreground, disabled-button);
149+
}
150+
151+
@return (
152+
calendar-date-selected-state-text-color: $default-contrast,
153+
calendar-date-selected-state-background-color: $palette-color,
154+
calendar-date-selected-disabled-state-background-color: $active-disabled-color,
155+
calendar-date-today-selected-state-outline-color: $default-contrast,
156+
calendar-date-focus-state-background-color: $active-background-color,
157+
calendar-date-hover-state-background-color: $active-background-color,
158+
);
159+
}
160+
161+
@function private-get-toggle-color-palette-color-tokens($config, $palette-name) {
162+
$palette: map.get($config, $palette-name);
163+
164+
@return (
165+
toggle-active-state-icon-color: theming.get-color-from-palette($palette, text),
166+
);
167+
}
168+
169+
170+
// Tokens that can be configured through Angular Material's density theming API.
171+
@function get-density-tokens($config) {
172+
@return ();
173+
}
174+
175+
// Combines the tokens generated by the above functions into a single map with placeholder values.
176+
// This is used to create token slots.
177+
@function get-token-slots() {
178+
@return sass-utils.deep-merge-all(
179+
get-unthemable-tokens(),
180+
get-color-tokens(token-utils.$placeholder-color-config),
181+
get-typography-tokens(token-utils.$placeholder-typography-config),
182+
get-density-tokens(token-utils.$placeholder-density-config)
183+
);
184+
}

src/material/datepicker/BUILD.bazel

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,16 @@ sass_library(
5757
sass_binary(
5858
name = "datepicker_content_scss",
5959
src = "datepicker-content.scss",
60+
deps = ["//src/material/core:core_scss_lib"],
6061
)
6162

6263
sass_binary(
6364
name = "datepicker_toggle_scss",
6465
src = "datepicker-toggle.scss",
65-
deps = ["//src/cdk:sass_lib"],
66+
deps = [
67+
"//src/cdk:sass_lib",
68+
"//src/material/core:core_scss_lib",
69+
],
6670
)
6771

6872
sass_binary(

0 commit comments

Comments
 (0)