358 lines
8.3 KiB
SCSS
358 lines
8.3 KiB
SCSS
//
|
|
// 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
|
|
/// <html dir="rtl">
|
|
/// <!-- ... -->
|
|
/// <div dir="ltr">
|
|
/// <div class="mdc-foo">Styled incorrectly as RTL!</div>
|
|
/// </div>
|
|
/// </html>
|
|
///
|
|
/// 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 <base-property>-left to <left-value> and
|
|
// <base-property>-right to <right-value> 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)
|
|
);
|
|
}
|