Skip to content

Commit

Permalink
refactor(material/datepicker): switch to tokens API (#27503)
Browse files Browse the repository at this point in the history
Reworks the datepicker to use tokens for theming.
  • Loading branch information
crisbeto authored Jul 25, 2023
1 parent 88f6648 commit 0c4f947
Show file tree
Hide file tree
Showing 10 changed files with 463 additions and 210 deletions.
1 change: 1 addition & 0 deletions src/dev-app/datepicker/datepicker-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ <h2>Range picker</h2>
<mat-date-range-picker
[touchUi]="touch"
[disabled]="datepickerDisabled"
[color]="color"
#range1Picker>
<mat-date-range-picker-actions *ngIf="showActions">
<button mat-button matDateRangePickerCancel>Cancel</button>
Expand Down
6 changes: 3 additions & 3 deletions src/material/core/theming/tests/theming-api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,15 @@ describe('theming api', () => {
)
));
// Updates the "icon" foreground color to "canary".
// Updates the "icon" foreground color to hotpink.
$color: map-get($theme, color);
$theme: map-merge($color,
(foreground: map-merge(map-get($color, foreground), (icon: "canary"))));
(foreground: map-merge(map-get($color, foreground), (icon: hotpink))));
@include angular-material-theme($theme);
`);

expect(result).toContain(': "canary"');
expect(result).toContain(': hotpink');
});

it('should warn if default density styles are duplicated', () => {
Expand Down
184 changes: 184 additions & 0 deletions src/material/core/tokens/m2/mat/_datepicker.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
@use 'sass:color';
@use 'sass:map';
@use 'sass:meta';
@use 'sass:math';
@use '../../token-utils';
@use '../../../theming/theming';
@use '../../../typography/typography-utils';
@use '../../../style/sass-utils';

// The prefix used to generate the fully qualified name for tokens in this file.
$prefix: (mat, datepicker);

$_selected-fade-amount: 0.6;
$_today-fade-amount: 0.2;

// Utility that produces a range background color from a specific color.
@function private-get-range-background-color($color) {
@return rgba($color, 0.2);
}

// Utility that produces the overlap selected color from an overlap color.
@function private-get-default-overlap-selected-color($overlap-color) {
@return color.adjust($overlap-color, $lightness: -30%);
}

// Default range comparison color.
$private-default-comparison-color: private-get-range-background-color(#f9ab00);

// Default range overlap color.
$private-default-overlap-color: #a8dab5;

// Tokens that can't be configured through Angular Material's current theming API,
// but may be in a future version of the theming API.
@function get-unthemable-tokens() {
@return ();
}

// Tokens that can be configured through Angular Material's color theming API.
@function get-color-tokens($config) {
$foreground: map.get($config, foreground);
$background: map.get($config, background);
$primary: map.get($config, primary);
$inactive-icon-color: theming.get-color-from-palette($foreground, icon);
$text-color: theming.get-color-from-palette($foreground, text);
$secondary-text-color: theming.get-color-from-palette($foreground, secondary-text);
$disabled-text-color: theming.get-color-from-palette($foreground, disabled-text);
$divider-color: theming.get-color-from-palette($foreground, divider);
$hint-text-color: theming.get-color-from-palette($foreground, hint-text);
$preview-outline-color: $divider-color;
$today-disabled-outline-color: null;

$primary-color: theming.get-color-from-palette(map.get($config, primary));
$range-tokens: get-range-color-tokens(private-get-range-background-color($primary-color));
$calendar-tokens: private-get-calendar-color-palette-color-tokens($config, primary);
$toggle-tokens: private-get-toggle-color-palette-color-tokens($config, primary);

// The divider color is set under the assumption that it'll be used
// for a solid border, but because we're using a dashed border for the
// preview range, we need to bump its opacity to ensure that it's visible.
@if meta.type-of($preview-outline-color) == color {
$preview-outline-opacity: math.min(opacity($preview-outline-color) * 2, 1);
$preview-outline-color: rgba($preview-outline-color, $preview-outline-opacity);
}

@if (meta.type-of($hint-text-color) == color) {
$today-disabled-outline-color: color.adjust($hint-text-color, $alpha: -$_today-fade-amount);
}
@else {
$today-disabled-outline-color: $disabled-text-color;
}

@return sass-utils.merge-all($calendar-tokens, $toggle-tokens, $range-tokens, (
toggle-icon-color: $inactive-icon-color,
calendar-body-label-text-color: $secondary-text-color,
calendar-period-button-icon-color: $inactive-icon-color,
calendar-navigation-button-icon-color: $inactive-icon-color,
calendar-header-divider-color: $divider-color,
calendar-header-text-color: $secondary-text-color,

// Note: though it's not text, the border is a hint about the fact
// that this is today's date, so we use the hint color.
calendar-date-today-outline-color: $hint-text-color,
calendar-date-today-disabled-state-outline-color: $today-disabled-outline-color,
calendar-date-text-color: $text-color,
calendar-date-outline-color: transparent,
calendar-date-disabled-state-text-color: $disabled-text-color,
calendar-date-preview-state-outline-color: $preview-outline-color,

range-input-separator-color: $text-color,
range-input-disabled-state-separator-color: $disabled-text-color,
range-input-disabled-state-text-color: $disabled-text-color,

calendar-container-background-color: theming.get-color-from-palette($background, card),
calendar-container-text-color: $text-color,
));
}

// Tokens that can be configured through Angular Material's typography theming API.
@function get-typography-tokens($config) {
$fallback-font: typography-utils.font-family($config);

@return (
// TODO(crisbeto): the typography tokens for other components set every typography dimension of
// an element (e.g. size, weight, line height, letter spacing). These tokens only set the values
// that were set in the previous theming API to reduce the amount of subtle screenshot
// differences. We should look into introducing the other tokens in a follow-up.
calendar-text-font: $fallback-font,
calendar-text-size: 13px, // TODO(crisbeto): this doesn't appear to affect anything

calendar-body-label-text-size: typography-utils.font-size($config, button),
calendar-body-label-text-weight: typography-utils.font-weight($config, button),

calendar-period-button-text-size: typography-utils.font-size($config, button),
calendar-period-button-text-weight: typography-utils.font-weight($config, button),

calendar-header-text-size: 11px,
calendar-header-text-weight: typography-utils.font-weight($config, body-1),
);
}

// Gets the tokens map that can be used to override the range colors.
@function get-range-color-tokens(
$range-color,
$comparison-color: $private-default-comparison-color,
$overlap-color: $private-default-overlap-color,
$overlap-selected-color: private-get-default-overlap-selected-color($overlap-color)) {

@return (
calendar-date-in-range-state-background-color: $range-color,
calendar-date-in-comparison-range-state-background-color: $comparison-color,
calendar-date-in-overlap-range-state-background-color: $overlap-color,
calendar-date-in-overlap-range-selected-state-background-color: $overlap-selected-color,
);
}

@function private-get-calendar-color-palette-color-tokens($config, $palette-name) {
$foreground: map.get($config, foreground);
$palette: map.get($config, $palette-name);
$palette-color: theming.get-color-from-palette($palette);
$default-contrast: theming.get-color-from-palette($palette, default-contrast);
$active-background-color: theming.get-color-from-palette($palette, 0.3);
$active-disabled-color: null;

@if (meta.type-of($palette-color) == color) {
$active-disabled-color: color.adjust($palette-color, $alpha: -$_selected-fade-amount);
}
@else {
$active-disabled-color: theming.get-color-from-palette($foreground, disabled-button);
}

@return (
calendar-date-selected-state-text-color: $default-contrast,
calendar-date-selected-state-background-color: $palette-color,
calendar-date-selected-disabled-state-background-color: $active-disabled-color,
calendar-date-today-selected-state-outline-color: $default-contrast,
calendar-date-focus-state-background-color: $active-background-color,
calendar-date-hover-state-background-color: $active-background-color,
);
}

@function private-get-toggle-color-palette-color-tokens($config, $palette-name) {
$palette: map.get($config, $palette-name);

@return (
toggle-active-state-icon-color: theming.get-color-from-palette($palette, text),
);
}


// Tokens that can be configured through Angular Material's density theming API.
@function get-density-tokens($config) {
@return ();
}

// Combines the tokens generated by the above functions into a single map with placeholder values.
// This is used to create token slots.
@function get-token-slots() {
@return sass-utils.deep-merge-all(
get-unthemable-tokens(),
get-color-tokens(token-utils.$placeholder-color-config),
get-typography-tokens(token-utils.$placeholder-typography-config),
get-density-tokens(token-utils.$placeholder-density-config)
);
}
6 changes: 5 additions & 1 deletion src/material/datepicker/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,16 @@ sass_library(
sass_binary(
name = "datepicker_content_scss",
src = "datepicker-content.scss",
deps = ["//src/material/core:core_scss_lib"],
)

sass_binary(
name = "datepicker_toggle_scss",
src = "datepicker-toggle.scss",
deps = ["//src/cdk:sass_lib"],
deps = [
"//src/cdk:sass_lib",
"//src/material/core:core_scss_lib",
],
)

sass_binary(
Expand Down
Loading

0 comments on commit 0c4f947

Please sign in to comment.