// Color Functions // -------------------------------------------------- @function color-error($color-value, $color-name: null) { $error-msg: " The value `#{$color-value}` must be a color. If you are setting the value as a map make sure both the base and contrast are defined as colors. For example: $colors: ( primary: #488aff, secondary: (base: #32db64, contrast: #000), );"; // If there was a name passed it means the value doesn't exist // so error that the value isn't defined @if ($color-name) { $error-msg: " The map color `#{$color-name}` is not defined. Please make sure the color exists in your `$colors` map. For example: $colors: ( #{$color-name}: #488aff );"; } @error $error-msg; @return null; } @function color-brightness($color-value) { @if (type-of($color-value) != color) { @return color-error($color-value); } @return (red($color-value) * .299 + green($color-value) * .587 + blue($color-value) * .114) / 255 * 100%; } @function color-inverse($color-value, $dark: #000, $light: #fff) { @if (type-of($color-value) != color) { @return color-error($color-value); } $brightness: color-brightness($color-value); $red: red($color-value); $green: green($color-value); @if ($brightness > 79) { @return $dark; } @if ($green > 240) { @return $dark; } @if ($red > 220 and $green > 180) { @return $dark; } @return $light; } // Pass dark and light colors based on the mode // this is mostly used for toolbar buttons/titles // // @param {String} $color-value - color to get the inverse of // @param {Boolean} $custom-contrast-mode - the mode to use // in order to pass the custom colors // // @return {Color} // -------------------------------------------------- @function mode-inverse($color-value, $custom-contrast-mode) { $dark: #000; $light: #fff; @if ($custom-contrast-mode == md) { $dark: #424242; $light: #fff; } @else if ($custom-contrast-mode == ios) { $dark: color($colors-ios, primary); $light: #fff; } @return color-inverse($color-value, $dark, $light); } @function color-shade($color-value, $amount:8%) { @if (type-of($color-value) != color) { @return color-error($color-value); } $lightness: lightness($color-value); $shade: #fff; @if ($lightness > 50) { $shade: #000; } @return mix($shade, $color-value, $amount); } // Copy Colors Map // -------------------------------------------------- @function copy-colors($colors-map) { @return map-merge($colors-map, ()); } // String Replace Function // -------------------------------------------------- @function str-replace($string, $search, $replace: "") { $index: str-index($string, $search); @if $index { @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); } @return $string; } // String Split Function // -------------------------------------------------- @function str-split($string, $separator) { // empty array/list $split-arr: (); // first index of separator in string $index: str-index($string, $separator); // loop through string @while $index != null { // get the substring from the first character to the separator $item: str-slice($string, 1, $index - 1); // push item to array $split-arr: append($split-arr, $item); // remove item and separator from string $string: str-slice($string, $index + 1); // find new index of separator $index: str-index($string, $separator); } // add the remaining string to list (the last item) $split-arr: append($split-arr, $string); @return $split-arr; } // Str extract between start and end // -------------------------------------------------- @function str-extract($string, $start, $end) { $start-index: str-index($string, $start); @if $start-index { $post: str-slice($string, $start-index + str-length($start)); $end-index: str-index($post, $end); @if $end-index { @return str-slice($post, 1, $end-index - 1); } } @return null; } // URL Encode Function // -------------------------------------------------- @function url-encode($val) { $spaces: str-replace($val, " ", "%20"); $encoded: str-replace($spaces, "#", "%23"); @return $encoded; } // Fetch nested keys // @param {Map} $map - Map // @param {Arglist} $keys - Keys to fetch // @return {*} // -------------------------------------------------- @function map-fetch($map, $keys...) { @each $key in $keys { $map: map-get($map, $key); } @return $map; } // Fetch map color value // @param {Map} $map - Map // @param {String} $color-name - Color name to get // @param {String} $color-key - Color key (optional), default base // @return {Color} // -------------------------------------------------- @function color($map, $color-name, $color-key:null) { // Get the value from $color-name in the map // this can be of type color or a map $color-value: map-get($map, $color-name); // If we were given a map we need to grab the value // of the key that is passed or the base key @if(type-of($color-value) == map) { @if($color-key) { $color-value: map-fetch($map, $color-name, $color-key); } @else { $color-value: map-fetch($map, $color-name, base); } } // If the value is a color then return the value // otherwise we need to error with the name @if (type-of($color-value) == color) { @return $color-value; } @return color-error($color-value, $color-name); } // Get the color map key based on the value // if it doesn't exist then return the value // -------------------------------------------------- @function color-key($colors, $value) { @each $color-name, $color-value in $colors { $base-value: color($colors, $color-name); @if ($base-value == $value) { @return map-get($colors, $color-name); } } @return $value; } // Fetch map color contrast // @param {Map} $colors - colors map // @param {String} $value - color value or color name // // Example values // -------------------------------------------------- // primary | #488aff | #444 // map key | map value | hex color not in map // -------------------------------------------------- // // @param {Boolean} $custom-contrast-mode - use custom // contrast function // @return {Color} // -------------------------------------------------- @function color-contrast($colors, $value, $custom-contrast-mode: null) { $color-value: null; // If the value is a color (e.g. #fff) // we need to call color-key to see if // it exists in the color map or not @if (type-of($value) == color) { $color-value: color-key($colors, $value); } @else { // If the value is a string (e.g. primary) // we want to get the value from the map // where it is the key $color-value: map-get($colors, $value); } // If the value is a map then get the contrast // from the map (e.g. (base: #488aff, contrast: blue)) @if (type-of($color-value) == map) { // If the map has the contrast key then use that // otherwise it is a map with just a base so get // the inverse of that base color @if map-has-key($color-value, contrast) { $color-value: map-get($color-value, contrast); } @else { $color-value: color-inverse(map-get($color-value, base)); } } @elseif ($custom-contrast-mode) { // If a mode was passed we need to call // the custom inverse function to get the inverse // color based on the mode $color-value: mode-inverse($color-value, $custom-contrast-mode); } @else { // Otherwise we were passed a color and can use the // function to get the inverse of that color // (e.g. #f4f4f4) $color-value: color-inverse($color-value); } // If the final value being returned is not a color // we should error @if (type-of($color-value) != color) { @return color-error($color-value); } @return $color-value; } // Create a list using the colors map // @param {Map} $colors - colors map // @return {List} $color-name, $color-base, $color-contrast // ---------------------------------------------------------- @function get-colors($colors, $custom-contrast-mode: null) { $colors-list: (); @each $color-name, $color-value in $colors { $color-base: null; $color-contrast: null; @if(type-of($color-value) == map) { $color-base: map-get($color-value, base); $color-contrast: map-get($color-value, contrast); } @else { $color-base: $color-value; $color-contrast: color-contrast($colors, $color-value, $custom-contrast-mode); } $colors-list: append($colors-list, ($color-name, $color-base, $color-contrast), comma); } @return $colors-list; }