/// Grid Math Engine /// ================ /// The `su` functions give you direct access to the math layer, /// without any syntax-sugar like shorthand parsing, and normalization. /// If you prefer named arguments, and stripped-down syntax, /// you can use these functions directly in your code – /// replacing `span`, `gutter`, and `slice`. /// /// These functions are also useful /// for building mixins or other extensions to Susy. /// Apply the Susy syntax to new mixins and functions, /// using our “Plugin Helpers”, /// or write your own syntax and pass the normalized results along /// to `su` for compilation. /// /// @group su-math /// /// @see su-span /// @see su-gutter /// @see su-slice /// @ignore _su-sum /// @ignore _su-calc-span /// @ignore _su-calc-sum /// @ignore _su-needs-calc-output

// Su Span // ——- /// Calculates and returns a CSS-ready span width, /// based on normalized span and context data – /// a low-level version of `susy-span`, /// with all of the logic and none of the syntax sugar. /// /// - Grids defined with unitless numbers will return `%` values. /// - Grids defined with comparable units /// will return a value in the units provided. /// - Grids defined with a mix of units, /// or a combination of untiless numbers and unit-lengths, /// will return a `calc()` string. /// /// @group su-math /// @see susy-span /// /// @param {number | list} $span - /// Number or list of grid columns to span /// @param {list} $columns - /// List of columns available /// @param {number} $gutters - /// Width of a gutter in column-comparable units /// @param {0 | 1 | -1} $spread - /// Number of gutters spanned, /// relative to `span` count /// @param {0 | 1 | -1} $container-spread [$spread] - /// Number of gutters spanned, /// relative to `columns` count /// @param {integer} $location [1] - /// Optional position of sub-span among full set of columns /// /// @return {length} - /// Relative or static length of a span on the grid @function su-span(

$span,
$columns,
$gutters,
$spread,
$container-spread: $spread,
$location: 1

) {

$span: su-valid-span($span);
$columns: su-valid-columns($columns);
$gutters: su-valid-gutters($gutters);
$spread: su-valid-spread($spread);

@if (type-of($span) == 'number') {
  @if (not unitless($span)) {
    @return $span;
  }

  $location: su-valid-location($span, $location, $columns);
  $span: su-slice($span, $columns, $location, $validate: false);
}

@if _su-needs-calc-output($span, $columns, $gutters, $spread, not 'validate') {
  @return _su-calc-span($span, $columns, $gutters, $spread, $container-spread, not 'validate');
}

$span-width: _su-sum($span, $gutters, $spread, $validate: false);

@if unitless($span-width) {
  $container-spread: su-valid-spread($container-spread);
  $container: _su-sum($columns, $gutters, $container-spread, $validate: false);
  @return percentage($span-width / $container);
}

@return $span-width;

}

// Su Gutter // ——— /// Calculates and returns a CSS-ready gutter width, /// based on normalized grid data – /// a low-level version of `susy-gutter`, /// with all of the logic and none of the syntax sugar. /// /// - Grids defined with unitless numbers will return `%` values. /// - Grids defined with comparable units /// will return a value in the units provided. /// - Grids defined with a mix of units, /// or a combination of untiless numbers and unit-lengths, /// will return a `calc()` string. /// /// @group su-math /// @see susy-gutter /// /// @param {list} $columns - /// List of columns in the grid /// @param {number} $gutters - /// Width of a gutter in column-comparable units /// @param {0 | 1 | -1} $container-spread - /// Number of gutters spanned, /// relative to `columns` count /// /// @return {length} - /// Relative or static length of one gutter in a grid @function su-gutter(

$columns,
$gutters,
$container-spread

) {

@if (type-of($gutters) == 'number') {
  @if ($gutters == 0) or (not unitless($gutters)) {
    @return $gutters;
  }
}

@if _su-needs-calc-output($gutters, $columns, $gutters, -1, not 'validate') {
  @return _su-calc-span($gutters, $columns, $gutters, -1, $container-spread, not 'validate');
}

$container: _su-sum($columns, $gutters, $container-spread);
@return percentage($gutters / $container);

}

// Su Slice // ——– /// Returns a list of columns /// based on a given span/location slice of the grid – /// a low-level version of `susy-slice`, /// with all of the logic and none of the syntax sugar. /// /// @group su-math /// @see susy-slice /// /// @param {number} $span - /// Number of grid columns to span /// @param {list} $columns - /// List of columns in the grid /// @param {number} $location [1] - /// Starting index of a span in the list of columns /// @param {bool} $validate [true] - /// Check that arguments are valid before proceeding /// /// @return {list} - /// Subset list of grid columns, based on span and location @function su-slice(

$span,
$columns,
$location: 1,
$validate: true

) {

@if $validate {
  $columns: su-valid-columns($columns);
  $location: su-valid-location($span, $location, $columns);
}

$floor: floor($span);
$sub-columns: ();

@for $i from $location to ($location + $floor) {
  $sub-columns: append($sub-columns, nth($columns, $i));
}

@if $floor != $span {
  $remainder: $span - $floor;
  $column: $location + $floor;
  $sub-columns: append($sub-columns, nth($columns, $column) * $remainder);
}

@return $sub-columns;

}

// Su Sum // —— /// Get the total sum of column-units in a layout. /// /// @group su-math /// @access private /// /// @param {list} $columns - /// List of columns in the grid /// @param {number} $gutters - /// Width of a gutter in column-comparable units /// @param {0 | 1 | -1} $spread - /// Number of gutters spanned, /// relative to `columns` count /// @param {bool} $validate [true] - /// Check that arguments are valid before proceeding /// /// @return {number} - /// Total sum of column-units in a grid @function _su-sum(

