plugin-ui-for-kzt 0.0.28 → 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.
Files changed (33) hide show
  1. package/dist/components/BaseBadge/BaseBadge.vue.d.ts +2 -2
  2. package/dist/components/BaseButton/BaseButton.vue.d.ts +1 -1
  3. package/dist/components/BaseCheckbox/BaseCheckbox.vue.d.ts +2 -2
  4. package/dist/components/BaseDropdown/BaseDropdown.vue.d.ts +1 -1
  5. package/dist/components/BaseInput/BaseInput.vue.d.ts +4 -4
  6. package/dist/components/BaseInputCalendar/BaseInputCalendar.vue.d.ts +3 -3
  7. package/dist/components/BaseInputCurrency/BaseInputCurrency.vue.d.ts +4 -4
  8. package/dist/components/BaseInputEmail/BaseInputEmail.vue.d.ts +3 -3
  9. package/dist/components/BaseInputPhone/BaseInputPhone.vue.d.ts +3 -3
  10. package/dist/components/BasePagination/BasePagination.vue.d.ts +1 -1
  11. package/dist/components/BaseRadio/BaseRadio.vue.d.ts +2 -2
  12. package/dist/components/BaseSegmentedButtons/BaseSegmentedButtons.vue.d.ts +1 -1
  13. package/dist/components/BaseSelect/BaseSelect.vue.d.ts +14 -4
  14. package/dist/components/BaseTable/BaseTable.vue.d.ts +14 -1
  15. package/dist/components/BaseTag/BaseTag.vue.d.ts +1 -1
  16. package/dist/components/BaseTextarea/BaseTextarea.vue.d.ts +3 -3
  17. package/dist/components/BaseToast/BaseToast.vue.d.ts +1 -1
  18. package/dist/components/BaseToggle/BaseToggle.vue.d.ts +2 -2
  19. package/dist/components/BaseTooltip/BaseTooltip.vue.d.ts +2 -2
  20. package/dist/index.js +1 -1
  21. package/dist/sprite.svg +1 -1
  22. package/example/App.vue +270 -6
  23. package/package.json +1 -1
  24. package/src/assets/icons/search.svg +4 -0
  25. package/src/components/BaseButton/BaseButton.vue +20 -20
  26. package/src/components/BaseSelect/BaseSelect.vue +155 -10
  27. package/src/components/BaseTable/BaseTable.vue +278 -26
  28. package/src/components/BaseTable/README.md +96 -1
  29. package/src/components/BaseTooltip/BaseTooltip.vue +9 -5
  30. package/src/components/BaseUpload/BaseUpload.vue +97 -25
  31. package/src/types/input.d.ts +1 -0
  32. package/src/types/table.d.ts +6 -0
  33. package/src/vue-virtual-scroller.d.ts +4 -0
package/example/App.vue CHANGED
@@ -1,19 +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
+
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
+
4
153
  <section>
5
- <BaseDefaultPages
6
- title="TUIELT"
7
- description="DEGASG"
8
- buttonText="Butootn"
9
- type="tech-work"
10
- />
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
+ />
11
174
  </section>
12
175
  </div>
13
176
  </template>
14
177
  <script setup lang="ts">
15
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
+ ])
16
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
+ }
17
281
  </script>
18
282
 
19
283
  <style lang="scss" scoped>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plugin-ui-for-kzt",
3
- "version": "0.0.28",
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>
@@ -114,17 +114,17 @@ const classList = computed(() => [
114
114
  font: var(--typography-text-s-medium);
115
115
  border-radius: var(--corner-radius-xs);
116
116
 
117
- #{$button}--only-icon {
118
- padding: 0;
119
- width: 32px;
120
- }
121
-
122
117
  .loader__circle-icon {
123
118
  width: 20px;
124
119
  height: 20px;
125
120
  }
126
121
  }
127
122
 
