@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.
Files changed (62) hide show
  1. package/mixins/floating-ui-content.js +102 -0
  2. package/mixins/floating-ui-item.js +219 -0
  3. package/mixins/floating-ui.js +74 -0
  4. package/mixins/form-control-icon.js +53 -0
  5. package/mixins/form-control.js +73 -0
  6. package/package.json +7 -3
  7. package/src/components/Avatar/VTAvatar.vue +32 -29
  8. package/src/components/Button/VTButton.vue +9 -5
  9. package/src/components/Dialog/VTDialog.vue +6 -11
  10. package/src/components/Dialog/VTDialogClose.vue +9 -9
  11. package/src/components/Dialog/VTDialogContent.vue +9 -9
  12. package/src/components/Dialog/VTDialogFooter.vue +5 -5
  13. package/src/components/Dialog/VTDialogHeader.vue +8 -8
  14. package/src/components/Dialog/VTDialogMain.vue +8 -8
  15. package/src/components/Dialog/VTDialogOverlay.vue +8 -8
  16. package/src/components/Dialog/VTDialogTitle.vue +4 -4
  17. package/src/components/Disclosure/VTDisclosureContent.vue +1 -1
  18. package/src/components/Disclosure/VTDisclosureDetails.vue +2 -2
  19. package/src/components/Disclosure/VTDisclosureHeader.vue +1 -1
  20. package/src/components/Disclosure/VTDisclosureIcon.vue +1 -1
  21. package/src/components/Drawer/VTDrawer.vue +14 -16
  22. package/src/components/Drawer/VTDrawerClose.vue +9 -9
  23. package/src/components/Drawer/VTDrawerContent.vue +8 -8
  24. package/src/components/Drawer/VTDrawerFooter.vue +3 -3
  25. package/src/components/Drawer/VTDrawerHeader.vue +4 -4
  26. package/src/components/Drawer/VTDrawerMain.vue +5 -5
  27. package/src/components/Drawer/VTDrawerOverlay.vue +6 -6
  28. package/src/components/Drawer/VTDrawerTitle.vue +5 -5
  29. package/src/components/DropdownMenu/VTDropdownMenu.vue +27 -29
  30. package/src/components/DropdownMenu/VTDropdownMenuContent.vue +27 -70
  31. package/src/components/DropdownMenu/VTDropdownMenuDivider.vue +8 -5
  32. package/src/components/DropdownMenu/VTDropdownMenuItem.vue +14 -123
  33. package/src/components/DropdownMenu/VTDropdownMenuLabel.vue +3 -3
  34. package/src/components/DropdownMenu/VTDropdownMenuTrigger.vue +96 -121
  35. package/src/components/Form/VTFormFeedback.vue +33 -22
  36. package/src/components/Form/VTFormGroup.vue +5 -7
  37. package/src/components/Form/VTFormLabel.vue +22 -0
  38. package/src/components/Form/VTFormRow.vue +5 -0
  39. package/src/components/Form/VTInput.vue +40 -0
  40. package/src/components/Form/VTInputIcon.vue +35 -0
  41. package/src/components/Form/VTInputPassword.vue +55 -0
  42. package/src/components/Form/VTTextarea.vue +22 -0
  43. package/src/components/Listbox/VTListbox.vue +26 -45
  44. package/src/components/Listbox/VTListboxContent.vue +24 -116
  45. package/src/components/Listbox/VTListboxItem.vue +10 -182
  46. package/src/components/Listbox/VTListboxLabel.vue +0 -10
  47. package/src/components/Listbox/VTListboxList.vue +24 -33
  48. package/src/components/Listbox/VTListboxSearch.vue +30 -29
  49. package/src/components/Listbox/VTListboxTrigger.vue +71 -88
  50. package/src/components/Popover/VTPopover.vue +24 -30
  51. package/src/components/Popover/VTPopoverContent.vue +24 -59
  52. package/src/components/Popover/VTPopoverDivider.vue +4 -11
  53. package/src/components/Popover/VTPopoverItem.vue +21 -14
  54. package/src/components/Popover/VTPopoverTrigger.vue +126 -21
  55. package/src/components/Tabs/VTTab.vue +10 -11
  56. package/src/components/Tabs/VTTabGroup.vue +9 -7
  57. package/src/components/Tabs/VTTabPanel.vue +4 -5
  58. package/src/components/Transitions/FadeInOut.vue +2 -2
  59. package/src/components/Utils/FloatingUi.vue +58 -0
  60. package/package-lock.json +0 -13
  61. package/src/components/Modal/VTModal.vue +0 -69
  62. package/src/utils/genId.js +0 -13
