// // 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. // // Selector '.mdc-*' should only be used in this project. // stylelint-disable selector-class-pattern @use 'sass:list'; @use 'sass:map'; @use 'sass:string'; @use '@material/feature-targeting/feature-targeting'; @use '@material/theme/theme'; @function set-styles_($base-styles, $scale-styles, $override-styles) { @each $style, $style-props in $scale-styles { // Merge base properties for all styles. $style-props: map.merge($base-styles, $style-props); // Merge overrides onto each style. $style-props: map.merge($style-props, map.get($override-styles, $style)); // Override original styles with new styles. $scale-styles: map.merge($scale-styles, (#{$style}: $style-props)); } @return $scale-styles; } @function get-letter-spacing_($tracking, $font-size) { @return $tracking / ($font-size * 16) * 1em; } @function pxToRem($px) { @return $px / 16px * 1rem; } $font-family: string.unquote('Roboto, sans-serif') !default; // Override styles $styles-headline1: () !default; $styles-headline2: () !default; $styles-headline3: () !default; $styles-headline4: () !default; $styles-headline5: () !default; $styles-headline6: () !default; $styles-subtitle1: () !default; $styles-subtitle2: () !default; $styles-body1: () !default; $styles-body2: () !default; $styles-caption: () !default; $styles-button: () !default; $styles-overline: () !default; $base: ( font-family: $font-family, ) !default; $font-weight-values: ( thin: 100, light: 300, regular: 400, medium: 500, bold: 700, black: 900, ) !default; $styles: set-styles_( $base, ( headline1: ( font-size: pxToRem(96px), line-height: pxToRem(96px), font-weight: map.get($font-weight-values, light), letter-spacing: get-letter-spacing_(-1.5, 6), text-decoration: inherit, text-transform: inherit, ), headline2: ( font-size: pxToRem(60px), line-height: pxToRem(60px), font-weight: map.get($font-weight-values, light), letter-spacing: get-letter-spacing_(-0.5, 3.75), text-decoration: inherit, text-transform: inherit, ), headline3: ( font-size: pxToRem(48px), line-height: pxToRem(50px), font-weight: map.get($font-weight-values, regular), letter-spacing: normal, text-decoration: inherit, text-transform: inherit, ), headline4: ( font-size: pxToRem(34px), line-height: pxToRem(40px), font-weight: map.get($font-weight-values, regular), letter-spacing: get-letter-spacing_(0.25, 2.125), text-decoration: inherit, text-transform: inherit, ), headline5: ( font-size: pxToRem(24px), line-height: pxToRem(32px), font-weight: map.get($font-weight-values, regular), letter-spacing: normal, text-decoration: inherit, text-transform: inherit, ), headline6: ( font-size: pxToRem(20px), line-height: pxToRem(32px), font-weight: map.get($font-weight-values, medium), letter-spacing: get-letter-spacing_(0.25, 1.25), text-decoration: inherit, text-transform: inherit, ), subtitle1: ( font-size: pxToRem(16px), line-height: pxToRem(28px), font-weight: map.get($font-weight-values, regular), letter-spacing: get-letter-spacing_(0.15, 1), text-decoration: inherit, text-transform: inherit, ), subtitle2: ( font-size: pxToRem(14px), line-height: pxToRem(22px), font-weight: map.get($font-weight-values, medium), letter-spacing: get-letter-spacing_(0.1, 0.875), text-decoration: inherit, text-transform: inherit, ), body1: ( font-size: pxToRem(16px), line-height: pxToRem(24px), font-weight: map.get($font-weight-values, regular), letter-spacing: get-letter-spacing_(0.5, 1), text-decoration: inherit, text-transform: inherit, ), body2: ( font-size: pxToRem(14px), line-height: pxToRem(20px), font-weight: map.get($font-weight-values, regular), letter-spacing: get-letter-spacing_(0.25, 0.875), text-decoration: inherit, text-transform: inherit, ), caption: ( font-size: pxToRem(12px), line-height: pxToRem(20px), font-weight: map.get($font-weight-values, regular), letter-spacing: get-letter-spacing_(0.4, 0.75), text-decoration: inherit, text-transform: inherit, ), button: ( font-size: pxToRem(14px), line-height: pxToRem(36px), font-weight: map.get($font-weight-values, medium), letter-spacing: get-letter-spacing_(1.25, 0.875), text-decoration: none, text-transform: uppercase, ), overline: ( font-size: pxToRem(12px), line-height: pxToRem(32px), font-weight: map.get($font-weight-values, medium), letter-spacing: get-letter-spacing_(2, 0.75), text-decoration: none, text-transform: uppercase, ), ), ( headline1: $styles-headline1, headline2: $styles-headline2, headline3: $styles-headline3, headline4: $styles-headline4, headline5: $styles-headline5, headline6: $styles-headline6, subtitle1: $styles-subtitle1, subtitle2: $styles-subtitle2, body1: $styles-body1, body2: $styles-body2, caption: $styles-caption, button: $styles-button, overline: $styles-overline, ) ) !default; @mixin core-styles($query: feature-targeting.all()) { .mdc-typography { @include base($query: $query); } @each $style in map.keys($styles) { .mdc-typography--#{$style} { @include typography($style, $query: $query); } } } @mixin base($query: feature-targeting.all()) { $feat-typography: feature-targeting.create-target($query, typography); @include smooth-font($query: $query); @include feature-targeting.targets($feat-typography) { @include theme.prop( font-family, ( varname: --mdc-typography-font-family, fallback: map.get($base, 'font-family'), ) ); } } @mixin typography($style, $query: feature-targeting.all(), $exclude-props: ()) { $feat-typography: feature-targeting.create-target($query, typography); $style-props: map.get($styles, $style); @if not map.has-key($styles, $style) { @error "Invalid style specified! #{$style} doesn't exist. Choose one of #{map.keys($styles)}"; } @include smooth-font($query: $query); @include feature-targeting.targets($feat-typography) { @each $key, $value in $style-props { @if list.index($exclude-props, $key) == null { $fallback: $value; @if $key == 'font-family' { // Each style has its own font-family custom property, but should // fallback to a generic font-family property. This allows // customizing the font-family for all styles or only specific ones. $fallback: ( varname: --mdc-typography-font-family, fallback: $fallback, ); } @include theme.prop( $key, ( varname: --mdc-typography-#{$style}-#{$key}, fallback: $fallback, ) ); } } } } /// Applies antialiasing via font-smoothing to text. @mixin smooth-font($query: feature-targeting.all()) { $feat-typography: feature-targeting.create-target($query, typography); @include feature-targeting.targets($feat-typography) { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; } } // Element must be `display: block` or `display: inline-block` for this to work. @mixin overflow-ellipsis($query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); @include feature-targeting.targets($feat-structure) { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } } /// Sets a container's baseline that text content will align to. /// /// If the `$display` is set to a flexbox display, only `$top` baseline may be /// set. A separate element must be added as a child of the container with a /// `$bottom` baseline. /// /// @param {Number} $top - the distance from the top of the container to the /// text's baseline. /// @param {Number} $bottom - the distance from the text's baseline to the /// bottom of the container. /// @param {String} $display - the display type of the container. May be `flex`, /// `inline-flex`, `block`, or `inline-block`. @mixin baseline( $top: 0, $bottom: 0, $display: block, $query: feature-targeting.all() ) { $validDisplayTypes: (flex, inline-flex, block, inline-block); @if list.index($validDisplayTypes, $display) == null { @error "mdc-typography: invalid display specified! #{$display} must be one of #{$validDisplayTypes}"; } $isFlexbox: $display == 'flex' or $display == 'inline-flex'; $feat-structure: feature-targeting.create-target($query, structure); @include feature-targeting.targets($feat-structure) { display: $display; @if $isFlexbox { align-items: baseline; } } @if $top > 0 { @include baseline-top($top, $query: $query); } @if $bottom > 0 { @if $isFlexbox { @error "mdc-typography: invalid baseline with display type. #{$display} cannot specifiy $bottom. Add a separate child element with its own $bottom."; } @include baseline-bottom($bottom, $query: $query); } } /// Sets the baseline of flow text content. /// /// Separate `$top` and `$bottom` baselines may be specified. You should ensure /// that the `$top` baseline matches the previous text content's $bottom /// baseline to ensure text is positioned appropriately. /// /// See go/css-baseline for reference on how this mixin works. /// /// This is intended for text flow content only (e.g. `

