@import "ionic.functions";

// Appearance
// --------------------------------------------------

@mixin appearance($val) {
  -moz-appearance: $val;
  -ms-appearance: $val;
  -webkit-appearance: $val;
  appearance: $val;
}

// Input Placeholder
// --------------------------------------------------

@mixin placeholder($color: #999, $text-indent: 0) {
  &::-moz-placeholder { // Firefox 19+
    color: $color;
  }

  &:-ms-input-placeholder {
    color: $color;
  }

  &::-webkit-input-placeholder {
    // Safari placeholder margin issue
    text-indent: $text-indent;
    color: $color;
  }
}

// Check that the given map values are in ascending order
// ---------------------------------------------------------------------------------

@mixin assert-ascending($map, $map-name) {
  $prev-key: null;
  $prev-num: null;
  @each $key, $num in $map {
    @if $prev-num == null {
      // Do nothing
    } @else if not comparable($prev-num, $num) {
      @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !";
    } @else if $prev-num >= $num {
      @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !";
    }
    $prev-key: $key;
    $prev-num: $num;
  }
}

// Check that the first value in the given map starts at 0
// ---------------------------------------------------------------------------------

@mixin assert-starts-at-zero($map, $map-name) {
  $values: map-values($map);
  $first-value: nth($values, 1);
  @if $first-value != 0 {
    @warn "First value in `#{$map-name}` must start at 0, but starts at #{$first-value}.";
  }
}

// Breakpoint Mixins
// ---------------------------------------------------------------------------------

// Breakpoint viewport sizes and media queries.
//
// Breakpoints are defined as a map of (name: minimum width), order from small to large:
//
//    (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)
//
// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.

// ---------------------------------------------------------------------------------

// Minimum breakpoint width. Null for the smallest (first) breakpoint.
//
//    >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
//    576px
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
  $min: map-get($breakpoints, $name);
  @return if($min != 0, $min, null);
}

// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash infront.
// Useful for making responsive utilities.
//
//    >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
//    ""  (Returns a blank string)
//    >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
//    "-sm"
@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {
  @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}");
}

// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.
// Makes the @content apply to the given breakpoint and wider.
@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
  $min: breakpoint-min($name, $breakpoints);
  @if $min {
    @media (min-width: $min) {
      @content;
    }
  } @else {
    @content;
  }
}

// Name of the next breakpoint, or null for the last breakpoint.
//
//    >> breakpoint-next(sm)
//    md
//    >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
//    md
//    >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl))
//    md
@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {
  $n: index($breakpoint-names, $name);
  @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);
}

// Maximum breakpoint width. Null for the largest (last) breakpoint.
// The maximum value is calculated as the minimum of the next one less 0.1.
//
//    >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
//    767px
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
  $next: breakpoint-next($name, $breakpoints);
  @return if($next, breakpoint-min($next, $breakpoints) - 1px, null);
}

// Media of at most the maximum breakpoint width. No query for the largest breakpoint.
// Makes the @content apply to the given breakpoint and narrower.
@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {
  $max: breakpoint-max($name, $breakpoints);
  @if $max {
    @media (max-width: $max) {
      @content;
    }
  } @else {
    @content;
  }
}

@mixin multi-dir() {
  @if $app-direction == multi {
    $root: #{&};
    @at-root [dir="ltr"], [dir="rtl"] {
      #{$root} {
        @content;
      }
    }
  } @else {
    @content;
  }
}

@mixin rtl() {
  @if $app-direction == multi {
    $root: #{&};
    @at-root [dir="rtl"] {
      #{$root} {
        @content;
      }
    }
  } @else if $app-direction == rtl {
    @content;
  }
}

@mixin ltr() {
  @if $app-direction == multi {
    $root: #{&};
    @at-root [dir="ltr"] {
      #{$root} {
        @content;
      }
    }
  } @else if $app-direction == ltr {
    @content;
  }
}

// If deprecated variable exists, use it, otherwise, use alternative
// @param {string} $property - property to default
// @param {string} $variable - the deprecated variable
// ----------------------------------------------------------
@mixin deprecated-variable($property, $variable) {
  @if $variable == null {
    @content;
  } @else {
    // TODO find variable name
    @warn "you are using a deprecated variable";
    #{$property}: $variable;
  }
}

