@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
@@ -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>
@@ -7,30 +7,34 @@
7
7
  * TODO:: if the dropdown is open and the user types something, the element with a matching value should be focused.
8
8
  */
9
9
 
10
- import { computed, nextTick, ref, watch } from 'vue';
10
+ import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
11
11
  import { InputColorType, Size } from '../../../enums';
12
12
  import type { SelectOption } from '../__types';
13
13
  import { useVModel } from '@vueuse/core';
14
14
  import type { Validator } from '@antify/validate';
15
15
 
16
- const emit = defineEmits(['update:open', 'update:modelValue']);
16
+ const emit = defineEmits([ 'update:open', 'update:modelValue', 'update:focused', 'selectElement' ]);
17
17
  const props = withDefaults(defineProps<{
18
- modelValue: string | number | null;
18
+ modelValue: string | string[] | number | number[] | null;
19
+ focused: string | number | null;
19
20
  open: boolean;
20
21
  options: SelectOption[];
21
22
  colorType?: InputColorType;
22
23
  validator?: Validator;
23
24
  size?: Size;
24
- inputRef?: HTMLElement | null
25
+ inputRef?: HTMLElement | null;
26
+ closeOnEnter?: boolean;
27
+ autoSelectFirstOnOpen?: boolean;
25
28
  }>(), {
26
29
  colorType: InputColorType.base,
30
+ focusOnOpen: true,
31
+ closeOnEnter: false,
32
+ autoSelectFirstOnOpen: true
27
33
  });
28
34
 
29
35
  const _modelValue = useVModel(props, 'modelValue', emit);
30
36
  const isOpen = useVModel(props, 'open', emit);
31
-
32
- const focusedDropDownItem = ref<string | number | null>(null);
33
- const dropDownRef = ref<HTMLElement | null>(null);
37
+ const focusedDropDownItem = useVModel(props, 'focused', emit);
34
38
 