`, `

`, ``, /// or `

` with only text content). Use `baseline()` to set the baseline of /// containers that are flexbox or have non-flow content children. /// /// @param {Number} $top - the distance from the top of the container to the /// text's baseline. /// @param {Number} $bottom - the distance from the text's baseline to the /// bottom of the container. /// @param {Boolean} $lineHeight - the line-height to use for the text. This /// is the distance between baselines of multiple lines of text. /// @param {String} $display - the display type of the container. May be `block` /// or `inline-block`. @mixin text-baseline( $top: 0, $bottom: 0, $display: block, $lineHeight: normal, $query: feature-targeting.all() ) { $validDisplayTypes: (block, inline-block); @if list.index($validDisplayTypes, $display) == null { @error "mdc-typography: invalid display specified! #{$display} must be one of #{$validDisplayTypes}"; } $feat-structure: feature-targeting.create-target($query, structure); @include baseline( $display: $display, $top: $top, $bottom: $bottom, $query: $query ); @include feature-targeting.targets($feat-structure) { @if $top > 0 { margin-top: 0; /* @alternate */ line-height: #{$lineHeight}; } @if $bottom > 0 { margin-bottom: -1 * $bottom; } } } /// Creates a baseline strut from the top of a container. This mixin is for /// advanced users, prefer `baseline()`. /// /// @param {Number} $distance - The distance from the top of the container to /// the text's baseline. @mixin baseline-top($distance, $query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); &::before { @include feature-targeting.targets($feat-structure) { @include baseline-strut_($distance); vertical-align: 0; } } } /// Creates a baseline strut from the baseline to the bottom of a container. /// This mixin is for advanced users, prefer `baseline()`. /// /// @param {Number} $distance - The distance from the text's baseline to the /// bottom of the container. @mixin baseline-bottom($distance, $query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); &::after { @include feature-targeting.targets($feat-structure) { @include baseline-strut_($distance); vertical-align: -1 * $distance; } } } /// Adds an invisible, zero-width prefix to a container's text. /// This ensures that the baseline is always where the text would be, instead /// of defaulting to the container bottom when text is empty. Do not use this /// mixin if the `baseline` mixin is already applied. @mixin zero-width-prefix($query: feature-targeting.all()) { $feat-structure: feature-targeting.create-target($query, structure); &::before { @include feature-targeting.targets($feat-structure) { content: '\200b'; } } } @mixin baseline-strut_($distance) { display: inline-block; width: 0; height: $distance; content: ''; }