edvoyui-component-library-test-flight 0.0.134 → 0.0.136

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.
@@ -1,16 +1,31 @@
1
1
  <template>
2
- <div>
2
+ <div ref="popperWrapper" class="w-max">
3
3
  <div
4
4
  ref="popperButton"
5
- :class="['inline-flex items-center text-sm font-semibold gap-x-2', customButton]"
5
+ :id="triggerId"
6
+ :aria-describedby="tooltipId"
7
+ :aria-expanded="isOpen"
8
+ aria-haspopup="true"
9
+ :class="['inline-flex items-center text-sm font-semibold gap-x-2 cursor-pointer', customButton]"
10
+ @click="handleClick"
11
+ @mouseenter="handleMouseEnter"
12
+ @mouseleave="handleMouseLeave"
13
+ @focus="handleFocus"
14
+ @blur="handleBlur"
6
15
  >
7
16
  <slot name="referenceButton" :open="isOpen"/>
8
17
  </div>
9
18
  <div
10
- ref="tooltip"
11
- :class="['poppertooltip h-auto text-sm font-normal bg-white', className]"
19
+ ref="tooltip"
20
+ :id="tooltipId"
21
+ role="tooltip"
22
+ :class="['poppertooltip h-auto text-sm font-normal select-none z-50', className]"
23
+ :data-show="isOpen ? '' : null"
24
+ @click.stop
25
+ @mouseenter="handleTooltipMouseEnter"
26
+ @mouseleave="handleTooltipMouseLeave"
12
27
  >
13
- <div class="arrow" data-popper-arrow />
28
+ <div ref="arrowElement" class="arrow" data-popper-arrow />
14
29
  <div
15
30
  v-if="title"
16
31
  class="text-base font-semibold text-current leading-[normal] px-4 py-2"
@@ -22,19 +37,23 @@
22
37
  </template>
23
38
 
24
39
  <script setup lang="ts">
25
- import { PropType } from "vue";
40
+ import { computed, nextTick, onBeforeUnmount, PropType, watch } from "vue";
26
41
  import { createPopper, Instance } from "@popperjs/core";
27
- import { onClickOutside, useEventListener } from "@vueuse/core";
42
+ import { onClickOutside } from "@vueuse/core";
28
43
  import { onMounted, ref } from "vue";
