@use 'unit';
@use '../compiled/tokens/scss/breakpoint';

/// This file contains functions for dynamically adjusting a CSS value from a
/// minimum amount to a maximum, starting from a minimum breakpoint width and
/// capping at a maximum width.
///
/// This is similar to Bootstrap's RFS, except that it's mobile-first and uses
/// the `clamp` function so as not to rely on media queries.
///
/// @link https://blog.typekit.com/2016/08/17/flexible-typography-with-css-locks/
/// @link https://betterwebtype.com/articles/2019/05/14/the-state-of-fluid-web-typography/
/// @link https://github.com/twbs/rfs

/// Generate a fluid `calc` function. Note that this won't cap the value on its
/// own: In most cases, you will want `fluid-clamp` instead.
///
/// @link https://zellwk.com/blog/media-query-units/
/// @param {Number} $min - The minimum amount.
/// @param {Number} $max - The maximum amount.
/// @param {Number} $min-width [breakpoint.$s] - The minimum viewport width in ems.
/// @param {Number} $max-width [breakpoint.$xl] - The maximum viewport width in ems.
/// @return CSS calc function.
@function fluid-calc(
  $min,
  $max,
  $min-width: breakpoint.$s,
  $max-width: breakpoint.$xl
) {
  $delta: unit.strip($max - $min);
  $delta-width: unit.strip($max-width - $min-width);

  // We need to convert the `min-width` value to `rem` so the `calc` won't be
  // influenced by the current `font-size`, which would cause the fluid
  // transformation to fall out of step with the viewport.
  $min-width-rem: unit.swap($min-width, rem);

  @return calc(
    #{$min} + #{$delta} * ((100vw - #{$min-width-rem}) / #{$delta-width})
  );
}

/// Generate a fluid `clamp` function. Unlike `fluid-calc`, this will prevent
/// the value from going below `$min` or above `$max`.
///
/// The fluid-clamp is a more predictable clamp over the native CSS clamp. It will
/// return predictable values between the $min and $max values between the
/// $min-width and $max-width breakpoints. In other words, you get a size relative
/// to the viewport width but between the $min and $max values. Very neat!
///
/// @param {Number} $min - The minimum amount.
/// @param {Number} $max - The maximum amount.
/// @param {Number} $min-width [breakpoint.$s] - The minimum viewport width in ems.
/// @param {Number} $max-width [breakpoint.$xl] - The maximum viewport width in ems.
/// @return CSS clamp function.
@function fluid-clamp(
  $min,
  $max,
  $min-width: breakpoint.$s,
  $max-width: breakpoint.$xl
) {
  $val: fluid-calc($min, $max, $min-width, $max-width);

  // Negative ranges are useful for fluid negation, such as negative padding
  // that breaks out of a container's padding. To support this, we need to swap
  // $min and $max when $min is greater.
  @if $min > $max {
    @return clamp(#{$max}, #{$val}, #{$min});
  }

  @return clamp(#{$min}, #{$val}, #{$max});
}
