@use 'sass:map';
@use 'sass:list';
@use '../global/variables' as var;

// ブレイクポイントのビューポートサイズとメディアクエリ
//
// `$grid-breakpoints` グローバル変数で定義されたマップがデフォルトで `$breakpoints` 引数として使用されます。

// 次のブレイクポイントの名前を返します。最後のブレイクポイントの場合は null を返します。
//
//    >> breakpoint-next(sm)
//    md
//    >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
//    md
//    >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl))
//    md
@function breakpoint-next($name, $breakpoints: var.$grid-breakpoints, $breakpoint-names: map.keys($breakpoints)) {
  $n: list.index($breakpoint-names, $name);

  @if not $n {
    @error "breakpoint `#{$name}` not found in `#{$breakpoints}`";
  }

  @return if($n < list.length($breakpoint-names), list.nth($breakpoint-names, $n + 1), null);
}

// 最小ブレイクポイント幅。最小（最初）のブレイクポイントの場合は null。
//
//    >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
//    576px
@function breakpoint-min($name, $breakpoints: var.$grid-breakpoints) {
  $min: map.get($breakpoints, $name);

  @return if($min != 0, $min, null);
}

// 最大ブレイクポイント幅。
// `min-` と `max-` プレフィックスおよび小数点を含むビューポートの制限に対応するため、
// 最大値を 0.02px 減らしています。
// 参照: https://www.w3.org/TR/mediaqueries-4/#mq-min-max
// Safariの現在の丸め込みバグに対応するため、0.01pxではなく0.02pxを使用しています。
// 参照: https://bugs.webkit.org/show_bug.cgi?id=178261
//
//    >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
//    767.98px
@function breakpoint-max($name, $breakpoints: var.$grid-breakpoints) {
  $max: map.get($breakpoints, $name);

  @return if($max and $max > 0, $max - 0.02, null);
}

// 最小ブレイクポイントの場合は空文字列を返し、それ以外の場合は名前の前にダッシュを付けて返します。
// レスポンシブユーティリティの作成に便利です。
//
//    >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
//    ""  (空文字列を返します)
//    >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
//    "-sm"
@function breakpoint-infix($name, $breakpoints: var.$grid-breakpoints) {
  @return if(breakpoint-min($name, $breakpoints) == null, '', '-#{$name}');
}

// 最小ブレイクポイント幅以上のメディア。最小ブレイクポイントの場合はクエリなし。
// 指定されたブレイクポイントおよびそれより大きい画面で @content を適用します。
@mixin media-breakpoint-up($name, $breakpoints: var.$grid-breakpoints) {
  $min: breakpoint-min($name, $breakpoints);

  @if $min {
    @media (min-width: $min) {
      @content;
    }
  } @else {
    @content;
  }
}

// 最大ブレイクポイント幅以下のメディア。最大ブレイクポイントの場合はクエリなし。
// 指定されたブレイクポイントおよびそれより小さい画面で @content を適用します。
@mixin media-breakpoint-down($name, $breakpoints: var.$grid-breakpoints) {
  $max: breakpoint-max($name, $breakpoints);

  @if $max {
    @media (max-width: $max) {
      @content;
    }
  } @else {
    @content;
  }
}

// 複数のブレイクポイント幅にまたがるメディア。
// 最小と最大のブレイクポイントの間で @content を適用します。
@mixin media-breakpoint-between($lower, $upper, $breakpoints: var.$grid-breakpoints) {
  $min: breakpoint-min($lower, $breakpoints);
  $max: breakpoint-max($upper, $breakpoints);

  @if $min != null and $max != null {
    @media (min-width: $min) and (max-width: $max) {
      @content;
    }
  } @else if $max == null {
    @include media-breakpoint-up($lower, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include media-breakpoint-down($upper, $breakpoints) {
      @content;
    }
  }
}

// ブレイクポイントの最小幅と最大幅の間のメディア。
// 最小ブレイクポイントには最小値なし、最大ブレイクポイントには最大値なし。
// 指定されたブレイクポイントのみで @content を適用し、より広いまたは狭い画面では適用しません。
@mixin media-breakpoint-only($name, $breakpoints: var.$grid-breakpoints) {
  $min: breakpoint-min($name, $breakpoints);
  $next: breakpoint-next($name, $breakpoints);
  $max: breakpoint-max($next, $breakpoints);

  @if $min != null and $max != null {
    @media (min-width: $min) and (max-width: $max) {
      @content;
    }
  } @else if $max == null {
    @include media-breakpoint-up($name, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include media-breakpoint-down($next, $breakpoints) {
      @content;
    }
  }
}
