edvoyui-component-library-test-flight 0.0.135 → 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,5 +1,5 @@
1
1
  export * from "/Volumes/work/repos/edvoy-ui-v2/src/components/popover/EUIPopover.vue?vue&type=script&setup=true&lang.ts";
2
- import "/Volumes/work/repos/edvoy-ui-v2/src/components/popover/EUIPopover.vue?vue&type=style&index=0&scoped=29b158d9&lang.scss";
2
+ import "/Volumes/work/repos/edvoy-ui-v2/src/components/popover/EUIPopover.vue?vue&type=style&index=0&scoped=03588f75&lang.scss";
3
3
  declare const _default: any;
4
4
  export default _default;
5
5
  //# sourceMappingURL=EUIPopover.vue.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "edvoyui-component-library-test-flight",
3
3
  "private": false,
4
- "version": "0.0.135",
4
+ "version": "0.0.136",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist/",
@@ -5,22 +5,261 @@
5
5
  >
6
6
  Edvoy User Interface
7
7
  </h1>
8
-
9
- <!-- TODO: Add scroll to tab section in Student details page same -->
10
-
11
8
  </div>
12
9
  </template>
13
10
  <script setup lang="ts">
14
-
15
11
  </script>
16
12
  <style lang="scss"></style>
17
13
 
18
14
  <!-- Development code here -->
19
15
 
20
- <!-- <template>
16
+ <!-- <template>
21
17
  <div class="h-[clac(100svh-64px)] w-full px-10 py-8 max-w-screen-xl mx-auto">
22
18
  <h1 class="mb-2 font-semibold text-gray-900 tetx-lg">Edvoy UI Componnet</h1>
23
19
 
