@antify/ui-module 1.1.4 → 1.2.0

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 (46) hide show
  1. package/dist/module.d.mts +2 -0
  2. package/dist/module.d.ts +2 -0
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +3 -0
  5. package/dist/runtime/components/AntAccordionItem.vue +1 -1
  6. package/dist/runtime/components/AntTag.vue +3 -3
  7. package/dist/runtime/components/AntToast.vue +1 -0
  8. package/dist/runtime/components/{Main.stories.mdx → Main.mdx} +3 -2
  9. package/dist/runtime/components/Main.stories.d.ts +7 -0
  10. package/dist/runtime/components/Main.stories.mjs +8 -0
  11. package/dist/runtime/components/__stories/AntAccordion.stories.mjs +13 -10
  12. package/dist/runtime/components/__stories/AntKeycap.stories.d.ts +1 -1
  13. package/dist/runtime/components/__stories/AntKeycap.stories.mjs +15 -12
  14. package/dist/runtime/components/__types/AntIcon.types.d.ts +1 -0
  15. package/dist/runtime/components/__types/AntIcon.types.mjs +1 -0
  16. package/dist/runtime/components/buttons/__stories/AntButton.stories.mjs +3 -0
  17. package/dist/runtime/components/form/AntCheckboxWidget/__stories/AntCheckbox.stories.mjs +3 -0
  18. package/dist/runtime/components/form/AntSelect.vue +4 -51
  19. package/dist/runtime/components/form/AntSwitch.vue +8 -3
  20. package/dist/runtime/components/form/AntTagInput.vue +306 -0
  21. package/dist/runtime/components/form/Elements/AntDropDown.vue +53 -23
  22. package/dist/runtime/components/form/Elements/AntField.vue +2 -2
  23. package/dist/runtime/components/form/Elements/__stories/AntBaseInput.stories.mjs +3 -0
  24. package/dist/runtime/components/form/Elements/__types/AntBaseInput.type.d.ts +1 -0
  25. package/dist/runtime/components/form/Elements/__types/AntBaseInput.type.mjs +1 -0
  26. package/dist/runtime/components/form/__stories/AntSelect.stories.mjs +3 -0
  27. package/dist/runtime/components/form/__stories/AntSwitch.stories.mjs +3 -0
  28. package/dist/runtime/components/form/__stories/AntSwitcher.stories.mjs +3 -0
  29. package/dist/runtime/components/form/__stories/AntTagInput.stories.d.ts +9 -0
  30. package/dist/runtime/components/form/__stories/AntTagInput.stories.mjs +106 -0
  31. package/dist/runtime/components/form/__stories/AntTextarea.stories.mjs +3 -0
  32. package/dist/runtime/components/form/index.d.ts +2 -1
  33. package/dist/runtime/components/form/index.mjs +2 -0
  34. package/dist/runtime/tailwind.config.d.ts +1 -0
  35. package/dist/runtime/tailwind.config.mjs +1 -0
  36. package/dist/runtime/types/AntTag.type.d.ts +1 -2
  37. package/dist/runtime/types/AntTag.type.mjs +1 -2
  38. package/package.json +20 -21
  39. package/src/runtime/components/AntAccordionItem.vue +2 -2
  40. package/src/runtime/components/AntTag.vue +3 -3
  41. package/src/runtime/components/AntToast.vue +1 -0
  42. package/src/runtime/components/form/AntSelect.vue +4 -51
  43. package/src/runtime/components/form/AntSwitch.vue +8 -3
  44. package/src/runtime/components/form/AntTagInput.vue +306 -0
  45. package/src/runtime/components/form/Elements/AntDropDown.vue +53 -23
  46. package/src/runtime/components/form/Elements/AntField.vue +2 -2