// SVG Background Image Mixin
// @param {string} $svg
// ----------------------------------------------------------
@mixin svg-background-image($svg, $flip-rtl: false) {
  $url: url-encode($svg);
  $viewBox: str-split(str-extract($svg, "viewBox='", "'"), " ");

  @if $flip-rtl != true or $viewBox == null {
    @include multi-dir() {
      background-image: url("data:image/svg+xml;charset=utf-8,#{$url}");
    }
  } @else {
    $transform: "transform='translate(#{nth($viewBox, 3)}, 0) scale(-1, 1)'";
    $flipped-url: $svg;
    $flipped-url: str-replace($flipped-url, "<path", "<path #{$transform}");
    $flipped-url: str-replace($flipped-url, "<line", "<line #{$transform}");
    $flipped-url: str-replace($flipped-url, "<polygon", "<polygon #{$transform}");
    $flipped-url: url-encode($flipped-url);

    @include ltr () {
      background-image: url("data:image/svg+xml;charset=utf-8,#{$url}");
    }
    @include rtl() {
      background-image: url("data:image/svg+xml;charset=utf-8,#{$flipped-url}");
    }
  }
}

// Add property horizontal
// @param {string} $start
// @param {string} $end
// ----------------------------------------------------------
@mixin property-horizontal($prop, $start, $end: $start) {
  @if $start == $end {
    @include multi-dir() {
      #{$prop}-left: $start;
      #{$prop}-right: $end;
    }
  } @else {
    @include ltr() {
      #{$prop}-left: $start;
      #{$prop}-right: $end;
    }
    @include rtl() {
      #{$prop}-left: $end;
      #{$prop}-right: $start;
    }
  }
}

// Add property for all directions
// @param {string} $prop
// @param {string} $top
// @param {string} $end
// @param {string} $bottom
// @param {string} $start
// @param {boolean} $content include content or use default
// ----------------------------------------------------------
@mixin property($prop, $top, $end: $top, $bottom: $top, $start: $end) {
  @if $top == $end and $top == $bottom and $top == $start {
    @include multi-dir() {
      #{$prop}: $top;
    }
  } @else if $top == $bottom and $end == $start and $top != null and $end != null {
    @include multi-dir() {
      #{$prop}: $top $end;
    }
  } @else if $end == $start and $top != null and $end != null and $bottom != null {
    @include multi-dir() {
      #{$prop}: $top $end $bottom;
    }
  } @else if $top != null and $end != null and $bottom != null and $start != null {
    @include ltr() {
      #{$prop}: $top $end $bottom $start;
    }
    @include rtl() {
      #{$prop}: $top $start $bottom $end;
    }
  } @else {
    @include property-horizontal($prop, $start, $end);
    @include multi-dir() {
      #{$prop}-top: $top;
      #{$prop}-bottom: $bottom;
    }
  }
}

// Add padding horizontal
// @param {string} $start
// @param {string} $end
// ----------------------------------------------------------
@mixin padding-horizontal($start, $end: $start) {
  @include property-horizontal(padding, $start, $end);
}

// Add padding for all directions
// @param {string} $top
// @param {string} $end
// @param {string} $bottom
// @param {string} $start
// ----------------------------------------------------------
@mixin padding($top, $end: $top, $bottom: $top, $start: $end) {
  @include property(padding, $top, $end, $bottom, $start);
}

// Add margin horizontal
// @param {string} $start
// @param {string} $end
// ----------------------------------------------------------
@mixin margin-horizontal($start, $end: $start) {
  @include property-horizontal(margin, $start, $end);
}

// Add margin for all directions
// @param {string} $top
// @param {string} $end
// @param {string} $bottom
// @param {string} $start
// ----------------------------------------------------------
@mixin margin($top, $end: $top, $bottom: $top, $start: $end) {
  @include property(margin, $top, $end, $bottom, $start);
}

// Add position horizontal
// @param {string} $start - amount to position start
// @param {string} $end - amount to left: 0; end
// ----------------------------------------------------------
@mixin position-horizontal($start: null, $end: null) {
  @if $start == $end {
    @include multi-dir() {
      left: $start;
      right: $end;
    }
  } @else {
    @include ltr() {
      left: $start;
      right: $end;
    }
    @include rtl() {
      left: $end;
      right: $start;
    }
  }
}

// Add position for all directions
// @param {string} $top
// @param {string} $end
// @param {string} $bottom
// @param {string} $start
// ----------------------------------------------------------
@mixin position($top: null, $end: null, $bottom: null, $start: null) {
  @include position-horizontal($start, $end);
  top: $top;
  bottom: $bottom;
}

