benjamincharity
7/7/2016 - 5:27 PM

Animated input

Animated input


//
// Animated input
//
// Structure:
//   <div>
//     <input>
//     <label>
//       <svg>
//       <span>
//     <div.validation> (optional)
$label_offset: 2.6em;
$label_offset_small: 2.6em;
$label_scale: .81;

@mixin label__animated(
  $size: 'large',
  $color: $color_secondary,
  $error_color: $color_primary
) {

  // .input
  display: inline-block;
  @if $size == 'small' {
    margin-bottom: 1.6em;
  } @else {
    margin-bottom: 2em;
  }
  position: relative;
  vertical-align: top;
  width: 100%;
  z-index: 1;

  &:last-of-type {
    margin-bottom: 0;
  }

  &.is--disabled {
    pointer-events: none;
  }

  &.is--filled {

    label {
      cursor: default;
      pointer-events: none;
    }

    svg {
      stroke-dashoffset: 0;
    }

    .label {
      opacity: 1;

      @if $size == 'small' {
        @include vendor_prefix(
          transform,
          scale3d($label_scale, $label_scale, 1) translate3d(0, $label_offset_small, 0)
        );
      } @else {
        @include vendor_prefix(
          transform,
          scale3d($label_scale, $label_scale, 1) translate3d(0, $label_offset, 0)
        );
      }

    }
  }

  // .input__field
  input {
    background: transparent;
    border: 0;
    border-radius: 0;
    color: $color;
    display: block;
    float: right;
    @if $size == 'small' {
      padding: .4em .8em;
    } @else {
      padding: .8em;
    }
    position: relative;
    width: 100%;
    // for iOS box shadows
    -webkit-appearance: none;

    // Not sure why this is needed...
    &[type=email] {
      width: calc(107.5% - 1.6em);
    }

    &:focus {
      outline: none;

      + label {
        cursor: default;
        pointer-events: none;

        // scss-lint:disable NestingDepth
        svg {
          stroke-dashoffset: 0;
        }

        .label {
          opacity: 1;
          @if $size == 'small' {
            @include vendor_prefix(
              transform,
              scale3d($label_scale, $label_scale, 1) translate3d(0, $label_offset_small, 0)
            );
          } @else {
            @include vendor_prefix(
              transform,
              scale3d($label_scale, $label_scale, 1) translate3d(0, $label_offset, 0)
            );
          }
        }
        // scss-lint:enable NestingDepth
      }
    }
  }

  // .input__label
  label {
    @include vendor_prefix(
      user-select,
      none
    );
    @include vendor_prefix(
      touch-callout,
      none
    );
    color: $color;
    cursor: text;
    display: inline-block;
    height: 100%;
    padding: 0 1em;
    position: absolute;
    text-align: left;
    text-transform: capitalize;
    width: 100%;
    // scss-lint:disable VendorPrefix
    -webkit-font-smoothing  : antialiased;
    -moz-osx-font-smoothing : grayscale;
    // scss-lint:enable VendorPrefix
  }

  // .graphic
  svg {
    @include vendor_prefix(
      transform,
      scale3d(1, -1, 1)
    );
    @include vendor_prefix(
      transition,
      stroke-dashoffset .3s
    );
    pointer-events: none;
    position: absolute;
    left: 0;
    top: 0;
    fill: none;
    stroke: $color;
    stroke-width: 4px;
    stroke-dasharray: 962;
    stroke-dashoffset: 558;
  }

  // .input__label-content
  .label {
    @include vendor_prefix(
      transform-origin,
      0% 50%
    );
    @include custom_transition();
    display: block;
    opacity: .6;
    @if $size == 'small' {
      padding: .1em 0;
    } @else {
      padding: 1em 0;
    }
    position: relative;
    width: 100%;
  }

  .validation {
    color: $error_color;
    font-size: 12px;
    line-height: 1em;
    padding: 0;
    position: absolute;
    right: 0;
    top: calc(100% + 8px);
    text-align: right;

    p {
      margin: 0;
    }
  }
}
<div
  class="account__input--animated"
  data-ng-class="{ 'is--filled': vm.newEmail.length > 0 }"
>

  <input
    id="email"
    name="email"
    type="email"
    autocomplete="off"
    autocorrect="off"
    autocapitalize="off"
    spellcheck="false"
    data-ng-model="vm.newEmail"
    data-ng-change="vm.validateEmail(vm.newEmail)"
  >

  <label for="email">

    <svg width="100%" height="100%" viewBox="0 0 404 77" preserveAspectRatio="none">
      <path d="m0,0l404,0l0,77l-404,0l0,-77z"></path>
    </svg>

    <span class="label">Email address</span>

  </label>

</div>