plugin-ui-for-kzt 0.0.30 → 0.0.32
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.
- package/dist/components/BaseBadge/BaseBadge.vue.d.ts +1 -1
- package/dist/components/BaseCalendar/BaseCalendar.vue.d.ts +45 -1
- package/dist/components/BaseCheckbox/BaseCheckbox.vue.d.ts +2 -2
- package/dist/components/BaseDefaultPages/BaseDefaultPages.vue.d.ts +2 -0
- package/dist/components/BaseDropdown/BaseDropdown.vue.d.ts +1 -1
- package/dist/components/BaseInput/BaseInput.vue.d.ts +2 -2
- package/dist/components/BaseInputCalendar/BaseInputCalendar.vue.d.ts +17 -8
- package/dist/components/BaseInputCurrency/BaseInputCurrency.vue.d.ts +9 -2
- package/dist/components/BaseInputEmail/BaseInputEmail.vue.d.ts +2 -2
- package/dist/components/BaseInputPhone/BaseInputPhone.vue.d.ts +2 -2
- package/dist/components/BaseRadio/BaseRadio.vue.d.ts +2 -2
- package/dist/components/BaseSegmentedButtons/BaseSegmentedButtons.vue.d.ts +1 -1
- package/dist/components/BaseSelect/BaseSelect.vue.d.ts +3 -3
- package/dist/components/BaseTextarea/BaseTextarea.vue.d.ts +2 -2
- package/dist/components/BaseToggle/BaseToggle.vue.d.ts +2 -2
- package/dist/index.js +1 -1
- package/example/App.vue +62 -270
- package/example/MyCustomModal.vue +1 -0
- package/package.json +1 -1
- package/src/assets/icons/calendar.svg +2 -2
- package/src/components/BaseCalendar/BaseCalendar.vue +28 -3
- package/src/components/BaseDefaultPages/BaseDefaultPages.vue +0 -9
- package/src/components/BaseIcon/BaseIcon.vue +1 -1
- package/src/components/BaseInputCalendar/BaseInputCalendar.vue +40 -5
- package/src/components/BaseInputCurrency/BaseInputCurrency.vue +21 -10
- package/src/components/BaseInputPhone/BaseInputPhone.vue +3 -3
- package/src/components/BaseModal/BaseModal.vue +1 -3
- package/src/components/BaseSelect/BaseSelect.vue +33 -6
- package/src/components/BaseSwiper/BaseSwiper.vue +9 -4
- package/src/components/BaseTextarea/BaseTextarea.vue +1 -0
- package/src/types/calendar.d.ts +5 -2
- package/src/types/default-pages.d.ts +1 -0
- package/src/types/input.d.ts +2 -2
- package/webpack.config.js +4 -0
- package/dist/assets/0e28e37419c99ac65b12.png +0 -0
- package/dist/assets/264165b2b0e8a6840eb0.png +0 -0
- /package/{src/assets → example}/404.png +0 -0
- /package/{src/assets → example}/tech-work.png +0 -0
package/example/App.vue
CHANGED
|
@@ -3,281 +3,73 @@
|
|
|
3
3
|
<h1>Plugin UI KZT - Компоненты</h1>
|
|
4
4
|
|
|
5
5
|
<section>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
</BaseUpload>
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
<div style="width: 400px;">
|
|
24
|
-
<h3>Одиночная загрузка (multiple: false)</h3>
|
|
25
|
-
<BaseUpload
|
|
26
|
-
:accepted-formats="['.pdf', '.docx', '.jpeg', '.jpg', '.png', '.svg']"
|
|
27
|
-
:multiple="false"
|
|
28
|
-
>
|
|
29
|
-
<template #title>
|
|
30
|
-
Перетащите файл сюда или кликните для выбора
|
|
31
|
-
</template>
|
|
32
|
-
<template #description>
|
|
33
|
-
Только один файл: PDF, DOCX, JPEG, JPG, PNG, SVG до 25 MB
|
|
34
|
-
</template>
|
|
35
|
-
</BaseUpload>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
|
-
</section>
|
|
39
|
-
|
|
40
|
-
<section>
|
|
41
|
-
<h2>Сравнение режимов</h2>
|
|
42
|
-
<div style="display: flex; gap: 20px;">
|
|
43
|
-
<div style="width: 300px;">
|
|
44
|
-
<h3>Дефолтный режим</h3>
|
|
45
|
-
<BaseSelect
|
|
46
|
-
id="select4"
|
|
47
|
-
:options="options"
|
|
48
|
-
:placeholder="'Выберите опцию'"
|
|
49
|
-
:label="'Опция'"
|
|
50
|
-
:searchable="false"
|
|
51
|
-
/>
|
|
52
|
-
</div>
|
|
53
|
-
<div style="width: 300px;">
|
|
54
|
-
<h3>Поисковый режим (новое поведение)</h3>
|
|
55
|
-
<BaseSelect
|
|
56
|
-
id="select5"
|
|
57
|
-
:options="searchableOptions"
|
|
58
|
-
:placeholder="'Выберите страну'"
|
|
59
|
-
:label="'Страна'"
|
|
60
|
-
:searchable="true"
|
|
61
|
-
:error="errorMessage"
|
|
62
|
-
@error="handleSelectError"
|
|
63
|
-
>
|
|
64
|
-
<template #empty>
|
|
65
|
-
<div>
|
|
66
|
-
Нет стран
|
|
67
|
-
</div>
|
|
68
|
-
</template>
|
|
69
|
-
</BaseSelect>
|
|
70
|
-
<p style="font-size: 12px; color: #666; margin-top: 8px;">
|
|
71
|
-
• Клик по стрелке открывает dropdown<br/>
|
|
72
|
-
• При точном совпадении элемент выбирается автоматически<br/>
|
|
73
|
-
• При выборе элемента иконка меняется на крестик<br/>
|
|
74
|
-
• Клик по крестику очищает выбор<br/>
|
|
75
|
-
• Клик по инпуту не очищает выбор<br/>
|
|
76
|
-
• При отсутствии совпадений эмитится ошибка
|
|
77
|
-
</p>
|
|
78
|
-
<div v-if="errorMessage" style="color: red; font-size: 12px; margin-top: 4px;">
|
|
79
|
-
Элемент не найден
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
</section>
|
|
84
|
-
|
|
85
|
-
<section>
|
|
86
|
-
<h2>Тест тултипов (несколько экземпляров)</h2>
|
|
87
|
-
<div style="display: flex; gap: 20px; align-items: center;">
|
|
88
|
-
<BaseTooltip
|
|
89
|
-
id="tooltip1"
|
|
90
|
-
title="Первый тултип"
|
|
91
|
-
content="Это первый тултип на странице"
|
|
92
|
-
trigger="click"
|
|
93
|
-
>
|
|
94
|
-
<template #trigger>
|
|
95
|
-
<button style="padding: 8px 16px; border: 1px solid #ccc; background: white; cursor: pointer;">
|
|
96
|
-
Тултип 1 (click)
|
|
97
|
-
</button>
|
|
98
|
-
</template>
|
|
99
|
-
</BaseTooltip>
|
|
100
|
-
|
|
101
|
-
<BaseTooltip
|
|
102
|
-
id="tooltip2"
|
|
103
|
-
title="Второй тултип"
|
|
104
|
-
content="Это второй тултип на странице"
|
|
105
|
-
trigger="click"
|
|
106
|
-
>
|
|
107
|
-
<template #trigger>
|
|
108
|
-
<button style="padding: 8px 16px; border: 1px solid #ccc; background: white; cursor: pointer;">
|
|
109
|
-
Тултип 2 (click)
|
|
110
|
-
</button>
|
|
111
|
-
</template>
|
|
112
|
-
</BaseTooltip>
|
|
113
|
-
|
|
114
|
-
<BaseTooltip
|
|
115
|
-
id="tooltip3"
|
|
116
|
-
title="Третий тултип"
|
|
117
|
-
content="Это третий тултип на странице"
|
|
118
|
-
trigger="hover"
|
|
119
|
-
>
|
|
120
|
-
<template #trigger>
|
|
121
|
-
<button style="padding: 8px 16px; border: 1px solid #ccc; background: white; cursor: pointer;">
|
|
122
|
-
Тултип 3 (hover)
|
|
123
|
-
</button>
|
|
124
|
-
</template>
|
|
125
|
-
</BaseTooltip>
|
|
126
|
-
</div>
|
|
127
|
-
</section>
|
|
128
|
-
|
|
129
|
-
<section>
|
|
130
|
-
<h2>BaseTable - Обычная таблица</h2>
|
|
131
|
-
<BaseTable
|
|
132
|
-
:columns="tableColumns"
|
|
133
|
-
:data="tableData"
|
|
134
|
-
:show-row-selection="true"
|
|
135
|
-
:show-actions="true"
|
|
136
|
-
:actions="tableActions"
|
|
137
|
-
/>
|
|
138
|
-
</section>
|
|
139
|
-
|
|
140
|
-
<section>
|
|
141
|
-
<h2>BaseTable - С пагинацией</h2>
|
|
142
|
-
<BaseTable
|
|
143
|
-
:columns="tableColumns"
|
|
144
|
-
:data="tableData"
|
|
145
|
-
:pagination="{ perPage: 5, currentPage: 1 }"
|
|
146
|
-
:show-row-selection="true"
|
|
147
|
-
:show-actions="true"
|
|
148
|
-
:actions="tableActions"
|
|
149
|
-
@page-change="handlePageChange"
|
|
150
|
-
/>
|
|
151
|
-
</section>
|
|
152
|
-
|
|
153
|
-
<section>
|
|
154
|
-
<h2>BaseTable - С виртуальным скроллом (высота: 400px)</h2>
|
|
155
|
-
<p style="font-size: 14px; color: #666; margin-bottom: 12px;">
|
|
156
|
-
• Колонки ID, Имя, Email, Статус теперь имеют заданные ширины: 80px, 200px, 1fr, 120px<br/>
|
|
157
|
-
• Ширины колонок в thead и виртуальном скролле полностью синхронизированы<br/>
|
|
158
|
-
• Можно использовать px, fr, auto или числовые значения для ширины<br/>
|
|
159
|
-
• Автоматическая компенсация ширины скроллбара - колонки не разъезжаются<br/>
|
|
160
|
-
• Настраиваемое выравнивание: ID - center, Имя - left, Email - left, Статус - right
|
|
161
|
-
</p>
|
|
162
|
-
<BaseTable
|
|
163
|
-
:columns="tableColumns"
|
|
164
|
-
:data="largeTableData"
|
|
165
|
-
:virtual-scroll="true"
|
|
166
|
-
:virtual-scroll-threshold="50"
|
|
167
|
-
:virtual-scroll-height="400"
|
|
168
|
-
:show-row-selection="true"
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
@scroll="handleScroll"
|
|
172
|
-
@scroll-end="handleScrollEnd"
|
|
6
|
+
<BaseInputCalendar
|
|
7
|
+
id="input-calendar"
|
|
8
|
+
v-model="demoValues.calendar"
|
|
9
|
+
placeholder="Доступно"
|
|
10
|
+
:min-date="new Date('2025-11-23')"
|
|
11
|
+
:max-date="new Date()"
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
<BaseTextarea
|
|
15
|
+
id="textarea"
|
|
16
|
+
v-model="demoValues.textarea"
|
|
17
|
+
placeholder="Введите текст..."
|
|
18
|
+
label="Текстовое поле"
|
|
19
|
+
readonly
|
|
173
20
|
/>
|
|
174
21
|
</section>
|
|
175
22
|
</div>
|
|
176
23
|
</template>
|
|
177
24
|
<script setup lang="ts">
|
|
178
|
-
import { ref
|
|
179
|
-
import
|
|
180
|
-
import
|
|
181
|
-
import
|
|
182
|
-
import
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
{ id: '
|
|
196
|
-
{ id: '
|
|
197
|
-
{ id: '
|
|
198
|
-
{ id: '
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
{ id: '
|
|
203
|
-
{ id: '
|
|
204
|
-
{ id: '
|
|
205
|
-
{ id: '
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
])
|
|
226
|
-
|
|
227
|
-
const tableData = ref([
|
|
228
|
-
{ id: 1, name: 'Иван Иванов', email: 'ivan@example.com', status: 'Активен' },
|
|
229
|
-
{ id: 2, name: 'Петр Петров', email: 'petr@example.com', status: 'Неактивен Неактивен Неактивен Неактивен Неактивен Неактивен Неактивен Неактивен Неактивен Неактивен Неактивен Неактивен' },
|
|
230
|
-
{ id: 3, name: 'Мария Сидорова', email: 'maria@example.com', status: 'Активен' },
|
|
231
|
-
{ id: 4, name: 'Анна Козлова', email: 'anna@example.com', status: 'Активен' },
|
|
232
|
-
{ id: 5, name: 'Сергей Волков', email: 'sergey@example.com', status: 'Неактивен' },
|
|
233
|
-
{ id: 6, name: 'Елена Морозова', email: 'elena@example.com', status: 'Активен' },
|
|
234
|
-
{ id: 7, name: 'Дмитрий Лебедев', email: 'dmitry@example.com', status: 'Активен' },
|
|
235
|
-
{ id: 8, name: 'Ольга Новикова', email: 'olga@example.com', status: 'Неактивен' }
|
|
236
|
-
])
|
|
237
|
-
|
|
238
|
-
// Большой набор данных для виртуального скролла
|
|
239
|
-
const largeTableData = computed(() => {
|
|
240
|
-
const data: any[] = []
|
|
241
|
-
for (let i = 1; i <= 100; i++) {
|
|
242
|
-
data.push({
|
|
243
|
-
id: i,
|
|
244
|
-
name: `Пользователь ${i}`,
|
|
245
|
-
email: `user${i}@example.com`,
|
|
246
|
-
status: i % 3 === 0 ? 'Неактивен Неактивен Неактивен Неактивен' : 'Активен'
|
|
247
|
-
})
|
|
248
|
-
}
|
|
249
|
-
console.log("🚀 ~ data:", data)
|
|
250
|
-
return data
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
const tableActions = ref([
|
|
254
|
-
{
|
|
255
|
-
key: 'edit',
|
|
256
|
-
icon: 'edit-table',
|
|
257
|
-
handler: (row: any) => {
|
|
258
|
-
console.log('Редактировать:', row)
|
|
259
|
-
}
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
key: 'delete',
|
|
263
|
-
icon: 'trash-table',
|
|
264
|
-
handler: (row: any) => {
|
|
265
|
-
console.log('Удалить:', row)
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
])
|
|
269
|
-
|
|
270
|
-
const handlePageChange = (page: number) => {
|
|
271
|
-
console.log('Смена страницы:', page)
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const handleScroll = (payload: any) => {
|
|
275
|
-
console.log('Скролл:', payload)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const handleScrollEnd = () => {
|
|
279
|
-
console.log('Достигнут конец списка - можно подгрузить еще данные')
|
|
280
|
-
}
|
|
25
|
+
import { ref } from 'vue';
|
|
26
|
+
import { useModal } from '../src/composables/useModal';
|
|
27
|
+
import BaseTextarea from '../src/components/BaseTextarea/BaseTextarea.vue';
|
|
28
|
+
import BaseSwiper from '../src/components/BaseSwiper/BaseSwiper.vue';
|
|
29
|
+
import BaseInputCalendar from '../src/components/BaseInputCalendar/BaseInputCalendar.vue';
|
|
30
|
+
import BaseInputCurrency from '../src/components/BaseInputCurrency/BaseInputCurrency.vue';
|
|
31
|
+
import BaseButton from '../src/components/BaseButton/BaseButton.vue';
|
|
32
|
+
import MyCustomModal from './MyCustomModal.vue';
|
|
33
|
+
|
|
34
|
+
const { open } = useModal();
|
|
35
|
+
|
|
36
|
+
const openModal = () => {
|
|
37
|
+
open('modal-example', {
|
|
38
|
+
closable: true,
|
|
39
|
+
}, MyCustomModal);
|
|
40
|
+
};
|
|
41
|
+
const currencyOptions = [
|
|
42
|
+
{ id: '1', name: 'USD', value: 'USD' as const, mask: '# #### ### 0.##', symbol: '$' },
|
|
43
|
+
{ id: '2', name: 'RUB', value: 'RUB' as const, mask: '# ##0.##', symbol: '₽' },
|
|
44
|
+
{ id: '3', name: 'KGS', value: 'KGS' as const, mask: '# ##0.##', symbol: '⃀' },
|
|
45
|
+
{ id: '4', name: 'UZS', value: 'UZS' as const, mask: '# ##0.##', symbol: 'сў' },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const iconOptions = [
|
|
49
|
+
{ id: 1, name: 'Пользователь', icon: 'email-sms' },
|
|
50
|
+
{ id: 2, name: 'Настройки', icon: 'document-text' },
|
|
51
|
+
{ id: 3, name: 'Файлы', icon: 'gallery' },
|
|
52
|
+
{ id: 4, name: 'Сообщения', icon: 'email-sms' },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
const demoValues = ref({
|
|
56
|
+
icons: iconOptions[0].id,
|
|
57
|
+
textarea: 'Тестовый текст',
|
|
58
|
+
calendar: new Date(),
|
|
59
|
+
calendarDisabled: new Date(),
|
|
60
|
+
calendarReadonly: new Date(),
|
|
61
|
+
currency: '0.00',
|
|
62
|
+
currency2: '0.00',
|
|
63
|
+
phone: '0777777777',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
const images = ref<string[]>([
|
|
69
|
+
'https://picsum.photos/seed/1/800/400',
|
|
70
|
+
'https://picsum.photos/seed/2/800/400',
|
|
71
|
+
'https://picsum.photos/seed/3/800/400',
|
|
72
|
+
]);
|
|
281
73
|
</script>
|
|
282
74
|
|
|
283
75
|
<style lang="scss" scoped>
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg viewBox="0 0 24 24" fill="none"
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
2
2
|
<path d="M8 2V5" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
3
|
<path d="M16 2V5" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
4
|
<path d="M3.5 9.08984H20.5" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
|
@@ -9,4 +9,4 @@
|
|
|
9
9
|
<path d="M11.9955 16.7002H12.0045" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
10
10
|
<path d="M8.29431 13.7002H8.30329" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
11
11
|
<path d="M8.29431 16.7002H8.30329" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
12
|
-
</svg>
|
|
12
|
+
</svg>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="base-calendar" :class="classList">
|
|
3
|
-
|
|
3
|
+
<vue-date-picker
|
|
4
|
+
:disabled="disabled || readonly"
|
|
4
5
|
v-model="computedModelValue"
|
|
5
6
|
:range="range"
|
|
6
7
|
locale="ru"
|
|
@@ -8,7 +9,8 @@
|
|
|
8
9
|
:inline="inline"
|
|
9
10
|
:text-input="textInputOptions"
|
|
10
11
|
:hide-navigation="['time']"
|
|
11
|
-
:min-date="
|
|
12
|
+
:min-date="minDateComputed"
|
|
13
|
+
:max-date="maxDateComputed"
|
|
12
14
|
:enable-time-picker="false"
|
|
13
15
|
:format="format"
|
|
14
16
|
month-name-format="long"
|
|
@@ -29,6 +31,7 @@ import VueDatePicker from '@vuepic/vue-datepicker';
|
|
|
29
31
|
import '@vuepic/vue-datepicker/dist/main.css';
|
|
30
32
|
import type { DateRange, TCoreCalendarProps } from '../../types/calendar';
|
|
31
33
|
import { useKitSize } from '../../composables/kit/size'
|
|
34
|
+
import { useKitState } from '../../composables/kit/state'
|
|
32
35
|
|
|
33
36
|
interface DpInputSlotProps {
|
|
34
37
|
value: string
|
|
@@ -37,8 +40,10 @@ interface DpInputSlotProps {
|
|
|
37
40
|
const props = withDefaults(defineProps<TCoreCalendarProps>(), {
|
|
38
41
|
range: false,
|
|
39
42
|
minDate: null,
|
|
43
|
+
maxDate: null,
|
|
40
44
|
size: 'medium',
|
|
41
45
|
inline: false,
|
|
46
|
+
disabled: false,
|
|
42
47
|
});
|
|
43
48
|
|
|
44
49
|
const emit: (event: 'update:modelValue', value: DateRange) => void = defineEmits();
|
|
@@ -46,8 +51,8 @@ const emit: (event: 'update:modelValue', value: DateRange) => void = defineEmits
|
|
|
46
51
|
const computedModelValue = computed<DateRange>({
|
|
47
52
|
get: () => props.modelValue ?? null,
|
|
48
53
|
set: (value: DateRange) => {
|
|
54
|
+
if (props.disabled || props.readonly) return;
|
|
49
55
|
emit('update:modelValue', value);
|
|
50
|
-
console.log(value);
|
|
51
56
|
},
|
|
52
57
|
});
|
|
53
58
|
|
|
@@ -58,14 +63,19 @@ const textInputOptions: { format: string } = {
|
|
|
58
63
|
const dayNames: string[] = ['П', 'В', 'С', 'Ч', 'П', 'С', 'В'];
|
|
59
64
|
|
|
60
65
|
const { sizeClassList } = useKitSize(props);
|
|
66
|
+
const { stateClassList } = useKitState(props);
|
|
61
67
|
|
|
62
68
|
const classList = computed(() => [
|
|
63
69
|
sizeClassList.value,
|
|
70
|
+
stateClassList.value,
|
|
64
71
|
{
|
|
65
72
|
'--is-readonly': props.readonly,
|
|
66
73
|
},
|
|
67
74
|
]);
|
|
68
75
|
|
|
76
|
+
const minDateComputed = computed(() => props.minDate || undefined);
|
|
77
|
+
const maxDateComputed = computed(() => props.maxDate || undefined);
|
|
78
|
+
|
|
69
79
|
function format(date: Date | string | (Date | string)[] | null): string {
|
|
70
80
|
if (!date) return '';
|
|
71
81
|
|
|
@@ -230,5 +240,20 @@ function getDayClass(date: Date): string {
|
|
|
230
240
|
color: var(--error-red);
|
|
231
241
|
}
|
|
232
242
|
}
|
|
243
|
+
|
|
244
|
+
&.--is-disabled,
|
|
245
|
+
&.--is-readonly {
|
|
246
|
+
pointer-events: none;
|
|
247
|
+
opacity: 0.6;
|
|
248
|
+
|
|
249
|
+
:deep(.dp__input) {
|
|
250
|
+
pointer-events: none;
|
|
251
|
+
cursor: not-allowed;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
:deep(.dp--menu-wrapper) {
|
|
255
|
+
pointer-events: none;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
233
258
|
}
|
|
234
259
|
</style>
|
|
@@ -33,18 +33,9 @@
|
|
|
33
33
|
import { computed } from 'vue';
|
|
34
34
|
import BaseButton from '../BaseButton/BaseButton.vue';
|
|
35
35
|
import type { IDefaultPagesProps } from '../../types/default-pages';
|
|
36
|
-
import techWorkImage from '../../assets/tech-work.png';
|
|
37
|
-
import error404Image from '../../assets/404.png';
|
|
38
36
|
|
|
39
37
|
const props = defineProps<IDefaultPagesProps>();
|
|
40
38
|
|
|
41
|
-
const imagePath = computed(() => {
|
|
42
|
-
const images:Record<string, any> = {
|
|
43
|
-
'tech-work': techWorkImage,
|
|
44
|
-
'404': error404Image
|
|
45
|
-
};
|
|
46
|
-
return images[props.type] || '';
|
|
47
|
-
});
|
|
48
39
|
const imageContainer = computed<string[]>(()=> [
|
|
49
40
|
`base-default-pages__image-container--${props.type}`
|
|
50
41
|
])
|
|
@@ -6,16 +6,20 @@
|
|
|
6
6
|
:range="range"
|
|
7
7
|
:size="size"
|
|
8
8
|
:min-date="minDate"
|
|
9
|
+
:max-date="maxDate"
|
|
9
10
|
:id="id"
|
|
11
|
+
:disabled="disabled"
|
|
12
|
+
:readonly="readonly"
|
|
10
13
|
>
|
|
11
14
|
<base-input
|
|
12
15
|
v-bind="{ ...$props }"
|
|
13
16
|
:model-value="formattedValue"
|
|
17
|
+
:disabled="disabled"
|
|
14
18
|
@update:model-value="handleInputUpdate"
|
|
15
19
|
>
|
|
16
|
-
<template #
|
|
20
|
+
<template #left-icon>
|
|
17
21
|
<base-icon
|
|
18
|
-
name="calendar"
|
|
22
|
+
name="calendar-icon"
|
|
19
23
|
:size="size"
|
|
20
24
|
class="base-input-calendar__icon"
|
|
21
25
|
/>
|
|
@@ -30,6 +34,7 @@
|
|
|
30
34
|
import { computed, ref, watch } from 'vue';
|
|
31
35
|
import BaseInput from '../BaseInput/BaseInput.vue';
|
|
32
36
|
import BaseCalendar from '../BaseCalendar/BaseCalendar.vue';
|
|
37
|
+
import BaseIcon from '../BaseIcon/BaseIcon.vue';
|
|
33
38
|
import type { DateRange, TCoreInputCalendarProps } from '../../types/calendar';
|
|
34
39
|
|
|
35
40
|
const props = withDefaults(defineProps<TCoreInputCalendarProps>(), {
|
|
@@ -39,6 +44,8 @@ const props = withDefaults(defineProps<TCoreInputCalendarProps>(), {
|
|
|
39
44
|
placeholder: '',
|
|
40
45
|
range: false,
|
|
41
46
|
minDate: null,
|
|
47
|
+
maxDate: null,
|
|
48
|
+
disabled: false,
|
|
42
49
|
});
|
|
43
50
|
|
|
44
51
|
const emit = defineEmits<{
|
|
@@ -50,8 +57,18 @@ const inputValue = ref<string>('');
|
|
|
50
57
|
|
|
51
58
|
watch(
|
|
52
59
|
() => props.modelValue,
|
|
53
|
-
(newValue) => {
|
|
54
|
-
|
|
60
|
+
(newValue: string | DateRange | undefined) => {
|
|
61
|
+
if (typeof newValue === 'string') {
|
|
62
|
+
inputValue.value = newValue;
|
|
63
|
+
} else if (newValue instanceof Date) {
|
|
64
|
+
const formatted = formatDateRange(newValue);
|
|
65
|
+
inputValue.value = formatted;
|
|
66
|
+
} else if (Array.isArray(newValue) && newValue.length === 2) {
|
|
67
|
+
const formatted = formatDateRange(newValue);
|
|
68
|
+
inputValue.value = formatted;
|
|
69
|
+
} else {
|
|
70
|
+
inputValue.value = '';
|
|
71
|
+
}
|
|
55
72
|
},
|
|
56
73
|
{ immediate: true },
|
|
57
74
|
);
|
|
@@ -144,9 +161,23 @@ function formatDateRange(value: DateRange | (string | Date)[]): string {
|
|
|
144
161
|
|
|
145
162
|
const calendarModelValue = computed<DateRange>({
|
|
146
163
|
get: () => {
|
|
147
|
-
|
|
164
|
+
const value = props.modelValue;
|
|
165
|
+
if (typeof value === 'string') {
|
|
166
|
+
return parseDateString(value);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (value instanceof Date) {
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
if (Array.isArray(value) && value.length === 2) {
|
|
173
|
+
return value as [Date, Date];
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
148
176
|
},
|
|
149
177
|
set: (value: DateRange) => {
|
|
178
|
+
if (props.disabled || props.readonly) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
150
181
|
const formatted = formatDateRange(value);
|
|
151
182
|
inputValue.value = formatted;
|
|
152
183
|
emit('update:modelValue', formatted);
|
|
@@ -158,6 +189,10 @@ const formattedValue = computed<string>(() => {
|
|
|
158
189
|
});
|
|
159
190
|
|
|
160
191
|
function handleInputUpdate(value: string) {
|
|
192
|
+
if (props.disabled || props.readonly) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
161
196
|
let filteredValue = value.replace(/[^0-9.\s-]/g, '');
|
|
162
197
|
|
|
163
198
|
if (props.range) {
|
|
@@ -39,33 +39,44 @@ import { useKitState } from '../../composables/kit/state';
|
|
|
39
39
|
import { useKitSize } from '../../composables/kit/size';
|
|
40
40
|
import type { ICoreInputProps, IOptionsCurrency } from '../../types/input';
|
|
41
41
|
|
|
42
|
-
const props = withDefaults(defineProps<ICoreInputProps
|
|
42
|
+
const props = withDefaults(defineProps<ICoreInputProps & {
|
|
43
|
+
options?: IOptionsCurrency[];
|
|
44
|
+
}>(), {
|
|
43
45
|
size: 'medium',
|
|
44
46
|
type: 'text',
|
|
45
47
|
modelValue: '',
|
|
46
48
|
placeholder: '0.00',
|
|
47
49
|
error: '',
|
|
50
|
+
options: undefined,
|
|
48
51
|
});
|
|
49
52
|
|
|
50
53
|
const emit: (event: 'update:modelValue', value: string) => void = defineEmits();
|
|
51
54
|
|
|
52
|
-
const
|
|
55
|
+
const defaultOptions: IOptionsCurrency[] = [
|
|
53
56
|
{ id: '1', name: 'KZT', value: 'KZT', mask: '# ##0.##', symbol: '₸' },
|
|
54
57
|
{ id: '2', name: 'RUB', value: 'RUB', mask: '# ##0.##', symbol: '₽' },
|
|
55
58
|
{ id: '3', name: 'KGS', value: 'KGS', mask: '# ##0.##', symbol: '⃀' },
|
|
56
59
|
{ id: '4', name: 'UZS', value: 'UZS', mask: '# ##0.##', symbol: 'сў' },
|
|
57
|
-
]
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const optionsCurrency = computed<IOptionsCurrency[]>(() => {
|
|
63
|
+
return props.options || defaultOptions;
|
|
64
|
+
});
|
|
58
65
|
|
|
59
|
-
const selectedOption =
|
|
66
|
+
const selectedOption = computed<IOptionsCurrency>(() => {
|
|
67
|
+
const option = optionsCurrency.value.find(opt => opt.id === selectedOptionId.value);
|
|
68
|
+
return option || optionsCurrency.value[0];
|
|
69
|
+
});
|
|
60
70
|
|
|
61
|
-
const selectedOptionId = ref<IOptionsCurrency['id']>(
|
|
71
|
+
const selectedOptionId = ref<IOptionsCurrency['id']>(optionsCurrency.value[0]?.id || '');
|
|
62
72
|
|
|
63
|
-
watch(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
watch(optionsCurrency, (newOptions) => {
|
|
74
|
+
if (newOptions.length > 0) {
|
|
75
|
+
if (!newOptions.find(opt => opt.id === selectedOptionId.value)) {
|
|
76
|
+
selectedOptionId.value = newOptions[0].id;
|
|
77
|
+
}
|
|
67
78
|
}
|
|
68
|
-
});
|
|
79
|
+
}, { immediate: true });
|
|
69
80
|
|
|
70
81
|
const { stateClassList, stateAttrs } = useKitState(props);
|
|
71
82
|
const { sizeClassList } = useKitSize(props);
|