// Add border radius for all directions
// @param {string} $top-start
// @param {string} $top-end
// @param {string} $bottom-end
// @param {string} $bottom-start
// ----------------------------------------------------------
@mixin border-radius($top-start, $top-end: $top-start, $bottom-end: $top-start, $bottom-start: $top-end) {
  @if $top-start == $top-end and $top-start == $bottom-end and $top-start == $bottom-start {
    @include multi-dir() {
      border-radius: $top-start;
    }
  } @else {
    @include ltr() {
      border-top-left-radius: $top-start;
      border-top-right-radius: $top-end;
      border-bottom-right-radius: $bottom-end;
      border-bottom-left-radius: $bottom-start;
    }

    @include rtl() {
      border-top-left-radius: $top-end;
      border-top-right-radius: $top-start;
      border-bottom-right-radius: $bottom-start;
      border-bottom-left-radius: $bottom-end;
    }
  }
}

// Sets correct text align with support for old browsers
// @param {string} $direction - text direction
// @param {string} $decorator - !important
// ----------------------------------------------------------
@mixin text-align($direction, $decorator: null) {
  @if $direction == start {
    text-align: left;
    text-align: start $decorator;
  } @else if $direction == end {
    text-align: right;
    text-align: end $decorator;
  } @else {
    text-align: $direction $decorator;
  }
}

// Add direction for all directions
// @param {string} $dir - Direction on LTR
@mixin direction($dir) {
  $other-dir: null;

  @if $dir == ltr {
    $other-dir: rtl;
  } @else {
    $other-dir: ltr;
  }

  @include ltr() {
    direction: $dir;
  }
  @include rtl() {
    direction: $other-dir;
  }
}

// Add float for all directions
// @param {string} $side
// @param {string} $decorator - !important
@mixin float($side, $decorator: null) {
  @if $side == start {
    @include ltr() {
      float: left $decorator;
    }
    @include rtl() {
      float: right $decorator;
    }
  } @else if $side == end {
    @include ltr() {
      float: right $decorator;
    }
    @include rtl() {
      float: left $decorator;
    }
  } @else {
    @include multi-dir() {
      float: $side $decorator;
    }
  }
}

@mixin background-position($horizontal, $horizontal-amount: null, $vertical: null, $vertical-amount: null) {
  @if $horizontal == start or $horizontal == end {
    $horizontal-ltr: null;
    $horizontal-rtl: null;
    @if $horizontal == start {
      $horizontal-ltr: left;
      $horizontal-rtl: right;
    } @else {
      $horizontal-ltr: right;
      $horizontal-rtl: left;
    }

    @include ltr() {
      background-position: $horizontal-ltr $horizontal-amount $vertical $vertical-amount;
    }
    @include rtl() {
      background-position: $horizontal-rtl $horizontal-amount $vertical $vertical-amount;
    }
  } @else {
    @include multi-dir() {
      background-position: $horizontal $horizontal-amount $vertical $vertical-amount;
    }
  }
}

