plugin-ui-for-kzt 0.0.23 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/assets/0e28e37419c99ac65b12.png +0 -0
  2. package/dist/assets/264165b2b0e8a6840eb0.png +0 -0
  3. package/dist/components/{DataTable/DataTable.vue.d.ts → BaseDefaultPages/BaseDefaultPages.vue.d.ts} +8 -6
  4. package/dist/components/BaseInput/BaseInput.vue.d.ts +1 -1
  5. package/dist/components/{Tooltip/Tooltip.vue.d.ts → BasePageLoader/BasePageLoader.vue.d.ts} +24 -11
  6. package/dist/components/BaseTable/BaseTable.vue.d.ts +44 -0
  7. package/dist/components/BaseToast/BaseToast.vue.d.ts +69 -0
  8. package/dist/composables/useToast.d.ts +2 -0
  9. package/dist/index.d.ts +6 -5
  10. package/dist/index.js +1 -1
  11. package/dist/plugins/toastPlugin.d.ts +4 -0
  12. package/dist/sprite.svg +1 -1
  13. package/dist/store/toast.d.ts +8 -0
  14. package/example/App.vue +196 -29
  15. package/package.json +1 -1
  16. package/src/assets/404.png +0 -0
  17. package/src/assets/icons/arrow-down-stick.svg +4 -0
  18. package/src/assets/icons/edit-table.svg +5 -0
  19. package/src/assets/icons/ellipsis.svg +5 -0
  20. package/src/assets/icons/loading-page-default.svg +4 -0
  21. package/src/assets/icons/loading-page-error.svg +6 -0
  22. package/src/assets/icons/loading-page-success.svg +5 -0
  23. package/src/assets/icons/loading-page-warning.svg +6 -0
  24. package/src/assets/icons/more-dots.svg +5 -0
  25. package/src/assets/icons/time-table.svg +7 -0
  26. package/src/assets/icons/toast-error.svg +3 -0
  27. package/src/assets/icons/toast-info.svg +3 -0
  28. package/src/assets/icons/toast-success.svg +3 -0
  29. package/src/assets/icons/toast-warning.svg +3 -0
  30. package/src/assets/icons/trash-table.svg +7 -0
  31. package/src/assets/tech-work.png +0 -0
  32. package/src/components/BaseChips/BaseChips.vue +3 -1
  33. package/src/components/BaseDefaultPages/BaseDefaultPages.vue +140 -0
  34. package/src/components/BaseDefaultPages/README.md +128 -0
  35. package/src/components/BaseOpenedListItem/BaseOpenedListItem.vue +3 -3
  36. package/src/components/BasePageLoader/BasePageLoader.vue +211 -0
  37. package/src/components/BasePageLoader/README.md +80 -0
  38. package/src/components/BaseSelect/BaseSelect.vue +7 -3
  39. package/src/components/BaseTable/BaseTable.vue +411 -0
  40. package/src/components/BaseTable/README.md +294 -0
  41. package/src/components/BaseToast/BaseToast.vue +200 -0
  42. package/src/components/BaseToast/README.md +103 -0
  43. package/src/components/BaseTooltip/BaseTooltip.vue +1 -0
  44. package/src/components/BaseUpload/BaseUpload.vue +1 -1
  45. package/src/composables/useToast.ts +10 -0
  46. package/src/index.ts +17 -13
  47. package/src/plugins/toastPlugin.ts +100 -0
  48. package/src/store/toast.ts +59 -0
  49. package/src/styles/root.scss +2 -0
  50. package/src/styles/toast.scss +36 -0
  51. package/src/types/default-pages.d.ts +6 -0
  52. package/src/types/loading-page.d.ts +12 -0
  53. package/src/types/pagination.d.ts +1 -0
  54. package/src/types/table.d.ts +33 -0
  55. package/src/types/toast.d.ts +25 -0
  56. package/webpack.config.js +12 -0
  57. package/dist/components/Spinner/Spinner.vue.d.ts +0 -20
  58. package/dist/components/Toaster/Toaster.vue.d.ts +0 -80
  59. package/dist/components/Toaster/timer.d.ts +0 -12
  60. package/dist/plugins/toasterPlugin.d.ts +0 -26
  61. package/src/components/DataTable/DataTable.vue +0 -169
  62. package/src/components/DataTable/README.md +0 -57
  63. package/src/components/Spinner/README.md +0 -35
  64. package/src/components/Spinner/Spinner.vue +0 -60
  65. package/src/components/Toaster/README.md +0 -70
  66. package/src/components/Toaster/Toaster.vue +0 -235
  67. package/src/components/Toaster/timer.ts +0 -45
  68. package/src/components/Tooltip/README.md +0 -37
  69. package/src/components/Tooltip/Tooltip.vue +0 -96
  70. package/src/components/icons/CloseIcon.vue +0 -5
  71. package/src/components/icons/ErrorIcon.vue +0 -7
  72. package/src/components/icons/InfoIcon.vue +0 -7
  73. package/src/components/icons/SuccessIcon.vue +0 -6
  74. package/src/components/icons/WarningIcon.vue +0 -7
  75. package/src/plugins/toasterPlugin.ts +0 -179