29
44
  const props = defineProps({
45
+ defaultOpen: {
46
+ type: Boolean,
47
+ default: false,
48
+ },
30
49
  title: {
31
50
  type: String,
32
51
  default: "",
33
52
  },
34
53
  trigger: {
35
- type: String as PropType<"click" | "hover">,
54
+ type: String as PropType<"click" | "hover" | "manual">,
36
55
  default: "click",
37
- validator: (value: string) => ["click", "hover"].includes(value),
56
+ validator: (value: string) => ["click", "hover", "manual"].includes(value),
38
57
  },
39
58
  className: {
40
59
  type: String,
@@ -49,60 +68,179 @@ const props = defineProps({
49
68
  type: String,
50
69
  required: false,
51
70
  default: ''
52
- }
71
+ },
72
+ visible: {
73
+ type: Boolean,
74
+ default: undefined,
75
+ },
76
+ hoverHideDelay: {
77
+ type: Number,
78
+ default: 100,
79
+ },
53
80
  });
54
81
 
82
+ const popperWrapper = ref<HTMLElement | null>(null);
55
83
  const popperInstance = ref<Instance | null>(null);
56
84
  const popperButton = ref<HTMLElement | null>(null);
57
85
  const tooltip = ref<HTMLElement | null>(null);
58
- const isOpen = ref(false);
86
+ const arrowElement = ref<HTMLElement | null>(null);
59
87
 
60
- const emit = defineEmits(['showPopover', 'hidePopover']);
88
+ const isOpen = ref(props.visible === undefined ? props.defaultOpen : props.visible);
89
+ const hideTimer = ref<ReturnType<typeof setTimeout> | null>(null);
61
90
 
62
- onMounted(() => {
63
- if (props.trigger === "click") {
64
- useEventListener(popperButton.value, "click", show);
65
- onClickOutside(popperButton.value, hide);
66
- } else if (props.trigger === "hover") {
67
- const showEvents = ["mouseenter", "focus"];
68
- const hideEvents = ["mouseleave", "blur"];
69
-
70
- showEvents.forEach((event) => {
71
- popperButton.value?.addEventListener(event, show);
72
- });
91
+ const uniqueId = `popover-${Math.random().toString(36).substring(2, 9)}`;
92
+ const triggerId = computed(() => `${uniqueId}-trigger`);
93
+ const tooltipId = computed(() => `${uniqueId}-tooltip`);
73
94
 
74
- hideEvents.forEach((event) => {
75
- popperButton.value?.addEventListener(event, hide);
76
- });
95
+ const emit = defineEmits<{
96
+ (e: 'update:visible', value: boolean): void;
97
+ (e: 'show'): void;
98
+ (e: 'hide'): void;
99
+ }>();
100
+
101
+ watch(() => props.visible, (newValue) => {
102
+ if (newValue !== undefined && newValue !== isOpen.value) {
103
+ if (newValue) {
104
+ show();
105
+ } else {
106
+ hide();
107
+ }
77
108
  }
109
+ });
78
110
 
79
- if (popperButton.value && tooltip.value) {
111
+ watch(isOpen, (newValue) => {
112
+ if (props.visible === undefined || newValue !== props.visible) {
113
+ emit('update:visible', newValue);
114
+ }
115
+ nextTick(() => {
116
+ popperInstance.value?.update();
117
+ });
118
+ });
119
+
120
+
121
+ const initializePopper = () => {
122
+ if (popperButton.value && tooltip.value && arrowElement.value) {
80
123
  popperInstance.value = createPopper(popperButton.value, tooltip.value, {
81
124
  placement: props.placement,
82
125
  modifiers: [
126
+ { name: 'offset', options: { offset: [0, 10] } },
127
+ { name: 'arrow', options: { element: arrowElement.value } },
83
128
  {
84
- name: "offset",
129
+ name: 'preventOverflow',
85
130
  options: {
86
- offset: [0, 8],
131
+ padding: 8,
87
132
  },
88
133
  },
89
134
  ],
90
135
  });
91
136
  }
92
- });
137
+ };
138
+
139
+ const destroyPopper = () => {
140
+ if (popperInstance.value) {
141
+ popperInstance.value.destroy();
142
+ popperInstance.value = null;
143
+ }
144
+ };
93
145
 
94
- function show() {
95
- tooltip.value?.setAttribute("data-show", "");
146
+ const show = () => {
147
+ if (isOpen.value) return;
148
+ clearTimeout(hideTimer.value!);
96
149
  isOpen.value = true;
97
- emit("showPopover");
98
- popperInstance.value?.update();
99
- }
150
+ emit('show');
151
+ nextTick(() => {
152
+ if (!popperInstance.value) {
153
+ initializePopper();
154
+ }
155
+ popperInstance.value?.update();
156
+ popperInstance.value?.forceUpdate();
157
+ });
158
+ };
100
159
 
101
- function hide() {
102
- tooltip.value?.removeAttribute("data-show");
103
- isOpen.value = false;
104
- emit("hidePopover");
105
- }
160
+ // Hide the popover
161
+ const hide = (immediate = false) => {
162
+ if (!isOpen.value) return; // Already closed
163
+
164
+ if (props.trigger === 'hover' && !immediate) {
165
+ clearTimeout(hideTimer.value!);
166
+ hideTimer.value = setTimeout(() => {
167
+ isOpen.value = false;
168
+ emit('hide');
169
+ }, props.hoverHideDelay);
170
+ } else {
171
+ clearTimeout(hideTimer.value!);
172
+ isOpen.value = false;
173
+ emit('hide');
174
+ }
175
+ };
176
+
177
+ const handleClick = () => {
178
+ if (props.trigger === 'click') {
179
+ if (isOpen.value) {
180
+ hide(true);
181
+ } else {
182
+ show();
183
+ }
184
+ }
185
+ };
186
+
187
+ const handleMouseEnter = () => {
188
+ if (props.trigger === 'hover') {
189
+ show();
190
+ }
191
+ };
192
+
193
+ const handleMouseLeave = () => {
194
+ if (props.trigger === 'hover') {
195
+ hide(false);
196
+ }
197
+ };
198
+
199
+ const handleFocus = () => {
200
+ if (props.trigger === 'hover') {
201
+ show();
202
+ }
203
+ };
204
+
205
+ const handleBlur = () => {
206
+ if (props.trigger === 'hover') {
207
+ hide(false);
208
+ }
209
+ };
210
+
211
+ const handleTooltipMouseEnter = () => {
212
+ if (props.trigger === 'hover') {
213
+ clearTimeout(hideTimer.value!);
214
+ }
215
+ };
216
+
217
+ const handleTooltipMouseLeave = () => {
218
+ if (props.trigger === 'hover') {
219
+ hide(false);
220
+ }
221
+ };
222
+
223
+ onMounted(() => {
224
+ if (isOpen.value) {
225
+ nextTick(() => {
226
+ initializePopper();
227
+ setTimeout(() => popperInstance.value?.forceUpdate(), 50);
228
+ });
229
+ }
230
+
231
+ if (props.trigger === 'click') {
232
+ onClickOutside(popperWrapper.value, () => {
233
+ if (isOpen.value) {
234
+ hide(true);
235
+ }
236
+ }, { ignore: [popperButton] });
237
+ }
238
+ });
239
+
240
+ onBeforeUnmount(() => {
241
+ destroyPopper();
242
+ clearTimeout(hideTimer.value!); // Clear any running timers
243
+ });
106
244
  </script>
107
245
 
108
246
  <style lang="scss" scoped>
@@ -63,9 +63,11 @@
63
63
  <template #expanded="{ row, rowIndex, headerLength }">
64
64
  <tr v-if="rowIndex === activeRowIndex" class="row-expanded" :key="`${row}-${rowIndex}-val`">
65
65
  <td :colspan="headerLength">
66
- <table
66
+ <div>
67
+ <table
67
68
  class="px-12 border-separate table-auto max-w-max border-spacing-x-0 border-spacing-y-2"
68
69
  >
70
+ <tbody>
69
71
  <tr
70
72
  class="rounded-lg group bg-white hover:bg-violet-50 hover:ring-1 ring-violet-300 hover:shadow-[0px_1px_2px_0px_#4B55631A,0px_2px_2px_0px_#4B556314]"
71
73
  >
@@ -122,7 +124,10 @@
122
124
  {{ data }}
123
125
  </td>
124
126
  </tr>
127
+ </tbody>
128
+
125
129
  </table>
130
+ </div>
126
131
  </td>
127
132
  </tr>
128
133
  </template>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="bg-white" v-bind="$attrs">
2
+ <div class="bg-white rounded-t-xl" v-bind="$attrs">
3
3
  <div
4
4
  class="relative z-10 inline-flex items-center w-full gap-2 pt-3 overflow-hidden transition-all duration-200 ease-in border border-b-0 border-solid rounded-t-xl isolate before:h-4 before:w-px before:bg-gray-200 before:-bottom-3 before:-left-px before:absolute after:h-4 after:w-px after:bg-gray-200 after:-bottom-3 after:-right-px after:absolute bg-gradient-to-b from-gray-100"
5
5
  >
@@ -20,7 +20,7 @@
20
20
  v-bind="buttonAttrs"
21
21
  :data-tab="data.name"
22
22
  :class="[
23
- 'capitalize box-border border-none inline-flex flex-row gap-x-2 items-center',
23
+ 'capitalize box-border border-none inline-flex flex-row gap-x-2 items-center will-change-contents',
24
24
  getBtnClass(data.name || ''),
25
25
  activeBtnName === data.name ? 'font-semibold' : 'font-normal',
26
26
  ]"