@antify/ui 1.0.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.
- package/dist/components/AntAccordion.vue +32 -7
- package/dist/components/AntAccordionItem.vue +48 -15
- package/dist/components/AntAlert.vue +8 -6
- package/dist/components/AntDropdown.vue +50 -36
- package/dist/components/AntIcon.vue +8 -6
- package/dist/components/AntKeycap.vue +22 -17
- package/dist/components/AntListGroup.vue +5 -3
- package/dist/components/AntModal.vue +17 -7
- package/dist/components/AntPopover.vue +118 -42
- package/dist/components/AntSkeleton.vue +1 -1
- package/dist/components/AntTooltip.vue +102 -76
- package/dist/components/__stories/AntAccordion.stories.d.ts +1 -0
- package/dist/components/__stories/AntAccordion.stories.js +73 -1
- package/dist/components/__stories/AntAccordion.stories.mjs +68 -0
- package/dist/components/__stories/AntDropdown.stories.js +27 -23
- package/dist/components/__stories/AntDropdown.stories.mjs +26 -22
- package/dist/components/__stories/AntKeycap.stories.js +13 -15
- package/dist/components/__stories/AntKeycap.stories.mjs +13 -13
- package/dist/components/__stories/AntListGroup.stories.js +1 -1
- package/dist/components/__stories/AntListGroup.stories.mjs +1 -1
- package/dist/components/__stories/AntModal.stories.js +2 -1
- package/dist/components/__stories/AntModal.stories.mjs +2 -1
- package/dist/components/__stories/AntPopover.stories.js +22 -21
- package/dist/components/__stories/AntPopover.stories.mjs +22 -20
- package/dist/components/__stories/AntTooltip.stories.d.ts +0 -10
- package/dist/components/__stories/AntTooltip.stories.js +32 -212
- package/dist/components/__stories/AntTooltip.stories.mjs +29 -193
- package/dist/components/__types/AntKeycap.types.d.ts +1 -0
- package/dist/components/__types/AntKeycap.types.js +1 -0
- package/dist/components/__types/AntKeycap.types.mjs +1 -0
- package/dist/components/buttons/AntButton.vue +41 -44
- package/dist/components/crud/AntCrud.vue +1 -1
- package/dist/components/crud/AntCrudDetailActions.vue +1 -0
- package/dist/components/crud/AntCrudTableFilter.vue +20 -18
- package/dist/components/forms/AntField.vue +7 -2
- package/dist/components/forms/__stories/AntField.stories.js +0 -16
- package/dist/components/forms/__stories/AntField.stories.mjs +2 -16
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.js +7 -7
- package/dist/components/index.mjs +2 -2
- package/dist/components/inputs/AntCheckbox.vue +25 -6
- package/dist/components/inputs/AntDateInput.vue +1 -1
- package/dist/components/inputs/AntRadio.vue +2 -1
- package/dist/components/inputs/AntSelect.vue +25 -22
- package/dist/components/inputs/AntSwitch.vue +2 -7
- package/dist/components/inputs/AntTagInput.vue +91 -114
- package/dist/components/inputs/AntTextarea.vue +7 -3
- package/dist/components/inputs/Elements/AntBaseInput.vue +2 -2
- package/dist/components/inputs/Elements/{AntDropDown.vue → AntSelectMenu.vue} +85 -40
- package/dist/components/inputs/Elements/__stories/AntBaseInput.stories.d.ts +0 -1
- package/dist/components/inputs/Elements/__stories/AntBaseInput.stories.js +1 -29
- package/dist/components/inputs/Elements/__stories/AntBaseInput.stories.mjs +0 -22
- package/dist/components/inputs/Elements/index.d.ts +2 -1
- package/dist/components/inputs/Elements/index.js +7 -0
- package/dist/components/inputs/Elements/index.mjs +3 -1
- package/dist/components/inputs/__stories/AntCheckbox.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntCheckbox.stories.js +1 -43
- package/dist/components/inputs/__stories/AntCheckbox.stories.mjs +0 -35
- package/dist/components/inputs/__stories/AntCheckboxGroup.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntCheckboxGroup.stories.js +1 -31
- package/dist/components/inputs/__stories/AntCheckboxGroup.stories.mjs +0 -28
- package/dist/components/inputs/__stories/AntDateInput.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntDateInput.stories.js +1 -32
- package/dist/components/inputs/__stories/AntDateInput.stories.mjs +0 -28
- package/dist/components/inputs/__stories/AntNumberInput.stories.d.ts +0 -2
- package/dist/components/inputs/__stories/AntNumberInput.stories.js +1 -65
- package/dist/components/inputs/__stories/AntNumberInput.stories.mjs +1 -54
- package/dist/components/inputs/__stories/AntPasswordInput.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntPasswordInput.stories.js +1 -35
- package/dist/components/inputs/__stories/AntPasswordInput.stories.mjs +0 -25
- package/dist/components/inputs/__stories/AntRadioGroup.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntRadioGroup.stories.js +1 -47
- package/dist/components/inputs/__stories/AntRadioGroup.stories.mjs +0 -46
- package/dist/components/inputs/__stories/AntRangeSlider.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntRangeSlider.stories.js +1 -33
- package/dist/components/inputs/__stories/AntRangeSlider.stories.mjs +1 -28
- package/dist/components/inputs/__stories/AntSelect.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntSelect.stories.js +18 -46
- package/dist/components/inputs/__stories/AntSelect.stories.mjs +16 -47
- package/dist/components/inputs/__stories/AntSwitch.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntSwitch.stories.js +1 -42
- package/dist/components/inputs/__stories/AntSwitch.stories.mjs +1 -37
- package/dist/components/inputs/__stories/AntSwitcher.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntSwitcher.stories.js +1 -51
- package/dist/components/inputs/__stories/AntSwitcher.stories.mjs +1 -51
- package/dist/components/inputs/__stories/AntTagInput.stories.d.ts +0 -1
- package/dist/components/inputs/__stories/AntTagInput.stories.js +1 -35
- package/dist/components/inputs/__stories/AntTagInput.stories.mjs +0 -33
- package/dist/components/inputs/__stories/AntTextInput.stories.d.ts +0 -2
- package/dist/components/inputs/__stories/AntTextInput.stories.js +1 -107
- package/dist/components/inputs/__stories/AntTextInput.stories.mjs +0 -104
- package/dist/components/inputs/__stories/AntTextarea.stories.d.ts +0 -2
- package/dist/components/inputs/__stories/AntTextarea.stories.js +7 -66
- package/dist/components/inputs/__stories/AntTextarea.stories.mjs +6 -55
- package/dist/components/inputs/__stories/AntUnitInput.stories.d.ts +0 -2
- package/dist/components/inputs/__stories/AntUnitInput.stories.js +1 -61
- package/dist/components/inputs/__stories/AntUnitInput.stories.mjs +0 -53
- package/dist/components/table/AntTable.vue +17 -15
- package/dist/components/table/AntTd.vue +1 -2
- package/dist/components/table/__stories/AntTable.stories.js +7 -14
- package/dist/components/table/__stories/AntTable.stories.mjs +7 -15
- package/dist/components/tabs/AntTabItem.vue +16 -6
- package/dist/components/tabs/AntTabs.vue +8 -0
- package/dist/components/tabs/__types/AntTabItem.types.d.ts +1 -0
- package/package.json +2 -1
|
@@ -8,7 +8,7 @@ import {computed, onMounted, type Ref, ref, watch} from 'vue';
|
|
|
8
8
|
import AntTag from '../AntTag.vue';
|
|
9
9
|
import AntIcon from '../AntIcon.vue';
|
|
10
10
|
import {AntTagSize, IconSize} from '../__types';
|
|
11
|
-
import
|
|
11
|
+
import AntSelectMenu from './Elements/AntSelectMenu.vue';
|
|
12
12
|
import AntSkeleton from '../AntSkeleton.vue';
|
|
13
13
|
import {vOnClickOutside} from '@vueuse/components';
|
|
14
14
|
import {AntTagInputSize} from './__types/AntTagInput.types';
|
|
@@ -61,7 +61,6 @@ const dropDownOpen = ref(false);
|
|
|
61
61
|
const hasInputState = computed(() => props.skeleton || props.readonly || props.disabled);
|
|
62
62
|
const focusedDropDownItem: Ref<string | number | null> = ref(null);
|
|
63
63
|
const tagInput = ref('');
|
|
64
|
-
const filteredOptions = ref(props.options);
|
|
65
64
|
const inputRef: Ref<HTMLElement | null> = ref(null);
|
|
66
65
|
const inputContainerClasses = computed(() => {
|
|
67
66
|
const variants: Record<InputState, string> = {
|
|
@@ -89,7 +88,6 @@ const inputContainerClasses = computed(() => {
|
|
|
89
88
|
'rounded-none': props.grouped === Grouped.center,
|
|
90
89
|
'rounded-tl-none rounded-bl-none rounded-tr-md rounded-br-md': props.grouped === Grouped.right,
|
|
91
90
|
'rounded-md': props.grouped === Grouped.none,
|
|
92
|
-
'rounded-bl-none rounded-br-none': dropDownOpen.value && (!props.options || props.options.length > 0) && !props.readonly,
|
|
93
91
|
'invisible': props.skeleton,
|
|
94
92
|
};
|
|
95
93
|
});
|
|
@@ -119,13 +117,23 @@ const skeletonGrouped = computed(() => {
|
|
|
119
117
|
return Grouped.left;
|
|
120
118
|
}
|
|
121
119
|
});
|
|
120
|
+
const filteredOptions = computed(() => {
|
|
121
|
+
return props.options.filter(option => {
|
|
122
|
+
// Remove all elements that are in modelValue from the filtered options
|
|
123
|
+
if (_modelValue.value && !props.allowDuplicates) {
|
|
124
|
+
return !_modelValue.value?.includes(option.value);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return option.label.toLowerCase().includes(tagInput.value.toLowerCase())
|
|
128
|
+
});
|
|
129
|
+
})
|
|
122
130
|
|
|
123
131
|
function onClickOutside() {
|
|
124
132
|
if (!dropDownOpen.value) {
|
|
125
133
|
return;
|
|
126
134
|
}
|
|
127
|
-
|
|
128
|
-
dropDownOpen.value = false;
|
|
135
|
+
console.log("click outside");
|
|
136
|
+
// dropDownOpen.value = false;
|
|
129
137
|
}
|
|
130
138
|
|
|
131
139
|
async function checkCreateTag(item: string): Promise<void> {
|
|
@@ -153,14 +161,13 @@ function addTagFromOptions(item: string | number) {
|
|
|
153
161
|
addTag(item);
|
|
154
162
|
|
|
155
163
|
if (props.autoCloseAfterSelection) {
|
|
164
|
+
console.log("HIER");
|
|
156
165
|
dropDownOpen.value = false;
|
|
157
166
|
}
|
|
158
167
|
}
|
|
159
168
|
}
|
|
160
169
|
|
|
161
170
|
function addTag(tagValue: string | number): void {
|
|
162
|
-
_modelValue.value = _modelValue.value || [];
|
|
163
|
-
|
|
164
171
|
if (!props.allowDuplicates && _modelValue.value?.includes(tagValue) || !tagValue) {
|
|
165
172
|
return;
|
|
166
173
|
}
|
|
@@ -172,53 +179,22 @@ function addTag(tagValue: string | number): void {
|
|
|
172
179
|
}
|
|
173
180
|
|
|
174
181
|
tagInput.value = '';
|
|
175
|
-
|
|
176
|
-
filterDropDown();
|
|
177
182
|
}
|
|
178
183
|
|
|
179
184
|
function removeLastTag() {
|
|
180
185
|
if (tagInput.value === '' && Array.isArray(_modelValue.value) && _modelValue.value.length > 0) {
|
|
181
186
|
_modelValue.value.splice(-1, 1);
|
|
182
|
-
|
|
183
|
-
filterDropDown();
|
|
184
187
|
}
|
|
185
188
|
}
|
|
186
189
|
|
|
187
190
|
function removeTag(tag: string | number) {
|
|
188
191
|
if (_modelValue.value && !props.disabled && !props.skeleton && !props.readonly) {
|
|
189
192
|
_modelValue.value.splice(_modelValue.value.findIndex((_value) => _value === tag), 1);
|
|
190
|
-
|
|
191
|
-
filterDropDown();
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
function changeFocus() {
|
|
196
|
-
if (props.openOnFocus) {
|
|
197
|
-
dropDownOpen.value = true;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function filterDropDown() {
|
|
202
|
-
if (!props.options) {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (props.allowCreate) {
|
|
207
|
-
focusedDropDownItem.value = null;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
197
|
dropDownOpen.value = true;
|
|
211
|
-
|
|
212
|
-
filteredOptions.value = props.options.filter(option => option.label.toLowerCase().includes(tagInput.value.toLowerCase()));
|
|
213
|
-
|
|
214
|
-
// Remove all elements that are in modelValue from the filtered options
|
|
215
|
-
if (_modelValue.value && !props.allowDuplicates) {
|
|
216
|
-
filteredOptions.value = filteredOptions.value.filter(option => !_modelValue.value?.includes(option.value));
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (!props.allowCreate && filteredOptions.value.length > 0) {
|
|
220
|
-
focusedDropDownItem.value = filteredOptions.value[0]?.value;
|
|
221
|
-
}
|
|
222
198
|
}
|
|
223
199
|
|
|
224
200
|
function onBlur(e: FocusEvent) {
|
|
@@ -251,89 +227,90 @@ onMounted(() => {
|
|
|
251
227
|
</script>
|
|
252
228
|
|
|
253
229
|
<template>
|
|
254
|
-
<
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
<div
|
|
264
|
-
v-on-click-outside="onClickOutside"
|
|
265
|
-
class="relative w-full"
|
|
230
|
+
<div>
|
|
231
|
+
<AntField
|
|
232
|
+
:label="label"
|
|
233
|
+
:size="size as unknown as Size"
|
|
234
|
+
:skeleton="_skeleton"
|
|
235
|
+
:description="description"
|
|
236
|
+
:state="state"
|
|
237
|
+
:expanded="expanded"
|
|
238
|
+
:messages="messages"
|
|
266
239
|
>
|
|
267
|
-
<AntSkeleton
|
|
268
|
-
v-if="skeleton"
|
|
269
|
-
absolute
|
|
270
|
-
rounded
|
|
271
|
-
:grouped="skeletonGrouped"
|
|
272
|
-
/>
|
|
273
|
-
|
|
274
240
|
<div
|
|
275
|
-
|
|
276
|
-
class="w-full flex items-center"
|
|
241
|
+
class="relative w-full"
|
|
277
242
|
>
|
|
243
|
+
<AntSkeleton
|
|
244
|
+
v-if="skeleton"
|
|
245
|
+
absolute
|
|
246
|
+
rounded
|
|
247
|
+
:grouped="skeletonGrouped"
|
|
248
|
+
/>
|
|
249
|
+
|
|
278
250
|
<div
|
|
279
|
-
class="
|
|
251
|
+
:class="inputContainerClasses"
|
|
252
|
+
class="w-full flex items-center"
|
|
253
|
+
v-on-click-outside="onClickOutside"
|
|
280
254
|
>
|
|
281
|
-
<
|
|
282
|
-
|
|
283
|
-
:key="`tag-input-tag-${index}`"
|
|
284
|
-
:size="AntTagSize.xs3"
|
|
285
|
-
:state="state as unknown as TagState"
|
|
286
|
-
:dismiss="!readonly"
|
|
287
|
-
@close="removeTag(tag)"
|
|
255
|
+
<div
|
|
256
|
+
class="flex gap-2.5 items-center"
|
|
288
257
|
>
|
|
289
|
-
|
|
290
|
-
|
|
258
|
+
<AntTag
|
|
259
|
+
v-for="(tag, index) in _modelValue"
|
|
260
|
+
:key="`tag-input-tag-${index}`"
|
|
261
|
+
:size="AntTagSize.xs3"
|
|
262
|
+
:state="state as unknown as TagState"
|
|
263
|
+
:dismiss="!readonly"
|
|
264
|
+
@close="removeTag(tag)"
|
|
265
|
+
>
|
|
266
|
+
{{ options.find((option: SelectOption) => option.value === tag)?.label }}
|
|
267
|
+
</AntTag>
|
|
268
|
+
</div>
|
|
269
|
+
|
|
270
|
+
<!-- Input -->
|
|
271
|
+
<div class="flex items-center w-32 shrink grow">
|
|
272
|
+
<AntIcon
|
|
273
|
+
:icon="icon"
|
|
274
|
+
:size="size === AntTagInputSize.sm ? IconSize.xs : IconSize.sm"
|
|
275
|
+
/>
|
|
276
|
+
|
|
277
|
+
<input
|
|
278
|
+
ref="inputRef"
|
|
279
|
+
v-model="tagInput"
|
|
280
|
+
type="text"
|
|
281
|
+
:placeholder="placeholder"
|
|
282
|
+
:class="inputClasses"
|
|
283
|
+
:disabled="disabled"
|
|
284
|
+
:readonly="readonly"
|
|
285
|
+
@focus="changeFocus"
|
|
286
|
+
@keydown.delete="removeLastTag"
|
|
287
|
+
@keydown.enter.prevent="checkCreateTag(tagInput)"
|
|
288
|
+
@blur="onBlur"
|
|
289
|
+
/>
|
|
290
|
+
</div>
|
|
291
291
|
</div>
|
|
292
292
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
/>
|
|
314
|
-
</div>
|
|
293
|
+
<AntSelectMenu
|
|
294
|
+
v-if="!disabled && !readonly"
|
|
295
|
+
v-model:focused="focusedDropDownItem"
|
|
296
|
+
v-model:open="dropDownOpen"
|
|
297
|
+
:model-value="null"
|
|
298
|
+
:auto-select-first-on-open="!allowCreate"
|
|
299
|
+
:options="filteredOptions"
|
|
300
|
+
:input-ref="inputRef"
|
|
301
|
+
:size="size as unknown as Size"
|
|
302
|
+
:state="state"
|
|
303
|
+
:focus-on-open="false"
|
|
304
|
+
:close-on-select-item="false"
|
|
305
|
+
@select-element="addTagFromOptions"
|
|
306
|
+
>
|
|
307
|
+
<template #empty>
|
|
308
|
+
<span v-if="allowCreate">
|
|
309
|
+
No tag found, create now
|
|
310
|
+
</span>
|
|
311
|
+
</template>
|
|
312
|
+
</AntSelectMenu>
|
|
315
313
|
</div>
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
v-if="filteredOptions && !disabled && !readonly"
|
|
319
|
-
ref="dropDownRef"
|
|
320
|
-
v-model:focused="focusedDropDownItem"
|
|
321
|
-
v-model:open="dropDownOpen"
|
|
322
|
-
:model-value="null"
|
|
323
|
-
:auto-select-first-on-open="!allowCreate"
|
|
324
|
-
:options="filteredOptions"
|
|
325
|
-
:input-ref="inputRef"
|
|
326
|
-
:size="size as unknown as Size"
|
|
327
|
-
:state="state"
|
|
328
|
-
:focus-on-open="false"
|
|
329
|
-
@select-element="addTagFromOptions"
|
|
330
|
-
>
|
|
331
|
-
<template #empty>
|
|
332
|
-
<span v-if="allowCreate">
|
|
333
|
-
No tag found, create now
|
|
334
|
-
</span>
|
|
335
|
-
</template>
|
|
336
|
-
</AntDropDown>
|
|
337
|
-
</div>
|
|
338
|
-
</AntField>
|
|
314
|
+
</AntField>
|
|
315
|
+
</div>
|
|
339
316
|
</template>
|
|
@@ -36,6 +36,7 @@ const props = withDefaults(defineProps<{
|
|
|
36
36
|
limiter?: boolean;
|
|
37
37
|
max?: number;
|
|
38
38
|
messages?: string[];
|
|
39
|
+
resize?: boolean;
|
|
39
40
|
}>(), {
|
|
40
41
|
state: InputState.base,
|
|
41
42
|
disabled: false,
|
|
@@ -45,6 +46,7 @@ const props = withDefaults(defineProps<{
|
|
|
45
46
|
grouped: Grouped.none,
|
|
46
47
|
showIcon: true,
|
|
47
48
|
limiter: false,
|
|
49
|
+
resize: true,
|
|
48
50
|
messages: () => []
|
|
49
51
|
});
|
|
50
52
|
const _modelValue = useVModel(props, 'modelValue', emit);
|
|
@@ -67,7 +69,7 @@ const inputClasses = computed(() => {
|
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
return {
|
|
70
|
-
'block transition-colors relative border-none outline w-full focus:z-10': true,
|
|
72
|
+
'block transition-colors relative border-none outline w-full focus:z-10 h-full text-black': true,
|
|
71
73
|
'outline-offset-[-1px] outline-1 focus:outline-offset-[-1px] focus:outline-1': true,
|
|
72
74
|
'disabled:opacity-50 disabled:cursor-not-allowed': props.disabled,
|
|
73
75
|
[variants[props.state]]: true,
|
|
@@ -90,7 +92,8 @@ const inputClasses = computed(() => {
|
|
|
90
92
|
'rounded-none': props.grouped === Grouped.center,
|
|
91
93
|
'rounded-tl-none rounded-bl-none rounded-tr-md rounded-br-md': props.grouped === Grouped.right,
|
|
92
94
|
'rounded-md': props.grouped === Grouped.none,
|
|
93
|
-
'invisible': props.skeleton
|
|
95
|
+
'invisible': props.skeleton,
|
|
96
|
+
'resize-none': !props.resize
|
|
94
97
|
};
|
|
95
98
|
});
|
|
96
99
|
const iconColor = computed(() => {
|
|
@@ -153,9 +156,10 @@ function onBlur(e: FocusEvent) {
|
|
|
153
156
|
:limiter-max-value="limiter && max !== undefined ? max : undefined"
|
|
154
157
|
:limiter-value="limiter ? _modelValue?.length : undefined"
|
|
155
158
|
:messages="messages"
|
|
159
|
+
:expanded-height="!resize"
|
|
156
160
|
>
|
|
157
161
|
<div
|
|
158
|
-
class="block relative w-full"
|
|
162
|
+
class="block relative w-full h-full"
|
|
159
163
|
:class="{...{'-mr-px': grouped !== Grouped.none}, ..._wrapperClass}"
|
|
160
164
|
>
|
|
161
165
|
<textarea
|
|
@@ -68,7 +68,7 @@ const inputClasses = computed(() => {
|
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
return {
|
|
71
|
-
'block transition-colors relative border-none outline w-full focus:z-10 text-black': true,
|
|
71
|
+
'block transition-colors relative border-none outline w-full focus:z-10 text-black font-regular': true,
|
|
72
72
|
'outline-offset-[-1px] outline-1 focus:outline-offset-[-1px] focus:outline-1': true,
|
|
73
73
|
'disabled:opacity-50 disabled:cursor-not-allowed': props.disabled,
|
|
74
74
|
'text-right': props.type === BaseInputType.number,
|
|
@@ -235,7 +235,7 @@ function onClickClearIcon() {
|
|
|
235
235
|
<div
|
|
236
236
|
v-if="(nullable && _modelValue !== null && _modelValue !== '') || (showIcon && icon) || hasSlotContent(slot['icon-right'])"
|
|
237
237
|
class="absolute h-full flex items-center justify-center right-0 top-0 transition-all z-20"
|
|
238
|
-
:class="{'w-6': size === Size.xs2, 'w-7': size === Size.
|
|
238
|
+
:class="{'w-6': size === Size.xs2, 'w-7': size === Size.xs, 'w-8': size === Size.sm, 'w-9': size === Size.md, 'w-10': size === Size.lg}"
|
|
239
239
|
>
|
|
240
240
|
<slot name="icon-right">
|
|
241
241
|
<AntIcon
|
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
* Fix overflow bug (See Ellipsis Text story)
|
|
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
|
-
|
|
10
9
|
import {computed, nextTick, onMounted, onUnmounted, ref, watch} from 'vue';
|
|
11
10
|
import {InputState, Size} from '../../../enums';
|
|
12
11
|
import type {SelectOption} from '../__types';
|
|
13
|
-
import {useVModel} from '@vueuse/core';
|
|
12
|
+
import {useElementSize, useVModel, onClickOutside} from '@vueuse/core';
|
|
14
13
|
import type {Validator} from '@antify/validate';
|
|
14
|
+
import {autoUpdate, flip, offset, useFloating} from "@floating-ui/vue";
|
|
15
|
+
import {vOnClickOutside} from '@vueuse/components';
|
|
15
16
|
|
|
16
17
|
const emit = defineEmits(['update:open', 'update:modelValue', 'update:focused', 'selectElement']);
|
|
17
18
|
const props = withDefaults(defineProps<{
|
|
@@ -25,17 +26,40 @@ const props = withDefaults(defineProps<{
|
|
|
25
26
|
inputRef?: HTMLElement | null;
|
|
26
27
|
closeOnEnter?: boolean;
|
|
27
28
|
autoSelectFirstOnOpen?: boolean;
|
|
29
|
+
closeOnSelectItem?: boolean;
|
|
28
30
|
}>(), {
|
|
29
31
|
state: InputState.base,
|
|
30
32
|
focusOnOpen: true,
|
|
31
33
|
closeOnEnter: false,
|
|
32
|
-
autoSelectFirstOnOpen: true
|
|
34
|
+
autoSelectFirstOnOpen: true,
|
|
35
|
+
closeOnSelectItem: true,
|
|
36
|
+
});
|
|
37
|
+
const reference = ref<HTMLElement | null | undefined>(props.inputRef)
|
|
38
|
+
const width = useElementSize(reference);
|
|
39
|
+
const floating = ref<HTMLElement | null>(null)
|
|
40
|
+
const {floatingStyles, middlewareData, placement} = useFloating(reference, floating, {
|
|
41
|
+
placement: 'bottom',
|
|
42
|
+
whileElementsMounted: autoUpdate,
|
|
43
|
+
middleware: [
|
|
44
|
+
offset(8),
|
|
45
|
+
flip({
|
|
46
|
+
fallbackPlacements: ['top'],
|
|
47
|
+
}),
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
onClickOutside(floating, () => {
|
|
52
|
+
console.log(props.open);
|
|
53
|
+
if (!props.open) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
emit('update:open', false);
|
|
33
58
|
});
|
|
34
59
|
|
|
35
60
|
const _modelValue = useVModel(props, 'modelValue', emit);
|
|
36
61
|
const isOpen = useVModel(props, 'open', emit);
|
|
37
62
|
const focusedDropDownItem = useVModel(props, 'focused', emit);
|
|
38
|
-
|
|
39
63
|
const dropdownClasses = computed(() => {
|
|
40
64
|
const variants: Record<InputState, string> = {
|
|
41
65
|
[InputState.base]: 'bg-neutral-300 border-neutral-300',
|
|
@@ -46,11 +70,9 @@ const dropdownClasses = computed(() => {
|
|
|
46
70
|
};
|
|
47
71
|
|
|
48
72
|
return {
|
|
49
|
-
'
|
|
50
|
-
'rounded-
|
|
73
|
+
'w-full border flex flex-col gap-px outline-none -mt-px overflow-hidden shadow-md z-[90]': true,
|
|
74
|
+
'rounded-md': true,
|
|
51
75
|
[variants[props.state]]: true,
|
|
52
|
-
// Size
|
|
53
|
-
'text-sm': props.size === Size.sm || props.size === Size.md
|
|
54
76
|
};
|
|
55
77
|
});
|
|
56
78
|
const dropDownItemClasses = computed(() => {
|
|
@@ -66,8 +88,11 @@ const dropDownItemClasses = computed(() => {
|
|
|
66
88
|
'select-none text-ellipsis overflow-hidden whitespace-nowrap': true,
|
|
67
89
|
[variants[props.state]]: true,
|
|
68
90
|
// Size
|
|
69
|
-
'p-1
|
|
70
|
-
'p-
|
|
91
|
+
'p-1 text-xs': props.size === Size.xs2,
|
|
92
|
+
'p-1.5 text-xs': props.size === Size.xs,
|
|
93
|
+
'p-1.5 text-sm': props.size === Size.sm,
|
|
94
|
+
'p-2 text-sm': props.size === Size.md,
|
|
95
|
+
'p-2.5 text-sm': props.size === Size.lg,
|
|
71
96
|
};
|
|
72
97
|
});
|
|
73
98
|
|
|
@@ -86,12 +111,12 @@ watch(isOpen, () => {
|
|
|
86
111
|
|
|
87
112
|
onMounted(() => {
|
|
88
113
|
nextTick(() => {
|
|
89
|
-
|
|
114
|
+
reference.value?.addEventListener('keydown', onKeyDownDropDown);
|
|
90
115
|
});
|
|
91
116
|
});
|
|
92
117
|
|
|
93
118
|
onUnmounted(() => {
|
|
94
|
-
|
|
119
|
+
reference.value?.removeEventListener('keydown', onKeyDownDropDown);
|
|
95
120
|
});
|
|
96
121
|
|
|
97
122
|
function onKeyDownDropDown(e: KeyboardEvent) {
|
|
@@ -100,6 +125,10 @@ function onKeyDownDropDown(e: KeyboardEvent) {
|
|
|
100
125
|
isOpen.value = false;
|
|
101
126
|
}
|
|
102
127
|
|
|
128
|
+
if (!isOpen.value) {
|
|
129
|
+
isOpen.value = true
|
|
130
|
+
}
|
|
131
|
+
|
|
103
132
|
emit('selectElement', focusedDropDownItem.value);
|
|
104
133
|
}
|
|
105
134
|
|
|
@@ -108,6 +137,7 @@ function onKeyDownDropDown(e: KeyboardEvent) {
|
|
|
108
137
|
}
|
|
109
138
|
|
|
110
139
|
if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
|
|
140
|
+
e.preventDefault()
|
|
111
141
|
isOpen.value = true;
|
|
112
142
|
|
|
113
143
|
const index = props.options.findIndex(option => option.value === focusedDropDownItem.value);
|
|
@@ -121,6 +151,7 @@ function onKeyDownDropDown(e: KeyboardEvent) {
|
|
|
121
151
|
}
|
|
122
152
|
|
|
123
153
|
if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
|
|
154
|
+
e.preventDefault()
|
|
124
155
|
isOpen.value = true;
|
|
125
156
|
|
|
126
157
|
const index = props.options.findIndex(option => option.value === focusedDropDownItem.value);
|
|
@@ -138,21 +169,24 @@ function onKeyDownDropDown(e: KeyboardEvent) {
|
|
|
138
169
|
|
|
139
170
|
function getActiveDropDownItemClasses(option: SelectOption) {
|
|
140
171
|
const variants: Record<InputState, string> = {
|
|
141
|
-
[InputState.base]: 'bg-neutral-
|
|
142
|
-
[InputState.success]: 'bg-success-
|
|
143
|
-
[InputState.info]: 'bg-info-
|
|
144
|
-
[InputState.warning]: 'bg-warning-
|
|
145
|
-
[InputState.danger]: 'bg-danger-
|
|
172
|
+
[InputState.base]: '!bg-neutral-100',
|
|
173
|
+
[InputState.success]: 'bg-success-200',
|
|
174
|
+
[InputState.info]: 'bg-info-200',
|
|
175
|
+
[InputState.warning]: 'bg-warning-200',
|
|
176
|
+
[InputState.danger]: 'bg-danger-200',
|
|
146
177
|
};
|
|
147
178
|
|
|
148
|
-
return option.value === focusedDropDownItem.value ? {[variants[props.state]]: true} : {};
|
|
179
|
+
return option.value === focusedDropDownItem.value ? {'bg-white': false, [variants[props.state]]: true} : {};
|
|
149
180
|
}
|
|
150
181
|
|
|
151
182
|
function onClickDropDownItem(e: MouseEvent, value: string | number | null) {
|
|
152
183
|
e.preventDefault();
|
|
153
|
-
|
|
184
|
+
reference.value?.focus();
|
|
185
|
+
|
|
186
|
+
if (props.closeOnSelectItem) {
|
|
187
|
+
isOpen.value = false;
|
|
188
|
+
}
|
|
154
189
|
|
|
155
|
-
isOpen.value = false;
|
|
156
190
|
emit('selectElement', value);
|
|
157
191
|
_modelValue.value = value;
|
|
158
192
|
}
|
|
@@ -164,26 +198,37 @@ watch(_modelValue, (val) => {
|
|
|
164
198
|
|
|
165
199
|
<template>
|
|
166
200
|
<div
|
|
167
|
-
|
|
168
|
-
|
|
201
|
+
ref="reference"
|
|
202
|
+
class="relative"
|
|
169
203
|
>
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
204
|
+
<slot/>
|
|
205
|
+
|
|
206
|
+
<teleport to="body">
|
|
207
|
+
<div
|
|
208
|
+
v-if="isOpen"
|
|
209
|
+
:class="dropdownClasses"
|
|
210
|
+
ref="floating"
|
|
211
|
+
:style="{width: `${width.width.value}px!important`, ...floatingStyles}"
|
|
212
|
+
>
|
|
213
|
+
<div
|
|
214
|
+
v-for="(option, index) in options"
|
|
215
|
+
:key="`option-${index}`"
|
|
216
|
+
:class="{...dropDownItemClasses, ...getActiveDropDownItemClasses(option)}"
|
|
217
|
+
@mousedown="(e) => onClickDropDownItem(e, option.value)"
|
|
218
|
+
@mouseover="() => focusedDropDownItem = option.value"
|
|
219
|
+
>
|
|
220
|
+
{{ option.label }}
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div
|
|
224
|
+
v-if="options.length === 0"
|
|
225
|
+
:class="{...dropDownItemClasses}"
|
|
226
|
+
>
|
|
227
|
+
<slot name="empty">
|
|
228
|
+
No options available
|
|
229
|
+
</slot>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</teleport>
|
|
188
233
|
</div>
|
|
189
234
|
</template>
|
|
@@ -4,7 +4,6 @@ declare const meta: Meta<typeof AntBaseInput>;
|
|
|
4
4
|
export default meta;
|
|
5
5
|
type Story = StoryObj<typeof AntBaseInput>;
|
|
6
6
|
export declare const Docs: Story;
|
|
7
|
-
export declare const withValidator: Story;
|
|
8
7
|
export declare const Nullable: Story;
|
|
9
8
|
export declare const IconLeft: Story;
|
|
10
9
|
export declare const IconRight: Story;
|
|
@@ -3,15 +3,13 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
|
|
6
|
+
module.exports = exports.Summary = exports.Nullable = exports.IconRight = exports.IconLeft = exports.Docs = void 0;
|
|
7
7
|
var _Size = require("../../../../enums/Size.enum");
|
|
8
8
|
var _AntBaseInput = require("../__types/AntBaseInput.types");
|
|
9
9
|
var _AntBaseInput2 = _interopRequireDefault(require("../AntBaseInput.vue"));
|
|
10
10
|
var _AntButton = _interopRequireDefault(require("../../../buttons/AntButton.vue"));
|
|
11
11
|
var _AntIcon = _interopRequireDefault(require("../../../AntIcon.vue"));
|
|
12
12
|
var _Grouped2 = require("../../../../enums/Grouped.enum");
|
|
13
|
-
var _validate = require("@antify/validate");
|
|
14
|
-
var _vue = require("vue");
|
|
15
13
|
var _freeSolidSvgIcons = require("@fortawesome/free-solid-svg-icons");
|
|
16
14
|
var _enums = require("../../../../enums");
|
|
17
15
|
var _AntFormGroup = _interopRequireDefault(require("../../../forms/AntFormGroup.vue"));
|
|
@@ -136,32 +134,6 @@ const Docs = exports.Docs = {
|
|
|
136
134
|
placeholder: "Placeholder"
|
|
137
135
|
}
|
|
138
136
|
};
|
|
139
|
-
const withValidator = exports.withValidator = {
|
|
140
|
-
render: args => ({
|
|
141
|
-
components: {
|
|
142
|
-
AntBaseInput: _AntBaseInput2.default
|
|
143
|
-
},
|
|
144
|
-
setup: () => {
|
|
145
|
-
const validator = (0, _vue.reactive)((0, _validate.useFieldValidator)([_validate.isRequiredRule, _validate.notBlankRule]));
|
|
146
|
-
return {
|
|
147
|
-
args,
|
|
148
|
-
validator,
|
|
149
|
-
InputState: _enums.InputState
|
|
150
|
-
};
|
|
151
|
-
},
|
|
152
|
-
template: `
|
|
153
|
-
<AntBaseInput
|
|
154
|
-
v-model="args.modelValue"
|
|
155
|
-
v-bind="args"
|
|
156
|
-
:state="args.state ? args.state : (validator.hasErrors() ? InputState.danger : undefined)"
|
|
157
|
-
@validate="(val) => validator.validate(val)"
|
|
158
|
-
/>`
|
|
159
|
-
}),
|
|
160
|
-
args: {
|
|
161
|
-
...Docs.args,
|
|
162
|
-
modelValue: ""
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
137
|
const Nullable = exports.Nullable = {
|
|
166
138
|
render: Docs.render,
|
|
167
139
|
args: {
|
|
@@ -4,8 +4,6 @@ import AntBaseInput from "../AntBaseInput.vue";
|
|
|
4
4
|
import AntButton from "../../../buttons/AntButton.vue";
|
|
5
5
|
import AntIcon from "../../../AntIcon.vue";
|
|
6
6
|
import { Grouped as _Grouped } from "../../../../enums/Grouped.enum.mjs";
|
|
7
|
-
import { isRequiredRule, notBlankRule, useFieldValidator } from "@antify/validate";
|
|
8
|
-
import { reactive } from "vue";
|
|
9
7
|
import { faSearch, faEye } from "@fortawesome/free-solid-svg-icons";
|
|
10
8
|
import { InputState } from "../../../../enums/index.mjs";
|
|
11
9
|
import AntFormGroup from "../../../forms/AntFormGroup.vue";
|
|
@@ -83,26 +81,6 @@ export const Docs = {
|
|
|
83
81
|
placeholder: "Placeholder"
|
|
84
82
|
}
|
|
85
83
|
};
|
|
86
|
-
export const withValidator = {
|
|
87
|
-
render: (args) => ({
|
|
88
|
-
components: { AntBaseInput },
|
|
89
|
-
setup: () => {
|
|
90
|
-
const validator = reactive(useFieldValidator([isRequiredRule, notBlankRule]));
|
|
91
|
-
return { args, validator, InputState };
|
|
92
|
-
},
|
|
93
|
-
template: `
|
|
94
|
-
<AntBaseInput
|
|
95
|
-
v-model="args.modelValue"
|
|
96
|
-
v-bind="args"
|
|
97
|
-
:state="args.state ? args.state : (validator.hasErrors() ? InputState.danger : undefined)"
|
|
98
|
-
@validate="(val) => validator.validate(val)"
|
|
99
|
-
/>`
|
|
100
|
-
}),
|
|
101
|
-
args: {
|
|
102
|
-
...Docs.args,
|
|
103
|
-
modelValue: ""
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
84
|
export const Nullable = {
|
|
107
85
|
render: Docs.render,
|
|
108
86
|
args: {
|
|
@@ -3,4 +3,5 @@ import AntField from '../../forms/AntField.vue';
|
|
|
3
3
|
import AntInputDescription from './AntInputDescription.vue';
|
|
4
4
|
import AntInputLabel from './AntInputLabel.vue';
|
|
5
5
|
import AntInputLimiter from './AntInputLimiter.vue';
|
|
6
|
-
|
|
6
|
+
import AntSelectMenu from './AntSelectMenu.vue';
|
|
7
|
+
export { AntBaseInput, AntField, AntInputDescription, AntInputLabel, AntInputLimiter, AntSelectMenu };
|