@import 'default-theme';
@import 'theme-functions';
@import 'variables';
@import 'mixins';

/** The width/height of the checkbox element. */
$md-checkbox-size: $md-toggle-size !default;
/** The width of the line used to draw the checkmark / mixedmark. */
$md-checkbox-mark-stroke-size: 2/15 * $md-checkbox-size !default;
/** The width of the checkbox border shown when the checkbox is unchecked. */
$md-checkbox-border-width: 2px;
/** The color of the checkbox border. */
$md-checkbox-border-color: if($md-is-dark-theme, rgba(white, 0.7), rgba(black, 0.54)) !default;
/** The color of the checkbox's checkmark / mixedmark. */
$md-checkbox-mark-color: md-color($md-background, background);
/** The color that is used as the checkbox background when it is checked. */
$md-checkbox-background-color: md-color($md-accent, 500);
/** The base duration used for the majority of transitions for the checkbox. */
$md-checkbox-transition-duration: 90ms;
/** The amount of spacing between the checkbox and its label. */
$md-checkbox-item-spacing: $md-toggle-padding;

// Manual calculation done on SVG
$_md-checkbox-mark-path-length: 22.910259;
$_md-checkbox-indeterminate-checked-easing-function: cubic-bezier(0.14, 0, 0, 1);

/**
 * Fades in the background of the checkbox when it goes from unchecked -> {checked,indeterminate}.
 */
@keyframes md-checkbox-fade-in-background {
  0% {
    opacity: 0;
  }

  50% {
    opacity: 1;
  }
}

/**
 * Fades out the background of the checkbox when it goes from {checked,indeterminate} -> unchecked.
 */
