plugin-ui-for-kzt 0.0.27 → 0.0.29

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/example/App.vue CHANGED
@@ -1,18 +1,283 @@
1
1
  <template>
2
2
  <div class="demo-page">
3
3
  <h1>Plugin UI KZT - Компоненты</h1>
4
+
5
+ <section>
6
+ <h2>BaseUpload с drag & drop</h2>
7
+ <div style="display: flex; gap: 20px;">
8
+ <div style="width: 400px;">
9
+ <h3>Множественная загрузка (multiple: true)</h3>
10
+ <BaseUpload
11
+ :accepted-formats="['.pdf', '.docx', '.jpeg', '.jpg', '.png', '.svg']"
12
+ :multiple="true"
13
+ >
14
+ <template #title>
15
+ Перетащите файлы сюда или кликните для выбора
16
+ </template>
17
+ <template #description>
18
+ Поддерживаемые форматы: PDF, DOCX, JPEG, JPG, PNG, SVG до 25 MB
19
+ </template>
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
+
4
85
  <section>
5
- <base-calendar v-model="testDate" inline />
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"
173
+ />
6
174
  </section>
7
175
  </div>
8
176
  </template>
9
177
  <script setup lang="ts">
10
- import { ref, watch } from 'vue'
178
+ import { ref, watch, computed } from 'vue'
179
+ import BaseSelect from '../src/components/BaseSelect/BaseSelect.vue'
180
+ import BaseTooltip from '../src/components/BaseTooltip/BaseTooltip.vue'
181
+ import BaseUpload from '../src/components/BaseUpload/BaseUpload.vue'
182
+ import BaseTable from '../src/components/BaseTable/BaseTable.vue'
183
+
184
+ const options = ref([
185
+ { id: 1, name: ' Option 1 Option 1 Option 1Option 1 Option 1Option 1' },
186
+ { id: 2, name: 'Option 2 Option 2 Option 2Option 2 Option 2Option 2' },
187
+ { id: 3, name: 'Option 3 Option 3 Option 3Option 3 Option 3Option 3' },
188
+ ])
189
+
190
+ const searchableOptions = ref([
191
+ { id: 'kz', name: 'Казахстан Казахстан Казахстан Казахстан Казахстан Казахстан Казахстан Казахстан Казахстан' },
192
+ { id: 'ru', name: 'Россия' },
193
+ { id: 'kg', name: 'Кыргызстан' },
194
+ { id: 'uz', name: 'Узбекистан' },
195
+ { id: 'tj', name: 'Таджикистан' },
196
+ { id: 'tm', name: 'Туркменистан' },
197
+ { id: 'af', name: 'Афганистан' },
198
+ { id: 'mn', name: 'Монголия' },
199
+ { id: 'cn', name: 'Китай' },
200
+ { id: 'ir', name: 'Иран' },
201
+ { id: 'tr', name: 'Турция' },
202
+ { id: 'ge', name: 'Грузия' },
203
+ { id: 'am', name: 'Армения' },
204
+ { id: 'az', name: 'Азербайджан' },
205
+ { id: 'by', name: 'Беларусь' },
206
+ { id: 'ua', name: 'Украина' },
207
+ { id: 'md', name: 'Молдова' },
208
+ { id: 'lt', name: 'Литва' },
209
+ { id: 'lv', name: 'Латвия' },
210
+ { id: 'ee', name: 'Эстония' },
211
+ ])
212
+
213
+ const errorMessage = ref(false)
214
+
215
+ function handleSelectError() {
216
+ errorMessage.value = true
217
+ }
218
+
219
+ // Данные для таблицы
220
+ const tableColumns = ref([
221
+ { key: 'id', label: 'ID', sortable: true, width: '80px', align: 'center' as const },
222
+ { key: 'name', label: 'Имя', sortable: true, width: '200px', align: 'left' as const },
223
+ { key: 'email', label: 'Email', sortable: true, width: '1fr', align: 'left' as const },
224
+ { key: 'status', label: 'Статус', sortable: true, width: '120px', align: 'right' as const }
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
+ })
11
252
 
12
- const testDate = ref(new Date())
13
- watch(()=> testDate.value,
14
- ()=> console.log('test Date', testDate.value)
15
- )
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
+ }
16
281
  </script>
17
282
 