@mixin transform-origin($x-axis, $y-axis: null) {
  @if $x-axis == start {
    @include ltr() {
      transform-origin: left $y-axis;
    }
    @include rtl() {
      transform-origin: right $y-axis;
    }
  } @else if $x-axis == end {
    @include ltr() {
      transform-origin: right $y-axis;
    }
    @include rtl() {
      transform-origin: left $y-axis;
    }
  } @else if $x-axis == left or $x-axis == right {
    @include multi-dir() {
      transform-origin: $x-axis $y-axis;
    }
  } @else {
    @include ltr() {
      transform-origin: $x-axis $y-axis;
    }
    @include rtl() {
      transform-origin: calc(100% - #{$x-axis}) $y-axis;
    }
  }
}

// Add transform for all directions
// @param {string} $transforms - comma separated list of transforms
@mixin transform($transforms...) {
  $extra: null;

  $x: null;
  $ltr-translate: null;
  $rtl-translate: null;

  @each $transform in $transforms {
    @if (str-index($transform, translate3d)) {
      $transform: str-replace($transform, 'translate3d(');
      $transform: str-replace($transform, ')');

      $coordinates: str-split($transform, ',');

      $x: nth($coordinates, 1);
      $y: nth($coordinates, 2);
      $z: nth($coordinates, 3);

      $ltr-translate: translate3d($x, $y, $z);
      $rtl-translate: translate3d(calc(-1 * #{$x}), $y, $z);
    } @else {
      @if $extra == null {
        $extra: $transform;
      } @else {
        $extra: $extra $transform;
      }
    }
  }

  @if $x == '0' or $x == null {
    @include multi-dir() {
      transform: $ltr-translate $extra;
    }
  } @else {
    @include ltr() {
      transform: $ltr-translate $extra;
    }

    @include rtl() {
      transform: $rtl-translate $extra;
    }
  }
}


// Add safe-area transform for all directions
// Used by item-reorder
// @param {string} $transforms - comma separated list of transforms
@mixin reorder-safe-translate($transforms...) {
  $extra: null;

  $x: null;
  $ltr-translate: null;
  $rtl-translate: null;

  @each $transform in $transforms {
    @if (str-index($transform, translate3d)) {
      $transform: str-replace($transform, 'translate3d(');
      $transform: str-replace($transform, ')');

      $coordinates: str-split($transform, ',');

      $x: nth($coordinates, 1);
      $y: nth($coordinates, 2);
      $z: nth($coordinates, 3);

      $ltr-translate: translate3d(calc(-1 * constant(safe-area-inset-right)), 0, 0);
      $rtl-translate: translate3d(constant(safe-area-inset-left), $y, $z);

      $ltr-env-translate: translate3d(calc(-1 * env(safe-area-inset-right)), 0, 0);
      $rtl-env-translate: translate3d(env(safe-area-inset-left), $y, $z);

    } @else {
      @if $extra == null {
        $extra: $transform;
      } @else {
        $extra: $extra $transform;
      }
    }
  }

  @if $x == '0' or $x == null {
    @include multi-dir() {
      transform: $ltr-translate $extra;
      transform: $ltr-env-translate $extra;
    }
  } @else {
    @include ltr() {
      transform: $ltr-translate $extra;
      transform: $ltr-env-translate $extra;
    }

    @include rtl() {
      transform: $rtl-translate $extra;
      transform: $rtl-env-translate $extra;
    }
  }
}

// Add safe-area-padding for all directions
// @param {string} $top
// @param {string} $end
// @param {string} $bottom
// @param {string} $start
// ----------------------------------------------------------
@mixin safe-area-padding($top, $end: $top, $bottom: $top, $start: $end) {
  $safe-area-start: null;
  $safe-area-end: null;
  $safe-area-start-env: null;
  $safe-area-end-env: null;

  @if ($start) {
    $safe-area-start: calc(constant(safe-area-inset-left) + #{$start});
    $safe-area-start-env: calc(env(safe-area-inset-left) + #{$start});
  }
  @if ($end) {
    $safe-area-end-env: calc(constant(safe-area-inset-right) + #{$end});
    $safe-area-end-env: calc(env(safe-area-inset-right) + #{$end});
  }

  @include padding($top, $end, $bottom, $start);

  @media screen and (orientation: landscape) {
    @include padding($top, $safe-area-end, $bottom, $safe-area-start);
    @include padding($top, $safe-area-end-env, $bottom, $safe-area-start-env);
  }
}


// Add safe area padding horizontal
// @param {string} $start
// @param {string} $end
// ----------------------------------------------------------
@mixin safe-area-padding-horizontal($start, $end: $start) {
  $safe-area-end: null;
  $safe-area-start: null;
  $safe-area-start-env: null;
  $safe-area-end-env: null;

  @if ($end) {
    $safe-area-end: calc(constant(safe-area-inset-right) + #{$end});
    $safe-area-end-env: calc(env(safe-area-inset-right) + #{$end});
  }
  @if ($start) {
    $safe-area-start: calc(constant(safe-area-inset-left) + #{$start});
    $safe-area-start-env: calc(env(safe-area-inset-left) + #{$start});
  }

  @include padding-horizontal($start, $end);

  @media screen and (orientation: landscape) {
    @include padding-horizontal($safe-area-start, $safe-area-end);
    @include padding-horizontal($safe-area-start-env, $safe-area-end-env);
  }
}


// Add safe position horizontal
// @param {string} $start - amount to position start
// @param {string} $end - amount to left: 0; end
// ----------------------------------------------------------
@mixin safe-position-horizontal($start: null, $end: null){
  $safe-area-start: null;
  $safe-area-end: null;
  $safe-area-start-env: null;
  $safe-area-end-env: null;
  @if ($start) {
    $safe-area-start: calc(constant(safe-area-inset-left) + #{$start});
    $safe-area-start-env: calc(env(safe-area-inset-left) + #{$start});
  }
  @if ($end) {
    $safe-area-end: calc(constant(safe-area-inset-right) + #{$end});
    $safe-area-end-env: calc(env(safe-area-inset-right) + #{$end});
  }

  @if $safe-area-start == $safe-area-end {
    @include multi-dir() {
      left: $safe-area-start;
      right: $safe-area-end;
    }
    @include multi-dir() {
      left: $safe-area-start-env;
      right: $safe-area-end-env;
    }
  } @else {
    @include ltr() {
      left: $safe-area-start;
      right: $safe-area-end;
    }
    @include ltr() {
      left: $safe-area-start-env;
      right: $safe-area-end-env;
    }
    @include rtl() {
      left: $safe-area-end;
      right: $safe-area-start;
    }
    @include rtl() {
      left: $safe-area-end-env;
      right: $safe-area-start-env;
    }
  }
}

