@charset 'UTF-8';

////
/// Flavor SCSS Mixins Position
/// @group mixins-position
/// @author blackmirror1980
////

/// Position modes
///
/// @access private
/// @type list
$position-modes: array-concat((static, absolute, fixed, relative, sticky), $css-default-modes);

/// Checks if something is a position mode
///
/// @access public
/// @param {string} $pm - the position mode
/// @return {boolean} - true if is position mode
@function is-position($pm) {
  @return is-defined($pm) and array-contains($position-modes, $pm);
}

/// Position point modes
///
/// @access private
/// @type list
$position-point-modes: array-concat((auto), $css-default-modes);

/// Checks if something is a position point value
///
/// @access public
/// @param {string | length} $ppv - the position point value
/// @return {boolean} - true if is position point value value
@function is-position-point-value($ppv) {
  @return is-defined($ppv) and (is-length($ppv) or array-contains($position-point-modes, $ppv));
}

/// Position points
///
/// @access private
/// @type list
$position-points: (top, right, bottom, left);

/// Checks if something is a position point
///
/// @access public
/// @param {string} $pp - the position point
/// @return {boolean} - true if is position point
@function is-position-point($pp) {
  @return is-defined($pp) and array-contains($position-points, $pp);
}

/// Position point mixin
///
/// @example scss - Usage
///   .position-point-element {
///     @include position-point(0, top);
///   }
///
/// @example css - Output
///   .position-point-element {
///     top: 0;
///   }
/// @access public
/// @param {string | length} $v - the point value (eg. 1px, 20%, auto, etc...)
/// @param {string} $p - the point (top, right, bottom, left)
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin position-point($v: auto, $p: null, $important: false) {
  @if is-position-point-value($v) and is-position-point($p) {
    #{$p}: $v important($important);
  }
  @else {
    @warn '`#{$p}: #{$v}` is not a valid position point value';
  }
}

/// Top mixin
///
/// @example scss - Usage
///   .top-element {
///     @include top(0);
///   }
///
/// @example css - Output
///   .top-element {
///     top: 0;
///   }
/// @see {mixin} position-point
/// @access public
/// @param {string | length} $v - the point value (eg. 1px, 20%, auto, etc...)
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin top($v: auto, $important: false) {
  @include position-point($v, top, $important);
}

/// Right mixin
///
/// @example scss - Usage
///   .right-element {
///     @include right(0);
///   }
///
/// @example css - Output
///   .right-element {
///     right: 0;
///   }
/// @see {mixin} position-point
/// @access public
/// @param {string | length} $v - the point value (eg. 1px, 20%, auto, etc...)
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin right($v: auto, $important: false) {
  @include position-point($v, right, $important);
}

/// Bottom mixin
///
/// @example scss - Usage
///   .bottom-element {
///     @include bottom(0);
///   }
///
/// @example css - Output
///   .bottom-element {
///     bottom: 0;
///   }
/// @see {mixin} position-point
/// @access public
/// @param {string | length} $v - the point value (eg. 1px, 20%, auto, etc...)
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin bottom($v: auto, $important: false) {
  @include position-point($v, bottom, $important);
}

/// Left mixin
///
/// @example scss - Usage
///   .left-element {
///     @include left(0);
///   }
///
/// @example css - Output
///   .left-element {
///     left: 0;
///   }
/// @see {mixin} position-point
/// @access public
/// @param {string | length} $v - the point value (eg. 1px, 20%, auto, etc...)
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin left($v: auto, $important: false) {
  @include position-point($v, left, $important);
}

/// Position mixin
///
/// @example scss - Usage
///   .position-element {
///     @include position(absolute 0 0 0 0);
///   }
///
/// @example css - Output
///   .position-element {
///     position: absolute;
///     top: 0;
///     right: 0;
///     bottom: 0;
///     left: 0;
///   }
///
/// @example scss - Usage - sticky
///   .position-element {
///     @include position(sticky 10px 2rem);
///   }
///
/// @example css - Output
///   .position-element {
///     position: -webkit-sticky;
///     position: sticky;
///     top: 10px;
///     right: 2rem;
///     bottom: 10px;
///     left: 2rem;
///   }
/// @access public
/// @param {string} $options - the options
/// @param {string} $options.position - the position mode
/// @param {length} $options.top - the top
/// @param {length} $options.right - the right
/// @param {length} $options.bottom - the bottom
/// @param {length} $options.left - the left
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin position($options, $important: false) {
  $settings: (position: static, top: null, right: null, bottom: null, left: null);

  @if is-object($options) {
    $settings: extend($settings, $options);
  }
  @else {
    $position: nth-value($options, 1);

    @if is-defined($position) {
      $settings: extend($settings, (position: $position));
    }

    $top: nth-value($options, 2, null);

    @if is-defined($top) {
      $settings: extend($settings, (top: $top));
    }

    $right: nth-value($options, 3, $top);

    @if is-defined($right) {
      $settings: extend($settings, (right: $right));
    }

    $bottom: nth-value($options, 4, $top);

    @if is-defined($bottom) {
      $settings: extend($settings, (bottom: $bottom));
    }

    $left: nth-value($options, 5, $right);

    @if is-defined($left) {
      $settings: extend($settings, (left: $left));
    }
  }

  $position: get($settings, position);

  @if is-defined($position) {
    @if is-position($position) {
      @if $position == sticky {
        position: -webkit-sticky important($important);
      }

      position: $position important($important);
    }
    @else {
      @warn '`position: #{$position}` is not a valid position mode';
    }
  }

  $top: get($settings, top);

  @if is-defined($top) {
    @include top($top, $important);
  }

  $right: get($settings, right);

  @if is-defined($right) {
    @include right($right, $important);
  }

  $bottom: get($settings, bottom);

  @if is-defined($bottom) {
    @include bottom($bottom, $important);
  }

  $left: get($settings, left);

  @if is-defined($left) {
    @include left($left, $important);
  }
}
