@use 'sass:math';
@use '../compiled/tokens/scss/color';
@use '../compiled/tokens/scss/ease';
@use '../compiled/tokens/scss/size';
@use '../compiled/tokens/scss/transition';
@use './theme';

/// Required themed properties (Default)
@include theme.props {
  --theme-color-background-input-disabled: #{color.$base-gray-light};
  --theme-color-border-input-disabled: #{color.$base-gray};
  --theme-color-border-input-hover: #{color.$brand-primary};
}

/// Required themed properties (Dark)
@include theme.props(dark) {
  --theme-color-background-input-disabled: #{color.$brand-primary-lighter};
  --theme-color-border-input-disabled: #{color.$brand-primary-dark};
  --theme-color-border-input-hover: currentColor;
}

/// Base input styles
///
/// 1. Browsers apply certain default styles unless appearance is set to `none`.
///    Unfortunately Chrome, Safari and Mozilla all still rely on the
///    vendor-prefixed version of this property at the time of this writing.
/// 2. Input heights vary between different types in certain browsers unless a
///    height is explicitly set.
/// 3. Non-normal line heights break placeholder text alignment in Safari.
/// 4. Safari will not style disabled inputs with readable text unless we set
///    this property in addition to `color`. Unfortunately this also resets the
///    appearance of `::placeholder`, which we'll style later on.
@mixin base {
  // stylelint-disable-next-line property-no-vendor-prefix
  -moz-appearance: none;
  // stylelint-disable-next-line property-no-vendor-prefix
  -webkit-appearance: none;
  appearance: none; // 1
  background-color: color.$text-light;
  block-size: size.$height-control-default; // 2
  border: size.$edge-control solid currentColor;
  border-radius: size.$border-radius-medium;
  color: color.$text-dark;
  display: block;
  font: inherit;
  font-style: normal;
  inline-size: 100%;
  line-height: normal; // 3
  outline: none;
  padding: size.$padding-control-vertical size.$spacing-control-text-inset;
  -webkit-text-fill-color: color.$text-dark; // 4
  transition-duration: transition.$quick;
  transition-property: background-color, border-color;
  transition-timing-function: ease.$out;
  vertical-align: middle;
}

/// Single-line input styles (text, email, etc.)
///
/// For certain single-line input types, using `text-indent` instead of
/// `padding-left` gives a more natural and intuitive appearance when text
/// content overflows.
///
/// It is not recommended to use this for search inputs because Safari gets
/// weird about search input padding.
@mixin single-line {
  padding-inline-start: 0;
  text-indent: size.$spacing-control-text-inset;
}

/// Multi-line input styles (textarea)
@mixin multi-line {
  block-size: size.$height-control-multiline;

  // Let the browser determine the height of the textarea based on its content
  // when it is not explicitly set.
  &[rows] {
    block-size: auto;
  }

  // Prevent resizing if elastic JavaScript behavior is applied
  &.is-elastic {
    resize: none;
  }
}

/// Types that disclose additional options should have an icon
///
/// 1. Firefox misaligns inner options when padding is applied, but all modern
///    browsers seem to align selects predictably even when there is no
///    vertical padding. We still keep a small amount of padding because
///    Firefox's inner dotted outline looks gross when it runs into the outer
///    border, and existing hacks around this visibly degrade text rendering.
/// 2. Prevents option text from overlapping icon.
@mixin icon-affordance(
  $icon-url: svg-load('icons/caret-down.svg', fill=color.$text-dark)
) {
  @if $icon-url {
    background-image: $icon-url;
  }

  background-position: right size.$spacing-control-icon-inset center;
  background-repeat: no-repeat;
  background-size: size.$square-control-icon;
  padding-block: math.div(size.$padding-control-vertical, 2); // 1
  padding-inline-end: size.$spacing-control-icon-inset +
    size.$square-control-icon; // 2
}

/// Various input and interaction states
@mixin states {
  &:hover:not(:disabled):not([readonly]) {
    background-color: color.$text-light-emphasis;
    border-color: var(--theme-color-border-input-hover);
  }

  /// We use plain ol' `focus` rather than `focus-visible` because text inputs
  /// are almost always in a state of keyboard interaction, making the difference
  /// (if any) minimal.
  &:focus {
    background-color: #fff;
    box-shadow: 0 0 0 size.$edge-large color.$brand-primary-lighter;
  }

  &[readonly]:not(:disabled) {
    background-color: transparent;
    border-color: transparent;
    color: inherit;
  }

  &:disabled {
    background-color: var(--theme-color-background-input-disabled);
    border-color: var(--theme-color-border-input-disabled);
    cursor: not-allowed;
  }

  /// 1. We set `-webkit-text-fill-color` on the root element so that Safari
  ///    would respect our disabled text color. But that also resets the
  ///    `::placeholder` color, so we have to specify our own so it will be
  ///    distinct from a normal value while maintaining reasonable high color
  ///    contrast.
  /// 2. Firefox uses `opacity` instead of a lightened text color, appearing
  ///    lighter than other browsers unless we reset it here.
  &::placeholder {
    color: color.$text-dark-muted; // 1
    opacity: 1; // 2
    -webkit-text-fill-color: color.$text-dark-muted; // 1
  }
}

/// All default input styles in one convenient mixin!
@mixin default {
  @include base;

  @include states;

  &[type='email'],
  &[type='text'] {
    @include single-line;
  }

  @at-root textarea#{&} {
    @include multi-line;
  }

  @at-root select#{&} {
    @include icon-affordance;
  }
}
