diff --git a/packages/mdc-list/_mixins.scss b/packages/mdc-list/_mixins.scss index 42eab5f0563..e50ba040890 100644 --- a/packages/mdc-list/_mixins.scss +++ b/packages/mdc-list/_mixins.scss @@ -21,55 +21,346 @@ @import "@material/rtl/mixins"; @import "@material/theme/mixins"; @import "@material/shape/mixins"; +@import "@material/ripple/mixins"; +@import "@material/theme/functions"; +@import "@material/typography/mixins"; +@import "@material/typography/variables"; @import "./variables"; // // Public // -@mixin mdc-list-item-primary-text-ink-color($color) { - @include mdc-theme-prop(color, $color); -} +@mixin mdc-list($query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + $feat-structure: mdc-feature-create-target($query, structure); + $feat-typography: mdc-feature-create-target($query, typography); + + $item-primary-text-baseline-height: 32px; + $item-secondary-text-baseline-height: 20px; + $dense-item-primary-text-baseline-height: 24px; + $divider-color: if( + mdc-theme-tone($mdc-theme-background) == "dark", + $mdc-list-divider-color-on-dark-bg, + $mdc-list-divider-color-on-light-bg + ); + + @include mdc-ripple-common($query); + + .mdc-list { + @include mdc-list-base_($query); + } + + @include mdc-list-item-secondary-text-ink-color(text-secondary-on-background, $query); + @include mdc-list-item-graphic-fill-color(transparent, $query); + @include mdc-list-item-graphic-ink-color(text-icon-on-background, $query); + @include mdc-list-item-meta-ink-color(text-hint-on-background, $query); + @include mdc-list-group-subheader-ink-color(text-primary-on-background, $query); + + .mdc-list--dense { + @include mdc-feature-targets($feat-structure) { + padding-top: 4px; + padding-bottom: 4px; + font-size: .812rem; + } + } + + .mdc-list-item { + @include mdc-feature-targets($feat-structure) { + @include mdc-list-item-base_; + } + } + + // "Selected" is ephemeral and likely to change soon. E.g., selecting one or more photos to share in Google Photos. + // "Activated" is more permanent. E.g., the currently highlighted navigation destination in a drawer. + .mdc-list-item--selected, + .mdc-list-item--activated { + @include mdc-list-item-primary-text-ink-color(primary, $query); + @include mdc-list-item-graphic-ink-color(primary, $query); + } + + .mdc-list-item--disabled { + @include mdc-list-item-primary-text-ink-color(text-disabled-on-background, $query); + } + + .mdc-list-item__graphic { + @include mdc-feature-targets($feat-structure) { + @include mdc-list-graphic-size_(24px); + + flex-shrink: 0; + align-items: center; + justify-content: center; + fill: currentColor; + } + } + + // Extra specificity is to override .material-icons display style if used in + // conjunction with mdc-list-item__graphic + // stylelint-disable plugin/selector-bem-pattern + .mdc-list .mdc-list-item__graphic { + @include mdc-feature-targets($feat-structure) { + display: inline-flex; + } + } + // stylelint-enable plugin/selector-bem-pattern + + .mdc-list-item__meta { + @include mdc-feature-targets($feat-structure) { + @include mdc-rtl-reflexive-property(margin, auto, 0, ".mdc-list-item"); + } + } + + .mdc-list-item__text { + @include mdc-typography-overflow-ellipsis($query); + } + + // Disable interaction on label elements that may automatically + // toggle corresponding checkbox / radio input. + .mdc-list-item__text[for] { + @include mdc-feature-targets($feat-structure) { + pointer-events: none; + } + } + + .mdc-list-item__primary-text { + @include mdc-typography-overflow-ellipsis($query); + @include mdc-typography-baseline-top($item-primary-text-baseline-height, $query); + @include mdc-typography-baseline-bottom($item-secondary-text-baseline-height, $query); + + @include mdc-feature-targets($feat-structure) { + display: block; + } + + // stylelint-disable plugin/selector-bem-pattern + .mdc-list--dense & { + @include mdc-typography-baseline-top($dense-item-primary-text-baseline-height, $query); + @include mdc-typography-baseline-bottom($item-secondary-text-baseline-height, $query); + } + // stylelint-enable plugin/selector-bem-pattern + } -@mixin mdc-list-item-secondary-text-ink-color($color) { .mdc-list-item__secondary-text { + @include mdc-typography(body2, $query); + @include mdc-typography-overflow-ellipsis($query); + @include mdc-typography-baseline-top($item-secondary-text-baseline-height, $query); + + @include mdc-feature-targets($feat-structure) { + display: block; + } + + // stylelint-disable plugin/selector-bem-pattern + .mdc-list--dense & { + @include mdc-typography-baseline-top($item-secondary-text-baseline-height, $query); + + @include mdc-feature-targets($feat-structure) { + font-size: inherit; + } + } + // stylelint-enable plugin/selector-bem-pattern + } + + // stylelint-disable plugin/selector-bem-pattern + .mdc-list--dense .mdc-list-item { + @include mdc-feature-targets($feat-structure) { + height: 40px; + } + } + + .mdc-list--dense .mdc-list-item__graphic { + @include mdc-feature-targets($feat-structure) { + @include mdc-list-graphic-size_(20px); + } + } + + .mdc-list--avatar-list .mdc-list-item { + @include mdc-feature-targets($feat-structure) { + height: 56px; + } + } + + .mdc-list--avatar-list .mdc-list-item__graphic { + @include mdc-feature-targets($feat-structure) { + @include mdc-list-graphic-size_(40px); + + border-radius: 50%; + } + } + + .mdc-list--two-line .mdc-list-item__text { + @include mdc-feature-targets($feat-structure) { + align-self: flex-start; + } + } + + .mdc-list--two-line .mdc-list-item { + @include mdc-feature-targets($feat-structure) { + height: 72px; + } + } + + .mdc-list--two-line.mdc-list--dense .mdc-list-item, + .mdc-list--avatar-list.mdc-list--dense .mdc-list-item { + @include mdc-feature-targets($feat-structure) { + height: 60px; + } + } + + .mdc-list--avatar-list.mdc-list--dense .mdc-list-item__graphic { + @include mdc-feature-targets($feat-structure) { + @include mdc-list-graphic-size_(36px); + } + } + + // List items should support states by default, but it should be possible to opt out. + // Direct child combinator is necessary for non-interactive modifier on parent to not + // match this selector. + :not(.mdc-list--non-interactive) > :not(.mdc-list-item--disabled).mdc-list-item { + @include mdc-list-item-interactive-ripple_($query); + } + + // Override anchor tag styles for the use-case of a list being used for navigation + // stylelint-disable selector-max-type,selector-no-qualifying-type + a.mdc-list-item { + @include mdc-feature-targets($feat-structure) { + color: inherit; + text-decoration: none; + } + } + // stylelint-enable selector-max-type,selector-no-qualifying-type + + .mdc-list-divider { + @include mdc-feature-targets($feat-structure) { + height: 0; + margin: 0; + border: none; + border-bottom-width: 1px; + border-bottom-style: solid; + } + } + + // Note: ideally we'd be able to hoist this to the top-level `$feat-color`, but doing so + // will cause the `border` declaration on `.mdc-list-divider` above to override it. + @include mdc-list-divider-color($divider-color, $query); + + .mdc-list-divider--padded { + @include mdc-feature-targets($feat-structure) { + // Leave gaps on each side to match the padding on list items + margin: 0 $mdc-list-side-padding; + } + } + + .mdc-list-divider--inset { + @include mdc-feature-targets($feat-structure) { + @include mdc-rtl-reflexive-box(margin, left, $mdc-list-text-offset, ".mdc-list-group"); + + width: calc(100% - #{$mdc-list-text-offset}); + } + } + + .mdc-list-divider--inset.mdc-list-divider--padded { + @include mdc-feature-targets($feat-structure) { + width: calc(100% - #{$mdc-list-text-offset} - #{$mdc-list-side-padding}); + } + } + + .mdc-list-group { + @include mdc-feature-targets($feat-structure) { + // Cancel top/bottom padding on individual lists within group + .mdc-list { + padding: 0; + } + } + } + + .mdc-list-group__subheader { + $mdc-list-subheader-virtual-height: 3rem; + $mdc-list-subheader-leading: map-get(map-get($mdc-typography-styles, body1), line-height); + $mdc-list-subheader-margin: + ($mdc-list-subheader-virtual-height - $mdc-list-subheader-leading) / 2; + + @include mdc-typography(subtitle1, $query); + + @include mdc-feature-targets($feat-structure) { + margin: $mdc-list-subheader-margin $mdc-list-side-padding; + } + } +} + +@mixin mdc-list-item-primary-text-ink-color($color, $query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + + @include mdc-feature-targets($feat-color) { @include mdc-theme-prop(color, $color); } } -@mixin mdc-list-item-graphic-fill-color($color) { +@mixin mdc-list-item-secondary-text-ink-color($color, $query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + + .mdc-list-item__secondary-text { + @include mdc-feature-targets($feat-color) { + @include mdc-theme-prop(color, $color); + } + } +} + +@mixin mdc-list-item-graphic-fill-color($color, $query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + .mdc-list-item__graphic { - @include mdc-theme-prop(background-color, $color); + @include mdc-feature-targets($feat-color) { + @include mdc-theme-prop(background-color, $color); + } } } -@mixin mdc-list-item-graphic-ink-color($color) { +@mixin mdc-list-item-graphic-ink-color($color, $query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + .mdc-list-item__graphic { - @include mdc-theme-prop(color, $color); + @include mdc-feature-targets($feat-color) { + @include mdc-theme-prop(color, $color); + } } } -@mixin mdc-list-item-meta-ink-color($color) { +@mixin mdc-list-item-meta-ink-color($color, $query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + .mdc-list-item__meta { - @include mdc-theme-prop(color, $color); + @include mdc-feature-targets($feat-color) { + @include mdc-theme-prop(color, $color); + } } } -@mixin mdc-list-item-shape-radius($radius, $rtl-reflexive: false) { +@mixin mdc-list-item-shape-radius($radius, $rtl-reflexive: false, $query: mdc-feature-all()) { + $feat-structure: mdc-feature-create-target($query, structure); + .mdc-list-item { - @include mdc-shape-radius($radius, $rtl-reflexive); + @include mdc-feature-targets($feat-structure) { + @include mdc-shape-radius($radius, $rtl-reflexive); + } } } -@mixin mdc-list-divider-color($color) { +@mixin mdc-list-divider-color($color, $query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + .mdc-list-divider { - @include mdc-theme-prop(border-bottom-color, $color); + @include mdc-feature-targets($feat-color) { + @include mdc-theme-prop(border-bottom-color, $color); + } } } -@mixin mdc-list-group-subheader-ink-color($color) { +@mixin mdc-list-group-subheader-ink-color($color, $query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + .mdc-list-group__subheader { - @include mdc-theme-prop(color, $color); + @include mdc-feature-targets($feat-color) { + @include mdc-theme-prop(color, $color); + } } } @@ -77,6 +368,52 @@ // Private // +@mixin mdc-list-base_($query: mdc-feature-all()) { + $feat-color: mdc-feature-create-target($query, color); + $feat-structure: mdc-feature-create-target($query, structure); + $feat-typography: mdc-feature-create-target($query, typography); + + @include mdc-typography(subtitle1, $query); + + @include mdc-feature-targets($feat-typography) { + // According to the mocks and stickersheet, the line-height is + // adjusted to 24px for text content, same as for body1. + /* @alternate */ + line-height: map-get(map-get($mdc-typography-styles, body1), line-height); + } + + @include mdc-feature-targets($feat-structure) { + margin: 0; + padding: 8px 0; + list-style-type: none; + } + + @include mdc-list-item-primary-text-ink-color(text-primary-on-background, $query); +} + +@mixin mdc-list-item-base_ { + display: flex; + position: relative; + align-items: center; + justify-content: flex-start; + height: 48px; + padding: 0 $mdc-list-side-padding; + overflow: hidden; + + &:focus { + outline: none; + } +} + +// Ripple styles for an interactive list item (one that is enabled and inside an interactive list). +@mixin mdc-list-item-interactive-ripple_($query: mdc-feature-all()) { + @include mdc-ripple-surface($query); + @include mdc-ripple-radius-bounded($query: $query); + @include mdc-states(mdc-theme-prop-value(on-surface), false, $query); + @include mdc-states-activated(primary, false, $query); + @include mdc-states-selected(primary, false, $query); +} + // Sets the width and height of the graphic element, as well as calculates the margins for // the graphic element such that the text is always offset by 72px, which is defined within // the spec. diff --git a/packages/mdc-list/mdc-list.scss b/packages/mdc-list/mdc-list.scss index 5f7d47d7930..de0773efe68 100644 --- a/packages/mdc-list/mdc-list.scss +++ b/packages/mdc-list/mdc-list.scss @@ -18,255 +18,5 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -@import "@material/ripple/common"; -@import "@material/ripple/mixins"; -@import "@material/rtl/mixins"; -@import "@material/theme/functions"; -@import "@material/typography/mixins"; -@import "@material/typography/variables"; @import "./mixins"; -@import "./variables"; - -// postcss-bem-linter: define list - -.mdc-list { - @include mdc-typography(subtitle1); - @include mdc-list-item-primary-text-ink-color(text-primary-on-background); - - margin: 0; - padding: 8px 0; - - // According to the mocks and stickersheet, the line-height is adjusted to 24px for text content, - // same as for body1. - /* @alternate */ - line-height: map-get(map-get($mdc-typography-styles, body1), line-height); - list-style-type: none; -} - -@at-root { - @include mdc-list-item-secondary-text-ink-color(text-secondary-on-background); - @include mdc-list-item-graphic-fill-color(transparent); - @include mdc-list-item-graphic-ink-color(text-icon-on-background); - @include mdc-list-item-meta-ink-color(text-hint-on-background); -} - -.mdc-list--dense { - padding-top: 4px; - padding-bottom: 4px; - font-size: .812rem; -} - -// postcss-bem-linter: end - -// postcss-bem-linter: define list-item - -.mdc-list-item { - display: flex; - position: relative; - align-items: center; - justify-content: flex-start; - height: 48px; - padding: 0 $mdc-list-side-padding; - overflow: hidden; - - &:focus { - outline: none; - } -} - -// "Selected" is ephemeral and likely to change soon. E.g., selecting one or more photos to share in Google Photos. -// "Activated" is more permanent. E.g., the currently highlighted navigation destination in a drawer. -.mdc-list-item--selected, -.mdc-list-item--activated { - @include mdc-list-item-primary-text-ink-color(primary); - @include mdc-list-item-graphic-ink-color(primary); -} - -.mdc-list-item--disabled { - @include mdc-list-item-primary-text-ink-color(text-disabled-on-background); -} - -.mdc-list-item__graphic { - @include mdc-list-graphic-size_(24px); - - flex-shrink: 0; - align-items: center; - justify-content: center; - fill: currentColor; -} - -// Extra specificity is to override .material-icons display style if used in conjunction with mdc-list-item__graphic -// stylelint-disable plugin/selector-bem-pattern -.mdc-list .mdc-list-item__graphic { - display: inline-flex; -} -// stylelint-enable plugin/selector-bem-pattern - -.mdc-list-item__meta { - @include mdc-rtl-reflexive-property(margin, auto, 0, ".mdc-list-item"); -} - -.mdc-list-item__text { - @include mdc-typography-overflow-ellipsis; -} - -// Disable interaction on label elements that may automatically toggle corresponding checkbox / radio input. -.mdc-list-item__text[for] { - pointer-events: none; -} - -$mdc-list-item-primary-text-baseline-height_: 32px; -$mdc-list-item-secondary-text-baseline-height_: 20px; -$mdc-list-dense-item-primary-text-baseline-height_: 24px; - -.mdc-list-item__primary-text { - @include mdc-typography-overflow-ellipsis; - @include mdc-typography-baseline-top($mdc-list-item-primary-text-baseline-height_); - @include mdc-typography-baseline-bottom($mdc-list-item-secondary-text-baseline-height_); - - display: block; - - // stylelint-disable plugin/selector-bem-pattern - .mdc-list--dense & { - @include mdc-typography-baseline-top($mdc-list-dense-item-primary-text-baseline-height_); - @include mdc-typography-baseline-bottom($mdc-list-item-secondary-text-baseline-height_); - } - // stylelint-enable plugin/selector-bem-pattern -} - -.mdc-list-item__secondary-text { - @include mdc-typography(body2); - @include mdc-typography-overflow-ellipsis; - @include mdc-typography-baseline-top($mdc-list-item-secondary-text-baseline-height_); - - display: block; - - // stylelint-disable plugin/selector-bem-pattern - .mdc-list--dense & { - @include mdc-typography-baseline-top($mdc-list-item-secondary-text-baseline-height_); - - font-size: inherit; - } - // stylelint-enable plugin/selector-bem-pattern -} - -// stylelint-disable plugin/selector-bem-pattern -.mdc-list--dense .mdc-list-item { - height: 40px; -} - -.mdc-list--dense .mdc-list-item__graphic { - @include mdc-list-graphic-size_(20px); -} - -.mdc-list--avatar-list .mdc-list-item { - height: 56px; -} - -.mdc-list--avatar-list .mdc-list-item__graphic { - @include mdc-list-graphic-size_(40px); - - border-radius: 50%; -} - -.mdc-list--two-line .mdc-list-item__text { - align-self: flex-start; -} - -.mdc-list--two-line .mdc-list-item { - height: 72px; -} - -.mdc-list--two-line.mdc-list--dense .mdc-list-item { - height: 60px; -} - -.mdc-list--avatar-list.mdc-list--dense .mdc-list-item { - height: 60px; -} - -.mdc-list--avatar-list.mdc-list--dense .mdc-list-item__graphic { - @include mdc-list-graphic-size_(36px); -} - -// List items should support states by default, but it should be possible to opt out. -// Direct child combinator is necessary for non-interactive modifier on parent to not match this selector. -:not(.mdc-list--non-interactive) > :not(.mdc-list-item--disabled).mdc-list-item { - @include mdc-ripple-surface; - @include mdc-ripple-radius-bounded; - @include mdc-states; - @include mdc-states-activated(primary); - @include mdc-states-selected(primary); -} -// postcss-bem-linter: end - -// Override anchor tag styles for the use-case of a list being used for navigation -// stylelint-disable selector-max-type,selector-no-qualifying-type -a.mdc-list-item { - color: inherit; - text-decoration: none; -} -// stylelint-enable selector-max-type,selector-no-qualifying-type - -// postcss-bem-linter: define list-divider - -.mdc-list-divider { - height: 0; - margin: 0; - border: none; - border-bottom-width: 1px; - border-bottom-style: solid; -} - -@at-root { - $divider-color: if( - mdc-theme-tone($mdc-theme-background) == "dark", - $mdc-list-divider-color-on-dark-bg, - $mdc-list-divider-color-on-light-bg - ); - - @include mdc-list-divider-color($divider-color); -} - -.mdc-list-divider--padded { - // Leave gaps on each side to match the padding on list items - margin: 0 $mdc-list-side-padding; -} - -.mdc-list-divider--inset { - @include mdc-rtl-reflexive-box(margin, left, $mdc-list-text-offset, ".mdc-list-group"); - - width: calc(100% - #{$mdc-list-text-offset}); -} - -.mdc-list-divider--inset.mdc-list-divider--padded { - width: calc(100% - #{$mdc-list-text-offset} - #{$mdc-list-side-padding}); -} - -// postcss-bem-linter: end - -// postcss-bem-linter: define list-group - -.mdc-list-group { - // Cancel top/bottom padding on individual lists within group - .mdc-list { - padding: 0; - } -} - -.mdc-list-group__subheader { - $mdc-list-subheader-virtual-height: 3rem; - $mdc-list-subheader-leading: map-get(map-get($mdc-typography-styles, body1), line-height); - $mdc-list-subheader-margin: - ($mdc-list-subheader-virtual-height - $mdc-list-subheader-leading) / 2; - - @include mdc-typography(subtitle1); - - margin: $mdc-list-subheader-margin $mdc-list-side-padding; -} - -@at-root { - @include mdc-list-group-subheader-ink-color(text-primary-on-background); -} - -// postcss-bem-linter: end +@include mdc-list; diff --git a/packages/mdc-menu/_mixins.scss b/packages/mdc-menu/_mixins.scss index 764c8184426..fc54232ab0b 100644 --- a/packages/mdc-menu/_mixins.scss +++ b/packages/mdc-menu/_mixins.scss @@ -35,10 +35,8 @@ // Customize the menu-surface and contained list to match the mdc-menu styles. .mdc-menu { - @include mdc-feature-targets($feat-color) { - @include mdc-list-item-meta-ink-color(text-primary-on-background); - @include mdc-list-item-graphic-ink-color(text-primary-on-background); - } + @include mdc-list-item-meta-ink-color(text-primary-on-background, $query); + @include mdc-list-item-graphic-ink-color(text-primary-on-background, $query); @include mdc-feature-targets($feat-structure) { min-width: $mdc-menu-min-width; diff --git a/test/scss/feature-targeting.scss b/test/scss/feature-targeting.scss index 747c0f04095..fbfb4d72f42 100644 --- a/test/scss/feature-targeting.scss +++ b/test/scss/feature-targeting.scss @@ -9,6 +9,7 @@ @import "@material/ripple/mixins"; @import "@material/typography/mixins"; @import "@material/switch/mixins"; +@import "@material/list/mixins"; .mdc-test { // Button @@ -38,11 +39,22 @@ // Elevation @include mdc-elevation(0, $query: mdc-feature-any()); + // List + @include mdc-list($query: mdc-feature-any()); + @include mdc-list-item-primary-text-ink-color(red, $query: mdc-feature-any()); + @include mdc-list-item-secondary-text-ink-color(red, $query: mdc-feature-any()); + @include mdc-list-item-graphic-fill-color(red, $query: mdc-feature-any()); + @include mdc-list-item-graphic-ink-color(red, $query: mdc-feature-any()); + @include mdc-list-item-meta-ink-color(red, $query: mdc-feature-any()); + @include mdc-list-item-shape-radius(42, $rtl-reflexive: false, $query: mdc-feature-any()); + @include mdc-list-divider-color(red, $query: mdc-feature-any()); + @include mdc-list-group-subheader-ink-color(red, $query: mdc-feature-any()); + // Menu @include mdc-menu($query: mdc-feature-any()); @include mdc-menu-width(0, $query: mdc-feature-any()); - // Menu surface + // Menu Surface @include mdc-menu-surface($query: mdc-feature-any()); @include mdc-menu-surface-fill-color(surface, $query: mdc-feature-any()); @include mdc-menu-surface-ink-color(on-surface, $query: mdc-feature-any()); @@ -68,13 +80,6 @@ @include mdc-ripple-radius-bounded($query: mdc-feature-any()); @include mdc-ripple-radius-unbounded($query: mdc-feature-any()); - // Typography - @include mdc-typography-base($query: mdc-feature-any()); - @include mdc-typography(button, $query: mdc-feature-any()); - @include mdc-typography-overflow-ellipsis($query: mdc-feature-any()); - @include mdc-typography-baseline-top(0, $query: mdc-feature-any()); - @include mdc-typography-baseline-bottom(0, $query: mdc-feature-any()); - // Switch @include mdc-switch($query: mdc-feature-any()); @include mdc-switch-toggled-on-color(on-surface, $query: mdc-feature-any()); @@ -85,4 +90,11 @@ @include mdc-switch-toggled-on-thumb-color(on-surface, $query: mdc-feature-any()); @include mdc-switch-toggled-off-track-color(on-surface, $query: mdc-feature-any()); @include mdc-switch-toggled-off-thumb-color(on-surface, $query: mdc-feature-any()); + + // Typography + @include mdc-typography-base($query: mdc-feature-any()); + @include mdc-typography(button, $query: mdc-feature-any()); + @include mdc-typography-overflow-ellipsis($query: mdc-feature-any()); + @include mdc-typography-baseline-top(0, $query: mdc-feature-any()); + @include mdc-typography-baseline-bottom(0, $query: mdc-feature-any()); }