20
+
21
+ <div class="grid w-full h-48 grid-cols-4 gap-4 mb-20 isolate">
22
+ <div
23
+ class="flex items-center justify-between w-full max-w-2xl gap-4 p-2 mx-auto border rounded-lg h-max"
24
+ >
25
+ <div class="text-base font-semibold leading-loose text-gray-900">
26
+ Popover Click Method
27
+ </div>
28
+
29
+ <div class="inline-flex items-center justify-end flex-none gap-4">
30
+ <EUIPopover
31
+ trigger="click"
32
+ placement="bottom-end"
33
+ className="max-w-80 min-w-80"
34
+ customButton="capitalize box-border border-none inline-flex flex-row gap-x-2 items-center active:scale-[.97] active:shadow-md transition duration-150 ease-in-out active:translate-y-0.5 rounded-lg bg-white hover:bg-gray-100 active:bg-gray-50 text-black cursor-pointer active:shadow-white/50 active:bg-transparent text-base font-semibold p-2"
35
+ >
36
+ <template #referenceButton="{ open }">
37
+ <div class="relative">
38
+ <FunnelIcon class="text-current size-6" />
39
+ <div
40
+ v-if="!open"
41
+ class="absolute bg-purple-600 border-2 border-white -top-1 -right-1 rounded-3xl size-3"
42
+ />
43
+ </div>
44
+ </template>
45
+
46
+ <div
47
+ class="block p-6 bg-white rounded-lg shadow-lg me-2 ring-1 ring-gray-100 ring-opacity-10"
48
+ >
49
+ <div>lorem ipsum dolor sit amet consectetur adipisicing elit.</div>
50
+ <div @click.stop>
51
+ <EUISelect
52
+ search-label="name"
53
+ label="Select Label"
54
+ placeholder="Placeholder"
55
+ :items="datas"
56
+ :multiple="true"
57
+ :multiple-limit="3"
58
+ />
59
+ </div>
60
+
61
+ <div>lorem ipsum dolor sit amet consectetur adipisicing elit</div>
62
+ <div class="flex items-center justify-end gap-4 pt-4">
63
+ <EUIButton
64
+ type="button"
65
+ size="md"
66
+ color="white"
67
+ :loading="isLoading"
68
+ @click="resetFilters()"
69
+ >Reset</EUIButton
70
+ >
71
+ <EUIButton
72
+ type="button"
73
+ size="md"
74
+ color="purple"
75
+ :loading="isLoading"
76
+ @click="applyFilter()"
77
+ >Apply</EUIButton
78
+ >
79
+ </div>
80
+ </div>
81
+ </EUIPopover>
82
+ </div>
83
+ </div>
84
+
85
+ <div
86
+ class="flex items-center justify-between w-full max-w-2xl gap-4 p-2 mx-auto border rounded-lg h-max"
87
+ >
88
+ <div class="text-base font-semibold leading-loose text-gray-900">
89
+ Popover Hover Method
90
+ </div>
91
+
92
+ <div class="inline-flex items-center justify-end flex-none gap-4">
93
+ <EUIPopover
94
+ trigger="hover"
95
+ placement="bottom-end"
96
+ :hover-hide-delay="150"
97
+ className="max-w-80 min-w-80"
98
+ customButton="capitalize box-border border-none inline-flex flex-row gap-x-2 items-center active:scale-[.97] active:shadow-md transition duration-150 ease-in-out active:translate-y-0.5 rounded-lg bg-white hover:bg-gray-100 active:bg-gray-50 text-black cursor-pointer active:shadow-white/50 active:bg-transparent text-base font-semibold p-2"
99
+ >
100
+ <template #referenceButton>
101
+ <div class="relative">
102
+ <FunnelIcon class="text-current size-6" />
103
+ <div
104
+ class="absolute bg-purple-600 border-2 border-white -top-1 -right-1 rounded-3xl size-3"
105
+ />
106
+ </div>
107
+ </template>
108
+ <div
109
+ class="block p-6 bg-white rounded-lg shadow-lg me-2 ring-1 ring-gray-100 ring-opacity-10"
110
+ >
111
+ <div>
112
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Ex atque
113
+ sed illo ipsa tenetur dolores minus quis, impedit aliquam magni.
114
+ Animi laborum tenetur culpa aperiam porro nihil eius soluta
115
+ asperiores.
116
+ </div>
117
+
118
+ <div class="flex items-center justify-end gap-4 pt-4">
119
+ <EUIButton
120
+ type="button"
121
+ size="md"
122
+ color="white"
123
+ :loading="isLoading"
124
+ @click="resetFilters()"
125
+ >Reset</EUIButton
126
+ >
127
+ <EUIButton
128
+ type="button"
129
+ size="md"
130
+ color="purple"
131
+ :loading="isLoading"
132
+ @click="applyFilter()"
133
+ >Apply</EUIButton
134
+ >
135
+ </div>
136
+ </div>
137
+ </EUIPopover>
138
+ </div>
139
+ </div>
140
+
141
+ <div
142
+ class="flex items-center justify-between w-full max-w-2xl gap-4 p-2 mx-auto border rounded-lg h-max"
143
+ >
144
+ <div class="text-base font-semibold leading-loose text-gray-900">
145
+ Popover Default Open
146
+ </div>
147
+
148
+ <div class="inline-flex items-center justify-end flex-none gap-4">
149
+ <EUIPopover
150
+ v-model:visible="isInitiallyOpen"
151
+ placement="bottom-end"
152
+ :hover-hide-delay="150"
153
+ className="max-w-80 min-w-80"
154
+ customButton="capitalize box-border border-none inline-flex flex-row gap-x-2 items-center active:scale-[.97] active:shadow-md transition duration-150 ease-in-out active:translate-y-0.5 rounded-lg bg-white hover:bg-gray-100 active:bg-gray-50 text-black cursor-pointer active:shadow-white/50 active:bg-transparent text-base font-semibold p-2"
155
+ >
156
+ <template #referenceButton>
157
+ <div class="relative">
158
+ <FunnelIcon class="text-current size-6" />
159
+ <div
160
+ class="absolute bg-purple-600 border-2 border-white -top-1 -right-1 rounded-3xl size-3"
161
+ />
162
+ </div>
163
+ </template>
164
+ <div
165
+ class="block p-6 bg-white rounded-lg shadow-lg me-2 ring-1 ring-gray-100 ring-opacity-10"
166
+ >
167
+ <div>
168
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Ex atque
169
+ sed illo ipsa tenetur dolores minus quis, impedit aliquam magni.
170
+ Animi laborum tenetur culpa aperiam porro nihil eius soluta
171
+ asperiores.
172
+ </div>
173
+
174
+ <div class="flex items-center justify-end gap-4 pt-4">
175
+ <EUIButton
176
+ type="button"
177
+ size="md"
178
+ color="white"
179
+ :loading="isLoading"
180
+ @click="resetFilters()"
181
+ >Reset</EUIButton
182
+ >
183
+ <EUIButton
184
+ type="button"
185
+ size="md"
186
+ color="purple"
187
+ :loading="isLoading"
188
+ @click="onDefaultClose()"
189
+ >Apply</EUIButton
190
+ >
191
+ </div>
192
+ </div>
193
+ </EUIPopover>
194
+ </div>
195
+ </div>
196
+
197
+ <div
198
+ class="flex items-center justify-between w-full max-w-2xl gap-4 p-2 mx-auto border rounded-lg h-max"
199
+ >
200
+ <div class="text-base font-semibold leading-loose text-gray-900">
201
+ Popover Manual
202
+ </div>
203
+
204
+ <div class="inline-flex items-center justify-end flex-none gap-4">
205
+ <EUIPopover
206
+ trigger="manual"
207
+ v-model:visible="popoverVisible"
208
+ placement="top"
209
+ className="max-w-80 min-w-80"
210
+ customButton="capitalize box-border border-none inline-flex flex-row gap-x-2 items-center active:scale-[.97] active:shadow-md transition duration-150 ease-in-out active:translate-y-0.5 rounded-lg bg-white hover:bg-gray-100 active:bg-gray-50 text-black cursor-pointer active:shadow-white/50 active:bg-transparent text-base font-semibold p-2"
211
+ @click="onPopoverToggle"
212
+ >
213
+ <template #referenceButton>
214
+ <div class="relative">
215
+ <FunnelIcon class="text-current size-6" />
216
+ <div
217
+ class="absolute bg-purple-600 border-2 border-white -top-1 -right-1 rounded-3xl size-3"
218
+ />
219
+ </div>
220
+ </template>
221
+ <div
222
+ class="block p-6 bg-white rounded-lg shadow-lg me-2 ring-1 ring-gray-100 ring-opacity-10"
223
+ >
224
+ <div>lorem ipsum dolor sit amet consectetur adipisicing elit.</div>
225
+ <div @click.stop>
226
+ <EUISelect
227
+ search-label="name"
228
+ label="Select Label"
229
+ placeholder="Placeholder"
230
+ :items="datas"
231
+ :multiple="true"
232
+ :multiple-limit="3"
233
+ />
234
+ </div>
235
+
236
+ <div>lorem ipsum dolor sit amet consectetur adipisicing elit</div>
237
+
238
+ <div class="flex items-center justify-end gap-4 pt-4">
239
+ <EUIButton
240
+ type="button"
241
+ size="md"
242
+ color="white"
243
+ :loading="isLoading"
244
+ @click="resetFilters()"
245
+ >Reset</EUIButton
246
+ >
247
+ <EUIButton
248
+ type="button"
249
+ size="md"
250
+ color="purple"
251
+ :loading="isLoading"
252
+ @click="applyFilter()"
253
+ >Apply</EUIButton
254
+ >
255
+ </div>
256
+ </div>
257
+ </EUIPopover>
258
+ </div>
259
+ </div>
260
+ </div>
261
+
262
+
24
263
  <div class="mb-10">