123
+ &.--extra-small-size#{&}--only-icon {
124
+ padding: 0;
125
+ width: 32px;
126
+ }
127
+
128
128
  &.--small-size {
129
129
  column-gap: var(--spacing-xs);
130
130
  height: 40px;
@@ -132,17 +132,17 @@ const classList = computed(() => [
132
132
  font: var(--typography-text-m-medium);
133
133
  border-radius: var(--corner-radius-s);
134
134
 
135
- #{$button}--only-icon {
136
- padding: 0;
137
- width: 40px;
138
- }
139
-
140
135
  .loader__circle-icon {
141
136
  width: 20px;
142
137
  height: 20px;
143
138
  }
144
139
  }
145
140
 
141
+ &.--small-size#{&}--only-icon {
142
+ padding: 0;
143
+ width: 40px;
144
+ }
145
+
146
146
  &.--medium-size {
147
147
  column-gap: var(--spacing-xs);
148
148
  height: 48px;
@@ -150,17 +150,17 @@ const classList = computed(() => [
150
150
  font: var(--typography-text-l-medium);
151
151
  border-radius: var(--corner-radius-m);
152
152
 
153
- #{$button}--only-icon {
154
- padding: 0;
155
- width: 48px;
156
- }
157
-
158
153
  .loader__circle-icon {
159
154
  width: 24px;
160
155
  height: 24px;
161
156
  }
162
157
  }
163
158
 
159
+ &.--medium-size#{&}--only-icon {
160
+ padding: 0;
161
+ width: 48px;
162
+ }
163
+
164
164
  &.--large-size {
165
165
  column-gap: var(--spacing-xs);
166
166
  height: 56px;
@@ -168,17 +168,17 @@ const classList = computed(() => [
168
168
  font: var(--typography-text-l-medium);
169
169
  border-radius: var(--corner-radius-m);
170
170
 
171
- #{$button}--only-icon {
172
- padding: 0;
173
- width: 56px;
174
- }
175
-
176
171
  .loader__circle-icon {
177
172
  width: 32px;
178
173
  height: 32px;
179
174
  }
180
175
  }
181
176
 
177
+ &.--large-size#{&}--only-icon {
178
+ padding: 0;
179
+ width: 56px;
180
+ }
181
+
182
182
  &.--is-interactive {
183
183
  height: 22px;
184
184
  padding: 0;
@@ -8,7 +8,9 @@
8
8
  :disabled="actualDisabled"
9
9
  >
10
10
  <template #top>
11
+ <!-- Старый header для дефолтного поведения -->
11
12
  <div
13
+ v-if="!searchable"
12
14
  :data-error="Boolean(error)"
13
15
  :data-disabled="disabled"
14
16
  class="base-select__header"
@@ -21,12 +23,9 @@
21
23
  <slot name="headerIcon" />
22
24
  </div>
23
25
 
24
- <div
25
- v-if="actualOption"
26
- class="base-select__header_value"
27
- >
28
- {{ actualOption.name }}
29
- </div>
26
+ <div v-if="actualOption" class="base-select__header_value">
27
+ {{ actualOption.name }}
28
+ </div>
30
29
 
31
30
  <div
32
31
  v-else
@@ -48,15 +47,45 @@
48
47
  </div>
49
48
  </div>
50
49
  </div>
50
+
51
+ <BaseInput
52
+ v-else
53
+ :id="id"
54
+ :model-value="displayValue || ''"
55
+ :placeholder="placeholder"
56
+ :disabled="disabled"
57
+ :readonly="readonly"
58
+ :size="size"
59
+ :error="Boolean(error)"
60
+ class="base-select__input"
61
+ @input="handleInputChange"
62
+ >
63
+ <template #left-icon>
64
+ <base-icon
65
+ name="search"
66
+ :size="size"
67
+ />
68
+ </template>
69
+
70
+ <template #right-icon>
71
+ <base-icon
72
+ v-if="!readonly"
73
+ :name="actualOption ? 'close' : 'arrow-down'"
74
+ :size="size"
75
+ class="base-select__toggle-icon"
76
+ @click="handleIconClick"
77
+ />
78
+ </template>
79
+ </BaseInput>
51
80
  </template>
52
81
 
53
82
  <template #dropdown>
54
83
  <div
55
- v-if="(options ?? []).length"
84
+ v-if="(filteredOptions ?? []).length"
56
85
  class="base-select__dropdown"
57
- >
86
+ >
58
87
  <dynamic-scroller
59
- :items="options as ICoreSelectBaseProps[]"
88
+ :items="filteredOptions as ICoreSelectBaseProps[]"
60
89
  :min-item-size="36"
61
90
  key-field="id"
62
91
  class="base-select__list"
@@ -86,6 +115,9 @@
86
115
  </template>
87
116
  </dynamic-scroller>
88
117
  </div>
118
+ <div class="base-select__empty">
119
+ <slot name="empty" />
120
+ </div>
89
121
  </template>
90
122
  </base-dropdown>
91
123
  </div>
@@ -99,6 +131,7 @@ import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller';
99
131
  import type { ICoreSelectProps, TSelectValue, ICoreSelectBaseProps, ICoreSelectOption, ISelectSlotProps } from '../../types/input';
100
132
  import BaseDropdown from '../BaseDropdown/BaseDropdown.vue';
101
133
  import BaseIcon from '../BaseIcon/BaseIcon.vue';
134
+ import BaseInput from '../BaseInput/BaseInput.vue';
102
135
  import BaseOpenedListItem from '../BaseOpenedListItem/BaseOpenedListItem.vue';
103
136
  import { useKitSize } from '../../composables/kit/size';
104
137
  import { useKitState } from '../../composables/kit/state';
@@ -109,18 +142,28 @@ const props = withDefaults(defineProps<ICoreSelectProps & {
109
142
  }>(), {
110
143
  options: () => [],
111
144
  size: 'medium',
145
+ searchable: false,
112
146
  });
113
147
 
114
148
  const emit = defineEmits<{
115
149
  (e: 'update:modelValue', value: TSelectValue): void
116
150
  (e: 'change', value: TSelectValue): void
151
+ (e: 'error'): void
117
152
  }>();
118
153
 
119
154
  const actualValue = ref<TSelectValue>(props.modelValue ?? '');
155
+ const searchQuery = ref<string>('');
120
156
  const actualOption = computed(() =>
121
157
  props.options?.find((item: ICoreSelectOption) => item?.id === actualValue.value) || null
122
158
  );
123
159
 
160
+ const displayValue = computed(() => {
161
+ if (actualOption.value) {
162
+ return actualOption.value.name;
163
+ }
164
+ return searchQuery.value;
165
+ });
166
+
124
167
  watch(() => props.modelValue, (val) => {
125
168
  actualValue.value = val ?? '';
126
169
  }, { immediate: true });
@@ -129,10 +172,66 @@ function handleInput(value: TSelectValue) {
129
172
  actualValue.value = value;
130
173
  emit('update:modelValue', value);
131
174
  emit('change', value);
175
+ dropdownVisible.value = false;
176
+ searchQuery.value = '';
177
+ }
178
+
179
+ function handleInputChange(event: Event) {
180
+ const target = event.target as HTMLInputElement;
181
+ const inputValue = target.value;
182
+ searchQuery.value = inputValue;
183
+
184
+ if (inputValue) {
185
+ const exactMatch = props.options?.find((option: ICoreSelectOption) =>
186
+ option.name.toLowerCase() === inputValue.toLowerCase()
187
+ );
188
+
189
+ if (exactMatch) {
190
+ handleInput(exactMatch.id);
191
+ return;
192
+ }
193
+
194
+ if (!dropdownVisible.value) {
195
+ dropdownVisible.value = true;
196
+ }
197
+ }
198
+ }
199
+
200
+ function handleIconClick(event: Event) {
201
+ event.stopPropagation();
202
+ if (actualOption.value) {
203
+ handleInput('');
204
+ } else {
205
+ dropdownVisible.value = !dropdownVisible.value;
206
+ }
132
207
  }
133
208
 
134
209
  const actualDisabled = computed(() => props.disabled || !props.options?.length);
135
210
  const dropdownVisible = ref(false);
211
+
212
+ const filteredOptions = computed(() => {
213
+ if (!props.searchable || !searchQuery.value.trim()) {
214
+ return props.options || [];
215
+ }
216
+
217
+ const query = searchQuery.value.toLowerCase().trim();
218
+ return (props.options || []).filter((option: ICoreSelectOption) =>
219
+ option.name.toLowerCase().includes(query)
220
+ );
221
+ });
222
+
223
+ watch(() => props.error, (error) => {
224
+ console.log('ERROR', error);
225
+ });
226
+
227
+ watch(dropdownVisible, (isVisible) => {
228
+ if (!isVisible) {
229
+ if (searchQuery.value && !actualOption.value) {
230
+ emit('error');
231
+ }
232
+ searchQuery.value = '';
233
+ }
234
+ });
136
235
  const { sizeClassList } = useKitSize(props);
137
236
  const { stateClassList } = useKitState(props);
138
237
  const { styleClassList } = useKitStyle(props);
@@ -162,6 +261,7 @@ defineSlots<{
162
261
  iconItem(props: { item: ICoreSelectBaseProps }): any;
163
262
  header(props: { value: ICoreSelectProps['options'] }): any;
164
263
  headerIcon(): any;
264
+ empty(): any;
165
265
  }>();
166
266
  </script>
167
267
 
@@ -185,6 +285,10 @@ defineSlots<{
185
285
  border: 1px solid var(--primary-black-300);
186
286
  outline: 4px solid var(--effects-primary-focus);
187
287
  }
288
+
289
+ &__toggle-icon {
290
+ transform: rotate(180deg);
291
+ }
188
292
  }
