Skip to content

refactor(material/menu): switch to tokens API #27377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/material/core/tokens/m2/mat/_menu.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@use 'sass:map';
@use '../../token-utils';
@use '../../../theming/theming';
@use '../../../style/sass-utils';
@use '../../../typography/typography-utils';

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

// 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 (
container-shape: 4px,
);
}

// 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);
$on-surface: if($is-dark, #fff, #000);
$active-state-layer-color: rgba($on-surface, if($is-dark, 0.08, 0.04));
$text-color: theming.get-color-from-palette($foreground, text);

@return (
item-label-text-color: $text-color,
item-icon-color: $text-color,
item-hover-state-layer-color: $active-state-layer-color,
item-focus-state-layer-color: $active-state-layer-color,
container-color: theming.get-color-from-palette($background, card),
);
}

// Tokens that can be configured through Angular Material's typography theming API.
@function get-typography-tokens($config) {
@return (
item-label-text-font:
typography-utils.font-family($config, body-1) or typography-utils.font-family($config),
item-label-text-size: typography-utils.font-size($config, body-1),
item-label-text-tracking: typography-utils.letter-spacing($config, body-1),
item-label-text-line-height: typography-utils.line-height($config, body-1),
item-label-text-weight: typography-utils.font-weight($config, body-1),
);
}

// 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)
);
}
64 changes: 9 additions & 55 deletions src/material/menu/_menu-theme.scss
Original file line number Diff line number Diff line change
@@ -1,71 +1,25 @@
@use '@material/theme/theme-color' as mdc-theme-color;
@use '@material/theme/theme' as mdc-theme;
@use '@material/menu-surface' as mdc-menu-surface;
@use '@material/list/evolution-mixins' as mdc-list;
@use '@material/typography' as mdc-typography;
@use '@material/ripple' as mdc-ripple;
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/tokens/m2/mat/menu' as tokens-mat-menu;
@use '../core/style/sass-utils';
@use '../core/tokens/token-utils';
@use '../core/theming/theming';
@use '../core/typography/typography';