18
283
  <style lang="scss" scoped>
@@ -52,4 +317,11 @@ watch(()=> testDate.value,
52
317
  overflow-x: auto;
53
318
  }
54
319
  }
320
+
321
+ .table-data__cell-actions {
322
+ display: flex;
323
+ align-items: center;
324
+ gap: var(--spacing-xs);
325
+ justify-content: flex-end;
326
+ }
55
327
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plugin-ui-for-kzt",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "description": "plugin-ui for kazaktelekom",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,4 @@
1
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M15.3333 28.0001C22.3289 28.0001 28 22.329 28 15.3334C28 8.33781 22.3289 2.66675 15.3333 2.66675C8.33773 2.66675 2.66667 8.33781 2.66667 15.3334C2.66667 22.329 8.33773 28.0001 15.3333 28.0001Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M29.3333 29.3334L26.6667 26.6667" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -30,6 +30,7 @@ const props = withDefaults(defineProps<ICoreButtonProps>(), {
30
30
  tag: 'button',
31
31
  color: 'primary',
32
32
  size: 'medium',
33
+ onlyIcon: false,
33
34
  });
34
35
 
35
36
  const { componentTag, interactiveClassList } = useKitInteractive(props);
@@ -64,6 +65,7 @@ const classList = computed(() => [
64
65
  colorClassList.value,
65
66
  stateClassList.value,
66
67
  styleClassList.value,
68
+ { 'base-button--only-icon': props.onlyIcon }
67
69
  ]);
68
70
  </script>
69
71
 
@@ -72,6 +74,8 @@ const classList = computed(() => [
72
74
  @import '@/styles/root';
73
75
 
74
76
  .base-button {
77
+ $button: &;
78
+
75
79
  @include reset-button;
76
80
  @include is-disabled-state;
77
81
 
@@ -83,7 +87,12 @@ const classList = computed(() => [
83
87
  appearance: none;
84
88
  cursor: pointer;
85
89
  user-select: none;
86
- transition: all var(--transition);
90
+ transition:
91
+ background-color var(--transition),
92
+ color var(--transition),
93
+ border-color var(--transition),
94
+ box-shadow var(--transition),
95
+ opacity var(--transition);
87
96
 
88
97
 
89
98
  &.--is-loading {
@@ -111,6 +120,11 @@ const classList = computed(() => [
111
120
  }
112
121
  }
113
122
 
123
+ &.--extra-small-size#{&}--only-icon {
124
+ padding: 0;
125
+ width: 32px;
126
+ }
127
+
114
128
  &.--small-size {
115
129
  column-gap: var(--spacing-xs);
116
130
  height: 40px;
@@ -124,6 +138,11 @@ const classList = computed(() => [
124
138
  }
125
139
  }
126
140
 
141
+ &.--small-size#{&}--only-icon {
142
+ padding: 0;
143
+ width: 40px;
144
+ }
145
+
127
146
  &.--medium-size {
128
147
  column-gap: var(--spacing-xs);
129
148
  height: 48px;
@@ -137,6 +156,11 @@ const classList = computed(() => [
137
156
  }
138
157
  }
139
158
 
159
+ &.--medium-size#{&}--only-icon {
160
+ padding: 0;
161
+ width: 48px;
162
+ }
163
+
140
164
  &.--large-size {
141
165
  column-gap: var(--spacing-xs);
142
166
  height: 56px;
@@ -150,6 +174,11 @@ const classList = computed(() => [
150
174
  }
151
175
  }
152
176
 
177
+ &.--large-size#{&}--only-icon {
178
+ padding: 0;
179
+ width: 56px;
180
+ }
181
+
153
182
  &.--is-interactive {
154
183
  height: 22px;
155
184
  padding: 0;
@@ -33,10 +33,18 @@
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';
36
38
 
37
39
  const props = defineProps<IDefaultPagesProps>();
38
40
 
39
- const imagePath = computed(()=> require(`@/assets/${props.type}.png`))
41
+ const imagePath = computed(() => {
42
+ const images:Record<string, any> = {
43
+ 'tech-work': techWorkImage,
44
+ '404': error404Image
45
+ };
46
+ return images[props.type] || '';
47
+ });
40
48
  const imageContainer = computed<string[]>(()=> [
41
49
  `base-default-pages__image-container--${props.type}`
42
50
  ])