/* ============================================================================
   @CORE -> MIXINS -> GENERATE AT BREAKPOINTS
   ========================================================================= */


/**
 * This mixin will take a class selector e.g. `.u-align-v-inline-top` and make
 * it available at any breakpoint you wish. Out of the box Scally applies this
 * to all utilities, all objects, and some of the layout modules (the
 * layout modules it isn't applied too apply this behavior custom to that
 * module), however it is turned off by default in favour of leaner stylesheets
 * and not all UI's are responsive. Turning it on requires setting the relevant
 * setting to 'true' e.g. for the Alignments utility if I wanted the "inline
 * vertical align top" utility: `.u-align-v-inline-top` to use this mixin I
 * change this setting:
 *
   $u-align-apply-breakpoints-for-v-inline-top: false !default;
 *
 * To `true` in my master stylesheet above the relevant `@import` like so:
 *
   $u-align-apply-breakpoints-for-v-inline-top: true;
   @import "scally/utilities/u-alignments";
 *
 * Everything in Scally that uses this mixin features a setting to apply the
 * breakpoint(s) for the mixin. So again if we look at the Alignments utility
 * you'll see this setting:
 *
   $u-align-apply-at-breakpoints: $default-breakpoints !default;
 *
 * Where `$default-breakpoints` equals the 'Lap' breakpoint defined in
 * Core -> Settings -> Breakpoints. All of these settings have the same
 * `$default-breakpoints` value so if this feature is turned on everything that
 * uses this mixin in Scally is available at the 'Lap' breakpoint. You can
 * override this setting and apply any of the Scally breakpoints or any
 * custom breakpoint you wish i.e. it will accept any integer. So if we wanted
 * this utility: `.u-align-v-inline-top` to be applied at the following Scally
 * breakpoints: 'Lap', 'Lap-large', 'Desk', and 'Desk-large' we would update
 * the `$u-align-apply-at-breakpoints` setting in our master stylesheet like
 * so:
 *
   // Set the breakpoints
   $u-align-apply-at-breakpoints: (lap, lap-large, desk, desk-large);
   // Turn the feature on
   $u-align-apply-breakpoints-for-v-inline-top: true;
   // Import the utility
   @import "scally/utilities/u-alignments";
 *
 * If you wanted it available at ALL of Scally's breakpoints then you can pass
 * in the keyword "all" like so:
 *
   $u-align-apply-at-breakpoints: (all);
 *
 * If you wanted this utility applied at a custom breakpoint of "999px" it's as
 * easy as:
 *
   $u-align-apply-at-breakpoints: 999;
 *
 * Or more than one custom breakpoint e.g. "999px" and "1366px":
 *
   $u-align-apply-at-breakpoints: (999, 1366);
 *
 * Or a mix of custom breakpoints and Scally breakpoints:
 *
   $u-align-apply-at-breakpoints: (lap, desk, 1366);
 *
 * The default for the media query generated by this mixin is `min-width` e.g.
 *
   @media (min-width: 40.0625em) {
     .u-align-v-inline-top-from-lap {
       vertical-align: top !important;
     }
   }
 *
 * For `max-width` media queries you need to apply the 'max' flag when defining
 * your breakpoints e.g.
 *
   $u-align-apply-at-breakpoints: (lap max, desk max, 1366 max);
 *
 * The format of the generated class using the default `min-width` media query
 * is:
 *
   .[class-selector]-from-[breakpoint]
 *
 * E.g.
 *
   .u-align-v-inline-top-from-lap
   .u-align-v-inline-top-from-desk
   .u-align-v-inline-top-from-desk-large
   .u-align-v-inline-top-from-999
 *
 * The format of the generated class using a `max-width` media query is:
 *
   .[class-selector]-up-to-[breakpoint]
 *
 * E.g.
 *
   .u-align-v-inline-top-up-to-lap
   .u-align-v-inline-top-up-to-desk
   .u-align-v-inline-top-up-to-desk-large
   .u-align-v-inline-top-up-to-999
 *
 * Sometimes the selector that is passed into the mixin is more complex than a
 * single class. To account for this apply the "{bp}" flag to the part of the
 * selector that needs it e.g.
 *
   .o-list-block--large{bp} > li
   .o-list-inline--divider{bp} > li + li

   @include generate-at-breakpoints('.o-list-block--large{bp} > li',
    $o-list-block-apply-at-breakpoints)

   @include generate-at-breakpoints('.o-list-inline--divider{bp} > li + li',
    $o-list-inline-apply-at-breakpoints)
 */


/**
 * Settings.
 */

// This placeholder will be replaced with the breakpoint name
$mixin-breakpoint-name-placeholder: "{bp}";


@mixin generate-at-breakpoints($class, $breakpoint-names: ()) {

  $all-breakpoint-names: map-keys($breakpoints);

  @if $breakpoint-names == all {
    $breakpoint-names: $all-breakpoint-names;
  }

  // When specifying one breakpoint with an explicit limit, it needs to be
  // casted into a list of lists, otherwise the mixin assumes there is a
  // breakpoint called 'max'
  @if length($breakpoint-names) == 2 and index((min max),
    nth($breakpoint-names, 2)) {
    $breakpoint-names-copy: $breakpoint-names;
    $breakpoint-names: ();
    $breakpoint-names: append($breakpoint-names, (nth($breakpoint-names-copy, 1)
     nth($breakpoint-names-copy, 2)));
  }

  @each $breakpoint-name in $breakpoint-names {

    $limit: "min";
    $joiner: "from";

    @if type-of($breakpoint-name) == list {
      $limit: nth($breakpoint-name, 2);
      $breakpoint-name: nth($breakpoint-name, 1);
    }
    @else {
      // Palm is a special case where it uses a `max-width` media query
      $limit: if($breakpoint-name == "palm", "max", "min");
    }

    @if $limit == max {
      $joiner: "up-to";
    }

    @include respond-to($breakpoint-name, $limit) {
      $final-selector: "#{$class}-#{$joiner}-#{$breakpoint-name}";

      // Handle complex selectors by replacing a placeholder with the
      // breakpoint suffix
      @if str_index($class, $mixin-breakpoint-name-placeholder) != null {
        $final-selector: str-replace($class, $mixin-breakpoint-name-placeholder,
         "-#{$joiner}-#{$breakpoint-name}");
      }

      // Output a class which applies the style at a given breakpoint
      #{$final-selector} {
        @content;
      }
    }
  }
}