// PLUMBER - Easy baseline grids with SASS // jamonserrano.github.io/plumber-sass // Copyright 2016 Viktor Honti // MIT License

@mixin plumber(

$font-size: null,
$line-height: null,
$leading-top: null,
$leading-bottom: null,
$grid-height: null,
$baseline: null,
$use-baseline-origin: null

) {

// *** VALIDATE PARAMETERS ***
// font-size
@if not $font-size {
        $font-size: -plumber-get-default(font-size);
}
@if not unitless($font-size) or $font-size <= 0 {
        @error '$font-size parameter must be a positive unitless number, got #{$font-size} instead';
}

// line-height
@if not $line-height {
        $line-height: -plumber-get-default(line-height);
}
@if not unitless($line-height) or $line-height != round($line-height) or $line-height < 1 {
        @error '$line-height parameter must be a positive unitless integer, got #{$line-height} instead';
}

// leading-top
@if not $leading-top {
        $leading-top: -plumber-get-default(leading-top);
}
@if not -plumber-is-integer($leading-top) {
        @error '$leading-top parameter must be a non-negative integer, got #{$leading-top} instead.';
}

// leading-bottom
@if not $leading-bottom {
        $leading-bottom: -plumber-get-default(leading-bottom);
}
@if not -plumber-is-integer($leading-bottom) {
        @error '$leading-bottom parameter must be a non-negative integer, got #{$leading-bottom} instead';
}

// grid-height
@if not $grid-height {
        $grid-height: -plumber-get-default(grid-height);
}
@if unitless($grid-height) or $grid-height < 0 {
        @error '$grid-height parameter must be a positive unit, got #{$grid-height} instead';
}

// baseline
@if not $baseline {
        $baseline: -plumber-get-default(baseline);
}
@if not $baseline {
        @error '$baseline must be passed as a parameter or defined in defaults';
} @else if not (unitless($baseline) and $baseline >= 0 and $baseline < 1) {
        @error '$baseline parameter must be a unitless fraction between 0 and 1, got #{$baseline} instead';
}

// use-baseline-origin
@if not $use-baseline-origin {
        $use-baseline-origin: -plumber-get-default(use-baseline-origin);
}
@if type-of($use-baseline-origin) != bool {
        @error '$use-baseline-origin parameter must be Boolean, got #{$use-baseline-origin} instead';
}

// *** CALCULATE BASELINE CORRECTION ***
// the distance of the original baseline from the bottom
$baseline-from-bottom: ($line-height - $font-size) / 2 + ($font-size * $baseline);
// the corrected baseline will be on the nearest gridline
$corrected-baseline: round($baseline-from-bottom);
// the difference between the original and the corrected baseline
$baseline-difference: $corrected-baseline - $baseline-from-bottom;

// if baseline origin is used for leadings substract the distance of the baseline from the edges
@if $use-baseline-origin == true {
        $leading-top: $leading-top - ($line-height - $corrected-baseline);
        $leading-bottom: $leading-bottom - $corrected-baseline;
}

// *** CALCULATE FONT SIZE AND LINE HEIGHT
$font-size: $font-size * $grid-height;
$line-height: $line-height * $grid-height;

// *** CALCULATE MARGINS AND PADDINGS ***
$padding-top: null;
$margin-top: null;
$margin-bottom: null;
$padding-bottom: null;

@if $baseline-difference < 0 {
        // add top leading
        $margin-top: $leading-top * $grid-height;
        // push the baseline down to the next gridline
        $padding-top: - $baseline-difference * $grid-height;
        // add the remaining distance to reach the next gridline
        $padding-bottom: (1 + $baseline-difference) * $grid-height;
        // add bottom leading and remove the 1 excess grid height that comes from pushing down
        $margin-bottom: ($leading-bottom - 1) * $grid-height;
} @else {
        // add top leading and remove the 1 excess grid height that comes from pulling up
        $margin-top: ($leading-top - 1) * $grid-height;
        // pull the baseline up to the previous gridline
        $padding-top: (1 - $baseline-difference) * $grid-height;
        // add the remaining distance to reach the next gridline
        $padding-bottom: $baseline-difference * $grid-height;
        // add bottom leading
        $margin-bottom: $leading-bottom * $grid-height;
}

// round pixel values to decrease browser inconsistencies
@if unit($grid-height) == "px" {
        $line-height: -plumber-round($line-height);
        $margin-top: -plumber-round($margin-top);
        $padding-top: -plumber-round($padding-top);
        $padding-bottom: -plumber-round($padding-bottom);
        $margin-bottom: -plumber-round($margin-bottom);
}

// *** CSS OUTPUT ***
font-size: $font-size;
line-height: $line-height;
margin-top: $margin-top;
padding-top: $padding-top;
padding-bottom: $padding-bottom;
margin-bottom: $margin-bottom;

}

// *** DEFAULTS *** // Do not change it here, use the plumber-set-defaults mixin instead! $-plumber-defaults: (

font-size: 2,
line-height: 3,
leading-top: 0,
leading-bottom: 0,
grid-height: 1rem,
baseline: null,
use-baseline-origin: false,

) !default;

// Merge provided settings into the defaults map @mixin plumber-set-defaults($defaults…) {

$-plumber-defaults: map-merge($-plumber-defaults, keywords($defaults)) !global;

}

// Get a default value @function -plumber-get-default($key) {

@return map-get($-plumber-defaults, $key);

}

// Check if a value is a non-negative integer @function -plumber-is-integer($value) {

@return (unitless($value) and $value == round($value));

}

// Round value to the nearest quarter pixel // This provides reasonable precision and prevents grid creep (by fractions adding up) in most browsers @function -plumber-round($value) {

@return round($value * 4) / 4;

}