sprintify-ui 0.0.0

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 (176) hide show
  1. package/README.md +188 -0
  2. package/dist/types/src/components/BaseAlert.vue.d.ts +51 -0
  3. package/dist/types/src/components/BaseAutocomplete.vue.d.ts +268 -0
  4. package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +273 -0
  5. package/dist/types/src/components/BaseAvatar.vue.d.ts +126 -0
  6. package/dist/types/src/components/BaseBadge.vue.d.ts +94 -0
  7. package/dist/types/src/components/BaseBelongsTo.vue.d.ts +268 -0
  8. package/dist/types/src/components/BaseBoolean.vue.d.ts +64 -0
  9. package/dist/types/src/components/BaseBreadcrumbs.vue.d.ts +66 -0
  10. package/dist/types/src/components/BaseButton.vue.d.ts +23 -0
  11. package/dist/types/src/components/BaseCard.vue.d.ts +74 -0
  12. package/dist/types/src/components/BaseCardRow.vue.d.ts +16 -0
  13. package/dist/types/src/components/BaseClipboard.vue.d.ts +74 -0
  14. package/dist/types/src/components/BaseContainer.vue.d.ts +34 -0
  15. package/dist/types/src/components/BaseCounter.vue.d.ts +125 -0
  16. package/dist/types/src/components/BaseDataIterator.vue.d.ts +345 -0
  17. package/dist/types/src/components/BaseDataTable.vue.d.ts +657 -0
  18. package/dist/types/src/components/BaseDataTableToggleColumns.vue.d.ts +1281 -0
  19. package/dist/types/src/components/BaseDatePicker.vue.d.ts +190 -0
  20. package/dist/types/src/components/BaseDateSelect.vue.d.ts +171 -0
  21. package/dist/types/src/components/BaseDescriptionList.vue.d.ts +48 -0
  22. package/dist/types/src/components/BaseDescriptionListItem.vue.d.ts +49 -0
  23. package/dist/types/src/components/BaseDialog.vue.d.ts +160 -0
  24. package/dist/types/src/components/BaseFilePicker.vue.d.ts +44 -0
  25. package/dist/types/src/components/BaseFileUploader.vue.d.ts +220 -0
  26. package/dist/types/src/components/BaseInput.vue.d.ts +209 -0
  27. package/dist/types/src/components/BaseInputLabel.vue.d.ts +31 -0
  28. package/dist/types/src/components/BaseLoadingCover.vue.d.ts +166 -0
  29. package/dist/types/src/components/BaseLoadingPage.vue.d.ts +2 -0
  30. package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +269 -0
  31. package/dist/types/src/components/BaseMediaLibraryItem.vue.d.ts +75 -0
  32. package/dist/types/src/components/BaseMenu.vue.d.ts +117 -0
  33. package/dist/types/src/components/BaseMenuItem.vue.d.ts +147 -0
  34. package/dist/types/src/components/BaseModalCenter.vue.d.ts +141 -0
  35. package/dist/types/src/components/BaseModalSide.vue.d.ts +141 -0
  36. package/dist/types/src/components/BaseNavbar.vue.d.ts +79 -0
  37. package/dist/types/src/components/BaseNavbarItem.vue.d.ts +80 -0
  38. package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +127 -0
  39. package/dist/types/src/components/BasePagination.vue.d.ts +25 -0
  40. package/dist/types/src/components/BasePaginationSimple.vue.d.ts +25 -0
  41. package/dist/types/src/components/BasePanel.vue.d.ts +31 -0
  42. package/dist/types/src/components/BasePassword.vue.d.ts +66 -0
  43. package/dist/types/src/components/BaseProcessRing.vue.d.ts +36 -0
  44. package/dist/types/src/components/BaseReadMore.vue.d.ts +74 -0
  45. package/dist/types/src/components/BaseSelect.vue.d.ts +55 -0
  46. package/dist/types/src/components/BaseSideNavigation.vue.d.ts +48 -0
  47. package/dist/types/src/components/BaseSideNavigationItem.vue.d.ts +92 -0
  48. package/dist/types/src/components/BaseSkeleton.vue.d.ts +93 -0
  49. package/dist/types/src/components/BaseSpinner.vue.d.ts +2 -0
  50. package/dist/types/src/components/BaseSwitch.vue.d.ts +39 -0
  51. package/dist/types/src/components/BaseSystemAlert.vue.d.ts +141 -0
  52. package/dist/types/src/components/BaseTabItem.vue.d.ts +70 -0
  53. package/dist/types/src/components/BaseTable.vue.d.ts +467 -0
  54. package/dist/types/src/components/BaseTableColumn.vue.d.ts +164 -0
  55. package/dist/types/src/components/BaseTabs.vue.d.ts +48 -0
  56. package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +274 -0
  57. package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +251 -0
  58. package/dist/types/src/components/BaseTextarea.vue.d.ts +228 -0
  59. package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +44 -0
  60. package/dist/types/src/components/BaseTitle.vue.d.ts +45 -0
  61. package/dist/types/src/components/BaseWordCount.vue.d.ts +31 -0
  62. package/dist/types/src/components/SlotComponent.d.ts +43 -0
  63. package/dist/types/src/components/index.d.ts +2 -0
  64. package/dist/types/src/composables/breakpoints.d.ts +12 -0
  65. package/dist/types/src/composables/modal.d.ts +6 -0
  66. package/dist/types/src/constants/MyConstants.d.ts +1 -0
  67. package/dist/types/src/constants/index.d.ts +2 -0
  68. package/dist/types/src/index.d.ts +253 -0
  69. package/dist/types/src/types/Media.d.ts +8 -0
  70. package/dist/types/src/types/UploadedFile.d.ts +9 -0
  71. package/dist/types/src/types/User.d.ts +6 -0
  72. package/dist/types/src/types/types.d.ts +88 -0
  73. package/dist/types/src/utils/fileSizeFormat.d.ts +1 -0
  74. package/dist/types/src/utils/index.d.ts +4 -0
  75. package/dist/types/src/utils/scrollPreventer.d.ts +4 -0
  76. package/dist/types/src/utils/toHumanList.d.ts +1 -0
  77. package/package.json +99 -0
  78. package/src/assets/button.css +80 -0
  79. package/src/assets/form.css +15 -0
  80. package/src/assets/main.css +3 -0
  81. package/src/assets/pikaday.css +134 -0
  82. package/src/assets/tailwind.css +5 -0
  83. package/src/components/BaseAlert.stories.js +52 -0
  84. package/src/components/BaseAlert.vue +152 -0
  85. package/src/components/BaseAutocomplete.stories.js +127 -0
  86. package/src/components/BaseAutocomplete.vue +376 -0
  87. package/src/components/BaseAutocompleteFetch.stories.js +121 -0
  88. package/src/components/BaseAutocompleteFetch.vue +185 -0
  89. package/src/components/BaseAvatar.stories.js +39 -0
  90. package/src/components/BaseAvatar.vue +92 -0
  91. package/src/components/BaseBadge.stories.js +61 -0
  92. package/src/components/BaseBadge.vue +70 -0
  93. package/src/components/BaseBelongsTo.stories.js +130 -0
  94. package/src/components/BaseBelongsTo.vue +122 -0
  95. package/src/components/BaseBoolean.stories.js +35 -0
  96. package/src/components/BaseBoolean.vue +29 -0
  97. package/src/components/BaseBreadcrumbs.stories.js +45 -0
  98. package/src/components/BaseBreadcrumbs.vue +78 -0
  99. package/src/components/BaseButton.stories.js +80 -0
  100. package/src/components/BaseButton.vue +39 -0
  101. package/src/components/BaseCard.stories.js +61 -0
  102. package/src/components/BaseCard.vue +49 -0
  103. package/src/components/BaseCardRow.vue +34 -0
  104. package/src/components/BaseClipboard.stories.js +31 -0
  105. package/src/components/BaseClipboard.vue +96 -0
  106. package/src/components/BaseContainer.stories.js +34 -0
  107. package/src/components/BaseContainer.vue +50 -0
  108. package/src/components/BaseCounter.stories.js +32 -0
  109. package/src/components/BaseCounter.vue +72 -0
  110. package/src/components/BaseDataIterator.stories.js +90 -0
  111. package/src/components/BaseDataIterator.vue +658 -0
  112. package/src/components/BaseDataTable.stories.js +95 -0
  113. package/src/components/BaseDataTable.vue +489 -0
  114. package/src/components/BaseDataTableToggleColumns.vue +69 -0
  115. package/src/components/BaseDatePicker.stories.js +53 -0
  116. package/src/components/BaseDatePicker.vue +166 -0
  117. package/src/components/BaseDateSelect.vue +192 -0
  118. package/src/components/BaseDescriptionList.vue +11 -0
  119. package/src/components/BaseDescriptionListItem.vue +12 -0
  120. package/src/components/BaseDialog.vue +104 -0
  121. package/src/components/BaseFilePicker.vue +101 -0
  122. package/src/components/BaseFileUploader.vue +166 -0
  123. package/src/components/BaseInput.vue +82 -0
  124. package/src/components/BaseInputLabel.vue +26 -0
  125. package/src/components/BaseLoadingCover.vue +84 -0
  126. package/src/components/BaseLoadingPage.vue +19 -0
  127. package/src/components/BaseMediaLibrary.vue +281 -0
  128. package/src/components/BaseMediaLibraryItem.vue +92 -0
  129. package/src/components/BaseMenu.vue +114 -0
  130. package/src/components/BaseMenuItem.vue +93 -0
  131. package/src/components/BaseModalCenter.vue +107 -0
  132. package/src/components/BaseModalSide.vue +112 -0
  133. package/src/components/BaseNavbar.vue +72 -0
  134. package/src/components/BaseNavbarItem.vue +72 -0
  135. package/src/components/BaseNavbarItemContent.vue +57 -0
  136. package/src/components/BasePagination.vue +82 -0
  137. package/src/components/BasePaginationSimple.vue +60 -0
  138. package/src/components/BasePanel.vue +39 -0
  139. package/src/components/BasePassword.vue +73 -0
  140. package/src/components/BaseProcessRing.vue +56 -0
  141. package/src/components/BaseReadMore.vue +72 -0
  142. package/src/components/BaseSelect.vue +59 -0
  143. package/src/components/BaseSideNavigation.vue +7 -0
  144. package/src/components/BaseSideNavigationItem.vue +42 -0
  145. package/src/components/BaseSkeleton.vue +24 -0
  146. package/src/components/BaseSpinner.vue +47 -0
  147. package/src/components/BaseSwitch.vue +87 -0
  148. package/src/components/BaseSystemAlert.vue +86 -0
  149. package/src/components/BaseTabItem.vue +30 -0
  150. package/src/components/BaseTable.vue +781 -0
  151. package/src/components/BaseTableColumn.vue +109 -0
  152. package/src/components/BaseTabs.vue +12 -0
  153. package/src/components/BaseTagAutocomplete.vue +385 -0
  154. package/src/components/BaseTagAutocompleteFetch.vue +154 -0
  155. package/src/components/BaseTextarea.vue +73 -0
  156. package/src/components/BaseTextareaAutoresize.vue +117 -0
  157. package/src/components/BaseTitle.vue +80 -0
  158. package/src/components/BaseWordCount.vue +36 -0
  159. package/src/components/SlotComponent.ts +37 -0
  160. package/src/components/index.ts +5 -0
  161. package/src/composables/breakpoints.ts +6 -0
  162. package/src/composables/modal.ts +77 -0
  163. package/src/constants/MyConstants.ts +1 -0
  164. package/src/constants/index.ts +5 -0
  165. package/src/env.d.ts +15 -0
  166. package/src/index.ts +70 -0
  167. package/src/lang/en.json +56 -0
  168. package/src/lang/fr.json +56 -0
  169. package/src/types/Media.ts +9 -0
  170. package/src/types/UploadedFile.ts +10 -0
  171. package/src/types/User.ts +7 -0
  172. package/src/types/types.ts +112 -0
  173. package/src/utils/fileSizeFormat.ts +15 -0
  174. package/src/utils/index.ts +5 -0
  175. package/src/utils/scrollPreventer.ts +21 -0
  176. package/src/utils/toHumanList.ts +20 -0
