@veritree/ui 0.19.2-2 → 0.19.2-21
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/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 +73 -0
- package/package.json +7 -3
- package/src/components/Avatar/VTAvatar.vue +32 -29
- package/src/components/Button/VTButton.vue +9 -5
- package/src/components/Dialog/VTDialog.vue +6 -11
- package/src/components/Dialog/VTDialogClose.vue +9 -9
- package/src/components/Dialog/VTDialogContent.vue +9 -9
- package/src/components/Dialog/VTDialogFooter.vue +5 -5
- package/src/components/Dialog/VTDialogHeader.vue +8 -8
- package/src/components/Dialog/VTDialogMain.vue +8 -8
- package/src/components/Dialog/VTDialogOverlay.vue +8 -8
- package/src/components/Dialog/VTDialogTitle.vue +4 -4
- package/src/components/Disclosure/VTDisclosureContent.vue +1 -1
- package/src/components/Disclosure/VTDisclosureDetails.vue +2 -2
- package/src/components/Disclosure/VTDisclosureHeader.vue +1 -1
- package/src/components/Disclosure/VTDisclosureIcon.vue +1 -1
- package/src/components/Drawer/VTDrawer.vue +14 -16
- package/src/components/Drawer/VTDrawerClose.vue +9 -9
- package/src/components/Drawer/VTDrawerContent.vue +8 -8
- package/src/components/Drawer/VTDrawerFooter.vue +3 -3
- 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 +27 -29
- package/src/components/DropdownMenu/VTDropdownMenuContent.vue +27 -70
- package/src/components/DropdownMenu/VTDropdownMenuDivider.vue +8 -5
- package/src/components/DropdownMenu/VTDropdownMenuItem.vue +14 -123
- package/src/components/DropdownMenu/VTDropdownMenuLabel.vue +3 -3
- package/src/components/DropdownMenu/VTDropdownMenuTrigger.vue +96 -121
- package/src/components/Form/VTFormFeedback.vue +33 -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 +122 -50
- package/src/components/Listbox/VTListboxContent.vue +20 -116
- package/src/components/Listbox/VTListboxItem.vue +116 -166
- package/src/components/Listbox/VTListboxLabel.vue +3 -14
- package/src/components/Listbox/VTListboxList.vue +10 -40
- package/src/components/Listbox/VTListboxSearch.vue +76 -68
- package/src/components/Listbox/VTListboxTrigger.vue +75 -86
- package/src/components/Popover/VTPopover.vue +24 -30
- package/src/components/Popover/VTPopoverContent.vue +24 -59
- package/src/components/Popover/VTPopoverDivider.vue +4 -11
- package/src/components/Popover/VTPopoverItem.vue +21 -14
- package/src/components/Popover/VTPopoverTrigger.vue +126 -21
- package/src/components/Tabs/VTTab.vue +10 -11
- package/src/components/Tabs/VTTabGroup.vue +9 -7
- package/src/components/Tabs/VTTabPanel.vue +4 -5
- package/src/components/Transitions/FadeInOut.vue +2 -2
- package/src/components/Utils/FloatingUi.vue +87 -0
- package/package-lock.json +0 -13
- package/src/components/Modal/VTModal.vue +0 -69
- package/src/utils/genId.js +0 -13
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import FloatingUi from '../src/components/Utils/FloatingUi.vue';
|
|
2
|
+
|
|
3
|
+
export const floatingUiContentMixin = {
|
|
4
|
+
components: {
|
|
5
|
+
FloatingUi,
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
props: {
|
|
9
|
+
headless: {
|
|
10
|
+
type: Boolean,
|
|
11
|
+
default: false,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
data() {
|
|
16
|
+
return {
|
|
17
|
+
el: null,
|
|
18
|
+
visible: false,
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
mounted() {
|
|
23
|
+
document.addEventListener('click', this.onDocumentClick);
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
destroyed() {
|
|
27
|
+
document.removeEventListener('click', this.onDocumentClick);
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
methods: {
|
|
31
|
+
show() {
|
|
32
|
+
if (this.visible) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.visible = true;
|
|
37
|
+
|
|
38
|
+
this.$nextTick(() => {
|
|
39
|
+
this.component.setActive();
|
|
40
|
+
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
this.el = document.getElementById(this.id);
|
|
43
|
+
this.$emit('shown');
|
|
44
|
+
}, 100);
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
hide() {
|
|
49
|
+
if (!this.visible) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.visible = false;
|
|
54
|
+
|
|
55
|
+
this.$nextTick(() => {
|
|
56
|
+
this.component.clearActive();
|
|
57
|
+
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
this.el = document.getElementById(this.id);
|
|
60
|
+
this.$emit('hidden');
|
|
61
|
+
}, 100);
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
onDocumentClick(e) {
|
|
66
|
+
if (!e) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
e.stopPropagation();
|
|
71
|
+
|
|
72
|
+
if (this.visible && !this.el.contains(e.target)) {
|
|
73
|
+
this.componentTrigger.cancel();
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
setActiveDescedant(id) {
|
|
78
|
+
this.activeDescedant = id;
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
export const floatingUiItemMixin = {
|
|
2
|
+
props: {
|
|
3
|
+
headless: {
|
|
4
|
+
type: Boolean,
|
|
5
|
+
default: false,
|
|
6
|
+
},
|
|
7
|
+
disabled: {
|
|
8
|
+
type: Boolean,
|
|
9
|
+
default: false,
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
computed: {
|
|
14
|
+
id() {
|
|
15
|
+
return `${this.componentName}-${this.apiInjected().id}-${this.index}`;
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
items() {
|
|
19
|
+
return this.apiInjected().items;
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
componentContent() {
|
|
23
|
+
return this.apiInjected().componentContent;
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
componentTrigger() {
|
|
27
|
+
return this.apiInjected().componentTrigger;
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
classComputed() {
|
|
31
|
+
return [
|
|
32
|
+
// default styles
|
|
33
|
+
this.headless
|
|
34
|
+
? `${this.componentName}`
|
|
35
|
+
: 'relative z-10 flex items-center gap-2 px-3 py-2 text-inherit no-underline cursor-pointer',
|
|
36
|
+
// disabled state styles
|
|
37
|
+
this.headless
|
|
38
|
+
? this.disabled
|
|
39
|
+
? `${this.componentName}--disabled`
|
|
40
|
+
: null
|
|
41
|
+
: this.disabled
|
|
42
|
+
? 'pointer-events-none opacity-75'
|
|
43
|
+
: null,
|
|
44
|
+
// selected state styles
|
|
45
|
+
this.headless
|
|
46
|
+
? this.selected
|
|
47
|
+
? `${this.componentName}--selected`
|
|
48
|
+
: null
|
|
49
|
+
: this.selected
|
|
50
|
+
? 'bg-gray-200'
|
|
51
|
+
: null,
|
|
52
|
+
];
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
data() {
|
|
57
|
+
return {
|
|
58
|
+
index: null,
|
|
59
|
+
selected: false,
|
|
60
|
+
tabIndex: 0,
|
|
61
|
+
eventType: null,
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
watch: {
|
|
66
|
+
selected(newValue) {
|
|
67
|
+
if (!newValue || !this.componentContent) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.componentContent.setActiveDescedant(this.id);
|
|
72
|
+
|
|
73
|
+
// do not scroll into view if it's a mouse event
|
|
74
|
+
if (this.eventType && this.eventType.includes('mouse')) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.$el.scrollIntoView({ block: 'nearest' });
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
mounted() {
|
|
83
|
+
this.init();
|
|
84
|
+
this.addMouseEventListeners();
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
beforeUnmount() {
|
|
88
|
+
this.apiInjected().unregisterItem(this.id);
|
|
89
|
+
this.removeMouseEventListeners();
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
methods: {
|
|
93
|
+
init() {
|
|
94
|
+
this.index = this.items.length;
|
|
95
|
+
|
|
96
|
+
const item = {
|
|
97
|
+
id: this.id,
|
|
98
|
+
text: '',
|
|
99
|
+
select: this.select,
|
|
100
|
+
unselect: this.unselect,
|
|
101
|
+
isSelected: this.isSelected,
|
|
102
|
+
focus: this.focus,
|
|
103
|
+
onClick: this.onClick,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
this.apiInjected().registerItem(item);
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* mousemove and mouseleave events will be attached to
|
|
111
|
+
* the element here instead of using vue @mousemove
|
|
112
|
+
* and @mouseleave in the element since they did
|
|
113
|
+
* not worker properly
|
|
114
|
+
*/
|
|
115
|
+
addMouseEventListeners() {
|
|
116
|
+
this.$el.addEventListener('mousemove', this.onMousemove);
|
|
117
|
+
this.$el.addEventListener('mouseleave', this.onMouseleave);
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* remove the mousemove and mouseleave added for
|
|
122
|
+
* avoiding memory leaks, if @mousemove and
|
|
123
|
+
* @mouseleave were in the element, this
|
|
124
|
+
* wound't be needed
|
|
125
|
+
*/
|
|
126
|
+
removeMouseEventListeners() {
|
|
127
|
+
this.$el.removeEventListener('mousemove', this.onMousemove);
|
|
128
|
+
this.$el.removeEventListener('mouseleave', this.onMouseleave);
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
select(eventType) {
|
|
132
|
+
this.eventType = eventType;
|
|
133
|
+
this.selected = true;
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
unselect() {
|
|
137
|
+
this.selected = false;
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
isSelected() {
|
|
141
|
+
return this.selected;
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
focus() {
|
|
145
|
+
if (!this.$el) return;
|
|
146
|
+
|
|
147
|
+
this.tabIndex = -1;
|
|
148
|
+
this.selected = true;
|
|
149
|
+
this.$el.focus();
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
focusFirstItem() {
|
|
153
|
+
const selectedIndex = this.getItemSelectedIndex();
|
|
154
|
+
const newSelectedIndex = 0;
|
|
155
|
+
|
|
156
|
+
this.setFocusToItem(selectedIndex, newSelectedIndex);
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
focusLastItem() {
|
|
160
|
+
const selectedIndex = this.getItemSelectedIndex();
|
|
161
|
+
const newSelectedIndex = this.items.length - 1;
|
|
162
|
+
|
|
163
|
+
this.setFocusToItem(selectedIndex, newSelectedIndex);
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Focus the next item in the menu.
|
|
168
|
+
* If is the last item, jump to the first item.
|
|
169
|
+
*/
|
|
170
|
+
focusNextItem() {
|
|
171
|
+
const selectedIndex = this.getItemSelectedIndex();
|
|
172
|
+
const isLast = selectedIndex === this.items.length - 1;
|
|
173
|
+
const firstItemIndex = 0;
|
|
174
|
+
const nextItemIndex = selectedIndex + 1;
|
|
175
|
+
const newSelectedIndex = isLast ? firstItemIndex : nextItemIndex;
|
|
176
|
+
|
|
177
|
+
this.setFocusToItem(selectedIndex, newSelectedIndex);
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Focus the previous item in the menu.
|
|
182
|
+
* If is the first item, jump to the last item.
|
|
183
|
+
*/
|
|
184
|
+
focusPreviousItem() {
|
|
185
|
+
const selectedIndex = this.getItemSelectedIndex();
|
|
186
|
+
const isFirst = selectedIndex === 0;
|
|
187
|
+
const lastItemIndex = this.items.length - 1;
|
|
188
|
+
const previousItemIndex = selectedIndex - 1;
|
|
189
|
+
const newSelectedIndex = isFirst ? lastItemIndex : previousItemIndex;
|
|
190
|
+
|
|
191
|
+
this.setFocusToItem(selectedIndex, newSelectedIndex);
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Focus/select item by removing its tabindex and calling
|
|
196
|
+
* focus to the element.
|
|
197
|
+
*
|
|
198
|
+
* @param {Number, String} selectedIndex
|
|
199
|
+
* @param {Number, String} newSelectedIndex
|
|
200
|
+
*/
|
|
201
|
+
setFocusToItem(selectedIndex, newSelectedIndex) {
|
|
202
|
+
this.tabIndex = 0;
|
|
203
|
+
|
|
204
|
+
// before focusing, let's unselect selected
|
|
205
|
+
// item that were previously focused
|
|
206
|
+
if (selectedIndex >= 0) {
|
|
207
|
+
this.items[selectedIndex].unselect();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// focus new item
|
|
211
|
+
if (this.items[newSelectedIndex]) {
|
|
212
|
+
this.items[newSelectedIndex].focus();
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
getItemSelectedIndex() {
|
|
217
|
+
return this.items.findIndex((item) => item.isSelected());
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
leaveMenu() {
|
|
221
|
+
if (this.componentTrigger) {
|
|
222
|
+
this.componentTrigger.cancel();
|
|
223
|
+
this.componentTrigger.focus();
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
onClick() {
|
|
228
|
+
if (this.disabled) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.value !== undefined
|
|
233
|
+
? this.apiInjected().emit(this.value)
|
|
234
|
+
: this.$emit('click');
|
|
235
|
+
|
|
236
|
+
this.$nextTick(() => this.leaveMenu());
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
onKeyEsc() {
|
|
240
|
+
this.leaveMenu();
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
onMousemove(event) {
|
|
244
|
+
if (this.selected) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// unselect all items before selecting new one
|
|
249
|
+
for (const item of this.items) {
|
|
250
|
+
item.unselect();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Select item passing the event type to decide if
|
|
255
|
+
* scrolling will be disabled or not. It is
|
|
256
|
+
* expected that on mouse move event, the scroll
|
|
257
|
+
* doesn't happen automatically.
|
|
258
|
+
*/
|
|
259
|
+
this.select(event.type);
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
onMouseleave() {
|
|
263
|
+
this.unselect();
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { computePosition, flip, shift, offset, size } from '@floating-ui/dom';
|
|
2
|
+
|
|
3
|
+
export const floatingUiMixin = {
|
|
4
|
+
data() {
|
|
5
|
+
return {
|
|
6
|
+
component: null,
|
|
7
|
+
componentTrigger: null,
|
|
8
|
+
componentContent: null,
|
|
9
|
+
active: false,
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
watch: {
|
|
14
|
+
active(newVal) {
|
|
15
|
+
if (newVal) this.$nextTick(() => this.positionContentToTrigger());
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
mounted() {
|
|
20
|
+
this.component = {
|
|
21
|
+
setActive: this.setActive,
|
|
22
|
+
clearActive: this.clearActive,
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
methods: {
|
|
27
|
+
setActive() {
|
|
28
|
+
this.active = true;
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
clearActive() {
|
|
32
|
+
this.active = null;
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
positionContentToTrigger() {
|
|
36
|
+
const trigger = document.getElementById(this.componentTrigger.id);
|
|
37
|
+
const content = document.getElementById(this.componentContent.id);
|
|
38
|
+
const minWidthLimit = Number(this.floatingUiMinWidth);
|
|
39
|
+
|
|
40
|
+
computePosition(trigger, content, {
|
|
41
|
+
placement: this.placement,
|
|
42
|
+
middleware: [
|
|
43
|
+
offset(5),
|
|
44
|
+
flip(),
|
|
45
|
+
shift({ padding: 5 }),
|
|
46
|
+
size({
|
|
47
|
+
apply({ rects }) {
|
|
48
|
+
if (!minWidthLimit) return;
|
|
49
|
+
|
|
50
|
+
const width = rects.reference.width;
|
|
51
|
+
const minWidth = width < minWidthLimit ? minWidthLimit : width;
|
|
52
|
+
|
|
53
|
+
Object.assign(content.style, {
|
|
54
|
+
minWidth: `${minWidth}px`,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
],
|
|
59
|
+
}).then(({ x, y }) => {
|
|
60
|
+
Object.assign(content.style, {
|
|
61
|
+
left: `${x}px`,
|
|
62
|
+
top: `${y}px`,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { formControlMixin, formControlStyleMixin } from '../mixins/form-control';
|
|
2
|
+
|
|
3
|
+
export const formControlIconMixin = {
|
|
4
|
+
inheritAttrs: false,
|
|
5
|
+
|
|
6
|
+
mixins: [formControlMixin, formControlStyleMixin],
|
|
7
|
+
|
|
8
|
+
data() {
|
|
9
|
+
return {
|
|
10
|
+
name: 'input',
|
|
11
|
+
};
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
computed: {
|
|
15
|
+
isLeft() {
|
|
16
|
+
return this.iconPlacement === 'left';
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
isRight() {
|
|
20
|
+
return this.iconPlacement === 'right';
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
classComputedWrapper() {
|
|
24
|
+
return [
|
|
25
|
+
this.headless ? 'form-control-wrapper' : 'relative',
|
|
26
|
+
// placement styles
|
|
27
|
+
this.headless
|
|
28
|
+
? `form-control-icon--${this.placement}`
|
|
29
|
+
: this.isLeft
|
|
30
|
+
? '[&_input]:pl-9'
|
|
31
|
+
: this.isRight
|
|
32
|
+
? '[&_input]:pr-9'
|
|
33
|
+
: null,
|
|
34
|
+
];
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
classComputedWrapperIcon() {
|
|
38
|
+
return [
|
|
39
|
+
this.headless
|
|
40
|
+
? 'form-control-wrapper__icon'
|
|
41
|
+
: `absolute top-0 bottom-0 flex w-9 justify-center items-center text-gray-400`,
|
|
42
|
+
// placement styles
|
|
43
|
+
this.headless
|
|
44
|
+
? null
|
|
45
|
+
: this.isLeft
|
|
46
|
+
? 'left-0'
|
|
47
|
+
: this.isRight
|
|
48
|
+
? 'right-0'
|
|
49
|
+
: null,
|
|
50
|
+
];
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export const formControlMixin = {
|
|
2
|
+
props: {
|
|
3
|
+
disabled: {
|
|
4
|
+
type: Boolean,
|
|
5
|
+
default: false,
|
|
6
|
+
},
|
|
7
|
+
headless: {
|
|
8
|
+
type: Boolean,
|
|
9
|
+
default: false,
|
|
10
|
+
},
|
|
11
|
+
modelValue: {
|
|
12
|
+
type: [String, Number, Object, Array],
|
|
13
|
+
default: null,
|
|
14
|
+
},
|
|
15
|
+
variant: {
|
|
16
|
+
type: [String, Object, Function],
|
|
17
|
+
default: '',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
computed: {
|
|
22
|
+
attrsComputed() {
|
|
23
|
+
// `Object.assign` merges objects together to form a new object
|
|
24
|
+
return Object.assign(
|
|
25
|
+
{},
|
|
26
|
+
// We add all the listeners from the parent
|
|
27
|
+
this.$attrs,
|
|
28
|
+
// Then we can add custom listeners or override the
|
|
29
|
+
// behavior of some listeners.
|
|
30
|
+
{
|
|
31
|
+
// This ensures that the component works with v-model
|
|
32
|
+
onInput: (event) => {
|
|
33
|
+
// if (this.lazy) return;
|
|
34
|
+
this.$emit('update:modelValue', event.target.value);
|
|
35
|
+
},
|
|
36
|
+
onBlur: (event) => {
|
|
37
|
+
this.$emit('blur', event);
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
isError() {
|
|
46
|
+
return this.variant === 'error';
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const formControlStyleMixin = {
|
|
52
|
+
computed: {
|
|
53
|
+
classComputed() {
|
|
54
|
+
return [
|
|
55
|
+
this.headless
|
|
56
|
+
? `${this.name}`
|
|
57
|
+
: 'leading-0 flex outline-none w-full max-w-full appearance-none items-center justify-between rounded border border-solid px-3 py-2 font-inherit text-base text-inherit file:hidden focus:border-secondary-200 appearance-none',
|
|
58
|
+
// variant styles
|
|
59
|
+
this.headless
|
|
60
|
+
? `${this.name}--${this.variant}`
|
|
61
|
+
: this.isError
|
|
62
|
+
? 'border-error-300'
|
|
63
|
+
: 'border-gray-300',
|
|
64
|
+
// height styles
|
|
65
|
+
this.headless
|
|
66
|
+
? null
|
|
67
|
+
: this.name === 'textarea'
|
|
68
|
+
? 'min-h-10' // limit it because input type number height can be different from other input types
|
|
69
|
+
: 'h-12 md:h-10',
|
|
70
|
+
];
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veritree/ui",
|
|
3
|
-
"version": "0.19.2-
|
|
3
|
+
"version": "0.19.2-21",
|
|
4
4
|
"description": "veritree ui library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -11,9 +11,13 @@
|
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@
|
|
14
|
+
"@floating-ui/dom": "^1.0.4",
|
|
15
|
+
"@veritree/icons": "^0.45.1"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
|
-
"@nuxt/kit": "^3.0.0
|
|
18
|
+
"@nuxt/kit": "^3.0.0",
|
|
19
|
+
"prettier": "^2.7.1",
|
|
20
|
+
"prettier-plugin-tailwindcss": "^0.1.13",
|
|
21
|
+
"tailwindcss": "^3.2.4"
|
|
18
22
|
}
|
|
19
23
|
}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
:class="
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
:class="[
|
|
4
|
+
// default styles
|
|
5
|
+
headless
|
|
6
|
+
? 'avatar'
|
|
7
|
+
: 'flex items-center justify-center overflow-hidden rounded-full bg-white border border-solid',
|
|
8
|
+
// variant styles
|
|
9
|
+
headless ? `avatar--${variant}` : null,
|
|
10
|
+
// sizes styles
|
|
11
|
+
headless
|
|
12
|
+
? `avatar--${size}`
|
|
13
|
+
: isSmall
|
|
14
|
+
? 'h-8 w-8'
|
|
15
|
+
: isLarge
|
|
16
|
+
? 'h-10 w-10'
|
|
17
|
+
: null,
|
|
18
|
+
]"
|
|
12
19
|
>
|
|
13
20
|
<slot></slot>
|
|
14
21
|
</div>
|
|
@@ -18,32 +25,28 @@
|
|
|
18
25
|
export default {
|
|
19
26
|
name: 'VTAvatar',
|
|
20
27
|
|
|
21
|
-
provide() {
|
|
22
|
-
return {
|
|
23
|
-
api: () => {
|
|
24
|
-
const { dark: isDark, headless: isHeadless, light: isLight } = this;
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
isDark,
|
|
28
|
-
isHeadless,
|
|
29
|
-
isLight,
|
|
30
|
-
};
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
|
|
35
28
|
props: {
|
|
36
29
|
headless: {
|
|
37
30
|
type: Boolean,
|
|
38
31
|
default: false,
|
|
39
32
|
},
|
|
40
|
-
|
|
41
|
-
type:
|
|
42
|
-
default:
|
|
33
|
+
variant: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: 'primary',
|
|
43
36
|
},
|
|
44
|
-
|
|
45
|
-
type:
|
|
46
|
-
default:
|
|
37
|
+
size: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: 'large',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
computed: {
|
|
44
|
+
isLarge() {
|
|
45
|
+
return this.size === 'large';
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
isSmall() {
|
|
49
|
+
return this.size === 'small';
|
|
47
50
|
},
|
|
48
51
|
},
|
|
49
52
|
};
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
headless
|
|
17
17
|
? `button--${variant}`
|
|
18
18
|
: isPrimary
|
|
19
|
-
? '
|
|
19
|
+
? 'bg-secondary-400 hover:bg-secondary-500 active:bg-secondary-600 border-transparent text-white disabled:bg-gray-200 disabled:text-gray-400'
|
|
20
20
|
: isSecondary
|
|
21
21
|
? 'border-gray-400 bg-white text-gray-700 hover:bg-gray-100 active:bg-gray-200 disabled:border-gray-300 disabled:text-gray-400'
|
|
22
22
|
: isTertiary
|
|
23
|
-
? '
|
|
23
|
+
? 'text-secondary-400 hover:text-secondary-500 active:text-secondary-500 border-transparent disabled:text-gray-400'
|
|
24
24
|
: isIcon
|
|
25
25
|
? 'text-primary-100 focus-within:bg-gray-200 hover:bg-gray-200 active:bg-gray-300'
|
|
26
26
|
: null,
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
: isLarge
|
|
31
31
|
? isIcon
|
|
32
32
|
? 'h-8 w-8'
|
|
33
|
-
: 'h-10'
|
|
33
|
+
: 'h-12 sm:h-10'
|
|
34
34
|
: isSmall
|
|
35
35
|
? isIcon
|
|
36
36
|
? 'h-6 w-6 p-1'
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
<VTSpinner v-if="busy" class="absolute inset-0 m-auto" />
|
|
42
42
|
<span
|
|
43
43
|
:class="[
|
|
44
|
-
headless ? null : 'inline-flex items-center gap-2 self-center
|
|
44
|
+
headless ? null : 'mx-auto inline-flex items-center gap-2 self-center',
|
|
45
45
|
headless && busy ? 'button--busy' : busy ? 'invisible' : null,
|
|
46
46
|
]"
|
|
47
47
|
>
|
|
@@ -115,7 +115,11 @@ export default {
|
|
|
115
115
|
},
|
|
116
116
|
|
|
117
117
|
tag() {
|
|
118
|
-
return this.$attrs.href
|
|
118
|
+
return this.$attrs.href
|
|
119
|
+
? 'a'
|
|
120
|
+
: this.to
|
|
121
|
+
? resolveComponent('NuxtLink')
|
|
122
|
+
: 'button';
|
|
119
123
|
},
|
|
120
124
|
|
|
121
125
|
type() {
|