// Foundation for Sites // https://get.foundation // Licensed under MIT Open Source //// /// @group functions //// /// Finds the greatest common divisor of two integers. /// /// @param {Number} $a - First number to compare. /// @param {Number} $b - Second number to compare. /// /// @returns {Number} The greatest common divisor. @function gcd($a, $b) { // From: http://rosettacode.org/wiki/Greatest_common_divisor#JavaScript @if ($b != 0) { @return gcd($b, $a % $b); } @else { @return abs($a); } } /// Handles decimal exponents by trying to convert them into a fraction and then use a nth-root-algorithm for parts of the calculation /// /// @param {Number} $base - The base number. /// @param {Number} $exponent - The exponent. /// /// @returns {Number} The product of the exponentiation. @function pow($base, $exponent, $prec: 16) { @if (floor($exponent) != $exponent) { $prec2 : pow(10, $prec); $exponent: round($exponent * $prec2); $denominator: gcd($exponent, $prec2); @return nth-root(pow($base, $exponent / $denominator), $prec2 / $denominator, $prec); } $value: $base; @if $exponent > 1 { @for $i from 2 through $exponent { $value: $value * $base; } } @else if $exponent < 1 { @for $i from 0 through -$exponent { $value: $value / $base; } } @return $value; } @function nth-root($num, $n: 2, $prec: 12) { // From: http://rosettacode.org/wiki/Nth_root#JavaScript $x: 1; @for $i from 0 through $prec { $x: 1 / $n * (($n - 1) * $x + ($num / pow($x, $n - 1))); } @return $x; } /// Calculates the height as a percentage of the width for a given ratio. /// @param {List} $ratio - Ratio to use to calculate the height, formatted as `x by y`. /// @return {Number} A percentage value for the height relative to the width of a responsive container. @function ratio-to-percentage($ratio) { $w: nth($ratio, 1); $h: nth($ratio, 3); @return $h / $w * 100%; } /// Parse the given `$fraction` to numerators and denumerators. /// /// @param {*} $fraction - Value representing a fraction to parse. It can be formatted as `50%`, `1 of 2`, `1/2` or `50` (no denominator would be returned). /// /// @return {List} List of parsed values with numerator at first position and denumerator as second. These values may be null. @function zf-parse-fraction($fraction) { @if type-of($fraction) == 'number' { // "50%" @if unit($fraction) == '%' { @return (strip-unit($fraction), 100); } @else if (unit($fraction) == '') { // "0.5" @if $fraction < 1 { @return ($fraction * 100, 100); } // "50" @else { @return ($fraction, null); } } } @else if type-of($fraction) == 'list' { // "50 of 100", "50/100"... @if length($fraction) == 3 and type-of(nth($fraction, 1) == 'number') and type-of(nth($fraction, 3) == 'number') { @return (nth($fraction, 1), nth($fraction, 3)); } } @return (null, null); } /// Returns whether the given `$value` represents a fraction. Supports formats like `50%`, `1 of 2`, `1 per 2` or `1/2`. /// /// @param {*} $value - Value to test. /// @param {Boolean} $allow-no-denominator [false] - If `true`, simple numbers without denominators like `50` are supported. /// /// @return {Boolean} `true` if `$value` represents a fraction, `false` otherwise. @function zf-is-fraction($value, $allow-no-denominator: false) { $parsed: zf-parse-fraction($value); @return not(nth($parsed, 1) == null or (nth($parsed, 2) == null and $allow-no-denominator == false)); } /// Calculate a percentage from a given fraction. /// /// @param {Number|List} $fraction - Value representing a fraction to use to calculate the percentage, formatted as `50` (relative to `$denominator`), `50%`, `1 of 2` or `1/2`. /// @param {Number|List} $denominator - Default value to use as denominator when `$fraction` represents an absolute value. @function fraction-to-percentage( $fraction, $denominator: null ) { $parsed: zf-parse-fraction($fraction); $parsed-nominator: nth($parsed, 1); $parsed-denominator: nth($parsed, 2); @if $parsed-nominator == null { @error 'Wrong syntax for "fraction-to-percentage()". Use a number, decimal, percentage, or "n of n" / "n/n".'; } @if $parsed-denominator == null { @if type-of($denominator) == 'number' { $parsed-denominator: $denominator; } @else { @error 'Error with "fraction-to-percentage()". A default "$denominator" is required to support absolute values'; } } @return percentage($parsed-nominator / $parsed-denominator); }