@veritree/ui 0.19.2-9 → 0.20.0-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/index.js +64 -68
- package/mixins/floating-ui-content.js +81 -0
- package/mixins/floating-ui-item.js +266 -0
- package/mixins/floating-ui.js +67 -0
- package/mixins/form-control-icon.js +53 -0
- package/mixins/form-control.js +71 -0
- package/nuxt.js +3 -0
- package/package.json +7 -3
- package/src/components/Alert/VTAlert.vue +55 -14
- package/src/components/Avatar/VTAvatar.vue +32 -29
- package/src/components/Button/VTButton.vue +9 -5
- 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/Dialog/VTDialog.vue +16 -21
- package/src/components/Dialog/VTDialogClose.vue +13 -19
- package/src/components/Dialog/VTDialogContent.vue +17 -12
- package/src/components/Dialog/VTDialogFooter.vue +9 -14
- package/src/components/Dialog/VTDialogHeader.vue +11 -13
- package/src/components/Dialog/VTDialogMain.vue +6 -13
- package/src/components/Dialog/VTDialogOverlay.vue +9 -13
- package/src/components/Dialog/VTDialogTitle.vue +8 -5
- package/src/components/Disclosure/VTDisclosureContent.vue +1 -1
- package/src/components/Disclosure/VTDisclosureDetails.vue +1 -1
- package/src/components/Disclosure/VTDisclosureHeader.vue +2 -2
- package/src/components/Disclosure/VTDisclosureIcon.vue +1 -1
- package/src/components/DropdownMenu/VTDropdownMenu.vue +42 -25
- package/src/components/DropdownMenu/VTDropdownMenuContent.vue +29 -64
- package/src/components/DropdownMenu/VTDropdownMenuDivider.vue +7 -13
- package/src/components/DropdownMenu/VTDropdownMenuItem.vue +11 -135
- package/src/components/DropdownMenu/VTDropdownMenuLabel.vue +3 -12
- package/src/components/DropdownMenu/VTDropdownMenuTrigger.vue +95 -115
- package/src/components/Form/VTFormFeedback.vue +39 -22
- package/src/components/Form/VTFormGroup.vue +5 -7
- package/src/components/Form/VTFormLabel.vue +22 -0
- package/src/components/Form/VTFormRow.vue +5 -0
- package/src/components/Form/VTInput.vue +40 -0
- package/src/components/Form/VTInputIcon.vue +35 -0
- package/src/components/Form/VTInputPassword.vue +55 -0
- package/src/components/Form/VTTextarea.vue +22 -0
- package/src/components/Listbox/VTListbox.vue +119 -47
- package/src/components/Listbox/VTListboxContent.vue +18 -114
- package/src/components/Listbox/VTListboxItem.vue +112 -163
- package/src/components/Listbox/VTListboxLabel.vue +3 -14
- package/src/components/Listbox/VTListboxList.vue +8 -38
- package/src/components/Listbox/VTListboxSearch.vue +75 -67
- package/src/components/Listbox/VTListboxTrigger.vue +73 -84
- package/src/components/Popover/VTPopover.vue +39 -26
- package/src/components/Popover/VTPopoverContent.vue +23 -58
- package/src/components/Popover/VTPopoverDivider.vue +4 -11
- package/src/components/Popover/VTPopoverItem.vue +13 -10
- package/src/components/Popover/VTPopoverTrigger.vue +120 -20
- package/src/components/ProgressBar/VTProgressBar.vue +21 -3
- package/src/components/Skeleton/VTSkeleton.vue +11 -0
- package/src/components/Skeleton/VTSkeletonItem.vue +9 -0
- package/src/components/Tabs/VTTab.vue +14 -12
- package/src/components/Tabs/VTTabPanel.vue +1 -1
- package/src/components/Tooltip/VTTooltip.vue +65 -0
- package/src/components/Tooltip/VTTooltipContent.vue +59 -0
- package/src/components/Tooltip/VTTooltipTrigger.vue +98 -0
- package/src/components/Utils/FloatingUi.vue +93 -0
- 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
|
@@ -3,20 +3,14 @@
|
|
|
3
3
|
:is="as"
|
|
4
4
|
:id="id"
|
|
5
5
|
:to="to"
|
|
6
|
-
:class="
|
|
7
|
-
MenuItem: headless,
|
|
8
|
-
'-mx-3 flex min-w-max items-center gap-3 px-3 py-2 text-inherit no-underline':
|
|
9
|
-
!headless,
|
|
10
|
-
'hover:bg-secondary-200/10': !dark,
|
|
11
|
-
'text-white hover:bg-fd-450 focus:bg-fd-450': dark,
|
|
12
|
-
'pointer-events-none opacity-75': disabled,
|
|
13
|
-
}"
|
|
14
|
-
:tabindex="tabIndex"
|
|
6
|
+
:class="classComputed"
|
|
15
7
|
:aria-disabled="disabled"
|
|
8
|
+
:tabindex="tabIndex"
|
|
9
|
+
class="-mx-3"
|
|
16
10
|
role="menuitem"
|
|
17
11
|
@click.stop.prevent="onClick"
|
|
18
|
-
@keydown.down.prevent="
|
|
19
|
-
@keydown.up.prevent="
|
|
12
|
+
@keydown.down.prevent="focusNextItem"
|
|
13
|
+
@keydown.up.prevent="focusPreviousItem"
|
|
20
14
|
@keydown.home.prevent="focusFirstItem"
|
|
21
15
|
@keydown.end.prevent="focusLastItem"
|
|
22
16
|
@keydown.esc.prevent="onKeyEsc"
|
|
@@ -28,11 +22,13 @@
|
|
|
28
22
|
</template>
|
|
29
23
|
|
|
30
24
|
<script>
|
|
31
|
-
import {
|
|
25
|
+
import { floatingUiItemMixin } from '../../../mixins/floating-ui-item';
|
|
32
26
|
|
|
33
27
|
export default {
|
|
34
28
|
name: 'VTDropdownMenuItem',
|
|
35
29
|
|
|
30
|
+
mixins: [floatingUiItemMixin],
|
|
31
|
+
|
|
36
32
|
inject: ['apiDropdownMenu'],
|
|
37
33
|
|
|
38
34
|
props: {
|
|
@@ -44,138 +40,18 @@ export default {
|
|
|
44
40
|
type: String,
|
|
45
41
|
default: null,
|
|
46
42
|
},
|
|
47
|
-
disabled: {
|
|
48
|
-
type: Boolean,
|
|
49
|
-
default: false,
|
|
50
|
-
},
|
|
51
43
|
},
|
|
52
44
|
|
|
53
45
|
data() {
|
|
54
46
|
return {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
tabIndex: 0,
|
|
47
|
+
apiInjected: this.apiDropdownMenu,
|
|
48
|
+
componentName: 'dropdown-menu-item',
|
|
58
49
|
};
|
|
59
50
|
},
|
|
60
51
|
|
|
61
52
|
computed: {
|
|
62
|
-
dark() {
|
|
63
|
-
return this.apiDropdownMenu().isDark;
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
headless() {
|
|
67
|
-
return this.apiDropdownMenu().isHeadless;
|
|
68
|
-
},
|
|
69
|
-
|
|
70
53
|
as() {
|
|
71
|
-
return this.href
|
|
72
|
-
? 'a'
|
|
73
|
-
: this.to
|
|
74
|
-
? resolveComponent('NuxtLink')
|
|
75
|
-
: 'button';
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
items() {
|
|
79
|
-
return this.apiDropdownMenu().items;
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
el() {
|
|
83
|
-
return this.$el;
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
trigger() {
|
|
87
|
-
return this.apiDropdownMenu().trigger;
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
content() {
|
|
91
|
-
return this.apiDropdownMenu().content;
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
mounted() {
|
|
96
|
-
const item = {
|
|
97
|
-
focus: this.focus,
|
|
98
|
-
el: this.el,
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
this.apiDropdownMenu().registerItem(item);
|
|
102
|
-
|
|
103
|
-
this.index = this.items.length - 1;
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
methods: {
|
|
107
|
-
focus() {
|
|
108
|
-
if (!this.el) return;
|
|
109
|
-
|
|
110
|
-
this.tabIndex = -1;
|
|
111
|
-
this.el.focus();
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
focusFirstItem() {
|
|
115
|
-
this.setFocusToItem(0);
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
focusLastItem() {
|
|
119
|
-
this.setFocusToItem(this.items.length - 1);
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Focus the previous item in the menu.
|
|
124
|
-
* If is the first item, jump to the last item.
|
|
125
|
-
*/
|
|
126
|
-
focusPreviousItem() {
|
|
127
|
-
const isLast = this.index === this.items.length - 1;
|
|
128
|
-
const goToIndex = isLast ? 0 : this.index + 1;
|
|
129
|
-
|
|
130
|
-
this.setFocusToItem(goToIndex);
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Focus the next item in the menu.
|
|
135
|
-
* If is the last item, jump to the first item.
|
|
136
|
-
*/
|
|
137
|
-
focusNextItem() {
|
|
138
|
-
const isFirst = this.index === 0;
|
|
139
|
-
const goToIndex = isFirst ? this.items.length - 1 : this.index - 1;
|
|
140
|
-
|
|
141
|
-
this.setFocusToItem(goToIndex);
|
|
142
|
-
},
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Focus item by remove its tabindex and calling
|
|
146
|
-
* focus to the element.
|
|
147
|
-
*
|
|
148
|
-
* @param {Number, String} goToIndex
|
|
149
|
-
*/
|
|
150
|
-
setFocusToItem(goToIndex) {
|
|
151
|
-
this.tabIndex = 0;
|
|
152
|
-
this.items[goToIndex].focus();
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Hides content/menu and focus on trigger
|
|
157
|
-
*/
|
|
158
|
-
leaveMenu() {
|
|
159
|
-
if (this.content) this.content.hide();
|
|
160
|
-
if (this.trigger) this.trigger.focus();
|
|
161
|
-
},
|
|
162
|
-
|
|
163
|
-
onKeyEsc() {
|
|
164
|
-
this.leaveMenu();
|
|
165
|
-
},
|
|
166
|
-
|
|
167
|
-
onClick(ev) {
|
|
168
|
-
if (this.disabled) return;
|
|
169
|
-
|
|
170
|
-
// Nuxtlink doesn't understand enter as a click
|
|
171
|
-
// so, we need to force it here
|
|
172
|
-
if (ev.key === 'Enter') {
|
|
173
|
-
ev.target.click();
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
this.$emit('click');
|
|
178
|
-
this.$nextTick(() => this.leaveMenu());
|
|
54
|
+
return this.href ? 'a' : this.to ? 'NuxtLink' : 'button';
|
|
179
55
|
},
|
|
180
56
|
},
|
|
181
57
|
};
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<span
|
|
3
|
-
:class="
|
|
4
|
-
MenuLabel: headless,
|
|
5
|
-
'mb-2 block text-xs uppercase': !headless,
|
|
6
|
-
'text-inherit': !dark,
|
|
7
|
-
'text-white': dark,
|
|
8
|
-
}"
|
|
3
|
+
:class="[headless ? 'dropdown-menu-label' : 'mb-2 block text-xs uppercase']"
|
|
9
4
|
>
|
|
10
5
|
<slot></slot>
|
|
11
6
|
</span>
|
|
@@ -15,15 +10,11 @@
|
|
|
15
10
|
export default {
|
|
16
11
|
name: 'VTDropdownMenuLabel',
|
|
17
12
|
|
|
18
|
-
inject: ['
|
|
13
|
+
inject: ['apiDropdownMenu'],
|
|
19
14
|
|
|
20
15
|
computed: {
|
|
21
|
-
dark() {
|
|
22
|
-
return this.api().isDark;
|
|
23
|
-
},
|
|
24
|
-
|
|
25
16
|
headless() {
|
|
26
|
-
return this.
|
|
17
|
+
return this.apiDropdownMenu().isHeadless;
|
|
27
18
|
},
|
|
28
19
|
},
|
|
29
20
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
+
:id="id"
|
|
3
4
|
:aria-haspopup="hasPopup"
|
|
4
5
|
:aria-expanded="expanded"
|
|
5
6
|
:aria-controls="controls"
|
|
6
|
-
@keydown.down.prevent="
|
|
7
|
-
@keydown.up.prevent="
|
|
8
|
-
@keydown.esc.
|
|
7
|
+
@keydown.down.prevent="onKeyDownOrUp"
|
|
8
|
+
@keydown.up.prevent="onKeyDownOrUp"
|
|
9
|
+
@keydown.esc.stop="onKeyEsc"
|
|
9
10
|
>
|
|
10
11
|
<slot></slot>
|
|
11
12
|
</div>
|
|
@@ -19,17 +20,20 @@ export default {
|
|
|
19
20
|
|
|
20
21
|
data() {
|
|
21
22
|
return {
|
|
22
|
-
trigger: null,
|
|
23
23
|
expanded: false,
|
|
24
|
-
controls: null,
|
|
25
24
|
hasPopup: false,
|
|
25
|
+
controls: null,
|
|
26
|
+
trigger: null,
|
|
26
27
|
};
|
|
27
28
|
},
|
|
28
29
|
|
|
29
30
|
computed: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
id() {
|
|
32
|
+
return `dropdown-menu-trigger-${this.apiDropdownMenu().id}`;
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
componentContent() {
|
|
36
|
+
return this.apiDropdownMenu().componentContent;
|
|
33
37
|
},
|
|
34
38
|
|
|
35
39
|
items() {
|
|
@@ -45,14 +49,28 @@ export default {
|
|
|
45
49
|
},
|
|
46
50
|
},
|
|
47
51
|
|
|
52
|
+
watch: {
|
|
53
|
+
expanded() {
|
|
54
|
+
this.toggleAriaHasPopup();
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
|
|
48
58
|
mounted() {
|
|
49
|
-
|
|
59
|
+
const trigger = {
|
|
60
|
+
id: this.id,
|
|
61
|
+
el: this.$el,
|
|
62
|
+
cancel: this.cancel,
|
|
63
|
+
focus: this.focus,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
this.apiDropdownMenu().registerTrigger(trigger);
|
|
67
|
+
|
|
50
68
|
this.setTrigger();
|
|
51
69
|
this.addTriggerEvents();
|
|
52
70
|
},
|
|
53
71
|
|
|
54
72
|
destroyed() {
|
|
55
|
-
this.trigger.removeEventListener('click', this.onClick
|
|
73
|
+
this.trigger.removeEventListener('click', this.onClick);
|
|
56
74
|
},
|
|
57
75
|
|
|
58
76
|
methods: {
|
|
@@ -60,140 +78,102 @@ export default {
|
|
|
60
78
|
this.trigger = this.$el.querySelector(':first-child');
|
|
61
79
|
},
|
|
62
80
|
|
|
63
|
-
addTriggerEvents() {
|
|
64
|
-
this.trigger.addEventListener('click', (e) => {
|
|
65
|
-
if (this.expanded) {
|
|
66
|
-
this.onClick();
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// delay stop propagation to close other visible
|
|
71
|
-
// dropdowns and delay click event to control
|
|
72
|
-
// this dropdown visibility
|
|
73
|
-
setTimeout(() => e.stopImmediatePropagation(), 50);
|
|
74
|
-
setTimeout(() => this.onClick(), 100);
|
|
75
|
-
});
|
|
76
|
-
},
|
|
77
|
-
|
|
78
81
|
/**
|
|
79
|
-
*
|
|
82
|
+
* Add event listener to slot element
|
|
83
|
+
*
|
|
84
|
+
* The click event has to be added to the slot child element
|
|
85
|
+
* since we are not setting the onclick on the component
|
|
86
|
+
* itself.
|
|
87
|
+
*
|
|
88
|
+
* Slot must have only one child element. It avoids
|
|
89
|
+
* errors related to adding the event listener.
|
|
80
90
|
*/
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.toggleExpanded();
|
|
84
|
-
this.content.show();
|
|
85
|
-
}
|
|
91
|
+
addTriggerEvents() {
|
|
92
|
+
this.trigger.addEventListener('click', this.onClick);
|
|
86
93
|
},
|
|
87
94
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (!this.trigger) return;
|
|
95
|
+
init(e) {
|
|
96
|
+
if (!this.componentContent) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
93
99
|
|
|
94
|
-
this.
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
if (this.expanded) {
|
|
101
|
+
this.cancel();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
97
104
|
|
|
98
|
-
|
|
99
|
-
* Toggles aria expanded attribute/state
|
|
100
|
-
*/
|
|
101
|
-
toggleExpanded() {
|
|
102
|
-
this.expanded = !this.expanded;
|
|
103
|
-
},
|
|
105
|
+
this.expanded = true;
|
|
104
106
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.
|
|
107
|
+
// delay stop propagation to close other visible
|
|
108
|
+
// dropdowns and delay click event to control
|
|
109
|
+
// this dropdown visibility
|
|
110
|
+
setTimeout(() => e.stopImmediatePropagation(), 50);
|
|
111
|
+
setTimeout(() => this.showComponentContent(), 100);
|
|
110
112
|
},
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
*/
|
|
115
|
-
toggleHasPopup() {
|
|
116
|
-
if (!this.content) return;
|
|
117
|
-
|
|
118
|
-
this.hasPopup = !this.hasPopup;
|
|
119
|
-
|
|
120
|
-
if (!this.hasPopup) {
|
|
121
|
-
this.controls = null;
|
|
114
|
+
cancel() {
|
|
115
|
+
if (!this.componentContent) {
|
|
122
116
|
return;
|
|
123
117
|
}
|
|
124
118
|
|
|
125
|
-
this.
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* On click, do the following:
|
|
130
|
-
*
|
|
131
|
-
* 1. Toggle aria expanded attribute/state
|
|
132
|
-
* 2. Open the menu if it's closed
|
|
133
|
-
* 3. Close the menu if it's open
|
|
134
|
-
*/
|
|
135
|
-
onClick() {
|
|
136
|
-
if (!this.content) return;
|
|
119
|
+
this.expanded = false;
|
|
137
120
|
|
|
138
|
-
this.
|
|
121
|
+
this.hideComponentContent();
|
|
122
|
+
},
|
|
139
123
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
else this.content.hide();
|
|
143
|
-
});
|
|
124
|
+
focus() {
|
|
125
|
+
if (this.trigger) this.trigger.focus();
|
|
144
126
|
},
|
|
145
127
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
*/
|
|
150
|
-
hide() {
|
|
151
|
-
this.hideExpanded();
|
|
128
|
+
showComponentContent() {
|
|
129
|
+
this.componentContent.show();
|
|
130
|
+
},
|
|
152
131
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
});
|
|
132
|
+
hideComponentContent() {
|
|
133
|
+
this.componentContent.hide();
|
|
156
134
|
},
|
|
157
135
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
* 2. if the menu is expanded, focus the first menu item
|
|
163
|
-
*/
|
|
164
|
-
onKeyArrowDown() {
|
|
165
|
-
if (!this.content) return;
|
|
136
|
+
toggleAriaHasPopup() {
|
|
137
|
+
if (this.expanded) {
|
|
138
|
+
this.hasPopup = this.componentContent !== null;
|
|
139
|
+
this.controls = this.hasPopup ? this.componentContent.id : null;
|
|
166
140
|
|
|
167
|
-
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
168
143
|
|
|
169
|
-
this
|
|
170
|
-
|
|
171
|
-
});
|
|
144
|
+
this.hasPopup = null;
|
|
145
|
+
this.controls = null;
|
|
172
146
|
},
|
|
173
147
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
* 1. if the menu is not expanded, expand it and focus the last menu item
|
|
178
|
-
* 2. if the menu is expanded, focus the last menu item
|
|
179
|
-
*/
|
|
180
|
-
onKeyArrowUp() {
|
|
181
|
-
if (!this.content) return;
|
|
148
|
+
onClick(e) {
|
|
149
|
+
this.init(e);
|
|
150
|
+
},
|
|
182
151
|
|
|
183
|
-
|
|
152
|
+
onKeyDownOrUp(e) {
|
|
153
|
+
if (!this.expanded) {
|
|
154
|
+
this.$el.click(e);
|
|
155
|
+
}
|
|
184
156
|
|
|
157
|
+
const keyCode = e.code;
|
|
158
|
+
const listItemPosition =
|
|
159
|
+
keyCode === 'ArrowDown'
|
|
160
|
+
? 'firstMenuItem'
|
|
161
|
+
: keyCode === 'ArrowUp'
|
|
162
|
+
? 'lastMenuItem'
|
|
163
|
+
: null;
|
|
164
|
+
|
|
165
|
+
// settimeout here is delaying the focusing the element
|
|
166
|
+
// since it is not rendered yet. All items will only
|
|
167
|
+
// be available when the content is fully visible.
|
|
185
168
|
this.$nextTick(() => {
|
|
186
|
-
this.
|
|
169
|
+
setTimeout(() => this[listItemPosition].focus(), 100);
|
|
187
170
|
});
|
|
188
171
|
},
|
|
189
172
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
this.toggleExpanded();
|
|
195
|
-
this.content.hide();
|
|
196
|
-
}
|
|
173
|
+
// change it to a better name or move the methods inside to another function
|
|
174
|
+
onKeyEsc() {
|
|
175
|
+
this.cancel();
|
|
176
|
+
this.focus();
|
|
197
177
|
},
|
|
198
178
|
},
|
|
199
179
|
};
|
|
@@ -1,7 +1,33 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<div
|
|
3
|
+
:class="[
|
|
4
|
+
headless ? 'form-feedback' : 'mt-1 flex items-baseline gap-2',
|
|
5
|
+
// variant styles
|
|
6
|
+
headless ? `form-feedback--${variant}` : null,
|
|
7
|
+
]"
|
|
8
|
+
>
|
|
9
|
+
<component
|
|
10
|
+
v-if="showIcon"
|
|
11
|
+
:is="icon"
|
|
12
|
+
:class="[
|
|
13
|
+
headless ? 'form-feedback__icon' : 'relative top-1 h-4 w-4 shrink-0',
|
|
14
|
+
// variant styles
|
|
15
|
+
headless
|
|
16
|
+
? `form-feedback__icon--${variant}`
|
|
17
|
+
: isError
|
|
18
|
+
? 'text-error-500'
|
|
19
|
+
: null,
|
|
20
|
+
]"
|
|
21
|
+
/>
|
|
22
|
+
<span
|
|
23
|
+
:class="[
|
|
24
|
+
headless
|
|
25
|
+
? 'form-feedback--text'
|
|
26
|
+
: 'text-sm lowercase text-gray-500 first-letter:uppercase',
|
|
27
|
+
]"
|
|
28
|
+
>
|
|
29
|
+
<slot />
|
|
30
|
+
</span>
|
|
5
31
|
</div>
|
|
6
32
|
</template>
|
|
7
33
|
|
|
@@ -17,32 +43,23 @@ export default {
|
|
|
17
43
|
},
|
|
18
44
|
|
|
19
45
|
props: {
|
|
20
|
-
variant: {
|
|
21
|
-
type: [String, Object],
|
|
22
|
-
default: '',
|
|
23
|
-
validator(value) {
|
|
24
|
-
if (value === '' || typeof value === 'object') {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return ['success', 'warning', 'error'].includes(value);
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
46
|
hideIcon: {
|
|
32
47
|
type: Boolean,
|
|
33
48
|
default: false,
|
|
34
49
|
},
|
|
50
|
+
headless: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
default: false,
|
|
53
|
+
},
|
|
54
|
+
variant: {
|
|
55
|
+
type: [String, Object],
|
|
56
|
+
default: '',
|
|
57
|
+
},
|
|
35
58
|
},
|
|
36
59
|
|
|
37
60
|
computed: {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (this.variant) {
|
|
42
|
-
classes[`form-feedback--${this.variant}`] = true;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return classes;
|
|
61
|
+
isError() {
|
|
62
|
+
return this.variant === 'error';
|
|
46
63
|
},
|
|
47
64
|
|
|
48
65
|
icon() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<component :is="as" :class="
|
|
2
|
+
<component :is="as" :class="[headless ? 'form-control' : 'mt-3']">
|
|
3
3
|
<slot></slot>
|
|
4
4
|
</component>
|
|
5
5
|
</template>
|
|
@@ -11,12 +11,10 @@ export default {
|
|
|
11
11
|
type: String,
|
|
12
12
|
default: 'div',
|
|
13
13
|
},
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
classes: {},
|
|
19
|
-
};
|
|
14
|
+
headless: {
|
|
15
|
+
type: Boolean,
|
|
16
|
+
default: false,
|
|
17
|
+
},
|
|
20
18
|
},
|
|
21
19
|
};
|
|
22
20
|
</script>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<label
|
|
3
|
+
:class="[
|
|
4
|
+
headless
|
|
5
|
+
? 'form-label'
|
|
6
|
+
: 'mb-1 flex justify-between gap-3 text-sm font-semibold',
|
|
7
|
+
]"
|
|
8
|
+
>
|
|
9
|
+
<slot />
|
|
10
|
+
</label>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
export default {
|
|
15
|
+
props: {
|
|
16
|
+
headless: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: false,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
</script>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<input
|
|
3
|
+
:class="classComputed"
|
|
4
|
+
:value="modelValue"
|
|
5
|
+
:disabled="disabled"
|
|
6
|
+
v-bind="attrsComputed"
|
|
7
|
+
/>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script>
|
|
11
|
+
import {
|
|
12
|
+
formControlMixin,
|
|
13
|
+
formControlStyleMixin,
|
|
14
|
+
} from '../../../mixins/form-control';
|
|
15
|
+
export default {
|
|
16
|
+
mixins: [formControlMixin, formControlStyleMixin],
|
|
17
|
+
data() {
|
|
18
|
+
return {
|
|
19
|
+
name: 'input',
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<style scoped>
|
|
26
|
+
/* input[type='date']::-webkit-inner-spin-button,
|
|
27
|
+
input[type='date']::-webkit-calendar-picker-indicator {
|
|
28
|
+
position: absolute;
|
|
29
|
+
opacity: 0;
|
|
30
|
+
} */
|
|
31
|
+
input[type='number'] {
|
|
32
|
+
appearance: textfield;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
input[type='number']::-webkit-inner-spin-button,
|
|
36
|
+
input[type='number']::-webkit-outer-spin-button {
|
|
37
|
+
appearance: none;
|
|
38
|
+
-webkit-appearance: none;
|
|
39
|
+
}
|
|
40
|
+
</style>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="classComputedWrapper">
|
|
3
|
+
<input
|
|
4
|
+
:class="classComputed"
|
|
5
|
+
:value="value"
|
|
6
|
+
:disabled="disabled"
|
|
7
|
+
v-bind="attrsComputed"
|
|
8
|
+
/>
|
|
9
|
+
<div :class="classComputedWrapperIcon">
|
|
10
|
+
<component :is="icon" class="h-5 w-5" />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
import { formControlIconMixin } from '../../../mixins/form-control-icon';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
name: 'VTInputIcon',
|
|
20
|
+
|
|
21
|
+
mixins: [formControlIconMixin],
|
|
22
|
+
|
|
23
|
+
props: {
|
|
24
|
+
icon: {
|
|
25
|
+
type: String,
|
|
26
|
+
default: null,
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
iconPlacement: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: 'left',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
</script>
|