diff --git a/scss/mixins/_background.scss b/scss/mixins/_background.scss index ea1543f..dcac6e1 100644 --- a/scss/mixins/_background.scss +++ b/scss/mixins/_background.scss @@ -60,7 +60,7 @@ $background-position-vertical-modes: array-concat((top, center, bottom), $css-de $h: nth-value($bp, 1); $h-valid: is-size($h) or is-percentage($h) or array-contains($background-position-horizontal-modes, $h); - $v: nth-value($bp, 2); + $v: if(length($bp) > 1, nth-value($bp, 2), center); $v-valid: is-size($v) or is-percentage($v) or array-contains($background-position-vertical-modes, $v); @return $h-valid and $v-valid; @@ -465,30 +465,187 @@ $linear-gradient-directions: (to top, to top right, to right top, to right, to b @include linear-gradient-base(repeating-linear-gradient, $options...); } -// $radial-gradient-shapes: (circle, ellipse); +@function is-radial-gradient-size($gp) { + @return is-background-position($gp); +} + +$radial-gradient-shapes: (circle, ellipse); + +@function is-radial-gradient-shape($gs) { + @return is-defined($gs) and array-contains($radial-gradient-shapes, $gs); +} + +$radial-gradient-extent-keywords: (closest-side, closest-corner, farthest-side, farthest-corner, cover, contain); + +@function is-radial-gradient-extent-keyword($gek) { + @return is-defined($gek) and array-contains($radial-gradient-extent-keywords, $gek); +} + +@function is-radial-gradient-position($gp) { + @return is-background-position($gp); +} + +@function get-radial-gradient-definition($gd) { + $gradient-definition-split: string-split(inspect($gd), ' at '); + $gradient-definition: string-split(nth-value($gradient-definition-split, 1), ' '); + $gradient-position: center; + + @if length($gradient-definition-split) > 1 { + $gradient-position: string-split(nth-value($gradient-definition-split, 2), ' '); + } + + // $gradient-shape-width: null; + // $gradient-shape-height: null; + $gradient-shape: ellipse; + $gradient-extend-keyword: farthest-corner; + + @each $gradient-definition-item in $gradient-definition { + $gradient-definition-item-index: index($gradient-definition, $gradient-definition-item); + + // @if is-number-between($gradient-definition-item-index, 1, 2) { + // $gradient-definition-item-number: to-number($gradient-definition-item); + // @if is-relative-length($gradient-definition-item-number) or is-absolute-length($gradient-definition-item-number) { + // @if $gradient-definition-item-index = 1 { + // $gradient-shape-width: $gradient-definition-item-number; + // } + + // @if $gradient-definition-item-index = 2 { + // $gradient-shape-height: $gradient-definition-item-number; + // } + // } + // } + + @if is-radial-gradient-shape($gradient-definition-item) { + $gradient-shape: $gradient-definition-item; + } + @else if is-radial-gradient-extent-keyword($gradient-definition-item) { + $gradient-extend-keyword: $gradient-definition-item; + } + } + + // @if is-defined($gradient-shape-width) and is-null($gradient-shape-height) { + // $gradient-shape-height: $gradient-shape-width; + // } + + @if not is-radial-gradient-position($gradient-position) { + $gradient-position: center; + } + + $radial-gradient-definition: ( + shape: $gradient-shape, + extent-keyword: $gradient-extend-keyword, + position: $gradient-position + ); + + // @if is-defined($gradient-shape-width) and is-defined($gradient-shape-height) { + // $radial-gradient-definition: extend($radial-gradient-definition, ( + // size: $gradient-shape-width $gradient-shape-height + // )); + // } + + @return $radial-gradient-definition; +} + +@function is-radial-gradient-definition($gd) { + $gradient-definition-valid: false; + + @if list-separator($gd) == space { + // $gradient-definition-size: get($gd, 'size'); + $gradient-definition-shape: get($gd, 'shape'); + $gradient-definition-extent-keyword: get($gd, 'extent-keyword'); + $gradient-definition-position: get($gd, 'position'); + + $gradient-definition-valid: true; + + // @if is-defined($gradient-definition-size) { + // $gradient-definition-valid: is-radial-gradient-size($gradient-definition-size); + // } + + // @if $gradient-definition-valid and is-defined($gradient-definition-shape) { + @if is-defined($gradient-definition-shape) { + $gradient-definition-valid: is-radial-gradient-shape($gradient-definition-shape); + } + + @if $gradient-definition-valid and is-defined($gradient-definition-extent-keyword) { + $gradient-definition-valid: is-radial-gradient-extent-keyword($gradient-definition-extent-keyword); + } + + @if $gradient-definition-valid and is-defined($gradient-definition-position) { + $gradient-definition-valid: is-radial-gradient-position($gradient-definition-position); + } + } + + @return $gradient-definition-valid; +} + +@function is-radial-gradient-options($options...) { + @if list-separator($options) == comma { + $definition: array-head($options); + $color-stops: $options; -// @function is-radial-gradient-shape($gs) { -// @return is-defined($gs) and array-contains($radial-gradient-shapes, $gs); -// } + @if not is-gradient-color-stop($definition) { + $color-stops: array-tail($options); + } + @else { + $definition: ellipse farthest-corner at center; + } -// $radial-gradient-extent-modes: (closest-side, closest-corner, farthest-side, farthest-corner, cover, contain); + $definition: get-radial-gradient-definition($definition); -// @function is-radial-gradient-extent($ge) { -// @return is-defined($ge) and array-contains($radial-gradient-extent-modes, $ge); -// } + @return is-radial-gradient-definition($definition) and is-gradient-color-stops($color-stops...); + } -// @function is-radial-gradient-position($gp) { -// @return is-background-position($gp); -// } + @return false; +} -// @function is-radial-gradient-definition($gd) { -// @if is-array($gd) and list-separator($gd) == space { -// $gradient-definition: string-split($gd, ' at '); +@mixin radial-gradient-base($function: radial-gradient, $options...) { + @if is-radial-gradient-options($options...) { + $definition: array-head($options); + $color-stops: $options; -// @warn($gradient-definition); -// @return true; -// } + @if not is-gradient-color-stop($definition) { + $color-stops: array-tail($options); + } + @else { + $definition: ellipse farthest-corner at center; + } -// @return false; -// } + $definition: get-radial-gradient-definition($definition); + $radial-gradient-definition: ''; + + // $radial-gradient-definition-size: get($definition, 'size'); + + $radial-gradient-definition-shape: get($definition, 'shape'); + $radial-gradient-definition-extent-keyword: get($definition, 'extent-keyword'); + $radial-gradient-definition-position: get($definition, 'position'); + + // @if is-defined($radial-gradient-definition-size) { + // $radial-gradient-definition: $radial-gradient-definition-size; + // } + + @if is-defined($radial-gradient-definition-shape) { + $radial-gradient-definition: $radial-gradient-definition-shape; + } + + @if is-defined($radial-gradient-definition-extent-keyword) { + $radial-gradient-definition: $radial-gradient-definition + ' ' + $radial-gradient-definition-extent-keyword; + } + + @if is-defined($radial-gradient-definition-position) { + $radial-gradient-definition: $radial-gradient-definition + ' at ' + $radial-gradient-definition-position; + } + + $radial-gradient-function-call: $function + '(' + $radial-gradient-definition + ',' + $color-stops + ')'; + + background-image: #{$radial-gradient-function-call}; + } +} + +@mixin radial-gradient($options...) { + @include radial-gradient-base(radial-gradient, $options...); +} + +@mixin repeating-radial-gradient($options...) { + @include radial-gradient-base(repeating-radial-gradient, $options...); +} diff --git a/scss/types/_array.scss b/scss/types/_array.scss index e450399..c71b85f 100644 --- a/scss/types/_array.scss +++ b/scss/types/_array.scss @@ -74,6 +74,18 @@ @return $join-string; } +@function array-remove($list, $value) { + $result: (); + + @each $item in $list { + @if $item != $value { + $result: append($result, $item, list-separator($list)); + } + } + + @return $result; +} + @function array-remove-nth($list, $index) { $result: (); diff --git a/scss/types/_number.scss b/scss/types/_number.scss index dfcfe7e..c5df6b9 100644 --- a/scss/types/_number.scss +++ b/scss/types/_number.scss @@ -80,3 +80,61 @@ @function is-percentage-number($pn) { @return is-number($pn) and is-number-between(unitstrip($pn), 0, 1); } + +/// +/// Casts a string into a number +/// +/// @param {String | Number} $value - Value to be parsed +/// +/// @return {Number} +/// +@function to-number($value) { + @if type-of($value) == 'number' { + @return $value; + } @else if type-of($value) != 'string' { + $_: log('Value for `to-number` should be a number or a string.'); + } + + $result: 0; + $digits: 0; + $minus: str-slice($value, 1, 1) == '-'; + $numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9); + + @for $i from if($minus, 2, 1) through str-length($value) { + $character: str-slice($value, $i, $i); + + @if not (index(map-keys($numbers), $character) or $character == '.') { + @return to-length(if($minus, -$result, $result), str-slice($value, $i)); + } + + @if $character == '.' { + $digits: 1; + } @else if $digits == 0 { + $result: $result * 10 + map-get($numbers, $character); + } @else { + $digits: $digits * 10; + $result: $result + map-get($numbers, $character) / $digits; + } + } + + @return if($minus, -$result, $result);; +} + + +/// +/// Add `$unit` to `$value` +/// +/// @param {Number} $value - Value to add unit to +/// @param {String} $unit - String representation of the unit +/// +/// @return {Number} - `$value` expressed in `$unit` +/// +@function to-length($value, $unit) { + $units: ('px': 1px, 'cm': 1cm, 'mm': 1mm, '%': 1%, 'ch': 1ch, 'pc': 1pc, 'in': 1in, 'em': 1em, 'rem': 1rem, 'pt': 1pt, 'ex': 1ex, 'vw': 1vw, 'vh': 1vh, 'vmin': 1vmin, 'vmax': 1vmax); + + @if not index(map-keys($units), $unit) { + $_: log('Invalid unit `#{$unit}`.'); + } + + @return $value * map-get($units, $unit); +} diff --git a/scss/types/_string.scss b/scss/types/_string.scss index 150e9f1..600c73a 100644 --- a/scss/types/_string.scss +++ b/scss/types/_string.scss @@ -147,7 +147,7 @@ @while $i!=null { $item: string-slice($s, 1, $i - 1); $split: array-concat($split, $item); - $s: string-slice($s, $i + 1); + $s: string-slice($s, $i + string-length($sep)); $i: string-index($s, $sep); }