@mixin color($config-or-theme) {
$config: theming.get-color-config($config-or-theme);
@include mdc-helpers.using-mdc-theme($config) {
@include mdc-menu-surface.core-styles(mdc-helpers.$mdc-theme-styles-query);

.mat-mdc-menu-panel-wrapper {
@include mdc-list.without-ripple(mdc-helpers.$mdc-theme-styles-query);
}

// MDC doesn't appear to have disabled styling for menu
// items so we have to grey them out ourselves.
.mat-mdc-menu-item[disabled] {
&,
.mat-mdc-menu-submenu-icon,
.mat-icon-no-color {
@include mdc-theme.prop(color, text-disabled-on-background);
}
}

// Since we're creating `mat-icon` and the submenu trigger
// chevron ourselves, we have to handle the color as well.
.mat-mdc-menu-item .mat-icon-no-color,
.mat-mdc-menu-submenu-icon {
@include mdc-theme.prop(color, text-primary-on-background);
}

// MDC's hover and focus styles are tied to their ripples which we aren't using.
.mat-mdc-menu-item:hover,
.mat-mdc-menu-item.cdk-program-focused,
.mat-mdc-menu-item.cdk-keyboard-focused,
.mat-mdc-menu-item-highlighted {
&:not([disabled]) {
$color: mdc-theme-color.$on-surface;
background: rgba($color, mdc-ripple.states-opacity($color, hover));
}
}
@include sass-utils.current-selector-or-root() {
@include token-utils.create-token-values(tokens-mat-menu.$prefix,
tokens-mat-menu.get-color-tokens($config));
}
}

@mixin typography($config-or-theme) {
$config: typography.private-typography-to-2018-config(
theming.get-typography-config($config-or-theme));
@include mdc-helpers.using-mdc-typography($config) {
@include mdc-menu-surface.core-styles(mdc-helpers.$mdc-typography-styles-query);

.mat-mdc-menu-content {
// Note that we include this private mixin, because the public
// one adds a bunch of styles that we aren't using for the menu.
@include mdc-list.list-base(mdc-helpers.$mdc-typography-styles-query);

// MDC uses the `subtitle1` level for list items, but the spec shows `body1` as the correct
// level.
&,
.mat-mdc-menu-item .mdc-list-item__primary-text {
@include mdc-typography.typography(body1, $query: mdc-helpers.$mdc-typography-styles-query);
}
}
@include sass-utils.current-selector-or-root() {
@include token-utils.create-token-values(tokens-mat-menu.$prefix,
tokens-mat-menu.get-typography-tokens($config));
}
}

Expand Down
9 changes: 1 addition & 8 deletions src/material/menu/menu-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export abstract class _MatMenuTriggerBase implements AfterContentInit, OnDestroy
private _menuCloseSubscription = Subscription.EMPTY;
private _scrollStrategy: () => ScrollStrategy;
private _changeDetectorRef = inject(ChangeDetectorRef);
protected _panelClass: string | null;

/**
* We're specifically looking for a `MatMenu` here since the generic `MatMenuPanel`
Expand Down Expand Up @@ -330,10 +329,6 @@ export abstract class _MatMenuTriggerBase implements AfterContentInit, OnDestroy
this._closingActionsSubscription = this._menuClosingActions().subscribe(() => this.closeMenu());
this._initMenu(menu);

if (this._panelClass) {
overlayRef.overlayElement.classList.add(this._panelClass);
}

if (menu instanceof _MatMenuBase) {
menu._startAnimation();
menu._directDescendantItems.changes.pipe(takeUntil(menu.close)).subscribe(() => {
Expand Down Expand Up @@ -691,6 +686,4 @@ export abstract class _MatMenuTriggerBase implements AfterContentInit, OnDestroy
},
exportAs: 'matMenuTrigger',
})
export class MatMenuTrigger extends _MatMenuTriggerBase {
protected override _panelClass = 'mat-mdc-menu-panel-wrapper';
}
export class MatMenuTrigger extends _MatMenuTriggerBase {}
65 changes: 59 additions & 6 deletions src/material/menu/menu.scss
Original file line number Diff line number Diff line change
@@ -1,27 +1,52 @@
@use 'sass:map';
@use '@angular/cdk';
@use '@material/menu-surface' as mdc-menu-surface;
@use '@material/list/evolution-mixins' as mdc-list-mixins;
@use '@material/list/evolution-variables' as mdc-list-variables;
@use '@material/typography/typography' as mdc-typography;
@use '../core/tokens/m2/mat/menu' as tokens-mat-menu;
@use '../core/tokens/token-utils';
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/style/menu-common';
@use '../core/style/button-common';


@include mdc-helpers.disable-mdc-fallback-declarations {
@include mdc-menu-surface.core-styles($query: structure);
}

// Prevent rendering mat-menu as it can affect the flex layout.
mat-menu {
display: none;
}

.mat-mdc-menu-content {
@include mdc-list-mixins.list-base($query: structure);

&,
.mat-mdc-menu-item .mdc-list-item__primary-text {
@include mdc-typography.smooth-font();
@include token-utils.use-tokens(tokens-mat-menu.$prefix, tokens-mat-menu.get-token-slots()) {
@include token-utils.create-token-slot(font-family, item-label-text-font);
@include token-utils.create-token-slot(line-height, item-label-text-line-height);
@include token-utils.create-token-slot(font-size, item-label-text-size);
@include token-utils.create-token-slot(letter-spacing, item-label-text-tracking);
@include token-utils.create-token-slot(font-weight, item-label-text-weight);
}
}
}

.mat-mdc-menu-panel {
@include token-utils.create-token-values(tokens-mat-menu.$prefix,
tokens-mat-menu.get-unthemable-tokens());
box-sizing: border-box;
outline: 0;

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

// TODO(crisbeto): we don't need this for anything, but it was there when
// we used MDC's structural styles and removing it leads to sub-pixels
// differences in text rendering which break a lot of screenshots internally.
// We should clean it up eventually and re-approve all the screenshots.
will-change: transform, opacity;

// Prevent users from interacting with the panel while it's animating. Note that
// people won't be able to click through it, because the overlay pane will catch the click.
// This fixes the following issues:
Expand Down Expand Up @@ -78,6 +103,20 @@ mat-menu {
$height-config: map.get(mdc-list-variables.$one-line-item-density-config, height);
min-height: map.get($height-config, default);

@include token-utils.use-tokens(tokens-mat-menu.$prefix, tokens-mat-menu.get-token-slots()) {
// The class selector isn't specific enough to overide the link pseudo selectors so we need
// to target them specifically, otherwise the item color might be overwritten by the user
// agent resets of the app.
&, &:visited, &:link {
@include token-utils.create-token-slot(color, item-label-text-color);
}

.mat-icon-no-color,
.mat-mdc-menu-submenu-icon {
@include token-utils.create-token-slot(color, item-icon-color);
}
}

// If the MDC list is loaded after the menu, this gets overwritten which breaks the text
// alignment. Ideally we'd wrap all the MDC mixins above with this selector, but the increased
// specificity breaks some internal overrides.
Expand Down Expand Up @@ -130,6 +169,20 @@ mat-menu {
@include menu-common.item-submenu-trigger(mdc-list-variables.$side-padding);
}

&:not([disabled]) {
@include token-utils.use-tokens(tokens-mat-menu.$prefix, tokens-mat-menu.get-token-slots()) {
&:hover {
@include token-utils.create-token-slot(background-color, item-hover-state-layer-color);
}

&.cdk-program-focused,
&.cdk-keyboard-focused,
&.mat-mdc-menu-item-highlighted {
@include token-utils.create-token-slot(background-color, item-focus-state-layer-color);
}
}
}

@include cdk.high-contrast(active, off) {
$outline-width: 1px;

Expand Down
4 changes: 0 additions & 4 deletions tools/public_api_guard/material/menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,6 @@ export interface MatMenuPanel<T = any> {

// @public
export class MatMenuTrigger extends _MatMenuTriggerBase {
// (undocumented)
protected _panelClass: string;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<MatMenuTrigger, "[mat-menu-trigger-for], [matMenuTriggerFor]", ["matMenuTrigger"], {}, {}, never, never, false, never>;
// (undocumented)
Expand Down Expand Up @@ -315,8 +313,6 @@ export abstract class _MatMenuTriggerBase implements AfterContentInit, OnDestroy
// (undocumented)
_openedBy: Exclude<FocusOrigin, 'program' | null> | undefined;
openMenu(): void;
// (undocumented)
protected _panelClass: string | null;
restoreFocus: boolean;
toggleMenu(): void;
triggersSubmenu(): boolean;
Expand Down