material-web/sass/_color.scss
Material Web Team 41d41cc278 chore: update repository for Material 3
PiperOrigin-RevId: 455635969
2022-06-17 16:42:04 +00:00

187 lines
5.8 KiB
SCSS

//
// Copyright 2022 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';
@use 'sass:string';
@use './assert';
@use './string-ext';
@use './var';
///
/// @example - scss
/// @debug color-var-hex-to-rgba(var(--foo-color-on-surface, #8ab4f8), 0.38);
/// // rgb(var(--foo-color-on-surface-rgb, 138, 180, 248), 0.38))
/// @param {String} $var - CSS custom property string in var(--foo, #hex) format.
/// @param {Number} $opacity - Opacity to mix with given color.
/// @return {String} Returns color string in rgb() format containing
/// CSS custom property for comma separated rgb color.
@function color-var-hex-to-rgba($var, $opacity) {
@if not var.is-var($var) {
@error '#{$var} is not a valid custom property.';
}
@if meta.type-of($opacity) != 'number' {
@error '#{$opacity} is not a valid number.';
}
$fallback: var.fallback($var);
// var(--foo-color-rgb, 31,31,31)
$var-rgb: var.create('#{var.name($var)}-rgb', hex-to-rgb($fallback));
@return string.unquote('rgb(#{$var-rgb}, #{$opacity})');
}
$_hex: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' 'a' 'b' 'c' 'd' 'e' 'f';
/// @example - scss
/// @debug _hex-to-dec('f8'); // 248
/// @param {String} $string - Hex number in string format.
/// @return {Number} Returns decimal number for given hex number.
@function _hex-to-dec($string) {
$string: string.to-lower-case($string);
$length: string.length($string);
$dec: 0;
@for $i from 1 through $length {
$factor: 1 + (15 * ($length - $i));
$index: list.index($_hex, string.slice($string, $i, $i));
$dec: $dec + $factor * ($index - 1);
}
@return $dec;
}
/// @example - scss
/// @debug hex-to-rgb('#8ab4f8'); // 138, 180, 248
/// @param {String} $string - CSS hex color in string format including '#'.
/// @return {String} Returns comma separated rgb values in string format.
@function hex-to-rgb($string) {
@if not string-ext.has-prefix($string, '#') {
@error '#{$string} is not in CSS hex color format.';
}
$string-lower: string.to-lower-case($string);
$r: '';
$g: '';
$b: '';
$length: string.length($string);
$max: if($length == 4, 1, 2);
// Check for length accuracy
@if $length != 4 and $length != 7 {
@return $string;
}
// Loop from the second character (omitting #)
@for $i from 2 through $length {
$c: string.slice($string-lower, $i, $i);
// If wrong character, return
@if list.index($_hex, $c) == null {
@return $string;
}
@if string.length($r) < $max {
$r: $r + $c;
} @else if string.length($g) < $max {
$g: $g + $c;
} @else if string.length($b) < $max {
$b: $b + $c;
}
}
@if $length == 4 {
$r: $r + $r;
$g: $g + $g;
$b: $b + $b;
}
@return #{_hex-to-dec($r), _hex-to-dec($g), _hex-to-dec($b)};
}
///
/// replace-as-rgba returns a map with the color key transformed to an RGBA
/// color value created by joining the color key value with the opacity key
/// value. The opacity key is removed from the map. This function is
/// non-destructive and returns a new instance of the given map. It should only
/// be used for disabled colors.
///
/// If $color is a var string then we would convert the color value to comma
/// separated rgb value.
///
/// @example
///. replace-as-rgba((
/// foo: red,
///. bar: 0.5
///. ), foo, bar) = (foo: rgba(255, 0, 0, 0.5))
/// @example
///. replace-as-rgba((
/// foo: var(--foo-color, #8ab4f8),
///. bar: 0.5
///. ), foo, bar) = (foo: rgb(var(--foo-color-rgb, 138, 180, 248), 0.5))
///
/// @param {Map} $map - the map with the given keys.
/// @param {String} $color-key - the color key in the map.
/// @param {String} $opacity-key - the opacity key in the map.
/// @return {Map} The map with the color key replaced by an RGBA representation.
@function replace-as-rgba($map, $color-key, $opacity-key) {
// Make a non-destructive copy of the map.
$out: map.merge($map, ());
$color: map.get($out, $color-key);
@if var.is-var($color) {
// TODO(b/213331407): Convert color from hex to rgba CSS color format to
// enable mixing rgb value with alpha using custom properties.
// (e.g., rgb(var(--foo-sys-color-on-surface-rgb, 31,31,31), 0.38))
// Remove once the attached bug is resolved.
$color: color-var-hex-to-rgba($color, map.get($out, $opacity-key));
} @else if meta.type-of($color) == 'color' {
$opacity: assert.is-type(map.get($out, $opacity-key), 'number');
$color: rgba($color, $opacity);
}
$out: map.set($out, $color-key, $color);
@return $out;
}
///
/// join-color-and-opacity-pairs returns a map with all given color and opacity
/// keys joined to create an RGBA color value. This function is non-destructive
/// and returns a new instance of the given map. It should only be used for
/// disabled colors.
///
/// @example
/// join-color-and-opacity-pairs((
/// foo-color: red,
/// foo-opacity: 0.2,
/// bar-color: green,
/// bar-opacity: 0.3,
/// ), (
/// (color-key: 'foo-color', opacity-key: 'foo-opacity'),
/// (color-key: 'bar-color', opacity-key: 'bar-opacity'),
/// )) = (foo-color: rgba(255, 0, 0, 0.2), bar-color: rgba(0, 255, 0, 0.3))
///
/// @param {Map} $map - the map with the values to modify.
/// @param {List<Map>} $color-opacity-key-pairs - the list of color/opacity key
/// pairs to join on the list.
/// @return {$Map} The map with the given color/opacity key pairs replaced by
/// RGBA representations.
///
@function join-color-and-opacity-pairs($map, $color-opacity-key-pairs) {
// Make a non-destructive copy of the map.
$out: map.merge($map, ());
@each $pair in $color-opacity-key-pairs {
$color-key: map.get($pair, color-key);
$opacity-key: map.get($pair, opacity-key);
$has-keys: map.has-key($out, $color-key) and
map.has-key($out, $opacity-key);
@if $has-keys {
$out: replace-as-rgba($out, $color-key, $opacity-key);
}
}
@return $out;
}