@use 'sass:list';
@use 'sass:string';
////
/// @group utils.transitions
////

@use 'collections.scss' as *;
@use 'strings.scss' as *;
@use 'units.scss' as *;

/// Simplified syntax for transitioning multiple individual properties on
/// an element, defaulting to standardized values for duration and easing.
///
/// @param {list} $proplist A list of properties to be transitioned
/// @param {duration} $dur [$transition-dur] The duration of the transition
/// @param {string} $ease [$transition-ease] The easing to be used in the transition
/// @param {duration} $delay [0ms] The delay for the transition
///
/// @example transition: transition(transform opacity);
/// @example transition: transition(transform opacity, 0.5s);
/// @example transition: transition(transform opacity, $ease: $ease-out-quart);

@function transition($proplist, $dur: 0.2s, $ease: $ease-out-cubic, $delay: null) {
    $transitions: ();

    $attrs: ($dur);

    @if ($ease) {
        $attrs: list.append($attrs, $ease);
    }

    @if ($delay) {
        $attrs: list.append($attrs, $delay);
    }

    @each $prop in $proplist {
        $transitions: list.append($transitions, $prop string.unquote(list-join($attrs, ' ')));
    }

    @return string.unquote(list-join($transitions, ', '));
}

/// Mixin version of the transition function.

@mixin transition($proplist, $dur: 0.2s, $ease: $ease-out-cubic, $delay: null) {
    transition: transition($proplist, $dur, $ease, $delay);
}

/// Set of mixins that generate classes for a vue transition. These dot not expose the full power of
/// vue transitions but it does simplify the creation of many by using simplified naming and grouping classes
/// that are commonly defined together. The outer mixin contains the inner (vt-*) mixins.
///
/// @param {string} $name The name of the transition
///
/// @example
/// // Create a fade transition by definining just the css transition and the hidden state.
///  @include vue-transition(fade) {
///
///     // define the transition
///     @include vt-transition {
///         transition: opacity 500ms;
///     }
///
///     // define the hidden state (the non-hidden state is implicty -- the normal state)
///     @include vt-hidden {
///         opacity: 0;
///     }
/// };
///
/// @example
/// // Create a slide and fade transition by
///  @include vue-transition(slide-x) {
///
///     // define the hidden state (the non-hidden state is implicty -- the normal state)
///     @include vt-transition {
///         transition: opacity 500ms;
///     }
///
///     // the hidden state before entering
///     @include vt-hidden-enter {
///         transform: translateY(-100px);
///         opacity: 0;
///     }
///
///     // the hidden after exiting
///     @include vt-hidden-leave {
///         transform: translateY(100px);
///         opacity: 0;
///     }
/// };

@mixin vue-transition($name) {
    .#{$name} {
        @content;
    }
}

/// Vue transition: Defines the transition  definition for a vue transition.
@mixin vt-transition() {
    &-enter-active,
    &-leave-active {
        @content;
    }
}

/// Vue transition: Defines the hidden state when that state is shared as the element is added and
/// also removed from the DOM. Use in the content area of the vue-transition mixin.
@mixin vt-hidden() {
    // vue2
    &-enter,

    // vue3
    &-enter-from,
    &-leave-to {
        @content;
    }
}

/// Vue transition: Defines the hidden state as an element is added into the DOM. Removed one frame
/// after element is inserted.

@mixin vt-hidden-enter() {
    // vue 2
    &-enter,

    // vue 3
    &-enter-from {
        @content;
    }
}

/// Vue transition: Defines a hidden state when an element is removed from the DOM.

@mixin vt-hidden-leave() {
    &-leave-to {
        @content;
    }
}

/// Vue transition: Defines the state as an element is actively transitioning when the state is
/// shared for both enter and leave. Use in the content area of the vue-transition mixin.

@mixin vt-active() {
    &-enter-active,
    &-leave-active {
        @content;
    }
}

/// Vue transition: Defines the active transition state as an element is being added to the DOM. Use
/// in the content area of the vue-transition mixin.

@mixin vt-entering() {
    &-enter-active {
        @content;
    }
}

/// Defines the the active transition state as element is begin removed from the DOM. Use in the
/// content area of the vue-transition mixin.

@mixin vt-leaving() {
    &-leave-active {
        @content;
    }
}

/// Vue transition: Simple helper that pins an object as it is being removed from the DOM (to make
/// room for the incoming element). In some cases just absolute positioning is enough, but in others
/// you may need to provide additional support (like a width or height) as @content or specific
/// top/left values. It also might be better to use a grid as a container where multiple elements
/// can easily occupy the same space but still size naturally and impact the layout of other
/// elments.

@mixin vt-pin($top: 0, $left: 0) {
    &-leave-active {
        position: absolute;
        top: $top;
        left: $left;
        @content;
    }
}

/// Creates a basic vue fade transition
///
/// @example vue-transition-fade() // =>
///  .fade-enter-active .fade-leave-active {
///   transition: opacity 300ms cubic-bezier(0.165, 0.84, 0.44, 1);
///  }
///  .fade-enter-active {
///    transition-delay: 0;
///  }
///  .fade-leave-active {
///    transition-delay: 0;
///  }
///  .fade-enter,
///  .fade-leave-to {
///    opacity: 0;
///  }