25
264
  <EUITabOutline
26
265
  activeColor="purple"
@@ -1152,7 +1391,7 @@ import EUIAvatar from "./avatar/EUIAvatar.vue";
1152
1391
  import EUIStepperTimeline from "./stepperTimeline/EUIStepperTimeline.vue";
1153
1392
  import EUIAccordion from "./accordion/EUIAccordion.vue";
1154
1393
  import EUITelephone from "./telephone/EUITelephone.vue";
1155
- import { DevicePhoneMobileIcon, ExclamationTriangleIcon, HomeIcon } from "@heroicons/vue/24/outline";
1394
+ import { DevicePhoneMobileIcon, ExclamationTriangleIcon, FunnelIcon, HomeIcon } from "@heroicons/vue/24/outline";
1156
1395
  import EUIDatepicker from "./datepicker/EUIDatepicker.vue";
1157
1396
  import EUIDashboardTable from "./table/EUIDashboardTable.vue";
1158
1397
  import tabData from "../data/tab";
@@ -1172,6 +1411,30 @@ import EUIAlerts from "./alerts/EUIAlerts.vue";
1172
1411
  import EUIButtonGroup from "./button/EUIButtonGroup.vue";
1173
1412
  import EUISearchExpand from "./searchexpand/EUISearchExpand.vue";
1174
1413
  import EUITabOutline from "./tabs/EUITabOutline.vue";
1414
+ import EUIPopover from "./popover/EUIPopover.vue";
1415
+
1416
+ // TODO: Popover
1417
+ const isLoading = ref(false);
1418
+ const popoverVisible = ref(false);
1419
+
1420
+ const isInitiallyOpen = ref(true);
1421
+ const onDefaultClose = () => {
1422
+ isInitiallyOpen.value = false;
1423
+ };
1424
+
1425
+ const onPopoverToggle = () => {
1426
+ popoverVisible.value = !popoverVisible.value;
1427
+ };
1428
+
1429
+ const onPopoverHide = () => {
1430
+ popoverVisible.value = false;
1431
+ };
1432
+
1433
+ const applyFilter = () => {
1434
+ onPopoverHide();
1435
+ };
1436
+
1437
+ const resetFilters = () => {};
1175
1438
 
