plugin-ui-for-kzt 0.0.38 → 0.0.41
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/BaseCalendar/BaseCalendar.vue.d.ts +1 -1
- package/dist/components/BaseInputCalendar/BaseInputCalendar.vue.d.ts +1 -1
- package/dist/components/BaseSelect/BaseSelect.vue.d.ts +3 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/BaseField/BaseField.vue +0 -1
- package/src/components/BaseSelect/BaseSelect.vue +145 -137
- package/src/components/BaseSelect/README.md +9 -0
package/package.json
CHANGED
|
@@ -2,86 +2,86 @@
|
|
|
2
2
|
<div class="base-select" :class="[classList]">
|
|
3
3
|
<div class="base-select__wrapper">
|
|
4
4
|
<base-dropdown
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
v-model="dropdownVisible"
|
|
6
|
+
transition-name="top"
|
|
7
|
+
auto-close
|
|
8
|
+
:disabled="actualDisabled"
|
|
9
9
|
>
|
|
10
10
|
<template #top>
|
|
11
11
|
<div
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
v-if="!searchable"
|
|
13
|
+
:data-error="Boolean(error)"
|
|
14
|
+
:data-disabled="disabled"
|
|
15
|
+
class="base-select__header"
|
|
16
16
|
>
|
|
17
17
|
<slot
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
name="header"
|
|
19
|
+
:value="actualOption ? [actualOption] : undefined"
|
|
20
20
|
>
|
|
21
|
-
<div
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
<div
|
|
22
|
+
v-if="actualOption?.icon && $slots.iconItem"
|
|
23
|
+
class="base-select__header_prefix_icon"
|
|
24
24
|
>
|
|
25
|
-
<slot name="iconItem" :item="actualOption"
|
|
25
|
+
<slot name="iconItem" :item="actualOption"/>
|
|
26
26
|
</div>
|
|
27
|
-
<div
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
<div
|
|
28
|
+
v-else-if="$slots.headerIcon"
|
|
29
|
+
class="base-select__header_prefix_icon"
|
|
30
30
|
>
|
|
31
|
-
<slot name="headerIcon"
|
|
31
|
+
<slot name="headerIcon"/>
|
|
32
32
|
</div>
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
<div v-if="actualOption" class="base-select__header_value">
|
|
35
|
+
{{ actualOption.name }}
|
|
36
|
+
</div>
|
|
37
37
|
|
|
38
38
|
<div
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
v-else
|
|
40
|
+
class="base-select__placeholder"
|
|
41
41
|
>
|
|
42
42
|
{{ placeholder }}
|
|
43
43
|
</div>
|
|
44
44
|
</slot>
|
|
45
45
|
|
|
46
46
|
<div
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
v-if="!readonly"
|
|
48
|
+
class="base-select__arrow-wrapper"
|
|
49
49
|
>
|
|
50
50
|
<div class="base-select__arrow">
|
|
51
51
|
<base-icon
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
name="arrow-down"
|
|
53
|
+
:size="size"
|
|
54
54
|
/>
|
|
55
55
|
</div>
|
|
56
56
|
</div>
|
|
57
57
|
</div>
|
|
58
58
|
|
|
59
59
|
<BaseInput
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
v-else
|
|
61
|
+
:id="id"
|
|
62
|
+
:model-value="displayValue || ''"
|
|
63
|
+
:placeholder="placeholder"
|
|
64
|
+
:disabled="disabled"
|
|
65
|
+
:readonly="readonly"
|
|
66
|
+
:size="size"
|
|
67
|
+
:error="Boolean(error)"
|
|
68
|
+
class="base-select__input"
|
|
69
|
+
@input="handleInputChange"
|
|
70
70
|
>
|
|
71
71
|
<template #left-icon>
|
|
72
72
|
<base-icon
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
name="search"
|
|
74
|
+
:size="size"
|
|
75
75
|
/>
|
|
76
76
|
</template>
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
<template #right-icon>
|
|
79
79
|
<base-icon
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
v-if="!readonly"
|
|
81
|
+
:name="actualOption ? 'close' : 'arrow-down'"
|
|
82
|
+
:size="size"
|
|
83
|
+
class="base-select__toggle-icon"
|
|
84
|
+
@click="handleIconClick"
|
|
85
85
|
/>
|
|
86
86
|
</template>
|
|
87
87
|
</BaseInput>
|
|
@@ -89,34 +89,34 @@
|
|
|
89
89
|
|
|
90
90
|
<template #dropdown>
|
|
91
91
|
<div
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
>
|
|
92
|
+
v-if="(filteredOptions ?? []).length"
|
|
93
|
+
class="base-select__dropdown"
|
|
94
|
+
>
|
|
95
95
|
<dynamic-scroller
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
:items="filteredOptions as ICoreSelectBaseProps[]"
|
|
97
|
+
:min-item-size="36"
|
|
98
|
+
key-field="id"
|
|
99
|
+
class="base-select__list"
|
|
100
100
|
>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
<template #default="{ item, index, active } : ISelectSlotProps">
|
|
102
|
+
<dynamic-scroller-item
|
|
103
|
+
:item="item"
|
|
104
|
+
:active="active"
|
|
105
|
+
:size-dependencies="[item.name]"
|
|
106
|
+
:data-index="index"
|
|
107
107
|
>
|
|
108
108
|
<div class="base-select__item-wrapper">
|
|
109
109
|
<base-opened-list-item
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
v-bind="listItemAttrs(item)"
|
|
111
|
+
:key="String(item.id ?? '')"
|
|
112
|
+
:size="size"
|
|
113
113
|
>
|
|
114
114
|
<template #icon>
|
|
115
115
|
<div v-if="$slots.iconItem">
|
|
116
|
-
<slot name="iconItem" :item="item"
|
|
116
|
+
<slot name="iconItem" :item="item"/>
|
|
117
117
|
</div>
|
|
118
118
|
</template>
|
|
119
|
-
{{ listItemAttrs(item).title }}
|
|
119
|
+
{{ listItemAttrs( item ).title }}
|
|
120
120
|
</base-opened-list-item>
|
|
121
121
|
</div>
|
|
122
122
|
</dynamic-scroller-item>
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
</dynamic-scroller>
|
|
125
125
|
</div>
|
|
126
126
|
<div class="base-select__empty">
|
|
127
|
-
<slot name="empty"
|
|
127
|
+
<slot name="empty"/>
|
|
128
128
|
</div>
|
|
129
129
|
</template>
|
|
130
130
|
</base-dropdown>
|
|
@@ -145,138 +145,145 @@ import { useKitSize } from '../../composables/kit/size';
|
|
|
145
145
|
import { useKitState } from '../../composables/kit/state';
|
|
146
146
|
import { useKitStyle } from '../../composables/kit/style';
|
|
147
147
|
|
|
148
|
-
const props = withDefaults(defineProps<ICoreSelectProps & {
|
|
148
|
+
const props = withDefaults( defineProps<ICoreSelectProps & {
|
|
149
149
|
modelValue?: TSelectValue
|
|
150
150
|
}>(), {
|
|
151
151
|
options: () => [],
|
|
152
152
|
size: 'medium',
|
|
153
153
|
searchable: false,
|
|
154
|
-
});
|
|
154
|
+
} );
|
|
155
155
|
|
|
156
156
|
const emit = defineEmits<{
|
|
157
|
-
(e: 'update:modelValue', value: TSelectValue): void
|
|
158
|
-
(e: 'change', value: TSelectValue): void
|
|
159
|
-
(e: 'error'): void
|
|
160
|
-
(e: 'search', query: string): void
|
|
161
|
-
(e: 'open'): void
|
|
162
|
-
(e: 'clear'): void
|
|
157
|
+
( e: 'update:modelValue', value: TSelectValue ): void
|
|
158
|
+
( e: 'change', value: TSelectValue ): void
|
|
159
|
+
( e: 'error' ): void
|
|
160
|
+
( e: 'search', query: string ): void
|
|
161
|
+
( e: 'open' ): void
|
|
162
|
+
( e: 'clear' ): void
|
|
163
|
+
( e: 'getSearchApi', value: string ): void
|
|
163
164
|
}>();
|
|
164
165
|
|
|
165
|
-
const actualValue = ref<TSelectValue>(props.modelValue ?? '');
|
|
166
|
-
const searchQuery = ref<string>('');
|
|
167
|
-
const actualOption = computed(() =>
|
|
168
|
-
|
|
166
|
+
const actualValue = ref<TSelectValue>( props.modelValue ?? '' );
|
|
167
|
+
const searchQuery = ref<string>( '' );
|
|
168
|
+
const actualOption = computed( () =>
|
|
169
|
+
props.options?.find( ( item: ICoreSelectOption ) => item?.id === actualValue.value ) || null
|
|
169
170
|
);
|
|
170
171
|
|
|
171
|
-
const displayValue = computed(() => {
|
|
172
|
-
if (actualOption.value) {
|
|
172
|
+
const displayValue = computed( () => {
|
|
173
|
+
if ( actualOption.value ) {
|
|
173
174
|
return actualOption.value.name;
|
|
174
175
|
}
|
|
175
176
|
return searchQuery.value;
|
|
176
|
-
});
|
|
177
|
+
} );
|
|
177
178
|
|
|
178
|
-
watch(() => props.modelValue, (val) => {
|
|
179
|
-
if (val && typeof val === 'object' && 'id' in val) {
|
|
179
|
+
watch( () => props.modelValue, ( val ) => {
|
|
180
|
+
if ( val && typeof val === 'object' && 'id' in val ) {
|
|
180
181
|
actualValue.value = (val as ICoreSelectOption).id as TSelectValue;
|
|
181
182
|
} else {
|
|
182
183
|
actualValue.value = val ?? '';
|
|
183
184
|
}
|
|
184
|
-
}, { immediate: true });
|
|
185
|
+
}, { immediate: true } );
|
|
185
186
|
|
|
186
|
-
function handleInput(value: TSelectValue) {
|
|
187
|
-
if (props.readonly || props.disabled) {
|
|
187
|
+
function handleInput( value: TSelectValue ) {
|
|
188
|
+
if ( props.readonly || props.disabled ) {
|
|
188
189
|
return;
|
|
189
190
|
}
|
|
190
191
|
actualValue.value = value;
|
|
191
|
-
emit('update:modelValue', value);
|
|
192
|
-
emit('change', value);
|
|
192
|
+
emit( 'update:modelValue', value );
|
|
193
|
+
emit( 'change', value );
|
|
193
194
|
dropdownVisible.value = false;
|
|
194
195
|
searchQuery.value = '';
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
function handleInputChange(event: Event) {
|
|
198
|
-
if (props.readonly || props.disabled) {
|
|
198
|
+
function handleInputChange( event: Event ) {
|
|
199
|
+
if ( props.readonly || props.disabled ) {
|
|
199
200
|
return;
|
|
200
201
|
}
|
|
201
202
|
const target = event.target as HTMLInputElement;
|
|
202
203
|
const inputValue = target.value;
|
|
203
204
|
searchQuery.value = inputValue;
|
|
204
205
|
|
|
205
|
-
emit('search', inputValue);
|
|
206
|
-
|
|
207
|
-
if (inputValue) {
|
|
208
|
-
const exactMatch = props.options?.find((option: ICoreSelectOption) =>
|
|
209
|
-
|
|
206
|
+
emit( 'search', inputValue );
|
|
207
|
+
|
|
208
|
+
if ( inputValue ) {
|
|
209
|
+
const exactMatch = props.options?.find( ( option: ICoreSelectOption ) =>
|
|
210
|
+
option.name.toLowerCase() === inputValue.toLowerCase()
|
|
210
211
|
);
|
|
211
|
-
|
|
212
|
-
if (exactMatch) {
|
|
213
|
-
handleInput(exactMatch.id);
|
|
212
|
+
|
|
213
|
+
if ( exactMatch ) {
|
|
214
|
+
handleInput( exactMatch.id );
|
|
214
215
|
return;
|
|
215
216
|
}
|
|
216
|
-
|
|
217
|
-
if (!dropdownVisible.value) {
|
|
217
|
+
|
|
218
|
+
if ( !dropdownVisible.value ) {
|
|
218
219
|
dropdownVisible.value = true;
|
|
219
220
|
}
|
|
220
221
|
}
|
|
221
222
|
}
|
|
222
223
|
|
|
223
|
-
function handleIconClick(event: Event) {
|
|
224
|
-
if (props.readonly || props.disabled) {
|
|
224
|
+
function handleIconClick( event: Event ) {
|
|
225
|
+
if ( props.readonly || props.disabled ) {
|
|
225
226
|
return;
|
|
226
227
|
}
|
|
227
228
|
event.stopPropagation();
|
|
228
|
-
if (actualOption.value) {
|
|
229
|
-
handleInput('');
|
|
230
|
-
emit('clear');
|
|
229
|
+
if ( actualOption.value ) {
|
|
230
|
+
handleInput( '' );
|
|
231
|
+
emit( 'clear' );
|
|
231
232
|
} else {
|
|
232
233
|
dropdownVisible.value = !dropdownVisible.value;
|
|
233
234
|
}
|
|
234
235
|
}
|
|
235
236
|
|
|
236
|
-
const actualDisabled = computed(() => props.disabled || !props.options?.length);
|
|
237
|
-
const dropdownVisible = ref(false);
|
|
237
|
+
const actualDisabled = computed( () => props.disabled || !props.options?.length );
|
|
238
|
+
const dropdownVisible = ref( false );
|
|
238
239
|
|
|
239
|
-
const filteredOptions = computed(() => {
|
|
240
|
-
if (!props.searchable || !searchQuery.value.trim()) {
|
|
240
|
+
const filteredOptions = computed( () => {
|
|
241
|
+
if ( !props.searchable || !searchQuery.value.trim() ) {
|
|
241
242
|
return props.options || [];
|
|
242
243
|
}
|
|
243
|
-
|
|
244
|
+
|
|
244
245
|
const query = searchQuery.value.toLowerCase().trim();
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
246
|
+
const searchableOptions = (props.options || []).filter( ( option: ICoreSelectOption ) =>
|
|
247
|
+
option.name.toLowerCase().includes( query ) );
|
|
248
|
+
if ( searchableOptions.length ) {
|
|
249
|
+
return searchableOptions
|
|
250
|
+
} else {
|
|
251
|
+
emit( 'getSearchApi', query )
|
|
252
|
+
return [];
|
|
253
|
+
}
|
|
254
|
+
;
|
|
255
|
+
} );
|
|
256
|
+
|
|
257
|
+
watch( () => props.error, ( error ) => {
|
|
258
|
+
console.log( 'ERROR', error );
|
|
259
|
+
} );
|
|
260
|
+
|
|
261
|
+
watch( dropdownVisible, ( isVisible ) => {
|
|
262
|
+
if ( isVisible ) {
|
|
263
|
+
emit( 'open' );
|
|
257
264
|
}
|
|
258
|
-
if (!isVisible) {
|
|
259
|
-
if (searchQuery.value && !actualOption.value) {
|
|
260
|
-
emit('error');
|
|
265
|
+
if ( !isVisible ) {
|
|
266
|
+
if ( searchQuery.value && !actualOption.value ) {
|
|
267
|
+
emit( 'error' );
|
|
261
268
|
}
|
|
262
269
|
searchQuery.value = '';
|
|
263
270
|
}
|
|
264
|
-
});
|
|
265
|
-
const { sizeClassList } = useKitSize(props);
|
|
266
|
-
const { stateClassList } = useKitState(props);
|
|
267
|
-
const { styleClassList } = useKitStyle(props);
|
|
271
|
+
} );
|
|
272
|
+
const { sizeClassList } = useKitSize( props );
|
|
273
|
+
const { stateClassList } = useKitState( props );
|
|
274
|
+
const { styleClassList } = useKitStyle( props );
|
|
268
275
|
|
|
269
|
-
const listItemAttrs = computed(() => (item: ICoreSelectOption) => ({
|
|
276
|
+
const listItemAttrs = computed( () => ( item: ICoreSelectOption ) => ({
|
|
270
277
|
icon: item.icon,
|
|
271
278
|
active: actualValue.value === item.id,
|
|
272
279
|
title: item.name || '',
|
|
273
280
|
style: item.style,
|
|
274
281
|
disabled: item.disabled,
|
|
275
282
|
class: 'base-select__item',
|
|
276
|
-
onClick: () => handleInput(item.id),
|
|
277
|
-
}));
|
|
283
|
+
onClick: () => handleInput( item.id ),
|
|
284
|
+
}) );
|
|
278
285
|
|
|
279
|
-
const classList = computed(() => [
|
|
286
|
+
const classList = computed( () => [
|
|
280
287
|
sizeClassList.value,
|
|
281
288
|
stateClassList.value,
|
|
282
289
|
styleClassList.value,
|
|
@@ -284,12 +291,12 @@ const classList = computed(() => [
|
|
|
284
291
|
'--is-readonly': props.readonly,
|
|
285
292
|
'--is-disabled': actualDisabled.value,
|
|
286
293
|
},
|
|
287
|
-
]);
|
|
294
|
+
] );
|
|
288
295
|
|
|
289
296
|
defineSlots<{
|
|
290
|
-
default(props: ISelectSlotProps): any;
|
|
291
|
-
iconItem(props: { item: ICoreSelectOption }): any;
|
|
292
|
-
header(props: { value: ICoreSelectProps['options'] }): any;
|
|
297
|
+
default( props: ISelectSlotProps ): any;
|
|
298
|
+
iconItem( props: { item: ICoreSelectOption } ): any;
|
|
299
|
+
header( props: { value: ICoreSelectProps['options'] } ): any;
|
|
293
300
|
headerIcon(): any;
|
|
294
301
|
empty(): any;
|
|
295
302
|
}>();
|
|
@@ -304,6 +311,7 @@ defineSlots<{
|
|
|
304
311
|
|
|
305
312
|
min-width: 320px;
|
|
306
313
|
height: 100%;
|
|
314
|
+
|
|
307
315
|
.dropdown {
|
|
308
316
|
&.--is-opened {
|
|
309
317
|
#{$select} {
|
|
@@ -363,7 +371,7 @@ defineSlots<{
|
|
|
363
371
|
|
|
364
372
|
&__header_value {
|
|
365
373
|
color: var(--primary-text-primary);
|
|
366
|
-
|
|
374
|
+
|
|
367
375
|
@include text-clamp(1);
|
|
368
376
|
}
|
|
369
377
|
|
|
@@ -400,7 +408,7 @@ defineSlots<{
|
|
|
400
408
|
&__toggle-icon {
|
|
401
409
|
cursor: pointer;
|
|
402
410
|
transition: transform var(--transition);
|
|
403
|
-
|
|
411
|
+
|
|
404
412
|
&:hover {
|
|
405
413
|
opacity: 0.7;
|
|
406
414
|
}
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
@open="handleEmployeeOpen"
|
|
38
38
|
@clear="handleEmployeeClear"
|
|
39
39
|
@error="handleSearchError"
|
|
40
|
+
@getSearchApi="handleGetNewOptions"
|
|
40
41
|
/>
|
|
41
42
|
</template>
|
|
42
43
|
|
|
@@ -94,6 +95,11 @@ const handleEmployeeSearch = (query) => {
|
|
|
94
95
|
}, 700) // Дебаунс 700мс
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
// Логика для запроса
|
|
99
|
+
const handleGetNewOptions = (query) => {
|
|
100
|
+
fetchEmployees()
|
|
101
|
+
}
|
|
102
|
+
|
|
97
103
|
// Загрузка при открытии если данных нет
|
|
98
104
|
const handleEmployeeOpen = () => {
|
|
99
105
|
if (employeeOptions.value.length === 0) {
|
|
@@ -180,6 +186,9 @@ const handleSearchError = () => {
|
|
|
180
186
|
- `error`
|
|
181
187
|
Эмитится когда пользователь вводит текст, но не выбирает ни одну опцию из списка. Полезно для валидации поиска.
|
|
182
188
|
|
|
189
|
+
- `getSearchApi`
|
|
190
|
+
Эмитится когда ничего не найден в options, чтобы сделать запрос для новых options
|
|
191
|
+
|
|
183
192
|
---
|
|
184
193
|
|
|
185
194
|
### 🧩 Слоты
|