189
293
 
190
294
  .dropdown__dropdown {
@@ -202,6 +306,10 @@ defineSlots<{
202
306
  #{$select}__header {
203
307
  border: 1px solid var(--error-red-light-01);
204
308
  }
309
+
310
+ #{$select}__toggle-icon {
311
+ color: var(--error-red);
312
+ }
205
313
  }
206
314
 
207
315
  &__wrapper {
@@ -225,6 +333,8 @@ defineSlots<{
225
333
 
226
334
  &__header_value {
227
335
  color: var(--primary-text-primary);
336
+
337
+ @include text-clamp(1);
228
338
  }
229
339
 
230
340
  &__placeholder {
@@ -247,6 +357,25 @@ defineSlots<{
247
357
  transform: translate3d(0, -50%, 0);
248
358
  }
249
359
 
360
+ &__input {
361
+ cursor: pointer;
362
+
363
+ @include text-clamp(1);
364
+
365
+ &.--is-readonly {
366
+ cursor: default;
367
+ }
368
+ }
369
+
370
+ &__toggle-icon {
371
+ cursor: pointer;
372
+ transition: transform var(--transition);
373
+
374
+ &:hover {
375
+ opacity: 0.7;
376
+ }
377
+ }
378
+
250
379
  &__dropdown {
251
380
  width: 100%;
252
381
  height: 100%;
@@ -266,7 +395,7 @@ defineSlots<{
266
395
  font: var(--typography-text-m-regular);
267
396
  }
268
397
 
269
- &__dropdown {
398
+ &__dropdown, &__input {
270
399
  border-radius: var(--corner-radius-s);
271
400
  }
272
401
 
@@ -289,6 +418,10 @@ defineSlots<{
289
418
  font: var(--typography-text-m-regular);
290
419
  }
291
420
 
421
+ &__input {
422
+ border-radius: var(--corner-radius-m);
423
+ }
424
+
292
425
  &__header {
293
426
  height: 48px;
294
427
  padding: var(--spacing-m) var(--spacing-2l);
@@ -307,6 +440,10 @@ defineSlots<{
307
440
  font: var(--typography-text-l-regular);
308
441
  }
309
442
 
443
+ &__input {
444
+ border-radius: var(--corner-radius-l);
445
+ }
446
+
310
447
  &__header {
311
448
  height: 56px;
312
449
  padding: var(--spacing-m) var(--spacing-l);
@@ -328,6 +465,10 @@ defineSlots<{
328
465
  &__arrow {
329
466
  color: var(--ui-colors-input-icon-disabled);
330
467
  }
468
+
469
+ &__toggle-icon {
470
+ color: var(--ui-colors-input-icon-disabled);
471
+ }
331
472
  }
332
473
  }
333
474
 
@@ -336,6 +477,10 @@ defineSlots<{
336
477
  &__header {
337
478
  pointer-events: none;
338
479
  }
480
+
481
+ &__input {
482
+ pointer-events: none;
483
+ }
339
484
  }
340
485
  }
341
486
  }