npm package: @parkonika-dev/design-system
Description: **Библиотека UI компонентов для Vue 3** с продуманной системой тем и цветовых схем. Коллекция современных, доступных и легко настраиваемых интерфейсных элементов.
Latest version: 1.1.3
Deprecated: ⚠️ DEPRECATED: This package is no longer maintained. Please use an alternative solution.

# @parkonika-dev/design-system

**Библиотека UI компонентов для Vue 3** с продуманной системой тем и цветовых схем. Коллекция современных, доступных и легко настраиваемых интерфейсных элементов.

## ✨ Особенности

-   **Гибкая темизация** - Настраивайте цвета через CSS переменные
-   **Адаптивность** - Идеально выглядят на всех устройствах
-   **Vue 3** - Современная композиция и реактивность

## 📖 Содержание <a id="content"></a>

-   [🚀 Установка](#installation)
-   [📦 Быстрый старт](#quick-start)
-   [🎨 Цветовая схема](#color-scheme)
-   [🎯 Компоненты](#components)
    -   [UiModalLib - Модальные окна](#uimodallib)
    -   [UiButton - Кнопки](#uibutton)
    -   [UiSwitch - Переключатели](#uiswitch)
    -   [UiLoader - Индикатор загрузки](#uiloader)
    -   [UiLink - Ссылки](#uilink)
    -   [UiNotification - Уведомления](#uinotification)
    -   [UiRadioButton - Радио кнопка](#uiradiobutton)
    -   [UiSelect - Выпадающий список](#uiselect)
    -   [UiCheckbox - Чекбокс](#uicheckbox)
    -   [UiTextarea - Текстовое поле](#uitextarea)
    -   [UiRange - Ползунок](#uirange)
    -   [UiInput - Поле ввода с валидацией](#uiinput)

---

## 🚀 Установка <a id="installation"></a>

#### Установить без указания версии

```bash
npm install @parkonika-dev/design-system
```

#### Установить последнюю версию

```bash
npm install @parkonika-dev/design-system@latest
```

#### Установить конкретную версию (если знаете точную)

```bash
npm install @parkonika-dev/design-system@1.0.52
```

#### Проверить доступные версии

```bash
npm view @parkonika-dev/design-system versions --json
```

#### Проверить актуальную версию

```bash
npm info @parkonika-dev/design-system
```

---

## 📦 Быстрый старт <a id="quick-start"></a>

```js
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import ParkonikaUI from '@parkonika-dev/design-system';
import '@parkonika-dev/design-system/style.css';

const app = createApp(App);
app.use(ParkonikaUI);
app.mount('#app');
```

---

## 🎨 Цветовая схема <a id="color-scheme"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Библиотека использует систему CSS-переменных для управления цветами. Все цвета определены в корневом scope (:root) и доступны для кастомизации.

#### Основные цвета

| CSS переменная       | Значение  | Категория         |
| -------------------- | --------- | ----------------- |
| `--black-color`      | `#000`    | Базовые цвета     |
| `--white-color`      | `#fff`    | Базовые цвета     |
| `--primary-color-01` | `#01434C` | Основная палитра  |
| `--primary-color-02` | `#4B777D` | Основная палитра  |
| `--primary-color-03` | `#C3E2E7` | Основная палитра  |
| `--green-color-01`   | `#00856B` | Зеленая палитра   |
| `--green-color-02`   | `#1C7D41` | Зеленая палитра   |
| `--green-color-03`   | `#26ca6a` | Зеленая палитра   |
| `--green-color-04`   | `#78d672` | Зеленая палитра   |
| `--green-color-05`   | `#bbf7d0` | Зеленая палитра   |
| `--laym-color-01`    | `#b8f51e` | Лаймовая палитра  |
| `--laym-color-02`    | `#98D400` | Лаймовая палитра  |
| `--laym-color-03`    | `#87b416` | Лаймовая палитра  |
| `--laym-color-04`    | `#d2f281` | Лаймовая палитра  |
| `--orange-color-01`  | `#fdad1d` | Оранжевая палитра |
| `--orange-color-02`  | `#e29303` | Оранжевая палитра |
| `--teal-color-01`    | `#80CBC4` | Бирюзовая палитра |
| `--teal-color-02`    | `#00897B` | Бирюзовая палитра |
| `--yellow-color-01`  | `#ffcc00` | Желтая палитра    |
| `--red-color-00`     | `#DE403C` | Красная палитра   |
| `--red-color-01`     | `#f00`    | Красная палитра   |
| `--red-color-02`     | `#900B09` | Красная палитра   |
| `--red-color-03`     | `#ff4d4f` | Красная палитра   |
| `--red-color-04`     | `#ff7875` | Красная палитра   |
| `--red-color-05`     | `#c646a8` | Красная палитра   |
| `--dark-color-06`    | `#0f0f0f` | Темная палитра    |
| `--dark-color-08`    | `#141414` | Темная палитра    |
| `--dark-color-10`    | `#1a1a1a` | Темная палитра    |
| `--dark-color-11`    | `#212327` | Темная палитра    |
| `--dark-color-12`    | `#1f1f1f` | Темная палитра    |
| `--dark-color-13`    | `#292a2d` | Темная палитра    |
| `--dark-color-15`    | `#262626` | Темная палитра    |
| `--dark-color-20`    | `#333333` | Темная палитра    |
| `--dark-color-25`    | `#404040` | Темная палитра    |
| `--dark-color-26`    | `#404045` | Темная палитра    |
| `--dark-color-30`    | `#4c4c4c` | Темная палитра    |
| `--grey-color-40`    | `#587777` | Серая палитра     |
| `--grey-color-50`    | `#707786` | Серая палитра     |
| `--grey-color-55`    | `#565656` | Серая палитра     |
| `--grey-color-60`    | `#7e7e7e` | Серая палитра     |
| `--grey-color-65`    | `#a0a0a0` | Серая палитра     |
| `--grey-color-70`    | `#c1c1c1` | Серая палитра     |
| `--grey-color-75`    | `#CCCBCB` | Серая палитра     |
| `--grey-color-90`    | `#DfDEDE` | Серая палитра     |
| `--grey-color-95`    | `#f6f6f6` | Серая палитра     |

---

## 🎯 Компоненты <a id="components"></a>

### UiModalLib - Модальные окна <a id="uimodallib"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Умные модальные окна с поддержкой глобального управления состоянием, вложенного контента и гибкой кастомизации.

#### Базовое подключение

```javascript
import { UiModalLib, useModalStore } from '@parkonika-dev/design-system';
```

#### Локальное управление (v-model)

Используйте v-model для быстрого управления состоянием модалки внутри компонента:

```vue
<template>
    <button @click="isModalOpen = true">Открыть модалку</button>

    <UiModalLib
        v-model="isModalOpen"
        modal-id="myModal"
    >
        <h2>Содержимое модалки</h2>
        <p>Простое управление через v-model</p>
    </UiModalLib>
</template>

<script setup>
    import { ref } from 'vue';
    import { UiModalLib } from '@parkonika-dev/design-system';

    const isModalOpen = ref(false);
</script>
```

#### Глобальное управление (рекомендуется для приложений)

Используйте хранилище для централизованного управления всеми модальными окнами:

vue

```vue
<template>
    <button @click="openModal">Открыть модалку</button>

    <UiModalLib modal-id="myModal">
        <h2>Содержимое модалки</h2>
        <p>Управление через глобальное хранилище</p>
    </UiModalLib>
</template>

<script setup>
    import { UiModalLib, useModalStore } from '@parkonika-dev/design-system';

    const modalStore = useModalStore();

    const openModal = () => {
        modalStore.setModalVisible('myModal', true);
    };

    const closeModal = () => {
        modalStore.setModalVisible('myModal', false);
    };
</script>
```

#### Пропсы

| Пропс               | Тип           | Обязательный | По умолчанию | Описание                         |
| ------------------- | ------------- | :----------: | ------------ | -------------------------------- |
| `modal-id`          | String        |      ✅      | -            | Уникальный идентификатор модалки |
| `v-model`           | Boolean       |      ❌      | `false`      | Состояние открытия/закрытия      |
| `close-icon`        | Object/String |      ❌      | `null`       | Компонент иконки закрытия        |
| `close-on-backdrop` | Boolean       |      ❌      | `true`       | Закрывать при клике на фон       |

#### Методы хранилища

| Метод                                 | Параметры                               | Описание                                     |
| ------------------------------------- | --------------------------------------- | -------------------------------------------- |
| `setModalVisible(modalId, isVisible)` | `modalId: string`, `isVisible: boolean` | Установить видимость модального окна         |
| `openModalWithProps(modalId, props)`  | `modalId: string`, `props: object`      | Открыть модальное окно с передачей данных    |
| `closeModal(modalId)`                 | `modalId: string`                       | Закрыть модальное окно и очистить его пропсы |
| `isModalOpen(modalId)`                | `modalId: string`                       | Проверить, открыто ли модальное окно         |
| `getModalProps(modalId)`              | `modalId: string`                       | Получить пропсы модального окна              |

#### События компонента

```vue
<UiModalLib modal-id="myModal" @open="onModalOpen" @close="onModalClose" @update:modelValue="onModelValueChange">
    Содержимое модалки
</UiModalLib>
```

#### Важные правила использования

| Статус         | Код                                                                                           | Описание                             |
| -------------- | --------------------------------------------------------------------------------------------- | ------------------------------------ |
| ✅ ПРАВИЛЬНО   | `modalStore.closeModal('myModal');`                                                           | Автоматически очищает пропсы         |
| ✅ ПРАВИЛЬНО   | `modalStore.setModalVisible('myModal', false);`                                               | Корректное закрытие модального окна  |
| ❌ НЕПРАВИЛЬНО | `modalStore.setModalVisible('myModal', false);`<br>`modalStore.modalProps['myModal'] = null;` | Не очищает пропсы и ломает хранилище |
| ❌ НЕПРАВИЛЬНО | `modalStore.modalProps = null;`                                                               | Уничтожает все модальные окна        |

---

### UiButton - Кнопки <a id="uibutton"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Универсальные кнопки с поддержкой различных стилей, состояний загрузки и размеров. Идеально подходят для любых действий в интерфейсе.

#### Основные типы кнопок

```vue
<template>
    <UiButton
        type="primary"
        @click="handleClick"
    >
        Основная кнопка
    </UiButton>

    <UiButton type="secondary"> Вторичная кнопка </UiButton>

    <UiButton type="tertiary"> Третичная кнопка </UiButton>

    <UiButton type="danger"> Опасное действие </UiButton>

    <UiButton :is-loading="true"> Загрузка... </UiButton>
</template>

<script setup>
    import { UiButton } from '@parkonika-dev/design-system';

    const handleClick = () => {
        console.log('Кнопка нажата');
    };
</script>
```

#### Пропсы UiButton

| Параметр     | Тип       | По умолчанию | Описание                                                                            |
| ------------ | --------- | ------------ | ----------------------------------------------------------------------------------- |
| `type`       | `String`  | `'primary'`  | Тип кнопки: `'primary'`, `'secondary'`, `'tertiary'`, `'danger'`, `'lite'`, `'pay'` |
| `buttonText` | `String`  | `'Далее'`    | Текст кнопки                                                                        |
| `size`       | `String`  | `'md'`       | Размер кнопки: `'sm'`, `'md'`, `'lg'`                                               |
| `disabled`   | `Boolean` | `false`      | Отключенное состояние                                                               |
| `isLoading`  | `Boolean` | `false`      | Состояние загрузки                                                                  |
| `isActive`   | `Boolean` | `false`      | Активное состояние                                                                  |
| `autoWidth`  | `Boolean` | `false`      | Автоматическая ширина                                                               |

---

### UiSwitch - Переключатели <a id="uiswitch"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Стильные переключатели для булевых значений с плавными анимациями и поддержкой различных тем.

```vue
<template>
    <UiSwitch v-model="isEnabled" />

    <UiSwitch
        v-model="darkMode"
        type="theme"
        @switch-toggle="handleThemeToggle"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiSwitch } from '@parkonika-dev/design-system';

    const isEnabled = ref(false);
    const darkMode = ref(false);

    const handleThemeToggle = event => {
        console.log('Переключатель изменен:', event);
    };
</script>
```

### UiLoader - Индикатор загрузки <a id="uiloader"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Элегантные индикаторы загрузки для отображения процессов выполнения операций. Поддерживает различные размеры и цвета.

```vue
<template>
    <UiLoader size="48px" />

    <UiLoader size="24px" />
</template>

<script setup>
    import { UiLoader } from '@parkonika-dev/design-system';
</script>
```

---

### UiLink - Ссылки <a id="uilink"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Доступные ссылки с поддержкой маршрутизации Vue Router и внешних URL. Имеют четкие состояния hover и focus.

```vue
<template>
    <UiLink
        to="/settings"
        type="primary"
    >
        Настройки
    </UiLink>

    <UiLink
        to="https://example.com"
        external
        type="secondary"
    >
        Внешняя ссылка
    </UiLink>
</template>

<script setup>
    import { UiLink } from '@parkonika-dev/design-system';
</script>
```

---

### UiNotification - Уведомления <a id="uinotification"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Красивые системные уведомления для информирования пользователей о событиях в приложении. Поддерживает 7 типов статусов с уникальными иконками и цветами.

#### Все доступные типы уведомлений

```js
// Поддерживаемые типы:
const notificationTypes = {
    success: 'Успех', // Зеленый
    error: 'Ошибка', // Красный
    warn: 'Предупреждение', // Желтый
    info: 'Информация', // Синий
    add: 'Добавление', // Зеленый
    delete: 'Удаление', // Красный
    reload: 'Перезагрузка', // Синий
};
```

#### Пропсы компонента

| Параметр     | Тип        | По умолчанию | Описание                                                                         |
| ------------ | ---------- | ------------ | -------------------------------------------------------------------------------- |
| `item`       | `Object`   | -            | Объект уведомления                                                               |
| `item.title` | `String`   | -            | Текст уведомления                                                                |
| `item.type`  | `String`   | `'info'`     | Тип: `'success'`, `'error'`, `'warn'`, `'info'`, `'add'`, `'delete'`, `'reload'` |
| `close`      | `Function` | -            | Функция закрытия уведомления                                                     |

#### Можно переопределить стили

```css
/* Глобальные стили для уведомлений */
.vue-notification-group {
    width: auto !important;
    margin: 0 0 16px;
    left: 20px !important;
    box-sizing: border-box;
}

@media screen and (max-width: 479px) {
    .vue-notification-group {
        width: 100% !important;
        left: 0 !important;
        margin: 0 0 65px;
        padding: 0 16px;
    }
}

@media screen and (max-width: 319px) {
    .vue-notification-group {
        padding: 0 7px;
    }
}
```

#### Использование в компонентах

##### Вариант A: Глобальное подключение в App.vue

```vue
<!-- App.vue -->
<template>
    <div id="app">
        <router-view />

        <!-- Глобальный контейнер для уведомлений -->
        <notifications position="bottom">
            <template #body="props">
                <UiNotification v-bind="props" />
            </template>
        </notifications>
    </div>
</template>

<script setup>
    import { UiNotification } from '@parkonika-dev/design-system';
</script>
```

##### Вариант B: Локальное использование в компоненте

```vue
<template>
    <div>
        <button @click="showNotification">Показать уведомление</button>

        <!-- Локальные уведомления -->
        <notifications
            position="bottom"
            :duration="5000"
        >
            <template #body="props">
                <UiNotification v-bind="props" />
            </template>
        </notifications>
    </div>
</template>

<script setup>
    import { UiNotification } from '@parkonika-dev/design-system';

    const showNotification = () => {
        // Уведомление будет показано через глобальный $notify
    };
</script>
```

---

### UiRadioButton - Радио кнопка <a id="uiradiobutton"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Кастомные радио-кнопки с поддержкой группировки и доступной разметкой. Идеальны для выбора одного варианта из нескольких.

#### Пропсы компонента

| Параметр     | Тип                                           | По умолчанию | Обязательный | Описание                             |
| ------------ | --------------------------------------------- | ------------ | ------------ | ------------------------------------ |
| `id`         | `String`                                      | -            | ✅           | Уникальный идентификатор радиокнопки |
| `value`      | `String` \| `Number` \| `Boolean`             | -            | ✅           | Значение радиокнопки                 |
| `modelValue` | `String` \| `Number` \| `Boolean` \| `Object` | `''`         | ❌           | Текущее выбранное значение (v-model) |
| `label`      | `String`                                      | `''`         | ❌           | Текст метки радиокнопки              |

#### Базовое использование

```vue
<template>
    <UiRadioButton
        id="option-1"
        v-model="selectedOption"
        value="option1"
        label="Первая опция"
    />

    <UiRadioButton
        id="option-2"
        v-model="selectedOption"
        value="option2"
        label="Вторая опция"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiRadioButton } from '@parkonika-dev/design-system';

    const selectedOption = ref('option1');
</script>
```

---

### UiSelect - Выпадающий список <a id="uiselect"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Функциональные выпадающие списки с поиском, валидацией и поддержкой сложных структур данных. Полностью кастомный дизайн.

#### Пропсы компонента

| Параметр         | Тип                                     | По умолчанию | Обязательный | Описание                                                 |
| ---------------- | --------------------------------------- | ------------ | :----------: | -------------------------------------------------------- |
| `modelValue`     | `String \| Number \| Boolean \| Object` | `''`         |      ❌      | Текущее выбранное значение (v-model)                     |
| `options`        | `Array`                                 | `[]`         |      ❌      | Массив опций (строк или объектов)                        |
| `label`          | `String`                                | `''`         |      ❌      | Текст метки селекта                                      |
| `placeholder`    | `String`                                | `''`         |      ❌      | Текст плейсхолдера                                       |
| `disabled`       | `Boolean`                               | `false`      |      ❌      | Отключенное состояние                                    |
| `required`       | `Boolean`                               | `false`      |      ❌      | Обязательное поле                                        |
| `error`          | `String`                                | `''`         |      ❌      | Текст ошибки                                             |
| `hint`           | `String`                                | `''`         |      ❌      | Текст подсказки                                          |
| `optionValue`    | `String`                                | `'value'`    |      ❌      | Ключ для значения опции (для объектов)                   |
| `optionLabel`    | `String`                                | `'label'`    |      ❌      | Ключ для отображаемого текста опции (для объектов)       |
| `optionDisabled` | `String`                                | `'disabled'` |      ❌      | Ключ для отключенного состояния опции (для объектов)     |
| `optionKey`      | `String`                                | `'id'`       |      ❌      | Ключ для уникального идентификатора опции (для объектов) |
| `id`             | `String`                                | `'random'`   |      ❌      | Уникальный идентификатор селекта                         |

#### События компонента

| Событие             | Тип данных                              | Описание                          |
| ------------------- | --------------------------------------- | --------------------------------- |
| `update:modelValue` | `String \| Number \| Boolean \| Object` | Обновление значения через v-model |
| `change`            | `String \| Number \| Boolean \| Object` | Изменение выбранного значения     |

### Базовое использование

```vue
<template>
    <UiSelect
        v-model="selectedValue"
        :options="options"
        label="Выберите опцию"
        placeholder="Выберите из списка"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiSelect } from '@parkonika-dev/design-system';

    const selectedValue = ref('');

    const options = [
        { id: 1, value: 'option1', label: 'Первая опция' },
        { id: 2, value: 'option2', label: 'Вторая опция' },
        { id: 3, value: 'option3', label: 'Третья опция', disabled: true },
    ];
</script>
```

#### Использование с простыми массивами

```vue
<template>
    <UiSelect
        v-model="selectedFruit"
        :options="fruits"
        label="Выберите фрукт"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiSelect } from '@parkonika-dev/design-system';

    const selectedFruit = ref('');

    const fruits = ['Яблоко', 'Банан', 'Апельсин', 'Груша'];
</script>
```

#### Использование с валидацией и подсказками

```vue
<template>
    <UiSelect
        v-model="selectedCountry"
        :options="countries"
        label="Страна"
        placeholder="Выберите страну"
        :required="true"
        :error="error"
        hint="Выберите страну из списка"
    />
</template>

<script setup>
    import { ref, computed } from 'vue';
    import { UiSelect } from '@parkonika-dev/design-system';

    const selectedCountry = ref('');

    const countries = [
        { id: 1, value: 'ru', label: 'Россия' },
        { id: 2, value: 'us', label: 'США' },
        { id: 3, value: 'de', label: 'Германия' },
        { id: 4, value: 'fr', label: 'Франция' },
    ];

    const error = computed(() => {
        return selectedCountry.value ? '' : 'Поле обязательно для заполнения';
    });
</script>
```

#### Кастомизация ключей опций

```vue
<template>
    <UiSelect
        v-model="selectedUser"
        :options="users"
        label="Пользователь"
        option-value="userId"
        option-label="userName"
        option-key="userId"
        option-disabled="isDisabled"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiSelect } from '@parkonika-dev/design-system';

    const selectedUser = ref('');

    const users = [
        { userId: 1, userName: 'Иван Иванов', isDisabled: false },
        { userId: 2, userName: 'Петр Петров', isDisabled: false },
        { userId: 3, userName: 'Сергей Сергеев', isDisabled: true },
    ];
</script>
```

#### Отключенное состояние

```vue
<template>
    <UiSelect
        v-model="selectedOption"
        :options="options"
        label="Отключенный селект"
        :disabled="true"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiSelect } from '@parkonika-dev/design-system';

    const selectedOption = ref('');
    const options = ['Опция 1', 'Опция 2', 'Опция 3'];
</script>
```

---

### UiCheckbox - Чекбокс <a id="uicheckbox"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Доступные чекбоксы с кастомным дизайном, состояниями неопределенности и поддержкой touch-устройств.

#### Пропсы компонента

| Параметр     | Тип       | Обязательный | По умолчанию | Описание                          |
| ------------ | --------- | :----------: | ------------ | --------------------------------- |
| `id`         | `String`  |      ✅      | -            | Уникальный идентификатор чекбокса |
| `label`      | `String`  |      ❌      | `''`         | Текст метки чекбокса              |
| `modelValue` | `Boolean` |      ❌      | `false`      | Текущее состояние (v-model)       |
| `disabled`   | `Boolean` |      ❌      | `false`      | Отключенное состояние             |

#### События компонента

| Событие             | Тип данных | Описание                           |
| ------------------- | ---------- | ---------------------------------- |
| `update:modelValue` | `Boolean`  | Обновление состояния через v-model |

#### Базовое использование

```vue
<template>
    <UiCheckbox
        id="agree-terms"
        v-model="isAgreed"
        label="Я согласен с условиями"
    />

    <UiCheckbox
        id="newsletter"
        v-model="receiveNews"
        label="Получать рассылку"
        :disabled="true"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiCheckbox } from '@parkonika-dev/design-system';

    const isAgreed = ref(false);
    const receiveNews = ref(true);
</script>
```

---

### UiTextarea - Текстовое поле <a id="uitextarea"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Многострочные текстовые поля с авто-размером, валидацией и подсветкой синтаксиса. Идеально для длинных текстов.

#### Пропсы компонента

| Параметр      | Тип       | Обязательный | По умолчанию | Описание                    |
| ------------- | --------- | :----------: | ------------ | --------------------------- |
| `modelValue`  | `String`  |      ❌      | `''`         | Текущее значение (v-model)  |
| `label`       | `String`  |      ❌      | `''`         | Текст метки текстового поля |
| `placeholder` | `String`  |      ❌      | `''`         | Текст плейсхолдера          |
| `disabled`    | `Boolean` |      ❌      | `false`      | Отключенное состояние       |
| `readonly`    | `Boolean` |      ❌      | `false`      | Только для чтения           |
| `error`       | `String`  |      ❌      | `''`         | Текст ошибки                |
| `hint`        | `String`  |      ❌      | `''`         | Текст подсказки             |
| `rows`        | `Number`  |      ❌      | `3`          | Количество строк            |
| `id`          | `String`  |      ❌      | `''`         | Уникальный идентификатор    |

#### События компонента

| Событие             | Тип данных | Описание                          |
| ------------------- | ---------- | --------------------------------- |
| `update:modelValue` | `String`   | Обновление значения через v-model |
| `input`             | `String`   | Ввод данных                       |
| `focus`             | `Event`    | Фокус на поле                     |
| `blur`              | `Event`    | Потеря фокуса                     |

#### Базовое использование

```vue
<template>
    <UiTextarea
        v-model="description"
        label="Описание"
        placeholder="Введите описание..."
        :rows="4"
    />

    <UiTextarea
        v-model="comment"
        label="Комментарий"
        :error="commentError"
        hint="Максимум 500 символов"
    />
</template>

<script setup>
    import { ref, computed } from 'vue';
    import { UiTextarea } from '@parkonika-dev/design-system';

    const description = ref('');
    const comment = ref('');

    const commentError = computed(() => {
        return comment.value.length > 500 ? 'Слишком длинный комментарий' : '';
    });
</script>
```

#### Использование с различными состояниями

```vue
<template>
    <UiTextarea
        v-model="text1"
        label="Обычное поле"
        placeholder="Введите текст..."
    />

    <UiTextarea
        v-model="text2"
        label="Отключенное поле"
        :disabled="true"
        value="Нельзя редактировать"
    />

    <UiTextarea
        v-model="text3"
        label="Только для чтения"
        :readonly="true"
        value="Только для просмотра"
    />

    <UiTextarea
        v-model="text4"
        label="Поле с ошибкой"
        :error="'Обязательное поле'"
    />

    <UiTextarea
        v-model="text5"
        label="Поле с подсказкой"
        hint="Это подсказка для пользователя"
        :rows="5"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiTextarea } from '@parkonika-dev/design-system';

    const text1 = ref('');
    const text2 = ref('Нельзя редактировать');
    const text3 = ref('Только для просмотра');
    const text4 = ref('');
    const text5 = ref('');
</script>
```

---

### UiRange - Ползунок <a id="uirange"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Интуитивные ползунки для выбора числовых значений в диапазоне. Поддерживает кастомные форматы значений и подсказки.

#### Пропсы компонента

| Параметр     | Тип                | Обязательный | По умолчанию | Описание                        |
| ------------ | ------------------ | :----------: | ------------ | ------------------------------- |
| `modelValue` | `Number \| String` |      ❌      | `0`          | Текущее значение (v-model)      |
| `label`      | `String`           |      ❌      | `''`         | Текст метки ползунка            |
| `min`        | `Number`           |      ❌      | `0`          | Минимальное значение            |
| `max`        | `Number`           |      ❌      | `100`        | Максимальное значение           |
| `step`       | `Number`           |      ❌      | `1`          | Шаг изменения                   |
| `unit`       | `String`           |      ❌      | `'%'`        | Единица измерения               |
| `disabled`   | `Boolean`          |      ❌      | `false`      | Отключенное состояние           |
| `required`   | `Boolean`          |      ❌      | `false`      | Обязательное поле               |
| `showValue`  | `Boolean`          |      ❌      | `true`       | Показывать текущее значение     |
| `hints`      | `Boolean`          |      ❌      | `false`      | Показывать подсказки min/max    |
| `format`     | `Function`         |      ❌      | `null`       | Функция форматирования значения |

#### События компонента

| Событие             | Тип данных | Описание                              |
| ------------------- | ---------- | ------------------------------------- |
| `update:modelValue` | `Number`   | Обновление значения через v-model     |
| `input`             | `Number`   | Ввод данных (при движении ползунка)   |
| `change`            | `Number`   | Изменение значения (после отпускания) |

#### Базовое использование

```vue
<template>
    <UiRange
        v-model="opacity"
        label="Прозрачность:"
        :min="0"
        :max="100"
        unit="%"
    />

    <UiRange
        v-model="volume"
        label="Громкость:"
        :min="0"
        :max="10"
        :step="0.1"
        unit=""
        :hints="true"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiRange } from '@parkonika-dev/design-system';

    const opacity = ref(50);
    const volume = ref(7.5);
</script>
```

#### Использование с форматированием

```vue
<template>
    <div class="position-editor">
        <UiRange
            v-model="x"
            label="Позиция X (горизонталь):"
            :min="0"
            :max="100"
            unit="%"
            @input="updatePreview"
        />

        <UiRange
            v-model="y"
            label="Позиция Y (вертикаль):"
            :min="0"
            :max="100"
            unit="%"
            @input="updatePreview"
        />

        <div
            class="preview"
            :style="previewStyles"
        >
            Элемент
        </div>
    </div>
</template>

<script setup>
    import { ref, computed } from 'vue';
    import { UiRange } from '@parkonika-dev/design-system';

    const x = ref(50);
    const y = ref(50);

    const previewStyles = computed(() => ({
        position: 'absolute',
        top: `${y.value}%`,
        left: `${x.value}%`,
        transform: 'translate(-50%, -50%)',
    }));

    const updatePreview = () => {
        console.log(`Position: X=${x.value}%, Y=${y.value}%`);
    };
</script>
```

---

### UiInput - Поле ввода с валидацией <a id="uiinput"></a>

#### [ ⬆️ 📖 К содержанию ](#content)

Умные поля ввода со встроенной валидацией, масками и поддержкой различных типов данных. Интегрируется с популярными библиотеками валидации.

#### Пропсы компонента

| Параметр        | Тип                | По умолчанию | Описание                                                |
| --------------- | ------------------ | ------------ | ------------------------------------------------------- |
| `modelValue`    | `String`, `Number` | `''`         | Значение поля (v-model)                                 |
| `type`          | `String`           | `'text'`     | Тип поля: `'text'`, `'password'`, `'email'`, `'number'` |
| `label`         | `String`           | `''`         | Метка поля                                              |
| `placeholder`   | `String`           | `''`         | Плейсхолдер                                             |
| `id`            | `String`           | `''`         | Уникальный ID поля                                      |
| `error`         | `String`           | `''`         | Текст ошибки валидации                                  |
| `textColor`     | `String`           | `''`         | Кастомный цвет текста                                   |
| `width`         | `String`           | `'100%'`     | Ширина поля                                             |
| `height`        | `String`           | `'39px'`     | Высота поля                                             |
| `minWidth`      | `String`           | `'280px'`    | Минимальная ширина                                      |
| `maxWidth`      | `String`           | `'100%'`     | Максимальная ширина                                     |
| `fontSize`      | `String`           | `'0.9rem'`   | Размер шрифта                                           |
| `fontSizeError` | `String`           | `'12px'`     | Размер шрифта ошибки                                    |
| `borderRadius`  | `String`           | `'10px'`     | Радиус скругления                                       |

#### События компонента

| Событие             | Описание           | Параметры                  |
| ------------------- | ------------------ | -------------------------- |
| `update:modelValue` | Изменение значения | `value` - новое значение   |
| `blur`              | Потеря фокуса      | `value` - текущее значение |

#### Базовое использование

```vue
<template>
    <UiInput
        v-model="username"
        label="Имя пользователя"
        placeholder="Введите ваше имя"
        id="username-input"
    />
</template>

<script setup>
    import { ref } from 'vue';
    import { UiInput } from '@parkonika-dev/design-system';

    const username = ref('');
</script>
```

#### Пример с ручной валидацией

```vue
<template>
    <form
        @submit="handleSubmit"
        class="form"
    >
        <UiInput
            id="screen-name-input"
            v-model="screenName"
            label="Имя директории"
            placeholder="Новая директория"
            class="form__input"
            :error="nameError"
            @blur="validateName"
        />

        <UiInput
            id="email-input"
            v-model="email"
            type="email"
            label="Email"
            placeholder="user@example.com"
            :error="emailError"
            @blur="validateEmail"
        />

        <button
            type="submit"
            :disabled="!isFormValid"
        >
            Сохранить
        </button>
    </form>
</template>

<script setup>
    import { ref, computed } from 'vue';
    import { UiInput } from '@parkonika-dev/design-system';

    const screenName = ref('');
    const email = ref('');
    const nameError = ref('');
    const emailError = ref('');

    // Валидация имени директории
    const validateName = () => {
        if (!screenName.value.trim()) {
            nameError.value = 'Поле обязательно для заполнения';
            return false;
        }

        if (!/^[a-zA-Z0-9_-]+$/.test(screenName.value)) {
            nameError.value = 'Только латинские буквы, цифры, дефисы и подчёркивания';
            return false;
        }

        if (screenName.value.length > 30) {
            nameError.value = 'Максимальная длина - 30 символов';
            return false;
        }

        nameError.value = '';
        return true;
    };

    // Валидация email
    const validateEmail = () => {
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

        if (!email.value.trim()) {
            emailError.value = 'Email обязателен для заполнения';
            return false;
        }

        if (!emailRegex.test(email.value)) {
            emailError.value = 'Некорректный формат email';
            return false;
        }

        emailError.value = '';
        return true;
    };

    // Проверка валидности формы
    const isFormValid = computed(() => {
        return screenName.value.trim() && email.value.trim() && !nameError.value && !emailError.value;
    });

    const handleSubmit = e => {
        e.preventDefault();

        const isNameValid = validateName();
        const isEmailValid = validateEmail();

        if (isNameValid && isEmailValid) {
            // Отправка формы
            console.log('Форма валидна:', {
                screenName: screenName.value,
                email: email.value,
            });
        }
    };
</script>
```

### Пример с Yup валидацией (сторонняя библиотек)

```vue
<template>
    <form
        @submit="handleSubmit"
        class="form"
    >
        <UiInput
            id="user-name-input"
            v-model="formData.userName"
            label="ФИО"
            placeholder="Иванов Иван Иванович"
            :error="errors.userName"
            @blur="validateField('userName')"
        />

        <UiInput
            id="car-number-input"
            v-model="formData.carNumber"
            label="Номер автомобиля"
            placeholder="A123BC"
            :error="errors.carNumber"
            @blur="validateField('carNumber')"
        />

        <UiInput
            id="email-input"
            v-model="formData.email"
            type="email"
            label="Email"
            placeholder="user@example.com"
            :error="errors.email"
            @blur="validateField('email')"
        />

        <button
            type="submit"
            :disabled="!isFormValid"
        >
            Зарегистрироваться
        </button>
    </form>
</template>

<script setup>
    import { ref, reactive, computed } from 'vue';
    import * as yup from 'yup';
    import { UiInput } from '@parkonika-dev/design-system';

    // Схема валидации Yup
    const validationSchema = yup.object({
        userName: yup.string().required('ФИО обязательно для заполнения'),
        carNumber: yup
            .string()
            .required('Номер авто обязателен для заполнения')
            .matches(/^(?=.*[A-Za-zА-Яа-я])[A-Za-zА-Яа-я0-9]{5,}$/, 'Не меньше 5 символов, минимум 1 буква'),
        email: yup
            .string()
            .required('Email обязателен для заполнения')
            .matches(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, 'Некорректный email (пример: user@example.com)')
            .test('no-disposable-email', 'Диспозейбл-email запрещены', async value => {
                if (!value) return true;
                const domain = value.split('@')[1];
                const disposableDomains = ['mailinator.com', 'temp-mail.org', '10minutemail.com'];
                return !disposableDomains.includes(domain);
            }),
    });

    // Данные формы
    const formData = reactive({
        userName: '',
        carNumber: '',
        email: '',
    });

    // Ошибки валидации
    const errors = reactive({
        userName: '',
        carNumber: '',
        email: '',
    });

    // Валидация отдельного поля
    const validateField = async fieldName => {
        try {
            await validationSchema.validateAt(fieldName, formData);
            errors[fieldName] = '';
            return true;
        } catch (error) {
            errors[fieldName] = error.message;
            return false;
        }
    };

    // Валидация всей формы
    const validateForm = async () => {
        try {
            await validationSchema.validate(formData, { abortEarly: false });
            Object.keys(errors).forEach(key => (errors[key] = ''));
            return true;
        } catch (error) {
            // Очищаем предыдущие ошибки
            Object.keys(errors).forEach(key => (errors[key] = ''));

            // Устанавливаем новые ошибки
            error.inner.forEach(err => {
                if (errors.hasOwnProperty(err.path)) {
                    errors[err.path] = err.message;
                }
            });
            return false;
        }
    };

    // Проверка валидности формы
    const isFormValid = computed(() => {
        return Object.values(errors).every(error => !error) && Object.values(formData).every(value => value.trim());
    });

    const handleSubmit = async e => {
        e.preventDefault();

        const isValid = await validateForm();

        if (isValid) {
            // Отправка формы
            console.log('Форма валидна:', formData);
            // Ваша логика отправки...
        }
    };
</script>
```

---

Документация постоянно обновляется. Следите за обновлениями!