edvoyui-component-library-test-flight 0.0.95 → 0.0.96

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 (103) hide show
  1. package/dist/EUISelectSearch.vue.d.ts +4 -0
  2. package/dist/EUISelectSearch.vue.d.ts.map +1 -0
  3. package/dist/accordion/EUIAccordion.vue.d.ts +2 -2
  4. package/dist/accordion/EUIAccordion.vue.d.ts.map +1 -1
  5. package/dist/avatar/EUIAvatar.vue.d.ts +2 -2
  6. package/dist/avatar/EUIAvatar.vue.d.ts.map +1 -1
  7. package/dist/button/EUIButton.vue.d.ts +5 -0
  8. package/dist/button/EUIButton.vue.d.ts.map +1 -0
  9. package/dist/checkbox/EUICheckbox.vue.d.ts +3 -3
  10. package/dist/checkbox/EUICheckbox.vue.d.ts.map +1 -1
  11. package/dist/datepicker/EUIDatepicker.vue.d.ts +3 -3
  12. package/dist/datepicker/EUIDatepicker.vue.d.ts.map +1 -1
  13. package/dist/dropdown/EUIMultiDropdown.vue.d.ts +2 -2
  14. package/dist/dropdown/EUIMultiDropdown.vue.d.ts.map +1 -1
  15. package/dist/errorMessage/EUIErrorMessage.vue.d.ts +2 -2
  16. package/dist/errorMessage/EUIErrorMessage.vue.d.ts.map +1 -1
  17. package/dist/input/EUIInput.vue.d.ts +2 -2
  18. package/dist/input/EUIInput.vue.d.ts.map +1 -1
  19. package/dist/library-vue-ts.cjs.js +23 -69
  20. package/dist/library-vue-ts.css +1 -1
  21. package/dist/library-vue-ts.es.js +10498 -13689
  22. package/dist/library-vue-ts.umd.js +23 -69
  23. package/dist/loader/EUICircleLoader.vue.d.ts +1 -1
  24. package/dist/loader/EUICircleLoader.vue.d.ts.map +1 -1
  25. package/dist/loader/EUICubeLoader.vue.d.ts +1 -1
  26. package/dist/loader/EUICubeLoader.vue.d.ts.map +1 -1
  27. package/dist/loader/EUILoader.vue.d.ts +2 -2
  28. package/dist/loader/EUILoader.vue.d.ts.map +1 -1
  29. package/dist/loader/EUISquareLoader.vue.d.ts +1 -1
  30. package/dist/loader/EUISquareLoader.vue.d.ts.map +1 -1
  31. package/dist/modal/EUIModal.vue.d.ts +2 -2
  32. package/dist/modal/EUIModal.vue.d.ts.map +1 -1
  33. package/dist/pillSelect/EUIPillSelect.vue.d.ts +2 -2
  34. package/dist/pillSelect/EUIPillSelect.vue.d.ts.map +1 -1
  35. package/dist/popover/EUIPopover.vue.d.ts +2 -2
  36. package/dist/popover/EUIPopover.vue.d.ts.map +1 -1
  37. package/dist/radio/EUIRadio.vue.d.ts +2 -2
  38. package/dist/radio/EUIRadio.vue.d.ts.map +1 -1
  39. package/dist/searchInput/EUISearch.vue.d.ts +2 -2
  40. package/dist/searchInput/EUISearch.vue.d.ts.map +1 -1
  41. package/dist/searchexpand/EUISearchExpand.vue.d.ts +2 -2
  42. package/dist/searchexpand/EUISearchExpand.vue.d.ts.map +1 -1
  43. package/dist/searchexpand/EUISearchToggle.vue.d.ts +2 -2
  44. package/dist/searchexpand/EUISearchToggle.vue.d.ts.map +1 -1
  45. package/dist/select/EUISelect.vue.d.ts +3 -3
  46. package/dist/select/EUISelect.vue.d.ts.map +1 -1
  47. package/dist/slideover/EUISlideover.vue.d.ts +2 -2
  48. package/dist/slideover/EUISlideover.vue.d.ts.map +1 -1
  49. package/dist/stepperTimeline/EUIStepperHorizontal.vue.d.ts +2 -2
  50. package/dist/stepperTimeline/EUIStepperHorizontal.vue.d.ts.map +1 -1
  51. package/dist/stepperTimeline/EUIStepperTimeline.vue.d.ts +2 -2
  52. package/dist/stepperTimeline/EUIStepperTimeline.vue.d.ts.map +1 -1
  53. package/dist/stepperTimeline/EUIStepperVertical.vue.d.ts +2 -2
  54. package/dist/stepperTimeline/EUIStepperVertical.vue.d.ts.map +1 -1
  55. package/dist/table/EUIDashboardTable.vue.d.ts +2 -2
  56. package/dist/table/EUIDashboardTable.vue.d.ts.map +1 -1
  57. package/dist/table/EUIPageLimit.vue.d.ts +2 -2
  58. package/dist/table/EUIPageLimit.vue.d.ts.map +1 -1
  59. package/dist/table/EUIPagination.vue.d.ts +2 -2
  60. package/dist/table/EUIPagination.vue.d.ts.map +1 -1
  61. package/dist/table/EUIStudentPagination.vue.d.ts +2 -2
  62. package/dist/table/EUIStudentPagination.vue.d.ts.map +1 -1
  63. package/dist/table/EUITable.vue.d.ts +2 -2
  64. package/dist/table/EUITable.vue.d.ts.map +1 -1
  65. package/dist/table/EUITableCheckbox.vue.d.ts +3 -3
  66. package/dist/table/EUITableCheckbox.vue.d.ts.map +1 -1
  67. package/dist/table/GrowthTable.vue.d.ts +5 -0
  68. package/dist/table/GrowthTable.vue.d.ts.map +1 -0
  69. package/dist/table/UCheckbox.vue.d.ts +2 -2
  70. package/dist/table/UCheckbox.vue.d.ts.map +1 -1
  71. package/dist/table/UTable.vue.d.ts +2 -2
  72. package/dist/table/UTable.vue.d.ts.map +1 -1
  73. package/dist/tabs/EUITabs.vue.d.ts +2 -2
  74. package/dist/tabs/EUITabs.vue.d.ts.map +1 -1
  75. package/dist/tag/EUITag.vue.d.ts +2 -2
  76. package/dist/tag/EUITag.vue.d.ts.map +1 -1
  77. package/dist/telephone/EUITelephone.vue.d.ts +3 -3
  78. package/dist/telephone/EUITelephone.vue.d.ts.map +1 -1
  79. package/dist/textArea/EUITextArea.vue.d.ts +2 -2
  80. package/dist/textArea/EUITextArea.vue.d.ts.map +1 -1
  81. package/dist/timeLine/EUITimeLine.vue.d.ts +2 -2
  82. package/dist/timeLine/EUITimeLine.vue.d.ts.map +1 -1
  83. package/dist/timeLine/EUITimeLineItem.vue.d.ts +2 -2
  84. package/dist/timeLine/EUITimeLineItem.vue.d.ts.map +1 -1
  85. package/dist/toggle/EUIToggle.vue.d.ts +2 -2
  86. package/dist/toggle/EUIToggle.vue.d.ts.map +1 -1
  87. package/dist/tooltip/EUITooltip.vue.d.ts +2 -2
  88. package/dist/tooltip/EUITooltip.vue.d.ts.map +1 -1
  89. package/package.json +1 -1
  90. package/src/components/HelloWorld.vue +0 -16
  91. package/src/components/accordion/EUIAccordion.vue +1 -0
  92. package/src/components/index.ts +1 -0
  93. package/src/components/input/EUIInput.vue +2 -3
  94. package/src/components/searchexpand/EUISearchExpand.vue +8 -47
  95. package/src/components/table/GrowthTable.vue +563 -0
  96. package/src/components/table/GrowthTableView.vue +108 -0
  97. package/src/data/table.ts +256 -0
  98. package/dist/EUIButton.vue.d.ts +0 -5
  99. package/dist/EUIButton.vue.d.ts.map +0 -1
  100. package/dist/selectSearch/EUISelectSearch.vue.d.ts +0 -4
  101. package/dist/selectSearch/EUISelectSearch.vue.d.ts.map +0 -1
  102. /package/src/components/checkbox/{EUIcheckbox.stories.ts → EUICheckbox.stories.ts} +0 -0
  103. /package/src/components/modal/{EUImodal.stories.ts → EUIModal.stories.ts} +0 -0
