@v1nt1248/3nclient-lib 0.3.28 → 0.3.30

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 (111) hide show
  1. package/dist/chunks/ui3n-notification-Dr_3Td9N.js +279 -0
  2. package/dist/components/index.d.ts +12 -12
  3. package/dist/components/ui3n-autocomplete/types.d.ts +13 -0
  4. package/dist/components/ui3n-autocomplete/ui3n-autocomplete.d.ts +2 -2
  5. package/dist/components/ui3n-badge/types.d.ts +12 -0
  6. package/dist/components/ui3n-badge/ui3n-badge-simple.d.ts +1 -1
  7. package/dist/components/ui3n-badge/ui3n-badge.d.ts +1 -1
  8. package/dist/components/ui3n-breadcrumbs/types.d.ts +1 -1
  9. package/dist/components/ui3n-breadcrumbs/ui3n-breadcrumb.d.ts +2 -2
  10. package/dist/components/ui3n-button/types.d.ts +4 -2
  11. package/dist/components/ui3n-checkbox/types.d.ts +11 -0
  12. package/dist/components/ui3n-checkbox/ui3n-checkbox.d.ts +4 -1
  13. package/dist/components/ui3n-chip/types.d.ts +6 -1
  14. package/dist/components/ui3n-chip/ui3n-chip.d.ts +2 -0
  15. package/dist/components/ui3n-drop-files/types.d.ts +7 -0
  16. package/dist/components/ui3n-drop-files/ui3n-drop-files.d.ts +7 -1
  17. package/dist/components/ui3n-editable/types.d.ts +11 -0
  18. package/dist/components/ui3n-editable/ui3n-editable.d.ts +4 -2
  19. package/dist/components/ui3n-icon/types.d.ts +5 -1
  20. package/dist/components/ui3n-icon/ui3n-icon.d.ts +2 -2
  21. package/dist/components/ui3n-input/types.d.ts +4 -0
  22. package/dist/components/ui3n-input/ui3n-input.d.ts +4 -1
  23. package/dist/components/ui3n-input-file/types.d.ts +11 -0
  24. package/dist/components/ui3n-input-file/ui3n-input-file.d.ts +4 -1
  25. package/dist/components/ui3n-list/types.d.ts +4 -0
  26. package/dist/components/ui3n-menu/types.d.ts +9 -0
  27. package/dist/components/ui3n-menu/ui3n-menu.d.ts +2 -1
  28. package/dist/components/ui3n-notification/ui3n-notification.d.ts +2 -2
  29. package/dist/components/ui3n-progress/ui3n-progress-circular.d.ts +1 -1
  30. package/dist/components/ui3n-progress/ui3n-progress-linear.d.ts +1 -1
  31. package/dist/components/ui3n-radio-group/types.d.ts +18 -0
  32. package/dist/components/ui3n-radio-group/ui3n-radio-group.d.ts +3 -1
  33. package/dist/components/ui3n-radio-group/ui3n-radio.d.ts +6 -7
  34. package/dist/components/ui3n-scrollbar-vertical/types.d.ts +2 -0
  35. package/dist/components/ui3n-scrollbar-vertical/ui3n-scrollbar-vertical.d.ts +2 -0
  36. package/dist/components/ui3n-selector/types.d.ts +11 -0
  37. package/dist/components/ui3n-selector/ui3n-selector.d.ts +2 -2
  38. package/dist/components/ui3n-slider/types.d.ts +11 -0
  39. package/dist/components/ui3n-slider/ui3n-slider.d.ts +4 -1
  40. package/dist/components/ui3n-step-line-bar/types.d.ts +4 -0
  41. package/dist/components/ui3n-switch/types.d.ts +11 -0
  42. package/dist/components/ui3n-switch/ui3n-switch.d.ts +4 -1
  43. package/dist/components/ui3n-table/composables/useTable.d.ts +1 -0
  44. package/dist/components/ui3n-table/types.d.ts +4 -0
  45. package/dist/components/ui3n-table/ui3n-table-sort-icon.d.ts +4 -1
  46. package/dist/components/ui3n-tabs/types.d.ts +4 -0
  47. package/dist/components/ui3n-text/types.d.ts +11 -0
  48. package/dist/components/ui3n-text/ui3n-text.d.ts +4 -1
  49. package/dist/components/ui3n-tooltip/types.d.ts +4 -0
  50. package/dist/components/ui3n-tooltip/ui3n-tooltip.d.ts +4 -2
  51. package/dist/style.css +1 -1
  52. package/dist/ui3n-components.js +2121 -1696
  53. package/dist/ui3n-plugins.js +1 -1
  54. package/package.json +1 -1
  55. package/src/components/index.ts +29 -7
  56. package/src/components/ui3n-autocomplete/types.ts +14 -1
  57. package/src/components/ui3n-autocomplete/ui3n-autocomplete.vue +189 -55
  58. package/src/components/ui3n-badge/types.ts +10 -0
  59. package/src/components/ui3n-badge/ui3n-badge-simple.vue +54 -55
  60. package/src/components/ui3n-badge/ui3n-badge.vue +4 -0
  61. package/src/components/ui3n-breadcrumbs/types.ts +1 -1
  62. package/src/components/ui3n-breadcrumbs/ui3n-breadcrumb.vue +7 -5
  63. package/src/components/ui3n-button/types.ts +4 -2
  64. package/src/components/ui3n-button/ui3n-button.vue +24 -19
  65. package/src/components/ui3n-checkbox/types.ts +12 -0
  66. package/src/components/ui3n-checkbox/ui3n-checkbox.vue +79 -29
  67. package/src/components/ui3n-chip/types.ts +6 -1
  68. package/src/components/ui3n-chip/ui3n-chip.vue +64 -61
  69. package/src/components/ui3n-dialog/ui3n-dialog.vue +3 -3
  70. package/src/components/ui3n-drop-files/types.ts +8 -0
  71. package/src/components/ui3n-drop-files/ui3n-drop-files.vue +73 -29
  72. package/src/components/ui3n-editable/types.ts +12 -0
  73. package/src/components/ui3n-editable/ui3n-editable.vue +56 -24
  74. package/src/components/ui3n-icon/types.ts +5 -1
  75. package/src/components/ui3n-icon/ui3n-icon.vue +45 -50
  76. package/src/components/ui3n-input/types.ts +4 -0
  77. package/src/components/ui3n-input/ui3n-input.vue +14 -1
  78. package/src/components/ui3n-input-file/types.ts +12 -0
  79. package/src/components/ui3n-input-file/ui3n-input-file.vue +33 -16
  80. package/src/components/ui3n-list/types.ts +4 -0
  81. package/src/components/ui3n-list/ui3n-list.vue +3 -1
  82. package/src/components/ui3n-menu/types.ts +9 -0
  83. package/src/components/ui3n-menu/ui3n-menu.vue +169 -39
  84. package/src/components/ui3n-notification/ui3n-notification.vue +190 -175
  85. package/src/components/ui3n-progress/ui3n-progress-circular.vue +40 -22
  86. package/src/components/ui3n-progress/ui3n-progress-linear.vue +14 -7
  87. package/src/components/ui3n-radio-group/types.ts +20 -0
  88. package/src/components/ui3n-radio-group/ui3n-radio-group.vue +61 -48
  89. package/src/components/ui3n-radio-group/ui3n-radio.vue +60 -65
  90. package/src/components/ui3n-scrollbar-vertical/types.ts +2 -0
  91. package/src/components/ui3n-scrollbar-vertical/ui3n-scrollbar-vertical.vue +4 -4
  92. package/src/components/ui3n-selector/types.ts +12 -0
  93. package/src/components/ui3n-selector/ui3n-selector.vue +63 -40
  94. package/src/components/ui3n-slider/types.ts +12 -0
  95. package/src/components/ui3n-slider/ui3n-slider.vue +88 -39
  96. package/src/components/ui3n-step-line-bar/types.ts +4 -0
  97. package/src/components/ui3n-step-line-bar/ui3n-step-line-bar.vue +8 -10
  98. package/src/components/ui3n-switch/types.ts +12 -0
  99. package/src/components/ui3n-switch/ui3n-switch.vue +57 -25
  100. package/src/components/ui3n-table/composables/useTable.ts +17 -0
  101. package/src/components/ui3n-table/types.ts +4 -0
  102. package/src/components/ui3n-table/ui3n-table-sort-icon.vue +9 -8
  103. package/src/components/ui3n-table/ui3n-table.vue +48 -17
  104. package/src/components/ui3n-tabs/types.ts +4 -0
  105. package/src/components/ui3n-tabs/ui3n-tabs.vue +146 -108
  106. package/src/components/ui3n-text/types.ts +12 -0
  107. package/src/components/ui3n-text/ui3n-text.vue +56 -15
  108. package/src/components/ui3n-tooltip/types.ts +4 -0
  109. package/src/components/ui3n-tooltip/ui3n-tooltip.vue +61 -43
  110. package/src/components/ui3n-virtual-scroll/ui3n-virtual-scroll.vue +201 -17
  111. package/dist/chunks/ui3n-notification-DlDM-u-R.js +0 -276