$columns,
$gutters,
$spread,
$validate: true

) {

@if $validate {
  $columns: su-valid-span($columns);
  $gutters: su-valid-gutters($gutters);
  $spread: su-valid-spread($spread);
}

// Calculate column-sum
$column-sum: 0;
@each $column in $columns {
  $column-sum: $column-sum + $column;
}

$gutter-sum: (ceil(length($columns)) + $spread) * $gutters;
$total: if(($gutter-sum > 0), $column-sum + $gutter-sum, $column-sum);

@return $total;

}

// Su Calc // ——- /// Return a usable span width as a `calc()` function, /// in order to create mixed-unit grids. /// /// @group su-math /// @access private /// /// @param {number | list} $span - /// Pre-sliced list of grid columns to span /// @param {list} $columns - /// List of columns available /// @param {number} $gutters - /// Width of a gutter in column-comparable units /// @param {0 | 1 | -1} $spread - /// Number of gutters spanned, /// relative to `span` count /// @param {0 | 1 | -1} $container-spread [$spread] - /// Number of gutters spanned, /// relative to `columns` count /// @param {bool} $validate [true] - /// Check that arguments are valid before proceeding /// /// @return {length} - /// Relative or static length of a span on the grid @function _su-calc-span(

$span,
$columns,
$gutters,
$spread,
$container-spread: $spread,
$validate: true

) {

@if $validate {
  $span: su-valid-span($span);
  $columns: su-valid-columns($columns);
  $gutters: su-valid-gutters($gutters);
  $spread: su-valid-spread($spread);
  $container-spread: su-valid-spread($container-spread);
}

// Span and context
$span: _su-calc-sum($span, $gutters, $spread, not 'validate');
$context: _su-calc-sum($columns, $gutters, $container-spread, not 'validate');

// Fixed and fluid
$fixed-span: map-get($span, 'fixed');
$fluid-span: map-get($span, 'fluid');
$fixed-context: map-get($context, 'fixed');
$fluid-context: map-get($context, 'fluid');

$calc: '#{$fixed-span}';
$fluid-calc: '(100% - #{$fixed-context})';

// Fluid-values
@if (not $fluid-span) {
  $fluid-calc: null;
} @else if ($fluid-span != $fluid-context) {
  $fluid-span: '* #{$fluid-span}';
  $fluid-context: if($fluid-context, '/ #{$fluid-context}', '');
  $fluid-calc: '(#{$fluid-calc $fluid-context $fluid-span})';
}

@if $fluid-calc {
  $calc: if(($calc != ''), '#{$calc} + ', '');
  $calc: '#{$calc + $fluid-calc}';
}

@return calc(#{unquote($calc)});

}

// Su Calc-Sum // ———– /// Get the total sum of fixed and fluid column-units /// for creating a mixed-unit layout with `calc()` values. /// /// @group su-math /// @access private /// /// @param {list} $columns - /// List of columns available /// @param {number} $gutters - /// Width of a gutter in column-comparable units /// @param {0 | 1 | -1} $spread - /// Number of gutters spanned, /// relative to `span` count /// @param {bool} $validate [true] - /// Check that arguments are valid before proceeding /// /// @return {map} - /// Map with `fixed` and `fluid` keys /// containing the proper math as strings @function _su-calc-sum(

$columns,
$gutters,
$spread,
$validate: true

) {

@if $validate {
  $columns: su-valid-span($columns);
  $gutters: su-valid-gutters($gutters);
  $spread: su-valid-spread($spread);
}

$fluid: 0;
$fixed: ();
$calc: null;

// Gutters
$gutters:  $gutters * (length($columns) + $spread);

// Columns
@each $col in append($columns, $gutters) {
  @if unitless($col) {
    $fluid: $fluid + $col;
  } @else {
    $fixed: _su-map-add-units($fixed, $col);
  }
}

// Compile Fixed Units
@each $unit, $total in $fixed {
  @if ($total != (0 * $total)) {
    $calc: if($calc, '#{$calc} + #{$total}', '#{$total}');
  }
}

// Calc null or string
@if $calc {
  $calc: if(str-index($calc, '+'), '(#{$calc})', '#{$calc}');
}

// Fluid 0 => null
$fluid: if(($fluid == 0), null, $fluid);

// Return map
$return: (
  'fixed': $calc,
  'fluid': $fluid,
);

@return $return;

}

// Needs Calc // ———- /// Check if `calc()` will be needed in defining a span, /// if the necessary units in a grid are not comparable. /// /// @group su-math /// @access private /// /// @param {list} $span - /// Slice of columns to span /// @param {list} $columns - /// List of available columns in the grid /// @param {number} $gutters - /// Width of a gutter /// @param {0 | 1 | -1} $spread - /// Number of gutters spanned, /// relative to `span` count /// @param {bool} $validate [true] - /// Check that arguments are valid before proceeding /// /// @return {bool} - /// `True` when units do not match, and `calc()` will be required @function _su-needs-calc-output(

$span,
$columns,
$gutters,
$spread,
$validate: true

) {

@if $validate {
  $span: su-valid-span($span);
  $columns: su-valid-columns($columns);
  $gutters: su-valid-gutters($gutters);
}

$has-gutter: if((length($span) > 1) or ($spread >= 0), true, false);
$check: if($has-gutter, append($span, $gutters), $span);
$safe-span: _su-is-comparable($check...);

@if ($safe-span == 'static') {
  @return false;
} @else if (not $safe-span) {
  @return true;
}

$safe-fluid: _su-is-comparable($gutters, $columns...);

@return not $safe-fluid;

}