@@ -1,4 +1,5 @@
1
1
  <template>
2
+
2
3
  <div class="relative rounded-full size-10">
3
4
  <div class="absolute top-0 right-0">
4
5
  <div
@@ -18,37 +19,11 @@
18
19
  <SearchBigZoomIn
19
20
  class="absolute text-current size-6 top-2 left-2"
20
21
  />
21
-
22
- <button
23
- v-if="isExpanded"
24
- :class="
25
- inputValue ? ' absolute inset-y-0 right-3 ' : ' hidden '
26
- "
27
- @click="(searchQuery=''), emit('update:modelValue', '')"
28
- >
29
- <svg
30
- xmlns="http://www.w3.org/2000/svg"
31
- fill="none"
32
- viewBox="0 0 24 24"
33
- stroke-width="1.5"
34
- stroke="currentColor"
35
- class="size-5"
36
- >
37
- <!-- <path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
38
- -->
39
- <path
40
- stroke-linecap="round"
41
- stroke-linejoin="round"
42
- d="M6 18 18 6M6 6l12 12"
43
- />
44
- </svg>
45
- </button>
46
-
47
22
  <input
48
23
  v-if="isExpanded"
49
24
  v-model="searchQuery"
50
25
  ref="input"
51
- :type="type === 'search' ? 'text' : type"
26
+ type="search"
52
27
  placeholder="Search here..."
