|
@function is-color($color) { |
|
@if (type-of($color) == color) { |
|
@return true; |
|
} |
|
@return false; |
|
} |
|
|
|
@function count-occurrences($string, $search) { |
|
$searchIndex: str-index($string, $search); |
|
$searchCount: 0; |
|
@while $searchIndex { |
|
$searchCount: $searchCount + 1; |
|
$string: str-slice($string, $searchIndex + 1); |
|
$searchIndex: str-index($string, $search); |
|
} |
|
@return $searchCount; |
|
} |
|
|
|
@function str-is-between($string, $first, $last) { |
|
$firstCount: count-occurrences($string, $first); |
|
$lastCount: count-occurrences($string, $last); |
|
@return $firstCount == $lastCount; |
|
} |
|
|
|
@function recursive-color($color, $index: 0) { |
|
$indices: ( |
|
0: h, |
|
1: s, |
|
2: l, |
|
3: a |
|
); |
|
// find end of part |
|
$end: str-index($color, ','); |
|
@while ($end and not str-is-between(str-slice($color, 0, $end - 1), '(', ')')) { |
|
$newEnd: str-index(str-slice($color, $end + 1), ','); |
|
@if (not $newEnd) { |
|
$newEnd: 0; |
|
} |
|
$end: 2 + $end + $newEnd; |
|
} |
|
@if ($end) { |
|
$part: str-slice($color, 0, $end - 1); |
|
$value: map-merge( |
|
( |
|
map-get($indices, $index): $part |
|
), |
|
recursive-color(str-slice($color, $end + 1), $index + 1) |
|
); |
|
@return $value; |
|
} |
|
@return (); |
|
} |
|
|
|
@function to-hsl($color) { |
|
$c: inspect($color); |
|
|
|
$h: 0; |
|
$s: 0; |
|
$l: 0; |
|
$a: 1; |
|
|
|
@if (is-color($color)) { |
|
// std color |
|
$h: hue($color); |
|
$s: saturation($color); |
|
$l: lightness($color); |
|
$a: alpha($color); |
|
|
|
@return (h: $h, s: $s, l: $l, a: $a); |
|
} |
|
|
|
@if (str-slice($c, 0, 3) == 'var') { |
|
// var(--color) |
|
$commaPos: str-index($c, ','); |
|
$end: -2; |
|
@if ($commaPos) { |
|
$end: $commaPos - 1; |
|
} |
|
$var: str-slice($c, 7, $end); |
|
|
|
$h: var(--#{$var}-h); |
|
$s: var(--#{$var}-s); |
|
$l: var(--#{$var}-l); |
|
$a: var(--#{$var}-a, 1); |
|
|
|
@return (h: $h, s: $s, l: $l, a: $a); |
|
} |
|
|
|
@if ($c == '0') { |
|
@return (h: $h, s: $s, l: $l, a: $a); |
|
} |
|
|
|
// color is (maybe complex) calculated color |
|
// e.g.: hsla(calc((var(--white-h) + var(--primary-h)) / 2), calc((var(--white-s) + var(--primary-s)) / 2), calc((var(--white-l) + var(--primary-l)) / 2), calc((var(--white-a, 1) + var(--primary-a, 1)) / 2)), hsla(calc((var(--white-h) + var(--primary-h)) / 2), calc((var(--white-s) + var(--primary-s)) / 2), calc((var(--white-l) + var(--primary-l)) / 2), calc((var(--white-a, 1) + var(--primary-a, 1)) / 2)) |
|
$startPos: str-index($c, '('); |
|
$c: str-slice($c, $startPos + 1, -2); // 3 or 4 comma-separated vomplex values |
|
@return recursive-color($c); |
|
// $hEnd: str-index($c, ','); |
|
// @if ($hEnd) { |
|
// $h: str-slice($c, 0, $hEnd - 1); |
|
// $c: str-slice($c, $hEnd + 1); |
|
// $sEnd: str-index($c, ','); |
|
// @if ($hEnd) { |
|
// $h: str-slice($c, 0, $hEnd - 1); |
|
// $c: str-slice($c, $hEnd + 1); |
|
// $sEnd: str-index($c, ','); |
|
// } |
|
// } |
|
|
|
// @return (h: $h, s: $s, l: $l, a: $a); |
|
} |
|
|
|
@function render-hsla($h, $s, $l, $a: 1) { |
|
@return hsla($h, $s, $l, $a); |
|
} |
|
|
|
@function lighten($color, $amount) { |
|
@if (is-color($color)) { |
|
@return scale-color($color: $color, $lightness: $amount); |
|
} |
|
|
|
$c: to-hsl($color); |
|
$h: map-get($c, h); |
|
$s: map-get($c, s); |
|
$l: map-get($c, l); |
|
$a: map-get($c, a); |
|
@return render-hsla($h, $s, calc(#{$l} + #{$amount}), $a); |
|
} |
|
|
|
@function darken($color, $amount) { |
|
@return lighten($color, $amount * -1); |
|
} |
|
|
|
@function rgba($red, $green, $blue: false, $alpha: false) { |
|
$color: $red; |
|
|
|
@if (not $blue and not $alpha) { |
|
$alpha: $green; |
|
$color: $red; |
|
} |
|
|
|
$c: to-hsl($color); |
|
$h: map-get($c, h); |
|
$s: map-get($c, s); |
|
$l: map-get($c, l); |
|
@return render-hsla($h, $s, $l, $alpha); |
|
} |
|
|
|
@function rgb($red, $green, $blue) { |
|
@return rgba($red, $green, $blue, 1); |
|
} |
|
|
|
@function mix($color-1, $color-2, $weight: 50%) { |
|
$c1: to-hsl($color-1); |
|
$c2: to-hsl($color-2); |
|
|
|
$h1: map-get($c1, h); |
|
$s1: map-get($c1, s); |
|
$l1: map-get($c1, l); |
|
$a1: map-get($c1, a); |
|
|
|
$h2: map-get($c2, h); |
|
$s2: map-get($c2, s); |
|
$l2: map-get($c2, l); |
|
$a2: map-get($c2, a); |
|
|
|
$h: calc((#{$h1} + #{$h2}) / 2); |
|
$s: calc((#{$s1} + #{$s2}) / 2); |
|
$l: calc((#{$l1} + #{$l2}) / 2); |
|
$a: calc((#{$a1} + #{$a2}) / 2); |
|
|
|
@return render-hsla($h, $s, $l, $a); |
|
} |
|
|
|
@function fade-in($color, $amount) { |
|
$c: to-hsl($color); |
|
|
|
$h: map-get($c, h); |
|
$s: map-get($c, s); |
|
$l: map-get($c, l); |
|
$a: map-get($c, a); |
|
@if (not $a) { |
|
$a: 1; |
|
} |
|
|
|
@return render-hsla($h, $s, $l, $a + $amount); |
|
} |
|
|
|
@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) { |
|
@if (is-color($color)) { |
|
$r: red($color); |
|
$g: green($color); |
|
$b: blue($color); |
|
|
|
$yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000; |
|
|
|
@if ($yiq >= $yiq-contrasted-threshold) { |
|
@return $dark; |
|
} @else { |
|
@return $light; |
|
} |
|
} @else { |
|
$c: to-hsl($color); |
|
$l: map-get($c, l); |
|
|
|
$th: $yiq-contrasted-threshold / 2.56; // convert hex to dec |
|
$lightness: calc(-100 * calc(#{$l} - #{$th * 1%})); |
|
|
|
// ignoring hue and saturation, just a light or dark gray |
|
@return render-hsla(0, 0%, $lightness, 1); |
|
} |
|
} |
@JohnnyTWA Please do, I have been neglecting comments and updates on this for too long. I welcome you to make this an npm package so more people can create nice things. Thanks a lot!