sprintify-ui 0.4.3 → 0.4.5

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 (417) hide show
  1. package/README.md +258 -259
  2. package/dist/sprintify-ui.es.js +27777 -18061
  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 +40 -40
  6. package/dist/types/src/components/BaseActionItemButton.vue.d.ts +25 -25
  7. package/dist/types/src/components/BaseAddressForm.vue.d.ts +84 -84
  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 +237 -237
  13. package/dist/types/src/components/BaseAutocompleteDrawer.vue.d.ts +91 -91
  14. package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +210 -210
  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 +60 -60
  18. package/dist/types/src/components/BaseBelongsTo.vue.d.ts +216 -216
  19. package/dist/types/src/components/BaseBoolean.vue.d.ts +10 -10
  20. package/dist/types/src/components/BaseBreadcrumbs.vue.d.ts +24 -24
  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/BaseCalendar.vue.d.ts +124 -0
  24. package/dist/types/src/components/BaseCard.vue.d.ts +21 -21
  25. package/dist/types/src/components/BaseCardRow.vue.d.ts +16 -16
  26. package/dist/types/src/components/BaseCharacterCounter.vue.d.ts +49 -49
  27. package/dist/types/src/components/BaseClickOutside.vue.d.ts +26 -26
  28. package/dist/types/src/components/BaseClipboard.vue.d.ts +22 -22
  29. package/dist/types/src/components/BaseColor.vue.d.ts +80 -80
  30. package/dist/types/src/components/BaseContainer.vue.d.ts +34 -34
  31. package/dist/types/src/components/BaseCounter.vue.d.ts +42 -42
  32. package/dist/types/src/components/BaseCropper.vue.d.ts +76 -76
  33. package/dist/types/src/components/BaseCropperModal.vue.d.ts +28 -28
  34. package/dist/types/src/components/BaseDataIterator.vue.d.ts +227 -227
  35. package/dist/types/src/components/BaseDataIteratorSectionBox.vue.d.ts +20 -20
  36. package/dist/types/src/components/BaseDataIteratorSectionButton.vue.d.ts +25 -25
  37. package/dist/types/src/components/BaseDataIteratorSectionColumns.vue.d.ts +657 -657
  38. package/dist/types/src/components/BaseDataIteratorSectionModal.vue.d.ts +32 -32
  39. package/dist/types/src/components/BaseDataTable.vue.d.ts +406 -406
  40. package/dist/types/src/components/BaseDataTableRowAction.vue.d.ts +31 -31
  41. package/dist/types/src/components/BaseDatePicker.vue.d.ts +124 -124
  42. package/dist/types/src/components/BaseDateSelect.vue.d.ts +79 -79
  43. package/dist/types/src/components/BaseDescriptionList.vue.d.ts +9 -9
  44. package/dist/types/src/components/BaseDescriptionListItem.vue.d.ts +10 -10
  45. package/dist/types/src/components/BaseDialog.vue.d.ts +60 -60
  46. package/dist/types/src/components/BaseDisplayRelativeTime.vue.d.ts +50 -50
  47. package/dist/types/src/components/BaseDraggable.vue.d.ts +49 -49
  48. package/dist/types/src/components/BaseDropdown.vue.d.ts +65 -65
  49. package/dist/types/src/components/BaseDropdownAutocomplete.vue.d.ts +132 -132
  50. package/dist/types/src/components/BaseField.vue.d.ts +58 -58
  51. package/dist/types/src/components/BaseFieldI18n.vue.d.ts +93 -93
  52. package/dist/types/src/components/BaseFilePicker.vue.d.ts +72 -72
  53. package/dist/types/src/components/BaseFilePickerCrop.vue.d.ts +63 -63
  54. package/dist/types/src/components/BaseFileUploader.vue.d.ts +142 -142
  55. package/dist/types/src/components/BaseForm.vue.d.ts +143 -143
  56. package/dist/types/src/components/BaseGantt.vue.d.ts +425 -425
  57. package/dist/types/src/components/BaseHasMany.vue.d.ts +149 -149
  58. package/dist/types/src/components/BaseHeader.vue.d.ts +98 -98
  59. package/dist/types/src/components/BaseIconPicker.vue.d.ts +34 -34
  60. package/dist/types/src/components/BaseInput.vue.d.ts +174 -174
  61. package/dist/types/src/components/BaseInputError.vue.d.ts +9 -9
  62. package/dist/types/src/components/BaseInputLabel.vue.d.ts +42 -42
  63. package/dist/types/src/components/BaseInputPercent.vue.d.ts +138 -138
  64. package/dist/types/src/components/BaseLayoutNotificationDropdown.vue.d.ts +36 -36
  65. package/dist/types/src/components/BaseLayoutNotificationItem.vue.d.ts +16 -16
  66. package/dist/types/src/components/BaseLayoutNotificationItemContent.vue.d.ts +21 -21
  67. package/dist/types/src/components/BaseLayoutSidebar.vue.d.ts +51 -51
  68. package/dist/types/src/components/BaseLayoutSidebarConfigurable.vue.d.ts +87 -87
  69. package/dist/types/src/components/BaseLayoutStacked.vue.d.ts +23 -23
  70. package/dist/types/src/components/BaseLayoutStackedConfigurable.vue.d.ts +78 -78
  71. package/dist/types/src/components/BaseLoadingCover.vue.d.ts +96 -96
  72. package/dist/types/src/components/BaseMediaGallery.vue.d.ts +64 -64
  73. package/dist/types/src/components/BaseMediaGalleryItem.vue.d.ts +45 -45
  74. package/dist/types/src/components/BaseMediaItem.vue.d.ts +27 -27
  75. package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +199 -199
  76. package/dist/types/src/components/BaseMediaList.vue.d.ts +46 -46
  77. package/dist/types/src/components/BaseMediaListItem.vue.d.ts +46 -46
  78. package/dist/types/src/components/BaseMediaPictures.vue.d.ts +55 -55
  79. package/dist/types/src/components/BaseMediaPicturesItem.vue.d.ts +54 -54
  80. package/dist/types/src/components/BaseMediaPreview.vue.d.ts +36 -36
  81. package/dist/types/src/components/BaseMenu.vue.d.ts +68 -68
  82. package/dist/types/src/components/BaseMenuItem.vue.d.ts +61 -61
  83. package/dist/types/src/components/BaseModalCenter.vue.d.ts +80 -80
  84. package/dist/types/src/components/BaseModalSide.vue.d.ts +62 -62
  85. package/dist/types/src/components/BaseNavbar.vue.d.ts +38 -38
  86. package/dist/types/src/components/BaseNavbarItem.vue.d.ts +26 -26
  87. package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +60 -60
  88. package/dist/types/src/components/BaseNavbarSideItem.vue.d.ts +44 -44
  89. package/dist/types/src/components/BaseNavbarSideItemContent.vue.d.ts +60 -60
  90. package/dist/types/src/components/BasePagination.vue.d.ts +35 -35
  91. package/dist/types/src/components/BasePanel.vue.d.ts +31 -31
  92. package/dist/types/src/components/BasePassword.vue.d.ts +67 -67
  93. package/dist/types/src/components/BaseProgressCircle.vue.d.ts +37 -37
  94. package/dist/types/src/components/BaseRadioGroup.vue.d.ts +105 -105
  95. package/dist/types/src/components/BaseReadMore.vue.d.ts +21 -21
  96. package/dist/types/src/components/BaseRichText.vue.d.ts +92 -92
  97. package/dist/types/src/components/BaseSelect.vue.d.ts +98 -98
  98. package/dist/types/src/components/BaseShortcut.vue.d.ts +86 -86
  99. package/dist/types/src/components/BaseSideNavigation.vue.d.ts +21 -21
  100. package/dist/types/src/components/BaseSideNavigationItem.vue.d.ts +41 -41
  101. package/dist/types/src/components/BaseSkeleton.vue.d.ts +31 -31
  102. package/dist/types/src/components/BaseStatistic.vue.d.ts +55 -55
  103. package/dist/types/src/components/BaseStepper.vue.d.ts +16 -16
  104. package/dist/types/src/components/BaseStepperItem.vue.d.ts +51 -51
  105. package/dist/types/src/components/BaseSwitch.vue.d.ts +87 -87
  106. package/dist/types/src/components/BaseSystemAlert.vue.d.ts +52 -52
  107. package/dist/types/src/components/BaseTabItem.vue.d.ts +41 -41
  108. package/dist/types/src/components/BaseTable.vue.d.ts +221 -221
  109. package/dist/types/src/components/BaseTableColumn.vue.d.ts +174 -174
  110. package/dist/types/src/components/BaseTabs.vue.d.ts +21 -21
  111. package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +209 -209
  112. package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +141 -141
  113. package/dist/types/src/components/BaseTextarea.vue.d.ts +103 -103
  114. package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +113 -113
  115. package/dist/types/src/components/BaseTimeline.vue.d.ts +14 -14
  116. package/dist/types/src/components/BaseTimelineItem.vue.d.ts +14 -14
  117. package/dist/types/src/components/BaseToast.vue.d.ts +20 -20
  118. package/dist/types/src/components/BaseUniqueCode.vue.d.ts +33 -33
  119. package/dist/types/src/components/SlotComponent.d.ts +43 -43
  120. package/dist/types/src/components/index.d.ts +97 -96
  121. package/dist/types/src/composables/breakpoints.d.ts +27 -27
  122. package/dist/types/src/composables/clickOutside.d.ts +8 -8
  123. package/dist/types/src/composables/field.d.ts +19 -19
  124. package/dist/types/src/composables/hasOptions.d.ts +7 -7
  125. package/dist/types/src/composables/mediaQuery.d.ts +2 -2
  126. package/dist/types/src/composables/modal.d.ts +6 -6
  127. package/dist/types/src/composables/paginatedData.d.ts +7 -7
  128. package/dist/types/src/constants/MyConstants.d.ts +1 -1
  129. package/dist/types/src/constants/index.d.ts +2 -2
  130. package/dist/types/src/i18n/index.d.ts +1 -1
  131. package/dist/types/src/index.d.ts +236 -224
  132. package/dist/types/src/services/gantt/format.d.ts +24 -24
  133. package/dist/types/src/services/gantt/timescale.d.ts +26 -26
  134. package/dist/types/src/services/gantt/types.d.ts +67 -67
  135. package/dist/types/src/stores/dialogs.d.ts +9 -9
  136. package/dist/types/src/stores/i18n.d.ts +5 -5
  137. package/dist/types/src/stores/notifications.d.ts +10 -10
  138. package/dist/types/src/stores/systemAlerts.d.ts +9 -9
  139. package/dist/types/src/stories/PageShow.vue.d.ts +2 -2
  140. package/dist/types/src/svg/BaseEmptyState.vue.d.ts +2 -2
  141. package/dist/types/src/svg/BaseSpinnerLarge.vue.d.ts +2 -2
  142. package/dist/types/src/svg/BaseSpinnerSmall.vue.d.ts +2 -2
  143. package/dist/types/src/types/CalendarEvent.d.ts +9 -0
  144. package/dist/types/src/types/Color.d.ts +9 -9
  145. package/dist/types/src/types/Country.d.ts +4 -4
  146. package/dist/types/src/types/ImagePickerResult.d.ts +5 -5
  147. package/dist/types/src/types/Media.d.ts +9 -9
  148. package/dist/types/src/types/Notification.d.ts +8 -8
  149. package/dist/types/src/types/Region.d.ts +5 -5
  150. package/dist/types/src/types/Status.d.ts +5 -5
  151. package/dist/types/src/types/StepperItem.d.ts +7 -7
  152. package/dist/types/src/types/TimelineItem.d.ts +9 -9
  153. package/dist/types/src/types/UploadedFile.d.ts +10 -10
  154. package/dist/types/src/types/User.d.ts +6 -6
  155. package/dist/types/src/types/index.d.ts +218 -218
  156. package/dist/types/src/utils/blob.d.ts +3 -3
  157. package/dist/types/src/utils/colors.d.ts +13 -13
  158. package/dist/types/src/utils/cropper/avatar.d.ts +5 -5
  159. package/dist/types/src/utils/cropper/cover.d.ts +5 -5
  160. package/dist/types/src/utils/cropper/presetInterface.d.ts +7 -7
  161. package/dist/types/src/utils/cropper/presets.d.ts +6 -6
  162. package/dist/types/src/utils/fileSizeFormat.d.ts +1 -1
  163. package/dist/types/src/utils/fileValidations.d.ts +2 -2
  164. package/dist/types/src/utils/index.d.ts +6 -6
  165. package/dist/types/src/utils/resizeImageFromURI.d.ts +1 -1
  166. package/dist/types/src/utils/scrollPreventer.d.ts +3 -3
  167. package/dist/types/src/utils/toHumanList.d.ts +1 -1
  168. package/package.json +148 -141
  169. package/src/assets/flatpickr.css +243 -243
  170. package/src/assets/form.css +6 -6
  171. package/src/assets/main.css +36 -36
  172. package/src/assets/tailwind.css +2 -2
  173. package/src/components/BaseActionItem.vue +68 -68
  174. package/src/components/BaseActionItemButton.vue +77 -77
  175. package/src/components/BaseAddressForm.stories.js +103 -103
  176. package/src/components/BaseAddressForm.vue +354 -354
  177. package/src/components/BaseAlert.stories.js +52 -52
  178. package/src/components/BaseAlert.vue +158 -158
  179. package/src/components/BaseApp.vue +16 -16
  180. package/src/components/BaseAppDialogs.vue +123 -123
  181. package/src/components/BaseAppNotifications.vue +40 -40
  182. package/src/components/BaseAutocomplete.stories.js +236 -236
  183. package/src/components/BaseAutocomplete.vue +523 -523
  184. package/src/components/BaseAutocompleteDrawer.vue +372 -372
  185. package/src/components/BaseAutocompleteFetch.stories.js +224 -224
  186. package/src/components/BaseAutocompleteFetch.vue +288 -288
  187. package/src/components/BaseAvatar.stories.js +39 -39
  188. package/src/components/BaseAvatar.vue +120 -120
  189. package/src/components/BaseAvatarGroup.stories.js +71 -71
  190. package/src/components/BaseAvatarGroup.vue +148 -148
  191. package/src/components/BaseBadge.stories.js +124 -124
  192. package/src/components/BaseBadge.vue +87 -87
  193. package/src/components/BaseBelongsTo.stories.js +223 -223
  194. package/src/components/BaseBelongsTo.vue +193 -193
  195. package/src/components/BaseBoolean.stories.js +35 -35
  196. package/src/components/BaseBoolean.vue +26 -26
  197. package/src/components/BaseBreadcrumbs.stories.js +50 -50
  198. package/src/components/BaseBreadcrumbs.vue +109 -109
  199. package/src/components/BaseButton.stories.js +88 -88
  200. package/src/components/BaseButton.vue +46 -46
  201. package/src/components/BaseButtonGroup.stories.js +86 -86
  202. package/src/components/BaseButtonGroup.vue +150 -150
  203. package/src/components/BaseCalendar.stories.js +202 -0
  204. package/src/components/BaseCalendar.vue +216 -0
  205. package/src/components/BaseCard.stories.js +61 -61
  206. package/src/components/BaseCard.vue +49 -49
  207. package/src/components/BaseCardRow.vue +34 -34
  208. package/src/components/BaseCharacterCounter.stories.js +30 -30
  209. package/src/components/BaseCharacterCounter.vue +64 -64
  210. package/src/components/BaseClickOutside.vue +37 -37
  211. package/src/components/BaseClipboard.stories.js +32 -32
  212. package/src/components/BaseClipboard.vue +83 -83
  213. package/src/components/BaseColor.stories.js +46 -46
  214. package/src/components/BaseColor.vue +154 -154
  215. package/src/components/BaseContainer.stories.js +34 -34
  216. package/src/components/BaseContainer.vue +50 -50
  217. package/src/components/BaseCounter.stories.js +47 -47
  218. package/src/components/BaseCounter.vue +82 -82
  219. package/src/components/BaseCropper.stories.js +113 -113
  220. package/src/components/BaseCropper.vue +458 -458
  221. package/src/components/BaseCropperModal.stories.js +54 -54
  222. package/src/components/BaseCropperModal.vue +143 -143
  223. package/src/components/BaseDataIterator.stories.js +197 -197
  224. package/src/components/BaseDataIterator.vue +839 -839
  225. package/src/components/BaseDataIteratorSectionBox.vue +36 -36
  226. package/src/components/BaseDataIteratorSectionButton.vue +53 -53
  227. package/src/components/BaseDataIteratorSectionColumns.vue +70 -70
  228. package/src/components/BaseDataIteratorSectionModal.vue +41 -41
  229. package/src/components/BaseDataTable.stories.js +226 -226
  230. package/src/components/BaseDataTable.vue +779 -779
  231. package/src/components/BaseDataTableRowAction.vue +53 -53
  232. package/src/components/BaseDatePicker.stories.js +130 -130
  233. package/src/components/BaseDatePicker.vue +296 -296
  234. package/src/components/BaseDateSelect.stories.js +47 -47
  235. package/src/components/BaseDateSelect.vue +241 -241
  236. package/src/components/BaseDescriptionList.stories.js +35 -35
  237. package/src/components/BaseDescriptionList.vue +13 -13
  238. package/src/components/BaseDescriptionListItem.vue +47 -47
  239. package/src/components/BaseDialog.stories.js +51 -51
  240. package/src/components/BaseDialog.vue +119 -119
  241. package/src/components/BaseDisplayRelativeTime.stories.js +47 -47
  242. package/src/components/BaseDisplayRelativeTime.vue +122 -122
  243. package/src/components/BaseDraggable.vue +71 -71
  244. package/src/components/BaseDropdown.stories.js +210 -210
  245. package/src/components/BaseDropdown.vue +280 -280
  246. package/src/components/BaseDropdownAutocomplete.stories.js +187 -187
  247. package/src/components/BaseDropdownAutocomplete.vue +235 -236
  248. package/src/components/BaseField.vue +112 -112
  249. package/src/components/BaseFieldI18n.stories.js +38 -38
  250. package/src/components/BaseFieldI18n.vue +170 -170
  251. package/src/components/BaseFilePicker.stories.js +84 -84
  252. package/src/components/BaseFilePicker.vue +163 -163
  253. package/src/components/BaseFilePickerCrop.stories.js +135 -135
  254. package/src/components/BaseFilePickerCrop.vue +130 -130
  255. package/src/components/BaseFileUploader.stories.js +102 -102
  256. package/src/components/BaseFileUploader.vue +185 -185
  257. package/src/components/BaseForm.stories.js +48 -48
  258. package/src/components/BaseForm.vue +335 -335
  259. package/src/components/BaseGantt.stories.js +133 -133
  260. package/src/components/BaseGantt.vue +336 -336
  261. package/src/components/BaseHasMany.stories.js +189 -189
  262. package/src/components/BaseHasMany.vue +137 -137
  263. package/src/components/BaseHeader.stories.js +133 -133
  264. package/src/components/BaseHeader.vue +188 -188
  265. package/src/components/BaseIconPicker.stories.js +22 -22
  266. package/src/components/BaseIconPicker.vue +225 -225
  267. package/src/components/BaseInput.stories.js +167 -167
  268. package/src/components/BaseInput.vue +264 -264
  269. package/src/components/BaseInputError.vue +7 -7
  270. package/src/components/BaseInputLabel.stories.js +36 -36
  271. package/src/components/BaseInputLabel.vue +57 -57
  272. package/src/components/BaseInputPercent.stories.js +65 -65
  273. package/src/components/BaseInputPercent.vue +139 -139
  274. package/src/components/BaseLayoutNotificationDropdown.vue +150 -150
  275. package/src/components/BaseLayoutNotificationItem.vue +53 -53
  276. package/src/components/BaseLayoutNotificationItemContent.vue +30 -30
  277. package/src/components/BaseLayoutSidebar.vue +236 -236
  278. package/src/components/BaseLayoutSidebarConfigurable.stories.js +166 -166
  279. package/src/components/BaseLayoutSidebarConfigurable.vue +181 -181
  280. package/src/components/BaseLayoutStacked.vue +52 -52
  281. package/src/components/BaseLayoutStackedConfigurable.stories.js +109 -109
  282. package/src/components/BaseLayoutStackedConfigurable.vue +158 -158
  283. package/src/components/BaseLoadingCover.stories.js +55 -55
  284. package/src/components/BaseLoadingCover.vue +101 -101
  285. package/src/components/BaseMediaGallery.vue +96 -96
  286. package/src/components/BaseMediaGalleryItem.vue +101 -101
  287. package/src/components/BaseMediaItem.stories.js +41 -41
  288. package/src/components/BaseMediaItem.vue +80 -80
  289. package/src/components/BaseMediaLibrary.stories.js +267 -267
  290. package/src/components/BaseMediaLibrary.vue +342 -342
  291. package/src/components/BaseMediaList.vue +67 -67
  292. package/src/components/BaseMediaListItem.vue +212 -212
  293. package/src/components/BaseMediaPictures.vue +64 -64
  294. package/src/components/BaseMediaPicturesItem.vue +100 -100
  295. package/src/components/BaseMediaPreview.stories.js +72 -72
  296. package/src/components/BaseMediaPreview.vue +106 -106
  297. package/src/components/BaseMenu.stories.js +129 -129
  298. package/src/components/BaseMenu.vue +165 -165
  299. package/src/components/BaseMenuItem.vue +145 -145
  300. package/src/components/BaseModalCenter.stories.js +68 -68
  301. package/src/components/BaseModalCenter.vue +128 -128
  302. package/src/components/BaseModalSide.stories.js +55 -55
  303. package/src/components/BaseModalSide.vue +116 -116
  304. package/src/components/BaseNavbar.stories.js +151 -151
  305. package/src/components/BaseNavbar.vue +91 -91
  306. package/src/components/BaseNavbarItem.vue +49 -49
  307. package/src/components/BaseNavbarItemContent.vue +97 -97
  308. package/src/components/BaseNavbarSideItem.vue +114 -114
  309. package/src/components/BaseNavbarSideItemContent.vue +111 -111
  310. package/src/components/BasePagination.stories.js +35 -35
  311. package/src/components/BasePagination.vue +266 -266
  312. package/src/components/BasePanel.stories.js +56 -56
  313. package/src/components/BasePanel.vue +42 -42
  314. package/src/components/BasePassword.stories.js +57 -57
  315. package/src/components/BasePassword.vue +107 -107
  316. package/src/components/BaseProgressCircle.stories.js +27 -27
  317. package/src/components/BaseProgressCircle.vue +80 -80
  318. package/src/components/BaseRadioGroup.stories.js +88 -88
  319. package/src/components/BaseRadioGroup.vue +125 -125
  320. package/src/components/BaseReadMore.stories.js +30 -30
  321. package/src/components/BaseReadMore.vue +73 -73
  322. package/src/components/BaseRichText.stories.js +102 -102
  323. package/src/components/BaseRichText.vue +198 -198
  324. package/src/components/BaseSelect.stories.js +118 -118
  325. package/src/components/BaseSelect.vue +224 -224
  326. package/src/components/BaseShortcut.stories.js +102 -102
  327. package/src/components/BaseShortcut.vue +112 -112
  328. package/src/components/BaseSideNavigation.stories.js +85 -85
  329. package/src/components/BaseSideNavigation.vue +32 -32
  330. package/src/components/BaseSideNavigationItem.vue +95 -95
  331. package/src/components/BaseSkeleton.stories.js +36 -36
  332. package/src/components/BaseSkeleton.vue +40 -40
  333. package/src/components/BaseStatistic.stories.js +51 -51
  334. package/src/components/BaseStatistic.vue +106 -106
  335. package/src/components/BaseStepper.stories.js +94 -94
  336. package/src/components/BaseStepper.vue +72 -72
  337. package/src/components/BaseStepperItem.stories.js +65 -65
  338. package/src/components/BaseStepperItem.vue +149 -149
  339. package/src/components/BaseSwitch.stories.js +130 -130
  340. package/src/components/BaseSwitch.vue +215 -215
  341. package/src/components/BaseSystemAlert.stories.js +63 -63
  342. package/src/components/BaseSystemAlert.vue +89 -89
  343. package/src/components/BaseTabItem.vue +97 -97
  344. package/src/components/BaseTable.vue +904 -904
  345. package/src/components/BaseTableColumn.vue +124 -124
  346. package/src/components/BaseTabs.stories.js +85 -85
  347. package/src/components/BaseTabs.vue +73 -73
  348. package/src/components/BaseTagAutocomplete.stories.js +258 -258
  349. package/src/components/BaseTagAutocomplete.vue +438 -438
  350. package/src/components/BaseTagAutocompleteFetch.stories.js +185 -185
  351. package/src/components/BaseTagAutocompleteFetch.vue +220 -220
  352. package/src/components/BaseTextarea.stories.js +58 -58
  353. package/src/components/BaseTextarea.vue +103 -103
  354. package/src/components/BaseTextareaAutoresize.stories.js +102 -102
  355. package/src/components/BaseTextareaAutoresize.vue +166 -166
  356. package/src/components/BaseTimeline.stories.js +55 -55
  357. package/src/components/BaseTimeline.vue +38 -38
  358. package/src/components/BaseTimelineItem.stories.js +78 -78
  359. package/src/components/BaseTimelineItem.vue +90 -90
  360. package/src/components/BaseToast.stories.js +50 -50
  361. package/src/components/BaseToast.vue +43 -43
  362. package/src/components/BaseUniqueCode.stories.js +36 -36
  363. package/src/components/BaseUniqueCode.vue +183 -183
  364. package/src/components/SlotComponent.ts +37 -37
  365. package/src/components/index.ts +196 -194
  366. package/src/composables/breakpoints.ts +94 -94
  367. package/src/composables/clickOutside.ts +80 -80
  368. package/src/composables/field.ts +117 -117
  369. package/src/composables/hasOptions.ts +68 -68
  370. package/src/composables/mediaQuery.ts +42 -42
  371. package/src/composables/modal.ts +73 -73
  372. package/src/composables/paginatedData.ts +65 -65
  373. package/src/constants/MyConstants.ts +1 -1
  374. package/src/constants/index.ts +5 -5
  375. package/src/env.d.ts +15 -15
  376. package/src/i18n/index.ts +60 -60
  377. package/src/index.ts +114 -114
  378. package/src/lang/en.json +95 -89
  379. package/src/lang/fr.json +95 -89
  380. package/src/services/gantt/format.ts +113 -113
  381. package/src/services/gantt/timescale.ts +242 -242
  382. package/src/services/gantt/types.ts +74 -74
  383. package/src/stores/dialogs.ts +45 -45
  384. package/src/stores/i18n.ts +14 -14
  385. package/src/stores/notifications.ts +47 -47
  386. package/src/stores/systemAlerts.ts +32 -32
  387. package/src/stories/List.stories.js +132 -132
  388. package/src/stories/PageShow.vue +423 -423
  389. package/src/stories/Show.stories.js +22 -22
  390. package/src/svg/BaseEmptyState.vue +38 -38
  391. package/src/svg/BaseSpinnerLarge.vue +59 -59
  392. package/src/svg/BaseSpinnerSmall.vue +15 -15
  393. package/src/types/CalendarEvent.ts +9 -0
  394. package/src/types/Color.ts +9 -9
  395. package/src/types/Country.ts +4 -4
  396. package/src/types/ImagePickerResult.ts +5 -5
  397. package/src/types/Media.ts +10 -10
  398. package/src/types/Notification.ts +10 -10
  399. package/src/types/Region.ts +5 -5
  400. package/src/types/Status.ts +5 -5
  401. package/src/types/StepperItem.ts +8 -8
  402. package/src/types/TimelineItem.ts +9 -9
  403. package/src/types/UploadedFile.ts +11 -11
  404. package/src/types/User.ts +7 -7
  405. package/src/types/index.ts +267 -267
  406. package/src/utils/blob.ts +30 -30
  407. package/src/utils/colors.ts +210 -210
  408. package/src/utils/cropper/avatar.ts +33 -33
  409. package/src/utils/cropper/cover.ts +41 -41
  410. package/src/utils/cropper/presetInterface.ts +16 -16
  411. package/src/utils/cropper/presets.ts +7 -7
  412. package/src/utils/fileSizeFormat.ts +15 -15
  413. package/src/utils/fileValidations.ts +26 -26
  414. package/src/utils/index.ts +16 -16
  415. package/src/utils/resizeImageFromURI.ts +118 -118
  416. package/src/utils/scrollPreventer.ts +11 -11
  417. package/src/utils/toHumanList.ts +20 -20
