Skip to content

Commit

Permalink
refactor(material/sidenav): switch to tokens API (angular#27468)
Browse files Browse the repository at this point in the history
Reworks the sidenav to use the new tokens theming API.
  • Loading branch information
crisbeto authored and Anthony Frénéat committed Jul 31, 2023
1 parent 551a95b commit 1d8379a
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 75 deletions.
65 changes: 65 additions & 0 deletions src/material/core/tokens/m2/mat/_sidenav.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@use 'sass:color';
@use 'sass:map';
@use 'sass:meta';
@use '../../token-utils';
@use '../../../theming/theming';
@use '../../../style/sass-utils';

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

// 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 (
// Currently zero, but it appears to be relevant for M3.
// See: https://m3.material.io/components/navigation-drawer/overview
container-shape: 0,
);
}

// Tokens that can be configured through Angular Material's color theming API.
@function get-color-tokens($config) {
$is-dark: map.get($config, is-dark);
$foreground: map.get($config, foreground);
$background: map.get($config, background);
$scrim-opacity: 0.6;
$scrim-color: theming.get-color-from-palette($background, card, $scrim-opacity);
$fallback-scrim-color: if($is-dark, rgba(#fff, $scrim-opacity), rgba(#000, $scrim-opacity));

@return (
container-divider-color: theming.get-color-from-palette($foreground, divider),
container-background-color: theming.get-color-from-palette($background, dialog),
container-text-color: theming.get-color-from-palette($foreground, text),
content-background-color: theming.get-color-from-palette($background, background),
content-text-color: theming.get-color-from-palette($foreground, text),

// We use invert() here to have the darken the background color expected to be used.
// If the background is light, we use a dark backdrop. If the background is dark, we
// use a light backdrop. If the value isn't a color, Sass will throw an error so we
// fall back to something generic.
scrim-color: if(meta.type-of($scrim-color) == color,
color.invert($scrim-color), $fallback-scrim-color),
);
}

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

// 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)
);
}
75 changes: 6 additions & 69 deletions src/material/sidenav/_sidenav-theme.scss
Original file line number Diff line number Diff line change
@@ -1,77 +1,14 @@
@use 'sass:color';
@use 'sass:map';
@use 'sass:meta';
@use '../core/style/private';
@use '../core/theming/theming';
@use '../core/tokens/m2/mat/sidenav' as tokens-mat-sidenav;
@use '../core/tokens/token-utils';
@use '../core/style/sass-utils';

