@charset 'UTF-8';

////
/// Flavor SCSS Mixins Transition
/// @group mixins-transition
/// @author blackmirror1980
////

/// Checks if something is a transition time value
///
/// @access public
/// @param {string | time} $tt - the transition time value (e.g. `initial` or `20ms`)
/// @return {boolean} - true if is a transform time value
@function is-transition-time($tt) {
  @return is-defined($tt) and (is-time($tt) or is-css-default($tt));
}

/// Transition delay mixin
///
/// @link https://www.w3schools.com/cssref/css3_pr_transition-delay.asp W3Schools transition-delay docs
/// @example scss - Usage
///   .transition-delay-element {
///     @include transition-delay(1s);
///   }
///
/// @example css - Output
///   .transition-delay-element {
///     -webkit-transition-delay: 1s;
///     -moz-transition-delay: 1s;
///     -ms-transition-delay: 1s;
///     -o-transition-delay: 1s;
///     transition-delay: 1s;
///   }
/// @access public
/// @param {string | time} $td - the transition delay value (e.g. `initial` or `10s`)
@mixin transition-delay($td) {
  @if is-transition-time($td) {
    @include prefixer(transition-delay, $td);
  }
  @else {
    @warn '`transition-delay: #{$td}` is not a valid transition-delay value';
  }
}

/// Transition duration mixin
///
/// @link https://www.w3schools.com/cssref/css3_pr_transition-duration.asp W3Schools transition-duration docs
/// @example scss - Usage
///   .transition-duration-element {
///     @include transition-duration(1s);
///   }
///
/// @example css - Output
///   .transition-duration-element {
///     -webkit-transition-duration: 1s;
///     -moz-transition-duration: 1s;
///     -ms-transition-duration: 1s;
///     -o-transition-duration: 1s;
///     transition-duration: 1s;
///   }
/// @access public
/// @param {string | time} $td - the transition duration value (e.g. `initial` or `10s`)
@mixin transition-duration($td) {
  @if is-transition-time($td) {
    @include prefixer(transition-duration, $td);
  }
  @else {
    @warn '`transition-duration: #{$td}` is not a valid transition-duration value';
  }
}

/// Transition property modes
///
/// @access private
/// @type list
$transition-property-modes: array-concat((none, all), $animateable-properties, $css-default-modes);

/// Checks if something is a transition property value
///
/// @access public
/// @param {string} $tp - the transform property value (e.g. `none`, `all`, `transform` or `initial` )
/// @return {boolean} - true if is a transform property value
@function is-transition-property($tp) {
  @return is-defined($tp) and array-contains($transition-property-modes, $tp);
}

/// Transition property mixin
///
/// @link https://www.w3schools.com/cssref/css3_pr_transition-property.asp W3Schools transition-property docs
/// @example scss - Usage
///   .transition-property-element {
///     @include transition-property(background-color);
///   }
///
/// @example css - Output
///   .transition-property-element {
///     -webkit-transition-property: background-color;
///     -moz-transition-property: background-color;
///     -ms-transition-property: background-color;
///     -o-transition-property: background-color;
///     transition-property: background-color;
///   }
/// @access public
/// @param {string} $tp - the transform property value (e.g. `none` or `all` or `initial`)
@mixin transition-property($tp) {
  @if is-transition-property($tp) {
    @include prefixer(transition-property, $tp);
  }
  @else {
    @warn '`transition-property: #{$tp}` is not a valid transition-property value';
  }
}

/// Transition timing functions
///
/// @access private
/// @type list
$transition-timing-functions-names: (steps, cubic-bezier);

/// Extracts transition function name from a transform-timing-function value
///
/// @access public
/// @param {string} $t - the transform-timing-function value (e.g. `cubic-bezier(0,0,1,1)`)
/// @return {string | null} - the transform-timing-function name or null
@function get-transition-timing-function-name($t) {
  @if(string-contains($t, '(') and string-contains($t, ')')) {
    @return str-slice($t, 1, str-index($t, '(') - 1);
  }

  @return null;
}

/// Checks if something is a transition timing function value
///
/// @access public
/// @param {string} $t - the transition value (e.g. `cubic-bezier(0,0,1,1)`)
/// @return {boolean} - true if is a transform-timing-function value
@function is-transition-timing-function($t) {
  $transition-timing-function-name: get-transition-timing-function-name($t);

  @return is-defined($transition-timing-function-name) and array-contains($transition-timing-functions-names, $transition-timing-function-name);
}

/// Transition timing modes
///
/// @access private
/// @type list
$transition-timing-modes: array-concat((linear, ease, ease-in, ease-out, ease-in-out, step-start, step-end), $css-default-modes);

/// Checks if something is a transition-timing-function value
///
/// @access public
/// @param {string} $ttf - the transition-timing-function value (e.g. `cubic-bezier(0,0,1,1)` or `ease-in-out`)
/// @return {boolean} - true if is a transition-timing-function value
@function is-transition-timing-mode-or-function($ttf) {
  @return is-defined($ttf) and (array-contains($transition-timing-modes, $ttf) or is-transition-timing-function($ttf));
}