@mixin vue-transition-fade(
    $name: 'fade',
    $lookup: 'slow',
    $dur: 0.2s,
    $ease: $ease-out-cubic,
    $enter-delay: 0,
    $leave-delay: 0,
    $pin: false,
    $leave-pointer-events: null // none
) {
    .#{$name}-enter-active,
    .#{$name}-leave-active {
        transition: opacity $dur $ease;
    }

    @if ($enter-delay) {
        .#{$name}-enter-active {
            transition-delay: $enter-delay;
        }
    }

    @if ($leave-delay) {
        .#{$name}-leave-active {
            transition-delay: $leave-delay;
        }
    }

    .#{$name}-enter,
    .#{$name}-enter-from,
    .#{$name}-leave-to {
        opacity: 0;
    }

    @if ($pin) {
        .#{$name}-leave-active {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
        }
    }

    @if ($leave-pointer-events) {
        .#{$name}-leave-active {
            pointer-events: $leave-pointer-events;
        }
    }
}

/// Creates a basic vue slide and fade transition
///
/// @example @include vue-transition-slide-fade() // =>
///
/// .class .slide-leave-active,
/// .class .slide-enter-active {
///   transition: transform 150ms cubic-bezier(0.165, 0.84, 0.44, 1), opacity 150ms cubic-bezier(0.165, 0.84, 0.44, 1);
/// }
/// .class .slide-enter {
///   opacity: 0;
///   transform: translateY(100px);
/// }
/// .class .slide-leave-to {
///   opacity: 0;
///   transform: translateY(-100px);
/// }
/// .class .slide-enter-active {
///   position: relative;
/// }
/// .class .slide-leave-active {
///   position: absolute;
///   top: 0;
///   left: 0;
///   width: 100%;
/// }

@mixin vue-transition-slide-fade(
    $name: 'slide',
    $lookup: null,
    $dur: 0.2s,
    $ease: $ease-out-cubic,
    $distance: 100px,
    $axis: 'Y',
    $pin: true
) {
    .#{$name}-leave-active,
    .#{$name}-enter-active {
        transition:
            transform $dur $ease,
            opacity $dur $ease;
    }
    .#{$name}-enter, // vue 2
    .#{$name}-enter-from {
        // vue 3
        opacity: 0;
        @if ($axis == 'X' or $axis == 'x') {
            transform: translateX($distance);
        } @else {
            transform: translateY($distance);
        }
    }

    .#{$name}-leave-to {
        opacity: 0;
        @if ($axis == 'X' or $axis == 'x') {
            transform: translateX($distance * -1);
        } @else {
            transform: translateY($distance * -1);
        }
    }

    @if ($pin) {
        .#{$name}-enter-active {
            position: relative;
        }
        .#{$name}-leave-active {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
        }
    }
}

// @mixin t-slide-fade-reverse(

// ----------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------

/// Cubic-bezier for Penner ease in cubic
$ease-in-cubic: cubic-bezier(0.55, 0.055, 0.675, 0.19);

/// Cubic-bezier for Penner ease in cubic
$ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);

/// Cubic-bezier for Penner ease in cubic
$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);

/// Cubic-bezier for Penner ease in circ
$ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.335);

/// Cubic-bezier for Penner ease out circ
$ease-out-circ: cubic-bezier(0.075, 0.82, 0.165, 1);

/// Cubic-bezier for Penner ease in-out circ
$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.15, 0.86);

/// Cubic-bezier for Penner ease in expo
$ease-in-expo: cubic-bezier(0.95, 0.05, 0.795, 0.035);

/// Cubic-bezier for Penner ease out expo
$ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);

/// Cubic-bezier for Penner ease in-out expo
$ease-in-out-expo: cubic-bezier(1, 0, 0, 1);

/// Cubic-bezier for Penner ease in quad
$ease-in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);

/// Cubic-bezier for Penner ease out quad
$ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);

/// Cubic-bezier for Penner ease in-out quad
$ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);

/// Cubic-bezier for Penner ease in quart
$ease-in-quart: cubic-bezier(0.895, 0.03, 0.685, 0.22);

/// Cubic-bezier for Penner ease out quart
$ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);

/// Cubic-bezier for Penner ease in-out quart
$ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);

/// Cubic-bezier for Penner ease in quint
$ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);

/// Cubic-bezier for Penner ease out quint
$ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);

/// Cubic-bezier for Penner ease in-out quint
$ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);

/// Cubic-bezier for Penner ease in sine
$ease-in-sine: cubic-bezier(0.47, 0, 0.745, 0.715);

/// Cubic-bezier for Penner ease out sine
$ease-out-sine: cubic-bezier(0.39, 0.575, 0.565, 1);

/// Cubic-bezier for Penner ease in-out sine
$ease-in-out-sine: cubic-bezier(0.445, 0.05, 0.55, 0.95);

/// Cubic-bezier for Penner ease in back
$ease-in-back: cubic-bezier(0.6, -0.28, 0.735, 0.045);

/// Cubic-bezier for Penner ease out back
$ease-out-back: cubic-bezier(0.175, 0.885, 0.32, 1.275);

/// Cubic-bezier for Penner ease in-out back
$ease-in-out-back: cubic-bezier(0.68, -0.55, 0.265, 1.55);

/// Cubic-bezier for custopm ease with a small bounce
$ease-out-smallbounce: cubic-bezier(0.175, 0.885, 0.315, 1.19);
