@mixin apply-props($args, $props...) {
    @for $i from 1 through length($args) {
        $val: nth($args, $i);

        @if $val != null {
            #{nth($props, $i)}: $val;
        }
    }
}

// position: position(top, right, bottom, left)
@mixin position($args...) {
    @include apply-props($args, top, right, bottom, left);
}

// width(height, min-width, max-width)
@mixin width($args...) {
    @include apply-props($args, width, min-width, max-width);
}

// fixed-width(width)
@mixin fixed-width($base) {
    @include apply-props(($base, $base), min-width, max-width);
}

// height(height, min-height, max-height)
@mixin height($args...) {
    @include apply-props($args, height, min-height, max-height);
}

// fixed-height(height)
@mixin fixed-height($base) {
    @include apply-props(($base, $base), min-height, max-height);
}

// size(width: auto, height: width)
@mixin size($width: auto, $height: $width) {
    height: $height;
    width: $width;
}

// min-size(width: auto, height: width)
@mixin min-size($width: auto, $height: $width) {
    min-height: $height;
    min-width: $width;
}

// max-size(width: auto, height: width)
@mixin max-size($width: auto, $height: $width) {
    max-height: $height;
    max-width: $width;
}

// fixed-height(width: auto, height: width)
@mixin fixed-size($width: auto, $height: $width) {
    @include fixed-width($width);
    @include fixed-height($height);
}

// pseudo(position: absolute, content: '')
@mixin pseudo($position: absolute, $content: '') {
    @include apply-props(($position, $content), position, content);
}

// font(font-weight, font-size, letter-spacing)
@mixin font($args...) {
    @include apply-props($args, font-weight, font-size, letter-spacing);
}

// whiteSpaceOverflow(white-space: nowrap, overflow: hidden, text-overflow: ellipsis)
@mixin white-space-overflow($white-space: nowrap, $overflow: hidden, $text-overflow: ellipsis) {
    @include apply-props(($white-space, $overflow, $text-overflow), white-space, overflow, text-overflow);
}

// stroke(stroke, stroke-width, stroke-linecap, stroke-dasharray, stroke-dashoffset)
@mixin stroke($args...) {
    @include apply-props($args, stroke, stroke-width, stroke-linecap, stroke-dasharray, stroke-dashoffset);
}

// flex(flex-direction, align-items, justify-content, flex-wrap);
@mixin flex($args...) {
    @include apply-props($args, flex-direction, align-items, justify-content, flex-wrap);
    display: flex;
}

// inline-flex(flex-direction, align-items, justify-content, flex-wrap);
@mixin inline-flex($args...) {
    @include apply-props($args, flex-direction, align-items, justify-content, flex-wrap);
    display: inline-flex;
}

// flex-self(align-self, justify-self)
@mixin flex-self($align-self: center, $justify-self: $align-self) {
    @include apply-props(($align-self, $justify-self), align-self, justify-self);
}

// animate(props) {timeline}
@mixin animate($props: '') {
    $animation-name: 'a' + random(100000);

    @keyframes #{$animation-name} {
        @content;
    }

    animation: #{$animation-name} #{$props};
}

// Alternative to flex-gap (see https://caniuse.com/#feat=flexbox-gap)
// margin-between-h(margin)
@mixin margin-between-h($margin) {
    &:not(:first-child):not(:last-child) {
        margin-left: $margin;
        margin-right: $margin;
    }

    &:first-child:not(:last-child) {
        margin-right: $margin;
    }

    &:last-child:not(:first-child) {
        margin-left: $margin;
    }
}

// margin-between-v(margin)
@mixin margin-between-v($margin) {
    &:not(:first-child):not(:last-child) {
        margin-bottom: $margin;
        margin-top: $margin;
    }

    &:first-child:not(:last-child) {
        margin-bottom: $margin;
    }

    &:last-child:not(:first-child) {
        margin-top: $margin;
    }
}

// Sequential animation delay based on childcount and a multiplier
@mixin sequential-animation-delay($child-count, $multiplier, $base: 0) {
    @for $i from 0 through $child-count {
        &:nth-child(#{$i}) {
            animation-delay: #{($i - 1) * $multiplier + $base};
        }
    }
}

// Order items easier
@mixin order($list) {
    @if type-of($list) == map {
        @each $selector, $order in $list {
            #{$selector} {
                order: $order;
            }
        }
    } @else if type-of($list) == list {
        @for $i from 1 through length($list) {
            #{nth($list, $i)} {
                order: $i;
            }
        }
    }
}