53
28
  class="h-10 text-sm font-medium text-gray-900 bg-transparent w-80 ps-10 pe-2 focus:outline-none"
54
29
  autocomplete="off"
@@ -63,7 +38,7 @@
63
38
  </template>
64
39
 
65
40
  <script lang="ts" setup>
66
- import { computed, onBeforeUnmount, onMounted, PropType, ref, toRefs, watch } from "vue";
41
+ import { onBeforeUnmount, onMounted, ref, toRefs, watch } from "vue";
67
42
  import SearchBigZoomIn from "../../assets/svg/SearchBigZoomIn.vue";
68
43
 
69
44
  const props = defineProps({
@@ -75,12 +50,6 @@ const props = defineProps({
75
50
  type: Boolean,
76
51
  default: false,
77
52
  },
78
- type: {
79
- type: String as PropType<
80
- "text" | "number" | "email" | "password" | "search"
81
- >,
82
- default: "text",
83
- },
84
53
  });
85
54
  const { searchSync } = toRefs(props);
86
55
  const emit = defineEmits(["update:modelValue"]);
@@ -95,10 +64,6 @@ function expandInput() {
95
64
  input?.value?.focus();
96
65
  }
97
66
 
98
- const inputValue = computed(() => {
99
- return props.modelValue === 0 ? true : !!props.modelValue;
100
- });
101
-
102
67
  function closeInput() {
103
68
  if (!searchQuery.value) {
104
69
  isExpanded.value = false;
@@ -114,15 +79,11 @@ function handleOutsideClick(event: MouseEvent) {
114
79
  }
115
80
  }
116
81
 
117
- watch(
118
- searchSync,
119
- (newVal) => {
120
- if (!newVal) {
121
- closeInput();
122
- }
123
- },
124
- { immediate: true, deep: true }
125
- );
82
+ watch(searchSync, (newVal) => {
83
+ if (!newVal) {
84
+ closeInput();
85
+ }
86
+ }, {immediate: true, deep:true});
126
87
 
127
88
  onMounted(() => {
128
89
  document.addEventListener("click", handleOutsideClick);
@@ -0,0 +1,563 @@
1
+ <template>
2
+ <div>
3
+ <Transition name="fade" mode="out-in">
4
+ <div
5
+ v-if="loading"
6
+ :class="[
7
+ 'overflow-hidden relative z-0 isolate bg-white backdrop-blur transition-colors duration-150 ease-in-out rounded-xl border border-gray-50',
8
+ tableHeight
9
+ ? tableHeight
10
+ : 'h-[calc(100svh-9rem)] max-h-[calc(100svh-9rem)]',
11
+ ]"
12
+ >
13
+ <div
14
+ class="absolute flex items-center z-[calc(infinity)] w-full h-auto pointer-events-none inset-0"
15
+ >
16
+ <EUICircleLoader />
17
+ </div>
18
+ </div>
19
+ <div v-else class="relative w-full mx-auto overflow-hidden">
20
+ <div
21
+ id="growth-table"
22
+ :class="[
23
+ 'scrollbar--thin overscroll-none',
24
+ computedItems.length === 0 ? 'overflow-hidden' : 'overflow-auto',
25
+ tableHeight
26
+ ? tableHeight
27
+ : 'h-[calc(100svh-13rem)] max-h-[calc(100svh-13rem)]',
28
+ ]"
29
+ ref="tableContainer"
30
+ @scroll="handleScroll"
31
+ >
32
+ <table>
33
+ <thead class="sticky top-0 left-0 z-50 bg-violet-100">
34
+ <tr>
35
+ <th v-if="checkable" class="checkable !table-cell">
36
+ <EUITableCheckbox
37
+ :checked="isAllChecked"
38
+ :indeterminate="isIndeterminate"
39
+ :disabled="isAllUncheckable"
40
+ @change="checkAll()"
41
+ />
42
+ </th>
43
+ <th
44
+ v-for="(header, headerIndex) in headers"
45
+ :key="`item-${headerIndex}`"
46
+ scope="col"
47
+ :class="[
48
+ 'px-3 py-1.5 text-gray-600 snap-start snap-always',
49
+ isScrolled && headerIndex === 0 ? stickyClass.head : '',
50
+ { 'cursor-pointer hover:text-gray-900': header?.sortable },
51
+ ]"
52
+ :style="
53
+ header?.width
54
+ ? `min-width:${header.width}px;max-width:${header.width}px;`
55
+ : ``
56
+ "
57
+ @click="sortBy(header, $event)"
58
+ >
59
+ <div
60
+ class="flex items-center gap-2 text-xs font-semibold text-current"
61
+ >
62
+ <slot name="header" :header="header">
63
+ <template v-if="!header?.activeYear">{{
64
+ capitalizeText(header?.text ?? header.name ?? "")
65
+ }}</template>
66
+ <div
67
+ v-else
68
+ class="bg-violet-600 text-white rounded-[0.625rem] px-3 py-2"
69
+ >
70
+ <div class="mb-2">
71
+ {{
72
+ capitalizeText(header?.text ?? header.name ?? "")
73
+ }}
74
+ </div>
75
+ <div class="space-x-3">
76
+ <span
77
+ v-for="(data, idx) in header?.activeYear"
78
+ :key="`year_${idx}`"
79
+ >{{ data }}</span
80
+ >
81
+ </div>
82
+ </div>
83
+ </slot>
84
+ <slot name="headerOptionalItem"></slot>
85
+ <SortArrow
86
+ v-if="header?.sortable"
87
+ :class="[
88
+ 'transform duration-100 transition-all',
89
+ currentSort === header.value
90
+ ? 'text-violet-700'
91
+ : 'text-gray-900',
92
+ sortClass(header),
93
+ ]"
94
+ />
95
+ </div>
96
+ </th>
97
+ </tr>
98
+ </thead>
99
+ <tbody>
100
+ <template
101
+ v-if="computedItems.length > 0"
102
+ v-for="(row, rowIndex) in computedItems"
103
+ :key="`table-row-${rowIndex}`"
104
+ >
105
+ <tr
106
+ @mouseenter="
107
+ $attrs.mouseenter
108
+ ? $emit('mouseenter', row, rowIndex)
109
+ : null
110
+ "
111
+ @mouseleave="
112
+ $attrs.mouseleave
113
+ ? $emit('mouseleave', row, rowIndex)
114
+ : null
115
+ "
116
+ >
117
+ <template v-if="checkable">
118
+ <td class="checkable">
119
+ <EUITableCheckbox
120
+ :disabled="!isRowCheckable(row)"
121
+ :checked="isRowChecked(row)"
122
+ @change="($event:boolean) => checkRow(row, rowIndex, $event)"
123
+ />
124
+ </td>
125
+ </template>
126
+ <td
127
+ v-for="(header, headerIndex) in headers"
128
+ :key="headerIndex"
129
+ :class="[
130
+ isScrolled && headerIndex === 0 ? stickyClass.body : '',
131
+ ]"
132
+ >
133
+ <slot
134
+ :name="`item.${header.value}`"
135
+ :row="row"
136
+ :rowIndex="rowIndex"
137
+ >
138
+ {{ getValueByPath(row, header?.value) }}
139
+ </slot>
140
+ </td>
141
+ </tr>
142
+ <template v-if="tableExpanded">
143
+ <slot name="expanded" :row="row" :rowIndex="rowIndex"></slot>
144
+ </template>
145
+ </template>
146
+ <template v-else-if="computedItems.length === 0">
147
+ <tr class="norecords">
148
+ <td
149
+ :colspan="
150
+ checkable === true ? headers.length + 1 : headers.length
151
+ "
152
+ >
153
+ <div
154
+ class="flex items-center justify-center text-xl font-medium text-gray-500 h-[calc(100svh-18rem)] max-w-screen-xl"
155
+ >
156
+ No matching records found
157
+ </div>
158
+ </td>
159
+ </tr>
160
+ </template>
161
+ </tbody>
162
+ <tfoot v-if="footers.length" class="sticky bottom-0 left-0 z-50 bg-[#FEF3C7]">
163
+ <template
164
+ v-if="footers.length > 0"
165
+ v-for="(row, rowIndex) in footers"
166
+ :key="`table-row-${rowIndex}`"
167
+ >
168
+ <tr>
169
+ <th v-if="checkable" class="empty"></th>
170
+ <th
171
+ v-for="(header, headerIndex) in headers"
172
+ :key="headerIndex"
173
+ :class="['px-3 py-1.5 text-gray-900 snap-start snap-always h-14',
174
+ isScrolled && headerIndex === 0 ? stickyClass.foot : '',
175
+ ]"
176
+ >
177
+ <slot
178
+ :name="`footer.${header.value}`"
179
+ :row="row"
180
+ :rowIndex="rowIndex"
181
+ >
182
+ {{ getValueByPath(row, header?.value) }}
183
+ </slot>
184
+ </th>
185
+ </tr>
186
+ </template>
187
+
188
+ </tfoot>
189
+ </table>
190
+ </div>
191
+ <div
192
+ v-if="paginated && computedItems.length !== 0"
193
+ class="sticky bottom-0 left-0 z-50 flex items-center justify-between px-2 py-2 bg-gray-100"
194
+ >
195
+ <slot name="tableCount">
196
+ <div class="inline-flex items-center gap-x-10">
197
+ <div class="text-sm font-normal text-gray-900">
198
+ 1-{{ limit }} of {{ total }}
199
+ </div>
200
+ <div class="inline-flex items-center gap-2">
201
+ <span class="text-sm font-normal text-gray-900"
202
+ >Result per page</span
203
+ >
204
+ <EUIPageLimit
205
+ :page-limit="limit"
206
+ @update-limit="changeLimit($event)"
207
+ @refetch="searchData($event)"
208
+ />
209
+ </div>
210
+ </div>
211
+ </slot>
212
+ <template v-if="paginated && computedItems.length !== 0">
213
+ <slot name="tablepagination">
214
+ <EUIPagination
215
+ :activePage="newCurrentPage"
216
+ :pageLimit="limit"
217
+ :totalCount="total"
218
+ @change-page="pageChanged($event)"
219
+ />
220
+ </slot>
221
+ </template>
222
+ </div>
223
+ </div>
224
+ </Transition>
225
+ </div>
226
+ </template>
227
+
228
+ <script setup lang="ts">
229
+ import {
230
+ computed,
231
+ onMounted,
232
+ onUnmounted,
233
+ PropType,
234
+ ref,
235
+ toRefs,
236
+ watch,
237
+ } from "vue";
238
+ import EUIPagination from "./EUIPagination.vue";
239
+ import EUITableCheckbox from "./EUITableCheckbox.vue";
240
+ import SortArrow from "../../assets/svg/SortArrow.vue";
241
+ import EUIPageLimit from "./EUIPageLimit.vue";
242
+ import { capitalizeText } from "../../utils/lodash";
243
+ import EUICircleLoader from "../loader/EUICircleLoader.vue";
244
+ import { indexOf, getValueByPath, defaultFilter } from "../../utils/helpers";
245
+
246
+ interface Header {
247
+ value: string;
248
+ text?: string;
249
+ name?: string;
250
+ width?: number;
251
+ sortable?: boolean;
252
+ activeYear?: string[];
253
+ }
254
+
255
+ const props = defineProps({
256
+ checkable: {
257
+ type: Boolean,
258
+ default: false,
259
+ },
260
+ stickyColumn: { type: Boolean, default: true },
261
+ paginated: { type: Boolean, default: false },
262
+ tableExpanded: { type: Boolean, default: false },
263
+ backendPagination: { type: Boolean, default: false },
264
+ checkedRows: { type: Array, default: () => ({}), required: true },
265
+ headers: {
266
+ type: Array as PropType<Header[]>,
267
+ default: () => ({}),
268
+ required: true,
269
+ },
270
+ items: { type: Array, required: true, default: () => ({}) },
271
+ footers: { type: Array, default: () => ({}) },
272
+ defaultSort: { type: String, default: "" },
273
+ defaultSortDirection: { type: String, default: "asc" },
274
+ search: { type: String, default: "" },
275
+ perPage: { type: Number, default: 5 },
276
+ currentPage: { type: Number, default: 0 },
277
+ total: { type: Number, default: 0 },
278
+ customIsChecked: {
279
+ type: Function as PropType<(item: any, obj: any) => boolean>,
280
+ default: () => () => false,
281
+ },
282
+ isRowCheckable: { type: Function, default: () => true },
283
+ tableHeight: {
284
+ type: String,
285
+ required: false,
286
+ default: "",
287
+ },
288
+ tableLoading: { type: Boolean, default: false },
289
+ });
290
+ const {
291
+ defaultSort,
292
+ defaultSortDirection,
293
+ checkedRows,
294
+ currentPage,
295
+ items,
296
+ backendPagination,
297
+ total,
298
+ search,
299
+ headers,
300
+ paginated,
301
+ isRowCheckable,
302
+ } = toRefs(props);
303
+
304
+ const currentSort = ref(defaultSort.value);
305
+ const currentSortDir = ref(defaultSortDirection.value);
306
+ const newCheckedRows = ref([...checkedRows.value]);
307
+ const newCurrentPage = ref(currentPage.value);
308
+ const limit = ref(props.perPage);
309
+ const loading = computed(() => props.tableLoading);
310
+
311
+ // Computed Property
312
+ const filteredItems = computed(() => {
313
+ let filteredItems = items.value.slice();
314
+ if (!backendPagination.value && search.value !== "") {
315
+ if (search.value.trim() === "") return filteredItems;
316
+ const props = headers.value.map((h) => h.value);
317
+ filteredItems = items.value.filter((item) =>
318
+ props.some((prop) =>
319
+ defaultFilter(
320
+ getValueByPath(item, prop),
321
+ search.value.toString().toLowerCase()
322
+ )
323
+ )
324
+ );
325
+ }
326
+ return filteredItems;
327
+ });
328
+
329
+ const computedItems = computed(() => {
330
+ let items = filteredItems.value;
331
+ // Sort items before slicing for pagination
332
+ items.sort((a: any, b: any) => {
333
+ const modifier = currentSortDir.value === "desc" ? -1 : 1;
334
+ if (a[currentSort.value] < b[currentSort.value]) return -1 * modifier;
335
+ if (a[currentSort.value] > b[currentSort.value]) return 1 * modifier;
336
+ return 0;
337
+ });
338
+ return items;
339
+ });
340
+
341
+ const searchData = (_data: any) => {
342
+ // console.log(_data);
343
+ };
344
+
345
+ const sortClass = computed(() => (header: any) => {
346
+ return currentSortDir.value === "asc" && currentSort.value === header.value
347
+ ? "rotate-0"
348
+ : currentSortDir.value === "desc" && currentSort.value === header.value
349
+ ? "rotate-180"
350
+ : "";
351
+ });
352
+
353
+ const isIndeterminate = computed(() => {
354
+ const validVisibleData = computedItems.value.filter((row) =>
355
+ isRowCheckable.value(row)
356
+ );
357
+ return (
358
+ newCheckedRows.value.length > 0 &&
359
+ newCheckedRows.value.length < validVisibleData.length
360
+ );
361
+ });
362
+
363
+ const isAllChecked = computed(() => {
364
+ return (
365
+ computedItems.value.length > 0 &&
366
+ computedItems.value.every((row) => newCheckedRows.value.includes(row))
367
+ );
368
+ });
369
+
370
+ const isAllUncheckable = computed(() => {
371
+ const validVisibleData = computedItems.value?.filter((row) =>
372
+ isRowCheckable.value!(row)
373
+ );
374
+ return validVisibleData.length === 0;
375
+ });
376
+
377
+ const emit = defineEmits([
378
+ "update:currentPage",
379
+ "changePage",
380
+ "sort",
381
+ "check",
382
+ "check-all",
383
+ "update:checkedRows",
384
+ "update:selectedRows",
385
+ "changeLimit",
386
+ "mouseenter",
387
+ "mouseleave",
388
+ ]);
389
+
390
+ const changeLimit = (limitData: number) => {
391
+ limit.value = limitData;
392
+ newCurrentPage.value = 1;
393
+ emit("update:currentPage", newCurrentPage.value);
394
+ emit("changeLimit", limitData);
395
+ };
396
+
397
+ const pageChanged = (page: number) => {
398
+ newCurrentPage.value = page > 0 ? page : 0;
399
+ emit("update:currentPage", newCurrentPage.value);
400
+ emit("changePage", page);
401
+ };
402
+
403
+ const sortBy = (header: any, event: any) => {
404
+ if (!header || !header.sortable) return;
405
+ if (header.value === currentSort.value) {
406
+ currentSortDir.value = currentSortDir.value === "asc" ? "desc" : "asc";
407
+ }
408
+ currentSort.value = header.value;
409
+ emit("sort", currentSort.value, currentSortDir.value, event);
410
+ };
411
+
412
+ const isRowChecked = (row: any) => {
413
+ return indexOf(newCheckedRows.value, row) >= 0;
414
+ };
415
+
416
+ const removeCheckedRow = (row: any) => {
417
+ const index = indexOf(newCheckedRows.value, row);
418
+ if (index >= 0) {
419
+ newCheckedRows.value.splice(index, 1);
420
+ }
421
+ };
422
+
423
+ const checkAll = () => {
424
+ if (isAllChecked.value) {
425
+ // Uncheck all rows
426
+ newCheckedRows.value = [];
427
+ } else {
428
+ // Check all rows
429
+ const rowsToCheck = computedItems.value.filter(
430
+ (row) => !newCheckedRows.value.includes(row)
431
+ );
432
+ newCheckedRows.value.push(...rowsToCheck);
433
+ }
434
+ emit("check", newCheckedRows.value);
435
+ emit("check-all", newCheckedRows.value);
436
+ emit("update:checkedRows", newCheckedRows.value);
437
+ emit("update:selectedRows", newCheckedRows.value);
438
+ };
439
+
440
+ const checkRow = (row: any, _rowIndex: number, _event: any) => {
441
+ const isChecked = newCheckedRows.value.includes(row);
442
+ if (_event && isChecked) {
443
+ removeCheckedRow(row);
444
+ } else {
445
+ newCheckedRows.value.push(row);
446
+ }
447
+ emit("check", newCheckedRows.value, row);
448
+ emit("update:checkedRows", newCheckedRows.value);
449
+ emit("update:selectedRows", newCheckedRows.value);
450
+ };
451
+
452
+ // watch
453
+ watch(
454
+ () => currentPage.value,
455
+ (newVal) => {
456
+ newCurrentPage.value = newVal;
457
+ },
458
+ { immediate: true }
459
+ );
460
+
461
+ watch(
462
+ () => checkedRows.value,
463
+ (rows) => {
464
+ newCheckedRows.value = [...rows];
465
+ },
466
+ {
467
+ immediate: true,
468
+ }
469
+ );
470
+
471
+ // table scroll to add class
472
+ const stickyClass = computed(() => {
473
+ return props.checkable && props.stickyColumn
474
+ ? {
475
+ head: "bg-violet-100 sticky left-[4.5rem] top-0 z-20",
476
+ foot: "bg-[#FEF3C7] sticky left-[4.5rem] top-0 z-20",
477
+ body: "bg-white sticky left-[4.5rem] top-0 z-10",
478
+ }
479
+ : {
480
+ head: "bg-violet-100 sticky left-0 top-0 z-20",
481
+ foot: "bg-[#FEF3C7] sticky left-0 top-0 z-20",
482
+ body: "bg-white sticky left-0 top-0 z-10",
483
+ };
484
+ });
485
+
486
+ const isOverflowing = ref(false);
487
+ const isScrolled = ref(false);
488
+ const tableContainer = ref<HTMLElement | null>(null);
489
+
490
+ const handleScroll = () => {
491
+ const container = tableContainer.value;
492
+ if (container) {
493
+ isScrolled.value = container.scrollLeft > 0;
494
+ }
495
+ };
496
+
497
+ const checkOverflow = () => {
498
+ const container = tableContainer.value;
499
+ if (container) {
500
+ isOverflowing.value = container.scrollWidth > container.clientWidth;
501
+ }
502
+ };
503
+
504
+ onMounted(() => {
505
+ window.addEventListener("resize", checkOverflow);
506
+ });
507
+
508
+ onUnmounted(() => {
509
+ window.removeEventListener("resize", checkOverflow);
510
+ });
511
+
512
+ // Watch for changes in the container's width to check for overflow
513
+ watch(() => tableContainer.value?.clientWidth, checkOverflow);
514
+ </script>
515
+
516
+ <style lang="scss" scoped>
517
+ #growth-table {
518
+ & table {
519
+ // border-spacing: 0 0.5rem;
520
+ @apply min-w-full text-sm font-light text-left table table-auto w-full -mt-2 box-border border-separate border-spacing-y-2 relative;
521
+ thead tr {
522
+ @apply snap-x snap-mandatory;
523
+ th {
524
+ @apply snap-always snap-start last-of-type:rounded-r-xl first-of-type:rounded-l-xl;
525
+ &:first-of-type.checkable {
526
+ min-height: 45px;
527
+ @apply flex items-center justify-center px-4 max-w-[4.5rem] w-[4.5rem] sticky left-0 top-0 z-20 bg-violet-100;
528
+ }
529
+ }
530
+ }
531
+ tbody {
532
+ @apply snap-y snap-mandatory snap-always;
533
+ tr:not(.norecords) {
534
+ @apply text-gray-500 transition-all duration-150 rounded-xl bg-white snap-start ease-in-out snap-x snap-mandatory;
535
+ &:hover {
536
+ @apply shadow-[1px_2px_40px_0px_#03022912] ring-1 ring-gray-100 ring-inset z-30;
537
+ }
538
+ td {
539
+ @apply px-3 py-1.5 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 h-14;
540
+ &:first-of-type.checkable {
541
+ @apply w-14 text-center sticky left-0 top-0 z-[11] bg-white;
542
+ }
543
+ }
544
+ &:hover td {
545
+ @apply font-medium text-gray-900 bg-white border-gray-100;
546
+ &:first-of-type.checkable {
547
+ @apply bg-white;
548
+ }
549
+ }
550
+ }
551
+ }
552
+ tfoot tr {
553
+ @apply snap-x snap-mandatory;
554
+ th {
555
+ @apply snap-always snap-start last-of-type:rounded-r-xl first-of-type:rounded-l-xl;
556
+ &:first-of-type.empty {
557
+ @apply table-cell min-h-10 px-2 max-w-[45px] w-[45px] sticky left-0 top-0 z-20 bg-[#FEF3C7];
558
+ }
559
+ }
560
+ }
561
+ }
562
+ }
563
+ </style>