@@ -0,0 +1,781 @@
1
+ <template>
2
+ <div class="relative w-full overflow-hidden">
3
+ <div ref="slot" style="display: none">
4
+ <slot />
5
+ </div>
6
+
7
+ <div class="flex flex-col">
8
+ <div
9
+ class="isolate overflow-x-auto overflow-y-auto"
10
+ :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }"
11
+ >
12
+ <div class="inline-block min-w-full align-middle">
13
+ <div class="relative">
14
+ <table class="min-w-full border-separate border-spacing-0">
15
+ <thead v-if="newColumns.length" ref="thead">
16
+ <tr>
17
+ <th v-if="showDetailRowIcon" class="th" />
18
+ <th
19
+ v-if="checkable && checkboxPosition === 'left'"
20
+ class="th pl-3"
21
+ align="left"
22
+ >
23
+ <input
24
+ type="checkbox"
25
+ autocomplete="off"
26
+ :checked="isAllChecked"
27
+ :disabled="isAllUncheckable"
28
+ :class="checkboxStyle"
29
+ @change="checkAll"
30
+ />
31
+ </th>
32
+ <th
33
+ v-for="(column, index) in visibleColumns"
34
+ :key="column.newKey + ':' + index + 'header'"
35
+ v-bind="column.thAttrs && column.thAttrs(column)"
36
+ :style="column.style"
37
+ class="th py-2 pl-3 pr-3 text-left"
38
+ @click.stop="sort(column, undefined, $event as any)"
39
+ >
40
+ <button
41
+ type="button"
42
+ class="flex w-full items-center bg-transparent text-left text-sm font-medium leading-tight text-slate-900"
43
+ :class="{
44
+ 'cursor-default': !column.sortable,
45
+ 'text-blue-600':
46
+ column.sortable && currentSortColumn === column,
47
+ }"
48
+ >
49
+ <span class="mr-1 whitespace-nowrap">{{
50
+ column.label
51
+ }}</span>
52
+ <span
53
+ v-show="column.sortable && currentSortColumn === column"
54
+ >
55
+ <Icon
56
+ icon="mdi:chevron-down"
57
+ class="h-5 w-5 duration-300"
58
+ :class="{
59
+ 'rotate-180': isAsc,
60
+ }"
61
+ />
62
+ </span>
63
+ </button>
64
+ </th>
65
+ <th
66
+ v-if="checkable && checkboxPosition === 'right'"
67
+ class="th pr-3"
68
+ align="right"
69
+ >
70
+ <input
71
+ autocomplete="off"
72
+ type="checkbox"
73
+ :checked="isAllChecked"
74
+ :disabled="isAllUncheckable"
75
+ :class="checkboxStyle"
76
+ @change="checkAll"
77
+ />
78
+ </th>
79
+ </tr>
80
+ </thead>
81
+
82
+ <tbody class="bg-white">
83
+ <tr v-if="newCheckedRows.length">
84
+ <td
85
+ :colspan="columnCount"
86
+ class="sticky z-10 p-0"
87
+ :style="{
88
+ top: theadHeight + 'px',
89
+ }"
90
+ :class="[borderClasses]"
91
+ >
92
+ <slot
93
+ name="checkedHeader"
94
+ :uncheck-all="uncheckAll"
95
+ :count="newCheckedRows.length"
96
+ :check-rows="newCheckedRows"
97
+ >
98
+ <div
99
+ class="flex items-center justify-between bg-slate-100 py-2 pl-3 pr-2 text-sm"
100
+ >
101
+ <div>
102
+ <span class="mr-3 text-slate-500"
103
+ >{{
104
+ $t('sui.x_rows_selected', {
105
+ count: newCheckedRows.length,
106
+ })
107
+ }}.</span
108
+ >
109
+ <button
110
+ type="button"
111
+ class="mr-3 inline text-slate-700 underline"
112
+ @click="uncheckAll()"
113
+ >
114
+ {{ $t('sui.deselect_all') }}
115
+ </button>
116
+ </div>
117
+ <BaseMenu
118
+ v-if="checkableActions?.length"
119
+ menu-class="w-52"
120
+ :items="checkableActions"
121
+ >
122
+ <template #button="{ open }">
123
+ <div
124
+ class="flex h-10 w-10 items-center justify-center rounded-full border border-slate-300 bg-white duration-150 hover:bg-slate-50"
125
+ :class="[
126
+ open
127
+ ? 'ring-2 ring-primary-500 ring-offset-2'
128
+ : false,
129
+ ]"
130
+ >
131
+ <Icon icon="heroicons-solid:dots-vertical" />
132
+ </div>
133
+ </template>
134
+ </BaseMenu>
135
+ </div>
136
+ </slot>
137
+ </td>
138
+ </tr>
139
+
140
+ <template v-for="(row, index) in data" :key="index">
141
+ <tr>
142
+ <td
143
+ v-if="showDetailRowIcon"
144
+ class="pl-3"
145
+ :class="borderBottomClasses(index, row)"
146
+ style="width: 36px"
147
+ >
148
+ <button
149
+ type="button"
150
+ class="mr-0 flex h-8 w-8 appearance-none items-center justify-center rounded-full border-0 bg-white text-slate-400 duration-300 hover:bg-slate-100 hover:text-slate-700"
151
+ :class="{
152
+ 'rotate-180': isVisibleDetailRow(row),
153
+ }"
154
+ @click.stop="toggleDetails(row)"
155
+ >
156
+ <Icon
157
+ v-if="hasDetailedVisible(row)"
158
+ icon="mdi:chevron-down"
159
+ class="h-5 w-5"
160
+ />
161
+ </button>
162
+ </td>
163
+
164
+ <td
165
+ v-if="checkable && checkboxPosition === 'left'"
166
+ class="pl-3"
167
+ :class="borderBottomClasses(index, row)"
168
+ >
169
+ <input
170
+ type="checkbox"
171
+ autocomplete="off"
172
+ :disabled="!isRowCheckable(row)"
173
+ :checked="isRowChecked(row)"
174
+ :class="checkboxStyle"
175
+ @click="checkRow(row, index, $event as MouseEvent)"
176
+ />
177
+ </td>
178
+
179
+ <SlotComponent
180
+ v-for="(column, colindex) in visibleColumns"
181
+ :key="column.newKey + index + ':' + colindex"
182
+ v-bind="column.tdAttrs && column.tdAttrs(row, column)"
183
+ :component="column"
184
+ scoped
185
+ name="default"
186
+ tag="td"
187
+ class="py-3 pl-3 pr-3 text-sm"
188
+ :class="borderBottomClasses(index, row)"
189
+ :data-label="column.label"
190
+ :props="{ row, column, index, colindex, toggleDetails }"
191
+ @click="
192
+ $emit(
193
+ 'cell-click',
194
+ row,
195
+ column,
196
+ index,
197
+ colindex,
198
+ $event
199
+ )
200
+ "
201
+ />
202
+
203
+ <td
204
+ v-if="checkable && checkboxPosition === 'right'"
205
+ class="pr-3"
206
+ :class="borderBottomClasses(index, row)"
207
+ align="right"
208
+ >
209
+ <input
210
+ type="checkbox"
211
+ autocomplete="off"
212
+ :disabled="!isRowCheckable(row)"
213
+ :checked="isRowChecked(row)"
214
+ :class="checkboxStyle"
215
+ @click="checkRow(row, index, $event as MouseEvent)"
216
+ />
217
+ </td>
218
+ </tr>
219
+
220
+ <transition :name="detailTransition">
221
+ <tr v-if="isActiveDetailRow(row)" :key="index + 'detail'">
222
+ <td
223
+ :colspan="columnCount"
224
+ class="td"
225
+ :class="borderBottomDetailClasses(index)"
226
+ >
227
+ <slot name="detail" :row="row" :index="index" />
228
+ </td>
229
+ </tr>
230
+ </transition>
231
+ </template>
232
+
233
+ <tr v-if="data.length == 0">
234
+ <td :colspan="columnCount">
235
+ <slot name="empty" />
236
+ </td>
237
+ </tr>
238
+ </tbody>
239
+ </table>
240
+
241
+ <slot name="loading">
242
+ <BaseLoadingCover
243
+ :delay="0"
244
+ :model-value="loading"
245
+ backdrop-class="bg-white bg-opacity-50"
246
+ />
247
+ <div v-if="loading" class="h-[300px]" />
248
+ </slot>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ </div>
254
+ </template>
255
+
256
+ <script lang="ts">
257
+ export default {
258
+ name: 'BaseTable',
259
+ inheritAttrs: false,
260
+ };
261
+ </script>
262
+
263
+ <script lang="ts" setup>
264
+ import { PropType, ref, Ref } from 'vue';
265
+ import { BaseTableColumn, MenuItemInterface, Row } from '@/types/types';
266
+ import SlotComponent from './SlotComponent';
267
+ import { useResizeObserver } from '@vueuse/core';
268
+ import { debounce, isArray } from 'lodash';
269
+
270
+ const checkboxStyle =
271
+ 'disabled:bg-slate-100 disabled:border-slate-300 disabled:cursor-not-allowed border-slate-400 rounded';
272
+
273
+ provide('table', getCurrentInstance());
274
+
275
+ const props = defineProps({
276
+ /** Table data */
277
+ data: {
278
+ type: Array as PropType<Row[]>,
279
+ default: () => [],
280
+ },
281
+ /** Loading state */
282
+ loading: {
283
+ default: false,
284
+ type: Boolean,
285
+ },
286
+ visibleColumns: {
287
+ default: undefined,
288
+ type: Array as PropType<number[]>,
289
+ },
290
+ /** Allow row details */
291
+ detailed: {
292
+ default: false,
293
+ type: Boolean,
294
+ },
295
+ /** Rows can be checked (multiple), checked rows will have a .is-checked class if you want to style */
296
+ checkable: {
297
+ default: false,
298
+ type: Boolean,
299
+ },
300
+ /** Define checkable actions */
301
+ checkableActions: {
302
+ default: undefined,
303
+ type: Array as PropType<MenuItemInterface[]>,
304
+ },
305
+ /**
306
+ * Position of the checkbox (if checkable is true)
307
+ * @values left, right
308
+ */
309
+ checkboxPosition: {
310
+ type: String as PropType<'left' | 'right'>,
311
+ default: 'left',
312
+ },
313
+ /** Custom method to verify if a row is checkable, works when is checkable */
314
+ isRowCheckable: {
315
+ type: Function,
316
+ default: () => true,
317
+ },
318
+ /** Set which rows are checked, use v-model:checkedRows to make it two-way binding */
319
+ checkedRows: {
320
+ default: () => [],
321
+ type: Array as PropType<Row[]>,
322
+ },
323
+ /** Sets the default sort column field */
324
+ sortField: {
325
+ type: String,
326
+ default: '',
327
+ },
328
+ /**
329
+ * Sets the default sort column direction
330
+ * @values asc, desc
331
+ */
332
+ sortDirection: {
333
+ type: String,
334
+ default: 'asc',
335
+ },
336
+ /** Controls the visibility of the trigger that toggles the detailed rows. */
337
+ hasDetailedVisible: {
338
+ type: Function,
339
+ default: () => true,
340
+ },
341
+ /** Use a unique key of your data Object when use detailed or opened detailed. (id recommended) */
342
+ rowKey: {
343
+ type: String,
344
+ default: 'id',
345
+ },
346
+ /* Transition name to use when toggling row details. */
347
+ detailTransition: {
348
+ type: String,
349
+ default: '',
350
+ },
351
+ /* Max height (in px) */
352
+ maxHeight: {
353
+ default: undefined,
354
+ type: Number,
355
+ },
356
+ });
357
+
358
+ const emit = defineEmits([
359
+ 'check',
360
+ 'check-all',
361
+ 'update:checkedRows',
362
+ 'details-open',
363
+ 'details-close',
364
+ 'update:openedDetailed',
365
+ 'sort',
366
+ 'cell-click',
367
+ ]);
368
+
369
+ const visibleDetailRows = ref([]) as Ref<Row[]>;
370
+ const newCheckedRows = ref([...props.checkedRows]) as Ref<Row[]>;
371
+ const lastCheckedRowIndex = ref(null) as Ref<number | null>;
372
+ const currentSortColumn = ref(null) as Ref<BaseTableColumn | null>;
373
+ const isAsc = ref(true);
374
+ const defaultSlots = ref([]) as Ref<BaseTableColumn[]>;
375
+ const sequence = ref(1);
376
+
377
+ const slot = ref(null) as Ref<HTMLElement | null>;
378
+ const thead = ref(null) as Ref<HTMLElement | null>;
379
+ const theadHeight = ref(0);
380
+
381
+ useResizeObserver(thead, () => setTheadHeightDebounce());
382
+
383
+ const setTheadHeightDebounce = debounce(() => {
384
+ setTheadHeight();
385
+ }, 100);
386
+
387
+ function setTheadHeight() {
388
+ if (thead.value) {
389
+ theadHeight.value = thead.value.clientHeight;
390
+ }
391
+ }
392
+
393
+ const newColumns = computed(() => {
394
+ return defaultSlots.value;
395
+ });
396
+
397
+ const visibleColumns = computed(() => {
398
+ if (!newColumns.value) {
399
+ return newColumns.value;
400
+ }
401
+
402
+ return newColumns.value.filter((column: BaseTableColumn) => {
403
+ if (column.visible === false) {
404
+ return false;
405
+ }
406
+
407
+ if (column.alwaysVisible) {
408
+ return true;
409
+ }
410
+
411
+ if (!isArray(props.visibleColumns)) {
412
+ return true;
413
+ }
414
+
415
+ if (props.visibleColumns.includes(column.newKey)) {
416
+ return true;
417
+ }
418
+
419
+ return false;
420
+ });
421
+ });
422
+
423
+ /**
424
+ * Return total column count based if it's checkable or expanded
425
+ */
426
+ const columnCount = computed(() => {
427
+ let count = visibleColumns.value.length;
428
+ count += props.checkable ? 1 : 0;
429
+ count += props.detailed ? 1 : 0;
430
+
431
+ return count;
432
+ });
433
+
434
+ /**
435
+ * Return if detailed row tabled
436
+ * will be with chevron column & icon or not
437
+ */
438
+ const showDetailRowIcon = computed(() => {
439
+ return props.detailed;
440
+ });
441
+
442
+ /**
443
+ * When checkedRows prop change, update internal value without
444
+ * mutating original data.
445
+ */
446
+ watch(
447
+ () => props.checkedRows,
448
+ (rows) => {
449
+ newCheckedRows.value = [...rows];
450
+ },
451
+ { deep: true }
452
+ );
453
+
454
+ watch(
455
+ () => props.sortField,
456
+ () => {
457
+ updateSortState();
458
+ }
459
+ );
460
+
461
+ watch(
462
+ () => props.sortDirection,
463
+ () => {
464
+ updateSortState();
465
+ }
466
+ );
467
+
468
+ onMounted(() => {
469
+ nextTick(() => {
470
+ updateSortState();
471
+ });
472
+ });
473
+
474
+ /**
475
+ * Sort the column.
476
+ * Toggle current direction on column if it's sortable
477
+ * and not just updating the prop.
478
+ */
479
+ function sort(column: BaseTableColumn, updatingData = false, event = null) {
480
+ if (!column || !column.sortable) {
481
+ return;
482
+ }
483
+
484
+ if (!updatingData) {
485
+ isAsc.value =
486
+ column === currentSortColumn.value
487
+ ? !isAsc.value
488
+ : props.sortDirection.toLowerCase() !== 'desc';
489
+ }
490
+
491
+ /**
492
+ * @property {string} field column field
493
+ * @property {boolean} direction 'asc' or 'desc'
494
+ * @property {Event} event native event
495
+ */
496
+ emit('sort', column.field, isAsc.value ? 'asc' : 'desc', event);
497
+
498
+ currentSortColumn.value = column;
499
+ }
500
+
501
+ /**
502
+ * Check if the row is checked (is added to the array).
503
+ */
504
+ function isRowChecked(row: Row): boolean {
505
+ return (
506
+ newCheckedRows.value.find((r) => r[props.rowKey] == row[props.rowKey]) !==
507
+ undefined
508
+ );
509
+ }
510
+
511
+ /**
512
+ * Check if all rows in the page are checkable.
513
+ */
514
+ const isAllUncheckable = computed(() => {
515
+ const validData = props.data.filter((row) => props.isRowCheckable(row));
516
+ return validData.length === 0;
517
+ });
518
+
519
+ /**
520
+ * Check if all rows in the page are checked.
521
+ */
522
+ const isAllChecked = computed(() => {
523
+ const validData = props.data.filter((row) => {
524
+ return props.isRowCheckable(row);
525
+ });
526
+
527
+ if (validData.length === 0) {
528
+ return false;
529
+ }
530
+
531
+ const missingChecked = validData.some((currentRow) => {
532
+ return !isRowChecked(currentRow);
533
+ });
534
+
535
+ return !missingChecked;
536
+ });
537
+
538
+ /**
539
+ * Remove a checked row from the array.
540
+ */
541
+ function removeCheckedRow(row: Row) {
542
+ const index = newCheckedRows.value.findIndex(
543
+ (r) => r[props.rowKey] == row[props.rowKey]
544
+ );
545
+ if (index >= 0) {
546
+ newCheckedRows.value.splice(index, 1);
547
+ }
548
+ }
549
+
550
+ /**
551
+ * Header checkbox click listener.
552
+ * Add or remove all rows in current page.
553
+ */
554
+ function checkAll() {
555
+ if (isAllChecked.value) {
556
+ newCheckedRows.value = [];
557
+ } else {
558
+ props.data.forEach((currentRow) => {
559
+ if (props.isRowCheckable(currentRow)) {
560
+ newCheckedRows.value.push(currentRow);
561
+ }
562
+ });
563
+ }
564
+
565
+ sendCheckUpdate();
566
+ }
567
+
568
+ /**
569
+ * Remove all rows in current page.
570
+ */
571
+ function uncheckAll() {
572
+ newCheckedRows.value = [];
573
+
574
+ sendCheckUpdate();
575
+ }
576
+
577
+ function sendCheckUpdate() {
578
+ emit('check', newCheckedRows.value);
579
+ emit('check-all', newCheckedRows.value);
580
+ emit('update:checkedRows', newCheckedRows.value);
581
+ }
582
+
583
+ /**
584
+ * Row checkbox click listener.
585
+ */
586
+ function checkRow(row: Row, index: number, event: MouseEvent) {
587
+ if (!props.isRowCheckable(row)) {
588
+ return;
589
+ }
590
+
591
+ const lastIndex = lastCheckedRowIndex.value;
592
+ lastCheckedRowIndex.value = index;
593
+
594
+ if (event.shiftKey && lastIndex !== null && index !== lastIndex) {
595
+ shiftCheckRow(row, index, lastIndex);
596
+ } else if (!isRowChecked(row)) {
597
+ newCheckedRows.value.push(row);
598
+ } else {
599
+ removeCheckedRow(row);
600
+ }
601
+
602
+ emit('check', newCheckedRows.value, row);
603
+
604
+ // Emit checked rows to update user variable
605
+ emit('update:checkedRows', newCheckedRows.value);
606
+ }
607
+
608
+ /**
609
+ * Check row when shift is pressed.
610
+ */
611
+ function shiftCheckRow(row: Row, index: number, lastCheckedRowIndex: number) {
612
+ // Get the subset of the list between the two indices
613
+ const subset = props.data.slice(
614
+ Math.min(index, lastCheckedRowIndex),
615
+ Math.max(index, lastCheckedRowIndex) + 1
616
+ );
617
+
618
+ // Determine the operation based on the state of the clicked checkbox
619
+ const shouldCheck = !isRowChecked(row);
620
+
621
+ subset.forEach((item) => {
622
+ removeCheckedRow(item);
623
+ if (shouldCheck && props.isRowCheckable(item)) {
624
+ newCheckedRows.value.push(item);
625
+ }
626
+ });
627
+ }
628
+
629
+ /**
630
+ * Toggle to show/hide details slot
631
+ */
632
+ function toggleDetails(row: Row) {
633
+ const found = isVisibleDetailRow(row);
634
+
635
+ if (found) {
636
+ closeDetailRow(row);
637
+ emit('details-close', row);
638
+ } else {
639
+ openDetailRow(row);
640
+ emit('details-open', row);
641
+ }
642
+
643
+ // Syncs the detailed rows with the parent component
644
+ emit('update:openedDetailed', visibleDetailRows.value);
645
+ }
646
+
647
+ function openDetailRow(row: Row) {
648
+ const index = getDetailedIndex(row);
649
+ visibleDetailRows.value.push(index);
650
+ }
651
+
652
+ function closeDetailRow(row: Row) {
653
+ const index = getDetailedIndex(row);
654
+ const i = visibleDetailRows.value.indexOf(index);
655
+ if (i >= 0) {
656
+ visibleDetailRows.value.splice(i, 1);
657
+ }
658
+ }
659
+
660
+ function isVisibleDetailRow(row: Row) {
661
+ const index = getDetailedIndex(row);
662
+ return visibleDetailRows.value.indexOf(index) >= 0;
663
+ }
664
+
665
+ function isActiveDetailRow(row: Row) {
666
+ return props.detailed && isVisibleDetailRow(row);
667
+ }
668
+
669
+ /**
670
+ * When the rowKey is defined we use the object[rowKey] as index.
671
+ * If not, use the object reference by default.
672
+ */
673
+ function getDetailedIndex(row: Row) {
674
+ const key = props.rowKey;
675
+ return !key.length || !row ? row : row[key];
676
+ }
677
+
678
+ /**
679
+ * Update sort state
680
+ */
681
+ function updateSortState() {
682
+ const sortField = props.sortField;
683
+
684
+ const sortDirection = props.sortDirection;
685
+
686
+ const sortColumn = newColumns.value.filter(
687
+ (column) => column.field === sortField
688
+ )[0];
689
+
690
+ // Set sort state
691
+
692
+ if (sortColumn) {
693
+ currentSortColumn.value = sortColumn;
694
+ isAsc.value = sortDirection.toLowerCase() !== 'desc';
695
+ } else {
696
+ currentSortColumn.value = null;
697
+ return;
698
+ }
699
+ }
700
+
701
+ /*
702
+ |--------------------------------------------------------------------------
703
+ | BaseTableColumns functions
704
+ |--------------------------------------------------------------------------
705
+ */
706
+
707
+ function addColumn(column: BaseTableColumn) {
708
+ defaultSlots.value.push(column);
709
+
710
+ const slotHTMLElement = slot.value as HTMLElement;
711
+
712
+ if (slotHTMLElement && slotHTMLElement.children) {
713
+ nextTick(() => {
714
+ const ids = defaultSlots.value
715
+ .map((it) => `[data-id="${it.newKey}"]`)
716
+ .join(',');
717
+
718
+ const sortedIds = Array.from(slotHTMLElement.querySelectorAll(ids)).map(
719
+ (el: Element) => el.getAttribute('data-id')
720
+ );
721
+
722
+ defaultSlots.value = defaultSlots.value.sort((a, b) => {
723
+ return (
724
+ sortedIds.indexOf(`${a.newKey}`) - sortedIds.indexOf(`${b.newKey}`)
725
+ );
726
+ });
727
+ });
728
+ }
729
+ }
730
+
731
+ function removeColumn(column: BaseTableColumn) {
732
+ defaultSlots.value = defaultSlots.value.filter(
733
+ (d) => d.newKey !== column.newKey
734
+ );
735
+ }
736
+
737
+ const borderClasses = 'border-b border-slate-300';
738
+
739
+ function borderBottomClasses(index: number, row: Record<string, any>): string {
740
+ if (index < props.data.length - 1) {
741
+ return borderClasses;
742
+ }
743
+
744
+ if (isActiveDetailRow(row)) {
745
+ return borderClasses;
746
+ }
747
+
748
+ return '';
749
+ }
750
+
751
+ function borderBottomDetailClasses(index: number): string {
752
+ if (index < props.data.length - 1) {
753
+ return borderClasses;
754
+ }
755
+
756
+ return '';
757
+ }
758
+
759
+ function nextSequence() {
760
+ return sequence.value++;
761
+ }
762
+
763
+ provide('addColumn', addColumn);
764
+ provide('removeColumn', removeColumn);
765
+ provide('nextSequence', nextSequence);
766
+
767
+ defineExpose({
768
+ newColumns,
769
+ });
770
+ </script>
771
+
772
+ <style scoped>
773
+ .th {
774
+ @apply bg-slate-50;
775
+ @apply sticky;
776
+ @apply top-0;
777
+ @apply z-10;
778
+ @apply border-b border-slate-300;
779
+ @apply bg-opacity-75 backdrop-blur backdrop-filter;
780
+ }
781
+ </style>