/// Transition timing function mixin
///
/// @link https://www.w3schools.com/cssref/css3_pr_transition-timing-function.asp W3Schools transition-timing-function docs
/// @example scss - Usage
///   .transition-timing-function-element {
///     @include transition-timing-function(linear);
///   }
///
/// @example css - Output
///   .transition-timing-function-element {
///     -webkit-transition-timing-function: linear;
///     -moz-transition-timing-function: linear;
///     -ms-transition-timing-function: linear;
///     -o-transition-timing-function: linear;
///     transition-timing-function: linear;
///   }
/// @access public
/// @param {string} $ttf - the transition timing function value (e.g. `cubic-bezier(0,0,1,1)` or `ease-in-out`)
@mixin transition-timing-function($ttf) {
  @if is-transition-timing-mode-or-function($ttf) {
    @include prefixer(transition-timing-function, $ttf);
  }
  @else {
    @warn '`transition-timing-function: #{$ttf}` is not a valid transition-timing-function value';
  }
}

/// Checks if something is a transition value
///
/// @access public
/// @param {string} $transition - the transition value (e.g. `background .3s linear 0`)
/// @return {boolean} - true if is a transition value
@function is-transition($transition) {
  $defaults: (property: all, duration: 0s, timing: ease, delay: 0s);

  @if is-object($transition) {
    $transition: extend($defaults, $transition);
  }
  @else {
    $transition-property: nth-value($transition, 1);
    $transition-duration: nth-value($transition, 2);
    $transition-timing-function: nth-value($transition, 3);
    $transition-delay: nth-value($transition, 4);

    $transition: extend($defaults, ());

    @if is-defined($transition-property) {
      $transition: extend($transition, (property: $transition-property));
    }

    @if is-defined($transition-duration) {
      $transition: extend($transition, (duration: $transition-duration));
    }

    @if is-defined($transition-timing-function) {
      $transition: extend($transition, (timing: $transition-timing-function));
    }

    @if is-defined($transition-delay) {
      $transition: extend($transition, (delay: $transition-delay));
    }
  }

  $is-transition-valid: true;

  $transition-property: get($transition, property);

  @if not is-transition-property($transition-property) {
    $is-transition-valid: false;

    @warn '`transition-property: #{$transition-property}` is not a valid transition-property value';
  }

  @if $is-transition-valid {
    $transition-duration: get($transition, duration);

    @if not is-transition-time($transition-duration) {
      $is-transition-valid: false;

      @warn '`transition-duration: #{$transition-duration}` is not a valid transition-duration value';
    }
  }

  @if $is-transition-valid {
    $transition-timing-function: get($transition, timing);

    @if not is-transition-timing-mode-or-function($transition-timing-function) {
      $is-transition-valid: false;

      @warn '`transition-timing-function: #{$transition-timing-function}` is not a valid transition-timing-function value';
    }
  }

  @if $is-transition-valid {
    $transition-delay: get($transition, delay);

    @if not is-transition-time($transition-delay) {
      $is-transition-valid: false;

      @warn '`transition-delay: #{$transition-delay}` is not a valid transition-delay value';
    }
  }

  @return $is-transition-valid;
}

/// Checks if a comma separated list is a transition values list
///
/// @access public
/// @param {string | array | list} $transitions - the transition values list (e.g. `background .3s linear 0, top .2s ease-in-out 1s`)
/// @return {boolean} - true if is a transition values list
@function is-transitions($transitions...) {
  $is-transitions-valid: true;

  @each $transition in $transitions {
    @if $is-transitions-valid {
      $is-transitions-valid: is-transition($transition);
    }
  }

  @return $is-transitions-valid;
}

/// Transform mixin
///
/// @example scss - Usage - single transition
///   .transition-element {
///     @include transition(background .3s linear 0);
///   }
///
/// @example css - Output - single transition
///   .transition-element {
///     -webkit-transition: background .3s linear 0;
///     -moz-transition: background .3s linear 0;
///     -ms-transition: background .3s linear 0;
///     -o-transition: background .3s linear 0;
///     transition: background .3s linear 0;
///   }
///
/// @example scss - Usage - multiple transitions
///   .transition-element {
///     @include transition(background .3s linear 0, top .2s ease-in-out 1s);
///   }
///
/// @example css - Output - multiple transitions
///   .transition-element {
///     -webkit-transition: background .3s linear 0, top .2s ease-in-out 1s;
///     -moz-transition: background .3s linear 0, top .2s ease-in-out 1s;
///     -ms-transition: background .3s linear 0, top .2s ease-in-out 1s;
///     -o-transition: background .3s linear 0, top .2s ease-in-out 1s;
///     transition: background .3s linear 0, top .2s ease-in-out 1s;
///   }
/// @access public
/// @param {string | array | list} $transitions - the transitions list (e.g. `background .3s linear 0, top .2s ease-in-out 1s`)
@mixin transition($transitions...) {
  @if is-transitions($transitions...) {
    @include prefixer(transition, $transitions);
  }
  @else {
    @warn '`transition: #{$transitions}` one or more are not valid css transition values';
  }
}
