@v1nt1248/3nclient-lib 0.1.80 → 0.1.81
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/ui3n-autocomplete/types.d.ts +3 -0
- package/dist/components/ui3n-autocomplete/ui3n-autocomplete.vue.d.ts +2 -1
- package/dist/style.css +1 -1
- package/dist/ui3n-components.js +2676 -2660
- package/package.json +1 -1
- package/src/components/ui3n-autocomplete/types.ts +3 -0
- package/src/components/ui3n-autocomplete/ui3n-autocomplete.vue +35 -10
package/package.json
CHANGED
|
@@ -20,6 +20,8 @@ export interface Ui3nAutocompleteProps<T extends Ui3nAutocompleteOptionBase> {
|
|
|
20
20
|
itemTitle?: keyof T;
|
|
21
21
|
itemValue?: keyof T;
|
|
22
22
|
modelValue: T[] | Array<T[keyof T]>;
|
|
23
|
+
addNewValue?: boolean;
|
|
24
|
+
newValueValidator?: (value: string) => boolean;
|
|
23
25
|
multiple?: boolean;
|
|
24
26
|
noDataText?: string;
|
|
25
27
|
placeholder?: string;
|
|
@@ -30,6 +32,7 @@ export interface Ui3nAutocompleteEmits<T extends Ui3nAutocompleteOptionBase> {
|
|
|
30
32
|
(event: 'update:modelValue', value: T[] | Array<T[keyof T]>): void;
|
|
31
33
|
(event: 'update:search', value: string): void;
|
|
32
34
|
(event: 'update:focused', value: boolean): void;
|
|
35
|
+
(event: 'valid:new-value', value: boolean): void;
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
export interface Ui3nAutocompleteSlots<T extends Ui3nAutocompleteOptionBase> {
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
const inputEl = ref<Nullable<HTMLInputElement>>(null);
|
|
53
53
|
const menuBodyEl = ref<Nullable<HTMLDivElement>>(null);
|
|
54
54
|
const activeItemsIndex = ref<Nullable<number>>(null);
|
|
55
|
+
const isNewValueValid = ref(true);
|
|
55
56
|
|
|
56
57
|
const ids = computed(() => props.returnObject
|
|
57
58
|
? (props.modelValue as T[]).map(item => item.id)
|
|
@@ -96,7 +97,7 @@
|
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
function onBlur() {
|
|
99
|
-
emits('update:focused', false)
|
|
100
|
+
emits('update:focused', false);
|
|
100
101
|
activeItemsIndex.value = null;
|
|
101
102
|
|
|
102
103
|
setTimeout(() => {
|
|
@@ -166,7 +167,7 @@
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
function handlePressingEscOrTabKeys() {
|
|
169
|
-
emits('update:focused', false)
|
|
170
|
+
emits('update:focused', false);
|
|
170
171
|
isMenuOpen.value = false;
|
|
171
172
|
activeItemsIndex.value = null;
|
|
172
173
|
query.value = '';
|
|
@@ -175,21 +176,35 @@
|
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
function handlePressingEnterKey() {
|
|
178
|
-
if (activeItemsIndex.value === null) {
|
|
179
|
+
if (activeItemsIndex.value === null && !isMenuOpen.value) {
|
|
179
180
|
isMenuOpen.value = true;
|
|
180
181
|
activeItemsIndex.value = 0;
|
|
181
182
|
menuBodyEl.value && menuBodyEl.value.focus();
|
|
182
183
|
return;
|
|
183
184
|
}
|
|
184
185
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
if (activeItemsIndex.value === null && isMenuOpen.value && query.value) {
|
|
187
|
+
isNewValueValid.value = !props.newValueValidator ? true : props.newValueValidator(query.value);
|
|
188
|
+
emits('valid:new-value', isNewValueValid.value);
|
|
189
|
+
if (isNewValueValid.value) {
|
|
190
|
+
const item = {
|
|
191
|
+
id: getRandomId(6),
|
|
192
|
+
[props.itemTitle]: query.value,
|
|
193
|
+
[props.itemValue]: query.value,
|
|
194
|
+
};
|
|
195
|
+
onItemClick(item as unknown as T);
|
|
196
|
+
}
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (activeItemsIndex.value !== null) {
|
|
201
|
+
const item = filteredItems.value[activeItemsIndex.value!];
|
|
202
|
+
onItemClick(item);
|
|
203
|
+
activeItemsIndex.value = null;
|
|
204
|
+
}
|
|
188
205
|
}
|
|
189
206
|
|
|
190
207
|
function onKeydown(event: KeyboardEvent, key: 'down' | 'up' | 'esc' | 'enter' | 'tab') {
|
|
191
|
-
if (isEmpty(filteredItems.value)) return;
|
|
192
|
-
|
|
193
208
|
switch (key) {
|
|
194
209
|
case 'down':
|
|
195
210
|
event.preventDefault();
|
|
@@ -219,6 +234,10 @@
|
|
|
219
234
|
if (val !== oVal) {
|
|
220
235
|
activeItemsIndex.value = null;
|
|
221
236
|
}
|
|
237
|
+
|
|
238
|
+
if (val && !isNewValueValid.value) {
|
|
239
|
+
isNewValueValid.value = true;
|
|
240
|
+
}
|
|
222
241
|
},
|
|
223
242
|
);
|
|
224
243
|
</script>
|
|
@@ -249,7 +268,8 @@
|
|
|
249
268
|
ref="inputEl"
|
|
250
269
|
v-model="query"
|
|
251
270
|
type="text"
|
|
252
|
-
:class="$style.input"
|
|
271
|
+
:class="[$style.input, !isNewValueValid && $style.inputWithError]"
|
|
272
|
+
:placeholder="isEmpty(modelValue) && placeholder ? placeholder : ''"
|
|
253
273
|
:disabled="disabled"
|
|
254
274
|
@input="onInput"
|
|
255
275
|
@focusin="emits('update:focused', true)"
|
|
@@ -343,7 +363,12 @@
|
|
|
343
363
|
&:hover,
|
|
344
364
|
&:focus {
|
|
345
365
|
height: calc(var(--autocomplete-min-height) - 2px);
|
|
346
|
-
|
|
366
|
+
|
|
367
|
+
&:not(.inputWithError) {
|
|
368
|
+
border: 1px solid var(--color-border-control-accent-focused);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
border: 1px solid var(--error-content-default);
|
|
347
372
|
}
|
|
348
373
|
}
|
|
349
374
|
|