// // 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. // @use 'sass:list'; @use 'sass:meta'; @use 'sass:selector'; @use '@material/theme/gss'; @use '@material/theme/selector-ext'; @use '@material/theme/theme'; $include: true !default; /// Creates a rule that will be applied when a component is within the context /// of an RTL layout. /// /// @example - scss /// .mdc-foo { /// padding-left: 4px; /// /// @include rtl { /// padding-left: auto; /// padding-right: 4px; /// } /// } /// /// @example - css /// .mdc-foo { /// padding-left: 4px; /// } /// /// [dir="rtl"] .mdc-foo, /// .mdc-foo[dir="rtl"] { /// padding-left: auto; /// padding-right: 4px; /// } /// /// Note that this mixin works by checking for an ancestor element with /// `[dir="rtl"]`. As a result, nested `dir` values are not supported: /// /// @example - html /// /// ///
///
Styled incorrectly as RTL!
///
/// /// /// In the future, selectors such as the `:dir` pseudo-class /// (http://mdn.io/css/:dir) will help us mitigate this. /// /// @content Content to be styled in an RTL context. @mixin rtl() { @if ($include) { $dir-rtl: '[dir=rtl]'; $rtl-selectors: list.join( selector.nest($dir-rtl, &), selector-ext.append-strict(&, $dir-rtl) ); @at-root { #{$rtl-selectors} { /*rtl:begin:ignore*/ @content; /*rtl:end:ignore*/ } } } } // Takes a base box-model property name (`margin`, `border`, `padding`, etc.) along with a // default direction (`left` or `right`) and value, and emits rules which apply the given value to the // specified direction by default and the opposite direction in RTL. // // For example: // // ```scss // .mdc-foo { // @include rtl-reflexive-box(margin, left, 8px); // } // ``` // // is equivalent to: // // ```scss // .mdc-foo { // margin-left: 8px; // margin-right: 0; // // @include rtl { // margin-left: 0; // margin-right: 8px; // } // } // ``` // // whereas: // // ```scss // .mdc-foo { // @include rtl-reflexive-box(margin, right, 8px); // } // ``` // // is equivalent to: // // ```scss // .mdc-foo { // margin-left: 0; // margin-right: 8px; // // @include rtl { // margin-left: 8px; // margin-right: 0; // } // } // ``` // // You can also pass an optional 4th `$root-selector` argument which will be forwarded to `mdc-rtl`, // e.g. `@include rtl-reflexive-box(margin, left, 8px, '.mdc-component')`. // // Note that this function will always zero out the original value in an RTL context. // If you're trying to flip the values, use `mdc-rtl-reflexive-property()` instead. @mixin reflexive-box( $base-property, $default-direction, $value, $replace: null ) { @if (list.index((right, left), $default-direction) == null) { @error "Invalid default direction: '#{$default-direction}'. Please specifiy either 'right' or 'left'."; } $left-value: $value; $right-value: 0; @if ($default-direction == right) { $left-value: 0; $right-value: $value; } @include reflexive-property( $base-property, $left-value, $right-value, $replace: $replace ); } // Takes a base property and emits rules that assign -left to and // -right to in a LTR context, and vice versa in a RTL context. // For example: // // ```scss // .mdc-foo { // @include rtl-reflexive-property(margin, auto, 12px); // } // ``` // // is equivalent to: // // ```scss // .mdc-foo { // margin-left: auto; // margin-right: 12px; // // @include rtl { // margin-left: 12px; // margin-right: auto; // } // } // ``` // // An optional 4th `$root-selector` argument can be given, which will be passed to `mdc-rtl`. @mixin reflexive-property( $base-property, $left-value, $right-value, $replace: null ) { $prop-left: #{$base-property}-left; $prop-right: #{$base-property}-right; @include reflexive( $prop-left, $left-value, $prop-right, $right-value, $replace: $replace ); } // Takes an argument specifying a horizontal position property (either 'left' or 'right') as well // as a value, and applies that value to the specified position in a LTR context, and flips it in a // RTL context. For example: // // ```scss // .mdc-foo { // @include rtl-reflexive-position(left, 0); // } // ``` // // is equivalent to: // // ```scss // .mdc-foo { // left: 0; // right: initial; // // @include rtl { // left: initial; // right: 0; // } // } // ``` // // An optional third $root-selector argument may also be given, which is passed to `mdc-rtl`. @mixin reflexive-position($position-property, $value, $replace: null) { @if (list.index((right, left), $position-property) == null) { @error "Invalid position #{position-property}. Please specifiy either right or left"; } // TODO: 'initial' is not supported in IE 11. https://caniuse.com/#feat=css-initial-value $left-value: $value; $right-value: initial; @if ($position-property == right) { $right-value: $value; $left-value: initial; } @include reflexive( left, $left-value, right, $right-value, $replace: $replace ); } // Takes pair of properties with values as arguments and flips it in RTL context. // For example: // // ```scss // .mdc-foo { // @include rtl-reflexive(left, 2px, right, 5px); // } // ``` // // is equivalent to: // // ```scss // .mdc-foo { // left: 2px; // right: 5px; // // @include rtl { // right: 2px; // left: 5px; // } // } // ``` // // An optional fifth `$root-selector` argument may also be given, which is passed to `mdc-rtl`. @mixin reflexive( $left-property, $left-value, $right-property, $right-value, $replace: null ) { $left-replace: null; $right-replace: null; @if $replace { @if meta.type-of($left-value) == 'string' { $left-replace: $replace; } @if meta.type-of($right-value) == 'string' { $right-replace: $replace; } @if $left-replace == null and $right-replace == null { @error 'mdc-rtl: $replace may only be used with strings but neither left nor right values are strings.'; } // If any replacements are null, treat the entire value as null (do not // emit anything). @each $name, $replacement in $replace { @if $replacement == null { $left-value: null; $right-value: null; } } } // Do not emit if either value are null @if $left-value and $right-value { @include _property($left-property, $left-value, $replace: $left-replace); @include _property($right-property, $right-value, $replace: $right-replace); @include rtl { @include _property( $left-property, $right-value, $replace: $right-replace ); @include _property($right-property, $left-value, $replace: $left-replace); } } } /// /// Adds RTL ignore annotation when `$mdc-rtl-include` is true. /// @mixin ignore-next-line() { @include gss.annotate( ( noflip: $include, ) ); } /// /// Adds `@noflip` annotation when `$mdc-rtl-include` is true. /// /// @param {String} $property /// @param {String} $value /// @param {Map} $replace /// @mixin _property($property, $value, $replace: null) { @include theme.property( $property, $value, $replace: $replace, $gss: (noflip: $include) ); }