@@ -0,0 +1,294 @@
1
+ # BaseTable – универсальная таблица с пагинацией, сортировкой, выбором строк и анимацией
2
+
3
+ ## 1. Обзор
4
+
5
+ `BaseTable` – готовый к использованию UI‑компонент, который покрывает самые распространённые сценарии работы с табличными данными:
6
+
7
+ | Возможность | Как реализовано |
8
+ |-------------|-----------------|
9
+ | **Пагинация** | `BasePagination` под капотом, управляется пропом `pagination`. |
10
+ | **Сортировка** | Указание `sortable: true` в колонке → клик генерирует событие `sort-change`. |
11
+ | **Выбор строк** | Чек‑боксы в каждой строке и «Выбрать всё» в заголовке. |
12
+ | **Отключённые строки** | Флаг `row.disabled` → визуальная стилизация и отключение чек‑бокса/кнопок. |
13
+ | **Кастомные ячейки** | Слоты `cell-{key}` позволяют переопределять отрисовку любой ячейки. |
14
+ | **Колонка‑действий** | Слот `actions` + массив `actions` (иконки + обработчики). |
15
+ | **Меню строки** | Слот `row-menu` (например, выпадающий `BaseDropdown`). |
16
+
17
+ ## 2. API компонента
18
+
19
+ ### Props
20
+
21
+ | Prop | Тип | По‑умолчанию | Описание |
22
+ |------|-----|--------------|----------|
23
+ | `data` | `Row[]` | `[]` | Массив строк, которые будут показаны в таблице. |
24
+ | `columns` | `Column[]` | `[]` | Описание колонок (см. ниже). |
25
+ | `rowKey` | `string \| ((row: Row) => unknown)` | `undefined` | Ключ/функция, используемая для уникального `key` строки. Если не задано – берётся `row.__uid` или JSON‑строка. |
26
+ | `showRowSelection` | `boolean` | `false` | Показывать чек‑бокс выбора строки и «Выбрать всё» в заголовке. |
27
+ | `checkboxTitle` | `string` | `''` | Текст рядом с чек‑боксом «Выбрать всё». |
28
+ | `showActions` | `boolean` | `false` | Показать колонку‑действий (по‑умолчанию слоты `actions`). |
29
+ | `actions` | `{ key: string; icon: string; handler: (row: Row) => void }[]` | `[]` | Массив действий, отрендеренных в колонке‑действий. Если `showActions` = `true`, а `actions` пустой – в слоте `actions` вы можете задать собственный UI. |
30
+ | `showPagination` | `boolean` | `true` (авто‑вычисляется) | Показать блок пагинации в футере. |
31
+ | `pagination` | `TPaginationProps` | `{ perPage: 10 }` | Параметры пагинации. Поддерживаемые свойства: <br>• `perPage` – количество строк на страницу.<br>• `currentPage` – текущая страница (управляемое значение).<br>• любые остальные свойства, которые принимает `BasePagination`. |
32
+ | `showHeader` | `boolean` | `true` | Если `false`, полностью убирает `<thead>` (можно использовать собственный `slot` `header`). |
33
+ | `rowSelectionDisabled` | `boolean` | `false` | Отключить возможность менять выбранные строки (чек‑боксы будут `disabled`). |
34
+ | `rowClass` | `((row: Row) => string) \| string` | `''` | Дополнительный CSS‑класс для строки. Если функция – возвращает класс в зависимости от строки. |
35
+ | `rowDisabledProp` | `string` | `'disabled'` | Имя свойства в объекте `Row`, которое считается флагом **disabled**. По‑умолчанию `row.disabled`. Позволяет переименовать, если в модели используется другое поле. |
36
+ | `...rest` | — | — | Все остальные props передаются напрямую в `BasePagination` (через `v-bind="pagination"`). |
37
+
38
+ ### Events
39
+
40
+ | Event | Payload | Описание |
41
+ |-------|---------|----------|
42
+ | `update:selected` | `Row[]` | Вызывается каждый раз, когда меняется набор выбранных строк. |
43
+ | `select-all` | `boolean` | Было ли отмечено «Выбрать всё». |
44
+ | `sort-change` | `{ key: string; order: 'asc' \| 'desc' }` | Пользователь кликнул по сортируемой колонке. Компонент **не** сортирует данные сам, вы должны обновить массив `data` согласно полученному payload. |
45
+ | `page-change` | `number` | Текущая страница изменилась (клик по пагинации). |
46
+
47
+ ### Slots
48
+
49
+ | Slot | Параметры | Описание |
50
+ |------|-----------|----------|
51
+ | `header` | — | Полностью заменяет содержимое `<thead>` (можно переопределить заголовок, добавить собственные ячейки). Если слот не задан, используется авто‑генерация из `columns`. |
52
+ | `cell-{key}` | `{ row: Row; value: any }` | Кастомный рендер ячейки конкретного столбца. Пример: `<template #cell-name="{ row }"><strong>{{ row.name }}</strong></template>` |
53
+ | `actions` | `{ row: Row }` | Содержимое колонки‑действий. По‑умолчанию выводятся кнопки из массива `actions`. |
54
+ | `row-menu` | `{ row: Row }` | Дополнительный столбец‑меню (например, `BaseDropdown`). |
55
+ | `empty` | — | Содержимое строки, показываемой когда `data` пустой (по‑умолчанию – `Нет данных`). |
56
+ | `default` (для `<BaseTable>`) | — | Плейсхолдер – обычно не используется, так как контент задаётся через перечисленные выше слоты. |
57
+
58
+ export interface Row {
59
+ /** Любые пользовательские поля */
60
+ [key: string]: unknown
61
+ /** Флаг, отключающий строку (по‑умолчанию `disabled`) */
62
+ disabled?: boolean
63
+ }
64
+
65
+ export interface Column {
66
+ /** Ключ доступа к полю из Row */
67
+ key: string
68
+ /** Текст в заголовке колонки */
69
+ label?: string
70
+ /** Пояснительная подсказка (title) */
71
+ tooltip?: string
72
+ /** Иконки слева и справа от заголовка (компоненты) */
73
+ icons?: [any, any] // любая vue‑компонента
74
+ /** Делает колонку сортируемой */
75
+ sortable?: boolean
76
+ /** Ширина/стилизация – задаётся через CSS (необязательно) */
77
+ width?: string | number
78
+ }
79
+
80
+ export interface TPaginationProps {
81
+ perPage?: number // сколько строк на страницу
82
+ currentPage?: number // текущая страница (управляемый проп)
83
+ }
84
+
85
+ ## 3. Примеры использования
86
+
87
+ ### 3.1. Базовая таблица
88
+
89
+ <template>
90
+ <BaseTable :data="rows" :columns="cols" />
91
+ </template>
92
+
93
+ <script setup lang="ts">
94
+ import BaseTable from '@/components/BaseTable/BaseTable.vue'
95
+
96
+ const cols = [
97
+ { key: 'id', label: 'ID' },
98
+ { key: 'title', label: 'Заголовок' },
99
+ { key: 'date', label: 'Дата', sortable: true },
100
+ ]
101
+
102
+ const rows = [
103
+ { id: 1, title: 'Заказ #123', date: '2024‑03‑01' },
104
+ { id: 2, title: 'Заказ #124', date: '2024‑03‑02' },
105
+ // …
106
+ ]
107
+ </script>
108
+
109
+ > В этом примере все функции по умолчанию (без пагинации, без выбора строк).
110
+
111
+ ### 3.2. Выбор строк (чек‑боксы)
112
+
113
+ <template>
114
+ <BaseTable
115
+ :data="items"
116
+ :columns="cols"
117
+ :show-row-selection="true"
118
+ @update:selected="onSelection"
119
+ />
120
+ </template>
121
+
122
+ <script setup lang="ts">
123
+ import BaseTable from '@/components/BaseTable/BaseTable.vue'
124
+
125
+ const cols = [{ key: 'name', label: 'Имя' }, { key: 'email', label: 'Email' }]
126
+
127
+ const items = [
128
+ { id: 1, name: 'Иван', email: 'ivan@example.com' },
129
+ { id: 2, name: 'Мария', email: 'maria@example.com' },
130
+ ]
131
+
132
+ function onSelection(selected) {
133
+ console.log('Выбрано строк:', selected)
134
+ }
135
+ </script>
136
+
137
+ > При активировании `showRowSelection` в заголовке появляется чек‑бокс «Выбрать всё». Выбранные строки доступны в `selected`.
138
+
139
+ <a name="example-sorting"></a>
140
+
141
+ ### 3.3. Сортируемые колонки
142
+
143
+ ```vue
144
+ <template>
145
+ <BaseTable
146
+ :data="sortedData"
147
+ :columns="cols"
148
+ @sort-change="handleSort"
149
+ />
150
+ </template>
151
+
152
+ <script setup lang="ts">
153
+ import { ref, computed } from 'vue'
154
+ import BaseTable from '@/components/BaseTable/BaseTable.vue'
155
+
156
+ const cols = [
157
+ { key: 'name', label: 'Имя', sortable: true },
158
+ { key: 'age', label: 'Возраст', sortable: true },
159
+ ]
160
+
161
+ const raw = [
162
+ { id: 1, name: 'Иван', age: 31 },
163
+ { id: 2, name: 'Мария', age: 27 },
164
+ { id: 3, name: 'Петр', age: 45 },
165
+ ]
166
+
167
+ const sortKey = ref<string | null>(null)
168
+ const sortOrder = ref<'asc' | 'desc'>('asc')
169
+
170
+ function handleSort({ key, order }) {
171
+ sortKey.value = key
172
+ sortOrder.value = order
173
+ }
174
+
175
+ /* Сортируем массив реактивно */
176
+ const sortedData = computed(() => {
177
+ if (!sortKey.value) return raw
178
+ return [...raw].sort((a, b) => {
179
+ const aVal = a[sortKey.value!]
180
+ const bVal = b[sortKey.value!]
181
+ if (aVal === bVal) return 0
182
+ if (sortOrder.value === 'asc') return aVal > bVal ? 1 : -1
183
+ else return aVal < bVal ? 1 : -1
184
+ })
185
+ })
186
+ </script>
187
+ ```
188
+
189
+ > Компонент генерирует событие `sort-change`, а реальную сортировку вы делаете в родителе (как показано).
190
+
191
+ <a name="example-pagination"></a>
192
+
193
+ ### 3.4. Пагинация
194
+
195
+ ```vue
196
+ <template>
197
+ <BaseTable
198
+ :data="bigList"
199
+ :columns="cols"
200
+ :pagination="{ perPage: 20, currentPage: 1 }"
201
+ @page-change="page => console.log('Страница:', page)"
202
+ />
203
+ </template>
204
+
205
+ <script setup lang="ts">
206
+ import BaseTable from '@/components/BaseTable/BaseTable.vue'
207
+
208
+ const cols = [{ key: 'index', label: '#' }, { key: 'value', label: 'Значение' }]
209
+
210
+ // Генерируем 200 строк
211
+ const bigList = Array.from({ length: 200 }, (_, i) => ({
212
+ index: i + 1,
213
+ value: `Элемент ${i + 1}`,
214
+ }))
215
+ </script>
216
+ ```
217
+
218
+ > Компонент автоматически рассчитывает количество страниц (`Math.ceil(data.length / perPage)`) и отображает `BasePagination` в футере.
219
+
220
+ <a name="example-disabled"></a>
221
+
222
+ ### 3.5. Отключённые строки
223
+
224
+ ```vue
225
+ <template>
226
+ <BaseTable
227
+ :data="rows"
228
+ :columns="cols"
229
+ :show-row-selection="true"
230
+ :show-actions="true"
231
+ :actions="rowActions"
232
+ />
233
+ </template>
234
+
235
+ <script setup lang="ts">
236
+ import BaseTable from '@/components/BaseTable/BaseTable.vue'
237
+
238
+ const cols = [{ key: 'name', label: 'Имя' }]
239
+
240
+ const rows = [
241
+ { id: 1, name: 'Активный 1' },
242
+ { id: 2, name: 'Отключённый', disabled: true }, // <-- будет в сером стиле
243
+ { id: 3, name: 'Активный 2' },
244
+ ]
245
+
246
+ const rowActions = [
247
+ {
248
+ key: 'edit',
249
+ icon: 'edit',
250
+ handler: (row) => console.log('edit', row),
251
+ },
252
+ ]
253
+ </script>
254
+
255
+ * Что происходит:
256
+ - Строка с полем `disabled: true` получает класс `--is-disabled`.
257
+ - Чек‑бокс и все кнопки в этой строке получают атрибут `disabled`.
258
+ - `pointer-events` отключены, поэтому пользователь не может кликнуть по ячейкам.
259
+
260
+
261
+ ### 3.6. Кастомные ячейки через слоты
262
+
263
+ <BaseTable :data="products" :columns="cols">
264
+ <!-- Ячейка «price» с форматированием -->
265
+ <template #cell-price="{ row }">
266
+ <span class="price">{{ formatPrice(row.price) }}</span>
267
+ </template>
268
+
269
+ <!-- Ячейка «status» с цветовой меткой -->
270
+ <template #cell-status="{ row }">
271
+ <span :class="['status', row.status]">{{ row.status }}</span>
272
+ </template>
273
+ </BaseTable>
274
+
275
+ ### 3.7. Кастомные действия (вместо массива `actions`)
276
+
277
+ Если вам нужен более сложный UI в колонке‑действий, просто переопределите слот `actions`:
278
+
279
+ <BaseTable
280
+ :data="users"
281
+ :columns="cols"
282
+ :show-actions="true"
283
+ >
284
+ <template #actions="{ row }">
285
+ <BaseButton size="extra-small" @click="openProfile(row)">
286
+ <BaseIcon name="user" />
287
+ </BaseButton>
288
+
289
+ <BaseDropdown>
290
+ <BaseDropdownItem @click="archive(row)">В архив</BaseDropdownItem>
291
+ <BaseDropdownItem @click="remove(row)" danger>Удалить</BaseDropdownItem>
292
+ </BaseDropdown>
293
+ </template>
294
+ </BaseTable>
@@ -0,0 +1,200 @@
1
+ <template>
2
+ <div class="base-toast" :class="classList" v-show="isOpen">
3
+ <div v-if="showIcon" class="base-toast__icon">
4
+ <base-icon :name="iconName" size="medium" />
5
+ </div>
6
+ <div class="base-toast__content">
7
+ <div class="base-toast__title">
8
+ {{ title }}
9
+ </div>
10
+ <div v-if="description" class="base-toast__description">
11
+ {{ description }}
12
+ </div>
13
+ <div
14
+ v-if="primaryActionText || secondaryActionText"
15
+ class="base-toast__actions"
16
+ >
17
+ <base-button
18
+ v-if="secondaryActionText"
19
+ color="secondary"
20
+ size="extra-small"
21
+ @click="emit('secondaryAction')"
22
+ >
23
+ {{ secondaryActionText }}
24
+ </base-button>
25
+ <base-button
26
+ v-if="primaryActionText"
27
+ color="primary"
28
+ size="extra-small"
29
+ @click="emit('primaryAction')"
30
+ >
31
+ {{ primaryActionText }}
32
+ </base-button>
33
+ </div>
34
+ </div>
35
+ <base-button
36
+ v-if="closable"
37
+ color="custom"
38
+ size="custom"
39
+ class="base-toast__close"
40
+ @click="emit('close')"
41
+ >
42
+ <base-icon name="close" size="medium" />
43
+ </base-button>
44
+ </div>
45
+ </template>
46
+
47
+ <script setup lang="ts">
48
+ import BaseIcon from '../BaseIcon/BaseIcon.vue';
49
+ import BaseButton from '../BaseButton/BaseButton.vue';
50
+ import { computed } from 'vue';
51
+ import type { IBaseToastProps } from '../../types/toast';
52
+
53
+ const props = withDefaults(defineProps<IBaseToastProps>(), {
54
+ type: 'info',
55
+ showIcon: true,
56
+ closable: true,
57
+ withBackground: false,
58
+ isOpen: true,
59
+ duration: undefined,
60
+ });
61
+
62
+ const emit = defineEmits<{
63
+ (e: 'close'): void;
64
+ (e: 'primaryAction'): void;
65
+ (e: 'secondaryAction'): void;
66
+ }>();
67
+
68
+ const iconName = computed(() => {
69
+ switch (props.type) {
70
+ case 'success':
71
+ return 'toast-success';
72
+ case 'warning':
73
+ return 'toast-warning';
74
+ case 'error':
75
+ return 'toast-error';
76
+ case 'info':
77
+ default:
78
+ return 'toast-info';
79
+ }
80
+ });
81
+
82
+ const classList = computed(() => [
83
+ `base-toast--${props.type}`,
84
+ { 'base-toast--has-description': props.description },
85
+ { 'base-toast--has-background': props.withBackground },
86
+ ]);
87
+ </script>
88
+
89
+ <style lang="scss" scoped>
90
+ @import '../../styles/variables';
91
+ @import '../../styles/root';
92
+
93
+ .base-toast {
94
+ display: flex;
95
+ align-items: flex-start;
96
+ gap: var(--spacing-s);
97
+ padding: var(--spacing-m);
98
+ border: 1px solid var(--primary-black-200);
99
+ border-radius: var(--corner-radius-m);
100
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
101
+ width: 100%;
102
+ max-width: 620px;
103
+ min-width: 335px;
104
+ background: var(--bg-light);
105
+ position: relative;
106
+ margin: 8px;
107
+ animation: slideIn 0.3s ease forwards;
108
+
109
+ @media (max-width: 768px) {
110
+ max-width: calc(100% - 16px);
111
+ min-width: calc(100% - 16px);
112
+ margin: 8px;
113
+ }
114
+
115
+ &--info,
116
+ &--success,
117
+ &--warning,
118
+ &--error {
119
+ border: none;
120
+ }
121
+
122
+ &.base-toast--has-background {
123
+ &.base-toast--info {
124
+ background: var(--primary-blue-100);
125
+ }
126
+ &.base-toast--success {
127
+ background: var(--success-green-light-05);
128
+ }
129
+ &.base-toast--warning {
130
+ background: var(--warning-orange-light-05);
131
+ }
132
+ &.base-toast--error {
133
+ background: var(--error-red-light-05);
134
+ }
135
+ }
136
+
137
+ &--has-description {
138
+ align-items: stretch;
139
+ }
140
+
141
+ &__icon {
142
+ display: flex;
143
+ align-items: flex-start;
144
+ }
145
+
146
+ &__content {
147
+ flex: 1;
148
+ display: flex;
149
+ flex-direction: column;
150
+ gap: var(--spacing-m);
151
+ }
152
+
153
+ &__title {
154
+ color: var(--primary-text-primary);
155
+ font: var(--typography-text-m-medium);
156
+ }
157
+
158
+ &__description {
159
+ color: var(--primary-text-secondary);
160
+ font: var(--typography-text-s-regular);
161
+ }
162
+
163
+ &__actions {
164
+ display: flex;
165
+ gap: var(--spacing-l);
166
+ }
167
+
168
+ &__close {
169
+ height: 100%;
170
+ background: none;
171
+ border: none;
172
+ }
173
+
174
+ &.base-toast--leave-active {
175
+ animation: slideOut 0.3s ease;
176
+ }
177
+ }
178
+
179
+ @keyframes slideIn {
180
+ from {
181
+ transform: translateY(100%);
182
+ opacity: 0;
183
+ }
184
+ to {
185
+ transform: translateY(0);
186
+ opacity: 1;
187
+ }
188
+ }
189
+
190
+ @keyframes slideOut {
191
+ from {
192
+ transform: translateY(0);
193
+ opacity: 1;
194
+ }
195
+ to {
196
+ transform: translateY(100%);
197
+ opacity: 0;
198
+ }
199
+ }
200
+ </style>
@@ -0,0 +1,103 @@
1
+ # Компонент `BaseToast` и Плагин `ToastPlugin`
2
+
3
+ Компонент `BaseToast` — это универсальный компонент уведомлений (тостов) для отображения кратких сообщений пользователю с поддержкой различных типов (инфо, успех, предупреждение, ошибка) и кастомизацией. Плагин `ToastPlugin` интегрирует компонент в приложение Vue.js, предоставляя удобный API для управления тостами через глобальный объект `$toast`.
4
+
5
+ ## Использование
6
+
7
+ ### Базовый пример
8
+ Используйте composable `useToast` для вызова тостов из любого компонента:
9
+
10
+ ```vue
11
+ <template>
12
+ <div>
13
+ <base-button @click="openToast">Показать тост</base-button>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { useToast } from '../composables/useToast';
19
+
20
+ const toast = useToast();
21
+
22
+ const openToast = () => {
23
+ toast.show('toast-1', {
24
+ title: 'Успех',
25
+ type: 'success',
26
+ description: 'Операция выполнена успешно!',
27
+ showIcon: true,
28
+ closable: true,
29
+ primaryActionText: 'Подтвердить',
30
+ secondaryActionText: 'Отмена',
31
+ });
32
+ };
33
+ </script>
34
+ ```
35
+
36
+ ### API
37
+ #### Методы
38
+ - **`$toast.show(id: string, props: IBaseToastProps)`**: Показывает новый тост.
39
+ - `id`: Уникальный идентификатор тоста (тосты с одинаковым `id` заменяют друг друга).
40
+ - `props`: Объект с настройками тоста (см. ниже).
41
+ - **`$toast.hide(id: string)`**: Скрывает тост по указанному `id`.
42
+ - **`$toast.clear()`**: Удаляет все тосты.
43
+
44
+ #### Свойства `IBaseToastProps`
45
+ - `title: string` (обязательно): Заголовок тоста.
46
+ - `type?: 'info' | 'success' | 'warning' | 'error'`: Тип тоста (по умолчанию `'info'`).
47
+ - `withBackground?: boolean`: Добавляет цветной фон в зависимости от типа (по умолчанию `false`).
48
+ - `description?: string`: Описание тоста.
49
+ - `showIcon?: boolean`: Показывать иконку (по умолчанию `true`).
50
+ - `closable?: boolean`: Показывать кнопку закрытия (по умолчанию `true`).
51
+ - `primaryActionText?: string`: Текст для основной кнопки действия.
52
+ - `secondaryActionText?: string`: Текст для вторичной кнопки действия.
53
+ - `duration?: number`: Время отображения в миллисекундах (по умолчанию рассчитывается: 5000 мс для текста ≤ 80 символов, 10000 мс для > 80 символов).
54
+
55
+ ### Примеры
56
+
57
+ #### Тост с кастомным временем
58
+ ```typescript
59
+ toast.show('toast-custom', {
60
+ title: 'Кастомный тост',
61
+ type: 'warning',
62
+ description: 'Это сообщение покажется на 3 секунды.',
63
+ duration: 3000,
64
+ });
65
+ ```
66
+
67
+ #### Тост с действиями
68
+ ```typescript
69
+ toast.show('toast-action', {
70
+ title: 'Действие',
71
+ type: 'info',
72
+ primaryActionText: 'Подтвердить',
73
+ secondaryActionText: 'Отмена',
74
+ onPrimaryAction: () => console.log('Подтверждено'),
75
+ onSecondaryAction: () => console.log('Отменено'),
76
+ });
77
+ ```
78
+
79
+ #### Замена тоста
80
+ ```typescript
81
+ toast.show('toast-1', { title: 'Тост 1', type: 'success' });
82
+ toast.show('toast-1', { title: 'Тост 2', type: 'success' }); // Заменит первый тост
83
+ ```
84
+
85
+ #### Несколько тостов
86
+ ```typescript
87
+ toast.show('toast-info', { title: 'Инфо', type: 'info' });
88
+ toast.show('toast-success', { title: 'Успех', type: 'success' });
89
+ ```
90
+ Тосты отображаются в колонке (максимум 4 на десктопе, 3 на мобильных).
91
+
92
+
93
+ ### Анимации
94
+ Анимации `slideIn` и `slideOut` определены в `BaseToast.vue`. Их можно переопределить, добавив собственные `@keyframes` в глобальные стили.
95
+
96
+ ## Поведение
97
+
98
+ - **Позиционирование**: Тосты отображаются в правом верхнему углу экрана (`top: 20px`, `right: 20px`) с максимальной шириной 620px на десктопе. На мобильных устройствах (ширина ≤ 768px) растягиваются на всю ширину с отступами 8px.
99
+ - **Автозакрытие**: По умолчанию 5 секунд для сообщений ≤ 80 символов, 10 секунд для > 80 символов. Можно задать кастомное время через `duration`.
100
+ - **Замена тостов**: Тосты с одинаковым `id` заменяют друг друга. Тосты с разными `id` отображаются в колонке.
101
+ - **Ограничение**: Максимум 4 тоста на десктопе, 3 на мобильных. При превышении удаляется самый старый тост.
102
+ - **Закрытие**: Тосты закрываются при нажатии на кнопку закрытия (если `closable`), по истечении времени или при смене страницы (событие `popstate`).
103
+
@@ -32,6 +32,7 @@
32
32
  <script setup lang="ts">
33
33
  import { computed, onMounted, onUnmounted, ref } from 'vue';
34
34
  import type { ITooltipProps } from '../../types/tooltip';
35
+ import BaseIcon from '../BaseIcon/BaseIcon.vue';
35
36
 
36
37
  const props = withDefaults(defineProps<ITooltipProps>(), {
37
38
  position: 'top',
@@ -389,7 +389,7 @@ gap: var(--spacing-l);
389
389
  }
390
390
 
391
391
  &__error {
392
- color: var(--primary-red-500);
392
+ color: var(--error-red);
393
393
  margin-top: 0.5rem;
394
394
  font-size: var(--typography-text-s-regular);
395
395
  }
@@ -0,0 +1,10 @@
1
+ import { inject } from 'vue';
2
+ import type { IToastApi } from '../types/toast';
3
+
4
+ export function useToast() {
5
+ const toast = inject<IToastApi>('$toast');
6
+ if (!toast) {
7
+ throw new Error('toast plugin is not installed');
8
+ }
9
+ return toast;
10
+ }