sprintify-ui 0.10.63 → 0.10.65
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.
- package/README.md +266 -266
- package/dist/{BaseCkeditor-B4PbYw6a.js → BaseCkeditor-D6D4FPEb.js} +2 -2
- package/dist/sprintify-ui.es.js +3731 -3593
- package/dist/style.css +3 -3
- package/dist/tailwindcss/button.js +260 -260
- package/dist/tailwindcss/index.js +21 -21
- package/dist/tailwindcss/input.js +22 -22
- package/dist/tailwindcss/overlay.js +12 -12
- package/dist/tailwindcss/table.js +91 -91
- package/dist/tailwindcss/theme.js +52 -52
- package/dist/types/components/BaseActionButtons.vue.d.ts +1 -1
- package/dist/types/components/BaseActionItem.vue.d.ts +10 -7
- package/dist/types/components/BaseAddressForm.vue.d.ts +1 -1
- package/dist/types/components/BaseAlert.vue.d.ts +11 -24
- package/dist/types/components/BaseApp.vue.d.ts +12 -14
- package/dist/types/components/BaseAssign.vue.d.ts +1 -1
- package/dist/types/components/BaseAutocomplete.vue.d.ts +455 -665
- package/dist/types/components/BaseAutocompleteDrawer.vue.d.ts +24 -119
- package/dist/types/components/BaseAutocompleteFetch.vue.d.ts +412 -1033
- package/dist/types/components/BaseAvatarGroup.vue.d.ts +1 -1
- package/dist/types/components/BaseBadge.vue.d.ts +11 -23
- package/dist/types/components/BaseBelongsTo.vue.d.ts +411 -998
- package/dist/types/components/BaseBelongsToFetch.vue.d.ts +371 -754
- package/dist/types/components/BaseBoolean.vue.d.ts +1 -1
- package/dist/types/components/BaseBreadcrumbs.vue.d.ts +1 -1
- package/dist/types/components/BaseButton.vue.d.ts +16 -78
- package/dist/types/components/BaseButtonGroup.vue.d.ts +15 -166
- package/dist/types/components/BaseCard.vue.d.ts +12 -26
- package/dist/types/components/BaseCardRow.vue.d.ts +11 -20
- package/dist/types/components/BaseCharacterCounter.vue.d.ts +1 -1
- package/dist/types/components/BaseClipboard.vue.d.ts +13 -45
- package/dist/types/components/BaseCollapse.vue.d.ts +20 -41
- package/dist/types/components/BaseContainer.vue.d.ts +11 -16
- package/dist/types/components/BaseCounter.vue.d.ts +1 -1
- package/dist/types/components/BaseCropper.vue.d.ts +30 -55
- package/dist/types/components/BaseDataIterator.vue.d.ts +42 -43
- package/dist/types/components/BaseDataIteratorSectionBox.vue.d.ts +12 -15
- package/dist/types/components/BaseDataIteratorSectionColumns.vue.d.ts +1 -1
- package/dist/types/components/BaseDataIteratorSectionModal.vue.d.ts +10 -19
- package/dist/types/components/BaseDataTable.vue.d.ts +736 -2088
- package/dist/types/components/BaseDataTableTemplate.vue.d.ts +100 -576
- package/dist/types/components/BaseDatePicker.vue.d.ts +1 -1
- package/dist/types/components/BaseDateSelect.vue.d.ts +1 -1
- package/dist/types/components/BaseDescriptionList.vue.d.ts +12 -12
- package/dist/types/components/BaseDescriptionListItem.vue.d.ts +15 -16
- package/dist/types/components/BaseDialog.vue.d.ts +413 -114
- package/dist/types/components/BaseDisplayRelativeTime.vue.d.ts +13 -55
- package/dist/types/components/BaseDraggable.vue.d.ts +16 -25
- package/dist/types/components/BaseDropdown.vue.d.ts +17 -155
- package/dist/types/components/BaseDropdownAutocomplete.vue.d.ts +16 -131
- package/dist/types/components/BaseField.vue.d.ts +12 -103
- package/dist/types/components/BaseFieldI18n.vue.d.ts +1 -1
- package/dist/types/components/BaseFilePicker.vue.d.ts +16 -35
- package/dist/types/components/BaseFilePickerCrop.vue.d.ts +42 -87
- package/dist/types/components/BaseFileUploader.vue.d.ts +29 -195
- package/dist/types/components/BaseForm.vue.d.ts +20 -161
- package/dist/types/components/BaseGantt.vue.d.ts +409 -1130
- package/dist/types/components/BaseHasMany.vue.d.ts +347 -590
- package/dist/types/components/BaseHasManyFetch.vue.d.ts +251 -602
- package/dist/types/components/BaseHeader.vue.d.ts +1 -1
- package/dist/types/components/BaseIconPicker.vue.d.ts +1 -1
- package/dist/types/components/BaseInputError.vue.d.ts +11 -23
- package/dist/types/components/BaseJsonReaderItem.vue.d.ts +1 -1
- package/dist/types/components/BaseLayoutNotificationItemContent.vue.d.ts +1 -1
- package/dist/types/components/BaseLayoutSidebar.vue.d.ts +16 -124
- package/dist/types/components/BaseLayoutSidebarConfigurable.vue.d.ts +13 -115
- package/dist/types/components/BaseLayoutStacked.vue.d.ts +22 -69
- package/dist/types/components/BaseLayoutStackedConfigurable.vue.d.ts +10 -120
- package/dist/types/components/BaseLazy.vue.d.ts +15 -20
- package/dist/types/components/BaseMediaGallery.vue.d.ts +1 -1
- package/dist/types/components/BaseMediaGalleryItem.vue.d.ts +1 -1
- package/dist/types/components/BaseMediaItem.vue.d.ts +1 -1
- package/dist/types/components/BaseMediaLibrary.vue.d.ts +34 -234
- package/dist/types/components/BaseMediaListItem.vue.d.ts +1 -1
- package/dist/types/components/BaseMediaPicturesItem.vue.d.ts +1 -1
- package/dist/types/components/BaseMenu.vue.d.ts +30 -233
- package/dist/types/components/BaseMenuItem.vue.d.ts +1 -1
- package/dist/types/components/BaseModalCenter.vue.d.ts +12 -88
- package/dist/types/components/BaseModalSide.vue.d.ts +20 -71
- package/dist/types/components/BaseNavbar.vue.d.ts +22 -88
- package/dist/types/components/BaseNavbarItem.vue.d.ts +1 -1
- package/dist/types/components/BaseNavbarItemContent.vue.d.ts +1 -1
- package/dist/types/components/BaseNavbarSideItem.vue.d.ts +1 -1
- package/dist/types/components/BaseNavbarSideItemContent.vue.d.ts +1 -1
- package/dist/types/components/BasePagination.vue.d.ts +1 -1
- package/dist/types/components/BaseRadioGroup.vue.d.ts +13 -113
- package/dist/types/components/BaseReadMore.vue.d.ts +12 -31
- package/dist/types/components/BaseRichText.vue.d.ts +1 -1
- package/dist/types/components/BaseSelect.vue.d.ts +12 -149
- package/dist/types/components/BaseShortcut.vue.d.ts +1 -1
- package/dist/types/components/BaseSideNavigation.vue.d.ts +12 -11
- package/dist/types/components/BaseSideNavigationItem.vue.d.ts +13 -22
- package/dist/types/components/BaseSkeleton.vue.d.ts +3 -3
- package/dist/types/components/BaseStepper.vue.d.ts +1 -1
- package/dist/types/components/BaseSwitch.vue.d.ts +10 -118
- package/dist/types/components/BaseSystemAlert.vue.d.ts +11 -58
- package/dist/types/components/BaseTabItem.vue.d.ts +18 -35
- package/dist/types/components/BaseTable.vue.d.ts +14 -29
- package/dist/types/components/BaseTableBody.vue.d.ts +12 -9
- package/dist/types/components/BaseTableCell.vue.d.ts +15 -40
- package/dist/types/components/BaseTableColumn.vue.d.ts +3 -3
- package/dist/types/components/BaseTableHead.vue.d.ts +12 -14
- package/dist/types/components/BaseTableHeader.vue.d.ts +17 -46
- package/dist/types/components/BaseTableRow.vue.d.ts +13 -40
- package/dist/types/components/BaseTabs.vue.d.ts +15 -21
- package/dist/types/components/BaseTagAutocomplete.vue.d.ts +203 -602
- package/dist/types/components/BaseTagAutocompleteFetch.vue.d.ts +348 -807
- package/dist/types/components/BaseTextareaAutoresize.vue.d.ts +1 -1
- package/dist/types/components/BaseTimeline.vue.d.ts +1 -1
- package/dist/types/components/BaseTimelineItem.vue.d.ts +1 -1
- package/dist/types/components/BaseToast.vue.d.ts +1 -1
- package/dist/types/components/BaseTooltip.vue.d.ts +15 -41
- package/dist/types/components/BaseUniqueCode.vue.d.ts +1 -1
- package/dist/types/stories/PageInputSizes.vue.d.ts +1 -1
- package/dist/types/stories/PageShow.vue.d.ts +1 -1
- package/dist/types/svg/BaseEmptyState.vue.d.ts +1 -1
- package/dist/types/svg/BaseSpinnerSmall.vue.d.ts +1 -1
- package/package.json +135 -135
- package/src/assets/base-cropper.css +61 -61
- package/src/assets/base-date-picker.css +4 -4
- package/src/assets/base-rich-text.css +270 -270
- package/src/assets/base-spinner.css +18 -18
- package/src/assets/base-tabs.css +4 -4
- package/src/assets/base-time-picker.css +9 -9
- package/src/assets/flatpickr.css +247 -247
- package/src/assets/form.css +6 -6
- package/src/assets/google-pac.css +25 -25
- package/src/assets/main.css +56 -56
- package/src/assets/tailwind.css +2 -2
- package/src/changelog.mdx +6 -6
- package/src/components/BaseActionButtons.vue +76 -76
- package/src/components/BaseActionItem.vue +80 -80
- package/src/components/BaseActionItemButton.vue +75 -75
- package/src/components/BaseAddressForm.stories.js +114 -114
- package/src/components/BaseAddressForm.vue +382 -382
- package/src/components/BaseAlert.stories.js +75 -75
- package/src/components/BaseAlert.vue +101 -101
- package/src/components/BaseApp.vue +16 -16
- package/src/components/BaseAppDialogs.vue +126 -126
- package/src/components/BaseAppSnackbars.vue +40 -40
- package/src/components/BaseAssign.mdx +98 -98
- package/src/components/BaseAssign.stories.js +78 -78
- package/src/components/BaseAssign.vue +366 -366
- package/src/components/BaseAutocomplete.stories.js +243 -243
- package/src/components/BaseAutocomplete.vue +603 -603
- package/src/components/BaseAutocompleteDrawer.vue +386 -386
- package/src/components/BaseAutocompleteFetch.stories.js +224 -224
- package/src/components/BaseAutocompleteFetch.vue +314 -314
- package/src/components/BaseAvatar.stories.js +39 -39
- package/src/components/BaseAvatar.vue +164 -164
- package/src/components/BaseAvatarGroup.stories.js +71 -71
- package/src/components/BaseAvatarGroup.vue +148 -148
- package/src/components/BaseBadge.stories.js +130 -130
- package/src/components/BaseBadge.vue +97 -97
- package/src/components/BaseBelongsTo.stories.js +220 -220
- package/src/components/BaseBelongsTo.vue +164 -164
- package/src/components/BaseBelongsToFetch.stories.js +223 -223
- package/src/components/BaseBelongsToFetch.vue +213 -213
- package/src/components/BaseBoolean.stories.js +35 -35
- package/src/components/BaseBoolean.vue +26 -26
- package/src/components/BaseBreadcrumbs.stories.js +50 -50
- package/src/components/BaseBreadcrumbs.vue +109 -109
- package/src/components/BaseButton.stories.js +126 -126
- package/src/components/BaseButton.vue +279 -279
- package/src/components/BaseButtonGroup.stories.js +114 -114
- package/src/components/BaseButtonGroup.vue +193 -193
- package/src/components/BaseCard.stories.js +63 -63
- package/src/components/BaseCard.vue +49 -49
- package/src/components/BaseCardRow.vue +53 -53
- package/src/components/BaseCharacterCounter.stories.js +30 -30
- package/src/components/BaseCharacterCounter.vue +64 -64
- package/src/components/BaseCkeditor.vue +154 -154
- package/src/components/BaseClipboard.stories.js +55 -55
- package/src/components/BaseClipboard.vue +105 -105
- package/src/components/BaseCollapse.stories.js +168 -168
- package/src/components/BaseCollapse.vue +98 -98
- package/src/components/BaseColor.stories.js +66 -66
- package/src/components/BaseColor.vue +155 -155
- package/src/components/BaseContainer.stories.js +34 -34
- package/src/components/BaseContainer.vue +64 -64
- package/src/components/BaseCounter.stories.js +47 -47
- package/src/components/BaseCounter.vue +83 -83
- package/src/components/BaseCropper.stories.js +113 -113
- package/src/components/BaseCropper.vue +390 -390
- package/src/components/BaseCropperModal.stories.js +54 -54
- package/src/components/BaseCropperModal.vue +143 -143
- package/src/components/BaseDataIterator.stories.js +292 -292
- package/src/components/BaseDataIterator.vue +986 -986
- package/src/components/BaseDataIteratorSectionBox.vue +36 -36
- package/src/components/BaseDataIteratorSectionButton.vue +42 -42
- package/src/components/BaseDataIteratorSectionColumns.vue +150 -150
- package/src/components/BaseDataIteratorSectionModal.vue +41 -41
- package/src/components/BaseDataTable.stories.js +393 -393
- package/src/components/BaseDataTable.vue +966 -966
- package/src/components/BaseDataTableRowAction.vue +70 -70
- package/src/components/BaseDataTableTemplate.vue +838 -838
- package/src/components/BaseDatePicker.stories.js +166 -166
- package/src/components/BaseDatePicker.vue +372 -372
- package/src/components/BaseDateSelect.stories.js +68 -68
- package/src/components/BaseDateSelect.vue +222 -222
- package/src/components/BaseDescriptionList.stories.js +35 -35
- package/src/components/BaseDescriptionList.vue +13 -13
- package/src/components/BaseDescriptionListItem.vue +47 -47
- package/src/components/BaseDialog.stories.js +95 -95
- package/src/components/BaseDialog.vue +221 -221
- package/src/components/BaseDisplayRelativeTime.stories.js +47 -47
- package/src/components/BaseDisplayRelativeTime.vue +126 -126
- package/src/components/BaseDraggable.stories.js +34 -34
- package/src/components/BaseDraggable.vue +111 -111
- package/src/components/BaseDropdown.stories.js +164 -164
- package/src/components/BaseDropdown.vue +74 -74
- package/src/components/BaseDropdownAutocomplete.stories.js +208 -208
- package/src/components/BaseDropdownAutocomplete.vue +203 -203
- package/src/components/BaseField.vue +151 -151
- package/src/components/BaseFieldI18n.stories.js +37 -37
- package/src/components/BaseFieldI18n.vue +170 -170
- package/src/components/BaseFilePicker.stories.js +84 -84
- package/src/components/BaseFilePicker.vue +163 -163
- package/src/components/BaseFilePickerCrop.stories.js +135 -135
- package/src/components/BaseFilePickerCrop.vue +130 -130
- package/src/components/BaseFileUploader.stories.js +101 -101
- package/src/components/BaseFileUploader.vue +185 -185
- package/src/components/BaseForm.mdx +87 -87
- package/src/components/BaseForm.stories.js +133 -133
- package/src/components/BaseForm.vue +372 -372
- package/src/components/BaseGantt.stories.js +145 -145
- package/src/components/BaseGantt.vue +384 -384
- package/src/components/BaseHasMany.stories.js +211 -211
- package/src/components/BaseHasMany.vue +135 -135
- package/src/components/BaseHasManyFetch.stories.js +278 -278
- package/src/components/BaseHasManyFetch.vue +222 -222
- package/src/components/BaseHeader.stories.js +137 -137
- package/src/components/BaseHeader.vue +141 -141
- package/src/components/BaseIconPicker.stories.js +22 -22
- package/src/components/BaseIconPicker.vue +225 -225
- package/src/components/BaseInput.stories.js +202 -202
- package/src/components/BaseInput.vue +402 -402
- package/src/components/BaseInputError.vue +39 -39
- package/src/components/BaseInputLabel.stories.js +36 -36
- package/src/components/BaseInputLabel.vue +83 -83
- package/src/components/BaseInputPercent.stories.js +66 -66
- package/src/components/BaseInputPercent.vue +139 -139
- package/src/components/BaseJsonReader.stories.js +120 -120
- package/src/components/BaseJsonReader.vue +51 -51
- package/src/components/BaseJsonReaderItem.vue +119 -119
- package/src/components/BaseLayoutNotificationDropdown.vue +153 -153
- package/src/components/BaseLayoutNotificationItem.vue +53 -53
- package/src/components/BaseLayoutNotificationItemContent.vue +41 -41
- package/src/components/BaseLayoutSidebar.vue +300 -300
- package/src/components/BaseLayoutSidebarConfigurable.stories.js +217 -217
- package/src/components/BaseLayoutSidebarConfigurable.vue +202 -202
- package/src/components/BaseLayoutStacked.vue +78 -78
- package/src/components/BaseLayoutStackedConfigurable.stories.js +181 -181
- package/src/components/BaseLayoutStackedConfigurable.vue +196 -196
- package/src/components/BaseLazy.stories.js +59 -59
- package/src/components/BaseLazy.vue +80 -80
- package/src/components/BaseLoadingCover.stories.js +55 -55
- package/src/components/BaseLoadingCover.vue +101 -101
- package/src/components/BaseMediaGallery.vue +96 -96
- package/src/components/BaseMediaGalleryItem.vue +101 -101
- package/src/components/BaseMediaItem.stories.js +41 -41
- package/src/components/BaseMediaItem.vue +80 -80
- package/src/components/BaseMediaLibrary.stories.js +267 -267
- package/src/components/BaseMediaLibrary.vue +357 -357
- package/src/components/BaseMediaList.vue +67 -67
- package/src/components/BaseMediaListItem.vue +213 -213
- package/src/components/BaseMediaPictures.vue +64 -64
- package/src/components/BaseMediaPicturesItem.vue +100 -100
- package/src/components/BaseMediaPreview.stories.js +72 -72
- package/src/components/BaseMediaPreview.vue +106 -106
- package/src/components/BaseMenu.stories.js +134 -134
- package/src/components/BaseMenu.vue +187 -187
- package/src/components/BaseMenuItem.vue +177 -177
- package/src/components/BaseModalCenter.stories.js +68 -68
- package/src/components/BaseModalCenter.vue +128 -128
- package/src/components/BaseModalSide.stories.js +61 -55
- package/src/components/BaseModalSide.vue +130 -116
- package/src/components/BaseNavbar.stories.js +152 -152
- package/src/components/BaseNavbar.vue +191 -191
- package/src/components/BaseNavbarItem.vue +108 -108
- package/src/components/BaseNavbarItemContent.vue +124 -124
- package/src/components/BaseNavbarSideItem.vue +187 -187
- package/src/components/BaseNavbarSideItemContent.vue +126 -126
- package/src/components/BasePagination.stories.js +35 -35
- package/src/components/BasePagination.vue +266 -266
- package/src/components/BasePanel.stories.js +56 -56
- package/src/components/BasePanel.vue +42 -42
- package/src/components/BasePassword.stories.js +80 -80
- package/src/components/BasePassword.vue +87 -87
- package/src/components/BaseProgressCircle.stories.js +27 -27
- package/src/components/BaseProgressCircle.vue +80 -80
- package/src/components/BaseRadioGroup.stories.js +87 -87
- package/src/components/BaseRadioGroup.vue +124 -124
- package/src/components/BaseReadMore.stories.js +30 -30
- package/src/components/BaseReadMore.vue +73 -73
- package/src/components/BaseRichText.stories.js +90 -90
- package/src/components/BaseRichText.vue +87 -87
- package/src/components/BaseScrollColumn.vue +128 -128
- package/src/components/BaseSelect.stories.js +151 -151
- package/src/components/BaseSelect.vue +241 -241
- package/src/components/BaseShortcut.stories.js +100 -100
- package/src/components/BaseShortcut.vue +114 -114
- package/src/components/BaseSideNavigation.stories.js +85 -85
- package/src/components/BaseSideNavigation.vue +32 -32
- package/src/components/BaseSideNavigationItem.vue +99 -99
- package/src/components/BaseSkeleton.stories.js +36 -36
- package/src/components/BaseSkeleton.vue +40 -40
- package/src/components/BaseStatistic.stories.js +51 -51
- package/src/components/BaseStatistic.vue +98 -98
- package/src/components/BaseStepper.stories.js +94 -94
- package/src/components/BaseStepper.vue +72 -72
- package/src/components/BaseStepperItem.stories.js +65 -65
- package/src/components/BaseStepperItem.vue +149 -149
- package/src/components/BaseSwitch.stories.js +133 -133
- package/src/components/BaseSwitch.vue +226 -226
- package/src/components/BaseSystemAlert.stories.js +63 -63
- package/src/components/BaseSystemAlert.vue +89 -89
- package/src/components/BaseTabItem.vue +192 -192
- package/src/components/BaseTable.stories.js +214 -214
- package/src/components/BaseTable.vue +111 -111
- package/src/components/BaseTableBody.vue +14 -14
- package/src/components/BaseTableCell.vue +204 -204
- package/src/components/BaseTableColumn.vue +140 -140
- package/src/components/BaseTableHead.vue +38 -38
- package/src/components/BaseTableHeader.vue +139 -139
- package/src/components/BaseTableRow.vue +197 -197
- package/src/components/BaseTabs.stories.js +165 -165
- package/src/components/BaseTabs.vue +203 -203
- package/src/components/BaseTagAutocomplete.stories.js +271 -271
- package/src/components/BaseTagAutocomplete.vue +565 -565
- package/src/components/BaseTagAutocompleteFetch.stories.js +211 -211
- package/src/components/BaseTagAutocompleteFetch.vue +237 -237
- package/src/components/BaseTextarea.stories.js +81 -81
- package/src/components/BaseTextarea.vue +138 -138
- package/src/components/BaseTextareaAutoresize.stories.js +125 -125
- package/src/components/BaseTextareaAutoresize.vue +187 -187
- package/src/components/BaseTimePicker.stories.js +68 -68
- package/src/components/BaseTimePicker.vue +379 -379
- package/src/components/BaseTimeline.stories.js +55 -55
- package/src/components/BaseTimeline.vue +38 -38
- package/src/components/BaseTimelineItem.stories.js +77 -77
- package/src/components/BaseTimelineItem.vue +90 -90
- package/src/components/BaseToast.stories.js +50 -50
- package/src/components/BaseToast.vue +43 -43
- package/src/components/BaseTooltip.stories.js +65 -65
- package/src/components/BaseTooltip.vue +93 -93
- package/src/components/BaseUniqueCode.stories.js +36 -36
- package/src/components/BaseUniqueCode.vue +183 -183
- package/src/components/SlotComponent.ts +37 -37
- package/src/components/index.ts +222 -222
- package/src/composables/breakpoints.ts +94 -94
- package/src/composables/clickOutside.ts +80 -80
- package/src/composables/field.ts +156 -156
- package/src/composables/hasOptions.ts +86 -86
- package/src/composables/inputSize.ts +35 -35
- package/src/composables/isLastColumn.ts +30 -30
- package/src/composables/mediaQuery.ts +42 -42
- package/src/composables/modal.ts +73 -73
- package/src/composables/paginatedData.ts +76 -76
- package/src/composables/tooltip.ts +84 -84
- package/src/constants/MyConstants.ts +1 -1
- package/src/constants/index.ts +5 -5
- package/src/env.d.ts +15 -15
- package/src/i18n/index.ts +60 -60
- package/src/index.ts +138 -138
- package/src/lang/en.json +101 -101
- package/src/lang/fr.json +101 -101
- package/src/services/gantt/format.ts +133 -133
- package/src/services/gantt/timescale.ts +250 -250
- package/src/services/gantt/types.ts +81 -81
- package/src/services/table/classes.ts +37 -37
- package/src/services/table/customKeyActions.ts +2 -2
- package/src/services/table/types.ts +27 -27
- package/src/stores/dialogs.ts +48 -48
- package/src/stores/i18n.ts +14 -14
- package/src/stores/snackbars.ts +47 -47
- package/src/stores/systemAlerts.ts +32 -32
- package/src/stories/InputSizes.stories.js +21 -21
- package/src/stories/List.stories.js +136 -136
- package/src/stories/PageInputSizes.vue +228 -228
- package/src/stories/PageShow.vue +423 -423
- package/src/stories/Show.stories.js +21 -21
- package/src/svg/BaseEmptyState.vue +38 -38
- package/src/svg/BaseSpinnerLarge.vue +40 -40
- package/src/svg/BaseSpinnerSmall.vue +13 -13
- package/src/types/Color.ts +9 -9
- package/src/types/Country.ts +4 -4
- package/src/types/ImagePickerResult.ts +5 -5
- package/src/types/Media.ts +10 -10
- package/src/types/Notification.ts +11 -11
- package/src/types/Region.ts +5 -5
- package/src/types/Status.ts +5 -5
- package/src/types/StepperItem.ts +8 -8
- package/src/types/ToolbarOption.ts +1 -1
- package/src/types/UploadedFile.ts +11 -11
- package/src/types/User.ts +7 -7
- package/src/types/index.ts +302 -302
- package/src/utils/blob.ts +30 -30
- package/src/utils/colors.ts +239 -239
- package/src/utils/cropper/avatar.ts +33 -33
- package/src/utils/cropper/cover.ts +41 -41
- package/src/utils/cropper/presetInterface.ts +16 -16
- package/src/utils/cropper/presets.ts +7 -7
- package/src/utils/deepIncludes.ts +76 -76
- package/src/utils/fileSizeFormat.ts +15 -15
- package/src/utils/fileValidations.ts +26 -26
- package/src/utils/getApiData.ts +11 -11
- package/src/utils/index.ts +18 -18
- package/src/utils/resizeImageFromURI.ts +118 -118
- package/src/utils/scrollPreventer.ts +11 -11
- package/src/utils/sizeBehaviors.ts +3 -3
- package/src/utils/sizes.ts +38 -38
- package/src/utils/slots.ts +12 -12
- package/src/utils/storage.ts +36 -36
- package/src/utils/toHumanList.ts +20 -20
- package/src/utils/uuid.ts +7 -7
|
@@ -1,838 +1,838 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="relative w-full overflow-hidden"
|
|
4
|
-
:style="{
|
|
5
|
-
minHeight: maxHeight ? maxHeight + 'px' : '200px',
|
|
6
|
-
}"
|
|
7
|
-
>
|
|
8
|
-
<div
|
|
9
|
-
ref="slot"
|
|
10
|
-
style="display: none"
|
|
11
|
-
>
|
|
12
|
-
<slot />
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
<BaseTable
|
|
16
|
-
ref="baseTableRef"
|
|
17
|
-
class="min-w-full"
|
|
18
|
-
:size="size"
|
|
19
|
-
:fixed-header="(maxHeight && maxHeight > 0) == true"
|
|
20
|
-
:fixed-column="true"
|
|
21
|
-
:max-height="maxHeight"
|
|
22
|
-
:loading="loading"
|
|
23
|
-
:virtual-scrolling="virtualScrolling"
|
|
24
|
-
>
|
|
25
|
-
<BaseTableHead v-if="newColumns.length">
|
|
26
|
-
<BaseTableRow>
|
|
27
|
-
<BaseTableHeader
|
|
28
|
-
v-for="(column, index) in visibleColumnsInternal"
|
|
29
|
-
:key="column.newKey + ':' + index + 'header'"
|
|
30
|
-
:style="column.style"
|
|
31
|
-
:tooltip="column.tooltip"
|
|
32
|
-
class="bg-slate-50"
|
|
33
|
-
>
|
|
34
|
-
<div class="flex gap-4">
|
|
35
|
-
<template v-if="index == 0">
|
|
36
|
-
<div
|
|
37
|
-
v-if="showDetailRowIcon"
|
|
38
|
-
class="flex h-5 w-5 shrink-0 grow-0"
|
|
39
|
-
/>
|
|
40
|
-
|
|
41
|
-
<div
|
|
42
|
-
v-if="checkable"
|
|
43
|
-
class="flex items-center cursor-pointer"
|
|
44
|
-
@click="checkAll"
|
|
45
|
-
>
|
|
46
|
-
<input
|
|
47
|
-
type="checkbox"
|
|
48
|
-
autocomplete="off"
|
|
49
|
-
:checked="isAllChecked"
|
|
50
|
-
:disabled="isAllUncheckable"
|
|
51
|
-
:class="checkboxStyle"
|
|
52
|
-
>
|
|
53
|
-
</div>
|
|
54
|
-
</template>
|
|
55
|
-
|
|
56
|
-
<button
|
|
57
|
-
type="button"
|
|
58
|
-
class="flex gap-2 w-full items-start bg-transparent text-left text-sm font-medium leading-tight text-slate-900"
|
|
59
|
-
:class="[
|
|
60
|
-
column.sortable ? 'cursor-pointer' : '',
|
|
61
|
-
column.align == 'right' ? 'justify-start flex-row-reverse text-right' : ''
|
|
62
|
-
]"
|
|
63
|
-
@click="sort(column, undefined, $event as any)"
|
|
64
|
-
>
|
|
65
|
-
<div
|
|
66
|
-
class="whitespace-nowrap text-slate-600"
|
|
67
|
-
:class="{
|
|
68
|
-
'text-[12px]': size == 'sm',
|
|
69
|
-
'text-xs': size == 'md',
|
|
70
|
-
}"
|
|
71
|
-
v-html="column.label"
|
|
72
|
-
/>
|
|
73
|
-
<!-- h-4 is used to make sure the tooltip icon is always smaller than label and avoid alignment issues when icon is not present -->
|
|
74
|
-
<div
|
|
75
|
-
v-if="column.sortable"
|
|
76
|
-
class="h-4 relative top-0.5"
|
|
77
|
-
:class="[
|
|
78
|
-
currentSortColumn === column
|
|
79
|
-
? ''
|
|
80
|
-
: 'opacity-0 duration-200 group-hover:opacity-100',
|
|
81
|
-
]"
|
|
82
|
-
>
|
|
83
|
-
<svg
|
|
84
|
-
width="11"
|
|
85
|
-
height="11"
|
|
86
|
-
viewBox="0 0 11 11"
|
|
87
|
-
fill="none"
|
|
88
|
-
class="block"
|
|
89
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
90
|
-
>
|
|
91
|
-
<path
|
|
92
|
-
:opacity="!isAsc ? '0.5' : '1'"
|
|
93
|
-
d="M4.88471 0.366233C5.00079 0.250125 5.1386 0.158021 5.29028 0.0951819C5.44196 0.0323429 5.60453 0 5.76871 0C5.93289 0 6.09546 0.0323429 6.24714 0.0951819C6.39882 0.158021 6.53663 0.250125 6.65271 0.366233L9.29871 3.01323C9.43119 3.15541 9.50331 3.34345 9.49988 3.53776C9.49646 3.73206 9.41774 3.91744 9.28033 4.05485C9.14292 4.19227 8.95753 4.27098 8.76323 4.27441C8.56893 4.27784 8.38088 4.20571 8.23871 4.07323L5.76871 1.60323L3.29871 4.07323C3.23005 4.14692 3.14725 4.20602 3.05525 4.24701C2.96325 4.28801 2.86393 4.31005 2.76323 4.31182C2.66253 4.3136 2.5625 4.29508 2.46911 4.25736C2.37572 4.21963 2.29089 4.16349 2.21967 4.09227C2.14845 4.02105 2.09231 3.93622 2.05459 3.84283C2.01686 3.74944 1.99834 3.64941 2.00012 3.54871C2.00189 3.44801 2.02394 3.34869 2.06493 3.25669C2.10592 3.1647 2.16502 3.08189 2.23871 3.01323L4.88471 0.366233Z"
|
|
94
|
-
fill="black"
|
|
95
|
-
></path>
|
|
96
|
-
<path
|
|
97
|
-
:opacity="isAsc ? '0.5' : '1'"
|
|
98
|
-
|
|
99
|
-
d="M4.84729 10.6083C4.96337 10.7244 5.10118 10.8165 5.25286 10.8793C5.40454 10.9422 5.56711 10.9745 5.73129 10.9745C5.89547 10.9745 6.05804 10.9422 6.20972 10.8793C6.3614 10.8165 6.49921 10.7244 6.61529 10.6083L9.26129 7.96129C9.39377 7.81912 9.4659 7.63107 9.46247 7.43677C9.45904 7.24247 9.38033 7.05708 9.24291 6.91967C9.1055 6.78226 8.92011 6.70354 8.72581 6.70012C8.53151 6.69669 8.34347 6.76881 8.20129 6.90129L5.73129 9.37129L3.26129 6.90129C3.11912 6.76881 2.93107 6.69669 2.73677 6.70012C2.54247 6.70354 2.35708 6.78226 2.21967 6.91967C2.08226 7.05708 2.00355 7.24247 2.00012 7.43677C1.99669 7.63107 2.06881 7.81912 2.20129 7.96129L4.84729 10.6083Z"
|
|
100
|
-
fill="black"
|
|
101
|
-
></path>
|
|
102
|
-
</svg>
|
|
103
|
-
</div>
|
|
104
|
-
</button>
|
|
105
|
-
</div>
|
|
106
|
-
</BaseTableHeader>
|
|
107
|
-
</BaseTableRow>
|
|
108
|
-
</BaseTableHead>
|
|
109
|
-
|
|
110
|
-
<BaseTableBody
|
|
111
|
-
class="bg-white"
|
|
112
|
-
>
|
|
113
|
-
<template
|
|
114
|
-
v-for="(row, index) in data"
|
|
115
|
-
:key="getRowKey(row)"
|
|
116
|
-
>
|
|
117
|
-
<BaseTableRow
|
|
118
|
-
:to="rowTo ? rowTo(row) : undefined"
|
|
119
|
-
:selected="rowSelected ? rowSelected(row) : false"
|
|
120
|
-
v-bind="rowBindings(row, index)"
|
|
121
|
-
>
|
|
122
|
-
<BaseTableCell
|
|
123
|
-
v-for="(column, columnIndex) in visibleColumnsInternal"
|
|
124
|
-
:key="column.newKey + index + ':' + columnIndex"
|
|
125
|
-
:class="[column.class, column.numeric ? 'tabular-nums' : '']"
|
|
126
|
-
:align="column.align"
|
|
127
|
-
:style="column.style"
|
|
128
|
-
:to="column.to ? column.to(row) : undefined"
|
|
129
|
-
:href="column.href ? column.href(row) : undefined"
|
|
130
|
-
:target="column.target"
|
|
131
|
-
:ignore-row-interactions="column.ignoreRowInteractions"
|
|
132
|
-
:on-click="onCellClick(row, index, column, columnIndex)"
|
|
133
|
-
>
|
|
134
|
-
<div :class="[columnIndex == 0 ? 'flex items-center gap-4' : '']">
|
|
135
|
-
<template v-if="columnIndex == 0">
|
|
136
|
-
<button
|
|
137
|
-
v-if="showDetailRowIcon"
|
|
138
|
-
type="button"
|
|
139
|
-
class="relative z-[1] || flex h-5 w-5 shrink-0 grow-0 appearance-none items-center justify-center rounded-full border border-slate-300 bg-white text-slate-400 shadow duration-100 hover:text-slate-600 hover:shadow-md"
|
|
140
|
-
@click.stop="toggleDetails(row)"
|
|
141
|
-
>
|
|
142
|
-
<BaseIcon
|
|
143
|
-
v-if="hasDetailedVisible(row)"
|
|
144
|
-
icon="mdi:chevron-down"
|
|
145
|
-
class="h-5 w-5 duration-300"
|
|
146
|
-
:class="{
|
|
147
|
-
'rotate-180': isVisibleDetailRow(row)
|
|
148
|
-
}"
|
|
149
|
-
/>
|
|
150
|
-
</button>
|
|
151
|
-
|
|
152
|
-
<div
|
|
153
|
-
v-if="checkable"
|
|
154
|
-
class="relative z-[1] || flex items-center group cursor-pointer bg-white"
|
|
155
|
-
@click.stop="checkRow(row, index, $event as MouseEvent)"
|
|
156
|
-
>
|
|
157
|
-
<input
|
|
158
|
-
type="checkbox"
|
|
159
|
-
autocomplete="off"
|
|
160
|
-
:disabled="!isRowCheckable(row)"
|
|
161
|
-
:checked="isRowChecked(row)"
|
|
162
|
-
:class="checkboxStyle"
|
|
163
|
-
>
|
|
164
|
-
</div>
|
|
165
|
-
</template>
|
|
166
|
-
|
|
167
|
-
<SlotComponent
|
|
168
|
-
:component="column"
|
|
169
|
-
scoped
|
|
170
|
-
name="default"
|
|
171
|
-
tag="div"
|
|
172
|
-
class="text-sm grow"
|
|
173
|
-
:data-label="column.label"
|
|
174
|
-
:props="{ row, column, index, columnIndex, toggleDetails }"
|
|
175
|
-
/>
|
|
176
|
-
</div>
|
|
177
|
-
</BaseTableCell>
|
|
178
|
-
</BaseTableRow>
|
|
179
|
-
|
|
180
|
-
<BaseTableRow
|
|
181
|
-
v-if="isActiveDetailRow(row)"
|
|
182
|
-
:key="getRowKey(row) + 'detail'"
|
|
183
|
-
>
|
|
184
|
-
<BaseTableCell
|
|
185
|
-
:colspan="columnCount"
|
|
186
|
-
>
|
|
187
|
-
<slot
|
|
188
|
-
name="detail"
|
|
189
|
-
:row="row"
|
|
190
|
-
:index="index"
|
|
191
|
-
/>
|
|
192
|
-
</BaseTableCell>
|
|
193
|
-
</BaseTableRow>
|
|
194
|
-
</template>
|
|
195
|
-
|
|
196
|
-
<BaseTableRow v-if="data.length == 0">
|
|
197
|
-
<BaseTableCell :colspan="columnCount">
|
|
198
|
-
<slot name="empty" />
|
|
199
|
-
</BaseTableCell>
|
|
200
|
-
</BaseTableRow>
|
|
201
|
-
</BaseTableBody>
|
|
202
|
-
</BaseTable>
|
|
203
|
-
</div>
|
|
204
|
-
</template>
|
|
205
|
-
|
|
206
|
-
<script lang="ts" setup>
|
|
207
|
-
import { PropType, ref } from 'vue';
|
|
208
|
-
import { BaseTableColumnData, CollectionItem, Row } from '@/types';
|
|
209
|
-
import SlotComponent from './SlotComponent';
|
|
210
|
-
import { isArray } from 'lodash';
|
|
211
|
-
import { Size } from '@/utils/sizes';
|
|
212
|
-
import objectHash from 'object-hash';
|
|
213
|
-
import BaseTable from './BaseTable.vue';
|
|
214
|
-
import BaseTableHead from './BaseTableHead.vue';
|
|
215
|
-
import BaseTableHeader from './BaseTableHeader.vue';
|
|
216
|
-
import BaseTableBody from './BaseTableBody.vue';
|
|
217
|
-
import BaseTableRow from './BaseTableRow.vue';
|
|
218
|
-
import BaseTableCell from './BaseTableCell.vue';
|
|
219
|
-
import { RouteLocationRaw } from 'vue-router';
|
|
220
|
-
import { customKeyActions } from '@/services/table/customKeyActions';
|
|
221
|
-
|
|
222
|
-
const checkboxStyle =
|
|
223
|
-
'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';
|
|
224
|
-
|
|
225
|
-
defineOptions({
|
|
226
|
-
name: 'BaseDataTableTemplate',
|
|
227
|
-
inheritAttrs: false,
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
provide('table', getCurrentInstance());
|
|
231
|
-
|
|
232
|
-
const props = defineProps({
|
|
233
|
-
/** Table data */
|
|
234
|
-
data: {
|
|
235
|
-
type: Array as PropType<Row[]>,
|
|
236
|
-
default: () => [],
|
|
237
|
-
},
|
|
238
|
-
/** Loading state */
|
|
239
|
-
loading: {
|
|
240
|
-
default: false,
|
|
241
|
-
type: Boolean,
|
|
242
|
-
},
|
|
243
|
-
visibleColumns: {
|
|
244
|
-
default: undefined,
|
|
245
|
-
type: Array as PropType<string[]>,
|
|
246
|
-
},
|
|
247
|
-
columnOrder: {
|
|
248
|
-
default: undefined,
|
|
249
|
-
type: Array as PropType<string[]>,
|
|
250
|
-
},
|
|
251
|
-
/** Allow row details */
|
|
252
|
-
detailed: {
|
|
253
|
-
default: false,
|
|
254
|
-
type: Boolean,
|
|
255
|
-
},
|
|
256
|
-
/** Rows can be checked (multiple) */
|
|
257
|
-
checkable: {
|
|
258
|
-
default: false,
|
|
259
|
-
type: Boolean,
|
|
260
|
-
},
|
|
261
|
-
/** Custom method to verify if a row is checkable, works when is checkable */
|
|
262
|
-
isRowCheckable: {
|
|
263
|
-
type: Function,
|
|
264
|
-
default: () => true,
|
|
265
|
-
},
|
|
266
|
-
/** Set which rows are checked, use v-model:checkedRows to make it two-way binding */
|
|
267
|
-
checkedRows: {
|
|
268
|
-
default: () => [],
|
|
269
|
-
type: Array as PropType<Row[]>,
|
|
270
|
-
},
|
|
271
|
-
/** Sets the default sort column field */
|
|
272
|
-
sortField: {
|
|
273
|
-
type: String,
|
|
274
|
-
default: '',
|
|
275
|
-
},
|
|
276
|
-
/**
|
|
277
|
-
* Sets the default sort column direction
|
|
278
|
-
* @values asc, desc
|
|
279
|
-
*/
|
|
280
|
-
sortDirection: {
|
|
281
|
-
type: String,
|
|
282
|
-
default: 'asc',
|
|
283
|
-
},
|
|
284
|
-
/** Controls the visibility of the trigger that toggles the detailed rows. */
|
|
285
|
-
hasDetailedVisible: {
|
|
286
|
-
type: Function,
|
|
287
|
-
default: () => true,
|
|
288
|
-
},
|
|
289
|
-
/* Max height (in px) */
|
|
290
|
-
maxHeight: {
|
|
291
|
-
default: undefined,
|
|
292
|
-
type: Number,
|
|
293
|
-
},
|
|
294
|
-
size: {
|
|
295
|
-
type: String as PropType<Size>,
|
|
296
|
-
default: 'md',
|
|
297
|
-
},
|
|
298
|
-
rowTo: {
|
|
299
|
-
default: undefined,
|
|
300
|
-
type: Function as PropType<((row: CollectionItem) => RouteLocationRaw) | undefined>,
|
|
301
|
-
},
|
|
302
|
-
rowHref: {
|
|
303
|
-
default: undefined,
|
|
304
|
-
type: Function as PropType<((row: CollectionItem) => string) | undefined>,
|
|
305
|
-
},
|
|
306
|
-
onRowClick: {
|
|
307
|
-
default: undefined,
|
|
308
|
-
type: Function as PropType<((row: CollectionItem, index: number, event: MouseEvent) => void) | undefined>,
|
|
309
|
-
},
|
|
310
|
-
rowKey: {
|
|
311
|
-
default: undefined,
|
|
312
|
-
type: Function as PropType<((row: CollectionItem) => string | number) | undefined>,
|
|
313
|
-
},
|
|
314
|
-
rowSelected: {
|
|
315
|
-
default: undefined,
|
|
316
|
-
type: Function as PropType<((row: CollectionItem) => boolean) | undefined>,
|
|
317
|
-
},
|
|
318
|
-
virtualScrolling: {
|
|
319
|
-
default: false,
|
|
320
|
-
type: Boolean,
|
|
321
|
-
},
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
const emit = defineEmits([
|
|
325
|
-
'check',
|
|
326
|
-
'check-all',
|
|
327
|
-
'update:checkedRows',
|
|
328
|
-
'details-open',
|
|
329
|
-
'details-close',
|
|
330
|
-
'update:openedDetailed',
|
|
331
|
-
'sort',
|
|
332
|
-
'cell-click',
|
|
333
|
-
'row-click',
|
|
334
|
-
]);
|
|
335
|
-
|
|
336
|
-
const visibleDetailRows = ref<string[]>([]);
|
|
337
|
-
// eslint-disable-next-line vue/no-setup-props-destructure
|
|
338
|
-
const newCheckedRows = ref<Row[]>([...props.checkedRows]);
|
|
339
|
-
const lastCheckedRowIndex = ref<number | null>(null);
|
|
340
|
-
const currentSortColumn = ref<BaseTableColumnData | null>(null);
|
|
341
|
-
const isAsc = ref(true);
|
|
342
|
-
const defaultSlots = ref<BaseTableColumnData[]>([]);
|
|
343
|
-
|
|
344
|
-
const slot = ref<HTMLElement | null>(null);
|
|
345
|
-
|
|
346
|
-
const newColumns = computed(() => {
|
|
347
|
-
const cols = defaultSlots.value;
|
|
348
|
-
|
|
349
|
-
if (props.columnOrder && props.columnOrder.length) {
|
|
350
|
-
|
|
351
|
-
const colOrder = props.columnOrder;
|
|
352
|
-
|
|
353
|
-
return cols
|
|
354
|
-
.sort((a, b) => {
|
|
355
|
-
|
|
356
|
-
// Always put actions column at the end
|
|
357
|
-
|
|
358
|
-
if (a.newKey === customKeyActions) {
|
|
359
|
-
return 1;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (b.newKey === customKeyActions) {
|
|
363
|
-
return -1;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// If not found, put it at the end
|
|
367
|
-
|
|
368
|
-
const existsA = colOrder.includes(a.newKey);
|
|
369
|
-
const existsB = colOrder.includes(b.newKey);
|
|
370
|
-
|
|
371
|
-
if (!existsA && !existsB) {
|
|
372
|
-
return 0;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (!existsA) {
|
|
376
|
-
return 1;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (!existsB) {
|
|
380
|
-
return -1;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Sort based on the order
|
|
384
|
-
|
|
385
|
-
return colOrder.indexOf(a.newKey) - colOrder.indexOf(b.newKey);
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
return cols;
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const visibleColumnsInternal = computed(() => {
|
|
394
|
-
|
|
395
|
-
if (!newColumns.value) {
|
|
396
|
-
return [];
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return newColumns.value
|
|
400
|
-
.filter((column: BaseTableColumnData) => {
|
|
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 = visibleColumnsInternal.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: BaseTableColumnData, 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
|
-
const found = newCheckedRows.value.find((r) => {
|
|
500
|
-
const key1 = getRowKey(r);
|
|
501
|
-
const key2 = getRowKey(row);
|
|
502
|
-
return key1 == key2
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
return found !== undefined;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Check if all rows in the page are checkable.
|
|
510
|
-
*/
|
|
511
|
-
const isAllUncheckable = computed(() => {
|
|
512
|
-
const validData = props.data.filter((row) => props.isRowCheckable(row));
|
|
513
|
-
return validData.length === 0;
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Check if all rows in the page are checked.
|
|
518
|
-
*/
|
|
519
|
-
const isAllChecked = computed(() => {
|
|
520
|
-
const validData = props.data.filter((row) => {
|
|
521
|
-
return props.isRowCheckable(row);
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
if (validData.length === 0) {
|
|
525
|
-
return false;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
const missingChecked = validData.some((currentRow) => {
|
|
529
|
-
return !isRowChecked(currentRow);
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
return !missingChecked;
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
function getCheckedRowIndex(row: Row) {
|
|
536
|
-
const foundIndex = newCheckedRows.value.findIndex((r) => {
|
|
537
|
-
const key1 = getRowKey(r);
|
|
538
|
-
const key2 = getRowKey(row);
|
|
539
|
-
return key1 == key2
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
return foundIndex;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* Remove a checked row from the array.
|
|
547
|
-
*/
|
|
548
|
-
function removeCheckedRow(row: Row) {
|
|
549
|
-
const index = getCheckedRowIndex(row);
|
|
550
|
-
if (index >= 0) {
|
|
551
|
-
newCheckedRows.value.splice(index, 1);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
/**
|
|
556
|
-
* Header checkbox click listener.
|
|
557
|
-
* Add or remove all rows in current page.
|
|
558
|
-
*/
|
|
559
|
-
function checkAll() {
|
|
560
|
-
if (isAllChecked.value) {
|
|
561
|
-
newCheckedRows.value = [];
|
|
562
|
-
} else {
|
|
563
|
-
props.data.forEach((currentRow) => {
|
|
564
|
-
if (props.isRowCheckable(currentRow) && !isRowChecked(currentRow)) {
|
|
565
|
-
newCheckedRows.value.push(currentRow);
|
|
566
|
-
}
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
sendCheckUpdate();
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
/**
|
|
574
|
-
* Remove all rows in current page.
|
|
575
|
-
*/
|
|
576
|
-
function uncheckAll() {
|
|
577
|
-
newCheckedRows.value = [];
|
|
578
|
-
|
|
579
|
-
sendCheckUpdate();
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
function sendCheckUpdate() {
|
|
583
|
-
emit('check', newCheckedRows.value);
|
|
584
|
-
emit('check-all', newCheckedRows.value);
|
|
585
|
-
emit('update:checkedRows', newCheckedRows.value);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
/**
|
|
589
|
-
* Row checkbox click listener.
|
|
590
|
-
*/
|
|
591
|
-
function checkRow(row: Row, index: number, event: MouseEvent) {
|
|
592
|
-
if (!props.isRowCheckable(row)) {
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
const lastIndex = lastCheckedRowIndex.value;
|
|
597
|
-
lastCheckedRowIndex.value = index;
|
|
598
|
-
|
|
599
|
-
if (event.shiftKey && lastIndex !== null && index !== lastIndex) {
|
|
600
|
-
shiftCheckRow(row, index, lastIndex);
|
|
601
|
-
} else if (!isRowChecked(row)) {
|
|
602
|
-
newCheckedRows.value.push(row);
|
|
603
|
-
} else {
|
|
604
|
-
removeCheckedRow(row);
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
emit('check', newCheckedRows.value, row);
|
|
608
|
-
|
|
609
|
-
// Emit checked rows to update user variable
|
|
610
|
-
emit('update:checkedRows', newCheckedRows.value);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* Check row when shift is pressed.
|
|
615
|
-
*/
|
|
616
|
-
function shiftCheckRow(row: Row, index: number, lastCheckedRowIndex: number) {
|
|
617
|
-
// Get the subset of the list between the two indices
|
|
618
|
-
const subset = props.data.slice(
|
|
619
|
-
Math.min(index, lastCheckedRowIndex),
|
|
620
|
-
Math.max(index, lastCheckedRowIndex) + 1
|
|
621
|
-
);
|
|
622
|
-
|
|
623
|
-
// Determine the operation based on the state of the clicked checkbox
|
|
624
|
-
const shouldCheck = !isRowChecked(row);
|
|
625
|
-
|
|
626
|
-
subset.forEach((item) => {
|
|
627
|
-
removeCheckedRow(item);
|
|
628
|
-
if (shouldCheck && props.isRowCheckable(item)) {
|
|
629
|
-
newCheckedRows.value.push(item);
|
|
630
|
-
}
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Toggle to show/hide details slot
|
|
636
|
-
*/
|
|
637
|
-
function toggleDetails(row: Row) {
|
|
638
|
-
const found = isVisibleDetailRow(row);
|
|
639
|
-
|
|
640
|
-
if (found) {
|
|
641
|
-
closeDetailRow(row);
|
|
642
|
-
emit('details-close', row);
|
|
643
|
-
} else {
|
|
644
|
-
openDetailRow(row);
|
|
645
|
-
emit('details-open', row);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Syncs the detailed rows with the parent component
|
|
649
|
-
emit('update:openedDetailed', visibleDetailRows.value);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
function openDetailRow(row: Row) {
|
|
653
|
-
const key = getRowKey(row);
|
|
654
|
-
visibleDetailRows.value.push(key);
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
function closeDetailRow(row: Row) {
|
|
658
|
-
const key = getRowKey(row);
|
|
659
|
-
const i = visibleDetailRows.value.indexOf(key);
|
|
660
|
-
if (i >= 0) {
|
|
661
|
-
visibleDetailRows.value.splice(i, 1);
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
function isVisibleDetailRow(row: Row) {
|
|
666
|
-
const key = getRowKey(row);
|
|
667
|
-
return visibleDetailRows.value.indexOf(key) >= 0;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
function isActiveDetailRow(row: Row) {
|
|
671
|
-
return props.detailed && isVisibleDetailRow(row);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
/**
|
|
675
|
-
* Update sort state
|
|
676
|
-
*/
|
|
677
|
-
function updateSortState() {
|
|
678
|
-
const sortField = props.sortField;
|
|
679
|
-
|
|
680
|
-
const sortDirection = props.sortDirection;
|
|
681
|
-
|
|
682
|
-
const sortColumn = newColumns.value.filter(
|
|
683
|
-
(column) => column.field === sortField
|
|
684
|
-
)[0];
|
|
685
|
-
|
|
686
|
-
// Set sort state
|
|
687
|
-
|
|
688
|
-
if (sortColumn) {
|
|
689
|
-
currentSortColumn.value = sortColumn;
|
|
690
|
-
isAsc.value = sortDirection.toLowerCase() !== 'desc';
|
|
691
|
-
} else {
|
|
692
|
-
currentSortColumn.value = null;
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
/*
|
|
698
|
-
|--------------------------------------------------------------------------
|
|
699
|
-
| BaseTableColumns functions
|
|
700
|
-
|--------------------------------------------------------------------------
|
|
701
|
-
*/
|
|
702
|
-
|
|
703
|
-
function addColumn(column: BaseTableColumnData) {
|
|
704
|
-
defaultSlots.value.push(column);
|
|
705
|
-
|
|
706
|
-
const slotHTMLElement = slot.value as HTMLElement;
|
|
707
|
-
|
|
708
|
-
if (slotHTMLElement && slotHTMLElement.children) {
|
|
709
|
-
nextTick(() => {
|
|
710
|
-
const ids = defaultSlots.value
|
|
711
|
-
.map((it) => `[data-id="${it.newKey}"]`)
|
|
712
|
-
.join(',');
|
|
713
|
-
|
|
714
|
-
const sortedIds = Array.from(slotHTMLElement.querySelectorAll(ids)).map(
|
|
715
|
-
(el: Element) => el.getAttribute('data-id')
|
|
716
|
-
);
|
|
717
|
-
|
|
718
|
-
defaultSlots.value = defaultSlots.value.sort((a, b) => {
|
|
719
|
-
return (
|
|
720
|
-
sortedIds.indexOf(`${a.newKey}`) - sortedIds.indexOf(`${b.newKey}`)
|
|
721
|
-
);
|
|
722
|
-
});
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
function removeColumn(column: BaseTableColumnData) {
|
|
728
|
-
defaultSlots.value = defaultSlots.value.filter(
|
|
729
|
-
(d) => d.newKey !== column.newKey
|
|
730
|
-
);
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
function rowBindings(row: CollectionItem, index: number) {
|
|
734
|
-
return {
|
|
735
|
-
onClick: props.onRowClick ? (event: MouseEvent) => props.onRowClick && props.onRowClick(row, index, event) : undefined,
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
function onCellClick(row: CollectionItem, index: number, column: BaseTableColumnData, columnIndex: number) {
|
|
740
|
-
if (!column.onClick) {
|
|
741
|
-
return undefined;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
return (event: MouseEvent) => {
|
|
745
|
-
if (!column.onClick) {
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
column.onClick(row, index, column, columnIndex, event);
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
let warningNoRowKeyFoundShown = false;
|
|
754
|
-
|
|
755
|
-
function getRowKey(row: Row): string {
|
|
756
|
-
|
|
757
|
-
if (props.rowKey) {
|
|
758
|
-
return props.rowKey(row) + '';
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
if (row.id) {
|
|
762
|
-
return row.id;
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
if (row.key) {
|
|
766
|
-
return row.key;
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
if (row.uuid) {
|
|
770
|
-
return row.uuid;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
if (!warningNoRowKeyFoundShown) {
|
|
774
|
-
console.warn('%cNo unique key found for items provided to BaseDataTable.%cPlease provide a unique key for each row (id, key or uuid) or use the row-key props to specify a unique key.', 'font-weight: bold', 'font-weight: normal');
|
|
775
|
-
warningNoRowKeyFoundShown = true;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
// if no key is found, hash a simplified version of the row object
|
|
779
|
-
// We use a simplified version to avoid hashing functions, objects, etc. for performance reasons
|
|
780
|
-
|
|
781
|
-
const simpleRow = {} as Record<string, string | number | boolean>;
|
|
782
|
-
|
|
783
|
-
for (const key in row) {
|
|
784
|
-
const value = row[key];
|
|
785
|
-
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
786
|
-
simpleRow[key] = value;
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
return objectHash(simpleRow);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
provide('addColumn', addColumn);
|
|
794
|
-
provide('removeColumn', removeColumn);
|
|
795
|
-
|
|
796
|
-
const baseTableRef = ref<InstanceType<typeof BaseTable> | null>(null);
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
/*
|
|
800
|
-
|--------------------------------------------------------------------------
|
|
801
|
-
| Checks
|
|
802
|
-
|--------------------------------------------------------------------------
|
|
803
|
-
*/
|
|
804
|
-
|
|
805
|
-
watch(
|
|
806
|
-
() => newColumns.value.map((item) => item.newKey),
|
|
807
|
-
(keys: string[]) => {
|
|
808
|
-
|
|
809
|
-
// check duplicates
|
|
810
|
-
|
|
811
|
-
const duplicates = keys.reduce((acc, key, index) => {
|
|
812
|
-
if (keys.indexOf(key) !== index && !acc.includes(key)) {
|
|
813
|
-
acc.push(key);
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
return acc;
|
|
817
|
-
}, [] as string[]);
|
|
818
|
-
|
|
819
|
-
if (duplicates.length) {
|
|
820
|
-
throw new Error(`Duplicate BaseTableColumn keys found: ${duplicates.join(', ')}`);
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
)
|
|
824
|
-
|
|
825
|
-
/*
|
|
826
|
-
|--------------------------------------------------------------------------
|
|
827
|
-
| Expose
|
|
828
|
-
|--------------------------------------------------------------------------
|
|
829
|
-
*/
|
|
830
|
-
|
|
831
|
-
defineExpose({
|
|
832
|
-
newColumns,
|
|
833
|
-
uncheckAll,
|
|
834
|
-
scrollTop: () => {
|
|
835
|
-
baseTableRef.value?.scrollTop();
|
|
836
|
-
},
|
|
837
|
-
});
|
|
838
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="relative w-full overflow-hidden"
|
|
4
|
+
:style="{
|
|
5
|
+
minHeight: maxHeight ? maxHeight + 'px' : '200px',
|
|
6
|
+
}"
|
|
7
|
+
>
|
|
8
|
+
<div
|
|
9
|
+
ref="slot"
|
|
10
|
+
style="display: none"
|
|
11
|
+
>
|
|
12
|
+
<slot />
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<BaseTable
|
|
16
|
+
ref="baseTableRef"
|
|
17
|
+
class="min-w-full"
|
|
18
|
+
:size="size"
|
|
19
|
+
:fixed-header="(maxHeight && maxHeight > 0) == true"
|
|
20
|
+
:fixed-column="true"
|
|
21
|
+
:max-height="maxHeight"
|
|
22
|
+
:loading="loading"
|
|
23
|
+
:virtual-scrolling="virtualScrolling"
|
|
24
|
+
>
|
|
25
|
+
<BaseTableHead v-if="newColumns.length">
|
|
26
|
+
<BaseTableRow>
|
|
27
|
+
<BaseTableHeader
|
|
28
|
+
v-for="(column, index) in visibleColumnsInternal"
|
|
29
|
+
:key="column.newKey + ':' + index + 'header'"
|
|
30
|
+
:style="column.style"
|
|
31
|
+
:tooltip="column.tooltip"
|
|
32
|
+
class="bg-slate-50"
|
|
33
|
+
>
|
|
34
|
+
<div class="flex gap-4">
|
|
35
|
+
<template v-if="index == 0">
|
|
36
|
+
<div
|
|
37
|
+
v-if="showDetailRowIcon"
|
|
38
|
+
class="flex h-5 w-5 shrink-0 grow-0"
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
<div
|
|
42
|
+
v-if="checkable"
|
|
43
|
+
class="flex items-center cursor-pointer"
|
|
44
|
+
@click="checkAll"
|
|
45
|
+
>
|
|
46
|
+
<input
|
|
47
|
+
type="checkbox"
|
|
48
|
+
autocomplete="off"
|
|
49
|
+
:checked="isAllChecked"
|
|
50
|
+
:disabled="isAllUncheckable"
|
|
51
|
+
:class="checkboxStyle"
|
|
52
|
+
>
|
|
53
|
+
</div>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<button
|
|
57
|
+
type="button"
|
|
58
|
+
class="flex gap-2 w-full items-start bg-transparent text-left text-sm font-medium leading-tight text-slate-900"
|
|
59
|
+
:class="[
|
|
60
|
+
column.sortable ? 'cursor-pointer' : '',
|
|
61
|
+
column.align == 'right' ? 'justify-start flex-row-reverse text-right' : ''
|
|
62
|
+
]"
|
|
63
|
+
@click="sort(column, undefined, $event as any)"
|
|
64
|
+
>
|
|
65
|
+
<div
|
|
66
|
+
class="whitespace-nowrap text-slate-600"
|
|
67
|
+
:class="{
|
|
68
|
+
'text-[12px]': size == 'sm',
|
|
69
|
+
'text-xs': size == 'md',
|
|
70
|
+
}"
|
|
71
|
+
v-html="column.label"
|
|
72
|
+
/>
|
|
73
|
+
<!-- h-4 is used to make sure the tooltip icon is always smaller than label and avoid alignment issues when icon is not present -->
|
|
74
|
+
<div
|
|
75
|
+
v-if="column.sortable"
|
|
76
|
+
class="h-4 relative top-0.5"
|
|
77
|
+
:class="[
|
|
78
|
+
currentSortColumn === column
|
|
79
|
+
? ''
|
|
80
|
+
: 'opacity-0 duration-200 group-hover:opacity-100',
|
|
81
|
+
]"
|
|
82
|
+
>
|
|
83
|
+
<svg
|
|
84
|
+
width="11"
|
|
85
|
+
height="11"
|
|
86
|
+
viewBox="0 0 11 11"
|
|
87
|
+
fill="none"
|
|
88
|
+
class="block"
|
|
89
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
90
|
+
>
|
|
91
|
+
<path
|
|
92
|
+
:opacity="!isAsc ? '0.5' : '1'"
|
|
93
|
+
d="M4.88471 0.366233C5.00079 0.250125 5.1386 0.158021 5.29028 0.0951819C5.44196 0.0323429 5.60453 0 5.76871 0C5.93289 0 6.09546 0.0323429 6.24714 0.0951819C6.39882 0.158021 6.53663 0.250125 6.65271 0.366233L9.29871 3.01323C9.43119 3.15541 9.50331 3.34345 9.49988 3.53776C9.49646 3.73206 9.41774 3.91744 9.28033 4.05485C9.14292 4.19227 8.95753 4.27098 8.76323 4.27441C8.56893 4.27784 8.38088 4.20571 8.23871 4.07323L5.76871 1.60323L3.29871 4.07323C3.23005 4.14692 3.14725 4.20602 3.05525 4.24701C2.96325 4.28801 2.86393 4.31005 2.76323 4.31182C2.66253 4.3136 2.5625 4.29508 2.46911 4.25736C2.37572 4.21963 2.29089 4.16349 2.21967 4.09227C2.14845 4.02105 2.09231 3.93622 2.05459 3.84283C2.01686 3.74944 1.99834 3.64941 2.00012 3.54871C2.00189 3.44801 2.02394 3.34869 2.06493 3.25669C2.10592 3.1647 2.16502 3.08189 2.23871 3.01323L4.88471 0.366233Z"
|
|
94
|
+
fill="black"
|
|
95
|
+
></path>
|
|
96
|
+
<path
|
|
97
|
+
:opacity="isAsc ? '0.5' : '1'"
|
|
98
|
+
|
|
99
|
+
d="M4.84729 10.6083C4.96337 10.7244 5.10118 10.8165 5.25286 10.8793C5.40454 10.9422 5.56711 10.9745 5.73129 10.9745C5.89547 10.9745 6.05804 10.9422 6.20972 10.8793C6.3614 10.8165 6.49921 10.7244 6.61529 10.6083L9.26129 7.96129C9.39377 7.81912 9.4659 7.63107 9.46247 7.43677C9.45904 7.24247 9.38033 7.05708 9.24291 6.91967C9.1055 6.78226 8.92011 6.70354 8.72581 6.70012C8.53151 6.69669 8.34347 6.76881 8.20129 6.90129L5.73129 9.37129L3.26129 6.90129C3.11912 6.76881 2.93107 6.69669 2.73677 6.70012C2.54247 6.70354 2.35708 6.78226 2.21967 6.91967C2.08226 7.05708 2.00355 7.24247 2.00012 7.43677C1.99669 7.63107 2.06881 7.81912 2.20129 7.96129L4.84729 10.6083Z"
|
|
100
|
+
fill="black"
|
|
101
|
+
></path>
|
|
102
|
+
</svg>
|
|
103
|
+
</div>
|
|
104
|
+
</button>
|
|
105
|
+
</div>
|
|
106
|
+
</BaseTableHeader>
|
|
107
|
+
</BaseTableRow>
|
|
108
|
+
</BaseTableHead>
|
|
109
|
+
|
|
110
|
+
<BaseTableBody
|
|
111
|
+
class="bg-white"
|
|
112
|
+
>
|
|
113
|
+
<template
|
|
114
|
+
v-for="(row, index) in data"
|
|
115
|
+
:key="getRowKey(row)"
|
|
116
|
+
>
|
|
117
|
+
<BaseTableRow
|
|
118
|
+
:to="rowTo ? rowTo(row) : undefined"
|
|
119
|
+
:selected="rowSelected ? rowSelected(row) : false"
|
|
120
|
+
v-bind="rowBindings(row, index)"
|
|
121
|
+
>
|
|
122
|
+
<BaseTableCell
|
|
123
|
+
v-for="(column, columnIndex) in visibleColumnsInternal"
|
|
124
|
+
:key="column.newKey + index + ':' + columnIndex"
|
|
125
|
+
:class="[column.class, column.numeric ? 'tabular-nums' : '']"
|
|
126
|
+
:align="column.align"
|
|
127
|
+
:style="column.style"
|
|
128
|
+
:to="column.to ? column.to(row) : undefined"
|
|
129
|
+
:href="column.href ? column.href(row) : undefined"
|
|
130
|
+
:target="column.target"
|
|
131
|
+
:ignore-row-interactions="column.ignoreRowInteractions"
|
|
132
|
+
:on-click="onCellClick(row, index, column, columnIndex)"
|
|
133
|
+
>
|
|
134
|
+
<div :class="[columnIndex == 0 ? 'flex items-center gap-4' : '']">
|
|
135
|
+
<template v-if="columnIndex == 0">
|
|
136
|
+
<button
|
|
137
|
+
v-if="showDetailRowIcon"
|
|
138
|
+
type="button"
|
|
139
|
+
class="relative z-[1] || flex h-5 w-5 shrink-0 grow-0 appearance-none items-center justify-center rounded-full border border-slate-300 bg-white text-slate-400 shadow duration-100 hover:text-slate-600 hover:shadow-md"
|
|
140
|
+
@click.stop="toggleDetails(row)"
|
|
141
|
+
>
|
|
142
|
+
<BaseIcon
|
|
143
|
+
v-if="hasDetailedVisible(row)"
|
|
144
|
+
icon="mdi:chevron-down"
|
|
145
|
+
class="h-5 w-5 duration-300"
|
|
146
|
+
:class="{
|
|
147
|
+
'rotate-180': isVisibleDetailRow(row)
|
|
148
|
+
}"
|
|
149
|
+
/>
|
|
150
|
+
</button>
|
|
151
|
+
|
|
152
|
+
<div
|
|
153
|
+
v-if="checkable"
|
|
154
|
+
class="relative z-[1] || flex items-center group cursor-pointer bg-white"
|
|
155
|
+
@click.stop="checkRow(row, index, $event as MouseEvent)"
|
|
156
|
+
>
|
|
157
|
+
<input
|
|
158
|
+
type="checkbox"
|
|
159
|
+
autocomplete="off"
|
|
160
|
+
:disabled="!isRowCheckable(row)"
|
|
161
|
+
:checked="isRowChecked(row)"
|
|
162
|
+
:class="checkboxStyle"
|
|
163
|
+
>
|
|
164
|
+
</div>
|
|
165
|
+
</template>
|
|
166
|
+
|
|
167
|
+
<SlotComponent
|
|
168
|
+
:component="column"
|
|
169
|
+
scoped
|
|
170
|
+
name="default"
|
|
171
|
+
tag="div"
|
|
172
|
+
class="text-sm grow"
|
|
173
|
+
:data-label="column.label"
|
|
174
|
+
:props="{ row, column, index, columnIndex, toggleDetails }"
|
|
175
|
+
/>
|
|
176
|
+
</div>
|
|
177
|
+
</BaseTableCell>
|
|
178
|
+
</BaseTableRow>
|
|
179
|
+
|
|
180
|
+
<BaseTableRow
|
|
181
|
+
v-if="isActiveDetailRow(row)"
|
|
182
|
+
:key="getRowKey(row) + 'detail'"
|
|
183
|
+
>
|
|
184
|
+
<BaseTableCell
|
|
185
|
+
:colspan="columnCount"
|
|
186
|
+
>
|
|
187
|
+
<slot
|
|
188
|
+
name="detail"
|
|
189
|
+
:row="row"
|
|
190
|
+
:index="index"
|
|
191
|
+
/>
|
|
192
|
+
</BaseTableCell>
|
|
193
|
+
</BaseTableRow>
|
|
194
|
+
</template>
|
|
195
|
+
|
|
196
|
+
<BaseTableRow v-if="data.length == 0">
|
|
197
|
+
<BaseTableCell :colspan="columnCount">
|
|
198
|
+
<slot name="empty" />
|
|
199
|
+
</BaseTableCell>
|
|
200
|
+
</BaseTableRow>
|
|
201
|
+
</BaseTableBody>
|
|
202
|
+
</BaseTable>
|
|
203
|
+
</div>
|
|
204
|
+
</template>
|
|
205
|
+
|
|
206
|
+
<script lang="ts" setup>
|
|
207
|
+
import { PropType, ref } from 'vue';
|
|
208
|
+
import { BaseTableColumnData, CollectionItem, Row } from '@/types';
|
|
209
|
+
import SlotComponent from './SlotComponent';
|
|
210
|
+
import { isArray } from 'lodash';
|
|
211
|
+
import { Size } from '@/utils/sizes';
|
|
212
|
+
import objectHash from 'object-hash';
|
|
213
|
+
import BaseTable from './BaseTable.vue';
|
|
214
|
+
import BaseTableHead from './BaseTableHead.vue';
|
|
215
|
+
import BaseTableHeader from './BaseTableHeader.vue';
|
|
216
|
+
import BaseTableBody from './BaseTableBody.vue';
|
|
217
|
+
import BaseTableRow from './BaseTableRow.vue';
|
|
218
|
+
import BaseTableCell from './BaseTableCell.vue';
|
|
219
|
+
import { RouteLocationRaw } from 'vue-router';
|
|
220
|
+
import { customKeyActions } from '@/services/table/customKeyActions';
|
|
221
|
+
|
|
222
|
+
const checkboxStyle =
|
|
223
|
+
'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';
|
|
224
|
+
|
|
225
|
+
defineOptions({
|
|
226
|
+
name: 'BaseDataTableTemplate',
|
|
227
|
+
inheritAttrs: false,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
provide('table', getCurrentInstance());
|
|
231
|
+
|
|
232
|
+
const props = defineProps({
|
|
233
|
+
/** Table data */
|
|
234
|
+
data: {
|
|
235
|
+
type: Array as PropType<Row[]>,
|
|
236
|
+
default: () => [],
|
|
237
|
+
},
|
|
238
|
+
/** Loading state */
|
|
239
|
+
loading: {
|
|
240
|
+
default: false,
|
|
241
|
+
type: Boolean,
|
|
242
|
+
},
|
|
243
|
+
visibleColumns: {
|
|
244
|
+
default: undefined,
|
|
245
|
+
type: Array as PropType<string[]>,
|
|
246
|
+
},
|
|
247
|
+
columnOrder: {
|
|
248
|
+
default: undefined,
|
|
249
|
+
type: Array as PropType<string[]>,
|
|
250
|
+
},
|
|
251
|
+
/** Allow row details */
|
|
252
|
+
detailed: {
|
|
253
|
+
default: false,
|
|
254
|
+
type: Boolean,
|
|
255
|
+
},
|
|
256
|
+
/** Rows can be checked (multiple) */
|
|
257
|
+
checkable: {
|
|
258
|
+
default: false,
|
|
259
|
+
type: Boolean,
|
|
260
|
+
},
|
|
261
|
+
/** Custom method to verify if a row is checkable, works when is checkable */
|
|
262
|
+
isRowCheckable: {
|
|
263
|
+
type: Function,
|
|
264
|
+
default: () => true,
|
|
265
|
+
},
|
|
266
|
+
/** Set which rows are checked, use v-model:checkedRows to make it two-way binding */
|
|
267
|
+
checkedRows: {
|
|
268
|
+
default: () => [],
|
|
269
|
+
type: Array as PropType<Row[]>,
|
|
270
|
+
},
|
|
271
|
+
/** Sets the default sort column field */
|
|
272
|
+
sortField: {
|
|
273
|
+
type: String,
|
|
274
|
+
default: '',
|
|
275
|
+
},
|
|
276
|
+
/**
|
|
277
|
+
* Sets the default sort column direction
|
|
278
|
+
* @values asc, desc
|
|
279
|
+
*/
|
|
280
|
+
sortDirection: {
|
|
281
|
+
type: String,
|
|
282
|
+
default: 'asc',
|
|
283
|
+
},
|
|
284
|
+
/** Controls the visibility of the trigger that toggles the detailed rows. */
|
|
285
|
+
hasDetailedVisible: {
|
|
286
|
+
type: Function,
|
|
287
|
+
default: () => true,
|
|
288
|
+
},
|
|
289
|
+
/* Max height (in px) */
|
|
290
|
+
maxHeight: {
|
|
291
|
+
default: undefined,
|
|
292
|
+
type: Number,
|
|
293
|
+
},
|
|
294
|
+
size: {
|
|
295
|
+
type: String as PropType<Size>,
|
|
296
|
+
default: 'md',
|
|
297
|
+
},
|
|
298
|
+
rowTo: {
|
|
299
|
+
default: undefined,
|
|
300
|
+
type: Function as PropType<((row: CollectionItem) => RouteLocationRaw) | undefined>,
|
|
301
|
+
},
|
|
302
|
+
rowHref: {
|
|
303
|
+
default: undefined,
|
|
304
|
+
type: Function as PropType<((row: CollectionItem) => string) | undefined>,
|
|
305
|
+
},
|
|
306
|
+
onRowClick: {
|
|
307
|
+
default: undefined,
|
|
308
|
+
type: Function as PropType<((row: CollectionItem, index: number, event: MouseEvent) => void) | undefined>,
|
|
309
|
+
},
|
|
310
|
+
rowKey: {
|
|
311
|
+
default: undefined,
|
|
312
|
+
type: Function as PropType<((row: CollectionItem) => string | number) | undefined>,
|
|
313
|
+
},
|
|
314
|
+
rowSelected: {
|
|
315
|
+
default: undefined,
|
|
316
|
+
type: Function as PropType<((row: CollectionItem) => boolean) | undefined>,
|
|
317
|
+
},
|
|
318
|
+
virtualScrolling: {
|
|
319
|
+
default: false,
|
|
320
|
+
type: Boolean,
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const emit = defineEmits([
|
|
325
|
+
'check',
|
|
326
|
+
'check-all',
|
|
327
|
+
'update:checkedRows',
|
|
328
|
+
'details-open',
|
|
329
|
+
'details-close',
|
|
330
|
+
'update:openedDetailed',
|
|
331
|
+
'sort',
|
|
332
|
+
'cell-click',
|
|
333
|
+
'row-click',
|
|
334
|
+
]);
|
|
335
|
+
|
|
336
|
+
const visibleDetailRows = ref<string[]>([]);
|
|
337
|
+
// eslint-disable-next-line vue/no-setup-props-destructure
|
|
338
|
+
const newCheckedRows = ref<Row[]>([...props.checkedRows]);
|
|
339
|
+
const lastCheckedRowIndex = ref<number | null>(null);
|
|
340
|
+
const currentSortColumn = ref<BaseTableColumnData | null>(null);
|
|
341
|
+
const isAsc = ref(true);
|
|
342
|
+
const defaultSlots = ref<BaseTableColumnData[]>([]);
|
|
343
|
+
|
|
344
|
+
const slot = ref<HTMLElement | null>(null);
|
|
345
|
+
|
|
346
|
+
const newColumns = computed(() => {
|
|
347
|
+
const cols = defaultSlots.value;
|
|
348
|
+
|
|
349
|
+
if (props.columnOrder && props.columnOrder.length) {
|
|
350
|
+
|
|
351
|
+
const colOrder = props.columnOrder;
|
|
352
|
+
|
|
353
|
+
return cols
|
|
354
|
+
.sort((a, b) => {
|
|
355
|
+
|
|
356
|
+
// Always put actions column at the end
|
|
357
|
+
|
|
358
|
+
if (a.newKey === customKeyActions) {
|
|
359
|
+
return 1;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (b.newKey === customKeyActions) {
|
|
363
|
+
return -1;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// If not found, put it at the end
|
|
367
|
+
|
|
368
|
+
const existsA = colOrder.includes(a.newKey);
|
|
369
|
+
const existsB = colOrder.includes(b.newKey);
|
|
370
|
+
|
|
371
|
+
if (!existsA && !existsB) {
|
|
372
|
+
return 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (!existsA) {
|
|
376
|
+
return 1;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (!existsB) {
|
|
380
|
+
return -1;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Sort based on the order
|
|
384
|
+
|
|
385
|
+
return colOrder.indexOf(a.newKey) - colOrder.indexOf(b.newKey);
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return cols;
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
const visibleColumnsInternal = computed(() => {
|
|
394
|
+
|
|
395
|
+
if (!newColumns.value) {
|
|
396
|
+
return [];
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return newColumns.value
|
|
400
|
+
.filter((column: BaseTableColumnData) => {
|
|
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 = visibleColumnsInternal.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: BaseTableColumnData, 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
|
+
const found = newCheckedRows.value.find((r) => {
|
|
500
|
+
const key1 = getRowKey(r);
|
|
501
|
+
const key2 = getRowKey(row);
|
|
502
|
+
return key1 == key2
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
return found !== undefined;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Check if all rows in the page are checkable.
|
|
510
|
+
*/
|
|
511
|
+
const isAllUncheckable = computed(() => {
|
|
512
|
+
const validData = props.data.filter((row) => props.isRowCheckable(row));
|
|
513
|
+
return validData.length === 0;
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Check if all rows in the page are checked.
|
|
518
|
+
*/
|
|
519
|
+
const isAllChecked = computed(() => {
|
|
520
|
+
const validData = props.data.filter((row) => {
|
|
521
|
+
return props.isRowCheckable(row);
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
if (validData.length === 0) {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const missingChecked = validData.some((currentRow) => {
|
|
529
|
+
return !isRowChecked(currentRow);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
return !missingChecked;
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
function getCheckedRowIndex(row: Row) {
|
|
536
|
+
const foundIndex = newCheckedRows.value.findIndex((r) => {
|
|
537
|
+
const key1 = getRowKey(r);
|
|
538
|
+
const key2 = getRowKey(row);
|
|
539
|
+
return key1 == key2
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
return foundIndex;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Remove a checked row from the array.
|
|
547
|
+
*/
|
|
548
|
+
function removeCheckedRow(row: Row) {
|
|
549
|
+
const index = getCheckedRowIndex(row);
|
|
550
|
+
if (index >= 0) {
|
|
551
|
+
newCheckedRows.value.splice(index, 1);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Header checkbox click listener.
|
|
557
|
+
* Add or remove all rows in current page.
|
|
558
|
+
*/
|
|
559
|
+
function checkAll() {
|
|
560
|
+
if (isAllChecked.value) {
|
|
561
|
+
newCheckedRows.value = [];
|
|
562
|
+
} else {
|
|
563
|
+
props.data.forEach((currentRow) => {
|
|
564
|
+
if (props.isRowCheckable(currentRow) && !isRowChecked(currentRow)) {
|
|
565
|
+
newCheckedRows.value.push(currentRow);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
sendCheckUpdate();
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Remove all rows in current page.
|
|
575
|
+
*/
|
|
576
|
+
function uncheckAll() {
|
|
577
|
+
newCheckedRows.value = [];
|
|
578
|
+
|
|
579
|
+
sendCheckUpdate();
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function sendCheckUpdate() {
|
|
583
|
+
emit('check', newCheckedRows.value);
|
|
584
|
+
emit('check-all', newCheckedRows.value);
|
|
585
|
+
emit('update:checkedRows', newCheckedRows.value);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Row checkbox click listener.
|
|
590
|
+
*/
|
|
591
|
+
function checkRow(row: Row, index: number, event: MouseEvent) {
|
|
592
|
+
if (!props.isRowCheckable(row)) {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const lastIndex = lastCheckedRowIndex.value;
|
|
597
|
+
lastCheckedRowIndex.value = index;
|
|
598
|
+
|
|
599
|
+
if (event.shiftKey && lastIndex !== null && index !== lastIndex) {
|
|
600
|
+
shiftCheckRow(row, index, lastIndex);
|
|
601
|
+
} else if (!isRowChecked(row)) {
|
|
602
|
+
newCheckedRows.value.push(row);
|
|
603
|
+
} else {
|
|
604
|
+
removeCheckedRow(row);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
emit('check', newCheckedRows.value, row);
|
|
608
|
+
|
|
609
|
+
// Emit checked rows to update user variable
|
|
610
|
+
emit('update:checkedRows', newCheckedRows.value);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Check row when shift is pressed.
|
|
615
|
+
*/
|
|
616
|
+
function shiftCheckRow(row: Row, index: number, lastCheckedRowIndex: number) {
|
|
617
|
+
// Get the subset of the list between the two indices
|
|
618
|
+
const subset = props.data.slice(
|
|
619
|
+
Math.min(index, lastCheckedRowIndex),
|
|
620
|
+
Math.max(index, lastCheckedRowIndex) + 1
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
// Determine the operation based on the state of the clicked checkbox
|
|
624
|
+
const shouldCheck = !isRowChecked(row);
|
|
625
|
+
|
|
626
|
+
subset.forEach((item) => {
|
|
627
|
+
removeCheckedRow(item);
|
|
628
|
+
if (shouldCheck && props.isRowCheckable(item)) {
|
|
629
|
+
newCheckedRows.value.push(item);
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Toggle to show/hide details slot
|
|
636
|
+
*/
|
|
637
|
+
function toggleDetails(row: Row) {
|
|
638
|
+
const found = isVisibleDetailRow(row);
|
|
639
|
+
|
|
640
|
+
if (found) {
|
|
641
|
+
closeDetailRow(row);
|
|
642
|
+
emit('details-close', row);
|
|
643
|
+
} else {
|
|
644
|
+
openDetailRow(row);
|
|
645
|
+
emit('details-open', row);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Syncs the detailed rows with the parent component
|
|
649
|
+
emit('update:openedDetailed', visibleDetailRows.value);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function openDetailRow(row: Row) {
|
|
653
|
+
const key = getRowKey(row);
|
|
654
|
+
visibleDetailRows.value.push(key);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function closeDetailRow(row: Row) {
|
|
658
|
+
const key = getRowKey(row);
|
|
659
|
+
const i = visibleDetailRows.value.indexOf(key);
|
|
660
|
+
if (i >= 0) {
|
|
661
|
+
visibleDetailRows.value.splice(i, 1);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function isVisibleDetailRow(row: Row) {
|
|
666
|
+
const key = getRowKey(row);
|
|
667
|
+
return visibleDetailRows.value.indexOf(key) >= 0;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
function isActiveDetailRow(row: Row) {
|
|
671
|
+
return props.detailed && isVisibleDetailRow(row);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Update sort state
|
|
676
|
+
*/
|
|
677
|
+
function updateSortState() {
|
|
678
|
+
const sortField = props.sortField;
|
|
679
|
+
|
|
680
|
+
const sortDirection = props.sortDirection;
|
|
681
|
+
|
|
682
|
+
const sortColumn = newColumns.value.filter(
|
|
683
|
+
(column) => column.field === sortField
|
|
684
|
+
)[0];
|
|
685
|
+
|
|
686
|
+
// Set sort state
|
|
687
|
+
|
|
688
|
+
if (sortColumn) {
|
|
689
|
+
currentSortColumn.value = sortColumn;
|
|
690
|
+
isAsc.value = sortDirection.toLowerCase() !== 'desc';
|
|
691
|
+
} else {
|
|
692
|
+
currentSortColumn.value = null;
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/*
|
|
698
|
+
|--------------------------------------------------------------------------
|
|
699
|
+
| BaseTableColumns functions
|
|
700
|
+
|--------------------------------------------------------------------------
|
|
701
|
+
*/
|
|
702
|
+
|
|
703
|
+
function addColumn(column: BaseTableColumnData) {
|
|
704
|
+
defaultSlots.value.push(column);
|
|
705
|
+
|
|
706
|
+
const slotHTMLElement = slot.value as HTMLElement;
|
|
707
|
+
|
|
708
|
+
if (slotHTMLElement && slotHTMLElement.children) {
|
|
709
|
+
nextTick(() => {
|
|
710
|
+
const ids = defaultSlots.value
|
|
711
|
+
.map((it) => `[data-id="${it.newKey}"]`)
|
|
712
|
+
.join(',');
|
|
713
|
+
|
|
714
|
+
const sortedIds = Array.from(slotHTMLElement.querySelectorAll(ids)).map(
|
|
715
|
+
(el: Element) => el.getAttribute('data-id')
|
|
716
|
+
);
|
|
717
|
+
|
|
718
|
+
defaultSlots.value = defaultSlots.value.sort((a, b) => {
|
|
719
|
+
return (
|
|
720
|
+
sortedIds.indexOf(`${a.newKey}`) - sortedIds.indexOf(`${b.newKey}`)
|
|
721
|
+
);
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function removeColumn(column: BaseTableColumnData) {
|
|
728
|
+
defaultSlots.value = defaultSlots.value.filter(
|
|
729
|
+
(d) => d.newKey !== column.newKey
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function rowBindings(row: CollectionItem, index: number) {
|
|
734
|
+
return {
|
|
735
|
+
onClick: props.onRowClick ? (event: MouseEvent) => props.onRowClick && props.onRowClick(row, index, event) : undefined,
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
function onCellClick(row: CollectionItem, index: number, column: BaseTableColumnData, columnIndex: number) {
|
|
740
|
+
if (!column.onClick) {
|
|
741
|
+
return undefined;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
return (event: MouseEvent) => {
|
|
745
|
+
if (!column.onClick) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
column.onClick(row, index, column, columnIndex, event);
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
let warningNoRowKeyFoundShown = false;
|
|
754
|
+
|
|
755
|
+
function getRowKey(row: Row): string {
|
|
756
|
+
|
|
757
|
+
if (props.rowKey) {
|
|
758
|
+
return props.rowKey(row) + '';
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (row.id) {
|
|
762
|
+
return row.id;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (row.key) {
|
|
766
|
+
return row.key;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (row.uuid) {
|
|
770
|
+
return row.uuid;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (!warningNoRowKeyFoundShown) {
|
|
774
|
+
console.warn('%cNo unique key found for items provided to BaseDataTable.%cPlease provide a unique key for each row (id, key or uuid) or use the row-key props to specify a unique key.', 'font-weight: bold', 'font-weight: normal');
|
|
775
|
+
warningNoRowKeyFoundShown = true;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// if no key is found, hash a simplified version of the row object
|
|
779
|
+
// We use a simplified version to avoid hashing functions, objects, etc. for performance reasons
|
|
780
|
+
|
|
781
|
+
const simpleRow = {} as Record<string, string | number | boolean>;
|
|
782
|
+
|
|
783
|
+
for (const key in row) {
|
|
784
|
+
const value = row[key];
|
|
785
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
786
|
+
simpleRow[key] = value;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
return objectHash(simpleRow);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
provide('addColumn', addColumn);
|
|
794
|
+
provide('removeColumn', removeColumn);
|
|
795
|
+
|
|
796
|
+
const baseTableRef = ref<InstanceType<typeof BaseTable> | null>(null);
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
/*
|
|
800
|
+
|--------------------------------------------------------------------------
|
|
801
|
+
| Checks
|
|
802
|
+
|--------------------------------------------------------------------------
|
|
803
|
+
*/
|
|
804
|
+
|
|
805
|
+
watch(
|
|
806
|
+
() => newColumns.value.map((item) => item.newKey),
|
|
807
|
+
(keys: string[]) => {
|
|
808
|
+
|
|
809
|
+
// check duplicates
|
|
810
|
+
|
|
811
|
+
const duplicates = keys.reduce((acc, key, index) => {
|
|
812
|
+
if (keys.indexOf(key) !== index && !acc.includes(key)) {
|
|
813
|
+
acc.push(key);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
return acc;
|
|
817
|
+
}, [] as string[]);
|
|
818
|
+
|
|
819
|
+
if (duplicates.length) {
|
|
820
|
+
throw new Error(`Duplicate BaseTableColumn keys found: ${duplicates.join(', ')}`);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
/*
|
|
826
|
+
|--------------------------------------------------------------------------
|
|
827
|
+
| Expose
|
|
828
|
+
|--------------------------------------------------------------------------
|
|
829
|
+
*/
|
|
830
|
+
|
|
831
|
+
defineExpose({
|
|
832
|
+
newColumns,
|
|
833
|
+
uncheckAll,
|
|
834
|
+
scrollTop: () => {
|
|
835
|
+
baseTableRef.value?.scrollTop();
|
|
836
|
+
},
|
|
837
|
+
});
|
|
838
|
+
</script>
|