@veritree/ui 0.19.2-21 → 0.19.2-23

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 (31) hide show
  1. package/package.json +1 -1
  2. package/src/components/Alert/VTAlert.vue +55 -14
  3. package/src/components/Dialog/VTDialog.vue +13 -17
  4. package/src/components/Dialog/VTDialogClose.vue +13 -19
  5. package/src/components/Dialog/VTDialogContent.vue +17 -12
  6. package/src/components/Dialog/VTDialogFooter.vue +9 -14
  7. package/src/components/Dialog/VTDialogHeader.vue +11 -13
  8. package/src/components/Dialog/VTDialogMain.vue +6 -13
  9. package/src/components/Dialog/VTDialogOverlay.vue +9 -13
  10. package/src/components/Dialog/VTDialogTitle.vue +8 -5
  11. package/src/components/Disclosure/VTDisclosureHeader.vue +1 -1
  12. package/src/components/DropdownMenu/VTDropdownMenu.vue +19 -0
  13. package/src/components/DropdownMenu/VTDropdownMenuContent.vue +14 -6
  14. package/src/components/DropdownMenu/VTDropdownMenuDivider.vue +7 -16
  15. package/src/components/DropdownMenu/VTDropdownMenuItem.vue +3 -7
  16. package/src/components/DropdownMenu/VTDropdownMenuLabel.vue +1 -10
  17. package/src/components/DropdownMenu/VTDropdownMenuTrigger.vue +4 -9
  18. package/src/components/Listbox/VTListboxItem.vue +0 -1
  19. package/src/components/Popover/VTPopover.vue +19 -0
  20. package/src/components/ProgressBar/VTProgressBar.vue +21 -3
  21. package/src/components/Skeleton/VTSkeleton.vue +11 -0
  22. package/src/components/Skeleton/VTSkeletonItem.vue +9 -0
  23. package/src/components/Tabs/VTTab.vue +13 -11
  24. package/src/components/Tooltip/VTTooltip.vue +65 -0
  25. package/src/components/Tooltip/VTTooltipContent.vue +59 -0
  26. package/src/components/Tooltip/VTTooltipTrigger.vue +98 -0
  27. package/src/components/Utils/FloatingUi.vue +6 -0
  28. package/src/components/Input/VTInput.vue +0 -82
  29. package/src/components/Input/VTInputDate.vue +0 -36
  30. package/src/components/Input/VTInputFile.vue +0 -60
  31. package/src/components/Input/VTInputUpload.vue +0 -54
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veritree/ui",
3
- "version": "0.19.2-21",
3
+ "version": "0.19.2-23",
4
4
  "description": "veritree ui library",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1,11 +1,9 @@
1
1
  <template>
2
2
  <div
3
- v-if="show"
3
+ v-if="modelValue"
4
4
  :class="[
5
5
  // default styles
6
- headless
7
- ? 'alert'
8
- : 'flex items-start gap-3 rounded border border-solid p-3',
6
+ headless ? 'alert' : 'flex items-start gap-3 rounded border border-solid',
9
7
  // variant styles
10
8
  headless
11
9
  ? `alert--${variant}`
@@ -16,6 +14,14 @@
16
14
  : isWarning
17
15
  ? 'border-warning-300 bg-warning-200 text-warning-700'
18
16
  : null,
17
+ // sizes styles
18
+ headless
19
+ ? `alert--${size}`
20
+ : isLarge
21
+ ? 'p-3'
22
+ : isSmall
23
+ ? 'py-1 px-2 text-sm'
24
+ : null,
19
25
  ]"
20
26
  role="alert"
21
27
  >
@@ -23,9 +29,15 @@
23
29
  <button
24
30
  v-if="dismissable"
25
31
  :class="[
26
- !headless
27
- ? 'ml-auto mt-1 h-4 w-4 shrink-0 text-current'
28
- : 'alert-close',
32
+ // default styles
33
+ headless ? 'alert-close' : 'ml-auto h-4 w-4 shrink-0 text-current',
34
+ headless
35
+ ? `alert-close--${variant}`
36
+ : isLarge
37
+ ? 'mt-1'
38
+ : isSmall
39
+ ? 'mt-0.5'
40
+ : null,
29
41
  ]"
30
42
  @click="hide"
31
43
  >
@@ -35,14 +47,30 @@
35
47
  </template>
36
48
 
37
49
  <script>
