From f3058069559df80d29cdc807e2e0fdcf6eb3b9bd Mon Sep 17 00:00:00 2001 From: Joy Zhong Date: Fri, 19 Aug 2022 08:15:30 -0700 Subject: [PATCH] feat(menu): Implement menu theming API. Use menu surface/list/list item `theme()` mixins to style subcomponents. PiperOrigin-RevId: 468705317 --- menu/lib/_menu-theme.scss | 118 ++++++++++++++++++++++++++++++++++++++ menu/lib/_menu.scss | 8 +++ menu/lib/_mixins.scss | 87 ---------------------------- menu/lib/menu-styles.scss | 12 +++- menu/lib/menu.ts | 2 +- 5 files changed, 137 insertions(+), 90 deletions(-) create mode 100644 menu/lib/_menu-theme.scss create mode 100644 menu/lib/_menu.scss delete mode 100644 menu/lib/_mixins.scss diff --git a/menu/lib/_menu-theme.scss b/menu/lib/_menu-theme.scss new file mode 100644 index 000000000..df3ccef8e --- /dev/null +++ b/menu/lib/_menu-theme.scss @@ -0,0 +1,118 @@ +// +// Copyright 2022 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +@use 'sass:map'; + +@use '@material/web/elevation/lib/elevation-theme'; +@use '@material/web/list/list'; +@use '@material/web/list/list-item'; +@use '@material/web/menusurface/menu-surface'; +@use '@material/web/sass/resolvers'; +@use '@material/web/sass/theme'; +@use '@material/web/tokens'; + +$_custom-property-prefix: 'menu'; + +$light-theme: tokens.md-comp-menu-values(); + +@mixin theme($theme) { + $theme: theme.validate-theme($light-theme, $theme); + $theme: _resolve-theme($theme, $resolvers); + $theme: theme.create-theme-vars($theme, $_custom-property-prefix); + + @include theme.emit-theme-vars($theme); +} + +@mixin theme-styles($theme, $resolvers: resolvers.$material) { + $theme: theme.validate-theme-styles($light-theme, $theme); + $theme: _resolve-theme($theme, $resolvers); + $theme: theme.create-theme-vars($theme, $_custom-property-prefix); + + @include menu-surface.theme( + ( + container-elevation-shadow: map.get($theme, 'container-elevation-shadow'), + container-shape: map.get($theme, 'container-shape'), + ), + $resolvers + ); + + @include list.theme( + ( + container-color: map.get($theme, 'container-color'), + container-surface-tint-layer-color: + map.get($theme, 'container-surface-tint-layer-color'), + container-elevation-overlay-opacity: + map.get($theme, 'container-elevation-overlay-opacity'), + ) + ); + @include list-item.theme( + ( + list-item-container-color: map.get($theme, 'container-color'), + list-item-one-line-container-height: + map.get($theme, 'list-item-container-height'), + list-item-disabled-label-text-color: + map.get($theme, 'list-item-disabled-label-text-color'), + list-item-disabled-label-text-opacity: + map.get($theme, 'list-item-disabled-label-text-opacity'), + list-item-hover-label-text-color: + map.get($theme, 'list-item-hover-label-text-color'), + list-item-hover-state-layer-color: + map.get($theme, 'list-item-hover-state-layer-color'), + list-item-hover-state-layer-opacity: + map.get($theme, 'list-item-hover-state-layer-opacity'), + list-item-label-text-color: map.get($theme, 'list-item-label-text-color'), + list-item-label-text-font: map.get($theme, 'list-item-label-text-font'), + list-item-label-text-line-height: + map.get($theme, 'list-item-label-text-line-height'), + list-item-label-text-size: map.get($theme, 'list-item-label-text-size'), + list-item-label-text-tracking: + map.get($theme, 'list-item-label-text-tracking'), + list-item-label-text-weight: + map.get($theme, 'list-item-label-text-tracking'), + list-item-disabled-leading-icon-color: + map.get( + $theme, + 'list-item-with-leading-icon-disabled-leading-icon-color' + ), + list-item-disabled-leading-icon-opacity: + map.get( + $theme, + 'list-item-with-leading-icon-disabled-leading-icon-opacity' + ), + list-item-hover-leading-icon-color: + map.get($theme, 'list-item-with-leading-icon-hover-icon-color'), + list-item-leading-icon-color: + map.get($theme, 'list-item-with-leading-icon-leading-icon-color'), + list-item-leading-icon-size: + map.get($theme, 'list-item-with-leading-icon-leading-icon-size'), + list-item-disabled-trailing-icon-color: + map.get( + $theme, + 'list-item-with-trailing-icon-disabled-trailing-icon-color' + ), + list-item-disabled-trailing-icon-opacity: + map.get( + $theme, + 'list-item-with-trailing-icon-disabled-trailing-icon-opacity' + ), + list-item-hover-trailing-icon-color: + map.get($theme, 'list-item-with-trailing-icon-hover-icon-color'), + list-item-trailing-icon-color: + map.get($theme, 'list-item-with-trailing-icon-trailing-icon-color'), + list-item-trailing-icon-size: + map.get($theme, 'list-item-with-leading-icon-trailing-icon-size'), + ) + ); +} + +@function _resolve-theme($theme, $resolvers) { + $theme: elevation-theme.resolve-theme( + $theme, + map.get($resolvers, 'elevation'), + $shadow-color-token: 'container-shadow-color', + $elevation-tokens: (container-elevation) + ); + @return $theme; +} diff --git a/menu/lib/_menu.scss b/menu/lib/_menu.scss new file mode 100644 index 000000000..8098470a7 --- /dev/null +++ b/menu/lib/_menu.scss @@ -0,0 +1,8 @@ +// +// Copyright 2022 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +@mixin static-styles() { + // Intentionally blank for future-proofing. +} diff --git a/menu/lib/_mixins.scss b/menu/lib/_mixins.scss deleted file mode 100644 index d1ecf3d03..000000000 --- a/menu/lib/_mixins.scss +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// stylelint-disable selector-class-pattern -- -// Selector '.md3-*' should only be used in this project. - -@use 'sass:math'; -@use '../../sass/dom'; - -$ink-color: rgba(#fff, 0.87); -$width-base: 56px !default; -$min-width: 2 * $width-base !default; - -@mixin core-styles() { - .md3-menu { - @include min-width($min-width); - - .md3-list { - &::before { - @include dom.transparent-border(); - } - } - - .md3-deprecated-list-divider { - margin: 8px 0; - } - - .md3-deprecated-list-item { - user-select: none; - } - - .md3-deprecated-list-item--disabled { - cursor: auto; - } - - //stylelint-disable selector-no-qualifying-type - a.md3-deprecated-list-item .md3-deprecated-list-item__text, - a.md3-deprecated-list-item .md3-deprecated-list-item__graphic { - pointer-events: none; - } - // stylelint-enable selector-no-qualifying-type - } - - // postcss-bem-linter: define menu - .md3-menu__selection-group { - padding: 0; - fill: currentColor; - - .md3-deprecated-list-item { - padding-left: 56px; - padding-right: 16px; - } - - // Extra specificity required to override `display` property on `md3-deprecated-list-item__graphic`. - .md3-menu__selection-group-icon { - left: 16px; - display: none; - position: absolute; - // IE11 requires the icon to be vertically centered due to its absolute positioning - top: 50%; - transform: translateY(-50%); - } - } - // postcss-bem-linter: end - - // stylelint-disable-next-line plugin/selector-bem-pattern - .md3-menu-item--selected .md3-menu__selection-group-icon { - display: inline; - } -} - -@mixin width($width) { - @if math.is-unitless($width) { - width: $width * $width-base; - } @else { - width: $width; - } -} - -/// Sets the min-width of the menu. -/// @param {Number} $min-width - the desired min-width. -@mixin min-width($min-width) { - min-width: $min-width; -} diff --git a/menu/lib/menu-styles.scss b/menu/lib/menu-styles.scss index 74499ba75..7a063c9f1 100644 --- a/menu/lib/menu-styles.scss +++ b/menu/lib/menu-styles.scss @@ -4,6 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -@use './mixins'; +// stylelint-disable selector-class-pattern -- +// Selector '.md3-*' should only be used in this project. -@include mixins.core-styles(); +@use './menu'; +@use './menu-theme'; + +@include menu.static-styles(); + +.md3-menu { + @include menu-theme.theme-styles(menu-theme.$light-theme); +} diff --git a/menu/lib/menu.ts b/menu/lib/menu.ts index b570afe1c..9c8a2695f 100644 --- a/menu/lib/menu.ts +++ b/menu/lib/menu.ts @@ -115,7 +115,7 @@ export abstract class Menu extends LitElement { .flipMenuHorizontally=${this.flipMenuHorizontally} .skipRestoreFocus=${this.skipRestoreFocus} ?stayOpenOnBodyClick=${this.stayOpenOnBodyClick} - class="md3-menu md3-menu-surface" + class="md3-menu" @closed=${this.onClosed} @opened=${this.onOpened} @keydown=${this.onKeydown}>