1176
1439
  const allDays = ref([
1177
1440
  { name: "7 days", count: 5 },
@@ -1,16 +1,31 @@
1
1
  <template>
2
- <div ref="popperWrapper" class="isolate w-max">
2
+ <div ref="popperWrapper" class="w-max">
3
3
  <div
4
4
  ref="popperButton"
5
+ :id="triggerId"
6
+ :aria-describedby="tooltipId"
7
+ :aria-expanded="isOpen"
8
+ aria-haspopup="true"
5
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,70 +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
 
55
82
  const popperWrapper = ref<HTMLElement | null>(null);
56
83
  const popperInstance = ref<Instance | null>(null);
57
84
  const popperButton = ref<HTMLElement | null>(null);
58
85
  const tooltip = ref<HTMLElement | null>(null);
59
- const isOpen = ref(false);
86
+ const arrowElement = ref<HTMLElement | null>(null);
60
87
 
61
- 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);
62
90
 
63
- onMounted(() => {
64
- onClickOutside(popperWrapper.value, hide);
91
+ const uniqueId = `popover-${Math.random().toString(36).substring(2, 9)}`;
92
+ const triggerId = computed(() => `${uniqueId}-trigger`);
93
+ const tooltipId = computed(() => `${uniqueId}-tooltip`);
65
94
 
66
- if (props.trigger === "click") {
67
- useEventListener(popperButton.value, "click", toggle);
68
- } else if (props.trigger === "hover") {
69
- const showEvents = ["mouseenter", "focus"];
70
- const hideEvents = ["mouseleave", "blur"];
95
+ const emit = defineEmits<{
96
+ (e: 'update:visible', value: boolean): void;
97
+ (e: 'show'): void;
98
+ (e: 'hide'): void;
99
+ }>();
71
100
 
72
- showEvents.forEach((event) => {
73
- popperButton.value?.addEventListener(event, show);
74
- });
101
+ watch(() => props.visible, (newValue) => {
102
+ if (newValue !== undefined && newValue !== isOpen.value) {
103
+ if (newValue) {
104
+ show();
105
+ } else {
106
+ hide();
107
+ }
108
+ }
109
+ });
75
110
 
76
- hideEvents.forEach((event) => {
77
- popperButton.value?.addEventListener(event, hide);
78
- });
111
+ watch(isOpen, (newValue) => {
112
+ if (props.visible === undefined || newValue !== props.visible) {
113
+ emit('update:visible', newValue);
79
114
  }
115
+ nextTick(() => {
116
+ popperInstance.value?.update();
117
+ });
118
+ });
80
119
 
81
- if (popperButton.value && tooltip.value) {
120
+
121
+ const initializePopper = () => {
122
+ if (popperButton.value && tooltip.value && arrowElement.value) {
82
123
  popperInstance.value = createPopper(popperButton.value, tooltip.value, {
83
124
  placement: props.placement,
84
125
  modifiers: [
126
+ { name: 'offset', options: { offset: [0, 10] } },
127
+ { name: 'arrow', options: { element: arrowElement.value } },
85
128
  {
86
- name: "offset",
129
+ name: 'preventOverflow',
87
130
  options: {
88
- offset: [0, 8],
131
+ padding: 8,
89
132
  },
90
133
  },
91
134
  ],
92
135
  });
93
136
  }
94
- });
137
+ };
95
138
 
96
- function toggle() {
97
- if (isOpen.value) {
98
- hide();
139
+ const destroyPopper = () => {
140
+ if (popperInstance.value) {
141
+ popperInstance.value.destroy();
142
+ popperInstance.value = null;
143
+ }
144
+ };
145
+
146
+ const show = () => {
147
+ if (isOpen.value) return;
148
+ clearTimeout(hideTimer.value!);
149
+ isOpen.value = true;
150
+ emit('show');
151
+ nextTick(() => {
152
+ if (!popperInstance.value) {
153
+ initializePopper();
154
+ }
155
+ popperInstance.value?.update();
156
+ popperInstance.value?.forceUpdate();
157
+ });
158
+ };
159
+
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);
99
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') {
100
189
  show();
101
190
  }
102
- }
191
+ };
103
192
 
104
- function show() {
105
- tooltip.value?.setAttribute("data-show", "");
106
- isOpen.value = true;
107
- emit("showPopover");
108
- popperInstance.value?.update();
109
- }
193
+ const handleMouseLeave = () => {
194
+ if (props.trigger === 'hover') {
195
+ hide(false);
196
+ }
197
+ };
110
198
 
111
- function hide() {
112
- tooltip.value?.removeAttribute("data-show");
113
- isOpen.value = false;
114
- emit("hidePopover");
115
- }
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
+ });
116
244
  </script>
117
245
 
118
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>