edvoyui-component-library-test-flight 0.0.21 → 0.0.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 (125) hide show
  1. package/dist/EUIButton.vue.d.ts.map +1 -0
  2. package/dist/library-vue-ts.cjs.js +4 -3
  3. package/dist/library-vue-ts.es.js +3 -8
  4. package/dist/library-vue-ts.umd.js +4 -3
  5. package/dist/select/EUISelect.vue.d.ts.map +1 -0
  6. package/package.json +4 -2
  7. package/src/App.vue +16 -0
  8. package/src/assets/fonts/gilroy/GilroyBold/font.woff +0 -0
  9. package/src/assets/fonts/gilroy/GilroyBold/font.woff2 +0 -0
  10. package/src/assets/fonts/gilroy/GilroyBoldItalic/font.woff +0 -0
  11. package/src/assets/fonts/gilroy/GilroyBoldItalic/font.woff2 +0 -0
  12. package/src/assets/fonts/gilroy/GilroyExtraBold/font.woff +0 -0
  13. package/src/assets/fonts/gilroy/GilroyExtraBold/font.woff2 +0 -0
  14. package/src/assets/fonts/gilroy/GilroyExtraBoldItalic/font.woff +0 -0
  15. package/src/assets/fonts/gilroy/GilroyExtraBoldItalic/font.woff2 +0 -0
  16. package/src/assets/fonts/gilroy/GilroyMedium/font.woff +0 -0
  17. package/src/assets/fonts/gilroy/GilroyMedium/font.woff2 +0 -0
  18. package/src/assets/fonts/gilroy/GilroyRegular/font.woff +0 -0
  19. package/src/assets/fonts/gilroy/GilroyRegular/font.woff2 +0 -0
  20. package/src/assets/fonts/gilroy/GilroySemiBold/font.woff +0 -0
  21. package/src/assets/fonts/gilroy/GilroySemiBold/font.woff2 +0 -0
  22. package/src/assets/fonts/inter/Inter-Bold.woff +0 -0
  23. package/src/assets/fonts/inter/Inter-Bold.woff2 +0 -0
  24. package/src/assets/fonts/inter/Inter-Italic.woff +0 -0
  25. package/src/assets/fonts/inter/Inter-Italic.woff2 +0 -0
  26. package/src/assets/fonts/inter/Inter-Medium.woff +0 -0
  27. package/src/assets/fonts/inter/Inter-Medium.woff2 +0 -0
  28. package/src/assets/fonts/inter/Inter-MediumItalic.woff +0 -0
  29. package/src/assets/fonts/inter/Inter-MediumItalic.woff2 +0 -0
  30. package/src/assets/fonts/inter/Inter-Regular.woff +0 -0
  31. package/src/assets/fonts/inter/Inter-Regular.woff2 +0 -0
  32. package/src/assets/fonts/inter/Inter-SemiBold.woff +0 -0
  33. package/src/assets/fonts/inter/Inter-SemiBold.woff2 +0 -0
  34. package/src/assets/fonts/inter/Inter-SemiBoldItalic.woff +0 -0
  35. package/src/assets/fonts/inter/Inter-SemiBoldItalic.woff2 +0 -0
  36. package/src/assets/scss/body.scss +15 -0
  37. package/src/assets/svg/ChevronDownSolid.vue +19 -0
  38. package/src/assets/svg/ChevronDownStroke.vue +22 -0
  39. package/src/assets/svg/SortArrow.vue +24 -0
  40. package/src/assets/svg/Student.vue +30 -0
  41. package/src/assets/svg/partner.vue +33 -0
  42. package/src/assets/svg/people.vue +25 -0
  43. package/src/assets/vue.svg +1 -0
  44. package/src/components/HelloWorld.vue +999 -0
  45. package/src/components/accordion/EUIAccordion.stories.ts +157 -0
  46. package/src/components/accordion/EUIAccordion.vue +90 -0
  47. package/src/components/avatar/EUIAvatar.stories.ts +157 -0
  48. package/src/components/avatar/EUIAvatar.vue +96 -0
  49. package/src/components/button/EUIButton.stories.ts +252 -0
  50. package/src/components/button/EUIButton.vue +151 -0
  51. package/src/components/checkbox/EUICheckbox.stories.ts +58 -0
  52. package/src/components/checkbox/EUICheckbox.vue +103 -0
  53. package/src/components/datepicker/EUIDatepicker.stories.ts +236 -0
  54. package/src/components/datepicker/EUIDatepicker.vue +185 -0
  55. package/src/components/delete.vue +108 -0
  56. package/src/components/dropdown/EUIMultiDropdown.stories.ts +187 -0
  57. package/src/components/dropdown/EUIMultiDropdown.vue +129 -0
  58. package/src/components/errorMessage/EUIErrorMessage.scss +0 -0
  59. package/src/components/errorMessage/EUIErrorMessage.stories.ts +41 -0
  60. package/src/components/errorMessage/EUIErrorMessage.vue +25 -0
  61. package/src/components/index.ts +46 -0
  62. package/src/components/input/EUIInput.stories.ts +174 -0
  63. package/src/components/input/EUIInput.vue +169 -0
  64. package/src/components/inputNormal/EUIInputNormal.stories.ts +164 -0
  65. package/src/components/inputNormal/EUIInputNormal.vue +161 -0
  66. package/src/components/loader/EUICircleLoader.vue +31 -0
  67. package/src/components/loader/EUICubeLoader.vue +237 -0
  68. package/src/components/loader/EUILoader.stories.ts +99 -0
  69. package/src/components/loader/EUILoader.vue +17 -0
  70. package/src/components/loader/EUISquareLoader.vue +47 -0
  71. package/src/components/modal/EUIModal.stories.ts +372 -0
  72. package/src/components/modal/EUIModal.vue +163 -0
  73. package/src/components/pillSelect/EUIPillSelect.stories.ts +74 -0
  74. package/src/components/pillSelect/EUIPillSelect.vue +149 -0
  75. package/src/components/popover/EUIPopover.stories.ts +247 -0
  76. package/src/components/popover/EUIPopover.vue +159 -0
  77. package/src/components/radio/EUIRadio.stories.ts +54 -0
  78. package/src/components/radio/EUIRadio.vue +78 -0
  79. package/src/components/searchInput/EUISearch.stories.ts +24 -0
  80. package/src/components/searchInput/EUISearch.vue +215 -0
  81. package/src/components/select/EUISelect.scss +0 -0
  82. package/src/components/select/EUISelect.stories.ts +49 -0
  83. package/src/components/select/EUISelect.vue +682 -0
  84. package/src/components/selectSearch/EUISelectSearch.vue +23 -0
  85. package/src/components/slideover/EUISlideover.stories.ts +318 -0
  86. package/src/components/slideover/EUISlideover.vue +207 -0
  87. package/src/components/stepperTimeline/EUIStepperHorizontal.vue +112 -0
  88. package/src/components/stepperTimeline/EUIStepperTimeline.stories.ts +54 -0
  89. package/src/components/stepperTimeline/EUIStepperTimeline.vue +16 -0
  90. package/src/components/stepperTimeline/EUIStepperVertical.vue +112 -0
  91. package/src/components/table/EUIDashboardTable.vue +482 -0
  92. package/src/components/table/EUIPageLimit.vue +66 -0
  93. package/src/components/table/EUIPagination.vue +175 -0
  94. package/src/components/table/EUIStudentPagination.vue +172 -0
  95. package/src/components/table/EUITable.stories.ts +190 -0
  96. package/src/components/table/EUITable.vue +508 -0
  97. package/src/components/table/EUITableCheckbox.vue +97 -0
  98. package/src/components/tabs/EUITabs.vue +128 -0
  99. package/src/components/tabs/EUItabs.stories.ts +123 -0
  100. package/src/components/tag/EUITag.stories.ts +46 -0
  101. package/src/components/tag/EUITag.vue +46 -0
  102. package/src/components/telephone/EUITelephone.stories.ts +202 -0
  103. package/src/components/telephone/EUITelephone.vue +280 -0
  104. package/src/components/textArea/EUITextArea.stories.ts +82 -0
  105. package/src/components/textArea/EUITextArea.vue +122 -0
  106. package/src/components/timeLine/EUITimeLine.stories.ts +247 -0
  107. package/src/components/timeLine/EUITimeLine.vue +43 -0
  108. package/src/components/timeLine/EUITimeLineItem.vue +124 -0
  109. package/src/components/toggle/EUIToggle.stories.ts +63 -0
  110. package/src/components/toggle/EUIToggle.vue +99 -0
  111. package/src/components/tooltip/EUITooltip.stories.ts +53 -0
  112. package/src/components/tooltip/EUITooltip.vue +108 -0
  113. package/src/data/books.ts +163 -0
  114. package/src/data/tab.ts +33 -0
  115. package/src/data/table.ts +5392 -0
  116. package/src/main.ts +5 -0
  117. package/src/utils/lodash.ts +9 -0
  118. package/src/utils/types.ts +9 -0
  119. package/src/vite-env.d.ts +5 -0
  120. package/dist/EUISelect.vue.d.ts.map +0 -1
  121. package/dist/button/EUIButton.vue.d.ts.map +0 -1
  122. package/dist/library-vue-ts.css +0 -1
  123. package/dist/style.scss +0 -118
  124. /package/dist/{button/EUIButton.vue.d.ts → EUIButton.vue.d.ts} +0 -0
  125. /package/dist/{EUISelect.vue.d.ts → select/EUISelect.vue.d.ts} +0 -0
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <div>
3
+ <EUIStepperHorizontal stepStatus="opportunity" />
4
+ <hr />
5
+ <EUIStepperVertical stepStatus="opportunity" />
6
+ </div>
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ import EUIStepperHorizontal from './EUIStepperHorizontal.vue';
11
+ import EUIStepperVertical from './EUIStepperVertical.vue';
12
+ </script>
13
+
14
+ <style scoped>
15
+
16
+ </style>
@@ -0,0 +1,112 @@
1
+ <template>
2
+ <nav aria-label="Progress" class="relative z-10">
3
+ <ol role="list" class="flex flex-col items-start justify-center w-full py-4 ps-4 pe-2">
4
+ <li
5
+ v-for="(step, stepIdx) in lifeCycleEntries"
6
+ :key="step.value"
7
+ :class="[
8
+ stepIdx !== lifeCycleEntries.length - 1 ? 'pb-8' : '',
9
+ 'relative flex items-center w-full ps-5',
10
+ getStatus(step.key, stepIdx) === 'upcoming'
11
+ ? 'pointer-events-none'
12
+ : '',
13
+ ]"
14
+ >
15
+ <template v-if="getStatus(step.key, stepIdx) === 'complete'">
16
+ <div
17
+ v-if="stepIdx !== lifeCycleEntries.length - 1"
18
+ class="absolute bg-green-500 h-full start-px top-0 w-[0.0875rem] z-0"
19
+ />
20
+ <div class="absolute top-0 -start-2 flex items-center size-5 bg-green-500 rounded-full border-[1.5px] border-green-500" >
21
+ <svg fill="currentColor" width="16" height="16" viewBox="0 0 24 24" class="text-white size-4"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"><title>Check icon</title></path></svg>
22
+ </div>
23
+ <div class="flex items-start justify-between max-w-full w-full py-0.5">
24
+ <span class="text-xs font-semibold text-gray-900">{{ startCase(step.value) }}</span>
25
+ <span class="text-xs font-medium text-gray-500">{{'26-05-2024 18:47'}}</span>
26
+ </div>
27
+ </template>
28
+ <template v-else-if="getStatus(step.key, stepIdx) === 'current'">
29
+ <div
30
+ class="absolute bg-orange-500 h-full start-px top-0 w-[0.0875rem] z-0"
31
+ />
32
+ <div class="absolute -start-2 top-0 flex items-center justify-center size-5 rounded-full bg-white border-[1.5px] border-orange-500">
33
+ <div class="size-2.5 bg-orange-400 rounded-full" />
34
+ </div>
35
+ <div class="flex items-start justify-between max-w-full w-full py-0.5">
36
+ <span class="text-xs font-semibold text-gray-900">{{ startCase(step.value) }}</span>
37
+ <span class="text-xs font-medium text-gray-500">{{'26-05-2024 18:47'}}</span>
38
+ </div>
39
+ </template>
40
+ <template v-else-if="getStatus(step.key, stepIdx) === 'upcoming'">
41
+ <div
42
+ v-if="stepIdx !== lifeCycleEntries.length - 1"
43
+ class="absolute bg-gray-300 h-full start-px top-0 w-[0.0875rem] z-0"
44
+ />
45
+ <div class="absolute top-0 -start-2 flex items-center justify-center size-5 rounded-full bg-gray-100 border-gray-300 border-[1.5px]">
46
+ <div class="bg-gray-200 rounded-full size-3" />
47
+ </div>
48
+ <div class="flex items-start justify-between max-w-full w-full py-0.5">
49
+ <span class="text-xs font-semibold text-gray-900">{{ startCase(step.value) }}</span>
50
+ <span class="text-xs font-medium text-gray-500">{{'26-05-2024 18:47'}}</span>
51
+ </div>
52
+ </template>
53
+ </li>
54
+ </ol>
55
+ </nav>
56
+ </template>
57
+ <script setup lang="ts">
58
+ import { startCase } from 'lodash';
59
+ import { computed, PropType } from 'vue';
60
+
61
+ const props = defineProps({
62
+ stepStatus: {
63
+ type: String as PropType<"contact" | "MQL" | 'SQL' | 'opportunity' | 'Prospect' | 'Prospect Paid' | 'Prospect Enrolled' | 'Customer'>,
64
+ default: 'contact'
65
+ }
66
+ })
67
+
68
+ const stepStatusEnum = ["contact" , "MQL" , 'SQL' , 'opportunity' , 'Prospect' , 'Prospect Paid' , 'Prospect Enrolled' , 'Customer']
69
+
70
+ const lifeCycleEntries = computed(() => {
71
+ return Object.entries(stepStatusEnum).map((x) => {
72
+ return { key: x[0], value: x[1] }
73
+ })
74
+ })
75
+
76
+ const lifeCycleState = computed(() => {
77
+ return currentStatus.value
78
+ })
79
+
80
+ const currentStatus = computed(() => props.stepStatus)
81
+
82
+ const status = computed(() => lifeCycleState.value)
83
+
84
+ const lifeCycle = computed(() => {
85
+ return lifeCycleEntries.value.findIndex((e) => e.value === status.value)
86
+ })
87
+
88
+ const getStatus = computed(() => {
89
+ return (status: string, index: number) => {
90
+ if (
91
+ index &&
92
+ lifeCycle.value === lifeCycleEntries.value.length - 1
93
+ ) {
94
+ return 'complete'
95
+ }
96
+ if (index === lifeCycle.value) {
97
+ return 'current'
98
+ }
99
+ if (index < lifeCycle.value) {
100
+ return 'complete'
101
+ }
102
+ if (index > lifeCycle.value) {
103
+ return 'upcoming'
104
+ }
105
+ return {
106
+ status,
107
+ }
108
+ }
109
+ })
110
+ </script>
111
+ <style lang="scss">
112
+ </style>
@@ -0,0 +1,482 @@
1
+ <template>
2
+ <div>
3
+ <div class="relative w-full mx-auto overflow-hidden">
4
+ <div
5
+ id="dashboard-table"
6
+ class="overflow-auto max-h-[calc(100svh-13rem)] scrollbar--thin overscroll-none"
7
+ ref="tableContainer"
8
+ @scroll="handleScroll"
9
+ >
10
+ <table class="eui-table">
11
+ <thead class="sticky top-0 left-0 z-50 bg-gray-100">
12
+ <tr>
13
+ <template v-if="checkable">
14
+ <th class="checkable">
15
+ <EUITableCheckbox
16
+ :checked="isAllChecked"
17
+ :indeterminate="isIndeterminate"
18
+ :disabled="isAllUncheckable"
19
+ class="flex justify-center mt-0"
20
+ @change="checkAll()"
21
+ />
22
+ </th>
23
+ </template>
24
+ <th
25
+ v-for="(header, headerIndex) in headers"
26
+ :key="`item-${headerIndex}`"
27
+ scope="col"
28
+ :class="[
29
+ 'px-3 py-2 text-gray-600 snap-start snap-always',
30
+ isScrolled && headerIndex === 0 ? stickyClass.head : '',
31
+ { 'cursor-pointer hover:text-gray-900': header?.sortable },
32
+ ]"
33
+ :style="
34
+ header?.width
35
+ ? `min-width:${header.width}px;max-width:${header.width}px;`
36
+ : ``
37
+ "
38
+ @click="sortBy(header, $event)"
39
+ >
40
+ <div
41
+ class="flex items-center gap-2 text-sm font-normal text-current"
42
+ >
43
+ <slot name="header" :header="header">
44
+ {{ capitalizeText(header?.text ?? header.name ?? '') }}
45
+ </slot>
46
+ <slot name="headerOptionalItem"></slot>
47
+ <SortArrow
48
+ v-if="header?.sortable"
49
+ :class="[
50
+ 'transform duration-100 transition-all',
51
+ currentSort === header.value
52
+ ? 'text-violet-700'
53
+ : 'text-gray-900',
54
+ sortClass(header),
55
+ ]"
56
+ />
57
+ </div>
58
+ </th>
59
+ </tr>
60
+ </thead>
61
+ <tbody>
62
+ <template
63
+ v-for="(row, rowIndex) in computedItems"
64
+ :key="`table-row-${rowIndex}`"
65
+ >
66
+ <tr
67
+ @mouseenter="$attrs.mouseenter ? $emit('mouseenter', row, rowIndex) : null"
68
+ @mouseleave="$attrs.mouseleave ? $emit('mouseleave', row, rowIndex) : null"
69
+ >
70
+ <template v-if="checkable">
71
+ <td class="checkable">
72
+ <EUITableCheckbox
73
+ :disabled="!isRowCheckable(row)"
74
+ :checked="isRowChecked(row)"
75
+ @change.prevent.stop="($event) => checkRow(row, rowIndex, $event)"
76
+ />
77
+ </td>
78
+ </template>
79
+ <td
80
+ v-for="(header, headerIndex) in headers"
81
+ :key="headerIndex"
82
+ :class="[isScrolled && headerIndex === 0 ? stickyClass.body : '']"
83
+ >
84
+ <slot
85
+ :name="`item.${header.value}`"
86
+ :row="row"
87
+ :rowIndex="rowIndex"
88
+ >
89
+ {{ getValueByPath(row, header?.value) }}
90
+ </slot>
91
+ </td>
92
+ </tr>
93
+ <template v-if="tableExpanded">
94
+ <slot name="expanded" :row="row" :rowIndex="rowIndex"></slot>
95
+ </template>
96
+ </template>
97
+ </tbody>
98
+ <tbody v-if="computedItems.length === 0">
99
+ <tr>
100
+ <td :colspan="headers.length">
101
+ <div
102
+ class="flex items-center justify-center text-xl font-medium text-gray-500 min-h-96"
103
+ >
104
+ No matching records found
105
+ </div>
106
+ </td>
107
+ </tr>
108
+ </tbody>
109
+ </table>
110
+ </div>
111
+ <div
112
+ class="sticky bottom-0 left-0 z-50 flex items-center justify-between px-2 py-2 bg-gray-100"
113
+ >
114
+ <slot name="tableCount">
115
+ <div class="inline-flex items-center gap-x-10">
116
+ <div class="text-sm font-normal text-gray-900">
117
+ 1-{{ limit }} of {{ total }}
118
+ </div>
119
+ <div class="inline-flex items-center gap-2">
120
+ <span class="text-sm font-normal text-gray-900"
121
+ >Result per page</span
122
+ >
123
+ <EUIPageLimit
124
+ :page-limit="limit"
125
+ @update-limit="changeLimit($event)"
126
+ @refetch="searchData($event)"
127
+ />
128
+ </div>
129
+ </div>
130
+ </slot>
131
+ <template v-if="paginated && computedItems.length !== 0">
132
+ <slot name="tablepagination">
133
+ <EUIPagination
134
+ :activePage="newCurrentPage"
135
+ :pageLimit="limit"
136
+ :totalCount="total"
137
+ @change-page="pageChanged($event)"
138
+ />
139
+ </slot>
140
+ </template>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </template>
145
+
146
+ <script setup lang="ts">
147
+ import { computed, onMounted, onUnmounted, PropType, ref, toRefs, watch } from "vue";
148
+ import EUIPagination from "./EUIPagination.vue";
149
+ import EUITableCheckbox from "./EUITableCheckbox.vue";
150
+ import SortArrow from "../../assets/svg/SortArrow.vue";
151
+ import EUIPageLimit from "./EUIPageLimit.vue";
152
+ import { capitalizeText } from "../../utils/lodash";
153
+
154
+ interface Header {
155
+ value: string;
156
+ text?: string;
157
+ name?: string;
158
+ width?: number;
159
+ sortable?: boolean;
160
+ }
161
+
162
+ const props = defineProps({
163
+ checkable: {
164
+ type: Boolean,
165
+ default: false,
166
+ },
167
+ stickyColumn: { type: Boolean, default: true },
168
+ paginated: { type: Boolean, default: false },
169
+ tableExpanded: { type: Boolean, default: false },
170
+ backendPagination: { type: Boolean, default: false },
171
+ checkedRows: { type: Array, default: () => ({}), required: true },
172
+ headers: { type: Array as PropType<Header[]>, default: () => ({}), required: true },
173
+ items: { type: Array, required: true, default: () => ({}) },
174
+ defaultSort: { type: String, default: "" },
175
+ defaultSortDirection: { type: String, default: "asc" },
176
+ search: { type: String, default: "" },
177
+ perPage: { type: Number, default: 5 },
178
+ currentPage: { type: Number, default: 0 },
179
+ total: { type: Number, default: 0 },
180
+ customIsChecked: {
181
+ type: Function as PropType<(item: any, obj: any) => boolean>,
182
+ default: () => () => false,
183
+ },
184
+ isRowCheckable: { type: Function, default: () => true },
185
+ });
186
+ const {
187
+ defaultSort,
188
+ defaultSortDirection,
189
+ checkedRows,
190
+ currentPage,
191
+ items,
192
+ backendPagination,
193
+ total,
194
+ search,
195
+ headers,
196
+ paginated,
197
+ isRowCheckable,
198
+ customIsChecked,
199
+ } = toRefs(props);
200
+
201
+ const currentSort = ref(defaultSort.value);
202
+ const currentSortDir = ref(defaultSortDirection.value);
203
+ const newCheckedRows = ref([...checkedRows.value]);
204
+ const newCurrentPage = ref(currentPage.value);
205
+ const lastCheckedRowIndex = ref();
206
+
207
+ const limit = ref(props.perPage);
208
+
209
+ // Computed Property
210
+ const filteredItems = computed(() => {
211
+ let filteredItems = items.value.slice();
212
+ if (!backendPagination.value && search.value !== "") {
213
+ if (search.value.trim() === "") return filteredItems;
214
+ const props = headers.value.map((h) => h.value);
215
+ filteredItems = items.value.filter((item) =>
216
+ props.some((prop) =>
217
+ defaultFilter(
218
+ getValueByPath(item, prop),
219
+ search.value.toString().toLowerCase()
220
+ )
221
+ )
222
+ );
223
+ }
224
+ return filteredItems;
225
+ });
226
+
227
+ const computedItems = computed(() => {
228
+ let items = filteredItems.value;
229
+ // Sort items before slicing for pagination
230
+ items.sort((a:any, b:any) => {
231
+ const modifier = currentSortDir.value === "desc" ? -1 : 1;
232
+ if (a[currentSort.value] < b[currentSort.value]) return -1 * modifier;
233
+ if (a[currentSort.value] > b[currentSort.value]) return 1 * modifier;
234
+ return 0;
235
+ });
236
+ return items
237
+
238
+ // Apply pagination
239
+ // const start = (newCurrentPage.value - 0) * limit.value;
240
+ // const end = start + limit.value;
241
+ // return items.slice(start, end);
242
+ });
243
+
244
+ const searchData = (data: number) => {
245
+ console.log(data);
246
+ };
247
+
248
+ const sortClass = computed(() => (header: any) => {
249
+ return currentSortDir.value === "asc" && currentSort.value === header.value
250
+ ? "rotate-0"
251
+ : currentSortDir.value === "desc" && currentSort.value === header.value
252
+ ? "rotate-180"
253
+ : "";
254
+ });
255
+
256
+ const isIndeterminate = computed(() => {
257
+ const validVisibleData = computedItems.value.filter((row) =>
258
+ isRowCheckable.value(row)
259
+ );
260
+ return (
261
+ newCheckedRows.value.length > 0 &&
262
+ newCheckedRows.value.length < validVisibleData.length
263
+ );
264
+ });
265
+
266
+ const isAllChecked = computed(() => {
267
+ const validVisibleData = computedItems.value.filter((row) =>
268
+ isRowCheckable.value(row)
269
+ );
270
+ if (validVisibleData.length === 0) return false;
271
+ return validVisibleData.every(
272
+ (row) => indexOf(newCheckedRows.value, row, customIsChecked.value) >= 0
273
+ );
274
+ });
275
+
276
+ const isAllUncheckable = computed(() => {
277
+ const validVisibleData = computedItems.value?.filter((row) =>
278
+ isRowCheckable.value!(row)
279
+ );
280
+ return validVisibleData.length === 0;
281
+ });
282
+
283
+ // methods
284
+ const defaultFilter = (value:any, search:any) => {
285
+ return value.toString().toLowerCase().includes(search);
286
+ };
287
+
288
+ const indexOf = (
289
+ array: any[],
290
+ obj: any,
291
+ fn: (item: any, obj: any) => boolean
292
+ ): number => {
293
+ if (!array) return -1;
294
+ if (!fn || typeof fn !== "function") return array?.indexOf(obj);
295
+ for (let i = 0; i < array.length; i++) {
296
+ if (fn(array[i], obj)) {
297
+ return i;
298
+ }
299
+ }
300
+ return -1;
301
+ };
302
+
303
+ const getValueByPath = (obj: any, path: string) => {
304
+ return path
305
+ .split(".")
306
+ .reduce(
307
+ (o: { [x: string]: any }, i: string | number) => (o ? o[i] : null),
308
+ obj
309
+ );
310
+ };
311
+
312
+ const emit = defineEmits([
313
+ "update:currentPage",
314
+ "changePage",
315
+ "sort",
316
+ "check",
317
+ "check-all",
318
+ "update:checkedRows",
319
+ "changeLimit",
320
+ "mouseenter",
321
+ "mouseleave"
322
+ ]);
323
+
324
+ const changeLimit = (limitData: number) => {
325
+ limit.value = limitData;
326
+ newCurrentPage.value = 1;
327
+ emit("update:currentPage", newCurrentPage.value);
328
+ emit("changeLimit", limitData);
329
+ };
330
+
331
+ const pageChanged = (page: number) => {
332
+ newCurrentPage.value = page > 0 ? page : 0;
333
+ emit("update:currentPage", newCurrentPage.value);
334
+ emit("changePage", page);
335
+ };
336
+
337
+ const sortBy = (header: any, event: any) => {
338
+ if (!header || !header.sortable) return;
339
+ if (header.value === currentSort.value) {
340
+ currentSortDir.value = currentSortDir.value === "asc" ? "desc" : "asc";
341
+ }
342
+ currentSort.value = header.value;
343
+ emit("sort", currentSort.value, currentSortDir.value, event);
344
+ };
345
+
346
+ const checkAll = () => {
347
+ const allRowsCheckable = computedItems.value.filter((row) =>
348
+ isRowCheckable.value(row)
349
+ );
350
+ const allChecked = isAllChecked.value;
351
+ newCheckedRows.value = allChecked ? [] : allRowsCheckable.slice();
352
+ emit("check", newCheckedRows.value);
353
+ emit("check-all", newCheckedRows.value);
354
+ emit("update:checkedRows", newCheckedRows.value);
355
+ };
356
+
357
+ const removeCheckedRow = (row:any) => {
358
+ const index = indexOf(newCheckedRows.value, row, customIsChecked.value);
359
+ if (index >= 0) {
360
+ newCheckedRows.value.splice(index, 1);
361
+ }
362
+ };
363
+
364
+ const isRowChecked = (row:any) => {
365
+ return indexOf(newCheckedRows.value, row, customIsChecked.value) >= 0;
366
+ };
367
+
368
+ const checkRow = (row: any, rowIndex: number, event: Event) => {
369
+ if (!isRowCheckable.value(row)) return;
370
+ if(event) {
371
+ lastCheckedRowIndex.value = rowIndex;
372
+ if (!isRowChecked(row)) {
373
+ newCheckedRows.value.push(row);
374
+ } else {
375
+ removeCheckedRow(row);
376
+ }
377
+ emit("check", newCheckedRows.value, row);
378
+ emit("update:checkedRows", newCheckedRows.value);
379
+ }
380
+ };
381
+
382
+ // watch
383
+ watch(
384
+ () => currentPage.value,
385
+ (newVal) => {
386
+ newCurrentPage.value = newVal;
387
+ },
388
+ { immediate: true }
389
+ );
390
+
391
+ watch(
392
+ () => checkedRows.value,
393
+ (rows) => {
394
+ newCheckedRows.value = [...rows];
395
+ },
396
+ {
397
+ immediate: true,
398
+ }
399
+ );
400
+
401
+ // table scroll to add class
402
+ const stickyClass = computed(() => {
403
+ return props.checkable && props.stickyColumn
404
+ ? {
405
+ head: "bg-gray-100 sticky left-[4.5rem] top-0 z-20",
406
+ body: "bg-white sticky left-[4.5rem] top-0 z-10",
407
+ }
408
+ : {
409
+ head: "bg-gray-100 sticky left-0 top-0 z-20",
410
+ body: "bg-white sticky left-0 top-0 z-10",
411
+ };
412
+ });
413
+
414
+ const isOverflowing = ref(false);
415
+ const isScrolled = ref(false);
416
+ const tableContainer = ref<HTMLElement | null>(null);
417
+
418
+ const handleScroll = () => {
419
+ const container = tableContainer.value;
420
+ if (container) {
421
+ isScrolled.value = container.scrollLeft > 0;
422
+ }
423
+ };
424
+
425
+ const checkOverflow = () => {
426
+ const container = tableContainer.value;
427
+ if (container) {
428
+ isOverflowing.value = container.scrollWidth > container.clientWidth;
429
+ }
430
+ };
431
+
432
+ onMounted(() => {
433
+ window.addEventListener("resize", checkOverflow);
434
+ });
435
+
436
+ onUnmounted(() => {
437
+ window.removeEventListener("resize", checkOverflow);
438
+ });
439
+
440
+ // Watch for changes in the container's width to check for overflow
441
+ watch(() => tableContainer.value?.clientWidth, checkOverflow);
442
+ </script>
443
+
444
+ <style lang="scss" scoped>
445
+ #dashboard-table {
446
+ & .eui-table {
447
+ border-spacing: 0 0.5rem;
448
+ @apply min-w-full text-sm font-light text-left table table-auto w-full -mt-2 box-border border-separate relative;
449
+ thead tr {
450
+ @apply snap-x snap-mandatory;
451
+ th {
452
+ @apply snap-always snap-start;
453
+ &:first-of-type.checkable {
454
+ height: 45px;
455
+ @apply flex items-center justify-center px-4 max-w-[4.5rem] w-[4.5rem] sticky left-0 top-0 z-20 bg-gray-100;
456
+ }
457
+ }
458
+ }
459
+ tbody {
460
+ @apply snap-y snap-mandatory snap-always;
461
+ tr {
462
+ @apply text-gray-500 transition-all duration-150 rounded-xl bg-white snap-start ease-in-out snap-x snap-mandatory;
463
+ &:hover {
464
+ @apply shadow-[1px_2px_40px_0px_#03022912] ring-1 ring-gray-100 ring-inset z-30;
465
+ }
466
+ td {
467
+ @apply px-4 py-4 text-sm font-normal last-of-type:rounded-r-xl first-of-type:rounded-l-xl transition-transform duration-100 ease-in-out border-solid border border-l-0 border-r-0 border-white first:border-s last:border-e;
468
+ &:first-of-type.checkable {
469
+ @apply w-14 text-center sticky left-0 top-0 z-[11] bg-white;
470
+ }
471
+ }
472
+ &:hover td {
473
+ @apply font-medium text-gray-900 bg-white border-gray-100;
474
+ &:first-of-type.checkable {
475
+ @apply bg-white;
476
+ }
477
+ }
478
+ }
479
+ }
480
+ }
481
+ }
482
+ </style>
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <div>
3
+ <EUIPopover
4
+ trigger="click"
5
+ placement="top"
6
+ className="max-w-40 min-w-40"
7
+ customButton="px-3 py-2 text-sm font-medium text-gray-900 bg-white rounded-md group hover:text-opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 gap-x-1"
8
+ >
9
+ <template #referenceButton="{ open }">
10
+ <span class="whitespace-nowrap">{{ pageLimit }}</span>
11
+ <component :is="iconStyle ? ChevronDownSolid : ChevronDownStroke"
12
+ :class="open ? 'text-gray-900 rotate-180' : 'text-gray-500'"
13
+ class="transition duration-100 ease-in-out transform rotate-0 size-6 group-hover:text-opacity-80"
14
+ aria-hidden="true"
15
+ />
16
+ </template>
17
+ <!-- Popper Content Here... -->
18
+ <div
19
+ class="overflow-hidden bg-white rounded-lg shadow-lg ring-1 ring-black ring-opacity-5"
20
+ >
21
+ <ul>
22
+ <li
23
+ v-for="item in pageList"
24
+ :key="item"
25
+ class="block w-full px-4 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50"
26
+ :class="[
27
+ item === pageLimit
28
+ ? 'bg-purple-100 text-purple-600'
29
+ : 'text-gray-700'
30
+ ]"
31
+ role="button"
32
+ aria-roledescription="button"
33
+ @click="changePageLimit(item)"
34
+ >
35
+ {{ item }} per page
36
+ </li>
37
+ </ul>
38
+ </div>
39
+ </EUIPopover>
40
+ </div>
41
+ </template>
42
+
43
+ <script lang="ts" setup>
44
+ import { PropType, ref, toRefs } from 'vue';
45
+ import ChevronDownSolid from '../../assets/svg/ChevronDownSolid.vue';
46
+ import ChevronDownStroke from '../../assets/svg/ChevronDownStroke.vue';
47
+ import EUIPopover from '../popover/EUIPopover.vue';
48
+
49
+ const props = defineProps({
50
+ pageLimit: {
51
+ type: Number as PropType<number>,
52
+ default: 5
53
+ },
54
+ iconStyle: {
55
+ type: Boolean,
56
+ default: false,
57
+ },
58
+ })
59
+ const { pageLimit } = toRefs(props)
60
+ const emit = defineEmits(['updateLimit', 'refetch'])
61
+ const pageList = ref([5, 10, 20, 30, 40, 50, 100])
62
+ const changePageLimit = (data: any) => {
63
+ emit('updateLimit', data)
64
+ emit('refetch')
65
+ }
66
+ </script>