# ZeenSwitch

Компонент switch input для форм

# Примеры:

  • Switch c boolean, дефолтная тема circleWithMainColor: false

  • Switch со значениями, альтернативная тема bgWithMainColor : { "name": "Вася", "id": "1" }

  • Disabled не отмеченный: false

  • Disabled отмеченный: true

  • С кастомными цветами: работающие в двух темах и disabled

# props

Название Тип Обязательный По умолчанию Описание
value any + - то, значение, которое хотим сохранять в data родителя
modelValue any + - сюда передается значение из v-model
disabled boolean - - если true, то компонент становится disabled
name string - -
theme string - circleWithMainColor доступны 2 темы: circleWithMainColor - фон круга основным цветом, а фон подложки дополнительным. bgWithMainColor - наоборот
trueValue any - true используется для хранения значения другого типа (не boolean) по состоянию true
falseValue any - false используется для хранения значения другого типа (не boolean) по состоянию false
color object - {} объект с кастомными цветами (подробнее см.ниже)

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

Название Тип Обязательный По умолчанию
switchMainColor основной цвет - берет значение из темы ($switch-main-color)
switchAdditionalColor дополнительный цвет - берет значение из темы ($switch-additional-color)
switchDisabledBackgroundColor цвет фона компонента в состоянии disabled - берет значение из темы ($switch-disabled-background-color)
switchDisabledCircleColor цвет круга компонента в состоянии disabled - берет значение из темы ($switch-disabled-circle-color)

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

<template>
  <div
    :id="`zeen-switch-${componentId}`"
    class="zeen-switch"
    :class="{
      'zeen-switch_main': bgMainTheme,
      'zeen-switch_small': isSmall,
    }"
  >
    <input
      class="zeen-switch__input"
      :value="value"
      :name="name"
      type="checkbox"
      v-model="model"
      :disabled="disabled"
      :id="componentId"
      :true-value="trueValue"
      :false-value="falseValue"
    />
    <label class="zeen-switch__label" :for="componentId"></label>
  </div>
</template>

<script>
export default {
  name: 'ZeenSwitch',
  model: {
    prop: 'modelValue',
    event: 'change',
  },
  props: {
    value: {
      required: false,
    },
    modelValue: {
      required: true,
    },
    disabled: {
      type: Boolean,
      required: false,
    },
    name: {
      type: String,
      required: false,
    },
    theme: {
      type: String,
      required: false,
      default: 'circleWithMainColor',
      validator: (theme) => ['circleWithMainColor', 'bgWithMainColor'].includes(theme),
    },
    trueValue: {
      required: false,
      default: true,
    },
    falseValue: {
      required: false,
      default: false,
    },
    isSmall: {
      type: Boolean,
      default: false,
    },
  },
  computed: {
    componentId() {
      return this._uid
    },
    bgMainTheme() {
      return this.theme === 'bgWithMainColor'
    },
    model: {
      get() {
        return this.modelValue
      },
      set(val) {
        this.$emit('change', val)
      },
    },
  },
}
</script>

<style lang="scss">
:root {
  /* Размеры */
  --switch-width-size: 46px;
  --switch-pointer-size: 21px;
  --switch-pointer-border-radius: 50%;
  --switch-border-radius: 38px;
  --switch-padding: 3px;

  /* Цвета */
  --switch-main: var(--main-color);
  --switch-second: var(--input-background-color);
  --switch-disable-pointer: var(--input-disable-color);
  --switch-disable-background: var(--input-background-color);
}
</style>

<style lang="scss" scoped>
.zeen-switch {
  --switch-pointer: var(--switch-main);
  --switch-background: var(--switch-second);
  position: relative;
  display: inline-block;
  overflow: hidden;
  width: var(--switch-width-size);

  &_main {
    --switch-pointer: var(--switch-second);
    --switch-background: var(--switch-main);
  }

  &_small {
    width: var(--switch-width-size-sm);

    .zeen-switch {
      &__label {
        &::after {
          width: var(--switch-pointer-size-sm);
          height: var(--switch-pointer-size-sm);
        }
      }
    }
  }

  &__label {
    display: block;
    width: 100%;
    color: transparent;
    user-select: none;

    border-radius: var(--switch-border-radius);
    transition: background-color 0.25s ease;
    background: var(--switch-background);
    padding: var(--switch-padding);

    &::after {
      content: '';
      cursor: pointer;
      width: var(--switch-pointer-size);
      height: var(--switch-pointer-size);
      border-radius: var(--switch-pointer-border-radius);
      transition: all 0.25s ease;
      background: var(--switch-pointer);
      display: block;
      // ignore -  требуется для корректной анимации
      margin-left: 0.0000001%;
    }
  }

  &__input {
    position: absolute;
    opacity: 0;
    width: 100%;
    cursor: pointer;

    &:disabled + .zeen-switch__label {
      --switch-pointer: var(--switch-disable-pointer);
      --switch-background: var(--switch-disable-background);

      &::after {
        cursor: not-allowed;
      }
    }

    &:checked + .zeen-switch__label::after {
      margin-left: 100%;
      transform: translateX(-100%);
    }
  }
}
</style>