@keyframes md-checkbox-fade-out-background {
  0%, 50% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

/**
 * "Draws" in the checkmark when the checkbox goes from unchecked -> checked.
 */
@keyframes md-checkbox-unchecked-checked-checkmark-path {
  0%, 50% {
    stroke-dashoffset: $_md-checkbox-mark-path-length;
  }

  50% {
    animation-timing-function: $md-linear-out-slow-in-timing-function;
  }

  100% {
    stroke-dashoffset: 0;
  }
}

/**
 * Horizontally expands the mixedmark when the checkbox goes from unchecked -> indeterminate.
 */
@keyframes md-checkbox-unchecked-indeterminate-mixedmark {
  0%, 68.2% {
    transform: scaleX(0);
  }

  68.2% {
    animation-timing-function: cubic-bezier(0, 0, 0, 1);
  }

  100% {
    transform: scaleX(1);
  }
}

/**
 * "Erases" the checkmark when the checkbox goes from checked -> unchecked.
 */
@keyframes md-checkbox-checked-unchecked-checkmark-path {
  from {
    animation-timing-function: $md-fast-out-linear-in-timing-function;
    stroke-dashoffset: 0;
  }

  to {
    stroke-dashoffset: $_md-checkbox-mark-path-length * -1;
  }
}

/**
 * Rotates and fades out the checkmark when the checkbox goes from checked -> indeterminate. This
 * animation helps provide the illusion of the checkmark "morphing" into the mixedmark.
 */
@keyframes md-checkbox-checked-indeterminate-checkmark {
  from {
    animation-timing-function: $md-linear-out-slow-in-timing-function;
    opacity: 1;
    transform: rotate(0deg);
  }

  to {
    opacity: 0;
    transform: rotate(45deg);
  }
}

/**
 * Rotates and fades the checkmark back into position when the checkbox goes from indeterminate ->
 * checked. This animation helps provide the illusion that the mixedmark is "morphing" into the
 * checkmark.
 */
@keyframes md-checkbox-indeterminate-checked-checkmark {
  from {
    animation-timing-function: $_md-checkbox-indeterminate-checked-easing-function;
    opacity: 0;
    transform: rotate(45deg);
  }

  to {
    opacity: 1;
    transform: rotate(360deg);
  }
}

/**
 * Rotates and fades in the mixedmark when the checkbox goes from checked -> indeterminate. This
 * animation, similar to md-checkbox-checked-indeterminate-checkmark, helps provide an illusion
 * of "morphing" from checkmark -> mixedmark.
 */
@keyframes md-checkbox-checked-indeterminate-mixedmark {
  from {
    animation-timing-function: $md-linear-out-slow-in-timing-function;
    opacity: 0;
    transform: rotate(-45deg);
  }

  to {
    opacity: 1;
    transform: rotate(0deg);
  }
}

/**
 * Rotates and fades out the mixedmark when the checkbox goes from indeterminate -> checked. This
 * animation, similar to md-checkbox-indeterminate-checked-checkmark, helps provide an illusion
 * of "morphing" from mixedmark -> checkmark.
 */
@keyframes md-checkbox-indeterminate-checked-mixedmark {
  from {
    animation-timing-function: $_md-checkbox-indeterminate-checked-easing-function;
    opacity: 1;
    transform: rotate(0deg);
  }

  to {
    opacity: 0;
    transform: rotate(315deg);
  }
}

/**
 * Horizontally collapses and fades out the mixedmark when the checkbox goes from indeterminate ->
 * unchecked.
 */
@keyframes md-checkbox-indeterminate-unchecked-mixedmark {
  0% {
    animation-timing-function: linear;
    opacity: 1;
    transform: scaleX(1);
  }

  32.8%, 100% {
    opacity: 0;
    transform: scaleX(0);
  }
}

/**
 * Applied to elements that cover the checkbox's entire inner container.
 */
%md-checkbox-cover-element {
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
}

/**
 * Applied to elements that are considered "marks" within the checkbox, e.g. the checkmark and
 * the mixedmark.
 */
%md-checkbox-mark {
  $width-padding-inset: 2 * $md-checkbox-border-width;
  width: calc(100% - #{$width-padding-inset});
}

/**
 * Applied to elements that appear to make up the outer box of the checkmark, such as the frame
 * that contains the border and the actual background element that contains the marks.
 */
%md-checkbox-outer-box {
  @extend %md-checkbox-cover-element;
  border-radius: 2px;
  box-sizing: border-box;
  pointer-events: none;
}

md-checkbox {
  cursor: pointer;
}

.md-checkbox-layout {
  // `cursor: inherit` ensures that the wrapper element gets the same cursor as the md-checkbox
  // (e.g. pointer by default, regular when disabled), instead of the browser default.
  cursor: inherit;
  align-items: baseline;
  display: inline-flex;
}

.md-checkbox-inner-container {
  display: inline-block;
  height: $md-checkbox-size;
  line-height: 0;
  margin: auto;
  margin-right: $md-checkbox-item-spacing;
  order: 0;
  position: relative;
  vertical-align: middle;
  white-space: nowrap;
  width: $md-checkbox-size;

  [dir='rtl'] & {
    margin: {
      left: $md-checkbox-item-spacing;
      right: auto;
    }
  }
}

// TODO(kara): Remove this style when fixing vertical baseline
.md-checkbox-layout .md-checkbox-label {
  line-height: 24px;
}

.md-checkbox-frame {
  @extend %md-checkbox-outer-box;

  background-color: transparent;
  border: $md-checkbox-border-width solid $md-checkbox-border-color;
  transition: border-color $md-checkbox-transition-duration $md-linear-out-slow-in-timing-function;
  will-change: border-color;
}

.md-checkbox-background {
  @extend %md-checkbox-outer-box;

  align-items: center;
  display: inline-flex;
  justify-content: center;
  transition: background-color $md-checkbox-transition-duration
                  $md-linear-out-slow-in-timing-function,
              opacity $md-checkbox-transition-duration $md-linear-out-slow-in-timing-function;
  will-change: background-color, opacity;
}

.md-checkbox-checkmark {
  @extend %md-checkbox-cover-element;
  @extend %md-checkbox-mark;

  fill: $md-checkbox-mark-color;
  width: 100%;
}

.md-checkbox-checkmark-path {
  // !important is needed here because a stroke must be set as an attribute on the SVG in order
  // for line animation to work properly.
  stroke: $md-checkbox-mark-color !important;
  stroke: {
    dashoffset: $_md-checkbox-mark-path-length;
    dasharray: $_md-checkbox-mark-path-length;
    width: $md-checkbox-mark-stroke-size;
  }
}

.md-checkbox-mixedmark {
  @extend %md-checkbox-mark;

  background-color: $md-checkbox-mark-color;
  height: floor($md-checkbox-mark-stroke-size);
  opacity: 0;
  transform: scaleX(0) rotate(0deg);
}

.md-checkbox-align-end {
  .md-checkbox-inner-container {
    order: 1;
    margin: {
      left: $md-checkbox-item-spacing;
      right: auto;
    }

    [dir='rtl'] & {
      margin: {
        left: auto;
        right: $md-checkbox-item-spacing;
      }
    }
  }
}

.md-checkbox-checked {
  .md-checkbox-checkmark {
    opacity: 1;
  }

  .md-checkbox-checkmark-path {
    stroke-dashoffset: 0;
  }

  .md-checkbox-mixedmark {
    transform: scaleX(1) rotate(-45deg);
  }

  .md-checkbox-background {
    background-color: $md-checkbox-background-color;
  }
}

.md-checkbox-indeterminate {
  .md-checkbox-background {
    background-color: $md-checkbox-background-color;
  }

  .md-checkbox-checkmark {
    opacity: 0;
    transform: rotate(45deg);
  }

  .md-checkbox-checkmark-path {
    stroke-dashoffset: 0;
  }

  .md-checkbox-mixedmark {
    opacity: 1;
    transform: scaleX(1) rotate(0deg);
  }
}


.md-checkbox-unchecked {
  .md-checkbox-background {
    background-color: transparent;
  }
}

.md-checkbox-disabled {
  // NOTE(traviskaufman): While the spec calls for translucent blacks/whites for disabled colors,
  // this does not work well with elements layered on top of one another. To get around this we
  // blend the colors together based on the base color and the theme background.
  $white-30pct-opacity-on-dark-theme: #686868;
  $black-26pct-opacity-on-light-theme: #b0b0b0;
  $disabled-color: if(
      $md-is-dark-theme, $white-30pct-opacity-on-dark-theme, $black-26pct-opacity-on-light-theme);

  cursor: default;

  &.md-checkbox-checked,
  &.md-checkbox-indeterminate {
    .md-checkbox-background {
      background-color: $disabled-color;
    }
  }

  &:not(.md-checkbox-checked) {
    .md-checkbox-frame {
      border-color: $disabled-color;
    }
  }
}

.md-checkbox-anim {
  $indeterminate-change-duration: 500ms;

  &-unchecked-checked {
    .md-checkbox-background {
      animation: $md-checkbox-transition-duration * 2 linear 0ms md-checkbox-fade-in-background;
    }

    .md-checkbox-checkmark-path {
      // Instead of delaying the animation, we simply multiply its length by 2 and begin the
      // animation at 50% in order to prevent a flash of styles applied to a checked checkmark
      // as the background is fading in before the animation begins.
      animation:
        $md-checkbox-transition-duration * 2 linear 0ms md-checkbox-unchecked-checked-checkmark-path;
    }
  }

  &-unchecked-indeterminate {
    .md-checkbox-background {
      animation: $md-checkbox-transition-duration * 2 linear 0ms md-checkbox-fade-in-background;
    }

    .md-checkbox-mixedmark {
      animation:
        $md-checkbox-transition-duration linear 0ms md-checkbox-unchecked-indeterminate-mixedmark;
    }
  }

  &-checked-unchecked {
    .md-checkbox-background {
      animation: $md-checkbox-transition-duration * 2 linear 0ms md-checkbox-fade-out-background;
    }

    .md-checkbox-checkmark-path {
      animation:
        $md-checkbox-transition-duration linear 0ms md-checkbox-checked-unchecked-checkmark-path;
    }
  }

  &-checked-indeterminate {
    .md-checkbox-checkmark {
      animation:
        $md-checkbox-transition-duration linear 0ms md-checkbox-checked-indeterminate-checkmark;
    }

    .md-checkbox-mixedmark {
      animation:
        $md-checkbox-transition-duration linear 0ms md-checkbox-checked-indeterminate-mixedmark;
    }
  }

  &-indeterminate-checked {
    .md-checkbox-checkmark {
      animation:
        $indeterminate-change-duration linear 0ms md-checkbox-indeterminate-checked-checkmark;
    }

    .md-checkbox-mixedmark {
      animation:
        $indeterminate-change-duration linear 0ms md-checkbox-indeterminate-checked-mixedmark;
    }
  }

  &-indeterminate-unchecked {
    .md-checkbox-background {
      animation: $md-checkbox-transition-duration * 2 linear 0ms md-checkbox-fade-out-background;
    }

    .md-checkbox-mixedmark {
      animation:
        $indeterminate-change-duration * 0.6 linear 0ms
        md-checkbox-indeterminate-unchecked-mixedmark;
    }
  }
}

// Underlying native input element.
// Visually hidden but still able to respond to focus.
.md-checkbox-input {
  @include md-visually-hidden;
}

@include md-temporary-ink-ripple(checkbox);