@mixin color($config-or-theme) {
$config: theming.get-color-config($config-or-theme);
$primary: map.get($config, primary);
$accent: map.get($config, accent);
$warn: map.get($config, warn);
$background: map.get($config, background);
$foreground: map.get($config, foreground);

$drawer-background-color: theming.get-color-from-palette($background, dialog);
$drawer-container-background-color: theming.get-color-from-palette($background, background);
$drawer-push-background-color: theming.get-color-from-palette($background, dialog);
$drawer-side-border: solid 1px theming.get-color-from-palette($foreground, divider);

.mat-drawer-container {
background-color: $drawer-container-background-color;
color: theming.get-color-from-palette($foreground, text);
}

.mat-drawer {
background-color: $drawer-background-color;
color: theming.get-color-from-palette($foreground, text);

&.mat-drawer-push {
background-color: $drawer-push-background-color;
}

&:not(.mat-drawer-side) {
// The elevation of z-16 is noted in the design specifications.
// See https://material.io/design/components/navigation-drawer.html
@include private.private-theme-elevation(16, $config);
}
}

.mat-drawer-side {
border-right: $drawer-side-border;

&.mat-drawer-end {
border-left: $drawer-side-border;
border-right: none;
}
}

[dir='rtl'] .mat-drawer-side {
border-left: $drawer-side-border;
border-right: none;

&.mat-drawer-end {
border-left: none;
border-right: $drawer-side-border;
}
}

.mat-drawer-backdrop.mat-drawer-shown {
$opacity: 0.6;
$backdrop-color: theming.get-color-from-palette($background, card, $opacity);

@if (meta.type-of($backdrop-color) == color) {
// We use invert() here to have the darken the background color expected to be used. If the
// background is light, we use a dark backdrop. If the background is dark,
// we use a light backdrop.
background-color: color.invert($backdrop-color);
}
@else {
// If we couldn't resolve the backdrop color to a color value, fall back to using
// `opacity` to make it opaque since its end value could be a solid color.
background-color: $backdrop-color;
opacity: $opacity;
}
@include sass-utils.current-selector-or-root() {
@include token-utils.create-token-values(tokens-mat-sidenav.$prefix,
tokens-mat-sidenav.get-color-tokens($config));
}
}

Expand Down
91 changes: 85 additions & 6 deletions src/material/sidenav/drawer.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
@use '@angular/cdk';

@use '../core/tokens/m2/mat/sidenav' as tokens-mat-sidenav;
@use '../core/tokens/token-utils';
@use '../core/style/variables';
@use '../core/style/layout-common';
@use '../core/style/elevation';

$drawer-content-z-index: 1;
$drawer-side-drawer-z-index: 2;
Expand All @@ -25,6 +28,12 @@ $drawer-over-drawer-z-index: 4;
// the application content does not get messed up with our own CSS.
@include drawer-stacking-context();

@include token-utils.use-tokens(
tokens-mat-sidenav.$prefix, tokens-mat-sidenav.get-token-slots()) {
@include token-utils.create-token-slot(color, content-text-color);
@include token-utils.create-token-slot(background-color, content-background-color);
}

box-sizing: border-box;
-webkit-overflow-scrolling: touch;

Expand Down Expand Up @@ -74,6 +83,11 @@ $drawer-over-drawer-z-index: 4;

&.mat-drawer-shown {
visibility: visible;

@include token-utils.use-tokens(
tokens-mat-sidenav.$prefix, tokens-mat-sidenav.get-token-slots()) {
@include token-utils.create-token-slot(background-color, scrim-color);
}
}

.mat-drawer-transition & {
Expand Down Expand Up @@ -108,7 +122,20 @@ $drawer-over-drawer-z-index: 4;
.mat-drawer {
$high-contrast-border: solid 1px currentColor;

// The elevation of z-16 is noted in the design specifications.
// See https://material.io/design/components/navigation-drawer.html
@include elevation.elevation(16);
@include drawer-stacking-context($drawer-over-drawer-z-index);
@include token-utils.create-token-values(
tokens-mat-sidenav.$prefix, tokens-mat-sidenav.get-unthemable-tokens());

@include token-utils.use-tokens(
tokens-mat-sidenav.$prefix, tokens-mat-sidenav.get-token-slots()) {
@include token-utils.create-token-slot(color, container-text-color);
@include token-utils.create-token-slot(background-color, container-background-color);
@include token-utils.create-token-slot(border-top-right-radius, container-shape);
@include token-utils.create-token-slot(border-bottom-right-radius, container-shape);
}

display: block;
position: absolute;
Expand All @@ -120,6 +147,7 @@ $drawer-over-drawer-z-index: 4;
overflow-y: auto; // TODO(kara): revisit scrolling behavior for drawers
transform: translate3d(-100%, 0, 0);


&, [dir='rtl'] &.mat-drawer-end {
@include cdk.high-contrast(active, off) {
border-right: $high-contrast-border;
Expand All @@ -140,15 +168,34 @@ $drawer-over-drawer-z-index: 4;
&.mat-drawer-end {
right: 0;
transform: translate3d(100%, 0, 0);

@include token-utils.use-tokens(
tokens-mat-sidenav.$prefix, tokens-mat-sidenav.get-token-slots()) {
@include token-utils.create-token-slot(border-top-left-radius, container-shape);
@include token-utils.create-token-slot(border-bottom-left-radius, container-shape);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}

[dir='rtl'] & {
transform: translate3d(100%, 0, 0);

&.mat-drawer-end {
left: 0;
right: auto;
transform: translate3d(-100%, 0, 0);
@include token-utils.use-tokens(
tokens-mat-sidenav.$prefix, tokens-mat-sidenav.get-token-slots()) {
@include token-utils.create-token-slot(border-top-left-radius, container-shape);
@include token-utils.create-token-slot(border-bottom-left-radius, container-shape);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
transform: translate3d(100%, 0, 0);

&.mat-drawer-end {
@include token-utils.create-token-slot(border-top-right-radius, container-shape);
@include token-utils.create-token-slot(border-bottom-right-radius, container-shape);
border-top-left-radius: 0;
border-bottom-left-radius: 0;
left: 0;
right: auto;
transform: translate3d(-100%, 0, 0);
}
}
}

Expand All @@ -164,6 +211,38 @@ $drawer-over-drawer-z-index: 4;
}
}

.mat-drawer-side {
box-shadow: none;

@include token-utils.use-tokens(
tokens-mat-sidenav.$prefix, tokens-mat-sidenav.get-token-slots()) {
@include token-utils.create-token-slot(border-right-color, container-divider-color);
border-right-width: 1px;
border-right-style: solid;

&.mat-drawer-end {
@include token-utils.create-token-slot(border-left-color, container-divider-color);
border-left-width: 1px;
border-left-style: solid;
border-right: none;
}

[dir='rtl'] & {
@include token-utils.create-token-slot(border-left-color, container-divider-color);
border-left-width: 1px;
border-left-style: solid;
border-right: none; // Clears the default LTR border.

&.mat-drawer-end {
@include token-utils.create-token-slot(border-right-color, container-divider-color);
border-right-width: 1px;
border-right-style: solid;
border-left: none;
}
}
}
}

// Note that this div isn't strictly necessary on all browsers, however we need it in
// order to avoid a layout issue in Chrome. The issue is that in RTL mode the browser doesn't
// account for the sidenav's scrollbar while positioning, which ends up pushing it partially
Expand Down

0 comments on commit 1d8379a

Please sign in to comment.