@veritree/ui 0.19.2-2 → 0.19.2-20
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 +102 -0
- package/mixins/floating-ui-item.js +219 -0
- package/mixins/floating-ui.js +74 -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 +26 -45
- package/src/components/Listbox/VTListboxContent.vue +24 -116
- package/src/components/Listbox/VTListboxItem.vue +10 -182
- package/src/components/Listbox/VTListboxLabel.vue +0 -10
- package/src/components/Listbox/VTListboxList.vue +24 -33
- package/src/components/Listbox/VTListboxSearch.vue +30 -29
- package/src/components/Listbox/VTListboxTrigger.vue +71 -88
- 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 +58 -0
- package/package-lock.json +0 -13
- package/src/components/Modal/VTModal.vue +0 -69
- package/src/utils/genId.js +0 -13
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<input
|
|
3
|
-
|
|
4
|
-
:class="{ ListboxList: headless, 'form-control mb-1': !headless }"
|
|
3
|
+
:value="modelValue"
|
|
5
4
|
type="text"
|
|
6
|
-
|
|
5
|
+
:class="classComputed"
|
|
6
|
+
@input="onInput"
|
|
7
|
+
@click.stop
|
|
7
8
|
@keydown.down.prevent="focusNextItem"
|
|
8
9
|
@keydown.up.prevent="focusPreviousItem"
|
|
9
10
|
@keydown.home.prevent="focusFirstItem"
|
|
@@ -15,40 +16,34 @@
|
|
|
15
16
|
</template>
|
|
16
17
|
|
|
17
18
|
<script>
|
|
19
|
+
import { formControlMixin } from '../../../mixins/form-control';
|
|
20
|
+
|
|
18
21
|
export default {
|
|
19
22
|
name: 'VTListboxSearch',
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
mixins: [formControlMixin],
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
headless: {
|
|
25
|
-
type: Boolean,
|
|
26
|
-
default: false,
|
|
27
|
-
},
|
|
28
|
-
},
|
|
26
|
+
inject: ['apiListbox'],
|
|
29
27
|
|
|
30
28
|
data() {
|
|
31
29
|
return {
|
|
32
|
-
|
|
30
|
+
name: 'listbox-search',
|
|
33
31
|
index: -1,
|
|
32
|
+
search: '',
|
|
34
33
|
};
|
|
35
34
|
},
|
|
36
35
|
|
|
37
36
|
computed: {
|
|
38
|
-
|
|
39
|
-
return this.
|
|
37
|
+
componentTrigger() {
|
|
38
|
+
return this.apiListbox().componentTrigger;
|
|
40
39
|
},
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
return this.
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
list() {
|
|
47
|
-
return this.api().list;
|
|
41
|
+
componentContent() {
|
|
42
|
+
return this.apiListbox().componentContent;
|
|
48
43
|
},
|
|
49
44
|
|
|
50
45
|
items() {
|
|
51
|
-
return this.
|
|
46
|
+
return this.apiListbox().items;
|
|
52
47
|
},
|
|
53
48
|
|
|
54
49
|
item() {
|
|
@@ -61,12 +56,13 @@ export default {
|
|
|
61
56
|
el: this.$el,
|
|
62
57
|
};
|
|
63
58
|
|
|
64
|
-
this.
|
|
59
|
+
this.apiListbox().registerSearch(search);
|
|
60
|
+
this.$nextTick(() => setTimeout(() => this.$el.focus(), 150));
|
|
65
61
|
},
|
|
66
62
|
|
|
67
|
-
|
|
63
|
+
beforeUnmount() {
|
|
68
64
|
this.search = '';
|
|
69
|
-
this.$emit('
|
|
65
|
+
this.$emit('update:modelValue', '');
|
|
70
66
|
},
|
|
71
67
|
|
|
72
68
|
methods: {
|
|
@@ -81,7 +77,9 @@ export default {
|
|
|
81
77
|
this.index = 0;
|
|
82
78
|
}
|
|
83
79
|
|
|
84
|
-
if (this.item)
|
|
80
|
+
if (this.item) {
|
|
81
|
+
this.item.select();
|
|
82
|
+
}
|
|
85
83
|
},
|
|
86
84
|
|
|
87
85
|
focusPreviousItem() {
|
|
@@ -109,21 +107,21 @@ export default {
|
|
|
109
107
|
},
|
|
110
108
|
|
|
111
109
|
unselectItem() {
|
|
112
|
-
const isMousemove = this.
|
|
110
|
+
const isMousemove = this.componentContent.getMousemove();
|
|
113
111
|
|
|
114
112
|
if (isMousemove) {
|
|
115
|
-
this.
|
|
113
|
+
this.componentContent.unsetMousemove();
|
|
116
114
|
this.items.forEach((item) => item.unselect());
|
|
117
115
|
}
|
|
118
116
|
|
|
119
117
|
if (this.item) this.item.unselect();
|
|
120
118
|
},
|
|
121
119
|
|
|
122
|
-
|
|
120
|
+
onInput(event) {
|
|
123
121
|
this.index = 0;
|
|
124
122
|
if (this.item) this.item.select();
|
|
125
123
|
|
|
126
|
-
this.$emit('
|
|
124
|
+
this.$emit('update:modelValue', event.target.value);
|
|
127
125
|
},
|
|
128
126
|
|
|
129
127
|
onKeyEnter() {
|
|
@@ -131,7 +129,10 @@ export default {
|
|
|
131
129
|
},
|
|
132
130
|
|
|
133
131
|
hide() {
|
|
134
|
-
if (this.
|
|
132
|
+
if (this.componentTrigger) {
|
|
133
|
+
this.componentTrigger.cancel();
|
|
134
|
+
this.componentTrigger.focus();
|
|
135
|
+
}
|
|
135
136
|
},
|
|
136
137
|
},
|
|
137
138
|
};
|
|
@@ -1,34 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<button
|
|
3
|
+
:id="id"
|
|
4
|
+
:class="classComputed"
|
|
5
|
+
:disabled="disabled"
|
|
3
6
|
:aria-expanded="expanded"
|
|
4
7
|
:aria-haspopup="hasPopup"
|
|
5
|
-
:class="{
|
|
6
|
-
'Listbox-button': headless,
|
|
7
|
-
'flex w-full justify-between rounded-md border border-solid py-2 px-3':
|
|
8
|
-
!headless,
|
|
9
|
-
'border-gray-300 text-gray-500': !dark && !headless,
|
|
10
|
-
'border-white/70 text-white focus-visible:ring-2 focus-visible:ring-white':
|
|
11
|
-
dark && !headless,
|
|
12
|
-
}"
|
|
13
8
|
type="button"
|
|
14
|
-
@click.
|
|
15
|
-
@keydown.down.prevent="
|
|
16
|
-
@keydown.up.prevent="
|
|
9
|
+
@click.prevent="onClick"
|
|
10
|
+
@keydown.down.prevent="onKeyDownOrUp"
|
|
11
|
+
@keydown.up.prevent="onKeyDownOrUp"
|
|
17
12
|
@keydown.esc.stop="onKeyEsc"
|
|
18
13
|
>
|
|
19
|
-
<span
|
|
20
|
-
:class="{
|
|
21
|
-
'Listbox-button__text': headless,
|
|
22
|
-
'text-left': !headless,
|
|
23
|
-
}"
|
|
24
|
-
>
|
|
14
|
+
<span :class="[headless ? 'listbox-button__text' : 'truncate text-left']">
|
|
25
15
|
<slot></slot>
|
|
26
16
|
</span>
|
|
27
|
-
<span
|
|
28
|
-
:class="{
|
|
29
|
-
'Listbox-button__icon': headless,
|
|
30
|
-
}"
|
|
31
|
-
>
|
|
17
|
+
<span :class="[headless ? 'listbox-button__icon' : 'shrink-0']">
|
|
32
18
|
<IconChevronDown
|
|
33
19
|
class="transition-transform"
|
|
34
20
|
:class="{ 'rotate-180': expanded }"
|
|
@@ -38,6 +24,7 @@
|
|
|
38
24
|
</template>
|
|
39
25
|
|
|
40
26
|
<script>
|
|
27
|
+
import { formControlMixin } from '../../../mixins/form-control';
|
|
41
28
|
import { IconChevronDown } from '@veritree/icons';
|
|
42
29
|
|
|
43
30
|
export default {
|
|
@@ -45,33 +32,26 @@ export default {
|
|
|
45
32
|
|
|
46
33
|
components: { IconChevronDown },
|
|
47
34
|
|
|
48
|
-
|
|
35
|
+
mixins: [formControlMixin],
|
|
49
36
|
|
|
50
|
-
|
|
51
|
-
headless: {
|
|
52
|
-
type: Boolean,
|
|
53
|
-
default: false,
|
|
54
|
-
},
|
|
55
|
-
},
|
|
37
|
+
inject: ['apiListbox'],
|
|
56
38
|
|
|
57
39
|
data() {
|
|
58
40
|
return {
|
|
41
|
+
name: 'listbox-button',
|
|
59
42
|
expanded: false,
|
|
60
43
|
hasPopup: false,
|
|
44
|
+
id: null,
|
|
61
45
|
};
|
|
62
46
|
},
|
|
63
47
|
|
|
64
48
|
computed: {
|
|
65
|
-
|
|
66
|
-
return this.
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
content() {
|
|
70
|
-
return this.api().content;
|
|
49
|
+
componentContent() {
|
|
50
|
+
return this.apiListbox().componentContent;
|
|
71
51
|
},
|
|
72
52
|
|
|
73
53
|
items() {
|
|
74
|
-
return this.
|
|
54
|
+
return this.apiListbox().items;
|
|
75
55
|
},
|
|
76
56
|
|
|
77
57
|
firstMenuItem() {
|
|
@@ -84,85 +64,88 @@ export default {
|
|
|
84
64
|
},
|
|
85
65
|
|
|
86
66
|
mounted() {
|
|
67
|
+
this.id = `listbox-trigger-${this.apiListbox().id}`;
|
|
68
|
+
|
|
87
69
|
const trigger = {
|
|
88
70
|
el: this.$el,
|
|
71
|
+
cancel: this.cancel,
|
|
89
72
|
focus: this.focus,
|
|
90
|
-
|
|
91
|
-
contract: this.contract,
|
|
73
|
+
id: this.id,
|
|
92
74
|
};
|
|
93
75
|
|
|
94
|
-
this.
|
|
76
|
+
this.apiListbox().registerTrigger(trigger);
|
|
95
77
|
},
|
|
96
78
|
|
|
97
79
|
methods: {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
80
|
+
init(e) {
|
|
81
|
+
if (!this.componentContent) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (this.expanded) {
|
|
86
|
+
this.cancel();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
102
90
|
this.expanded = true;
|
|
103
|
-
this.content.show();
|
|
104
|
-
},
|
|
105
91
|
|
|
106
|
-
|
|
107
|
-
|
|
92
|
+
// delay stop propagation to close other visible
|
|
93
|
+
// dropdowns and delay click event to control
|
|
94
|
+
// this dropdown visibility
|
|
95
|
+
setTimeout(() => e.stopImmediatePropagation(), 50);
|
|
96
|
+
setTimeout(() => this.showComponentContent(), 100);
|
|
108
97
|
},
|
|
109
98
|
|
|
110
|
-
|
|
111
|
-
if (!this.
|
|
99
|
+
cancel() {
|
|
100
|
+
if (!this.componentContent) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
112
103
|
this.expanded = false;
|
|
113
|
-
},
|
|
114
104
|
|
|
115
|
-
|
|
116
|
-
* On click, do the following:
|
|
117
|
-
*
|
|
118
|
-
* 1. Toggle aria expanded attribute/state
|
|
119
|
-
* 2. Open the menu if it's closed
|
|
120
|
-
* 3. Close the menu if it's open
|
|
121
|
-
*/
|
|
122
|
-
onClick() {
|
|
123
|
-
if (!this.content) return;
|
|
124
|
-
this.expanded ? this.content.hide() : this.showContent();
|
|
105
|
+
this.hideComponentContent();
|
|
125
106
|
},
|
|
126
107
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
* 1. if the menu is not expanded, expand it and focus the first menu item
|
|
131
|
-
* 2. if the menu is expanded, focus the first menu item
|
|
132
|
-
*/
|
|
133
|
-
onKeyArrowDown() {
|
|
134
|
-
if (!this.content) return;
|
|
108
|
+
focus() {
|
|
109
|
+
this.$el.focus();
|
|
110
|
+
},
|
|
135
111
|
|
|
136
|
-
|
|
112
|
+
showComponentContent() {
|
|
113
|
+
this.componentContent.show();
|
|
114
|
+
},
|
|
137
115
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
});
|
|
116
|
+
hideComponentContent() {
|
|
117
|
+
this.componentContent.hide();
|
|
141
118
|
},
|
|
142
119
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
* 1. if the menu is not expanded, expand it and focus the last menu item
|
|
147
|
-
* 2. if the menu is expanded, focus the last menu item
|
|
148
|
-
*/
|
|
149
|
-
onKeyArrowUp() {
|
|
150
|
-
if (!this.content) return;
|
|
120
|
+
onClick(e) {
|
|
121
|
+
this.init(e);
|
|
122
|
+
},
|
|
151
123
|
|
|
152
|
-
|
|
124
|
+
onKeyDownOrUp(e) {
|
|
125
|
+
if (!this.expanded) {
|
|
126
|
+
this.$el.click(e);
|
|
127
|
+
}
|
|
153
128
|
|
|
129
|
+
const keyCode = e.code;
|
|
130
|
+
const listItemPosition =
|
|
131
|
+
keyCode === 'ArrowDown'
|
|
132
|
+
? 'firstMenuItem'
|
|
133
|
+
: keyCode === 'ArrowUp'
|
|
134
|
+
? 'lastMenuItem'
|
|
135
|
+
: null;
|
|
136
|
+
|
|
137
|
+
// settimeout here is delaying the focusing the element
|
|
138
|
+
// since it is not rendered yet. All items will only
|
|
139
|
+
// be available when the content is fully visible.
|
|
154
140
|
this.$nextTick(() => {
|
|
155
|
-
this.
|
|
141
|
+
setTimeout(() => this[listItemPosition].focus(), 100);
|
|
156
142
|
});
|
|
157
143
|
},
|
|
158
144
|
|
|
145
|
+
// change it to a better name or move the methods inside to another function
|
|
159
146
|
onKeyEsc() {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (this.expanded) {
|
|
163
|
-
this.toggleExpanded();
|
|
164
|
-
this.content.hide();
|
|
165
|
-
}
|
|
147
|
+
this.cancel();
|
|
148
|
+
this.focus();
|
|
166
149
|
},
|
|
167
150
|
},
|
|
168
151
|
};
|
|
@@ -2,43 +2,41 @@
|
|
|
2
2
|
<div
|
|
3
3
|
:id="id"
|
|
4
4
|
class="relative"
|
|
5
|
-
:aria-haspopup="
|
|
6
|
-
:aria-controls="
|
|
5
|
+
:aria-haspopup="componentContent ? 'true' : null"
|
|
6
|
+
:aria-controls="componentContent ? componentContent.id : null"
|
|
7
7
|
>
|
|
8
8
|
<slot></slot>
|
|
9
9
|
</div>
|
|
10
10
|
</template>
|
|
11
11
|
|
|
12
12
|
<script>
|
|
13
|
-
import {
|
|
13
|
+
import { floatingUiMixin } from '../../../mixins/floating-ui';
|
|
14
|
+
import { genId } from '../../utils/ids';
|
|
14
15
|
|
|
15
16
|
export default {
|
|
16
|
-
name:
|
|
17
|
+
name: 'VTPopover',
|
|
18
|
+
|
|
19
|
+
mixins: [floatingUiMixin],
|
|
17
20
|
|
|
18
21
|
provide() {
|
|
19
22
|
return {
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const registerButton = (button) => {
|
|
25
|
-
if (!button) return;
|
|
26
|
-
this.button = button;
|
|
23
|
+
apiPopover: () => {
|
|
24
|
+
const registerTrigger = (trigger) => {
|
|
25
|
+
if (!trigger) return;
|
|
26
|
+
this.componentTrigger = trigger;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
const registerContent = (content) => {
|
|
30
30
|
if (!content) return;
|
|
31
|
-
this.
|
|
31
|
+
this.componentContent = content;
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
return {
|
|
35
|
-
id,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
content,
|
|
41
|
-
registerButton,
|
|
35
|
+
id: this.componentId,
|
|
36
|
+
component: this.component,
|
|
37
|
+
componentTrigger: this.componentTrigger,
|
|
38
|
+
componentContent: this.componentContent,
|
|
39
|
+
registerTrigger,
|
|
42
40
|
registerContent,
|
|
43
41
|
};
|
|
44
42
|
},
|
|
@@ -50,22 +48,18 @@ export default {
|
|
|
50
48
|
type: Boolean,
|
|
51
49
|
default: false,
|
|
52
50
|
},
|
|
53
|
-
dark: {
|
|
54
|
-
type: Boolean,
|
|
55
|
-
default: false,
|
|
56
|
-
},
|
|
57
|
-
right: {
|
|
58
|
-
type: Boolean,
|
|
59
|
-
default: false,
|
|
60
|
-
},
|
|
61
51
|
},
|
|
62
52
|
|
|
63
53
|
data() {
|
|
64
54
|
return {
|
|
65
|
-
|
|
66
|
-
button: null,
|
|
67
|
-
content: null,
|
|
55
|
+
componentId: genId(),
|
|
68
56
|
};
|
|
69
57
|
},
|
|
58
|
+
|
|
59
|
+
computed: {
|
|
60
|
+
id() {
|
|
61
|
+
return `popover-${this.componentId}`;
|
|
62
|
+
},
|
|
63
|
+
},
|
|
70
64
|
};
|
|
71
65
|
</script>
|
|
@@ -1,82 +1,47 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
leave-to-class="translate-y-[15px] opacity-0"
|
|
9
|
-
@after-leave="hide"
|
|
2
|
+
<FloatingUi
|
|
3
|
+
:visible="visible"
|
|
4
|
+
:id="id"
|
|
5
|
+
:headless="headless"
|
|
6
|
+
:class="{ 'popover-content': headless }"
|
|
7
|
+
:floating-ui-class="floatingUiClass"
|
|
10
8
|
>
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
:id="id"
|
|
14
|
-
:class="{
|
|
15
|
-
PopoverPanel: headless,
|
|
16
|
-
'absolute top-full mt-3 rounded-md shadow-300 ': !headless,
|
|
17
|
-
'bg-white': !dark,
|
|
18
|
-
'border-gray-700 bg-forest-default shadow-gray-700': dark,
|
|
19
|
-
'left-0': !right,
|
|
20
|
-
'right-0': right,
|
|
21
|
-
}"
|
|
22
|
-
>
|
|
23
|
-
<slot></slot>
|
|
24
|
-
</div>
|
|
25
|
-
</transition>
|
|
9
|
+
<slot></slot>
|
|
10
|
+
</FloatingUi>
|
|
26
11
|
</template>
|
|
27
12
|
|
|
28
13
|
<script>
|
|
29
|
-
import {
|
|
14
|
+
import { floatingUiContentMixin } from '../../../mixins/floating-ui-content';
|
|
30
15
|
|
|
31
16
|
export default {
|
|
32
|
-
name:
|
|
17
|
+
name: 'VTPopoverContent',
|
|
33
18
|
|
|
34
|
-
|
|
19
|
+
mixins: [floatingUiContentMixin],
|
|
35
20
|
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
id: `popover-panel-${genId()}`,
|
|
39
|
-
visible: false,
|
|
40
|
-
};
|
|
41
|
-
},
|
|
21
|
+
inject: ['apiPopover'],
|
|
42
22
|
|
|
43
23
|
computed: {
|
|
44
|
-
|
|
45
|
-
return this.
|
|
24
|
+
id() {
|
|
25
|
+
return `popover-content-${this.apiPopover().id}`;
|
|
46
26
|
},
|
|
47
27
|
|
|
48
|
-
|
|
49
|
-
return this.
|
|
28
|
+
component() {
|
|
29
|
+
return this.apiPopover().component;
|
|
50
30
|
},
|
|
51
31
|
|
|
52
|
-
|
|
53
|
-
return this.
|
|
32
|
+
componentTrigger() {
|
|
33
|
+
return this.apiPopover().componentTrigger;
|
|
54
34
|
},
|
|
55
35
|
},
|
|
56
36
|
|
|
57
37
|
mounted() {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (this.visible && !this.$el.contains(e.target)) this.hide();
|
|
64
|
-
});
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
destroyed() {
|
|
68
|
-
// TODO: Create a directive or mixin for this
|
|
69
|
-
document.removeEventListener("click", this.hide());
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
methods: {
|
|
73
|
-
show() {
|
|
74
|
-
this.visible = true;
|
|
75
|
-
},
|
|
38
|
+
const content = {
|
|
39
|
+
id: this.id,
|
|
40
|
+
show: this.show,
|
|
41
|
+
hide: this.hide,
|
|
42
|
+
};
|
|
76
43
|
|
|
77
|
-
|
|
78
|
-
this.visible = false;
|
|
79
|
-
},
|
|
44
|
+
this.apiPopover().registerContent(content);
|
|
80
45
|
},
|
|
81
46
|
};
|
|
82
47
|
</script>
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
:class="{
|
|
4
4
|
PopoverDivider: headless,
|
|
5
5
|
'h-[1px]': !headless,
|
|
6
|
-
'bg-white': !dark,
|
|
7
|
-
'bg-fd-500': dark,
|
|
8
6
|
}"
|
|
9
7
|
></div>
|
|
10
8
|
</template>
|
|
@@ -13,15 +11,10 @@
|
|
|
13
11
|
export default {
|
|
14
12
|
name: 'VTPopoverDivider',
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return this.api().isDark;
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
headless() {
|
|
24
|
-
return this.api().isHeadless;
|
|
14
|
+
props: {
|
|
15
|
+
headless: {
|
|
16
|
+
type: Boolean,
|
|
17
|
+
default: false,
|
|
25
18
|
},
|
|
26
19
|
},
|
|
27
20
|
};
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
3
|
:is="as"
|
|
4
|
-
:class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}"
|
|
4
|
+
:class="[
|
|
5
|
+
// default styles
|
|
6
|
+
headless
|
|
7
|
+
? 'popover-item'
|
|
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
|
+
]"
|
|
11
10
|
@click="onClick"
|
|
12
11
|
>
|
|
13
12
|
<slot></slot>
|
|
@@ -18,30 +17,38 @@
|
|
|
18
17
|
export default {
|
|
19
18
|
name: 'VTPopoverItem',
|
|
20
19
|
|
|
21
|
-
inject: ['
|
|
20
|
+
inject: ['apiPopover'],
|
|
22
21
|
|
|
23
22
|
props: {
|
|
24
|
-
|
|
25
|
-
type:
|
|
26
|
-
default:
|
|
23
|
+
headless: {
|
|
24
|
+
type: Boolean,
|
|
25
|
+
default: false,
|
|
27
26
|
},
|
|
28
27
|
href: {
|
|
29
28
|
type: String,
|
|
30
29
|
default: null,
|
|
31
30
|
},
|
|
31
|
+
to: {
|
|
32
|
+
type: [String, Object],
|
|
33
|
+
default: null,
|
|
34
|
+
},
|
|
32
35
|
},
|
|
33
36
|
|
|
34
37
|
computed: {
|
|
35
38
|
dark() {
|
|
36
|
-
return this.
|
|
39
|
+
return this.apiPopover().isDark;
|
|
37
40
|
},
|
|
38
41
|
|
|
39
42
|
headless() {
|
|
40
|
-
return this.
|
|
43
|
+
return this.apiPopover().isHeadless;
|
|
41
44
|
},
|
|
42
45
|
|
|
43
46
|
as() {
|
|
44
|
-
return this.href
|
|
47
|
+
return this.href
|
|
48
|
+
? 'a'
|
|
49
|
+
: this.to
|
|
50
|
+
? resolveComponent('NuxtLink')
|
|
51
|
+
: 'button';
|
|
45
52
|
},
|
|
46
53
|
},
|
|
47
54
|
|