@veritree/ui 0.27.0 → 0.28.0-1
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/.claude/settings.local.json +10 -0
- package/index.js +105 -75
- package/mixins/floating-ui-content.js +17 -4
- package/mixins/floating-ui-item.js +31 -15
- package/mixins/floating-ui.js +142 -24
- package/mixins/form-control-icon.js +3 -3
- package/mixins/form-control.js +45 -20
- package/nuxt.js +38 -26
- package/package.json +17 -6
- package/src/components/Alert/VTAlert.vue +55 -14
- package/src/components/Avatar/VTAvatarImage.vue +6 -26
- package/src/components/Badge/VTBadge.vue +60 -0
- package/src/components/Badge/VTBadgeNew.vue +60 -0
- package/src/components/Breadcrumb/VTBreadcrumbItem.vue +11 -0
- package/src/components/Breadcrumb/VTBreadcrumbLink.vue +40 -0
- package/src/components/Breadcrumb/VTBreadcrumbList.vue +11 -0
- package/src/components/Breadcrumb/VTBreadcrumbRoot.vue +11 -0
- package/src/components/Breadcrumb/VTBreadcrumbSeparator.vue +19 -0
- package/src/components/Button/VTButton.vue +104 -56
- package/src/components/Carousel/VTCarousel.vue +69 -0
- package/src/components/Carousel/VTCarouselBackward.vue +36 -0
- package/src/components/Carousel/VTCarouselForward.vue +38 -0
- package/src/components/Carousel/VTCarouselTracker.vue +80 -0
- package/src/components/Checkbox/VTCheckbox.vue +134 -0
- package/src/components/Checkbox/VTCheckboxLabel.vue +3 -0
- package/src/components/Checkbox/VTCheckboxText.vue +20 -0
- package/src/components/Chip/VTChip.vue +29 -0
- package/src/components/Dialog/VTDialog.vue +59 -25
- package/src/components/Dialog/VTDialogClose.vue +3 -2
- package/src/components/Dialog/VTDialogContent.vue +29 -7
- package/src/components/Dialog/VTDialogFooter.vue +17 -2
- package/src/components/Dialog/VTDialogHeader.vue +2 -1
- package/src/components/Dialog/VTDialogMain.vue +5 -1
- package/src/components/Dialog/VTDialogOverlay.vue +5 -1
- package/src/components/Dialog/VTDialogTitle.vue +1 -1
- package/src/components/Disclosure/VTDisclosure.vue +2 -11
- package/src/components/Disclosure/VTDisclosureContent.vue +26 -52
- package/src/components/Disclosure/VTDisclosureDetails.vue +27 -2
- package/src/components/Disclosure/VTDisclosureHeader.vue +56 -89
- package/src/components/Disclosure/VTDisclosureIcon.vue +42 -31
- package/src/components/Divider/VTDivider.vue +9 -0
- package/src/components/Drawer/VTDrawer.vue +6 -15
- package/src/components/Drawer/VTDrawerClose.vue +5 -5
- package/src/components/Drawer/VTDrawerContent.vue +10 -10
- package/src/components/Drawer/VTDrawerFooter.vue +4 -4
- package/src/components/Drawer/VTDrawerHeader.vue +4 -4
- package/src/components/Drawer/VTDrawerMain.vue +5 -5
- package/src/components/Drawer/VTDrawerOverlay.vue +6 -6
- package/src/components/Drawer/VTDrawerTitle.vue +5 -5
- package/src/components/DropdownMenu/VTDropdownMenu.vue +0 -6
- package/src/components/DropdownMenu/VTDropdownMenuContent.vue +10 -1
- package/src/components/DropdownMenu/VTDropdownMenuDivider.vue +7 -16
- package/src/components/DropdownMenu/VTDropdownMenuItem.vue +5 -1
- package/src/components/DropdownMenu/VTDropdownMenuLabel.vue +1 -10
- package/src/components/DropdownMenu/VTDropdownMenuTrigger.vue +2 -4
- package/src/components/Form/VTFieldset.vue +5 -0
- package/src/components/Form/VTForm.vue +11 -0
- package/src/components/Form/VTFormCol.vue +20 -0
- package/src/components/Form/VTFormFeedback.vue +7 -1
- package/src/components/Form/VTFormGroup.vue +5 -7
- package/src/components/Form/VTFormLabel.vue +22 -0
- package/src/components/Form/VTFormLabelHelper.vue +22 -0
- package/src/components/Form/VTFormRow.vue +5 -0
- package/src/components/Form/VTInput.vue +2 -5
- package/src/components/Form/VTInputDate.vue +602 -0
- package/src/components/Form/VTInputIcon.vue +3 -9
- package/src/components/Form/VTInputNumber.vue +198 -0
- package/src/components/Form/VTInputPassword.vue +14 -5
- package/src/components/Form/VTInputRange.vue +92 -0
- package/src/components/Form/VTLegend.vue +24 -0
- package/src/components/Form/VTTextarea.vue +2 -2
- package/src/components/Image/VTImage.vue +10 -10
- package/src/components/Listbox/VTListbox.vue +128 -9
- package/src/components/Listbox/VTListboxContent.vue +14 -1
- package/src/components/Listbox/VTListboxDivider.vue +21 -0
- package/src/components/Listbox/VTListboxGroup.vue +9 -0
- package/src/components/Listbox/VTListboxItem.vue +57 -15
- package/src/components/Listbox/VTListboxLabel.vue +5 -4
- package/src/components/Listbox/VTListboxList.vue +1 -6
- package/src/components/Listbox/VTListboxPlaceholder.vue +25 -0
- package/src/components/Listbox/VTListboxSearch.vue +12 -8
- package/src/components/Listbox/VTListboxTrigger.vue +87 -6
- package/src/components/Listbox/VTListboxTriggerHighlight.vue +204 -0
- package/src/components/Listbox/VTListboxViewport.vue +33 -0
- package/src/components/Popover/VTPopoverContent.vue +3 -3
- package/src/components/Popover/VTPopoverDivider.vue +1 -1
- package/src/components/Popover/VTPopoverItem.vue +6 -2
- package/src/components/ProgressBar/VTProgressBar.vue +35 -10
- package/src/components/ProgressBar/VTProgressBarIndicator.vue +53 -0
- package/src/components/ScrollShadows/VTScrollShadows.vue +76 -0
- package/src/components/Separator/VTSeparator.vue +13 -0
- package/src/components/Switch/VTSwitch.vue +61 -0
- package/src/components/Tabs/VTTab.vue +6 -5
- package/src/components/Tabs/VTTabGroup.vue +88 -9
- package/src/components/Tabs/VTTabPanel.vue +4 -5
- package/src/components/Toast/README.md +263 -0
- package/src/components/Toast/VTToast.vue +145 -0
- package/src/components/Toast/VTToastAction.vue +25 -0
- package/src/components/Toast/VTToastClose.vue +52 -0
- package/src/components/Toast/VTToastContent.vue +25 -0
- package/src/components/Toast/VTToastDescription.vue +36 -0
- package/src/components/Toast/VTToastIcon.vue +72 -0
- package/src/components/Toast/VTToastItem.vue +180 -0
- package/src/components/Toast/VTToastTitle.vue +34 -0
- package/src/components/Tooltip/VTTooltipTrigger.vue +3 -5
- package/src/components/Transitions/FadeInOut.vue +2 -2
- package/src/components/Utils/FloatingUi.vue +31 -13
- package/src/helpers/currency.js +21 -0
- package/src/utils/components.js +18 -0
- package/src/utils/images.js +31 -12
- package/src/components/Input/VTInput.vue +0 -82
- package/src/components/Input/VTInputDate.vue +0 -36
- package/src/components/Input/VTInputFile.vue +0 -60
- package/src/components/Input/VTInputUpload.vue +0 -54
- package/src/components/Modal/VTModal.vue +0 -69
- package/src/utils/genId.js +0 -13
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<li
|
|
3
3
|
:id="id"
|
|
4
|
-
:class="
|
|
4
|
+
:class="computedClasses"
|
|
5
5
|
:aria-disabled="disabled"
|
|
6
|
+
:disabled="disabled"
|
|
6
7
|
:aria-selected="String(selected)"
|
|
7
8
|
:tabindex="tabIndex"
|
|
8
9
|
:role="'option'"
|
|
@@ -16,10 +17,25 @@
|
|
|
16
17
|
@keydown.enter.prevent="onClick"
|
|
17
18
|
@keydown.tab.prevent
|
|
18
19
|
>
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
<template v-if="this.multiple">
|
|
21
|
+
<input
|
|
22
|
+
:id="`${id}-checkbox`"
|
|
23
|
+
:ref="`${id}-checkbox`"
|
|
24
|
+
:value="value"
|
|
25
|
+
:checked="checked"
|
|
26
|
+
class="form-control-check"
|
|
27
|
+
type="checkbox"
|
|
28
|
+
@click.stop
|
|
29
|
+
@change="onChange(value, $event)"
|
|
30
|
+
/>
|
|
31
|
+
<slot></slot>
|
|
32
|
+
</template>
|
|
33
|
+
<template v-else>
|
|
34
|
+
<slot></slot>
|
|
35
|
+
<span v-if="checked" class="ml-auto">
|
|
36
|
+
<IconCheckOutline class="text-secondary-300 h-5 w-5" />
|
|
37
|
+
</span>
|
|
38
|
+
</template>
|
|
23
39
|
</li>
|
|
24
40
|
</template>
|
|
25
41
|
|
|
@@ -54,6 +70,10 @@ export default {
|
|
|
54
70
|
},
|
|
55
71
|
|
|
56
72
|
computed: {
|
|
73
|
+
computedClasses() {
|
|
74
|
+
return this.classComputed;
|
|
75
|
+
},
|
|
76
|
+
|
|
57
77
|
componentContent() {
|
|
58
78
|
return this.apiInjected().componentContent;
|
|
59
79
|
},
|
|
@@ -66,22 +86,30 @@ export default {
|
|
|
66
86
|
return this.apiListbox().search;
|
|
67
87
|
},
|
|
68
88
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
multiple() {
|
|
90
|
+
return this.apiListbox().multiple;
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
checked() {
|
|
94
|
+
if (this.multiple) {
|
|
95
|
+
return this.apiListbox().valueComputed.some(
|
|
96
|
+
(value) => JSON.stringify(this.value) === JSON.stringify(value),
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
76
100
|
return (
|
|
77
101
|
JSON.stringify(this.value) ===
|
|
78
|
-
JSON.stringify(this.apiListbox().
|
|
102
|
+
JSON.stringify(this.apiListbox().valueComputed)
|
|
79
103
|
);
|
|
80
104
|
},
|
|
81
105
|
},
|
|
82
106
|
|
|
83
107
|
mounted() {
|
|
84
|
-
if (this.
|
|
108
|
+
if (this.multiple) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (this.checked) {
|
|
85
113
|
/**
|
|
86
114
|
* There are some conflicts between the portal and the interaction
|
|
87
115
|
* with the element. It's unclear why it happens but if no delay,
|
|
@@ -141,7 +169,7 @@ export default {
|
|
|
141
169
|
* with any of the items to get its index value
|
|
142
170
|
*/
|
|
143
171
|
const newItemSelectedIndex = this.items.findIndex((item) =>
|
|
144
|
-
item.text.toLowerCase().includes(this.search.toLowerCase())
|
|
172
|
+
item.text.toLowerCase().includes(this.search.toLowerCase()),
|
|
145
173
|
);
|
|
146
174
|
|
|
147
175
|
/**
|
|
@@ -160,6 +188,20 @@ export default {
|
|
|
160
188
|
this.apiListbox().clearSearch();
|
|
161
189
|
}, 1000);
|
|
162
190
|
},
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* On change is used only when multiple is set to true.
|
|
194
|
+
* It handles the checkbox changes to interact with
|
|
195
|
+
* the provider by pushing or removing values.
|
|
196
|
+
*
|
|
197
|
+
* @param {*} value
|
|
198
|
+
* @param {Object} event
|
|
199
|
+
*/
|
|
200
|
+
onChange(value, event) {
|
|
201
|
+
event.target.checked
|
|
202
|
+
? this.apiListbox().pushValueToValueComputed(value)
|
|
203
|
+
: this.apiListbox().removeValueFromValueComputed(value);
|
|
204
|
+
},
|
|
163
205
|
},
|
|
164
206
|
};
|
|
165
207
|
</script>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
3
|
:is="as"
|
|
4
|
-
:class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
:class="[
|
|
5
|
+
headless
|
|
6
|
+
? 'listbox-label'
|
|
7
|
+
: 'mb-0.5 block px-3 text-xs font-normal uppercase text-gray-600',
|
|
8
|
+
]"
|
|
8
9
|
>
|
|
9
10
|
<slot></slot>
|
|
10
11
|
</component>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="as"
|
|
4
|
+
:class="[headless ? 'listbox-placeholder' : 'font-light text-gray-500']"
|
|
5
|
+
>
|
|
6
|
+
<slot></slot>
|
|
7
|
+
</component>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script>
|
|
11
|
+
export default {
|
|
12
|
+
name: 'VTListboxPlaceholder',
|
|
13
|
+
|
|
14
|
+
props: {
|
|
15
|
+
as: {
|
|
16
|
+
type: String,
|
|
17
|
+
default: 'span',
|
|
18
|
+
},
|
|
19
|
+
headless: {
|
|
20
|
+
type: Boolean,
|
|
21
|
+
default: false,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
</script>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="-mx-3 -mt-2">
|
|
3
3
|
<input
|
|
4
|
-
ref="
|
|
4
|
+
ref="searchInput"
|
|
5
5
|
v-model="search"
|
|
6
6
|
v-bind="$attrs"
|
|
7
7
|
type="text"
|
|
8
|
-
class="leading-0 font-inherit w-full max-w-full appearance-none border-b border-solid border-gray-300 py-2 px-3 text-base text-inherit"
|
|
8
|
+
class="leading-0 hidden sm:block font-inherit w-full max-w-full appearance-none border-b border-solid border-gray-300 py-2 px-3 text-base text-inherit"
|
|
9
9
|
@input="onChange"
|
|
10
10
|
@click.stop
|
|
11
11
|
@keydown.down.prevent="focusNextItem"
|
|
@@ -29,6 +29,8 @@ export default {
|
|
|
29
29
|
|
|
30
30
|
inheritAttrs: false,
|
|
31
31
|
|
|
32
|
+
emits: ['change'],
|
|
33
|
+
|
|
32
34
|
inject: ['apiListbox'],
|
|
33
35
|
|
|
34
36
|
data() {
|
|
@@ -59,12 +61,11 @@ export default {
|
|
|
59
61
|
};
|
|
60
62
|
|
|
61
63
|
this.apiListbox().registerSearch(componentSearch);
|
|
62
|
-
this.$nextTick(() => setTimeout(() => this.$refs.
|
|
64
|
+
this.$nextTick(() => setTimeout(() => this.$refs.searchInput.focus(), 150));
|
|
63
65
|
},
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
beforeUnmount() {
|
|
66
68
|
this.search = '';
|
|
67
|
-
this.$emit('change', this.search.trim());
|
|
68
69
|
},
|
|
69
70
|
|
|
70
71
|
methods: {
|
|
@@ -111,6 +112,7 @@ export default {
|
|
|
111
112
|
|
|
112
113
|
// select new item
|
|
113
114
|
if (this.items[newSelectedIndex]) {
|
|
115
|
+
this.index = newSelectedIndex;
|
|
114
116
|
this.items[newSelectedIndex].select();
|
|
115
117
|
}
|
|
116
118
|
},
|
|
@@ -124,10 +126,12 @@ export default {
|
|
|
124
126
|
},
|
|
125
127
|
|
|
126
128
|
onChange() {
|
|
127
|
-
this.index = 0;
|
|
128
|
-
if (this.item) this.item.select();
|
|
129
|
-
|
|
130
129
|
this.$emit('change', this.search.trim());
|
|
130
|
+
|
|
131
|
+
this.$nextTick(() => {
|
|
132
|
+
this.index = 0;
|
|
133
|
+
if (this.item) this.item.select();
|
|
134
|
+
});
|
|
131
135
|
},
|
|
132
136
|
|
|
133
137
|
onKeyEnter() {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<button
|
|
3
3
|
:id="id"
|
|
4
|
-
:
|
|
5
|
-
:
|
|
4
|
+
:data-testid="dataTestidComputed"
|
|
5
|
+
:class="classList"
|
|
6
|
+
:disabled="isDisabled"
|
|
6
7
|
:aria-expanded="expanded"
|
|
7
8
|
:aria-haspopup="hasPopup"
|
|
9
|
+
:role="role"
|
|
8
10
|
type="button"
|
|
9
11
|
@click.prevent="onClick"
|
|
10
12
|
@keydown.down.prevent="onKeyDownOrUp"
|
|
@@ -14,9 +16,19 @@
|
|
|
14
16
|
<span :class="[headless ? 'listbox-button__text' : 'truncate text-left']">
|
|
15
17
|
<slot></slot>
|
|
16
18
|
</span>
|
|
17
|
-
<span
|
|
19
|
+
<span
|
|
20
|
+
:class="[
|
|
21
|
+
headless ? 'listbox-button__icon' : '-mr-1 ml-2 shrink-0 text-gray-500',
|
|
22
|
+
]"
|
|
23
|
+
>
|
|
24
|
+
<VTSpinner v-if="loading" class="mr-0.5 max-w-4 max-h-4" />
|
|
25
|
+
<IconChevronDownV2
|
|
26
|
+
v-else-if="apiListbox().version === '2'"
|
|
27
|
+
:class="{ 'rotate-180': expanded }"
|
|
28
|
+
/>
|
|
18
29
|
<IconChevronDown
|
|
19
|
-
|
|
30
|
+
v-else
|
|
31
|
+
class="w-5 text-gray-700 transition-transform"
|
|
20
32
|
:class="{ 'rotate-180': expanded }"
|
|
21
33
|
/>
|
|
22
34
|
</span>
|
|
@@ -39,6 +51,27 @@ export default {
|
|
|
39
51
|
|
|
40
52
|
inject: ['apiListbox'],
|
|
41
53
|
|
|
54
|
+
inheritAttrs: false,
|
|
55
|
+
|
|
56
|
+
props: {
|
|
57
|
+
dataTestid: {
|
|
58
|
+
type: String,
|
|
59
|
+
default: null,
|
|
60
|
+
},
|
|
61
|
+
role: {
|
|
62
|
+
type: String,
|
|
63
|
+
default: 'combobox',
|
|
64
|
+
},
|
|
65
|
+
loading: {
|
|
66
|
+
type: Boolean,
|
|
67
|
+
default: false,
|
|
68
|
+
},
|
|
69
|
+
stopPropagation: {
|
|
70
|
+
type: Boolean,
|
|
71
|
+
default: false,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
|
|
42
75
|
data() {
|
|
43
76
|
return {
|
|
44
77
|
expanded: false,
|
|
@@ -51,10 +84,18 @@ export default {
|
|
|
51
84
|
return `listbox-trigger-${this.apiListbox().id}`;
|
|
52
85
|
},
|
|
53
86
|
|
|
87
|
+
dataTestidComputed() {
|
|
88
|
+
return this.dataTestid || `listbox-trigger-${this.apiListbox().id}`;
|
|
89
|
+
},
|
|
90
|
+
|
|
54
91
|
componentContent() {
|
|
55
92
|
return this.apiListbox().componentContent;
|
|
56
93
|
},
|
|
57
94
|
|
|
95
|
+
multiple() {
|
|
96
|
+
return this.apiListbox().multiple;
|
|
97
|
+
},
|
|
98
|
+
|
|
58
99
|
items() {
|
|
59
100
|
return this.apiListbox().items;
|
|
60
101
|
},
|
|
@@ -66,6 +107,42 @@ export default {
|
|
|
66
107
|
lastMenuItem() {
|
|
67
108
|
return this.items[this.items.length - 1];
|
|
68
109
|
},
|
|
110
|
+
|
|
111
|
+
classList() {
|
|
112
|
+
if (this.headless) {
|
|
113
|
+
return this.$attrs.class || null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// TODO: role isn't the best way to determine button styles, we should have a better prop for that
|
|
117
|
+
if (this.role === 'combobox') {
|
|
118
|
+
const version2Classes = [];
|
|
119
|
+
|
|
120
|
+
if (this.apiListbox().version === '2') {
|
|
121
|
+
version2Classes.push('listbox-trigger--version-2');
|
|
122
|
+
|
|
123
|
+
if (this.variant) {
|
|
124
|
+
version2Classes.push(`listbox-trigger--${this.variant}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (this.size) {
|
|
128
|
+
version2Classes.push(`listbox-trigger--${this.size}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return [
|
|
133
|
+
this.classComputed,
|
|
134
|
+
this.headless ? null : 'hover:bg-gray-200',
|
|
135
|
+
...version2Classes,
|
|
136
|
+
this.$attrs.class,
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return `button-base button--${this.variant} button--${this.size}`;
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
isDisabled() {
|
|
144
|
+
return this.disabled || this.loading;
|
|
145
|
+
},
|
|
69
146
|
},
|
|
70
147
|
|
|
71
148
|
mounted() {
|
|
@@ -122,7 +199,11 @@ export default {
|
|
|
122
199
|
},
|
|
123
200
|
|
|
124
201
|
onClick(e) {
|
|
202
|
+
if (this.stopPropagation) {
|
|
203
|
+
e.stopPropagation();
|
|
204
|
+
}
|
|
125
205
|
this.init(e);
|
|
206
|
+
this.$emit('click');
|
|
126
207
|
},
|
|
127
208
|
|
|
128
209
|
onKeyDownOrUp(e) {
|
|
@@ -135,8 +216,8 @@ export default {
|
|
|
135
216
|
keyCode === 'ArrowDown'
|
|
136
217
|
? 'firstMenuItem'
|
|
137
218
|
: keyCode === 'ArrowUp'
|
|
138
|
-
|
|
139
|
-
|
|
219
|
+
? 'lastMenuItem'
|
|
220
|
+
: null;
|
|
140
221
|
|
|
141
222
|
// settimeout here is delaying the focusing the element
|
|
142
223
|
// since it is not rendered yet. All items will only
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:id="highlightId"
|
|
4
|
+
:class="[
|
|
5
|
+
headless ? 'listbox-highlight' : 'relative',
|
|
6
|
+
headless
|
|
7
|
+
? isActive
|
|
8
|
+
? 'listbox-highlight--active'
|
|
9
|
+
: null
|
|
10
|
+
: isActive
|
|
11
|
+
? '[&>*]:border-gray-700'
|
|
12
|
+
: null,
|
|
13
|
+
]"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
import { computePosition, offset, autoUpdate } from '@floating-ui/dom';
|
|
21
|
+
|
|
22
|
+
export default {
|
|
23
|
+
name: 'VTListboxHighlight',
|
|
24
|
+
|
|
25
|
+
inject: ['apiListbox'],
|
|
26
|
+
|
|
27
|
+
props: {
|
|
28
|
+
/**
|
|
29
|
+
* Determines whether the button will use its default atomic style (tailwind) or its default class
|
|
30
|
+
* @type {boolean}
|
|
31
|
+
* @values
|
|
32
|
+
* - true: The button will have no default style and can be fully customized with a custom class
|
|
33
|
+
* - false: The button will use its default atomic style (tailwind) and can be further customized with additional classes
|
|
34
|
+
* @default null
|
|
35
|
+
*/
|
|
36
|
+
headless: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
default: false,
|
|
39
|
+
},
|
|
40
|
+
/**
|
|
41
|
+
* The default value for the listbox item, used to determine its initial state.
|
|
42
|
+
* @type {string|null}
|
|
43
|
+
* @default null
|
|
44
|
+
*/
|
|
45
|
+
defaultValue: {
|
|
46
|
+
type: String,
|
|
47
|
+
default: null,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
computed: {
|
|
52
|
+
/**
|
|
53
|
+
* Computed property that generates an identifier for the counter element associated with the listbox.
|
|
54
|
+
*
|
|
55
|
+
* @property
|
|
56
|
+
* @name counterId
|
|
57
|
+
* @memberof VTListboxTriggerHighlight
|
|
58
|
+
* @description Returns an ID for the listbox counter element.
|
|
59
|
+
* @returns {string} The generated counter ID.
|
|
60
|
+
*/
|
|
61
|
+
counterId() {
|
|
62
|
+
return `listbox-counter-${this.apiListbox().id}`;
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Computed property that generates an identifier for the highlight element associated with the listbox.
|
|
67
|
+
*
|
|
68
|
+
* @property
|
|
69
|
+
* @name highlightId
|
|
70
|
+
* @memberof VTListboxTriggerHighlight
|
|
71
|
+
* @description Returns an ID for the listbox highlight element.
|
|
72
|
+
* @returns {string} The generated highlight ID.
|
|
73
|
+
*/
|
|
74
|
+
highlightId() {
|
|
75
|
+
return `listbox-highlight-${this.apiListbox().id}`;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Computes the current value of the listbox item.
|
|
80
|
+
*
|
|
81
|
+
* @property
|
|
82
|
+
* @name computedValue
|
|
83
|
+
* @memberof VTListboxTriggerHighlight
|
|
84
|
+
* @description Returns the computed value of the listbox item.
|
|
85
|
+
* @returns {*} The computed value.
|
|
86
|
+
*/
|
|
87
|
+
computedValue() {
|
|
88
|
+
return this.apiListbox().valueComputed;
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Checks if the computed value is an array.
|
|
93
|
+
*
|
|
94
|
+
* @property
|
|
95
|
+
* @name isValueAnArray
|
|
96
|
+
* @memberof VTListboxTriggerHighlight
|
|
97
|
+
* @description Checks if the computed value is an array.
|
|
98
|
+
* @returns {boolean} True if the value is an array, false otherwise.
|
|
99
|
+
*/
|
|
100
|
+
isValueAnArray() {
|
|
101
|
+
return Array.isArray(this.computedValue);
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Computes the length of the value, considering whether it's an array or a single value.
|
|
106
|
+
*
|
|
107
|
+
* @property
|
|
108
|
+
* @name computedValueLength
|
|
109
|
+
* @memberof VTListboxTriggerHighlight
|
|
110
|
+
* @description Returns the length of the computed value.
|
|
111
|
+
* @returns {number} The length of the computed value.
|
|
112
|
+
*/
|
|
113
|
+
computedValueLength() {
|
|
114
|
+
if (this.isValueAnArray) {
|
|
115
|
+
return this.computedValue.length;
|
|
116
|
+
} else {
|
|
117
|
+
return this.computedValue ? 1 : 0;
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Determines if the listbox item is active based on its value and default value.
|
|
123
|
+
*
|
|
124
|
+
* @property
|
|
125
|
+
* @name isActive
|
|
126
|
+
* @memberof VTListboxTriggerHighlight
|
|
127
|
+
* @description Checks if the listbox item is considered active.
|
|
128
|
+
* @returns {boolean} True if the listbox item is active, false otherwise.
|
|
129
|
+
*/
|
|
130
|
+
isActive() {
|
|
131
|
+
return this.isValueAnArray
|
|
132
|
+
? this.computedValueLength > 0
|
|
133
|
+
: this.defaultValue !== this.computedValue;
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
// /**
|
|
137
|
+
// * Checks if the badge should be visible for the listbox item.
|
|
138
|
+
// *
|
|
139
|
+
// * @property
|
|
140
|
+
// * @name isBadgeVisible
|
|
141
|
+
// * @memberof VTListboxTriggerHighlight
|
|
142
|
+
// * @description Checks if the badge should be visible for the listbox item.
|
|
143
|
+
// * @returns {boolean} True if the badge should be visible, false otherwise.
|
|
144
|
+
// */
|
|
145
|
+
// isBadgeVisible() {
|
|
146
|
+
// return this.isValueAnArray && this.isActive;
|
|
147
|
+
// },
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// mounted() {
|
|
151
|
+
// this.$nextTick(() => this.positionFloatingContent());
|
|
152
|
+
// },
|
|
153
|
+
|
|
154
|
+
// methods: {
|
|
155
|
+
// /**
|
|
156
|
+
// * Positions the floating content relative to a specified trigger element.
|
|
157
|
+
// *
|
|
158
|
+
// * @function
|
|
159
|
+
// * @name positionFloatingContent
|
|
160
|
+
// * @description Calculates and updates the position of the floating content
|
|
161
|
+
// * based on the position of the reference element.
|
|
162
|
+
// * @returns {void}
|
|
163
|
+
// */
|
|
164
|
+
// positionFloatingContent() {
|
|
165
|
+
// /**
|
|
166
|
+
// * The reference element that triggers the positioning of the floating content.
|
|
167
|
+
// * @type {HTMLElement}
|
|
168
|
+
// */
|
|
169
|
+
// const referenceElement = document.getElementById(this.highlightId);
|
|
170
|
+
|
|
171
|
+
// /**
|
|
172
|
+
// * The floating element whose position needs to be updated.
|
|
173
|
+
// * @type {HTMLElement}
|
|
174
|
+
// */
|
|
175
|
+
// const floatingElement = document.getElementById(this.counterId);
|
|
176
|
+
|
|
177
|
+
// /**
|
|
178
|
+
// * Callback function to update the position of the floating element
|
|
179
|
+
// * using the autoUpdate and computePosition utilities.
|
|
180
|
+
// * @type {Function}
|
|
181
|
+
// */
|
|
182
|
+
// const updatePositionCallback = () => {
|
|
183
|
+
// computePosition(referenceElement, floatingElement, {
|
|
184
|
+
// placement: 'top-end',
|
|
185
|
+
// middleware: [
|
|
186
|
+
// offset({
|
|
187
|
+
// alignmentAxis: -10,
|
|
188
|
+
// mainAxis: -10,
|
|
189
|
+
// }),
|
|
190
|
+
// ],
|
|
191
|
+
// }).then(({ x, y }) => {
|
|
192
|
+
// Object.assign(floatingElement.style, {
|
|
193
|
+
// left: `${x}px`,
|
|
194
|
+
// top: `${y}px`,
|
|
195
|
+
// });
|
|
196
|
+
// });
|
|
197
|
+
// };
|
|
198
|
+
|
|
199
|
+
// // Call the autoUpdate function with the specified elements and callback.
|
|
200
|
+
// autoUpdate(referenceElement, floatingElement, updatePositionCallback);
|
|
201
|
+
// },
|
|
202
|
+
// },
|
|
203
|
+
};
|
|
204
|
+
</script>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:id="id"
|
|
4
|
+
:class="[
|
|
5
|
+
headless
|
|
6
|
+
? 'listbox-viewport'
|
|
7
|
+
: '-mx-3 max-h-[300px] w-auto overflow-y-auto scroll-auto',
|
|
8
|
+
]"
|
|
9
|
+
>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
export default {
|
|
16
|
+
name: 'VTListboxViewport',
|
|
17
|
+
|
|
18
|
+
inject: ['apiListbox'],
|
|
19
|
+
|
|
20
|
+
props: {
|
|
21
|
+
headless: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
default: false,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
computed: {
|
|
28
|
+
id() {
|
|
29
|
+
return `listbox-viewport-${this.apiListbox().id}`;
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
</script>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<FloatingUi
|
|
3
|
-
:id="id"
|
|
4
3
|
:visible="visible"
|
|
4
|
+
:id="id"
|
|
5
5
|
:headless="headless"
|
|
6
|
-
:
|
|
7
|
-
|
|
6
|
+
:class="{ 'popover-content': headless }"
|
|
7
|
+
:floating-ui-class="floatingUiClass"
|
|
8
8
|
>
|
|
9
9
|
<slot></slot>
|
|
10
10
|
</FloatingUi>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// default styles
|
|
6
6
|
headless
|
|
7
7
|
? 'popover-item'
|
|
8
|
-
: 'relative z-10 -mx-3 flex items-center gap-2 px-3 py-2 text-inherit no-underline
|
|
8
|
+
: 'hover:bg-secondary-200/10 relative z-10 -mx-3 flex items-center gap-2 px-3 py-2 text-inherit no-underline',
|
|
9
9
|
]"
|
|
10
10
|
@click="onClick"
|
|
11
11
|
>
|
|
@@ -44,7 +44,11 @@ export default {
|
|
|
44
44
|
},
|
|
45
45
|
|
|
46
46
|
as() {
|
|
47
|
-
return this.href
|
|
47
|
+
return this.href
|
|
48
|
+
? 'a'
|
|
49
|
+
: this.to
|
|
50
|
+
? resolveComponent('NuxtLink')
|
|
51
|
+
: 'button';
|
|
48
52
|
},
|
|
49
53
|
},
|
|
50
54
|
|