// // Copyright 2018 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. // // Selector '.mdc-*' should only be used in this project. // stylelint-disable selector-class-pattern @use 'sass:list'; @use '@material/theme/custom-properties'; @use '@material/theme/theme'; @use '@material/shape/functions' as shape-functions; @use '@material/shape/mixins' as shape-mixins; @use '@material/floating-label/mixins' as floating-label-mixins; @use '@material/feature-targeting/feature-targeting'; @use '@material/rtl/rtl'; @use './variables'; @mixin core-styles($query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); .mdc-notched-outline { @include base_($query); &__leading, &__notch, &__trailing { @include feature-targeting.targets($feat-structure) { box-sizing: border-box; height: 100%; border-top: variables.$border-width solid; border-bottom: variables.$border-width solid; pointer-events: none; } } &__leading { @include feature-targeting.targets($feat-structure) { @include rtl.reflexive-property( border, variables.$border-width solid, none ); width: variables.$leading-width; } } &__trailing { @include feature-targeting.targets($feat-structure) { @include rtl.reflexive-property( border, none, variables.$border-width solid ); flex-grow: 1; } } &__notch { @include feature-targeting.targets($feat-structure) { flex: 0 0 auto; width: auto; max-width: calc(100% - #{variables.$leading-width} * 2); } } .mdc-floating-label { @include feature-targeting.targets($feat-structure) { display: inline-block; position: relative; max-width: 100%; } } .mdc-floating-label--float-above { @include feature-targeting.targets($feat-structure) { text-overflow: clip; } } &--upgraded .mdc-floating-label--float-above { @include feature-targeting.targets($feat-structure) { max-width: calc(100% / 0.75); } } } .mdc-notched-outline--notched { .mdc-notched-outline__notch { @include feature-targeting.targets($feat-structure) { @include rtl.reflexive-box(padding, right, 8px); border-top: none; } } } .mdc-notched-outline--no-label { .mdc-notched-outline__notch { @include feature-targeting.targets($feat-structure) { display: none; } } } } @mixin color($color, $query: feature-targeting.all()) { $feat-color: feature-targeting.create-target($query, color); .mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing { @include feature-targeting.targets($feat-color) { @include theme.property(border-color, $color); } } } @mixin stroke-width($width, $query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); .mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing { @include feature-targeting.targets($feat-structure) { border-width: $width; } } } /// /// Adds top offset to compensate for border width box size when it is notched. /// Use this when floating label is aligned to center to prevent label jump on focus. /// @param {Number} $stroke-width Stroke width of notched outline that needs to be offset. /// @mixin notch-offset($stroke-width, $query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); .mdc-notched-outline--notched .mdc-notched-outline__notch { @include feature-targeting.targets($feat-structure) { padding-top: $stroke-width; } } } @mixin shape-radius( $radius, $rtl-reflexive: false, $component-height: null, $query: feature-targeting.all() ) { $feat-structure: feature-targeting.create-target($query, structure); // Resolve the radius relative to the notched outline component's height. The // component should provide its current height from its density. The resolved // radius allows percentage radii to be converted to pixels. $resolved-radius: shape-functions.resolve-radius( $radius, $component-height: $component-height ); // Grab the top-left radius. We'll need it to adjust the leading for the // label notch if the resulting radius shape is larger than the default // leading. $top-left-radius: list.nth( shape-functions.unpack-radius($resolved-radius), 1 ); $top-left-is-custom-prop: custom-properties.is-custom-prop($top-left-radius); $top-left-radius-px: $top-left-radius; @if ($top-left-is-custom-prop) { $top-left-radius-px: custom-properties.get-fallback($top-left-radius); } .mdc-notched-outline__leading { // mask the leading to apply the top-left and bottom-left corners @include shape-mixins.radius( shape-functions.mask-radius($radius, 1 0 0 1), $rtl-reflexive: true, $component-height: $component-height, $query: $query ); @include feature-targeting.targets($feat-structure) { @if ($top-left-radius-px > variables.$leading-width) { // If the radius is bigger than the default leading width, we need to // increase the leading width width: $top-left-radius-px; @if ($top-left-is-custom-prop) { // The radius may be a custom property, in which case the above width // is the IE11 fallback value. /* @alternate */ } } @if ($top-left-is-custom-prop) { // If the top-left radius is dynamic, the width of the leading is // the max of whichever is larger: the default leading width or the // value of the custom property. $var: custom-properties.create-var($top-left-radius); @supports (top: max(0%)) { width: max(#{variables.$leading-width}, #{$var}); } } } } // Similar to above, adjust the max-width of the notch if we adjusted the // leading's width. .mdc-notched-outline__notch { @include feature-targeting.targets($feat-structure) { @if ($top-left-radius-px > variables.$leading-width) { max-width: calc(100% - #{$top-left-radius-px} * 2); @if ($top-left-is-custom-prop) { /* @alternate */ } } @if ($top-left-is-custom-prop) { $var: custom-properties.create-var($top-left-radius); @supports (top: max(0%)) { max-width: calc(100% - max(#{variables.$leading-width}, #{$var}) * 2); } } } } .mdc-notched-outline__trailing { // mask the leading to apply the top-right and bottom-right corners @include shape-mixins.radius( shape-functions.mask-radius($radius, 0 1 1 0), $rtl-reflexive: true, $component-height: $component-height, $query: $query ); } } @mixin floating-label-float-position( $positionY, $positionX: 0%, $scale: 0.75, $query: feature-targeting.all() ) { $feat-structure: feature-targeting.create-target($query, structure); @include floating-label-mixins.float-position( $positionY + variables.$label-adjust, $positionX, 1, $query: $query ); .mdc-floating-label--float-above { @include feature-targeting.targets($feat-structure) { font-size: ($scale * 1rem); } } // Two selectors to ensure we select the appropriate class when applied from this component or a parent component. &.mdc-notched-outline--upgraded, .mdc-notched-outline--upgraded { @include floating-label-mixins.float-position( $positionY, $positionX, $scale, $query: $query ); // stylelint-disable-next-line no-descending-specificity .mdc-floating-label--float-above { @include feature-targeting.targets($feat-structure) { font-size: 1rem; } } } } /// /// Sets floating label position in notched outline when label is afloat. /// /// @param {Number} $positionY Absolute Y-axis position in `px`. /// @param {Number} $positionX Absolute X-axis position in `px`. Defaults to `0`. /// @param {Number} $scale Defaults to `.75`. /// /// @todo Replace mixin `mdc-notched-outline-floating-label-float-position` with this mixin when floating label is /// center aligned in all the places. /// @mixin floating-label-float-position-absolute( $positionY, $positionX: 0, $scale: 0.75, $query: feature-targeting.all() ) { $feat-structure: feature-targeting.create-target($query, structure); @include floating-label-mixins.float-position( $positionY + variables.$label-adjust-absolute, $positionX, 1, $query: $query ); .mdc-floating-label--float-above { @include feature-targeting.targets($feat-structure) { font-size: ($scale * 1rem); } } // Two selectors to ensure we select the appropriate class when applied from this component or a parent component. &.mdc-notched-outline--upgraded, .mdc-notched-outline--upgraded { @include floating-label-mixins.float-position( $positionY, $positionX, $scale, $query: $query ); // stylelint-disable-next-line no-descending-specificity .mdc-floating-label--float-above { @include feature-targeting.targets($feat-structure) { font-size: 1rem; } } } } /// /// Sets the max-width for the notch /// /// @param {Number} $max-width Max-width for the notch /// @mixin notch-max-width($max-width, $query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch { @include feature-targeting.targets($feat-structure) { max-width: $max-width; } } } // // Private // @mixin base_($query) { $feat-structure: feature-targeting.create-target($query, structure); @include feature-targeting.targets($feat-structure) { display: flex; position: absolute; top: 0; right: 0; left: 0; box-sizing: border-box; width: 100%; max-width: 100%; height: 100%; @include rtl.ignore-next-line(); text-align: left; pointer-events: none; @include rtl.rtl { @include rtl.ignore-next-line(); text-align: right; } } }