50
+ import IconClose from '@veritree/icons/src/components/IconClose.vue';
51
+
38
52
  export default {
39
53
  name: 'VTAlert',
40
54
 
55
+ components: {
56
+ IconClose,
57
+ },
58
+
59
+ data() {
60
+ return {
61
+ modelValueLocal: true,
62
+ };
63
+ },
64
+
41
65
  props: {
42
66
  variant: {
43
67
  type: String,
44
68
  default: 'success',
45
69
  },
70
+ size: {
71
+ type: String,
72
+ default: 'large',
73
+ },
46
74
  headless: {
47
75
  type: Boolean,
48
76
  default: false,
@@ -51,12 +79,10 @@ export default {
51
79
  type: Boolean,
52
80
  default: false,
53
81
  },
54
- },
55
-
56
- data() {
57
- return {
58
- show: true,
59
- };
82
+ modelValue: {
83
+ type: Boolean,
84
+ default: null,
85
+ },
60
86
  },
61
87
 
62
88
  computed: {
@@ -71,12 +97,27 @@ export default {
71
97
  isWarning() {
72
98
  return this.variant === 'warning';
73
99
  },
100
+
101
+ isLarge() {
102
+ return this.size === 'large';
103
+ },
104
+
105
+ isSmall() {
106
+ return this.size === 'small';
107
+ },
108
+
109
+ isVisible() {
110
+ return this.modelValue !== null ? this.modelValue : this.modelValueLocal;
111
+ },
74
112
  },
75
113
 
76
114
  methods: {
77
115
  hide() {
116
+ this.modelValue !== null
117
+ ? this.$emit('update:modelValue', false)
118
+ : (this.modelValueLocal = false);
119
+
78
120
  this.$emit('dismiss');
79
- this.show = false;
80
121
  },
81
122
  },
82
123
  };
@@ -3,10 +3,11 @@
3
3
  <div
4
4
  v-if="modelValue"
5
5
  :id="id"
6
- :class="{
7
- Dialog: headless,
8
- 'fixed inset-0 z-50 grid grid-cols-1 grid-rows-1 p-4 md:p-8': !headless,
9
- }"
6
+ :class="
7
+ headless
8
+ ? 'dialog'
9
+ : `fixed inset-0 z-50 grid grid-cols-1 grid-rows-1 ${classes}`
10
+ "
10
11
  aria-modal="true"
11
12
  v-bind="$attrs"
12
13
  @click="onClick"
@@ -27,10 +28,7 @@ export default {
27
28
  provide() {
28
29
  return {
29
30
  apiDialog: () => {
30
- const id = this.id;
31
31
  const componentId = this.componentId;
32
- const isDark = this.dark;
33
- const isHeadless = this.headless;
34
32
 
35
33
  const registerContent = (content) => {
36
34
  if (!content) return;
@@ -46,15 +44,15 @@ export default {
46
44
 
47
45
  const emit = () => this.emit();
48
46
 
47
+ const full = this.full;
48
+
49
49
  return {
50
- id,
51
50
  componentId,
52
- isDark,
53
- isHeadless,
54
51
  hide,
55
52
  emit,
56
53
  registerContent,
57
54
  registerOverlay,
55
+ full,
58
56
  };
59
57
  },
60
58
  };
@@ -69,7 +67,7 @@ export default {
69
67
  type: Boolean,
70
68
  default: false,
71
69
  },
72
- dark: {
70
+ full: {
73
71
  type: Boolean,
74
72
  default: false,
75
73
  },
@@ -88,6 +86,10 @@ export default {
88
86
  return `dialog-${this.componentId}`;
89
87
  },
90
88
 
89
+ classes() {
90
+ return !this.full ? 'p-4 md:p-6' : '';
91
+ },
92
+
91
93
  hasContent() {
92
94
  return this.content !== null;
93
95
  },
@@ -97,12 +99,6 @@ export default {
97
99
  },
98
100
  },
99
101
 
100
- watch: {
101
- visible(isVisible) {
102
- if (!isVisible) this.hide();
103
- },
104
- },
105
-
106
102
  mounted() {
107
103
  if (this.hasContent) this.content.show();
108
104
  if (this.hasOverlay) this.overlay.show();
@@ -2,13 +2,13 @@
2
2
  <VTButton
3
3
  variant="icon"
4
4
  :id="id"
5
- :class="{
6
- 'Dialog-close': headless,
7
- }"
8
- :theme="theme"
5
+ :class="[headless ? 'dialog-close' : null]"
9
6
  @click.prevent="hide"
10
- ><slot><IconClose class="h-5 w-5" /></slot
11
- ></VTButton>
7
+ >
8
+ <slot>
9
+ <IconClose class="h-4 w-4" />
10
+ </slot>
11
+ </VTButton>
12
12
  </template>
13
13
 
14
14
  <script>
@@ -22,23 +22,17 @@ export default {
22
22
 
23
23
  inject: ['apiDialog'],
24
24
 
25
+ props: {
26
+ headless: {
27
+ type: Boolean,
28
+ default: false,
29
+ },
30
+ },
31
+
25
32
  computed: {
26
33
  id() {
27
34
  return `dialog-close-${this.apiDialog().componentId}`;
28
35
  },
29
-
30
- dark() {
31
- return this.apiDialog().isDark;
32
- },
33
-
34
- headless() {
35
- return this.apiDialog().isHeadless;
36
- },
37
-
38
- // temporary till button theme is implemented
39
- theme() {
40
- return this.dark ? 'dark' : null;
41
- },
42
36
  },
43
37
 
44
38
  methods: {
@@ -11,15 +11,13 @@
11
11
  <div
12
12
  v-show="visible"
13
13
  :id="id"
14
- :class="{
15
- 'Dialog-content': headless,
16
- 'relative m-auto max-h-full max-w-full overflow-auto rounded p-6 focus:outline-none sm:p-10 flex flex-col':
17
- !headless,
18
- 'bg-white': !dark,
19
- 'bg-fd-600': dark,
20
- }"
14
+ :class="
15
+ headless
16
+ ? 'dialog-content'
17
+ : `relative m-auto flex flex-col overflow-auto rounded bg-white p-4 focus:outline-none lg:p-6 ${classes}`
18
+ "
21
19
  tabindex="-1"
22
- @keyup.esc="hide"
20
+ @keydown.esc.stop="hide"
23
21
  >
24
22
  <slot></slot>
25
23
  </div>
@@ -32,6 +30,13 @@ export default {
32
30
 
33
31
  inject: ['apiDialog'],
34
32
 
33
+ props: {
34
+ headless: {
35
+ type: Boolean,
36
+ default: false,
37
+ },
38
+ },
39
+
35
40
  data() {
36
41
  return {
37
42
  visible: false,
@@ -43,12 +48,12 @@ export default {
43
48
  return `dialog-content-${this.apiDialog().componentId}`;
44
49
  },
45
50
 
46
- dark() {
47
- return this.apiDialog().isDark;
51
+ classes() {
52
+ return this.full ? 'h-screen w-screen' : 'max-h-full max-w-full';
48
53
  },
49
54
 
50
- headless() {
51
- return this.apiDialog().isHeadless;
55
+ full() {
56
+ return this.apiDialog().full;
52
57
  },
53
58
  },
54
59
 
@@ -1,7 +1,11 @@
1
1
  <template>
2
2
  <component
3
3
  :is="as"
4
- :class="{ 'Dialog-footer': headless, 'w-full': !headless }"
4
+ :class="[
5
+ headless
6
+ ? 'dialog-footer'
7
+ : '-mx-4 -mb-4 flex items-center justify-between gap-x-3 p-4 md:-mx-6 md:-mb-6 md:p-6',
8
+ ]"
5
9
  >
6
10
  <slot></slot>
7
11
  </component>
@@ -10,24 +14,15 @@
10
14
  <script>
11
15
  export default {
12
16
  name: 'VTDialogFooter',
13
-
14
- inject: ['apiDialog'],
15
-
16
17
  props: {
18
+ headless: {
19
+ type: Boolean,
20
+ default: false,
21
+ },
17
22
  as: {
18
23
  type: String,
19
24
  default: 'footer',
20
25
  },
21
26
  },
22
-
23
- computed: {
24
- dark() {
25
- return this.apiDialog().isDark;
26
- },
27
-
28
- headless() {
29
- return this.apiDialog().isHeadless;
30
- },
31
- },
32
27
  };
33
28
  </script>
@@ -2,10 +2,12 @@
2
2
  <component
3
3
  :is="as"
4
4
  :id="id"
5
- :class="{
6
- 'Dialog-header': headless,
7
- 'mb-8 flex justify-between gap-x-3 items-center w-full': !headless,
8
- }"
5
+ :class="[
6
+ headless
7
+ ? 'dialog-header'
8
+ : '-mx-4 -mt-4 flex items-center justify-between gap-x-3 p-4 md:-mx-6 md:-mt-6 md:p-6',
9
+ ]"
10
+ @click.stop
9
11
  >
10
12
  <slot></slot>
11
13
  </component>
@@ -18,6 +20,10 @@ export default {
18
20
  inject: ['apiDialog'],
19
21
 
20
22
  props: {
23
+ headless: {
24
+ type: Boolean,
25
+ default: false,
26
+ },
21
27
  as: {
22
28
  type: String,
23
29
  default: 'header',
@@ -25,16 +31,8 @@ export default {
25
31
  },
26
32
 
27
33
  computed: {
28
- dark() {
29
- return this.apiDialog().isDark;
30
- },
31
-
32
- headless() {
33
- return this.apiDialog().isHeadless;
34
- },
35
-
36
34
  id() {
37
- return `${this.apiDialog().id}-header`;
35
+ return `dialog-header-${this.apiDialog().componentId}`;
38
36
  },
39
37
  },
40
38
 
@@ -2,10 +2,7 @@
2
2
  <component
3
3
  :is="as"
4
4
  :id="id"
5
- :class="{
6
- 'Dialog-body': headless,
7
- 'flex-1 w-full h-full overflow-y-auto': !headless,
8
- }"
5
+ :class="[headless ? 'dialog-body' : 'h-full flex-1 overflow-y-auto']"
9
6
  >
10
7
  <slot></slot>
11
8
  </component>
@@ -18,6 +15,10 @@ export default {
18
15
  inject: ['apiDialog'],
19
16
 
20
17
  props: {
18
+ headless: {
19
+ type: Boolean,
20
+ default: false,
21
+ },
21
22
  as: {
22
23
  type: String,
23
24
  default: 'main',
@@ -25,16 +26,8 @@ export default {
25
26
  },
26
27
 
27
28
  computed: {
28
- dark() {
29
- return this.apiDialog().isDark;
30
- },
31
-
32
- headless() {
33
- return this.apiDialog().isHeadless;
34
- },
35
-
36
29
  id() {
37
- return `${this.apiDialog().id}-desc`;
30
+ return `dialog-main-${this.apiDialog().componentId}`;
38
31
  },
39
32
  },
40
33
 
@@ -3,11 +3,8 @@
3
3
  <div
4
4
  v-if="visible"
5
5
  :id="id"
6
- :class="{
7
- 'Dialog-overlay': headless,
8
- 'bg-primary-200/80 fixed inset-0': !headless,
9
- }"
10
- ></div>
6
+ :class="[headless ? 'dialog-overlay' : 'bg-primary-200/80 fixed inset-0']"
7
+ />
11
8
  </FadeInOut>
12
9
  </template>
13
10
 
@@ -23,6 +20,13 @@ export default {
23
20
 
24
21
  inject: ['apiDialog'],
25
22
 
23
+ props: {
24
+ headless: {
25
+ type: Boolean,
26
+ default: false,
27
+ },
28
+ },
29
+
26
30
  data() {
27
31
  return {
28
32
  visible: false,
@@ -33,14 +37,6 @@ export default {
33
37
  id() {
34
38
  return `dialog-overlay-${this.apiDialog().componentId}`;
35
39
  },
36
-
37
- dark() {
38
- return this.apiDialog().isDark;
39
- },
40
-
41
- headless() {
42
- return this.apiDialog().isHeadless;
43
- },
44
40
  },
45
41
 
46
42
  mounted() {
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <span
3
3
  :id="id"
4
- :class="{ 'Dialog-header': headless, 'text-2xl font-semibold': !headless }"
4
+ :class="[headless ? 'dialog-header' : 'text-2xl font-semibold']"
5
5
  >
6
6
  <slot></slot
7
7
  ></span>
@@ -13,13 +13,16 @@ export default {
13
13
 
14
14
  inject: ['apiDialog'],
15
15
 
16
- computed: {
17
- headless() {
18
- return this.apiDialog().isHeadless;
16
+ props: {
17
+ headless: {
18
+ type: Boolean,
19
+ default: false,
19
20
  },
21
+ },
20
22
 
23
+ computed: {
21
24
  id() {
22
- return `${this.apiDialog().id}-title`;
25
+ return `dialog-overlay-${this.apiDialog().componentId}`;
23
26
  },
24
27
  },
25
28
  };
@@ -4,7 +4,7 @@
4
4
  :class="[
5
5
  headless
6
6
  ? 'details-header'
7
- : 'flex cursor-pointer justify-between gap-3 text-body font-semibold',
7
+ : 'text-body flex cursor-pointer justify-between gap-3 font-semibold',
8
8
  ]"
9
9
  :aria-controls="ariaControls"
10
10
  :aria-expanded="String(ariaExpanded)"
@@ -56,12 +56,31 @@ export default {
56
56
  type: Boolean,
57
57
  default: false,
58
58
  },
59
+ placement: {
60
+ type: String,
61
+ default: 'bottom-start',
62
+ },
59
63
  },
60
64
 
61
65
  data() {
62
66
  return {
63
67
  componentId: genId(),
64
68
  items: [],
69
+ /**
70
+ * Explaining the need for the floatingUiMinWidth data
71
+ *
72
+ * The floating ui is a result of two items:
73
+ *
74
+ * 1. Trigger: the action button
75
+ * 2. Content: the popper/wrapper that appears after triggering the action button
76
+ *
77
+ * By default, the content will match the triggers width.
78
+ * The problem with this is that the trigger width
79
+ * might be too small causing the content to not fit
80
+ * what is inside it properly. So, to avoid this,
81
+ * a min width is needed.
82
+ */
83
+ floatingUiMinWidth: 200,
65
84
  };
66
85
  },
67
86
 
@@ -1,10 +1,9 @@
1
1
  <template>
2
2
  <FloatingUi
3
- :visible="visible"
4
3
  :id="id"
4
+ :visible="visible"
5
5
  :headless="headless"
6
- :class="{ 'dropdown-menu-content': headless }"
7
- :floating-ui-class="floatingUiClass"
6
+ component="dropdown"
8
7
  >
9
8
  <slot></slot>
10
9
  </FloatingUi>
@@ -16,6 +15,8 @@ import { floatingUiContentMixin } from '../../../mixins/floating-ui-content';
16
15
  export default {
17
16
  name: 'VTDropdownMenuContent',
18
17
 
18
+ inheritAttrs: false,
19
+
19
20
  mixins: [floatingUiContentMixin],
20
21
 
21
22
  inject: ['apiDropdownMenu'],
@@ -39,13 +40,20 @@ export default {
39
40
  id: this.id,
40
41
  hide: this.hide,
41
42
  show: this.show,
42
- getMousemove: this.getMousemove,
43
- setMousemove: this.setMousemove,
44
- unsetMousemove: this.unsetMousemove,
45
43
  setActiveDescedant: this.setActiveDescedant,
46
44
  };
47
45
 
48
46
  this.apiDropdownMenu().registerContent(content);
49
47
  },
48
+
49
+ methods: {
50
+ hidden() {
51
+ this.$emit('hidden');
52
+ },
53
+
54
+ shown() {
55
+ this.$emit('shown');
56
+ },
57
+ },
50
58
  };
51
59
  </script>
@@ -1,9 +1,8 @@
1
1
  <template>
2
2
  <div
3
- :class="{
4
- PopoverDivider: headless,
5
- '-mx-3 my-2 h-[1px]': !headless,
6
- }"
3
+ :class="[
4
+ headless ? 'dropdown-menu-divider' : '-mx-3 my-2 h-[1px] bg-gray-200',
5
+ ]"
7
6
  ></div>
8
7
  </template>
9
8
 
@@ -13,18 +12,10 @@ export default {
13
12
 
14
13
  inject: ['apiDropdownMenu'],
15
14
 
16
- headless: {
17
- type: Boolean,
18
- default: false,
19
- },
20
-
21
- computed: {
22
- dark() {
23
- return this.apiDropdownMenu().isDark;
24
- },
25
-
26
- headless() {
27
- return this.apiDropdownMenu().isHeadless;
15
+ props: {
16
+ headless: {
17
+ type: Boolean,
18
+ default: false,
28
19
  },
29
20
  },
30
21
  };
@@ -9,8 +9,8 @@
9
9
  class="-mx-3"
10
10
  role="menuitem"
11
11
  @click.stop.prevent="onClick"
12
- @keydown.down.prevent="focusPreviousItem"
13
- @keydown.up.prevent="focusNextItem"
12
+ @keydown.down.prevent="focusNextItem"
13
+ @keydown.up.prevent="focusPreviousItem"
14
14
  @keydown.home.prevent="focusFirstItem"
15
15
  @keydown.end.prevent="focusLastItem"
16
16
  @keydown.esc.prevent="onKeyEsc"
@@ -51,11 +51,7 @@ export default {
51
51
 
52
52
  computed: {
53
53
  as() {
54
- return this.href
55
- ? 'a'
56
- : this.to
57
- ? resolveComponent('NuxtLink')
58
- : 'button';
54
+ return this.href ? 'a' : this.to ? 'NuxtLink' : 'button';
59
55
  },
60
56
  },
61
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>
@@ -18,10 +13,6 @@ export default {
18
13
  inject: ['apiDropdownMenu'],
19
14
 
20
15
  computed: {
21
- dark() {
22
- return this.apiDropdownMenu().isDark;
23
- },
24
-
25
16
  headless() {
26
17
  return this.apiDropdownMenu().isHeadless;
27
18
  },