@@ -1,839 +1,839 @@
1
- <template>
2
- <div ref="dataIteratorNode">
3
- <div
4
- class="grid w-full max-w-full grid-flow-row gap-4"
5
- :class="{
6
- 'grid-cols-[1fr_300px]': hasSidebar,
7
- }"
8
- >
9
- <div
10
- class="min-w-0"
11
- :class="{ 'col-span-1': !compactLayout, 'col-span-2': compactLayout }"
12
- >
13
- <!-- Header -->
14
- <div
15
- class="flex space-x-2 empty:mb-0"
16
- :class="{
17
- 'mb-2.5': size == 'sm',
18
- 'mb-4': size == 'md',
19
- }"
20
- >
21
- <!-- Search bar -->
22
- <div
23
- v-if="searchable"
24
- class="grow"
25
- >
26
- <div
27
- class="relative"
28
- :class="{
29
- 'h-9': size == 'sm',
30
- 'h-11': size == 'md',
31
- }"
32
- >
33
- <div
34
- class="pointer-events-none absolute left-0 top-0 flex h-full items-center justify-center pl-2.5"
35
- >
36
- <BaseIcon
37
- class="text-slate-400"
38
- :class="{
39
- 'h-5 w-5': size == 'sm',
40
- 'h-6 w-6': size == 'md',
41
- }"
42
- icon="heroicons:magnifying-glass"
43
- />
44
- </div>
45
- <input
46
- ref="searchInput"
47
- v-model="searchQuery"
48
- type="text"
49
- class="w-full h-full py-0 overflow-hidden rounded-md border border-slate-300 bg-white shadow-sm placeholder:font-light placeholder:text-sm focus:ring-blue-300 focus:ring-4"
50
- :class="{
51
- 'pl-9 pr-8': size == 'sm',
52
- 'pl-10 pr-9': size == 'md',
53
- }"
54
- :placeholder="t('sui.autocomplete_placeholder')"
55
- @input="onSearch"
56
- >
57
- <div
58
- v-if="searchQuery"
59
- class="absolute right-0 top-0 flex h-full items-center justify-center p-1"
60
- >
61
- <button
62
- type="button"
63
- class="flex appearance-none items-center rounded p-1 hover:bg-slate-100"
64
- @click="searchQuery = ''; onSearch('');"
65
- >
66
- <BaseIcon
67
- class="text-slate-500"
68
- :class="{
69
- 'h-5 w-5': size == 'sm',
70
- 'h-6 w-6': size == 'md',
71
- }"
72
- icon="heroicons:x-mark"
73
- />
74
- </button>
75
- </div>
76
- </div>
77
- </div>
78
-
79
- <template v-if="compactLayout">
80
- <template
81
- v-for="(section, i) in sectionsInternal"
82
- :key="section.name"
83
- >
84
- <BaseDataIteratorSectionButton
85
- :section="section"
86
- :size="size"
87
- @open="openSection(i)"
88
- />
89
- </template>
90
- </template>
91
-
92
- <!-- Menu -->
93
- <BaseMenu
94
- v-if="actions && actions.length"
95
- tw-menu="w-52"
96
- :size="size == 'sm' ? 'xs' : 'sm'"
97
- :items="actions"
98
- >
99
- <template #button="{ open }">
100
- <div
101
- class="flex items-center justify-center rounded-md border border-slate-300 bg-white shadow-sm duration-150 hover:bg-slate-50"
102
- :class="[
103
- open ? 'ring-2 ring-primary-500 ring-offset-2' : false,
104
- {
105
- 'h-9 w-9': size == 'sm',
106
- 'h-11 w-11': size == 'md',
107
- }
108
- ]"
109
- >
110
- <BaseIcon icon="heroicons-solid:dots-vertical" />
111
- </div>
112
- </template>
113
- </BaseMenu>
114
- </div>
115
-
116
- <slot
117
- :items="items"
118
- :loading="loading"
119
- :error="error"
120
- :first-load="firstLoad"
121
- :page="page"
122
- :sort-field="sortField"
123
- :sort-direction="sortDirection"
124
- :on-sort-change="onSortChange"
125
- :on-page-change="onPageChange"
126
- />
127
-
128
- <!-- Pagination -->
129
-
130
- <div
131
- v-if="paginationMetadata"
132
- class="mt-4"
133
- >
134
- <p
135
- class="text-center text-sm text-slate-500 sm:text-right [&>b]:font-medium [&>b]:text-slate-600"
136
- >
137
- {{ t('sui.pagination_detail_1') }}
138
-
139
- <b>{{ paginationStart }}</b> - <b>{{ paginationEnd }}</b>
140
-
141
- {{ t('sui.pagination_detail_2') }}
142
-
143
- <b>{{ paginationMetadata.total }}</b>
144
- </p>
145
- </div>
146
-
147
- <div
148
- v-if="paginationMetadata"
149
- class="mt-4"
150
- >
151
- <BasePagination
152
- :model-value="page"
153
- :last-page="lastPage"
154
- @update:model-value="onPageChange"
155
- />
156
- </div>
157
- </div>
158
-
159
- <div
160
- v-if="!compactLayout"
161
- ref="sidebar"
162
- class="space-y-3"
163
- >
164
- <slot
165
- name="sidebarTop"
166
- :pagination-metadata="paginationMetadata"
167
- />
168
-
169
- <template
170
- v-for="section in sectionsInternal"
171
- :key="section.name"
172
- >
173
- <BaseDataIteratorSectionBox :section="section">
174
- <slot
175
- :name="section.name"
176
- :query="query"
177
- :update-query="updateFilterQuery"
178
- :update-query-value="updateFilterQueryValue"
179
- />
180
- </BaseDataIteratorSectionBox>
181
- </template>
182
-
183
- <slot
184
- name="sidebarBottom"
185
- :pagination-metadata="paginationMetadata"
186
- />
187
- </div>
188
- </div>
189
-
190
- <template
191
- v-for="(section, i) in sectionsInternal"
192
- :key="section.name"
193
- >
194
- <BaseDataIteratorSectionModal
195
- :section="section"
196
- :model-value="sectionModalActive == i"
197
- @update:model-value="closeSection"
198
- >
199
- <slot
200
- :name="section.name"
201
- :query="query"
202
- :update-query="updateFilterQuery"
203
- :update-query-value="updateFilterQueryValue"
204
- />
205
- </BaseDataIteratorSectionModal>
206
- </template>
207
- </div>
208
- </template>
209
-
210
- <script lang="ts">
211
- /* eslint-disable @typescript-eslint/no-explicit-any */
212
- import { t } from '@/i18n';
213
- type Direction = 'asc' | 'desc';
214
-
215
- const DEFAULT_QUERY = {
216
- page: 1,
217
- search: '',
218
- sort: '',
219
- filter: {},
220
- } as DataTableQuery;
221
- </script>
222
-
223
- <script lang="ts" setup>
224
- import { cloneDeep, debounce, merge, set } from 'lodash';
225
- import hash from 'object-hash';
226
- import { PropType } from 'vue';
227
- import {
228
- Collection,
229
- DataIteratorSection,
230
- DataTableQuery,
231
- MenuItemInterface,
232
- PaginatedCollection,
233
- ResourceCollection,
234
- } from '@/types';
235
-
236
- import BaseMenu from './BaseMenu.vue';
237
- import BasePagination from './BasePagination.vue';
238
- import { config } from '@/index';
239
- import { useMutationObserver, useResizeObserver } from '@vueuse/core';
240
- import { useHasPaginatedData } from '@/composables/paginatedData';
241
- import BaseDataIteratorSectionButton from './BaseDataIteratorSectionButton.vue';
242
- import BaseDataIteratorSectionModal from './BaseDataIteratorSectionModal.vue';
243
- import BaseDataIteratorSectionBox from './BaseDataIteratorSectionBox.vue';
244
-
245
- const props = defineProps({
246
- /**
247
- * Base URL from which to make requests
248
- */
249
- url: {
250
- required: true,
251
- type: String,
252
- },
253
-
254
- /**
255
- * Query params that always get applied.
256
- * To add overwrite-able query params, use defaultQuery.
257
- */
258
- urlQuery: {
259
- default: undefined,
260
- type: Object as PropType<Record<string, any>>,
261
- },
262
-
263
- /**
264
- * Query params that gets applied by default.
265
- * These may be overwritten by URL params generated by the data-table or filters
266
- * To add query params that are always active, use urlQuery.
267
- */
268
- defaultQuery: {
269
- default: function () {
270
- return DEFAULT_QUERY;
271
- },
272
- type: Object as PropType<DataTableQuery>,
273
- },
274
-
275
- /**
276
- * Add a search bar.
277
- */
278
- searchable: {
279
- default: true,
280
- type: Boolean,
281
- },
282
-
283
- /**
284
- * Configure contextual actions.
285
- */
286
- actions: {
287
- default: undefined,
288
- type: Array as PropType<MenuItemInterface[]>,
289
- },
290
-
291
- /**
292
- * Save data table state in URL.
293
- */
294
- historyMode: {
295
- default: false,
296
- type: Boolean,
297
- },
298
-
299
- /**
300
- * Layout type
301
- */
302
- layout: {
303
- default: 'default',
304
- type: String as PropType<'default' | 'compact'>,
305
- },
306
-
307
- /**
308
- * Overall size and spacing of the component
309
- */
310
- size: {
311
- default: 'md',
312
- type: String as PropType<'sm' | 'md'>,
313
- },
314
-
315
- /**
316
- * Sections
317
- */
318
- sections: {
319
- default: undefined,
320
- type: Array as PropType<DataIteratorSection[]>,
321
- },
322
-
323
- /**
324
- * Scroll to top when fetching new data
325
- */
326
- scrollTopOnFetch: {
327
- default: true,
328
- type: Boolean,
329
- },
330
- });
331
-
332
- const http = config.http;
333
-
334
- const emit = defineEmits([
335
- 'click',
336
- 'delete',
337
- 'checkAll',
338
- 'update:checked-rows',
339
- 'check',
340
- 'update:query',
341
- 'will-scroll-top',
342
- 'fetch',
343
- ]);
344
-
345
- const dataIteratorNode = ref<null | HTMLElement>(null);
346
- const searchInput = ref<null | HTMLInputElement>(null);
347
-
348
- const route = useRoute();
349
- const router = useRouter();
350
- const routeName = route.name;
351
-
352
- let willUnmount = false;
353
-
354
- onBeforeUnmount(() => {
355
- willUnmount = true;
356
- });
357
-
358
- const width = ref(800);
359
- useResizeObserver(dataIteratorNode, () => {
360
- width.value = dataIteratorNode.value?.clientWidth ?? 800;
361
- });
362
-
363
- /** Data table state */
364
-
365
- const firstLoad = ref(false);
366
- const loading = ref(true);
367
- const error = ref(false);
368
- const searchQuery = ref('');
369
-
370
- let lastUrl = '';
371
- let lastQueryHash = '';
372
-
373
- // eslint-disable-next-line vue/no-setup-props-destructure
374
- const query = ref<DataTableQuery>(cloneDeep(props.defaultQuery));
375
- const slots = useSlots();
376
-
377
- const compactLayout = computed(() => {
378
- if (props.layout === 'compact') {
379
- return true;
380
- }
381
- return width.value < 1024;
382
- });
383
-
384
- const hasFilters = computed((): boolean => {
385
- const numberOfFilterSlots = slots.filters;
386
- return numberOfFilterSlots !== undefined;
387
- });
388
-
389
- /*
390
- |--------------------------------------------------------------------------
391
- | Has sidebar observer
392
- |--------------------------------------------------------------------------
393
- */
394
-
395
- const hasSidebar = ref(false);
396
- const sidebar = ref<null | HTMLElement>(null);
397
-
398
- function checkIfSidebarIsEmpty() {
399
- hasSidebar.value = (sidebar?.value?.childElementCount ?? 0) > 0;
400
- }
401
-
402
- const checkIfSidebarIsEmptyDebounce = debounce(checkIfSidebarIsEmpty, 100);
403
-
404
- useMutationObserver(sidebar, checkIfSidebarIsEmptyDebounce, {
405
- attributes: false,
406
- childList: true,
407
- });
408
-
409
- onMounted(() => {
410
- checkIfSidebarIsEmpty();
411
- });
412
-
413
- watch(
414
- () => compactLayout.value,
415
- () => {
416
- // After the sidebar appears...
417
- nextTick(() => {
418
- checkIfSidebarIsEmpty();
419
- });
420
- }
421
- );
422
-
423
- /*
424
- |--------------------------------------------------------------------------
425
- | Query params
426
- |--------------------------------------------------------------------------
427
- */
428
-
429
- function updateFilterQueryValue(key: string, value: any) {
430
- let newQuery = cloneDeep(query.value);
431
- newQuery = set(newQuery, key, value);
432
- newQuery = set(newQuery, 'page', 1);
433
- updateQuery(newQuery);
434
- }
435
-
436
- function updateFilterQuery(newQuery: DataTableQuery) {
437
- newQuery = set(newQuery, 'page', 1);
438
- updateQuery(newQuery);
439
- }
440
-
441
- function updateQuery(newQuery: DataTableQuery) {
442
- if (!props.historyMode) {
443
- query.value = newQuery;
444
- fetch();
445
- return;
446
- }
447
-
448
- if (route.name === null) {
449
- throw new Error('Route name is required for history mode');
450
- }
451
-
452
- const newRoute = router.resolve({
453
- name: route.name,
454
- params: route.params,
455
- });
456
-
457
- const newParams = config.formatQueryString(newQuery);
458
- const newRoutePath = newRoute.fullPath + '?' + newParams;
459
-
460
- const oldParamString = getRouteQuery();
461
- const oldParams = config.formatQueryString(oldParamString);
462
-
463
- // Push new route if different
464
- if (oldParams != newParams) {
465
- if (!firstLoad.value) {
466
- router.replace(newRoutePath);
467
- return;
468
- }
469
- router.push(newRoutePath);
470
- return;
471
- }
472
-
473
- // If the URL is unchanged, we must manually trigger the fetch() method
474
- // on first load.
475
-
476
- if (!firstLoad.value) {
477
- query.value = newQuery;
478
- fetch();
479
- }
480
- }
481
-
482
- function queryHash(query: DataTableQuery): string {
483
- return hash(query);
484
- }
485
-
486
- /*
487
- |--------------------------------------------------------------------------
488
- | Data fetching
489
- |--------------------------------------------------------------------------
490
- */
491
-
492
- const url = computed<string>(() => {
493
- return props.url;
494
- });
495
-
496
- /*
497
- |--------------------------------------------------------------------------
498
- | Handlers
499
- |--------------------------------------------------------------------------
500
- */
501
-
502
- function onPageChange(p: number) {
503
- const newQuery = cloneDeep(query.value);
504
-
505
- newQuery.page = p;
506
-
507
- updateQuery(newQuery);
508
-
509
- scrollIntoView();
510
- }
511
-
512
- function onSortChange(field: string, direction: Direction) {
513
- let newSort = field;
514
-
515
- if (newSort && direction == 'desc') {
516
- newSort = '-' + newSort;
517
- }
518
-
519
- const newQuery = cloneDeep(query.value);
520
-
521
- newQuery.page = 1;
522
- newQuery.sort = newSort;
523
-
524
- updateQuery(newQuery);
525
- }
526
-
527
- const onSearch = debounce((event: any) => {
528
- const newQuery = cloneDeep(query.value);
529
-
530
- newQuery.page = 1;
531
- newQuery.search = searchQuery.value;
532
-
533
- updateQuery(newQuery);
534
- }, 350);
535
-
536
- /*
537
- |--------------------------------------------------------------------------
538
- | Route watcher
539
- |--------------------------------------------------------------------------
540
- */
541
-
542
- watch(
543
- () => route.query,
544
- () => {
545
- // Wait for the willUnmount flag to be set
546
- nextTick(() => {
547
- onRouteChange();
548
- });
549
- }
550
- );
551
-
552
- watch(
553
- () => props.url,
554
- () => {
555
- fetch();
556
- }
557
- );
558
-
559
- watch(
560
- () => props.urlQuery,
561
- () => {
562
- fetch();
563
- }
564
- );
565
-
566
- function getRouteQuery() {
567
- return config.parseQueryString(window.location.search.replace(/^(\?)/, ''));
568
- }
569
-
570
- function onRouteChange() {
571
- if (!props.historyMode) {
572
- return;
573
- }
574
-
575
- if (willUnmount) {
576
- return;
577
- }
578
-
579
- // Stop if route was changed
580
- if (route.name != routeName) {
581
- return;
582
- }
583
-
584
- const routeQuery = getRouteQuery();
585
- const newQuery = routeQuery as DataTableQuery;
586
-
587
- const newQueryHash = queryHash(newQuery);
588
-
589
- if (newQueryHash == lastQueryHash) {
590
- return;
591
- }
592
-
593
- lastQueryHash = newQueryHash;
594
-
595
- query.value = newQuery;
596
-
597
- // Update search input if not in focus
598
- if (searchInput.value && searchInput.value !== document.activeElement) {
599
- updateSearchInput();
600
- }
601
-
602
- fetch();
603
- }
604
-
605
- /*
606
- |--------------------------------------------------------------------------
607
- | Fetch
608
- |--------------------------------------------------------------------------
609
- */
610
-
611
- function fetchWithLoading(force = false) {
612
- fetch(force, true);
613
- }
614
-
615
- function fetchWithoutLoading(force = false) {
616
- fetch(force, false);
617
- }
618
-
619
- function fetch(force = false, showLoading = true) {
620
- if (willUnmount) {
621
- return;
622
- }
623
-
624
- const urlSplit = url.value.split(/[?#]/);
625
-
626
- const baseUrl = urlSplit[0];
627
- const urlQueryString = urlSplit[1] ?? null;
628
- const urlQuery = config.parseQueryString(urlQueryString);
629
-
630
- // Ordered by priority
631
- const allParams = merge(
632
- cloneDeep(query.value),
633
- cloneDeep(props.urlQuery),
634
- cloneDeep(urlQuery)
635
- );
636
-
637
- const queryString = config.formatQueryString(allParams);
638
-
639
- const fullUrl = baseUrl + '?' + queryString;
640
-
641
- if (lastUrl == fullUrl && !force) {
642
- return;
643
- }
644
-
645
- if (showLoading) {
646
- loading.value = true;
647
- }
648
-
649
- lastUrl = fullUrl;
650
-
651
- http
652
- .get(fullUrl)
653
- .then((response) => {
654
- data.value = response.data;
655
- loading.value = false;
656
- error.value = false;
657
- firstLoad.value = true;
658
- emit('fetch', data.value);
659
- })
660
- .catch(() => {
661
- data.value = null;
662
- loading.value = false;
663
- error.value = true;
664
- })
665
- .finally(() => {
666
- loading.value = false;
667
- });
668
- }
669
-
670
- /*
671
- |--------------------------------------------------------------------------
672
- | Data parsing
673
- |--------------------------------------------------------------------------
674
- */
675
-
676
- const data = ref<null | ResourceCollection | PaginatedCollection | Collection>(
677
- null
678
- );
679
-
680
- const { items, paginationMetadata, lastPage } = useHasPaginatedData(data);
681
-
682
- const page = computed((): number => {
683
- if (query.value.page && parseInt(query.value.page + '')) {
684
- return parseInt(query.value.page + '');
685
- }
686
- return 1;
687
- });
688
-
689
- const sortField = computed((): string => {
690
- return query.value.sort?.trim().replace(/^(-)/, '') ?? '';
691
- });
692
-
693
- const sortDirection = computed((): Direction => {
694
- if (query.value.sort && query.value.sort.length) {
695
- if (query.value.sort[0] == '-') {
696
- return 'desc';
697
- }
698
- }
699
- return 'asc';
700
- });
701
-
702
- const searchKeywords = computed((): string => {
703
- return query.value.search ?? '';
704
- });
705
-
706
- /*
707
- |--------------------------------------------------------------------------
708
- | Helpers
709
- |--------------------------------------------------------------------------
710
- */
711
-
712
- /** Scroll into view */
713
-
714
- const scrollIntoView = () => {
715
- emit('will-scroll-top');
716
-
717
- if (!props.scrollTopOnFetch) {
718
- return;
719
- }
720
-
721
- scrollIntoViewAction();
722
- };
723
-
724
- const scrollIntoViewAction = () => {
725
- if (dataIteratorNode.value == null) {
726
- return;
727
- }
728
-
729
- dataIteratorNode.value.scrollIntoView({
730
- behavior: 'smooth',
731
- });
732
- };
733
-
734
- function updateSearchInput() {
735
- searchQuery.value = searchKeywords.value;
736
- }
737
-
738
- const paginationStart = computed(() => {
739
- if (paginationMetadata.value == null) {
740
- return '';
741
- }
742
-
743
- return (
744
- paginationMetadata.value.per_page *
745
- (paginationMetadata.value.current_page - 1) +
746
- 1
747
- );
748
- });
749
-
750
- const paginationEnd = computed(() => {
751
- if (paginationMetadata.value == null) {
752
- return '';
753
- }
754
-
755
- return Math.min(
756
- paginationMetadata.value.current_page * paginationMetadata.value.per_page,
757
- paginationMetadata.value.total
758
- );
759
- });
760
-
761
- /*
762
- |--------------------------------------------------------------------------
763
- | Created
764
- |--------------------------------------------------------------------------
765
- */
766
-
767
- let newQuery = cloneDeep(query.value);
768
- const routeQuery = getRouteQuery();
769
-
770
- newQuery = merge(newQuery, routeQuery);
771
-
772
- updateQuery(newQuery);
773
-
774
- // Update search input on first load
775
- onMounted(() => {
776
- updateSearchInput();
777
- });
778
-
779
- /*
780
- |--------------------------------------------------------------------------
781
- | Sections
782
- |--------------------------------------------------------------------------
783
- */
784
-
785
- const sectionModalActive = ref<null | number>(null);
786
-
787
- const sectionsInternal = computed<DataIteratorSection[]>(() => {
788
- const sections = props.sections ?? [];
789
-
790
- if (hasFilters.value) {
791
- return [
792
- {
793
- name: 'filters',
794
- title: t('sui.filters'),
795
- closeText: t('sui.apply_filters'),
796
- icon: 'heroicons:funnel',
797
- opened: true,
798
- },
799
- ...sections,
800
- ];
801
- }
802
-
803
- return sections;
804
- });
805
-
806
- function openSection(index: number) {
807
- if (sectionsInternal.value[index]) {
808
- sectionModalActive.value = index;
809
- } else {
810
- sectionModalActive.value = null;
811
- }
812
- }
813
-
814
- function closeSection() {
815
- sectionModalActive.value = null;
816
- }
817
-
818
- /*
819
- |--------------------------------------------------------------------------
820
- | Provide
821
- |--------------------------------------------------------------------------
822
- */
823
-
824
- provide('dataIterator:width', width);
825
-
826
- /*
827
- |--------------------------------------------------------------------------
828
- | Exposed API
829
- |--------------------------------------------------------------------------
830
- */
831
-
832
- defineExpose({
833
- fetch: () => fetch(true),
834
- fetchWithLoading: () => fetchWithLoading(true),
835
- fetchWithoutLoading: () => fetchWithoutLoading(true),
836
- scrollIntoView: scrollIntoViewAction,
837
- query,
838
- });
839
- </script>
1
+ <template>
2
+ <div ref="dataIteratorNode">
3
+ <div
4
+ class="grid w-full max-w-full grid-flow-row gap-4"
5
+ :class="{
6
+ 'grid-cols-[1fr_300px]': hasSidebar,
7
+ }"
8
+ >
9
+ <div
10
+ class="min-w-0"
11
+ :class="{ 'col-span-1': !compactLayout, 'col-span-2': compactLayout }"
12
+ >
13
+ <!-- Header -->
14
+ <div
15
+ class="flex space-x-2 empty:mb-0"
16
+ :class="{
17
+ 'mb-2.5': size == 'sm',
18
+ 'mb-4': size == 'md',
19
+ }"
20
+ >
21
+ <!-- Search bar -->
22
+ <div
23
+ v-if="searchable"
24
+ class="grow"
25
+ >
26
+ <div
27
+ class="relative"
28
+ :class="{
29
+ 'h-9': size == 'sm',
30
+ 'h-11': size == 'md',
31
+ }"
32
+ >
33
+ <div
34
+ class="pointer-events-none absolute left-0 top-0 flex h-full items-center justify-center pl-2.5"
35
+ >
36
+ <BaseIcon
37
+ class="text-slate-400"
38
+ :class="{
39
+ 'h-5 w-5': size == 'sm',
40
+ 'h-6 w-6': size == 'md',
41
+ }"
42
+ icon="heroicons:magnifying-glass"
43
+ />
44
+ </div>
45
+ <input
46
+ ref="searchInput"
47
+ v-model="searchQuery"
48
+ type="text"
49
+ class="w-full h-full py-0 overflow-hidden rounded-md border border-slate-300 bg-white shadow-sm placeholder:font-light placeholder:text-sm focus:ring-blue-300 focus:ring-4"
50
+ :class="{
51
+ 'pl-9 pr-8': size == 'sm',
52
+ 'pl-10 pr-9': size == 'md',
53
+ }"
54
+ :placeholder="t('sui.autocomplete_placeholder')"
55
+ @input="onSearch"
56
+ >
57
+ <div
58
+ v-if="searchQuery"
59
+ class="absolute right-0 top-0 flex h-full items-center justify-center p-1"
60
+ >
61
+ <button
62
+ type="button"
63
+ class="flex appearance-none items-center rounded p-1 hover:bg-slate-100"
64
+ @click="searchQuery = ''; onSearch('');"
65
+ >
66
+ <BaseIcon
67
+ class="text-slate-500"
68
+ :class="{
69
+ 'h-5 w-5': size == 'sm',
70
+ 'h-6 w-6': size == 'md',
71
+ }"
72
+ icon="heroicons:x-mark"
73
+ />
74
+ </button>
75
+ </div>
76
+ </div>
77
+ </div>
78
+
79
+ <template v-if="compactLayout">
80
+ <template
81
+ v-for="(section, i) in sectionsInternal"
82
+ :key="section.name"
83
+ >
84
+ <BaseDataIteratorSectionButton
85
+ :section="section"
86
+ :size="size"
87
+ @open="openSection(i)"
88
+ />
89
+ </template>
90
+ </template>
91
+
92
+ <!-- Menu -->
93
+ <BaseMenu
94
+ v-if="actions && actions.length"
95
+ tw-menu="w-52"
96
+ :size="size == 'sm' ? 'xs' : 'sm'"
97
+ :items="actions"
98
+ >
99
+ <template #button="{ open }">
100
+ <div
101
+ class="flex items-center justify-center rounded-md border border-slate-300 bg-white shadow-sm duration-150 hover:bg-slate-50"
102
+ :class="[
103
+ open ? 'ring-2 ring-primary-500 ring-offset-2' : false,
104
+ {
105
+ 'h-9 w-9': size == 'sm',
106
+ 'h-11 w-11': size == 'md',
107
+ }
108
+ ]"
109
+ >
110
+ <BaseIcon icon="heroicons-solid:dots-vertical" />
111
+ </div>
112
+ </template>
113
+ </BaseMenu>
114
+ </div>
115
+
116
+ <slot
117
+ :items="items"
118
+ :loading="loading"
119
+ :error="error"
120
+ :first-load="firstLoad"
121
+ :page="page"
122
+ :sort-field="sortField"
123
+ :sort-direction="sortDirection"
124
+ :on-sort-change="onSortChange"
125
+ :on-page-change="onPageChange"
126
+ />
127
+
128
+ <!-- Pagination -->
129
+
130
+ <div
131
+ v-if="paginationMetadata"
132
+ class="mt-4"
133
+ >
134
+ <p
135
+ class="text-center text-sm text-slate-500 sm:text-right [&>b]:font-medium [&>b]:text-slate-600"
136
+ >
137
+ {{ t('sui.pagination_detail_1') }}
138
+
139
+ <b>{{ paginationStart }}</b> - <b>{{ paginationEnd }}</b>
140
+
141
+ {{ t('sui.pagination_detail_2') }}
142
+
143
+ <b>{{ paginationMetadata.total }}</b>
144
+ </p>
145
+ </div>
146
+
147
+ <div
148
+ v-if="paginationMetadata"
149
+ class="mt-4"
150
+ >
151
+ <BasePagination
152
+ :model-value="page"
153
+ :last-page="lastPage"
154
+ @update:model-value="onPageChange"
155
+ />
156
+ </div>
157
+ </div>
158
+
159
+ <div
160
+ v-if="!compactLayout"
161
+ ref="sidebar"
162
+ class="space-y-3"
163
+ >
164
+ <slot
165
+ name="sidebarTop"
166
+ :pagination-metadata="paginationMetadata"
167
+ />
168
+
169
+ <template
170
+ v-for="section in sectionsInternal"
171
+ :key="section.name"
172
+ >
173
+ <BaseDataIteratorSectionBox :section="section">
174
+ <slot
175
+ :name="section.name"
176
+ :query="query"
177
+ :update-query="updateFilterQuery"
178
+ :update-query-value="updateFilterQueryValue"
179
+ />
180
+ </BaseDataIteratorSectionBox>
181
+ </template>
182
+
183
+ <slot
184
+ name="sidebarBottom"
185
+ :pagination-metadata="paginationMetadata"
186
+ />
187
+ </div>
188
+ </div>
189
+
190
+ <template
191
+ v-for="(section, i) in sectionsInternal"
192
+ :key="section.name"
193
+ >
194
+ <BaseDataIteratorSectionModal
195
+ :section="section"
196
+ :model-value="sectionModalActive == i"
197
+ @update:model-value="closeSection"
198
+ >
199
+ <slot
200
+ :name="section.name"
201
+ :query="query"
202
+ :update-query="updateFilterQuery"
203
+ :update-query-value="updateFilterQueryValue"
204
+ />
205
+ </BaseDataIteratorSectionModal>
206
+ </template>
207
+ </div>
208
+ </template>
209
+
210
+ <script lang="ts">
211
+ /* eslint-disable @typescript-eslint/no-explicit-any */
212
+ import { t } from '@/i18n';
213
+ type Direction = 'asc' | 'desc';
214
+
215
+ const DEFAULT_QUERY = {
216
+ page: 1,
217
+ search: '',
218
+ sort: '',
219
+ filter: {},
220
+ } as DataTableQuery;
221
+ </script>
222
+
223
+ <script lang="ts" setup>
224
+ import { cloneDeep, debounce, merge, set } from 'lodash';
225
+ import hash from 'object-hash';
226
+ import { PropType } from 'vue';
227
+ import {
228
+ Collection,
229
+ DataIteratorSection,
230
+ DataTableQuery,
231
+ MenuItemInterface,
232
+ PaginatedCollection,
233
+ ResourceCollection,
234
+ } from '@/types';
235
+
236
+ import BaseMenu from './BaseMenu.vue';
237
+ import BasePagination from './BasePagination.vue';
238
+ import { config } from '@/index';
239
+ import { useMutationObserver, useResizeObserver } from '@vueuse/core';
240
+ import { useHasPaginatedData } from '@/composables/paginatedData';
241
+ import BaseDataIteratorSectionButton from './BaseDataIteratorSectionButton.vue';
242
+ import BaseDataIteratorSectionModal from './BaseDataIteratorSectionModal.vue';
243
+ import BaseDataIteratorSectionBox from './BaseDataIteratorSectionBox.vue';
244
+
245
+ const props = defineProps({
246
+ /**
247
+ * Base URL from which to make requests
248
+ */
249
+ url: {
250
+ required: true,
251
+ type: String,
252
+ },
253
+
254
+ /**
255
+ * Query params that always get applied.
256
+ * To add overwrite-able query params, use defaultQuery.
257
+ */
258
+ urlQuery: {
259
+ default: undefined,
260
+ type: Object as PropType<Record<string, any>>,
261
+ },
262
+
263
+ /**
264
+ * Query params that gets applied by default.
265
+ * These may be overwritten by URL params generated by the data-table or filters
266
+ * To add query params that are always active, use urlQuery.
267
+ */
268
+ defaultQuery: {
269
+ default: function () {
270
+ return DEFAULT_QUERY;
271
+ },
272
+ type: Object as PropType<DataTableQuery>,
273
+ },
274
+
275
+ /**
276
+ * Add a search bar.
277
+ */
278
+ searchable: {
279
+ default: true,
280
+ type: Boolean,
281
+ },
282
+
283
+ /**
284
+ * Configure contextual actions.
285
+ */
286
+ actions: {
287
+ default: undefined,
288
+ type: Array as PropType<MenuItemInterface[]>,
289
+ },
290
+
291
+ /**
292
+ * Save data table state in URL.
293
+ */
294
+ historyMode: {
295
+ default: false,
296
+ type: Boolean,
297
+ },
298
+
299
+ /**
300
+ * Layout type
301
+ */
302
+ layout: {
303
+ default: 'default',
304
+ type: String as PropType<'default' | 'compact'>,
305
+ },
306
+
307
+ /**
308
+ * Overall size and spacing of the component
309
+ */
310
+ size: {
311
+ default: 'md',
312
+ type: String as PropType<'sm' | 'md'>,
313
+ },
314
+
315
+ /**
316
+ * Sections
317
+ */
318
+ sections: {
319
+ default: undefined,
320
+ type: Array as PropType<DataIteratorSection[]>,
321
+ },
322
+
323
+ /**
324
+ * Scroll to top when fetching new data
325
+ */
326
+ scrollTopOnFetch: {
327
+ default: true,
328
+ type: Boolean,
329
+ },
330
+ });
331
+
332
+ const http = config.http;
333
+
334
+ const emit = defineEmits([
335
+ 'click',
336
+ 'delete',
337
+ 'checkAll',
338
+ 'update:checked-rows',
339
+ 'check',
340
+ 'update:query',
341
+ 'will-scroll-top',
342
+ 'fetch',
343
+ ]);
344
+
345
+ const dataIteratorNode = ref<null | HTMLElement>(null);
346
+ const searchInput = ref<null | HTMLInputElement>(null);
347
+
348
+ const route = useRoute();
349
+ const router = useRouter();
350
+ const routeName = route.name;
351
+
352
+ let willUnmount = false;
353
+
354
+ onBeforeUnmount(() => {
355
+ willUnmount = true;
356
+ });
357
+
358
+ const width = ref(800);
359
+ useResizeObserver(dataIteratorNode, () => {
360
+ width.value = dataIteratorNode.value?.clientWidth ?? 800;
361
+ });
362
+
363
+ /** Data table state */
364
+
365
+ const firstLoad = ref(false);
366
+ const loading = ref(true);
367
+ const error = ref(false);
368
+ const searchQuery = ref('');
369
+
370
+ let lastUrl = '';
371
+ let lastQueryHash = '';
372
+
373
+ // eslint-disable-next-line vue/no-setup-props-destructure
374
+ const query = ref<DataTableQuery>(cloneDeep(props.defaultQuery));
375
+ const slots = useSlots();
376
+
377
+ const compactLayout = computed(() => {
378
+ if (props.layout === 'compact') {
379
+ return true;
380
+ }
381
+ return width.value < 1024;
382
+ });
383
+
384
+ const hasFilters = computed((): boolean => {
385
+ const numberOfFilterSlots = slots.filters;
386
+ return numberOfFilterSlots !== undefined;
387
+ });
388
+
389
+ /*
390
+ |--------------------------------------------------------------------------
391
+ | Has sidebar observer
392
+ |--------------------------------------------------------------------------
393
+ */
394
+
395
+ const hasSidebar = ref(false);
396
+ const sidebar = ref<null | HTMLElement>(null);
397
+
398
+ function checkIfSidebarIsEmpty() {
399
+ hasSidebar.value = (sidebar?.value?.childElementCount ?? 0) > 0;
400
+ }
401
+
402
+ const checkIfSidebarIsEmptyDebounce = debounce(checkIfSidebarIsEmpty, 100);
403
+
404
+ useMutationObserver(sidebar, checkIfSidebarIsEmptyDebounce, {
405
+ attributes: false,
406
+ childList: true,
407
+ });
408
+
409
+ onMounted(() => {
410
+ checkIfSidebarIsEmpty();
411
+ });
412
+
413
+ watch(
414
+ () => compactLayout.value,
415
+ () => {
416
+ // After the sidebar appears...
417
+ nextTick(() => {
418
+ checkIfSidebarIsEmpty();
419
+ });
420
+ }
421
+ );
422
+
423
+ /*
424
+ |--------------------------------------------------------------------------
425
+ | Query params
426
+ |--------------------------------------------------------------------------
427
+ */
428
+
429
+ function updateFilterQueryValue(key: string, value: any) {
430
+ let newQuery = cloneDeep(query.value);
431
+ newQuery = set(newQuery, key, value);
432
+ newQuery = set(newQuery, 'page', 1);
433
+ updateQuery(newQuery);
434
+ }
435
+
436
+ function updateFilterQuery(newQuery: DataTableQuery) {
437
+ newQuery = set(newQuery, 'page', 1);
438
+ updateQuery(newQuery);
439
+ }
440
+
441
+ function updateQuery(newQuery: DataTableQuery) {
442
+ if (!props.historyMode) {
443
+ query.value = newQuery;
444
+ fetch();
445
+ return;
446
+ }
447
+
448
+ if (route.name === null) {
449
+ throw new Error('Route name is required for history mode');
450
+ }
451
+
452
+ const newRoute = router.resolve({
453
+ name: route.name,
454
+ params: route.params,
455
+ });
456
+
457
+ const newParams = config.formatQueryString(newQuery);
458
+ const newRoutePath = newRoute.fullPath + '?' + newParams;
459
+
460
+ const oldParamString = getRouteQuery();
461
+ const oldParams = config.formatQueryString(oldParamString);
462
+
463
+ // Push new route if different
464
+ if (oldParams != newParams) {
465
+ if (!firstLoad.value) {
466
+ router.replace(newRoutePath);
467
+ return;
468
+ }
469
+ router.push(newRoutePath);
470
+ return;
471
+ }
472
+
473
+ // If the URL is unchanged, we must manually trigger the fetch() method
474
+ // on first load.
475
+
476
+ if (!firstLoad.value) {
477
+ query.value = newQuery;
478
+ fetch();
479
+ }
480
+ }
481
+
482
+ function queryHash(query: DataTableQuery): string {
483
+ return hash(query);
484
+ }
485
+
486
+ /*
487
+ |--------------------------------------------------------------------------
488
+ | Data fetching
489
+ |--------------------------------------------------------------------------
490
+ */
491
+
492
+ const url = computed<string>(() => {
493
+ return props.url;
494
+ });
495
+
496
+ /*
497
+ |--------------------------------------------------------------------------
498
+ | Handlers
499
+ |--------------------------------------------------------------------------
500
+ */
501
+
502
+ function onPageChange(p: number) {
503
+ const newQuery = cloneDeep(query.value);
504
+
505
+ newQuery.page = p;
506
+
507
+ updateQuery(newQuery);
508
+
509
+ scrollIntoView();
510
+ }
511
+
512
+ function onSortChange(field: string, direction: Direction) {
513
+ let newSort = field;
514
+
515
+ if (newSort && direction == 'desc') {
516
+ newSort = '-' + newSort;
517
+ }
518
+
519
+ const newQuery = cloneDeep(query.value);
520
+
521
+ newQuery.page = 1;
522
+ newQuery.sort = newSort;
523
+
524
+ updateQuery(newQuery);
525
+ }
526
+
527
+ const onSearch = debounce((event: any) => {
528
+ const newQuery = cloneDeep(query.value);
529
+
530
+ newQuery.page = 1;
531
+ newQuery.search = searchQuery.value;
532
+
533
+ updateQuery(newQuery);
534
+ }, 350);
535
+
536
+ /*
537
+ |--------------------------------------------------------------------------
538
+ | Route watcher
539
+ |--------------------------------------------------------------------------
540
+ */
541
+
542
+ watch(
543
+ () => route.query,
544
+ () => {
545
+ // Wait for the willUnmount flag to be set
546
+ nextTick(() => {
547
+ onRouteChange();
548
+ });
549
+ }
550
+ );
551
+
552
+ watch(
553
+ () => props.url,
554
+ () => {
555
+ fetch();
556
+ }
557
+ );
558
+
559
+ watch(
560
+ () => props.urlQuery,
561
+ () => {
562
+ fetch();
563
+ }
564
+ );
565
+
566
+ function getRouteQuery() {
567
+ return config.parseQueryString(window.location.search.replace(/^(\?)/, ''));
568
+ }
569
+
570
+ function onRouteChange() {
571
+ if (!props.historyMode) {
572
+ return;
573
+ }
574
+
575
+ if (willUnmount) {
576
+ return;
577
+ }
578
+
579
+ // Stop if route was changed
580
+ if (route.name != routeName) {
581
+ return;
582
+ }
583
+
584
+ const routeQuery = getRouteQuery();
585
+ const newQuery = routeQuery as DataTableQuery;
586
+
587
+ const newQueryHash = queryHash(newQuery);
588
+
589
+ if (newQueryHash == lastQueryHash) {
590
+ return;
591
+ }
592
+
593
+ lastQueryHash = newQueryHash;
594
+
595
+ query.value = newQuery;
596
+
597
+ // Update search input if not in focus
598
+ if (searchInput.value && searchInput.value !== document.activeElement) {
599
+ updateSearchInput();
600
+ }
601
+
602
+ fetch();
603
+ }
604
+
605
+ /*
606
+ |--------------------------------------------------------------------------
607
+ | Fetch
608
+ |--------------------------------------------------------------------------
609
+ */
610
+
611
+ function fetchWithLoading(force = false) {
612
+ fetch(force, true);
613
+ }
614
+
615
+ function fetchWithoutLoading(force = false) {
616
+ fetch(force, false);
617
+ }
618
+
619
+ function fetch(force = false, showLoading = true) {
620
+ if (willUnmount) {
621
+ return;
622
+ }
623
+
624
+ const urlSplit = url.value.split(/[?#]/);
625
+
626
+ const baseUrl = urlSplit[0];
627
+ const urlQueryString = urlSplit[1] ?? null;
628
+ const urlQuery = config.parseQueryString(urlQueryString);
629
+
630
+ // Ordered by priority
631
+ const allParams = merge(
632
+ cloneDeep(query.value),
633
+ cloneDeep(props.urlQuery),
634
+ cloneDeep(urlQuery)
635
+ );
636
+
637
+ const queryString = config.formatQueryString(allParams);
638
+
639
+ const fullUrl = baseUrl + '?' + queryString;
640
+
641
+ if (lastUrl == fullUrl && !force) {
642
+ return;
643
+ }
644
+
645
+ if (showLoading) {
646
+ loading.value = true;
647
+ }
648
+
649
+ lastUrl = fullUrl;
650
+
651
+ http
652
+ .get(fullUrl)
653
+ .then((response) => {
654
+ data.value = response.data;
655
+ loading.value = false;
656
+ error.value = false;
657
+ firstLoad.value = true;
658
+ emit('fetch', data.value);
659
+ })
660
+ .catch(() => {
661
+ data.value = null;
662
+ loading.value = false;
663
+ error.value = true;
664
+ })
665
+ .finally(() => {
666
+ loading.value = false;
667
+ });
668
+ }
669
+
670
+ /*
671
+ |--------------------------------------------------------------------------
672
+ | Data parsing
673
+ |--------------------------------------------------------------------------
674
+ */
675
+
676
+ const data = ref<null | ResourceCollection | PaginatedCollection | Collection>(
677
+ null
678
+ );
679
+
680
+ const { items, paginationMetadata, lastPage } = useHasPaginatedData(data);
681
+
682
+ const page = computed((): number => {
683
+ if (query.value.page && parseInt(query.value.page + '')) {
684
+ return parseInt(query.value.page + '');
685
+ }
686
+ return 1;
687
+ });
688
+
689
+ const sortField = computed((): string => {
690
+ return query.value.sort?.trim().replace(/^(-)/, '') ?? '';
691
+ });
692
+
693
+ const sortDirection = computed((): Direction => {
694
+ if (query.value.sort && query.value.sort.length) {
695
+ if (query.value.sort[0] == '-') {
696
+ return 'desc';
697
+ }
698
+ }
699
+ return 'asc';
700
+ });
701
+
702
+ const searchKeywords = computed((): string => {
703
+ return query.value.search ?? '';
704
+ });
705
+
706
+ /*
707
+ |--------------------------------------------------------------------------
708
+ | Helpers
709
+ |--------------------------------------------------------------------------
710
+ */
711
+
712
+ /** Scroll into view */
713
+
714
+ const scrollIntoView = () => {
715
+ emit('will-scroll-top');
716
+
717
+ if (!props.scrollTopOnFetch) {
718
+ return;
719
+ }
720
+
721
+ scrollIntoViewAction();
722
+ };
723
+
724
+ const scrollIntoViewAction = () => {
725
+ if (dataIteratorNode.value == null) {
726
+ return;
727
+ }
728
+
729
+ dataIteratorNode.value.scrollIntoView({
730
+ behavior: 'smooth',
731
+ });
732
+ };
733
+
734
+ function updateSearchInput() {
735
+ searchQuery.value = searchKeywords.value;
736
+ }
737
+
738
+ const paginationStart = computed(() => {
739
+ if (paginationMetadata.value == null) {
740
+ return '';
741
+ }
742
+
743
+ return (
744
+ paginationMetadata.value.per_page *
745
+ (paginationMetadata.value.current_page - 1) +
746
+ 1
747
+ );
748
+ });
749
+
750
+ const paginationEnd = computed(() => {
751
+ if (paginationMetadata.value == null) {
752
+ return '';
753
+ }
754
+
755
+ return Math.min(
756
+ paginationMetadata.value.current_page * paginationMetadata.value.per_page,
757
+ paginationMetadata.value.total
758
+ );
759
+ });
760
+
761
+ /*
762
+ |--------------------------------------------------------------------------
763
+ | Created
764
+ |--------------------------------------------------------------------------
765
+ */
766
+
767
+ let newQuery = cloneDeep(query.value);
768
+ const routeQuery = getRouteQuery();
769
+
770
+ newQuery = merge(newQuery, routeQuery);
771
+
772
+ updateQuery(newQuery);
773
+
774
+ // Update search input on first load
775
+ onMounted(() => {
776
+ updateSearchInput();
777
+ });
778
+
779
+ /*
780
+ |--------------------------------------------------------------------------
781
+ | Sections
782
+ |--------------------------------------------------------------------------
783
+ */
784
+
785
+ const sectionModalActive = ref<null | number>(null);
786
+
787
+ const sectionsInternal = computed<DataIteratorSection[]>(() => {
788
+ const sections = props.sections ?? [];
789
+
790
+ if (hasFilters.value) {
791
+ return [
792
+ {
793
+ name: 'filters',
794
+ title: t('sui.filters'),
795
+ closeText: t('sui.apply_filters'),
796
+ icon: 'heroicons:funnel',
797
+ opened: true,
798
+ },
799
+ ...sections,
800
+ ];
801
+ }
802
+
803
+ return sections;
804
+ });
805
+
806
+ function openSection(index: number) {
807
+ if (sectionsInternal.value[index]) {
808
+ sectionModalActive.value = index;
809
+ } else {
810
+ sectionModalActive.value = null;
811
+ }
812
+ }
813
+
814
+ function closeSection() {
815
+ sectionModalActive.value = null;
816
+ }
817
+
818
+ /*
819
+ |--------------------------------------------------------------------------
820
+ | Provide
821
+ |--------------------------------------------------------------------------
822
+ */
823
+
824
+ provide('dataIterator:width', width);
825
+
826
+ /*
827
+ |--------------------------------------------------------------------------
828
+ | Exposed API
829
+ |--------------------------------------------------------------------------
830
+ */
831
+
832
+ defineExpose({
833
+ fetch: () => fetch(true),
834
+ fetchWithLoading: () => fetchWithLoading(true),
835
+ fetchWithoutLoading: () => fetchWithoutLoading(true),
836
+ scrollIntoView: scrollIntoViewAction,
837
+ query,
838
+ });
839
+ </script>