sprintify-ui 0.1.15 → 0.1.17

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