35
39
  const dropdownClasses = computed(() => {
36
40
  const variants: Record<InputColorType, string> = {
@@ -68,28 +72,45 @@ const dropDownItemClasses = computed(() => {
68
72
  };
69
73
  });
70
74
 
71
- watch(isOpen, (val) => {
75
+ watch(isOpen, () => {
72
76
  nextTick(() => {
73
- if (val) {
74
- dropDownRef.value?.focus();
75
- focusedDropDownItem.value = _modelValue.value || props.options[0].value;
77
+ if (props.autoSelectFirstOnOpen) {
78
+ focusedDropDownItem.value =
79
+ typeof _modelValue.value === 'string' || typeof _modelValue.value === 'number' ? _modelValue.value :
80
+ Array.isArray(_modelValue.value) ? _modelValue.value[0] :
81
+ props.options[0].value;
82
+ } else {
83
+ focusedDropDownItem.value = null;
76
84
  }
77
85
  });
78
86
  });
79
87
 
88
+ onMounted(() => {
89
+ nextTick(() => {
90
+ props.inputRef?.addEventListener('keydown', onKeyDownDropDown);
91
+ });
92
+ });
93
+
94
+ onUnmounted(() => {
95
+ props.inputRef?.removeEventListener('keydown', onKeyDownDropDown);
96
+ });
97
+
80
98
  function onKeyDownDropDown(e: KeyboardEvent) {
81
99
  if (e.key === 'Enter') {
82
- isOpen.value = false;
83
- _modelValue.value = focusedDropDownItem.value;
84
- props.inputRef?.focus();
100
+ if (props.closeOnEnter) {
101
+ isOpen.value = false;
102
+ }
103
+
104
+ emit('selectElement', focusedDropDownItem.value);
85
105
  }
86
106
 
87
107
  if (e.key === 'Escape') {
88
108
  isOpen.value = false;
89
- props.inputRef?.focus();
90
109
  }
91
110
 
92
111
  if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
112
+ isOpen.value = true;
113
+
93
114
  const index = props.options.findIndex(option => option.value === focusedDropDownItem.value);
94
115
  const option = props.options[index + 1];
95
116
 
@@ -101,6 +122,8 @@ function onKeyDownDropDown(e: KeyboardEvent) {
101
122
  }
102
123
 
103
124
  if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
125
+ isOpen.value = true;
126
+
104
127
  const index = props.options.findIndex(option => option.value === focusedDropDownItem.value);
105
128
  const option = props.options[index - 1];
106
129
 
@@ -123,7 +146,7 @@ function getActiveDropDownItemClasses(option: SelectOption) {
123
146
  [InputColorType.danger]: 'bg-danger-100/25',
124
147
  };
125
148
 
126
- return option.value === focusedDropDownItem.value ? {[variants[props.colorType]]: true} : {};
149
+ return option.value === focusedDropDownItem.value ? { [variants[props.colorType]]: true } : {};
127
150
  }
128
151
 
129
152
  function onClickDropDownItem(e: MouseEvent, value: string | number | null) {
@@ -131,17 +154,19 @@ function onClickDropDownItem(e: MouseEvent, value: string | number | null) {
131
154
  props.inputRef?.focus();
132
155
 
133
156
  isOpen.value = false;
157
+ emit('selectElement', value);
134
158
  _modelValue.value = value;
135
159
  }
160
+
161
+ watch(_modelValue, (val) => {
162
+ focusedDropDownItem.value = Array.isArray(val) ? val[0] : val;
163
+ });
136
164
  </script>
137
165
 
138
166
  <template>
139
167
  <div
140
168
  v-if="isOpen"
141
169
  :class="dropdownClasses"
142
- @keydown="onKeyDownDropDown"
143
- ref="dropDownRef"
144
- tabindex="0"
145
170
  >
146
171
  <div
147
172
  v-for="(option, index) in options"
@@ -152,9 +177,14 @@ function onClickDropDownItem(e: MouseEvent, value: string | number | null) {
152
177
  >
153
178
  {{ option.label }}
154
179
  </div>
180
+
181
+ <div
182
+ v-if="options.length === 0"
183
+ :class="{...dropDownItemClasses}"
184
+ >
185
+ <slot name="empty">
186
+ No options available
187
+ </slot>
188
+ </div>
155
189
  </div>
156
190
  </template>
157
-
158
- <style scoped>
159
-
160
- </style>
@@ -7,7 +7,7 @@ import {handleEnumValidation} from '../../../handler';
7
7
  import AntInputLimiter from './AntInputLimiter.vue';
8
8
  import {InputColorType} from '../../../enums';
9
9
 
10
- const emits = defineEmits(['clickLabel', 'validate']);
10
+ defineEmits(['clickLabel', 'validate']);
11
11
  const props = withDefaults(defineProps<{
12
12
  label?: string;
13
13
  description?: string;
@@ -25,7 +25,7 @@ const props = withDefaults(defineProps<{
25
25
  skeleton: false,
26
26
  size: Size.md,
27
27
  showMessageOnError: true,
28
- errors: [],
28
+ errors: () => [],
29
29
  expanded: true
30
30
  });
31
31
 
@@ -109,6 +109,9 @@ export const IconLeft = {
109
109
  }
110
110
  };
111
111
  export const Summary = {
112
+ parameters: {
113
+ chromatic: { disableSnapshot: false }
114
+ },
112
115
  render: (args) => ({
113
116
  components: { AntBaseInput, AntButton },
114
117
  setup: () => {
@@ -1,6 +1,7 @@
1
1
  export declare enum BaseInputType {
2
2
  date = "date",
3
3
  datetime = "datetime",
4
+ datetimeLocal = "datetime-local",
4
5
  email = "email",
5
6
  hidden = "hidden",
6
7
  month = "month",
@@ -1,6 +1,7 @@
1
1
  export var BaseInputType = /* @__PURE__ */ ((BaseInputType2) => {
2
2
  BaseInputType2["date"] = "date";
3
3
  BaseInputType2["datetime"] = "datetime";
4
+ BaseInputType2["datetimeLocal"] = "datetime-local";
4
5
  BaseInputType2["email"] = "email";
5
6
  BaseInputType2["hidden"] = "hidden";
6
7
  BaseInputType2["month"] = "month";
@@ -144,6 +144,9 @@ export const ellipsisText = {
144
144
  }
145
145
  };
146
146
  export const summary = {
147
+ parameters: {
148
+ chromatic: { disableSnapshot: false }
149
+ },
147
150
  render: (args) => ({
148
151
  components: { AntSelect },
149
152
  setup() {
@@ -46,6 +46,9 @@ export const withValidator = {
46
46
  }
47
47
  };
48
48
  export const Summary = {
49
+ parameters: {
50
+ chromatic: { disableSnapshot: false }
51
+ },
49
52
  render: (args) => ({
50
53
  components: { AntSwitch },
51
54
  setup() {
@@ -85,6 +85,9 @@ export const withValidator = {
85
85
  }
86
86
  };
87
87
  export const Summary = {
88
+ parameters: {
89
+ chromatic: { disableSnapshot: false }
90
+ },
88
91
  render: (args) => ({
89
92
  components: { AntSwitcher },
90
93
  setup() {
@@ -0,0 +1,9 @@
1
+ import { AntTagInput } from '../index';
2
+ import type { Meta, StoryObj } from '@storybook/vue3';
3
+ declare const meta: Meta<typeof AntTagInput>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof AntTagInput>;
6
+ export declare const Docs: Story;
7
+ export declare const AllowCreate: Story;
8
+ export declare const Disabled: Story;
9
+ export declare const Skeleton: Story;
@@ -0,0 +1,106 @@
1
+ import { AntTagInput } from "../index.mjs";
2
+ import { ref } from "vue";
3
+ import { InputColorType, Size } from "../../../enums/index.mjs";
4
+ const meta = {
5
+ title: "Components/Forms/Tag input",
6
+ component: AntTagInput,
7
+ argTypes: {
8
+ modelValue: {
9
+ control: "text",
10
+ table: { type: { summary: "string|null" } }
11
+ },
12
+ colorType: {
13
+ control: { type: "select" },
14
+ options: Object.values(InputColorType)
15
+ },
16
+ size: {
17
+ control: { type: "radio" },
18
+ options: Object.values(Size),
19
+ table: { defaultValue: { summary: Size.md } }
20
+ },
21
+ placeholder: {
22
+ table: { defaultValue: { summary: "this.label" } }
23
+ },
24
+ createCallback: {
25
+ control: "none",
26
+ description: "If allowCreate is true the createCallback needs to be specified. It will be called when the user creates a new tag. It should return a promise that resolves to a SelectOption.",
27
+ table: {
28
+ type: {
29
+ summary: "(item: string) => Promise<SelectOption>",
30
+ detail: `
31
+ Params:
32
+ item: string - the label of the new tag
33
+
34
+ Returns:
35
+ Promise<SelectOption> - the new tag as a SelectOption
36
+ `
37
+ }
38
+ }
39
+ }
40
+ }
41
+ };
42
+ export default meta;
43
+ const options = [
44
+ {
45
+ label: "Tag",
46
+ value: "1"
47
+ },
48
+ {
49
+ label: "Cat",
50
+ value: "2"
51
+ },
52
+ {
53
+ label: "Dog",
54
+ value: "3"
55
+ },
56
+ {
57
+ label: "Chicken",
58
+ value: "4"
59
+ }
60
+ ];
61
+ export const Docs = {
62
+ render: (args) => ({
63
+ components: { AntTagInput },
64
+ setup() {
65
+ const value = ref([]);
66
+ return {
67
+ args,
68
+ value
69
+ };
70
+ },
71
+ template: `
72
+ <div style="width: 360px">
73
+ <AntTagInput v-model="value" v-bind="args"/>
74
+ </div>
75
+ `
76
+ }),
77
+ args: {
78
+ options
79
+ }
80
+ };
81
+ export const AllowCreate = {
82
+ render: Docs.render,
83
+ args: {
84
+ options,
85
+ allowCreate: true,
86
+ createCallback(item) {
87
+ return new Promise((resolve) => {
88
+ resolve({ label: item, value: `${Math.random()}-${item}` });
89
+ });
90
+ }
91
+ }
92
+ };
93
+ export const Disabled = {
94
+ render: Docs.render,
95
+ args: {
96
+ options,
97
+ disabled: true
98
+ }
99
+ };
100
+ export const Skeleton = {
101
+ render: Docs.render,
102
+ args: {
103
+ options,
104
+ skeleton: true
105
+ }
106
+ };
@@ -86,6 +86,9 @@ export const limited = {
86
86
  }
87
87
  };
88
88
  export const summary = {
89
+ parameters: {
90
+ chromatic: { disableSnapshot: false }
91
+ },
89
92
  render: (args, ctx) => ({
90
93
  // @ts-ignore
91
94
  components: Docs.render(args, ctx).components,
@@ -5,7 +5,8 @@ import AntSwitcher from './AntSwitcher.vue';
5
5
  import AntSearch from './AntSearch.vue';
6
6
  import AntSelect from './AntSelect.vue';
7
7
  import AntSwitch from './AntSwitch.vue';
8
+ import AntTagInput from './AntTagInput.vue';
8
9
  import AntTextarea from './AntTextarea.vue';
9
10
  import AntTextInput from './AntTextInput.vue';
10
11
  import AntUnitInput from './AntUnitInput.vue';
11
- export { AntButton, AntNumberInput, AntRangeSlider, AntSwitcher, AntSearch, AntSelect, AntSwitch, AntTextarea, AntTextInput, AntUnitInput, };
12
+ export { AntButton, AntNumberInput, AntRangeSlider, AntSwitcher, AntSearch, AntSelect, AntSwitch, AntTagInput, AntTextarea, AntTextInput, AntUnitInput, };
@@ -5,6 +5,7 @@ import AntSwitcher from "./AntSwitcher.vue";
5
5
  import AntSearch from "./AntSearch.vue";
6
6
  import AntSelect from "./AntSelect.vue";
7
7
  import AntSwitch from "./AntSwitch.vue";
8
+ import AntTagInput from "./AntTagInput.vue";
8
9
  import AntTextarea from "./AntTextarea.vue";
9
10
  import AntTextInput from "./AntTextInput.vue";
10
11
  import AntUnitInput from "./AntUnitInput.vue";
@@ -16,6 +17,7 @@ export {
16
17
  AntSearch,
17
18
  AntSelect,
18
19
  AntSwitch,
20
+ AntTagInput,
19
21
  AntTextarea,
20
22
  AntTextInput,
21
23
  AntUnitInput