@@ -82,6 +82,7 @@ declare const _default: {
82
82
  'danger-800-font': any;
83
83
  'danger-900-font': any;
84
84
  'danger-950-font': any;
85
+ transparent: any;
85
86
  white: any;
86
87
  black: any;
87
88
  'neutral-50': any;
@@ -1,5 +1,6 @@
1
1
  import defaultColors from "tailwindcss/colors.js";
2
2
  const colors = {
3
+ "transparent": defaultColors.transparent,
3
4
  "white": defaultColors.white,
4
5
  "black": defaultColors.black,
5
6
  "neutral-50": defaultColors.slate["50"],
@@ -1,8 +1,7 @@
1
1
  export declare enum TagColorType {
2
2
  danger = "danger",
3
3
  info = "info",
4
- neutral300 = "neutral-300",
5
- neutral50 = "neutral-50",
4
+ base = "base",
6
5
  success = "success",
7
6
  warning = "warning"
8
7
  }
@@ -1,8 +1,7 @@
1
1
  export var TagColorType = /* @__PURE__ */ ((TagColorType2) => {
2
2
  TagColorType2["danger"] = "danger";
3
3
  TagColorType2["info"] = "info";
4
- TagColorType2["neutral300"] = "neutral-300";
5
- TagColorType2["neutral50"] = "neutral-50";
4
+ TagColorType2["base"] = "base";
6
5
  TagColorType2["success"] = "success";
7
6
  TagColorType2["warning"] = "warning";
8
7
  return TagColorType2;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@antify/ui-module",
3
3
  "private": false,
4
- "version": "1.1.4",
4
+ "version": "1.2.0",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "exports": {
@@ -41,31 +41,29 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "@faker-js/faker": "^8.3.1",
44
- "@nuxt/eslint-config": "^0.2.0",
45
- "@nuxt/module-builder": "^0.5.5",
46
- "@storybook/addon-docs": "^7.6.10",
47
- "@storybook/addon-essentials": "^7.6.10",
48
- "@storybook/addon-interactions": "^7.6.10",
49
- "@storybook/addon-links": "^7.6.10",
50
- "@storybook/blocks": "^7.6.10",
51
- "@storybook/test": "^7.6.10",
52
- "@storybook/vue3": "^7.6.10",
53
- "@storybook/vue3-vite": "^7.6.10",
54
- "@typescript-eslint/eslint-plugin": "^6.19.1",
55
- "@typescript-eslint/parser": "^6.19.1",
44
+ "@nuxt/eslint-config": "latest",
45
+ "@nuxt/module-builder": "latest",
46
+ "@storybook/addon-docs": "^8.0.0-beta.5",
47
+ "@storybook/addon-essentials": "^8.0.0-beta.5",
48
+ "@storybook/addon-interactions": "^8.0.0-beta.5",
49
+ "@storybook/addon-links": "^8.0.0-beta.5",
50
+ "@storybook/addon-mdx-gfm": "^8.0.0-beta.5",
51
+ "@storybook/blocks": "^8.0.0-beta.5",
52
+ "@storybook/test": "^8.0.0-beta.5",
53
+ "@storybook/vue3": "^8.0.0-beta.5",
54
+ "@storybook/vue3-vite": "^8.0.0-beta.5",
55
+ "@vitejs/plugin-vue": "^5.0.4",
56
56
  "autoprefixer": "^10.4.16",
57
- "eslint": "^8.56.0",
58
- "eslint-config-prettier": "^9.1.0",
59
- "eslint-plugin-storybook": "^0.6.15",
60
- "eslint-plugin-vue": "^9.20.1",
57
+ "chromatic": "^11.0.0",
58
+ "eslint": "latest",
59
+ "eslint-plugin-storybook": "latest",
61
60
  "nuxt": "^3.9.3",
62
61
  "ofetch": "^1.3.3",
63
- "react": "^18.2.0",
64
- "react-dom": "^18.2.0",
65
62
  "standard-version": "latest",
66
- "storybook": "7.5.3",
63
+ "storybook": "^8.0.0-beta.5",
67
64
  "typescript": "^5.3.3",
68
65
  "unbuild": "^2.0.0",
66
+ "vite": "^5.1.4",
69
67
  "vue-cli-plugin-tailwind": "3.0.0"
70
68
  },
71
69
  "scripts": {
@@ -76,6 +74,7 @@
76
74
  "storybook": "storybook dev -p 6006 --no-open",
77
75
  "build-storybook": "storybook build",
78
76
  "release": "standard-version && git push --follow-tags && pnpm publish --access public",
79
- "release-minor": "standard-version -- --release-as minor && git push --follow-tags && pnpm publish"
77
+ "release-minor": "standard-version -- --release-as minor && git push --follow-tags && pnpm publish",
78
+ "chromatic": "npx chromatic --project-token=chpt_2abc12269958fdc"
80
79
  }
81
80
  }
@@ -93,12 +93,12 @@ function onClick() {
93
93
  animation: slide 1s reverse;
94
94
  }
95
95
 
96
- @keyframes slide {
96
+ /*@keyframes slide {
97
97
  0% {
98
98
  //transform: translateY(-100%); max-height: 0; opacity: 0;
99
99
  }
100
100
  100% {
101
101
  //transform: translateY(0%); max-height: 100%; opacity: 1;
102
102
  }
103
- }
103
+ }*/
104
104
  </style>
@@ -6,6 +6,7 @@ import {handleEnumValidation} from '../handler';
6
6
  import {type IconDefinition} from '@fortawesome/free-solid-svg-icons';
7
7
  import {faCircleXmark} from '@fortawesome/free-solid-svg-icons';
8
8
 
9
+ defineEmits(['close']);
9
10
  const props = withDefaults(defineProps<{
10
11
  colorType?: TagColorType,
11
12
  size?: Size;
@@ -13,7 +14,7 @@ const props = withDefaults(defineProps<{
13
14
  dismiss?: boolean
14
15
  }>(), {
15
16
  size: Size.md,
16
- colorType: TagColorType.neutral300,
17
+ colorType: TagColorType.base,
17
18
  dismiss: false
18
19
  });
19
20
 
@@ -21,8 +22,7 @@ const classes = computed(() => {
21
22
  const variants: Record<TagColorType, string> = {
22
23
  [TagColorType.danger]: 'bg-danger-500 text-danger-500-font',
23
24
  [TagColorType.info]: 'bg-info-500 text-info-500-font',
24
- [TagColorType.neutral300]: 'bg-neutral-300 text-neutral-300-font',
25
- [TagColorType.neutral50]: 'bg-neutral-50 text-neutral-50-font',
25
+ [TagColorType.base]: 'bg-neutral-300 text-neutral-300-font',
26
26
  [TagColorType.success]: 'bg-success-500 text-success-500-font',
27
27
  [TagColorType.warning]: 'bg-warning-500 text-warning-500-font',
28
28
  };
@@ -68,6 +68,7 @@ onMounted(() => {
68
68
  <div
69
69
  :class="classes"
70
70
  data-e2e="toast"
71
+ :data-e2e-color-type="props.colorType"
71
72
  >
72
73
  <div class="inline-flex items-center justify-between w-content gap-2.5">
73
74
  <div class="inline-flex items-center gap-2.5">
@@ -14,7 +14,7 @@
14
14
  */
15
15
  import AntField from './Elements/AntField.vue';
16
16
  import {type SelectOption} from './__types/AntSelect.type';
17
- import {computed, onMounted, ref, watch, nextTick} from 'vue';
17
+ import {computed, onMounted, ref} from 'vue';
18
18
  import {Size} from '../../enums/Size.enum';
19
19
  import {FieldValidator} from '@antify/validate';
20
20
  import {handleEnumValidation} from '../../handler';
@@ -164,13 +164,6 @@ onMounted(() => {
164
164
 
165
165
  focusedDropDownItem.value = _modelValue.value;
166
166
  });
167
- watch(isOpen, (val) => {
168
- nextTick(() => {
169
- if (val) {
170
- dropDownRef.value?.focus();
171
- }
172
- });
173
- });
174
167
 
175
168
  function onClickOutside() {
176
169
  if (!isOpen.value) {
@@ -181,47 +174,6 @@ function onClickOutside() {
181
174
  inputRef.value?.focus();
182
175
  }
183
176
 
184
- function onKeyDownInput(e: KeyboardEvent) {
185
- if (e.key === 'Enter') {
186
- isOpen.value = true;
187
- inputRef.value?.blur();
188
- }
189
-
190
- if (e.key === 'Escape') {
191
- isOpen.value = false;
192
- inputRef.value?.focus();
193
- }
194
-
195
- if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
196
- const index = props.options.findIndex(option => option.value === _modelValue.value);
197
- const option = props.options[index + 1];
198
-
199
- if (index === -1) {
200
- _modelValue.value = props.options[0].value;
201
- } else if (option !== undefined) {
202
- _modelValue.value = option.value;
203
- }
204
- }
205
-
206
- if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
207
- const index = props.options.findIndex(option => option.value === _modelValue.value);
208
- const option = props.options[index - 1];
209
-
210
- if (option !== undefined) {
211
- _modelValue.value = option.value;
212
- }
213
- }
214
- }
215
-
216
- function onFocusInInput() {
217
- inputRef.value?.addEventListener('keydown', onKeyDownInput);
218
- }
219
-
220
- function onFocusOutInput(e: FocusEvent) {
221
- e.preventDefault();
222
- inputRef.value?.removeEventListener('keydown', onKeyDownInput);
223
- }
224
-
225
177
  function onClickSelectInput(e: MouseEvent) {
226
178
  e.preventDefault();
227
179
 
@@ -280,9 +232,8 @@ function onClickRemoveButton() {
280
232
  ref="inputRef"
281
233
  :tabindex="disabled ? undefined : 0"
282
234
  @mousedown="onClickSelectInput"
283
- @focusin="onFocusInInput"
284
- @focusout="onFocusOutInput"
285
235
  v-bind="$attrs"
236
+ @click="inputRef?.focus()"
286
237
  >
287
238
  <div
288
239
  v-if="_modelValue === null && placeholder !== undefined"
@@ -329,6 +280,8 @@ function onClickRemoveButton() {
329
280
  :input-ref="inputRef"
330
281
  :size="size"
331
282
  :color-type="_colorType"
283
+ @select-element="(e) => _modelValue = e"
284
+ close-on-enter
332
285
  />
333
286
  </div>
334
287
 
@@ -1,12 +1,11 @@
1
1
  <script setup lang="ts">
2
2
  import AntField from './Elements/AntField.vue';
3
- import { useVModel } from '@vueuse/core';
4
3
  import { computed, type Ref } from 'vue';
5
4
  import { FieldValidator } from '@antify/validate';
6
5
  import AntSkeleton from '../AntSkeleton.vue';
7
6
  import { InputColorType, Size } from '../../enums';
8
7
 
9
- const emits = defineEmits([ 'update:modelValue' ]);
8
+ const emits = defineEmits([ 'update:modelValue', 'input' ]);
10
9
  const props = withDefaults(defineProps<{
11
10
  modelValue: boolean;
12
11
  label?: string;
@@ -23,7 +22,13 @@ const props = withDefaults(defineProps<{
23
22
  colorType: InputColorType.base
24
23
  });
25
24
 
26
- const _value = useVModel(props, 'modelValue', emits);
25
+ const _value = computed({
26
+ get: () => props.modelValue,
27
+ set: (value: boolean) => {
28
+ emits('update:modelValue', value)
29
+ emits('input', value)
30
+ }
31
+ });
27
32
  const hasAction = computed(() => (!props.skeleton && !props.readonly && !props.disabled))
28
33
  const _colorType: Ref<InputColorType> = computed(() => props.validator?.hasErrors() ? InputColorType.danger : props.colorType);
29
34
 
@@ -0,0 +1,306 @@
1
+ <script setup lang="ts">
2
+
3
+ import { AntField } from './Elements';
4
+ import type { SelectOption } from './__types';
5
+ import { Grouped, InputColorType, Size } from '../../enums';
6
+ import type { FieldValidator } from '@antify/validate';
7
+ import { useVModel } from '@vueuse/core';
8
+ import {
9
+ faChevronRight,
10
+ type IconDefinition
11
+ } from '@fortawesome/free-solid-svg-icons';
12
+ import { computed, type Ref, ref } from 'vue';
13
+ import AntTag from '../AntTag.vue';
14
+ import AntIcon from '../AntIcon.vue';
15
+ import { IconSize } from '../__types';
16
+ import AntDropDown from './Elements/AntDropDown.vue';
17
+ import AntSkeleton from '../AntSkeleton.vue';
18
+ import { vOnClickOutside } from '@vueuse/components'
19
+
20
+ const emit = defineEmits([ 'update:modelValue' ]);
21
+ const props = withDefaults(
22
+ defineProps<{
23
+ modelValue: (string | number)[] | null;
24
+ options: SelectOption[];
25
+ label?: string;
26
+ description?: string;
27
+ placeholder?: string;
28
+ size?: Size;
29
+ colorType?: InputColorType;
30
+ disabled?: boolean;
31
+ skeleton?: boolean;
32
+ validator?: FieldValidator;
33
+ name?: string;
34
+ showMessageOnError?: boolean;
35
+ expanded?: boolean;
36
+ icon?: IconDefinition;
37
+ grouped?: Grouped;
38
+ nullable?: boolean;
39
+
40
+ allowCreate?: boolean;
41
+ allowDuplicates?: boolean;
42
+ openOnFocus?: boolean;
43
+ autoCloseAfterSelection?: boolean;
44
+
45
+ createCallback?: (item: string) => Promise<SelectOption>;
46
+ }>(), {
47
+ size: Size.md,
48
+ colorType: InputColorType.base,
49
+ icon: () => faChevronRight,
50
+ grouped: Grouped.none,
51
+
52
+ allowCreate: false,
53
+ allowDuplicates: false,
54
+ openOnFocus: true,
55
+ autoCloseAfterSelection: false,
56
+ showMessageOnError: true,
57
+
58
+ placeholder: 'Add new tag'
59
+ }
60
+ );
61
+
62
+ const _modelValue: Ref<(string | number)[] | null> = useVModel(props, 'modelValue', emit);
63
+ const _skeleton = useVModel(props, 'skeleton', emit);
64
+
65
+ const dropDownOpen = ref(false);
66
+ const focusedDropDownItem: Ref<string | number | null> = ref(null);
67
+ const tagInput = ref('');
68
+ const filteredOptions = ref(props.options);
69
+
70
+ const inputRef: Ref<HTMLElement | null> = ref(null);
71
+
72
+ const _colorType = computed(() => props.validator?.hasErrors() ? InputColorType.danger : props.colorType);
73
+
74
+ const inputContainerClasses = computed(() => {
75
+ const variants: Record<InputColorType, string> = {
76
+ [InputColorType.base]: 'outline-neutral-300 focus-within:outline-primary-500 focus-within:ring-primary-200 bg-white',
77
+ [InputColorType.danger]: 'outline-danger-500 focus-within:outline-danger-500 focus-within:ring-danger-200 bg-danger-100',
78
+ [InputColorType.info]: 'outline-info-500 focus-within:outline-info-500 focus-within:ring-info-200 bg-info-100',
79
+ [InputColorType.success]: 'outline-success-500 focus-within:outline-success-500 focus-within:ring-success-200 bg-success-100',
80
+ [InputColorType.warning]: 'outline-warning-500 focus-within:outline-warning-500 focus-within:ring-warning-200 bg-warning-100',
81
+ };
82
+
83
+ return {
84
+ 'flex gap-1 items-center flex-wrap': true,
85
+ 'transition-colors relative border-none outline w-full focus-within:z-10': true,
86
+ 'outline-offset-[-1px] outline-1 focus-within:outline-offset-[-1px] focus-within:outline-1': true,
87
+ 'opacity-50 cursor-not-allowed': props.disabled,
88
+ [variants[_colorType.value]]: true,
89
+ // Size
90
+ 'focus-within:ring-2 px-1.5 py-1.5 text-xs': props.size === Size.sm,
91
+ 'focus-within:ring-4 px-2.5 py-1.5 text-sm': props.size === Size.md,
92
+ // Grouping
93
+ 'rounded-tl-md rounded-bl-md rounded-tr-none rounded-br-none': props.grouped === Grouped.left,
94
+ 'rounded-none': props.grouped === Grouped.center,
95
+ 'rounded-tl-none rounded-bl-none rounded-tr-md rounded-br-md': props.grouped === Grouped.right,
96
+ 'rounded-md': props.grouped === Grouped.none,
97
+ 'rounded-bl-none rounded-br-none': dropDownOpen.value && (!props.options || props.options.length > 0),
98
+ 'invisible': props.skeleton,
99
+ };
100
+ });
101
+
102
+ const inputClasses = computed(() => {
103
+ const variants: Record<InputColorType, string> = {
104
+ [InputColorType.base]: 'placeholder:text-neutral-500',
105
+ [InputColorType.danger]: 'placeholder:text-danger-700',
106
+ [InputColorType.info]: 'placeholder:text-info-700',
107
+ [InputColorType.success]: 'placeholder:text-success-700',
108
+ [InputColorType.warning]: 'placeholder:text-warning-700',
109
+ };
110
+
111
+ return {
112
+ 'outline-0 border:none ring:none bg-transparent w-full py-1': true,
113
+ 'opacity-50 cursor-not-allowed': props.disabled,
114
+ [variants[_colorType.value]]: true,
115
+ }
116
+ });
117
+
118
+ const skeletonGrouped = computed(() => {
119
+ if (!props.nullable || (props.nullable && _modelValue.value === null)) {
120
+ return props.grouped;
121
+ }
122
+
123
+ if (props.grouped === Grouped.right || props.grouped === Grouped.center) {
124
+ return Grouped.center;
125
+ } else {
126
+ return Grouped.left;
127
+ }
128
+ });
129
+
130
+ function onClickOutside() {
131
+ if (!dropDownOpen.value) {
132
+ return;
133
+ }
134
+
135
+ dropDownOpen.value = false;
136
+ }
137
+
138
+ async function checkCreateTag(item: string): Promise<void> {
139
+ if (props.allowCreate && focusedDropDownItem.value) {
140
+ // If allowCreate is active but a item is focused inside the dropdown do nothing here.
141
+ return;
142
+ }
143
+
144
+ if (item && props.allowCreate && props.createCallback) {
145
+ const newOption: SelectOption = await props.createCallback(item);
146
+
147
+ addTag(newOption.value);
148
+ }
149
+ }
150
+
151
+ function addTagFromOptions(item: string | number) {
152
+ if (props.allowCreate && !focusedDropDownItem.value) {
153
+ // If allowCreate is active we don't need to add it here.
154
+ return;
155
+ }
156
+
157
+ const option = props.options?.find(option => option.value === item);
158
+
159
+ if (option) {
160
+ addTag(item);
161
+
162
+ if (props.autoCloseAfterSelection) {
163
+ dropDownOpen.value = false;
164
+ }
165
+ }
166
+ }
167
+
168
+ function addTag(tagValue: string | number): void {
169
+ _modelValue.value = _modelValue.value || [];
170
+
171
+ if (!props.allowDuplicates && _modelValue.value.includes(tagValue) || !tagValue) {
172
+ return;
173
+ }
174
+
175
+ _modelValue.value.push(tagValue);
176
+
177
+ tagInput.value = '';
178
+
179
+ filterDropDown();
180
+ }
181
+
182
+ function removeLastTag() {
183
+ if (tagInput.value === '' && _modelValue.value && _modelValue.value.length > 0) {
184
+ _modelValue.value.splice(-1, 1);
185
+
186
+ filterDropDown();
187
+ }
188
+ }
189
+
190
+ function removeTag(tag: string | number) {
191
+ if (_modelValue.value && !props.disabled && !props.skeleton) {
192
+ _modelValue.value.splice(_modelValue.value.findIndex((_value) => _value === tag), 1);
193
+
194
+ filterDropDown();
195
+ }
196
+ }
197
+
198
+ function changeFocus() {
199
+ if (props.openOnFocus) {
200
+ dropDownOpen.value = true;
201
+ }
202
+ }
203
+
204
+ function filterDropDown() {
205
+ if (!props.options) {
206
+ return;
207
+ }
208
+
209
+ if (props.allowCreate) {
210
+ focusedDropDownItem.value = null;
211
+ }
212
+
213
+ dropDownOpen.value = true;
214
+
215
+ filteredOptions.value = props.options.filter(option => option.label.toLowerCase().includes(tagInput.value.toLowerCase()));
216
+
217
+ // Remove all elements that are in modelValue from the filtered options
218
+ if (_modelValue.value && !props.allowDuplicates) {
219
+ filteredOptions.value = filteredOptions.value.filter(option => !_modelValue.value?.includes(option.value));
220
+ }
221
+
222
+ if (!props.allowCreate && filteredOptions.value.length > 0) {
223
+ focusedDropDownItem.value = filteredOptions.value[0]?.value;
224
+ }
225
+ }
226
+ </script>
227
+
228
+ <template>
229
+ <AntField
230
+ :label="label"
231
+ :size="size"
232
+ :skeleton="_skeleton"
233
+ :description="description"
234
+ :color-type="colorType"
235
+ :validator="validator"
236
+ :show-message-on-error="showMessageOnError"
237
+ :expanded="expanded"
238
+ >
239
+ <div
240
+ class="relative w-full"
241
+ v-on-click-outside="onClickOutside"
242
+ >
243
+ <AntSkeleton
244
+ v-if="skeleton"
245
+ absolute
246
+ rounded
247
+ :grouped="skeletonGrouped"
248
+ />
249
+
250
+ <div
251
+ :class="inputContainerClasses"
252
+ class="w-full flex gap-2.5 items-center"
253
+ >
254
+ <AntTag
255
+ v-for="(tag, index) in _modelValue"
256
+ :key="`tag-input-tag-${index}`"
257
+ :size="size"
258
+ :color-type="_colorType"
259
+ dismiss
260
+ @close="removeTag(tag)"
261
+ >
262
+ {{ options.find((option: SelectOption) => option.value === tag)?.label }}
263
+ </AntTag>
264
+
265
+ <!-- Input -->
266
+ <div class="flex items-center gap-1 w-32 shrink grow">
267
+ <AntIcon :icon="icon" :size="size === Size.sm ? IconSize.xs : IconSize.sm"/>
268
+
269
+ <input
270
+ v-model="tagInput"
271
+ type="text"
272
+ ref="inputRef"
273
+ :placeholder="placeholder"
274
+ :class="inputClasses"
275
+ :disabled="disabled"
276
+ @focus="changeFocus"
277
+ @input="filterDropDown"
278
+ @keydown.delete="removeLastTag"
279
+ @keydown.enter.prevent="checkCreateTag(tagInput)"
280
+ />
281
+ </div>
282
+ </div>
283
+
284
+ <AntDropDown
285
+ v-if="filteredOptions && !disabled"
286
+ v-model:focused="focusedDropDownItem"
287
+ v-model:open="dropDownOpen"
288
+ ref="dropDownRef"
289
+ :model-value="null"
290
+ :auto-select-first-on-open="!allowCreate"
291
+ :options="filteredOptions"
292
+ :input-ref="inputRef"
293
+ :size="size"
294
+ :color-type="_colorType"
295
+ :focus-on-open="false"
296
+ @select-element="addTagFromOptions"
297
+ >
298
+ <template #empty>
299
+ <span v-if="allowCreate">
300
+ No tag found, create now
301
+ </span>
302
+ </template>
303
+ </AntDropDown>
304
+ </div>
305
+ </AntField>
306
+ </template>