# ZeenTextInput

Компонент текстового input для форм

# Примеры:

  • Input:

  • Disabled

  • Input с ошибкой:

  • Input с текстом, что все верно:

  • Input с типом email и кастомными цветами и ошибкой:

  • Input c иконкой:

  • Input c типом пароль и иконкой:

# props

Название Тип Обязательный По умолчанию Описание
value string + то, что указано в data родителя
placeholder string - -
required boolean - false если true, то при инпуту добавится атрибут required
name string - -
type string - 'text'
error string - '' если значение truthy, то отобразится переданный текст и сменится цвет лейбла и бордера
correct string - '' если значение truthy, то отобразится переданный текст и сменится цвет лейбла и бордера
color object - {} объект с кастомными цветами (подробнее см.ниже)

Благодаря v-bind="$attrs" поддерживаются дополнительные атрибуты.

# Кастомные цвета в объекте color

Обработка цветов осуществляется миксином InputColorMixin

Название Тип Обязательный По умолчанию
textColor цвет текста инпута - берет значение из темы ($input-text-color)
backgroundColor цвет фона инпута - берет значение из темы ($input-background-color)
borderFocusColor цвет бордера инпута при фокусе - берет значение из темы ($input-main-color)
errorColor цвет лейбла и бордера при truthy error - берет значение из темы ($input-error-color)
correctColor цвет лейбла и бордера при truthy correct - берет значение из темы ($input-correct-color)

# Иконки

Компонент имеет именованный слот btn. В него можно подставлять иконки, кнопки и другие элементы. Позиционируется с правой стороны инпута по центру. Если слот пустой, то этот элемент не рендерится, иначе - инпуту добавляется дополнительный класс для увеличения padding-right.

# Source Code - исходный код компонента

<template>
  <div
    :id="`zeen-text-input-${componentId}`"
    :key="componentId"
    class="zeen-text-input"
    :class="{
      'zeen-text-input_error': error,
      'zeen-text-input_correct': correct,
    }"
  >
    <label v-if="error || correct" class="zeen-text-input__label" :for="componentId">{{ error || correct }}</label>
    <div class="zeen-text-input__wrapper">
      <input
        class="zeen-text-input__input"
        :class="{
          'zeen-text-input__input_with-btn': hasBtnSlot,
          'zeen-text-input__input_with-two-btn': hasTwoBtnSlot,
          'zeen-text-input__input_password': type === 'password',
          'zeen-text-input__input_no-radius': noRadius,
        }"
        :value="value"
        :placeholder="placeholder"
        :required="required"
        :disabled="disabled"
        :name="name"
        :type="type"
        @input="onInput"
        @keyup.enter="$emit('handleKeypress')"
        v-bind="$attrs"
        :id="componentId"
        :key="`input-${componentId}`"
      />
      <div class="zeen-text-input__btn" v-if="hasBtnSlot">
        <slot name="btn"></slot>
        <slot name="img"></slot>
      </div>
    </div>
  </div>
</template>

<script>
import componentIdSsr from '../../../mixins/componentIdSsr'

export default {
  name: 'ZeenTextInput',
  mixins: [componentIdSsr],
  props: {
    value: {
      type: [String, Number],
      required: false,
      default: null,
    },
    placeholder: {
      type: String,
      required: false,
    },
    required: {
      type: Boolean,
      required: false,
    },
    disabled: {
      type: Boolean,
      required: false,
    },
    name: {
      type: String,
      required: false,
    },
    type: {
      type: String,
      default: 'text',
    },
    error: {
      type: String,
      default: '',
    },
    correct: {
      type: String,
      default: '',
    },
    color: {
      type: Object,
      default: () => {
        return {}
      },
    },
    noRadius: {
      type: Boolean,
      default: false,
    },
  },
  methods: {
    onInput(e) {
      this.$emit('input', e.target.value)
    },
  },
  computed: {
    hasBtnSlot() {
      return !!this.$slots.btn
    },
    hasTwoBtnSlot() {
      return this.$slots.btn && this.$slots?.btn?.length > 1
    },
  },
}
</script>
<style lang="scss">
:root {
  /* Размеры кнопки */
  --text-input-label-size: var(--main-input-label-size);
  --text-input-label-line-height: 1.4;

  /* Цвета кнопки */
  --text-input-label-base-color: var(--input-main-placeholder-color);
  --text-input-label-error-color: var(--input-error-color);
  --text-input-label-correct-color: var(--input-correct-color);
  --text-input-border-base-focus-color: var(--input-main-color);
  --text-input-color: var(--input-main-value-color);
  --text-input-background: var(--input-background-color);

  --text-input-border-color: transparent;
  --text-input-border-error-color: var(--text-input-label-error-color);
  --text-input-border-correct-color: var(--text-input-label-correct-color);

  --text-input-placeholder-color: var(--input-main-placeholder-color);
  --text-input-placeholder-disable-color: var(--input-placeholder-disable-color);
}
</style>
<style lang="scss" scoped>
.zeen-text-input {
  --text-input-label-color: var(--text-input-label-base-color);
  --text-input-border-focus-color: var(--text-input-border-base-focus-color);

  &_error {
    --text-input-label-color: var(--text-input-label-error-color);
    --text-input-border-focus-color: var(--text-input-border-error-color);
    --text-input-border-color: var(--text-input-border-focus-color);
  }

  &_correct {
    --text-input-label-color: var(--text-input-label-correct-color);
    --text-input-border-focus-color: var(--text-input-border-correct-color);
    --text-input-border-color: var(--text-input-border-focus-color);
  }

  &__label {
    display: block;
    font-size: var(--text-input-label-size);
    line-height: var(--text-input-label-line-height);
    color: var(--text-input-label-color);
    margin: 0 0 var(--main-input-label-offset-bottom) var(--main-input-label-offset-left);
  }

  &__wrapper {
    position: relative;
  }

  &__input {
    width: 100%;
    box-sizing: border-box;
    border-radius: var(--text-input-border-radius);
    border: var(--text-input-border-width) solid var(--text-input-border-color);
    padding: var(--text-input-vertical-padding) var(--text-input-horizontal-padding);
    font-size: var(--text-input-text-size);
    line-height: 1.5;
    -webkit-appearance: none;
    outline: none;
    color: var(--text-input-color);
    background: var(--text-input-background);

    &::placeholder {
      font-size: inherit;
      line-height: inherit;
    }

    &:focus {
      border-color: var(--text-input-border-focus-color);
    }

    &:disabled {
      --text-input-border-color: transparent;

      &::placeholder {
        --text-input-placeholder-color: var(--text-input-placeholder-disable-color);
      }
    }

    &::placeholder {
      color: var(--text-input-placeholder-color);
    }

    &_with-btn {
      padding-right: 50px;
    }

    &_with-two-btn {
      padding-right: 100px;
    }

    &_no-radius {
      border-radius: 0;
    }
  }

  &__btn {
    position: absolute;
    right: 25px;
    top: 50%;
    transform: translate(0, -50%);
    display: flex;
    align-items: center;
  }
}
</style>