@@ -1,29 +1,29 @@
1
1
  <template>
2
- <div :class="{ Listbox: headless, relative: !headless, 'z-20': active }">
2
+ <div :class="{ listbox: headless }">
3
3
  <slot></slot>
4
4
  </div>
5
5
  </template>
6
6
 
7
7
  <script>
8
- import { genId } from "../../utils/ids";
8
+ import { floatingUiMixin } from '../../../mixins/floating-ui';
9
+ import { genId } from '../../utils/ids';
9
10
 
10
11
  export default {
11
- name: "VTListbox",
12
+ name: 'VTListbox',
13
+
14
+ mixins: [floatingUiMixin],
12
15
 
13
16
  provide() {
14
17
  return {
15
- api: () => {
16
- const { dark: isDark, right: isRight } = this;
17
- const { id, listbox, trigger, content, search, list, items } = this;
18
-
18
+ apiListbox: () => {
19
19
  const registerTrigger = (trigger) => {
20
20
  if (!trigger) return;
21
- this.trigger = trigger;
21
+ this.componentTrigger = trigger;
22
22
  };
23
23
 
24
24
  const registerContent = (content) => {
25
25
  if (!content) return;
26
- this.content = content;
26
+ this.componentContent = content;
27
27
  };
28
28
 
29
29
  const registerSearch = (search) => {
@@ -31,10 +31,10 @@ export default {
31
31
  this.search = search;
32
32
  };
33
33
 
34
- const registerList = (list) => {
35
- if (!list) return;
36
- this.list = list;
37
- };
34
+ // const registerList = (list) => {
35
+ // if (!list) return;
36
+ // this.list = list;
37
+ // };
38
38
 
39
39
  const registerItem = (item) => {
40
40
  if (!item) return;
@@ -47,24 +47,21 @@ export default {
47
47
  };
48
48
 
49
49
  const emit = (value) => {
50
- this.$emit("input", value);
51
- this.$emit("change", value);
50
+ this.$emit('update:modelValue', value);
51
+ this.$emit('change', value);
52
52
  };
53
53
 
54
54
  return {
55
- id,
56
- isDark,
57
- isRight,
58
- listbox,
59
- trigger,
60
- search,
61
- content,
62
- list,
63
- items,
55
+ id: this.componentId,
56
+ component: this.component,
57
+ componentTrigger: this.componentTrigger,
58
+ componentContent: this.componentContent,
59
+ items: this.items,
60
+ search: this.search,
64
61
  registerTrigger,
65
62
  registerContent,
66
63
  registerSearch,
67
- registerList,
64
+ // registerList,
68
65
  registerItem,
69
66
  unregisterItem,
70
67
  emit,
@@ -94,31 +91,15 @@ export default {
94
91
 
95
92
  data() {
96
93
  return {
97
- id: `listbox-${genId()}`,
98
- listbox: null,
99
- trigger: null,
100
- content: null,
94
+ componentId: genId(),
101
95
  search: null,
102
- list: null,
103
96
  items: [],
104
- active: false,
105
- };
106
- },
107
-
108
- mounted() {
109
- this.listbox = {
110
- setActive: this.setActive,
111
- clearActive: this.clearActive,
112
97
  };
113
98
  },
114
99
 
115
- methods: {
116
- setActive() {
117
- this.active = true;
118
- },
119
-
120
- clearActive() {
121
- this.active = null;
100
+ computed: {
101
+ id() {
102
+ return `listbox-${this.componentId}`;
122
103
  },
123
104
  },
124
105
  };
@@ -1,95 +1,44 @@
1
1
  <template>
2
- <transition
3
- enter-active-class="duration-200 ease-out"
4
- enter-class="translate-y-[15px] opacity-0"
5
- enter-to-class="translate-y-0 opacity-100"
6
- leave-active-class="duration-200 ease-in"
7
- leave-class="translate-y-0 opacity-100"
8
- leave-to-class="translate-y-[15px] opacity-0"
9
- @after-leave="hide"
2
+ <FloatingUi
3
+ :visible="visible"
4
+ :id="id"
5
+ :aria-activedescendant="activeDescedant"
6
+ :headless="headless"
7
+ :class="{ 'listbox-content': headless }"
8
+ :floating-ui-class="floatingUiClass"
9
+ role="listbox"
10
10
  >
11
- <div
12
- v-if="visible"
13
- :id="id"
14
- :aria-activedescendant="activeDescedant"
15
- :class="{
16
- MenuList: headless,
17
- 'absolute z-10 grid w-full min-w-[222px] overflow-hidden rounded-md py-2 px-3':
18
- !headless,
19
- 'border-gray-100 bg-white shadow-300': !dark && !headless,
20
- 'bg-forest-default border border-solid border-gray-700 shadow-gray-700':
21
- dark && !headless,
22
- 'left-0': !right && !headless,
23
- 'right-0': right && !headless,
24
- 'top-full mt-3': isTop && !headless,
25
- 'bottom-full mb-3': isBottom && !headless,
26
- }"
27
- role="listbox"
28
- >
29
- <slot></slot>
30
- </div>
31
- </transition>
11
+ <slot></slot>
12
+ </FloatingUi>
32
13
  </template>
33
14
 
34
15
  <script>
35
- import { genId } from "../../utils/ids";
16
+ import { floatingUiContentMixin } from '../../../mixins/floating-ui-content';
36
17
 
37
18
  export default {
38
- name: "VTListboxContent",
19
+ name: 'VTListboxContent',
39
20
 
40
- inject: ["api"],
21
+ mixins: [floatingUiContentMixin],
41
22
 
42
- props: {
43
- headless: {
44
- type: Boolean,
45
- default: false,
46
- },
47
- bottom: {
48
- type: Boolean,
49
- default: false,
50
- },
51
- top: {
52
- type: Boolean,
53
- default: true,
54
- },
55
- },
23
+ inject: ['apiListbox'],
56
24
 
57
25
  data() {
58
26
  return {
59
- id: `listboxcontent-${genId()}`,
60
27
  activeDescedant: null,
61
- visible: false,
62
28
  };
63
29
  },
64
30
 
65
31
  computed: {
66
- dark() {
67
- return this.api().isDark;
68
- },
69
-
70
- right() {
71
- return this.api().isRight;
72
- },
73
-
74
- listbox() {
75
- return this.api().listbox;
76
- },
77
-
78
- trigger() {
79
- return this.api().trigger;
32
+ id() {
33
+ return `listbox-content-${this.apiListbox().id}`;
80
34
  },
81
35
 
82
- search() {
83
- return this.api().search;
36
+ component() {
37
+ return this.apiListbox().component;
84
38
  },
85
39
 
86
- // directions
87
- isTop() {
88
- return this.top && !this.bottom;
89
- },
90
-
91
- isBottom() {
92
- return this.bottom;
40
+ componentTrigger() {
41
+ return this.apiListbox().componentTrigger;
93
42
  },
94
43
  },
95
44
 
@@ -98,54 +47,13 @@ export default {
98
47
  id: this.id,
99
48
  show: this.show,
100
49
  hide: this.hide,
50
+ getMousemove: this.getMousemove,
51
+ setMousemove: this.setMousemove,
52
+ unsetMousemove: this.unsetMousemove,
101
53
  setActiveDescedant: this.setActiveDescedant,
102
54
  };
103
55
 
104
- this.api().registerContent(content);
105
-
106
- // TODO: Create a directive or mixin for this
107
- document.addEventListener("click", (e) => {
108
- e.stopPropagation();
109
- if (this.visible && !this.$el.contains(e.target)) this.trigger.onClick();
110
- });
111
- },
112
-
113
- destroyed() {
114
- // TODO: Create a directive or mixin for this
115
- document.removeEventListener("click", this.trigger.onClick());
116
- },
117
-
118
- methods: {
119
- show() {
120
- if (this.visible) return;
121
-
122
- this.visible = true;
123
-
124
- this.$nextTick(() => {
125
- this.listbox.setActive();
126
-
127
- if (this.search) this.search.el.focus();
128
- });
129
- },
130
-
131
- hide() {
132
- if (!this.visible) return;
133
-
134
- this.visible = false;
135
-
136
- this.$nextTick(() => {
137
- this.trigger.focus();
138
-
139
- setTimeout(() => {
140
- this.listbox.clearActive();
141
- this.trigger.contract();
142
- }, 100);
143
- });
144
- },
145
-
146
- setActiveDescedant(id) {
147
- this.activeDescedant = id;
148
- },
56
+ this.apiListbox().registerContent(content);
149
57
  },
150
58
  };
151
59
  </script>
@@ -1,14 +1,7 @@
1
1
  <template>
2
2
  <li
3
3
  :id="id"
4
- :class="{
5
- ListboxItem: headless,
6
- 'relative z-10 flex items-center gap-2 px-3 py-2 no-underline': !headless,
7
- 'hover:bg-secondary-200/10': !dark && !headless,
8
- 'text-white': dark && !headless,
9
- 'pointer-events-none opacity-75': disabled && !headless,
10
- 'bg-secondary-200/10': selected && !headless,
11
- }"
4
+ :class="classComputed"
12
5
  :aria-disabled="disabled"
13
6
  :aria-selected="String(selected)"
14
7
  :tabindex="tabIndex"
@@ -24,28 +17,21 @@
24
17
  @mouseout="onMouseleave"
25
18
  @keydown.tab.prevent
26
19
  >
27
- <span class="truncate"><slot></slot></span>
20
+ <slot></slot>
28
21
  </li>
29
22
  </template>
30
23
 
31
24
  <script>
32
- import { scrollElementIntoView } from "../../utils/components";
33
- import { genId } from "../../utils/ids";
25
+ import { floatingUiItemMixin } from '../../../mixins/floating-ui-item';
34
26
 
35
27
  export default {
36
- name: "VTListboxItem",
28
+ name: 'VTListboxItem',
37
29
 
38
- inject: ["api"],
30
+ mixins: [floatingUiItemMixin],
31
+
32
+ inject: ['apiListbox'],
39
33
 
40
34
  props: {
41
- headless: {
42
- type: Boolean,
43
- default: false,
44
- },
45
- disabled: {
46
- type: Boolean,
47
- default: false,
48
- },
49
35
  value: {
50
36
  type: [String, Number, Object, Array],
51
37
  required: true,
@@ -54,172 +40,14 @@ export default {
54
40
 
55
41
  data() {
56
42
  return {
57
- id: `listboxitem-${genId()}`,
58
- index: null,
59
- selected: false,
60
- tabIndex: 0,
43
+ apiInjected: this.apiListbox,
44
+ componentName: 'listbox-item',
61
45
  };
62
46
  },
63
47
 
64
48
  computed: {
65
- dark() {
66
- return this.api().isDark;
67
- },
68
-
69
- items() {
70
- return this.api().items;
71
- },
72
-
73
- el() {
74
- return this.$el;
75
- },
76
-
77
- trigger() {
78
- return this.api().trigger;
79
- },
80
-
81
- content() {
82
- return this.api().content;
83
- },
84
-
85
- list() {
86
- return this.api().list;
87
- },
88
-
89
49
  search() {
90
- return this.api().search;
91
- },
92
- },
93
-
94
- watch: {
95
- selected(newValue) {
96
- if (!newValue || !this.list) return;
97
-
98
- if (this.content) {
99
- this.content.setActiveDescedant(this.id);
100
- }
101
-
102
- const isMousemove = this.list.getMousemove();
103
-
104
- if (!isMousemove) {
105
- scrollElementIntoView(this.el, this.list.el);
106
- }
107
- },
108
- },
109
-
110
- mounted() {
111
- const item = {
112
- id: this.id,
113
- focus: this.focus,
114
- select: this.select,
115
- unselect: this.unselect,
116
- onClick: this.onClick,
117
- };
118
-
119
- this.api().registerItem(item);
120
-
121
- this.index = this.items.length - 1;
122
- },
123
-
124
- beforeDestroy() {
125
- this.api().unregisterItem(this.id);
126
- },
127
-
128
- methods: {
129
- select() {
130
- this.selected = true;
131
- },
132
-
133
- unselect() {
134
- this.selected = false;
135
- },
136
-
137
- focus() {
138
- if (!this.el) return;
139
-
140
- this.tabIndex = -1;
141
- this.selected = true;
142
- this.el.focus();
143
- },
144
-
145
- focusFirstItem() {
146
- this.setFocusToItem(0);
147
- },
148
-
149
- focusLastItem() {
150
- this.setFocusToItem(this.items.length - 1);
151
- },
152
-
153
- /**
154
- * Focus the previous item in the menu.
155
- * If is the first item, jump to the last item.
156
- */
157
- focusPreviousItem() {
158
- const isLast = this.index === this.items.length - 1;
159
- const goToIndex = isLast ? 0 : this.index + 1;
160
-
161
- this.setFocusToItem(goToIndex);
162
- },
163
-
164
- /**
165
- * Focus the next item in the menu.
166
- * If is the last item, jump to the first item.
167
- */
168
- focusNextItem() {
169
- const isFirst = this.index === 0;
170
- const goToIndex = isFirst ? this.items.length - 1 : this.index - 1;
171
-
172
- this.setFocusToItem(goToIndex);
173
- },
174
-
175
- /**
176
- * Focus item by remove its tabindex and calling
177
- * focus to the element.
178
- *
179
- * @param {Number, String} goToIndex
180
- */
181
- setFocusToItem(goToIndex) {
182
- this.tabIndex = 0;
183
- this.selected = false;
184
-
185
- const isMousemove = this.list.getMousemove();
186
-
187
- if (isMousemove) {
188
- this.list.unsetMousemove();
189
- this.items.forEach((item) => item.unselect());
190
- }
191
-
192
- this.items[goToIndex].focus();
193
- },
194
-
195
- /**
196
- * Hides content/menu and focus on trigger
197
- */
198
- leaveMenu() {
199
- if (this.content) this.content.hide();
200
- },
201
-
202
- onKeyEsc() {
203
- this.leaveMenu();
204
- },
205
-
206
- onClick() {
207
- if (this.disabled) return;
208
-
209
- this.api().emit(this.value);
210
- this.$nextTick(() => this.leaveMenu());
211
- },
212
-
213
- onMousemove() {
214
- this.items.forEach((item) => item.unselect());
215
-
216
- this.select();
217
- this.list.setMousemove();
218
- },
219
-
220
- onMouseleave() {
221
- this.unselect();
222
- this.list.unsetMousemove();
50
+ return this.apiInjected().search;
223
51
  },
224
52
  },
225
53
  };
@@ -4,8 +4,6 @@
4
4
  :class="{
5
5
  ListboxLabel: headless,
6
6
  'mb-2 block text-xs font-normal uppercase': !headless,
7
- 'text-inherit': !dark && !headless,
8
- 'text-white': dark && !headless,
9
7
  }"
10
8
  >
11
9
  <slot></slot>
@@ -16,8 +14,6 @@
16
14
  export default {
17
15
  name: 'VTListboxLabel',
18
16
 
19
- inject: ['api'],
20
-
21
17
  props: {
22
18
  as: {
23
19
  type: String,
@@ -28,11 +24,5 @@ export default {
28
24
  default: false,
29
25
  },
30
26
  },
31
-
32
- computed: {
33
- dark() {
34
- return this.api().isDark;
35
- },
36
- },
37
27
  };
38
28
  </script>
@@ -1,22 +1,19 @@
1
1
  <template>
2
2
  <ul
3
3
  :id="id"
4
- :class="{
5
- ListboxList: headless,
6
- '-mx-3 max-h-[160px] w-auto overflow-y-auto': !headless,
7
- }"
4
+ :class="[
5
+ headless ? 'listbox-list' : 'max-h-[160px] w-auto overflow-y-auto -mx-3',
6
+ ]"
8
7
  >
9
8
  <slot></slot>
10
9
  </ul>
11
10
  </template>
12
11
 
13
12
  <script>
14
- import { genId } from "../../utils/ids";
15
-
16
13
  export default {
17
- name: "VTListboxList",
14
+ name: 'VTListboxList',
18
15
 
19
- inject: ["api"],
16
+ inject: ['apiListbox'],
20
17
 
21
18
  props: {
22
19
  headless: {
@@ -25,39 +22,33 @@ export default {
25
22
  },
26
23
  },
27
24
 
28
- data() {
29
- return {
30
- id: `listboxlist-${genId()}`,
31
- isMousemove: false,
32
- };
25
+ computed: {
26
+ id() {
27
+ return `listbox-list-${this.apiListbox().id}`;
28
+ },
33
29
  },
34
30
 
35
- mounted() {
36
- const list = {
37
- el: this.$el,
38
- getMousemove: this.getMousemove,
39
- setMousemove: this.setMousemove,
40
- unsetMousemove: this.unsetMousemove,
41
- };
31
+ // mounted() {
32
+ // const list = {
33
+ // el: this.$el,
34
+ // };
42
35
 
43
- this.api().registerList(list);
44
- },
36
+ // this.apiListbox().registerList(list);
37
+ // },
45
38
 
46
39
  methods: {
47
40
  // Mousemove instead of mouseover to support keyboard navigation.
48
41
  // The problem with mouseover is that when scrolling (scrollIntoView),
49
42
  // mouseover event gets triggered.
50
- setMousemove() {
51
- this.isMousemove = true;
52
- },
53
-
54
- unsetMousemove() {
55
- this.isMousemove = false;
56
- },
57
-
58
- getMousemove() {
59
- return this.isMousemove;
60
- },
43
+ // setMousemove() {
44
+ // this.isMousemove = true;
45
+ // },
46
+ // unsetMousemove() {
47
+ // this.isMousemove = false;
48
+ // },
49
+ // getMousemove() {
50
+ // return this.isMousemove;
51
+ // },
61
52
  },
62
53
  };
63
54
  </script>