@@ -1,5 +1,5 @@
1
1
  import { B as e, n as t, r as n, t as r } from "./chunks/plugins-keys-jqAZ5D94.js";
2
- import { t as i } from "./chunks/ui3n-notification-DlDM-u-R.js";
2
+ import { t as i } from "./chunks/ui3n-notification-Dr_3Td9N.js";
3
3
  import { createApp as a, markRaw as o, ref as s } from "vue";
4
4
  import "pinia";
5
5
  import c from "mitt";
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@v1nt1248/3nclient-lib",
3
3
  "license": "AGPL-3.0-or-later",
4
4
  "author": "v1nt1248",
5
- "version": "0.3.28",
5
+ "version": "0.3.30",
6
6
  "description": "Library for 3NWeb clients",
7
7
  "type": "module",
8
8
  "files": [
@@ -6,20 +6,26 @@ import type { Ui3nButtonProps, Ui3nButtonEmits } from './ui3n-button/types';
6
6
  import Ui3nChip from './ui3n-chip/ui3n-chip.vue';
7
7
  import type { Ui3nChipProps, Ui3nChipEmits, Ui3nChipSlots } from './ui3n-chip/types';
8
8
  import Ui3nDropFiles from './ui3n-drop-files/ui3n-drop-files.vue';
9
- import type { Ui3nDropFilesProps, Ui3nDropFilesEmits, Ui3nDropFilesSlots } from './ui3n-drop-files/types';
9
+ import type {
10
+ Ui3nDropFilesProps,
11
+ Ui3nDropFilesEmits,
12
+ Ui3nDropFilesSlots,
13
+ Ui3nDropFilesExpose,
14
+ } from './ui3n-drop-files/types';
10
15
  import Ui3nEmoji from './ui3n-emoji/ui3n-emoji.vue';
11
16
  import type { Ui3nEmojiProps, Ui3nEmojiEmits } from './ui3n-emoji/types';
12
17
  import Ui3nInput from './ui3n-input/ui3n-input.vue';
13
18
  import type { Ui3nInputProps, Ui3nInputEmits, Ui3nInputSlots, Ui3nInputExpose } from './ui3n-input/types';
14
19
  import Ui3nInputFile from './ui3n-input-file/ui3n-input-file.vue';
15
- import type { Ui3nInputFileProps, Ui3nInputFileEmits } from './ui3n-input-file/types';
20
+ import type { Ui3nInputFileProps, Ui3nInputFileEmits, Ui3nInputFileExpose } from './ui3n-input-file/types';
16
21
  import Ui3nText from './ui3n-text/ui3n-text.vue';
17
- import type { Ui3nTextProps, Ui3nTextEmits } from './ui3n-text/types';
22
+ import type { Ui3nTextProps, Ui3nTextEmits, Ui3nTextExpose } from './ui3n-text/types';
18
23
  import Ui3nCheckbox from './ui3n-checkbox/ui3n-checkbox.vue';
19
24
  import type {
20
25
  Ui3nCheckboxProps,
21
26
  Ui3nCheckboxEmits,
22
27
  Ui3nCheckboxSlots,
28
+ Ui3nCheckboxExpose,
23
29
  Ui3nCheckboxValue,
24
30
  } from './ui3n-checkbox/types';
25
31
  import Ui3nNotification from './ui3n-notification/ui3n-notification.vue';
@@ -51,7 +57,7 @@ import type {
51
57
  Ui3nDialogEvent,
52
58
  } from './ui3n-dialog/types';
53
59
  import Ui3nMenu from './ui3n-menu/ui3n-menu.vue';
54
- import type { Ui3nMenuProps, Ui3nMenuEmits, Ui3nMenuSlots } from './ui3n-menu/types';
60
+ import type { Ui3nMenuProps, Ui3nMenuEmits, Ui3nMenuSlots, Ui3nMenuExpose } from './ui3n-menu/types';
55
61
  import Ui3nList from './ui3n-list/ui3n-list.vue';
56
62
  import type { Ui3nListProps, Ui3nListEmits, Ui3nListSlots } from './ui3n-list/types';
57
63
  import Ui3nVirtualScroll from './ui3n-virtual-scroll/ui3n-virtual-scroll.vue';
@@ -69,7 +75,7 @@ import type {
69
75
  Ui3nBreadcrumbsProps,
70
76
  } from './ui3n-breadcrumbs/types';
71
77
  import Ui3nSwitch from './ui3n-switch/ui3n-switch.vue';
72
- import type { Ui3nSwitchProps, Ui3nSwitchEmits, Ui3nSwitchSlots } from './ui3n-switch/types';
78
+ import type { Ui3nSwitchProps, Ui3nSwitchEmits, Ui3nSwitchSlots, Ui3nSwitchExpose } from './ui3n-switch/types';
73
79
  import Ui3nStepLineBar from './ui3n-step-line-bar/ui3n-step-line-bar.vue';
74
80
  import type { Ui3nStepLineBarProps } from './ui3n-step-line-bar/types';
75
81
  import Ui3nProgressLinear from './ui3n-progress/ui3n-progress-linear.vue';
@@ -88,28 +94,32 @@ import type {
88
94
  Ui3nRadioEmits,
89
95
  Ui3nRadioProps,
90
96
  Ui3nRadioSlots,
97
+ Ui3nRadioExpose,
91
98
  Ui3nRadioGroupEmits,
92
99
  Ui3nRadioGroupProps,
93
100
  Ui3nRadioGroupSlots,
101
+ Ui3nRadioGroupExpose,
94
102
  Ui3nRadioValue,
95
103
  } from './ui3n-radio-group/types';
96
104
  import Ui3nEditable from './ui3n-editable/ui3n-editable.vue';
97
- import type { Ui3nEditableProps, Ui3nEditableEmits } from './ui3n-editable/types';
105
+ import type { Ui3nEditableProps, Ui3nEditableEmits, Ui3nEditableExpose } from './ui3n-editable/types';
98
106
  import Ui3nAutocomplete from './ui3n-autocomplete/ui3n-autocomplete.vue';
99
107
  import type {
100
108
  Ui3nAutocompleteProps,
101
109
  Ui3nAutocompleteEmits,
102
110
  Ui3nAutocompleteSlots,
111
+ Ui3nAutocompleteExpose,
103
112
  Ui3nAutocompleteOptionBase,
104
113
  } from './ui3n-autocomplete/types';
105
114
  import Ui3nSlider from './ui3n-slider/ui3n-slider.vue';
106
- import type { UI3nSliderProps, UI3nSliderEmits } from './ui3n-slider/types';
115
+ import type { UI3nSliderProps, UI3nSliderEmits, UI3nSliderExpose } from './ui3n-slider/types';
107
116
  import Ui3nSelector from './ui3n-selector/ui3n-selector.vue';
108
117
  import type {
109
118
  Ui3nSelectorOptionBase,
110
119
  Ui3nSelectorProps,
111
120
  Ui3nSelectorEmits,
112
121
  Ui3nSelectorSlots,
122
+ Ui3nSelectorExpose,
113
123
  Ui3nSelectorItemDisplayingFunction,
114
124
  } from './ui3n-selector/types';
115
125
  import Ui3nMobileMenu from './ui3n-mobile-menu/ui3n-mobile-menu.vue';
@@ -150,6 +160,7 @@ export {
150
160
  Ui3nDropFilesProps,
151
161
  Ui3nDropFilesEmits,
152
162
  Ui3nDropFilesSlots,
163
+ Ui3nDropFilesExpose,
153
164
  Ui3nEmoji,
154
165
  Ui3nEmojiProps,
155
166
  Ui3nEmojiEmits,
@@ -161,13 +172,16 @@ export {
161
172
  Ui3nInputFile,
162
173
  Ui3nInputFileProps,
163
174
  Ui3nInputFileEmits,
175
+ Ui3nInputFileExpose,
164
176
  Ui3nText,
165
177
  Ui3nTextProps,
166
178
  Ui3nTextEmits,
179
+ Ui3nTextExpose,
167
180
  Ui3nCheckbox,
168
181
  Ui3nCheckboxProps,
169
182
  Ui3nCheckboxEmits,
170
183
  Ui3nCheckboxSlots,
184
+ Ui3nCheckboxExpose,
171
185
  Ui3nCheckboxValue,
172
186
  Ui3nNotification,
173
187
  Ui3nTableSortIcon,
@@ -197,6 +211,7 @@ export {
197
211
  Ui3nMenuProps,
198
212
  Ui3nMenuEmits,
199
213
  Ui3nMenuSlots,
214
+ Ui3nMenuExpose,
200
215
  Ui3nList,
201
216
  Ui3nListProps,
202
217
  Ui3nListEmits,
@@ -220,6 +235,7 @@ export {
220
235
  Ui3nSwitchProps,
221
236
  Ui3nSwitchEmits,
222
237
  Ui3nSwitchSlots,
238
+ Ui3nSwitchExpose,
223
239
  Ui3nStepLineBar,
224
240
  Ui3nStepLineBarProps,
225
241
  Ui3nProgressLinear,
@@ -237,24 +253,30 @@ export {
237
253
  Ui3nRadioEmits,
238
254
  Ui3nRadioProps,
239
255
  Ui3nRadioSlots,
256
+ Ui3nRadioExpose,
240
257
  Ui3nRadioGroupEmits,
241
258
  Ui3nRadioGroupProps,
242
259
  Ui3nRadioGroupSlots,
260
+ Ui3nRadioGroupExpose,
243
261
  Ui3nEditable,
244
262
  Ui3nEditableProps,
245
263
  Ui3nEditableEmits,
264
+ Ui3nEditableExpose,
246
265
  Ui3nAutocomplete,
247
266
  Ui3nAutocompleteProps,
248
267
  Ui3nAutocompleteEmits,
249
268
  Ui3nAutocompleteSlots,
269
+ Ui3nAutocompleteExpose,
250
270
  Ui3nAutocompleteOptionBase,
251
271
  Ui3nSlider,
252
272
  UI3nSliderProps,
253
273
  UI3nSliderEmits,
274
+ UI3nSliderExpose,
254
275
  Ui3nSelector,
255
276
  Ui3nSelectorProps,
256
277
  Ui3nSelectorEmits,
257
278
  Ui3nSelectorSlots,
279
+ Ui3nSelectorExpose,
258
280
  Ui3nSelectorOptionBase,
259
281
  Ui3nSelectorItemDisplayingFunction,
260
282
  Ui3nMobileMenu,
@@ -25,6 +25,10 @@ export type Ui3nAutocompleteValue<T extends Ui3nAutocompleteOptionBase> = {
25
25
  * Autocomplete component properties
26
26
  */
27
27
  export interface Ui3nAutocompleteProps<T extends Ui3nAutocompleteOptionBase> {
28
+ /**
29
+ * HTML name attribute for form submission
30
+ */
31
+ name?: string;
28
32
  /**
29
33
  * Whether to show chips
30
34
  * @default false
@@ -53,6 +57,11 @@ export interface Ui3nAutocompleteProps<T extends Ui3nAutocompleteOptionBase> {
53
57
  * @default false
54
58
  */
55
59
  hideSelected?: boolean;
60
+ /**
61
+ * Whether to lock scroll when menu is open
62
+ * @default false
63
+ */
64
+ lockScroll?: boolean;
56
65
  /**
57
66
  * Items to display
58
67
  */
@@ -131,7 +140,7 @@ export interface Ui3nAutocompleteSlots<T extends Ui3nAutocompleteOptionBase> {
131
140
  /**
132
141
  * Chip slot
133
142
  */
134
- chip: (props: { item: T | T[keyof T]; index: number }) => VNode;
143
+ chip: (props: { item: T | T[keyof T]; index: number; isHighlighted: boolean }) => VNode;
135
144
  /**
136
145
  * No data text slot
137
146
  */
@@ -141,3 +150,7 @@ export interface Ui3nAutocompleteSlots<T extends Ui3nAutocompleteOptionBase> {
141
150
  */
142
151
  selection: (props: { value: T[] | Array<T[keyof T]> }) => VNode;
143
152
  }
153
+
154
+ export interface Ui3nAutocompleteExpose {
155
+ clear: () => void;
156
+ }
@@ -1,19 +1,3 @@
1
- <!--
2
- Copyright (C) 2025 3NSoft Inc.
3
-
4
- This program is free software: you can redistribute it and/or modify it under
5
- the terms of the GNU General Public License as published by the Free Software
6
- Foundation, either version 3 of the License, or (at your option) any later
7
- version.
8
-
9
- This program is distributed in the hope that it will be useful, but
10
- WITHOUT ANY WARRANTY; without even the implied warranty of
11
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
- See the GNU General Public License for more details.
13
-
14
- You should have received a copy of the GNU General Public License along with
15
- this program. If not, see <http://www.gnu.org/licenses/>.
16
- -->
17
1
  <script setup lang="ts" generic="T extends Ui3nAutocompleteOptionBase">
18
2
  import { computed, ref, watch } from 'vue';
19
3
  import cloneDeep from 'lodash/cloneDeep';
@@ -21,19 +5,21 @@
21
5
  import size from 'lodash/size';
22
6
  import Ui3nChip from '../ui3n-chip/ui3n-chip.vue';
23
7
  import Ui3nMenu from '../ui3n-menu/ui3n-menu.vue';
24
- import Ui3nHtml from '@/directives/ui3n-html';
25
- import { markSearch, getRandomId } from '@/utils';
8
+ import Ui3nHtml from '../../directives/ui3n-html';
9
+ import { markSearch, getRandomId } from '../../utils';
26
10
  import type { Nullable } from '@/types';
27
- import {
11
+ import type {
28
12
  Ui3nAutocompleteOptionBase,
29
13
  Ui3nAutocompleteProps,
30
14
  Ui3nAutocompleteEmits,
31
15
  Ui3nAutocompleteSlots,
16
+ Ui3nAutocompleteExpose,
32
17
  } from './types';
33
18
 
34
19
  const vUi3nHtml = Ui3nHtml;
35
20
 
36
21
  const props = withDefaults(defineProps<Ui3nAutocompleteProps<T>>(), {
22
+ lockScroll: false,
37
23
  clearOnSelect: false,
38
24
  filterKeys: () => [],
39
25
  hideSelected: false,
@@ -52,6 +38,7 @@
52
38
  const inputEl = ref<Nullable<HTMLInputElement>>(null);
53
39
  const menuBodyEl = ref<Nullable<HTMLDivElement>>(null);
54
40
  const activeItemsIndex = ref<Nullable<number>>(null);
41
+ const isLastChipHighlighted = ref(false);
55
42
  const isNewValueValid = ref(true);
56
43
 
57
44
  const ids = computed(() =>
@@ -93,12 +80,14 @@
93
80
  });
94
81
 
95
82
  function onInput() {
83
+ isLastChipHighlighted.value = false;
96
84
  emits('update:search', query.value);
97
85
  }
98
86
 
99
87
  function onBlur() {
100
88
  emits('update:focused', false);
101
89
  activeItemsIndex.value = null;
90
+ isLastChipHighlighted.value = false;
102
91
 
103
92
  setTimeout(() => {
104
93
  isMenuOpen.value = false;
@@ -145,7 +134,7 @@
145
134
  function handlePressingDownKey() {
146
135
  if (activeItemsIndex.value === null) {
147
136
  activeItemsIndex.value = 0;
148
- menuBodyEl.value && menuBodyEl.value.focus();
137
+ menuBodyEl.value && menuBodyEl.value.focus({ preventScroll: true });
149
138
  return;
150
139
  }
151
140
 
@@ -157,7 +146,7 @@
157
146
  function handlePressingUpKey() {
158
147
  if (activeItemsIndex.value === null) {
159
148
  activeItemsIndex.value = size(filteredItems.value) - 1;
160
- menuBodyEl.value && menuBodyEl.value.focus();
149
+ menuBodyEl.value && menuBodyEl.value.focus({ preventScroll: true });
161
150
  return;
162
151
  }
163
152
 
@@ -179,7 +168,7 @@
179
168
  if (activeItemsIndex.value === null && !isMenuOpen.value) {
180
169
  isMenuOpen.value = true;
181
170
  activeItemsIndex.value = 0;
182
- menuBodyEl.value && menuBodyEl.value.focus();
171
+ menuBodyEl.value && menuBodyEl.value.focus({ preventScroll: true });
183
172
  return;
184
173
  }
185
174
 
@@ -206,30 +195,80 @@
206
195
  }
207
196
  }
208
197
 
209
- function onKeydown(event: KeyboardEvent, key: 'down' | 'up' | 'esc' | 'enter' | 'tab') {
198
+ function handleBackspaceKey() {
199
+ if (props.disabled || query.value !== '' || isEmpty(props.modelValue)) {
200
+ return;
201
+ }
202
+
203
+ if (!isLastChipHighlighted.value) {
204
+ isLastChipHighlighted.value = true;
205
+ return;
206
+ }
207
+
208
+ const updatedModelValue = cloneDeep(props.modelValue);
209
+ updatedModelValue.pop();
210
+ emits('update:modelValue', updatedModelValue);
211
+
212
+ isLastChipHighlighted.value = false;
213
+ }
214
+
215
+ function onKeydown(event: KeyboardEvent, key: 'down' | 'up' | 'esc' | 'enter' | 'tab' | 'backspace') {
210
216
  switch (key) {
211
- case 'down':
217
+ case 'down': {
212
218
  event.preventDefault();
213
219
  event.stopPropagation();
214
220
  handlePressingDownKey();
215
221
  break;
216
- case 'up':
222
+ }
223
+
224
+ case 'up': {
217
225
  event.preventDefault();
218
226
  event.stopPropagation();
219
227
  handlePressingUpKey();
220
228
  break;
229
+ }
230
+
221
231
  case 'esc':
222
232
  case 'tab':
223
233
  handlePressingEscOrTabKeys();
224
234
  break;
225
- case 'enter':
235
+
236
+ case 'enter': {
226
237
  event.preventDefault();
227
238
  event.stopPropagation();
228
239
  handlePressingEnterKey();
229
240
  break;
241
+ }
242
+
243
+ case 'backspace':
244
+ handleBackspaceKey();
245
+ break;
230
246
  }
231
247
  }
232
248
 
249
+ function clear() {
250
+ query.value = '';
251
+ isMenuOpen.value = false;
252
+ activeItemsIndex.value = null;
253
+ isNewValueValid.value = true;
254
+
255
+ emits('update:modelValue', [] as unknown as T[] & Array<T[keyof T]>);
256
+ emits('update:search', '');
257
+ }
258
+
259
+ defineExpose<Ui3nAutocompleteExpose>({
260
+ clear,
261
+ });
262
+
263
+ watch(
264
+ () => props.name,
265
+ newName => {
266
+ if (!newName) {
267
+ clear();
268
+ }
269
+ },
270
+ );
271
+
233
272
  watch(
234
273
  () => size(filteredItems.value),
235
274
  (val, oVal) => {
@@ -246,10 +285,48 @@
246
285
 
247
286
  <template>
248
287
  <div :class="$style.ui3nAutocomplete">
288
+ <!-- 'hidden inputs' block for setting of 'name' attr when used in a form -->
289
+ <fieldset
290
+ v-if="name && !isEmpty(modelValue)"
291
+ :class="$style.hiddenBlock"
292
+ >
293
+ <template v-if="!multiple">
294
+ <input
295
+ type="hidden"
296
+ :name="name"
297
+ :value="returnObject ? JSON.stringify(modelValue) : modelValue"
298
+ />
299
+ </template>
300
+
301
+ <template v-else>
302
+ <template v-if="!returnObject">
303
+ <input
304
+ v-for="(val, index) in modelValue as Array<T[keyof T]>"
305
+ :key="`${name}-flat-${index}`"
306
+ type="hidden"
307
+ :name="`${name}[]`"
308
+ :value="val"
309
+ />
310
+ </template>
311
+
312
+ <template v-else>
313
+ <input
314
+ v-for="(item, index) in modelValue as T[]"
315
+ :key="item.id || `${name}-obj-${index}`"
316
+ type="hidden"
317
+ :name="`${name}[]`"
318
+ :value="JSON.stringify(item)"
319
+ />
320
+ </template>
321
+ </template>
322
+ </fieldset>
323
+
249
324
  <ui3n-menu
250
325
  v-model="isMenuOpen"
326
+ :lock-scroll="lockScroll"
251
327
  :offset-x="2"
252
328
  :offset-y="4"
329
+ position-strategy="fixed"
253
330
  position-autoupdate
254
331
  :content-border-radius="[0, 0, 8, 8]"
255
332
  :disabled="disabled"
@@ -258,19 +335,31 @@
258
335
  ref="activatorEl"
259
336
  :class="$style.trigger"
260
337
  >
261
- <template v-if="chips">
338
+ <transition-group
339
+ v-if="chips"
340
+ name="chipAnim"
341
+ tag="div"
342
+ :class="$style.chipsContainer"
343
+ >
262
344
  <!-- @vue-ignore -->
263
- <template
345
+ <div
264
346
  v-for="(item, index) in modelValue"
265
- :key="item.id"
347
+ :key="item.id || index"
348
+ :class="$style.chipWrapper"
266
349
  >
267
350
  <slot
268
351
  name="chip"
269
352
  :item="item"
270
353
  :index="index"
354
+ :is-highlighted="index === size(modelValue) - 1 && isLastChipHighlighted"
271
355
  >
272
356
  <ui3n-chip
273
357
  height="32"
358
+ :color="
359
+ index === size(modelValue) - 1 && isLastChipHighlighted
360
+ ? 'var(--color-bg-control-primary-hover)'
361
+ : undefined
362
+ "
274
363
  round
275
364
  closeable
276
365
  @close="onChipClose(item)"
@@ -278,8 +367,8 @@
278
367
  {{ returnObject ? (item as T)[props.itemTitle] : item }}
279
368
  </ui3n-chip>
280
369
  </slot>
281
- </template>
282
- </template>
370
+ </div>
371
+ </transition-group>
283
372
 
284
373
  <template v-else>
285
374
  <div :class="$style.displayValue">
@@ -295,13 +384,14 @@
295
384
  :placeholder="isEmpty(modelValue) && placeholder ? placeholder : ''"
296
385
  :disabled="disabled"
297
386
  @input="onInput"
298
- @focusin="emits('update:focused', true)"
387
+ @focusin.prevent="emits('update:focused', true)"
299
388
  @focusout="onBlur"
300
389
  @keydown.down="onKeydown($event, 'down')"
301
390
  @keydown.up="onKeydown($event, 'up')"
302
391
  @keydown.esc="onKeydown($event, 'esc')"
303
392
  @keydown.enter="onKeydown($event, 'enter')"
304
393
  @keydown.tab="onKeydown($event, 'tab')"
394
+ @keydown.delete="onKeydown($event, 'backspace')"
305
395
  />
306
396
  </div>
307
397
 
@@ -356,11 +446,16 @@
356
446
 
357
447
  <style lang="scss" module>
358
448
  .ui3nAutocomplete {
359
- --autocomplete-min-height: var(--spacing-l);
449
+ --ui3n-autocomplete-min-height: 32px;
450
+ --ui3n-autocomplete-font-size: 12px;
451
+ --ui3n-autocomplete-item-font-size: 13px;
452
+ --ui3n-autocomplete-padding-inline: 8px;
453
+ --ui3n-autocomplete-padding-block: 4px;
454
+ --ui3n-autocomplete-border-radius: 4px;
360
455
 
361
456
  position: relative;
362
457
  width: 100%;
363
- min-height: var(--autocomplete-min-height);
458
+ min-height: var(--ui3n-autocomplete-min-height);
364
459
 
365
460
  :global(.match-search) {
366
461
  font-weight: 600;
@@ -368,29 +463,36 @@
368
463
  }
369
464
  }
370
465
 
466
+ .hiddenBlock {
467
+ display: none;
468
+ border: none;
469
+ padding: 0;
470
+ margin: 0;
471
+ }
472
+
371
473
  .trigger {
372
474
  display: flex;
373
475
  width: 100%;
374
476
  flex-wrap: wrap;
375
477
  justify-content: flex-start;
376
478
  align-items: flex-start;
377
- gap: var(--spacing-xs);
479
+ gap: 4px;
378
480
  }
379
481
 
380
482
  .displayValue {
381
- font-size: var(--font-12);
382
- line-height: var(--autocomplete-min-height);
483
+ font-size: var(--ui3n-autocomplete-font-size);
484
+ line-height: var(--ui3n-autocomplete-min-height);
383
485
  font-weight: 400;
384
486
  color: var(--color-text-control-primary-default);
385
487
  }
386
488
 
387
489
  .input {
388
- border-radius: var(--spacing-xs);
389
- padding: 0 var(--spacing-s);
490
+ border-radius: var(--ui3n-autocomplete-border-radius);
491
+ padding: 0 var(--ui3n-autocomplete-padding-inline);
390
492
  flex-grow: 1;
391
- height: var(--autocomplete-min-height);
392
- font-size: var(--font-12);
393
- line-height: var(--autocomplete-min-height);
493
+ height: var(--ui3n-autocomplete-min-height);
494
+ font-size: var(--ui3n-autocomplete-font-size);
495
+ line-height: var(--ui3n-autocomplete-min-height);
394
496
  font-weight: 400;
395
497
  color: var(--color-text-control-primary-default);
396
498
  background-color: transparent;
@@ -407,8 +509,8 @@
407
509
  }
408
510
 
409
511
  &.inputWithError {
410
- height: calc(var(--autocomplete-min-height) - 2px);
411
- padding: 0 calc(var(--spacing-s) - 1px);
512
+ height: calc(var(--ui3n-autocomplete-min-height) - 2px);
513
+ padding: 0 calc(var(--ui3n-autocomplete-padding-inline) - 1px);
412
514
  border: 1px solid var(--error-content-default);
413
515
  }
414
516
  }
@@ -416,20 +518,20 @@
416
518
  .body {
417
519
  position: relative;
418
520
  background-color: var(--color-bg-block-primary-default);
419
- padding: var(--spacing-xs);
521
+ padding: 4px;
420
522
  }
421
523
 
422
524
  .item {
423
525
  display: flex;
424
- min-height: var(--spacing-l);
526
+ min-height: var(--ui3n-autocomplete-min-height);
425
527
  justify-content: flex-start;
426
528
  align-items: center;
427
- padding: var(--spacing-xs) var(--spacing-s);
428
- font-size: var(--font-13);
429
- line-height: var(--font-16);
529
+ padding: var(--ui3n-autocomplete-padding-block) var(--ui3n-autocomplete-padding-inline);
530
+ font-size: var(--ui3n-autocomplete-item-font-size);
531
+ line-height: 1.23;
430
532
  font-weight: 500;
431
533
  color: var(--color-text-control-primary-default);
432
- border-radius: var(--spacing-xs);
534
+ border-radius: var(--ui3n-autocomplete-border-radius);
433
535
  user-select: none;
434
536
  cursor: pointer;
435
537
 
@@ -452,14 +554,46 @@
452
554
 
453
555
  .noData {
454
556
  display: flex;
455
- min-height: var(--spacing-l);
557
+ min-height: var(--ui3n-autocomplete-min-height);
456
558
  justify-content: flex-start;
457
559
  align-items: center;
458
- padding: var(--spacing-xs) var(--spacing-s);
459
- font-size: var(--font-13);
460
- line-height: var(--font-16);
560
+ padding: var(--ui3n-autocomplete-padding-block) var(--ui3n-autocomplete-padding-inline);
561
+ font-size: var(--ui3n-autocomplete-item-font-size);
562
+ line-height: 1.23;
461
563
  font-weight: 500;
462
564
  color: var(--color-text-control-primary-default);
463
- border-radius: var(--spacing-xs);
565
+ border-radius: var(--ui3n-autocomplete-border-radius);
566
+ }
567
+
568
+ .chipsContainer {
569
+ display: flex;
570
+ flex-wrap: wrap;
571
+ gap: 4px;
572
+ align-items: flex-start;
573
+ }
574
+
575
+ .chipWrapper {
576
+ display: inline-flex;
577
+ }
578
+
579
+ :global {
580
+ .chipAnim-enter-from,
581
+ .chipAnim-leave-to {
582
+ opacity: 0;
583
+ transform: scale(0.85);
584
+ }
585
+
586
+ .chipAnim-enter-active,
587
+ .chipAnim-leave-active {
588
+ transition: all 0.2s ease;
589
+ }
590
+
591
+ .chipAnim-move {
592
+ transition: transform 0.2s ease;
593
+ }
594
+
595
+ .chipAnim-leave-active {
596
+ position: absolute !important;
597
+ }
464
598
  }
465
599
  </style>
@@ -1,6 +1,10 @@
1
1
  import type { VNode } from 'vue';
2
2
 
3
3
  export interface Ui3nBadgeSimpleProps {
4
+ /**
5
+ * Root element id
6
+ */
7
+ id?: string;
4
8
  /** For simple display as a circle */
5
9
  dot?: boolean;
6
10
  /** Text displayed inside the circle */
@@ -11,7 +15,13 @@ export interface Ui3nBadgeSimpleProps {
11
15
  textColor?: string;
12
16
  }
13
17
 
18
+ export interface Ui3nBadgeSimpleEmits {
19
+ (event: 'change:size', val: { width: number; height: number }): void;
20
+ }
21
+
14
22
  export interface Ui3nBadgeProps {
23
+ /** Root element id*/
24
+ id?: string;
15
25
  /** For simple display as a circle */
16
26
  dot?: boolean;
17
27
  /** Text displayed inside the circle */