// // Copyright 2017 Google Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // stylelint-disable selector-class-pattern -- // Selector '.mdc-*' should only be used in this project. @use 'sass:math'; @use '@material/elevation/mixins' as elevation-mixins; @use '@material/feature-targeting/feature-targeting'; @use '@material/ripple/ripple'; @use '@material/ripple/ripple-theme'; @use '@material/rtl/rtl'; @use '@material/shape/mixins' as shape-mixins; @use '@material/theme/theme'; @use './variables'; @use '@material/theme/theme-color'; @use '@material/dom/mixins' as dom-mixins; // // Public // $ripple-target: '.mdc-card__ripple'; @mixin core-styles($query: feature-targeting.all()) { @include without-ripple($query); @include ripple($query); } @mixin static-styles($query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); $feat-color: feature-targeting.create-target($query, color); .mdc-card { @include feature-targeting.targets($feat-structure) { @include container-layout_; } // Transparent card border for high-contrast mode. &::after { @include dom-mixins.transparent-border($query: $query); @include feature-targeting.targets($feat-structure) { pointer-events: none; } } } .mdc-card--outlined { // Outlined card already displays border in high-contrast mode. // Overwriting styles set above to remove a duplicate border. &::after { @include feature-targeting.targets($feat-structure) { border: none; } } } .mdc-card__content { @include feature-targeting.targets($feat-structure) { border-radius: inherit; height: 100%; } } // // Media // .mdc-card__media { @include feature-targeting.targets($feat-structure) { position: relative; // Child element `__media-content` has `position: absolute` box-sizing: border-box; background-repeat: no-repeat; background-position: center; background-size: cover; } &::before { @include feature-targeting.targets($feat-structure) { display: block; content: ''; } } } .mdc-card__media:first-child { @include feature-targeting.targets($feat-structure) { border-top-left-radius: inherit; border-top-right-radius: inherit; } } .mdc-card__media:last-child { @include feature-targeting.targets($feat-structure) { border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; } } .mdc-card__media--square { @include media-aspect-ratio(1, 1, $query); } .mdc-card__media--16-9 { @include media-aspect-ratio(16, 9, $query); } .mdc-card__media-content { @include feature-targeting.targets($feat-structure) { position: absolute; top: 0; right: 0; bottom: 0; left: 0; box-sizing: border-box; } } // // Primary action // .mdc-card__primary-action { @include feature-targeting.targets($feat-structure) { @include container-layout_; position: relative; // Needed to prevent the ripple wash from overflowing the container in IE and Edge outline: none; color: inherit; text-decoration: none; cursor: pointer; overflow: hidden; } } .mdc-card__primary-action:first-child { @include feature-targeting.targets($feat-structure) { border-top-left-radius: inherit; border-top-right-radius: inherit; } } .mdc-card__primary-action:last-child { @include feature-targeting.targets($feat-structure) { border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; } } // // Action row // .mdc-card__actions { @include feature-targeting.targets($feat-structure) { @include actions-layout_; min-height: 52px; padding: 8px; } } .mdc-card__actions--full-bleed { @include feature-targeting.targets($feat-structure) { padding: 0; } } .mdc-card__action-buttons, .mdc-card__action-icons { @include feature-targeting.targets($feat-structure) { @include actions-layout_; } } .mdc-card__action-icons { @include feature-targeting.targets($feat-color) { @include theme.property(color, variables.$action-icon-color); } @include feature-targeting.targets($feat-structure) { flex-grow: 1; justify-content: flex-end; } } .mdc-card__action-buttons + .mdc-card__action-icons { @include feature-targeting.targets($feat-structure) { @include rtl.reflexive-box(margin, left, 16px); } } // // Action items // .mdc-card__action { @include feature-targeting.targets($feat-structure) { @include actions-layout_(inline-flex); justify-content: center; cursor: pointer; user-select: none; } &:focus { @include feature-targeting.targets($feat-structure) { outline: none; } } } // // Action buttons // .mdc-card__action--button { @include feature-targeting.targets($feat-structure) { @include rtl.reflexive-box(margin, right, 8px); padding: 0 8px; } &:last-child { @include feature-targeting.targets($feat-structure) { @include rtl.reflexive-box(margin, right, 0); } } } .mdc-card__actions--full-bleed .mdc-card__action--button { @include feature-targeting.targets($feat-structure) { justify-content: space-between; width: 100%; height: auto; max-height: none; margin: 0; padding: 8px 16px; @include rtl.ignore-next-line(); text-align: left; } @include rtl.rtl { @include feature-targeting.targets($feat-structure) { @include rtl.ignore-next-line(); text-align: right; } } } // // Action icons // .mdc-card__action--icon { @include feature-targeting.targets($feat-structure) { // Icon buttons are taller than buttons, so we need to adjust their margins to prevent the action row from // expanding. margin: -6px 0; // Same padding as mdc-icon-button. padding: 12px; } } .mdc-card__action--icon:not(:disabled) { @include feature-targeting.targets($feat-color) { @include theme.property(color, variables.$action-icon-color); } } } // This API is intended for use by frameworks that may want to separate the ripple-related styles from the other // card styles. It is recommended that most users use `mdc-card-core-styles` instead. @mixin without-ripple($query: feature-targeting.all()) { // postcss-bem-linter: define card $feat-color: feature-targeting.create-target($query, color); $feat-structure: feature-targeting.create-target($query, structure); // prettier-ignore @include elevation-mixins.overlay-common($query); // COPYBARA_COMMENT_THIS_LINE .mdc-card { @include shape-radius(variables.$shape-radius, $query: $query); @include fill-color(surface, $query); @include elevation-mixins.overlay-surface-position($query: $query); @include elevation-mixins.overlay-dimensions(100%, $query: $query); @include elevation-mixins.elevation(1, $query: $query); // Transparent card border for high-contrast mode. &::after { @include shape-radius(variables.$shape-radius, $query: $query); } } .mdc-card--outlined { @include elevation-mixins.elevation(0, $query: $query); @include outline(variables.$outline-color, $query: $query); } @include static-styles($query: $query); // postcss-bem-linter: end } // This API is intended for use by frameworks that may want to separate the ripple-related styles from the other // card styles. It is recommended that most users use `mdc-card-core-styles` instead. @mixin ripple($query: feature-targeting.all()) { @include ripple.common($query); // COPYBARA_COMMENT_THIS_LINE $feat-structure: feature-targeting.create-target($query, structure); .mdc-card__primary-action { @include ripple.surface($query, $ripple-target: $ripple-target); @include ripple.radius-bounded( $query: $query, $ripple-target: $ripple-target ); @include ripple-theme.states( $query: $query, $ripple-target: $ripple-target ); #{$ripple-target} { @include feature-targeting.targets($feat-structure) { box-sizing: content-box; height: 100%; overflow: hidden; left: 0; pointer-events: none; position: absolute; top: 0; width: 100%; } } @include ripple-theme.focus { &::after { @include dom-mixins.transparent-border( $border-width: 5px, $border-style: double, $query: $query ); } } } } @mixin fill-color($color, $query: feature-targeting.all()) { $feat-color: feature-targeting.create-target($query, color); @include feature-targeting.targets($feat-color) { @include theme.property(background-color, $color); } } @mixin outline( $color, $thickness: variables.$outline-width, $query: feature-targeting.all() ) { $feat-color: feature-targeting.create-target($query, color); $feat-structure: feature-targeting.create-target($query, structure); @include feature-targeting.targets($feat-structure) { @include theme.property(border-width, $thickness); border-style: solid; } @include feature-targeting.targets($feat-color) { @include theme.property(border-color, $color); } } @mixin shape-radius( $radius, $rtl-reflexive: false, $query: feature-targeting.all() ) { @include shape-mixins.radius($radius, $rtl-reflexive, $query: $query); } @mixin media-aspect-ratio($x, $y, $query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); &::before { @include feature-targeting.targets($feat-structure) { // This clever trick brought to you by: http://www.mademyday.de/css-height-equals-width-with-pure-css.html margin-top: math.percentage(math.div($y, $x)); } } } // // Private // @mixin container-layout_ { display: flex; flex-direction: column; box-sizing: border-box; } @mixin actions-layout_($display: flex) { display: $display; flex-direction: row; align-items: center; box-sizing: border-box; }