vueless 1.3.2-beta.4 → 1.3.3-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components.d.ts +77 -0
- package/components.ts +77 -0
- package/icons/storybook/keep.svg +1 -0
- package/icons/storybook/keyboard_arrow_down.svg +1 -0
- package/icons/storybook/keyboard_arrow_up.svg +1 -0
- package/index.d.ts +0 -78
- package/index.ts +0 -78
- package/package.json +7 -3
- package/tailwind.css +6 -0
- package/ui.button/UButton.vue +1 -0
- package/ui.data-table/UTable.vue +133 -7
- package/ui.data-table/UTableRow.vue +48 -3
- package/ui.data-table/config.ts +9 -3
- package/ui.data-table/storybook/stories.ts +223 -6
- package/ui.data-table/tests/UTableRow.test.ts +9 -0
- package/ui.data-table/types.ts +8 -0
package/components.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* Buttons & Links */
|
|
2
|
+
export { default as UButton } from "./ui.button/UButton.vue";
|
|
3
|
+
export { default as ULink } from "./ui.button-link/ULink.vue";
|
|
4
|
+
export { default as UToggle } from "./ui.button-toggle/UToggle.vue";
|
|
5
|
+
/* Dropdowns */
|
|
6
|
+
export { default as UDropdownButton } from "./ui.dropdown-button/UDropdownButton.vue";
|
|
7
|
+
export { default as UDropdownBadge } from "./ui.dropdown-badge/UDropdownBadge.vue";
|
|
8
|
+
export { default as UDropdownLink } from "./ui.dropdown-link/UDropdownLink.vue";
|
|
9
|
+
/* Form Inputs & Controls */
|
|
10
|
+
export { default as UInput } from "./ui.form-input/UInput.vue";
|
|
11
|
+
export { default as UInputFile } from "./ui.form-input-file/UInputFile.vue";
|
|
12
|
+
export { default as UInputNumber } from "./ui.form-input-number/UInputNumber.vue";
|
|
13
|
+
export { default as UInputCounter } from "./ui.form-input-counter/UInputCounter.vue";
|
|
14
|
+
export { default as UInputPassword } from "./ui.form-input-password/UInputPassword.vue";
|
|
15
|
+
export { default as UInputRating } from "./ui.form-input-rating/UInputRating.vue";
|
|
16
|
+
export { default as UInputSearch } from "./ui.form-input-search/UInputSearch.vue";
|
|
17
|
+
export { default as UTextarea } from "./ui.form-textarea/UTextarea.vue";
|
|
18
|
+
export { default as USelect } from "./ui.form-select/USelect.vue";
|
|
19
|
+
export { default as UListbox } from "./ui.form-listbox/UListbox.vue";
|
|
20
|
+
export { default as UCheckbox } from "./ui.form-checkbox/UCheckbox.vue";
|
|
21
|
+
export { default as UCheckboxGroup } from "./ui.form-checkbox-group/UCheckboxGroup.vue";
|
|
22
|
+
export { default as UCheckboxMultiState } from "./ui.form-checkbox-multi-state/UCheckboxMultiState.vue";
|
|
23
|
+
export { default as USwitch } from "./ui.form-switch/USwitch.vue";
|
|
24
|
+
export { default as URadio } from "./ui.form-radio/URadio.vue";
|
|
25
|
+
export { default as URadioGroup } from "./ui.form-radio-group/URadioGroup.vue";
|
|
26
|
+
export { default as UCalendar } from "./ui.form-calendar/UCalendar.vue";
|
|
27
|
+
export { default as UDatePicker } from "./ui.form-date-picker/UDatePicker.vue";
|
|
28
|
+
export { default as UDatePickerRange } from "./ui.form-date-picker-range/UDatePickerRange.vue";
|
|
29
|
+
export { default as UColorToggle } from "./ui.form-color-toggle/UColorToggle.vue";
|
|
30
|
+
export { default as ULabel } from "./ui.form-label/ULabel.vue";
|
|
31
|
+
/* Text & Content */
|
|
32
|
+
export { default as UHeader } from "./ui.text-header/UHeader.vue";
|
|
33
|
+
export { default as UText } from "./ui.text-block/UText.vue";
|
|
34
|
+
export { default as UAlert } from "./ui.text-alert/UAlert.vue";
|
|
35
|
+
export { default as UNotify } from "./ui.text-notify/UNotify.vue";
|
|
36
|
+
export { default as UNumber } from "./ui.text-number/UNumber.vue";
|
|
37
|
+
export { default as UFile } from "./ui.text-file/UFile.vue";
|
|
38
|
+
export { default as UFiles } from "./ui.text-files/UFiles.vue";
|
|
39
|
+
export { default as UEmpty } from "./ui.text-empty/UEmpty.vue";
|
|
40
|
+
export { default as UBadge } from "./ui.text-badge/UBadge.vue";
|
|
41
|
+
/* Containers */
|
|
42
|
+
export { default as UDivider } from "./ui.container-divider/UDivider.vue";
|
|
43
|
+
export { default as UCol } from "./ui.container-col/UCol.vue";
|
|
44
|
+
export { default as URow } from "./ui.container-row/URow.vue";
|
|
45
|
+
export { default as UGroup } from "./ui.container-group/UGroup.vue";
|
|
46
|
+
export { default as UGroups } from "./ui.container-groups/UGroups.vue";
|
|
47
|
+
export { default as UAccordion } from "./ui.container-accordion/UAccordion.vue";
|
|
48
|
+
export { default as UAccordionItem } from "./ui.container-accordion-item/UAccordionItem.vue";
|
|
49
|
+
export { default as UCard } from "./ui.container-card/UCard.vue";
|
|
50
|
+
export { default as UModal } from "./ui.container-modal/UModal.vue";
|
|
51
|
+
export { default as UModalConfirm } from "./ui.container-modal-confirm/UModalConfirm.vue";
|
|
52
|
+
export { default as UDrawer } from "./ui.container-drawer/UDrawer.vue";
|
|
53
|
+
export { default as UPage } from "./ui.container-page/UPage.vue";
|
|
54
|
+
/* Images and Icons */
|
|
55
|
+
export { default as UIcon } from "./ui.image-icon/UIcon.vue";
|
|
56
|
+
export { default as UAvatar } from "./ui.image-avatar/UAvatar.vue";
|
|
57
|
+
/* Data */
|
|
58
|
+
export { default as UTable } from "./ui.data-table/UTable.vue";
|
|
59
|
+
export { default as UDataList } from "./ui.data-list/UDataList.vue";
|
|
60
|
+
/* Navigation */
|
|
61
|
+
export { default as UTab } from "./ui.navigation-tab/UTab.vue";
|
|
62
|
+
export { default as UTabs } from "./ui.navigation-tabs/UTabs.vue";
|
|
63
|
+
export { default as UProgress } from "./ui.navigation-progress/UProgress.vue";
|
|
64
|
+
export { default as UPagination } from "./ui.navigation-pagination/UPagination.vue";
|
|
65
|
+
export { default as UBreadcrumbs } from "./ui.navigation-breadcrumbs/UBreadcrumbs.vue";
|
|
66
|
+
/* Loaders and Skeletons */
|
|
67
|
+
export { default as ULoader } from "./ui.loader/ULoader.vue";
|
|
68
|
+
export { default as ULoaderProgress } from "./ui.loader-progress/ULoaderProgress.vue";
|
|
69
|
+
export { default as ULoaderOverlay } from "./ui.loader-overlay/ULoaderOverlay.vue";
|
|
70
|
+
export { default as USkeleton } from "./ui.skeleton/USkeleton.vue";
|
|
71
|
+
export { default as USkeletonText } from "./ui.skeleton-text/USkeletonText.vue";
|
|
72
|
+
export { default as USkeletonInput } from "./ui.skeleton-input/USkeletonInput.vue";
|
|
73
|
+
export { default as USkeletonChoice } from "./ui.skeleton-choice/USkeletonChoice.vue";
|
|
74
|
+
/* Other */
|
|
75
|
+
export { default as UDot } from "./ui.other-dot/UDot.vue";
|
|
76
|
+
export { default as UChip } from "./ui.other-chip/UChip.vue";
|
|
77
|
+
export { default as UThemeColorToggle } from "./ui.other-theme-color-toggle/UThemeColorToggle.vue";
|
package/components.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* Buttons & Links */
|
|
2
|
+
export { default as UButton } from "./ui.button/UButton.vue";
|
|
3
|
+
export { default as ULink } from "./ui.button-link/ULink.vue";
|
|
4
|
+
export { default as UToggle } from "./ui.button-toggle/UToggle.vue";
|
|
5
|
+
/* Dropdowns */
|
|
6
|
+
export { default as UDropdownButton } from "./ui.dropdown-button/UDropdownButton.vue";
|
|
7
|
+
export { default as UDropdownBadge } from "./ui.dropdown-badge/UDropdownBadge.vue";
|
|
8
|
+
export { default as UDropdownLink } from "./ui.dropdown-link/UDropdownLink.vue";
|
|
9
|
+
/* Form Inputs & Controls */
|
|
10
|
+
export { default as UInput } from "./ui.form-input/UInput.vue";
|
|
11
|
+
export { default as UInputFile } from "./ui.form-input-file/UInputFile.vue";
|
|
12
|
+
export { default as UInputNumber } from "./ui.form-input-number/UInputNumber.vue";
|
|
13
|
+
export { default as UInputCounter } from "./ui.form-input-counter/UInputCounter.vue";
|
|
14
|
+
export { default as UInputPassword } from "./ui.form-input-password/UInputPassword.vue";
|
|
15
|
+
export { default as UInputRating } from "./ui.form-input-rating/UInputRating.vue";
|
|
16
|
+
export { default as UInputSearch } from "./ui.form-input-search/UInputSearch.vue";
|
|
17
|
+
export { default as UTextarea } from "./ui.form-textarea/UTextarea.vue";
|
|
18
|
+
export { default as USelect } from "./ui.form-select/USelect.vue";
|
|
19
|
+
export { default as UListbox } from "./ui.form-listbox/UListbox.vue";
|
|
20
|
+
export { default as UCheckbox } from "./ui.form-checkbox/UCheckbox.vue";
|
|
21
|
+
export { default as UCheckboxGroup } from "./ui.form-checkbox-group/UCheckboxGroup.vue";
|
|
22
|
+
export { default as UCheckboxMultiState } from "./ui.form-checkbox-multi-state/UCheckboxMultiState.vue";
|
|
23
|
+
export { default as USwitch } from "./ui.form-switch/USwitch.vue";
|
|
24
|
+
export { default as URadio } from "./ui.form-radio/URadio.vue";
|
|
25
|
+
export { default as URadioGroup } from "./ui.form-radio-group/URadioGroup.vue";
|
|
26
|
+
export { default as UCalendar } from "./ui.form-calendar/UCalendar.vue";
|
|
27
|
+
export { default as UDatePicker } from "./ui.form-date-picker/UDatePicker.vue";
|
|
28
|
+
export { default as UDatePickerRange } from "./ui.form-date-picker-range/UDatePickerRange.vue";
|
|
29
|
+
export { default as UColorToggle } from "./ui.form-color-toggle/UColorToggle.vue";
|
|
30
|
+
export { default as ULabel } from "./ui.form-label/ULabel.vue";
|
|
31
|
+
/* Text & Content */
|
|
32
|
+
export { default as UHeader } from "./ui.text-header/UHeader.vue";
|
|
33
|
+
export { default as UText } from "./ui.text-block/UText.vue";
|
|
34
|
+
export { default as UAlert } from "./ui.text-alert/UAlert.vue";
|
|
35
|
+
export { default as UNotify } from "./ui.text-notify/UNotify.vue";
|
|
36
|
+
export { default as UNumber } from "./ui.text-number/UNumber.vue";
|
|
37
|
+
export { default as UFile } from "./ui.text-file/UFile.vue";
|
|
38
|
+
export { default as UFiles } from "./ui.text-files/UFiles.vue";
|
|
39
|
+
export { default as UEmpty } from "./ui.text-empty/UEmpty.vue";
|
|
40
|
+
export { default as UBadge } from "./ui.text-badge/UBadge.vue";
|
|
41
|
+
/* Containers */
|
|
42
|
+
export { default as UDivider } from "./ui.container-divider/UDivider.vue";
|
|
43
|
+
export { default as UCol } from "./ui.container-col/UCol.vue";
|
|
44
|
+
export { default as URow } from "./ui.container-row/URow.vue";
|
|
45
|
+
export { default as UGroup } from "./ui.container-group/UGroup.vue";
|
|
46
|
+
export { default as UGroups } from "./ui.container-groups/UGroups.vue";
|
|
47
|
+
export { default as UAccordion } from "./ui.container-accordion/UAccordion.vue";
|
|
48
|
+
export { default as UAccordionItem } from "./ui.container-accordion-item/UAccordionItem.vue";
|
|
49
|
+
export { default as UCard } from "./ui.container-card/UCard.vue";
|
|
50
|
+
export { default as UModal } from "./ui.container-modal/UModal.vue";
|
|
51
|
+
export { default as UModalConfirm } from "./ui.container-modal-confirm/UModalConfirm.vue";
|
|
52
|
+
export { default as UDrawer } from "./ui.container-drawer/UDrawer.vue";
|
|
53
|
+
export { default as UPage } from "./ui.container-page/UPage.vue";
|
|
54
|
+
/* Images and Icons */
|
|
55
|
+
export { default as UIcon } from "./ui.image-icon/UIcon.vue";
|
|
56
|
+
export { default as UAvatar } from "./ui.image-avatar/UAvatar.vue";
|
|
57
|
+
/* Data */
|
|
58
|
+
export { default as UTable } from "./ui.data-table/UTable.vue";
|
|
59
|
+
export { default as UDataList } from "./ui.data-list/UDataList.vue";
|
|
60
|
+
/* Navigation */
|
|
61
|
+
export { default as UTab } from "./ui.navigation-tab/UTab.vue";
|
|
62
|
+
export { default as UTabs } from "./ui.navigation-tabs/UTabs.vue";
|
|
63
|
+
export { default as UProgress } from "./ui.navigation-progress/UProgress.vue";
|
|
64
|
+
export { default as UPagination } from "./ui.navigation-pagination/UPagination.vue";
|
|
65
|
+
export { default as UBreadcrumbs } from "./ui.navigation-breadcrumbs/UBreadcrumbs.vue";
|
|
66
|
+
/* Loaders and Skeletons */
|
|
67
|
+
export { default as ULoader } from "./ui.loader/ULoader.vue";
|
|
68
|
+
export { default as ULoaderProgress } from "./ui.loader-progress/ULoaderProgress.vue";
|
|
69
|
+
export { default as ULoaderOverlay } from "./ui.loader-overlay/ULoaderOverlay.vue";
|
|
70
|
+
export { default as USkeleton } from "./ui.skeleton/USkeleton.vue";
|
|
71
|
+
export { default as USkeletonText } from "./ui.skeleton-text/USkeletonText.vue";
|
|
72
|
+
export { default as USkeletonInput } from "./ui.skeleton-input/USkeletonInput.vue";
|
|
73
|
+
export { default as USkeletonChoice } from "./ui.skeleton-choice/USkeletonChoice.vue";
|
|
74
|
+
/* Other */
|
|
75
|
+
export { default as UDot } from "./ui.other-dot/UDot.vue";
|
|
76
|
+
export { default as UChip } from "./ui.other-chip/UChip.vue";
|
|
77
|
+
export { default as UThemeColorToggle } from "./ui.other-theme-color-toggle/UThemeColorToggle.vue";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="m640.22-454.22 86 77v68.37H514.07v240.28L480-34.5l-34.07-34.07v-240.28H234.02v-68.37l80-77v-327.45h-50v-68.13h426.2v68.13h-50v327.45Zm-313.96 77h301.48l-55.89-51.89v-352.56h-189.7v352.56l-55.89 51.89Zm150.74 0Z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="M480-338.26 234.26-584 283-632.74l197 197 197-197L725.74-584 480-338.26Z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="m480-548.26-197 197L234.26-400 480-645.74 725.74-400 677-351.26l-197-197Z"/></svg>
|
package/index.d.ts
CHANGED
|
@@ -53,84 +53,6 @@ export { NotificationType, NotificationPosition, NotificationDuration } from "./
|
|
|
53
53
|
/* directives */
|
|
54
54
|
export { default as vTooltip } from "./v.tooltip/vTooltip";
|
|
55
55
|
export { default as vClickOutside } from "./v.click-outside/vClickOutside";
|
|
56
|
-
/* components */
|
|
57
|
-
/* Buttons & Links */
|
|
58
|
-
export { default as UButton } from "./ui.button/UButton.vue";
|
|
59
|
-
export { default as ULink } from "./ui.button-link/ULink.vue";
|
|
60
|
-
export { default as UToggle } from "./ui.button-toggle/UToggle.vue";
|
|
61
|
-
/* Dropdowns */
|
|
62
|
-
export { default as UDropdownButton } from "./ui.dropdown-button/UDropdownButton.vue";
|
|
63
|
-
export { default as UDropdownBadge } from "./ui.dropdown-badge/UDropdownBadge.vue";
|
|
64
|
-
export { default as UDropdownLink } from "./ui.dropdown-link/UDropdownLink.vue";
|
|
65
|
-
/* Form Inputs & Controls */
|
|
66
|
-
export { default as UInput } from "./ui.form-input/UInput.vue";
|
|
67
|
-
export { default as UInputFile } from "./ui.form-input-file/UInputFile.vue";
|
|
68
|
-
export { default as UInputNumber } from "./ui.form-input-number/UInputNumber.vue";
|
|
69
|
-
export { default as UInputCounter } from "./ui.form-input-counter/UInputCounter.vue";
|
|
70
|
-
export { default as UInputPassword } from "./ui.form-input-password/UInputPassword.vue";
|
|
71
|
-
export { default as UInputRating } from "./ui.form-input-rating/UInputRating.vue";
|
|
72
|
-
export { default as UInputSearch } from "./ui.form-input-search/UInputSearch.vue";
|
|
73
|
-
export { default as UTextarea } from "./ui.form-textarea/UTextarea.vue";
|
|
74
|
-
export { default as USelect } from "./ui.form-select/USelect.vue";
|
|
75
|
-
export { default as UListbox } from "./ui.form-listbox/UListbox.vue";
|
|
76
|
-
export { default as UCheckbox } from "./ui.form-checkbox/UCheckbox.vue";
|
|
77
|
-
export { default as UCheckboxGroup } from "./ui.form-checkbox-group/UCheckboxGroup.vue";
|
|
78
|
-
export { default as UCheckboxMultiState } from "./ui.form-checkbox-multi-state/UCheckboxMultiState.vue";
|
|
79
|
-
export { default as USwitch } from "./ui.form-switch/USwitch.vue";
|
|
80
|
-
export { default as URadio } from "./ui.form-radio/URadio.vue";
|
|
81
|
-
export { default as URadioGroup } from "./ui.form-radio-group/URadioGroup.vue";
|
|
82
|
-
export { default as UCalendar } from "./ui.form-calendar/UCalendar.vue";
|
|
83
|
-
export { default as UDatePicker } from "./ui.form-date-picker/UDatePicker.vue";
|
|
84
|
-
export { default as UDatePickerRange } from "./ui.form-date-picker-range/UDatePickerRange.vue";
|
|
85
|
-
export { default as UColorToggle } from "./ui.form-color-toggle/UColorToggle.vue";
|
|
86
|
-
export { default as ULabel } from "./ui.form-label/ULabel.vue";
|
|
87
|
-
/* Text & Content */
|
|
88
|
-
export { default as UHeader } from "./ui.text-header/UHeader.vue";
|
|
89
|
-
export { default as UText } from "./ui.text-block/UText.vue";
|
|
90
|
-
export { default as UAlert } from "./ui.text-alert/UAlert.vue";
|
|
91
|
-
export { default as UNotify } from "./ui.text-notify/UNotify.vue";
|
|
92
|
-
export { default as UNumber } from "./ui.text-number/UNumber.vue";
|
|
93
|
-
export { default as UFile } from "./ui.text-file/UFile.vue";
|
|
94
|
-
export { default as UFiles } from "./ui.text-files/UFiles.vue";
|
|
95
|
-
export { default as UEmpty } from "./ui.text-empty/UEmpty.vue";
|
|
96
|
-
export { default as UBadge } from "./ui.text-badge/UBadge.vue";
|
|
97
|
-
/* Containers */
|
|
98
|
-
export { default as UDivider } from "./ui.container-divider/UDivider.vue";
|
|
99
|
-
export { default as UCol } from "./ui.container-col/UCol.vue";
|
|
100
|
-
export { default as URow } from "./ui.container-row/URow.vue";
|
|
101
|
-
export { default as UGroup } from "./ui.container-group/UGroup.vue";
|
|
102
|
-
export { default as UGroups } from "./ui.container-groups/UGroups.vue";
|
|
103
|
-
export { default as UAccordion } from "./ui.container-accordion/UAccordion.vue";
|
|
104
|
-
export { default as UAccordionItem } from "./ui.container-accordion-item/UAccordionItem.vue";
|
|
105
|
-
export { default as UCard } from "./ui.container-card/UCard.vue";
|
|
106
|
-
export { default as UModal } from "./ui.container-modal/UModal.vue";
|
|
107
|
-
export { default as UModalConfirm } from "./ui.container-modal-confirm/UModalConfirm.vue";
|
|
108
|
-
export { default as UDrawer } from "./ui.container-drawer/UDrawer.vue";
|
|
109
|
-
export { default as UPage } from "./ui.container-page/UPage.vue";
|
|
110
|
-
/* Images and Icons */
|
|
111
|
-
export { default as UIcon } from "./ui.image-icon/UIcon.vue";
|
|
112
|
-
export { default as UAvatar } from "./ui.image-avatar/UAvatar.vue";
|
|
113
|
-
/* Data */
|
|
114
|
-
export { default as UTable } from "./ui.data-table/UTable.vue";
|
|
115
|
-
export { default as UDataList } from "./ui.data-list/UDataList.vue";
|
|
116
|
-
/* Navigation */
|
|
117
|
-
export { default as UTab } from "./ui.navigation-tab/UTab.vue";
|
|
118
|
-
export { default as UTabs } from "./ui.navigation-tabs/UTabs.vue";
|
|
119
|
-
export { default as UProgress } from "./ui.navigation-progress/UProgress.vue";
|
|
120
|
-
export { default as UPagination } from "./ui.navigation-pagination/UPagination.vue";
|
|
121
|
-
export { default as UBreadcrumbs } from "./ui.navigation-breadcrumbs/UBreadcrumbs.vue";
|
|
122
|
-
/* Loaders and Skeletons */
|
|
123
|
-
export { default as ULoader } from "./ui.loader/ULoader.vue";
|
|
124
|
-
export { default as ULoaderProgress } from "./ui.loader-progress/ULoaderProgress.vue";
|
|
125
|
-
export { default as ULoaderOverlay } from "./ui.loader-overlay/ULoaderOverlay.vue";
|
|
126
|
-
export { default as USkeleton } from "./ui.skeleton/USkeleton.vue";
|
|
127
|
-
export { default as USkeletonText } from "./ui.skeleton-text/USkeletonText.vue";
|
|
128
|
-
export { default as USkeletonInput } from "./ui.skeleton-input/USkeletonInput.vue";
|
|
129
|
-
export { default as USkeletonChoice } from "./ui.skeleton-choice/USkeletonChoice.vue";
|
|
130
|
-
/* Other */
|
|
131
|
-
export { default as UDot } from "./ui.other-dot/UDot.vue";
|
|
132
|
-
export { default as UChip } from "./ui.other-chip/UChip.vue";
|
|
133
|
-
export { default as UThemeColorToggle } from "./ui.other-theme-color-toggle/UThemeColorToggle.vue";
|
|
134
56
|
/* eslint-enable prettier/prettier */
|
|
135
57
|
|
|
136
58
|
/* types */
|
package/index.ts
CHANGED
|
@@ -59,84 +59,6 @@ export { NotificationType, NotificationPosition, NotificationDuration } from "./
|
|
|
59
59
|
/* directives */
|
|
60
60
|
export { default as vTooltip } from "./v.tooltip/vTooltip";
|
|
61
61
|
export { default as vClickOutside } from "./v.click-outside/vClickOutside";
|
|
62
|
-
/* components */
|
|
63
|
-
/* Buttons & Links */
|
|
64
|
-
export { default as UButton } from "./ui.button/UButton.vue";
|
|
65
|
-
export { default as ULink } from "./ui.button-link/ULink.vue";
|
|
66
|
-
export { default as UToggle } from "./ui.button-toggle/UToggle.vue";
|
|
67
|
-
/* Dropdowns */
|
|
68
|
-
export { default as UDropdownButton } from "./ui.dropdown-button/UDropdownButton.vue";
|
|
69
|
-
export { default as UDropdownBadge } from "./ui.dropdown-badge/UDropdownBadge.vue";
|
|
70
|
-
export { default as UDropdownLink } from "./ui.dropdown-link/UDropdownLink.vue";
|
|
71
|
-
/* Form Inputs & Controls */
|
|
72
|
-
export { default as UInput } from "./ui.form-input/UInput.vue";
|
|
73
|
-
export { default as UInputFile } from "./ui.form-input-file/UInputFile.vue";
|
|
74
|
-
export { default as UInputNumber } from "./ui.form-input-number/UInputNumber.vue";
|
|
75
|
-
export { default as UInputCounter } from "./ui.form-input-counter/UInputCounter.vue";
|
|
76
|
-
export { default as UInputPassword } from "./ui.form-input-password/UInputPassword.vue";
|
|
77
|
-
export { default as UInputRating } from "./ui.form-input-rating/UInputRating.vue";
|
|
78
|
-
export { default as UInputSearch } from "./ui.form-input-search/UInputSearch.vue";
|
|
79
|
-
export { default as UTextarea } from "./ui.form-textarea/UTextarea.vue";
|
|
80
|
-
export { default as USelect } from "./ui.form-select/USelect.vue";
|
|
81
|
-
export { default as UListbox } from "./ui.form-listbox/UListbox.vue";
|
|
82
|
-
export { default as UCheckbox } from "./ui.form-checkbox/UCheckbox.vue";
|
|
83
|
-
export { default as UCheckboxGroup } from "./ui.form-checkbox-group/UCheckboxGroup.vue";
|
|
84
|
-
export { default as UCheckboxMultiState } from "./ui.form-checkbox-multi-state/UCheckboxMultiState.vue";
|
|
85
|
-
export { default as USwitch } from "./ui.form-switch/USwitch.vue";
|
|
86
|
-
export { default as URadio } from "./ui.form-radio/URadio.vue";
|
|
87
|
-
export { default as URadioGroup } from "./ui.form-radio-group/URadioGroup.vue";
|
|
88
|
-
export { default as UCalendar } from "./ui.form-calendar/UCalendar.vue";
|
|
89
|
-
export { default as UDatePicker } from "./ui.form-date-picker/UDatePicker.vue";
|
|
90
|
-
export { default as UDatePickerRange } from "./ui.form-date-picker-range/UDatePickerRange.vue";
|
|
91
|
-
export { default as UColorToggle } from "./ui.form-color-toggle/UColorToggle.vue";
|
|
92
|
-
export { default as ULabel } from "./ui.form-label/ULabel.vue";
|
|
93
|
-
/* Text & Content */
|
|
94
|
-
export { default as UHeader } from "./ui.text-header/UHeader.vue";
|
|
95
|
-
export { default as UText } from "./ui.text-block/UText.vue";
|
|
96
|
-
export { default as UAlert } from "./ui.text-alert/UAlert.vue";
|
|
97
|
-
export { default as UNotify } from "./ui.text-notify/UNotify.vue";
|
|
98
|
-
export { default as UNumber } from "./ui.text-number/UNumber.vue";
|
|
99
|
-
export { default as UFile } from "./ui.text-file/UFile.vue";
|
|
100
|
-
export { default as UFiles } from "./ui.text-files/UFiles.vue";
|
|
101
|
-
export { default as UEmpty } from "./ui.text-empty/UEmpty.vue";
|
|
102
|
-
export { default as UBadge } from "./ui.text-badge/UBadge.vue";
|
|
103
|
-
/* Containers */
|
|
104
|
-
export { default as UDivider } from "./ui.container-divider/UDivider.vue";
|
|
105
|
-
export { default as UCol } from "./ui.container-col/UCol.vue";
|
|
106
|
-
export { default as URow } from "./ui.container-row/URow.vue";
|
|
107
|
-
export { default as UGroup } from "./ui.container-group/UGroup.vue";
|
|
108
|
-
export { default as UGroups } from "./ui.container-groups/UGroups.vue";
|
|
109
|
-
export { default as UAccordion } from "./ui.container-accordion/UAccordion.vue";
|
|
110
|
-
export { default as UAccordionItem } from "./ui.container-accordion-item/UAccordionItem.vue";
|
|
111
|
-
export { default as UCard } from "./ui.container-card/UCard.vue";
|
|
112
|
-
export { default as UModal } from "./ui.container-modal/UModal.vue";
|
|
113
|
-
export { default as UModalConfirm } from "./ui.container-modal-confirm/UModalConfirm.vue";
|
|
114
|
-
export { default as UDrawer } from "./ui.container-drawer/UDrawer.vue";
|
|
115
|
-
export { default as UPage } from "./ui.container-page/UPage.vue";
|
|
116
|
-
/* Images and Icons */
|
|
117
|
-
export { default as UIcon } from "./ui.image-icon/UIcon.vue";
|
|
118
|
-
export { default as UAvatar } from "./ui.image-avatar/UAvatar.vue";
|
|
119
|
-
/* Data */
|
|
120
|
-
export { default as UTable } from "./ui.data-table/UTable.vue";
|
|
121
|
-
export { default as UDataList } from "./ui.data-list/UDataList.vue";
|
|
122
|
-
/* Navigation */
|
|
123
|
-
export { default as UTab } from "./ui.navigation-tab/UTab.vue";
|
|
124
|
-
export { default as UTabs } from "./ui.navigation-tabs/UTabs.vue";
|
|
125
|
-
export { default as UProgress } from "./ui.navigation-progress/UProgress.vue";
|
|
126
|
-
export { default as UPagination } from "./ui.navigation-pagination/UPagination.vue";
|
|
127
|
-
export { default as UBreadcrumbs } from "./ui.navigation-breadcrumbs/UBreadcrumbs.vue";
|
|
128
|
-
/* Loaders and Skeletons */
|
|
129
|
-
export { default as ULoader } from "./ui.loader/ULoader.vue";
|
|
130
|
-
export { default as ULoaderProgress } from "./ui.loader-progress/ULoaderProgress.vue";
|
|
131
|
-
export { default as ULoaderOverlay } from "./ui.loader-overlay/ULoaderOverlay.vue";
|
|
132
|
-
export { default as USkeleton } from "./ui.skeleton/USkeleton.vue";
|
|
133
|
-
export { default as USkeletonText } from "./ui.skeleton-text/USkeletonText.vue";
|
|
134
|
-
export { default as USkeletonInput } from "./ui.skeleton-input/USkeletonInput.vue";
|
|
135
|
-
export { default as USkeletonChoice } from "./ui.skeleton-choice/USkeletonChoice.vue";
|
|
136
|
-
/* Other */
|
|
137
|
-
export { default as UDot } from "./ui.other-dot/UDot.vue";
|
|
138
|
-
export { default as UChip } from "./ui.other-chip/UChip.vue";
|
|
139
|
-
export { default as UThemeColorToggle } from "./ui.other-theme-color-toggle/UThemeColorToggle.vue";
|
|
140
62
|
/* eslint-enable prettier/prettier */
|
|
141
63
|
|
|
142
64
|
/* types */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueless",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3-beta.0",
|
|
4
4
|
"description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
|
|
5
5
|
"author": "Johnny Grid <hello@vueless.com> (https://vueless.com)",
|
|
6
6
|
"homepage": "https://vueless.com",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"@vue/eslint-config-typescript": "^14.6.0",
|
|
58
58
|
"@vue/test-utils": "^2.4.6",
|
|
59
59
|
"@vue/tsconfig": "^0.7.0",
|
|
60
|
-
"@vueless/storybook": "^1.2.
|
|
60
|
+
"@vueless/storybook": "^1.2.11",
|
|
61
61
|
"eslint": "^9.32.0",
|
|
62
|
-
"eslint-plugin-storybook": "^
|
|
62
|
+
"eslint-plugin-storybook": "^10.0.2",
|
|
63
63
|
"eslint-plugin-vue": "^10.3.0",
|
|
64
64
|
"globals": "^16.3.0",
|
|
65
65
|
"jsdom": "^26.1.0",
|
|
@@ -98,6 +98,10 @@
|
|
|
98
98
|
"./composables/*": "./composables/*",
|
|
99
99
|
"./constants": "./constants.js",
|
|
100
100
|
"./constants.js": "./constants.js",
|
|
101
|
+
"./components": {
|
|
102
|
+
"import": "./components.ts",
|
|
103
|
+
"types": "./components.d.ts"
|
|
104
|
+
},
|
|
101
105
|
"./plugin-vite": "./plugin-vite.js",
|
|
102
106
|
"./plugin-vite.js": "./plugin-vite.js",
|
|
103
107
|
"./storybook": "./utils/node/storybook.js",
|
package/tailwind.css
CHANGED
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
[type='checkbox']:checked {
|
|
29
29
|
@apply !bg-none;
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
input:-webkit-autofill,
|
|
33
|
+
input:-webkit-autofill:focus {
|
|
34
|
+
-webkit-box-shadow: 0 0 0px 1000px var(--vl-bg) inset !important;
|
|
35
|
+
-webkit-text-fill-color: var(--vl-text) !important;
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
/* ------ Tailwind theme settings ------ */
|
package/ui.button/UButton.vue
CHANGED
package/ui.data-table/UTable.vue
CHANGED
|
@@ -40,7 +40,9 @@ import type {
|
|
|
40
40
|
Config,
|
|
41
41
|
DateDivider,
|
|
42
42
|
FlatRow,
|
|
43
|
+
ColumnObject,
|
|
43
44
|
} from "./types";
|
|
45
|
+
import { StickySide } from "./types";
|
|
44
46
|
|
|
45
47
|
defineOptions({ inheritAttrs: false });
|
|
46
48
|
|
|
@@ -166,13 +168,20 @@ const visibleColumns = computed(() => {
|
|
|
166
168
|
return normalizedColumns.value.filter((column) => column.isShown !== false);
|
|
167
169
|
});
|
|
168
170
|
|
|
171
|
+
const columnPositions = ref<Map<string, number>>(new Map());
|
|
172
|
+
|
|
169
173
|
const colsCount = computed(() => {
|
|
170
174
|
return normalizedColumns.value.length + 1;
|
|
171
175
|
});
|
|
172
176
|
|
|
173
|
-
const isShownActionsHeader = computed(
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
const isShownActionsHeader = computed(() => {
|
|
178
|
+
const hasSelectedRows = Boolean(localSelectedRows.value.length);
|
|
179
|
+
const hasHeaderActions = hasSlotContent(slots["header-actions"], {
|
|
180
|
+
"selected-rows": localSelectedRows.value,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return hasSelectedRows && hasHeaderActions;
|
|
184
|
+
});
|
|
176
185
|
|
|
177
186
|
const isHeaderSticky = computed(() => {
|
|
178
187
|
const positionForFixHeader =
|
|
@@ -212,6 +221,8 @@ const tableRowAttrs = computed(() => ({
|
|
|
212
221
|
bodyCellNestedIconWrapperAttrs,
|
|
213
222
|
bodyRowCheckedAttrs,
|
|
214
223
|
bodyRowAttrs,
|
|
224
|
+
bodyCellStickyLeftAttrs,
|
|
225
|
+
bodyCellStickyRightAttrs,
|
|
215
226
|
}));
|
|
216
227
|
|
|
217
228
|
watch(localSelectedRows, onChangeLocalSelectedRows, { deep: true });
|
|
@@ -223,15 +234,19 @@ watch(isFooterSticky, (newValue) =>
|
|
|
223
234
|
newValue ? nextTick(setFooterCellWidth) : setFooterCellWidth(null),
|
|
224
235
|
);
|
|
225
236
|
|
|
226
|
-
onMounted(() => {
|
|
237
|
+
onMounted(async () => {
|
|
227
238
|
document.addEventListener("keyup", onKeyupEsc);
|
|
228
239
|
document.addEventListener("scroll", onScroll, { passive: true });
|
|
229
240
|
window.addEventListener("resize", onWindowResize);
|
|
241
|
+
|
|
242
|
+
await nextTick();
|
|
243
|
+
calculateStickyColumnPositions();
|
|
230
244
|
});
|
|
231
245
|
|
|
232
246
|
onUpdated(() => {
|
|
233
247
|
tableHeight.value = Number(tableWrapperRef.value?.offsetHeight);
|
|
234
248
|
tableWidth.value = Number(tableWrapperRef.value?.offsetWidth);
|
|
249
|
+
calculateStickyColumnPositions();
|
|
235
250
|
});
|
|
236
251
|
|
|
237
252
|
onBeforeUnmount(() => {
|
|
@@ -257,6 +272,106 @@ function onWindowResize() {
|
|
|
257
272
|
|
|
258
273
|
setHeaderCellWidth();
|
|
259
274
|
setFooterCellWidth();
|
|
275
|
+
calculateStickyColumnPositions();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function calculateStickyColumnPositions() {
|
|
279
|
+
if (!headerRowRef.value) return;
|
|
280
|
+
|
|
281
|
+
const headerCells = [...headerRowRef.value.children] as HTMLElement[];
|
|
282
|
+
const positions = new Map<string, number>();
|
|
283
|
+
let leftOffset = 0;
|
|
284
|
+
|
|
285
|
+
if (props.selectable) {
|
|
286
|
+
leftOffset = headerCells[0]?.offsetWidth || 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
visibleColumns.value.forEach((column, index) => {
|
|
290
|
+
const cellIndex = props.selectable ? index + 1 : index;
|
|
291
|
+
const cell = headerCells[cellIndex];
|
|
292
|
+
|
|
293
|
+
if (!cell) return;
|
|
294
|
+
|
|
295
|
+
if (column.sticky === StickySide.Left) {
|
|
296
|
+
positions.set(column.key, leftOffset);
|
|
297
|
+
leftOffset += cell.offsetWidth;
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
let rightOffset = 0;
|
|
302
|
+
|
|
303
|
+
for (let i = visibleColumns.value.length - 1; i >= 0; i--) {
|
|
304
|
+
const column = visibleColumns.value[i];
|
|
305
|
+
const cellIndex = props.selectable ? i + 1 : i;
|
|
306
|
+
const cell = headerCells[cellIndex];
|
|
307
|
+
|
|
308
|
+
if (!cell) continue;
|
|
309
|
+
|
|
310
|
+
if (column.sticky === StickySide.Right) {
|
|
311
|
+
positions.set(column.key, rightOffset);
|
|
312
|
+
rightOffset += cell.offsetWidth;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
let hasChanged = positions.size !== columnPositions.value.size;
|
|
317
|
+
|
|
318
|
+
if (!hasChanged) {
|
|
319
|
+
for (const [key, value] of positions) {
|
|
320
|
+
if (columnPositions.value.get(key) !== value) {
|
|
321
|
+
hasChanged = true;
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (hasChanged) {
|
|
328
|
+
columnPositions.value = positions;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function getStickyColumnStyle(column: ColumnObject) {
|
|
333
|
+
const position = columnPositions.value.get(column.key);
|
|
334
|
+
|
|
335
|
+
if (position === undefined) return {};
|
|
336
|
+
|
|
337
|
+
if (column.sticky === StickySide.Left) {
|
|
338
|
+
return { left: `${position / PX_IN_REM}rem` };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (column.sticky === StickySide.Right) {
|
|
342
|
+
return { right: `${position / PX_IN_REM}rem` };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return {};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function getStickyColumnClass(column: ColumnObject) {
|
|
349
|
+
if (column.sticky === StickySide.Left) {
|
|
350
|
+
return headerCellStickyLeftAttrs.value.class as string;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (column.sticky === StickySide.Right) {
|
|
354
|
+
return headerCellStickyRightAttrs.value.class as string;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return "";
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function getHeaderCheckboxCellClass() {
|
|
361
|
+
return cx([
|
|
362
|
+
headerCellCheckboxAttrs.value.class as string,
|
|
363
|
+
visibleColumns.value[0]?.sticky === StickySide.Left
|
|
364
|
+
? (headerCellStickyLeftAttrs.value.class as string)
|
|
365
|
+
: "",
|
|
366
|
+
]);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function getHeaderCellClass(column: ColumnObject) {
|
|
370
|
+
return cx([
|
|
371
|
+
headerCellBaseAttrs.value.class as string,
|
|
372
|
+
column.thClass,
|
|
373
|
+
getStickyColumnClass(column),
|
|
374
|
+
]);
|
|
260
375
|
}
|
|
261
376
|
|
|
262
377
|
function getDateDividerData(rowDate: string | Date | undefined) {
|
|
@@ -510,6 +625,10 @@ const {
|
|
|
510
625
|
bodyCellNestedIconWrapperAttrs,
|
|
511
626
|
bodyRowCheckedAttrs,
|
|
512
627
|
bodyRowAttrs,
|
|
628
|
+
headerCellStickyLeftAttrs,
|
|
629
|
+
headerCellStickyRightAttrs,
|
|
630
|
+
bodyCellStickyLeftAttrs,
|
|
631
|
+
bodyCellStickyRightAttrs,
|
|
513
632
|
} = useUI<Config>(defaultConfig, mutatedProps);
|
|
514
633
|
</script>
|
|
515
634
|
|
|
@@ -652,7 +771,12 @@ const {
|
|
|
652
771
|
</tr>
|
|
653
772
|
|
|
654
773
|
<tr ref="header-row" v-bind="headerRowAttrs">
|
|
655
|
-
<th
|
|
774
|
+
<th
|
|
775
|
+
v-if="selectable"
|
|
776
|
+
v-bind="headerCellCheckboxAttrs"
|
|
777
|
+
:class="getHeaderCheckboxCellClass()"
|
|
778
|
+
:style="visibleColumns[0]?.sticky === StickySide.Left ? { left: '0' } : {}"
|
|
779
|
+
>
|
|
656
780
|
<UCheckbox
|
|
657
781
|
v-model="selectAll"
|
|
658
782
|
size="md"
|
|
@@ -676,7 +800,8 @@ const {
|
|
|
676
800
|
v-for="(column, index) in visibleColumns"
|
|
677
801
|
:key="index"
|
|
678
802
|
v-bind="headerCellBaseAttrs"
|
|
679
|
-
:class="
|
|
803
|
+
:class="getHeaderCellClass(column)"
|
|
804
|
+
:style="getStickyColumnStyle(column)"
|
|
680
805
|
>
|
|
681
806
|
<!--
|
|
682
807
|
@slot Use it to customize needed header cell.
|
|
@@ -684,7 +809,7 @@ const {
|
|
|
684
809
|
@binding {number} index
|
|
685
810
|
-->
|
|
686
811
|
<slot
|
|
687
|
-
v-if="hasSlotContent($slots[`header-${column.key}`])"
|
|
812
|
+
v-if="hasSlotContent($slots[`header-${column.key}`], { column, index })"
|
|
688
813
|
:name="`header-${column.key}`"
|
|
689
814
|
:column="column"
|
|
690
815
|
:index="index"
|
|
@@ -754,6 +879,7 @@ const {
|
|
|
754
879
|
:data-test="getDataTest('row')"
|
|
755
880
|
:is-expanded="localExpandedRows.includes(row.id)"
|
|
756
881
|
:is-checked="isRowSelected(row)"
|
|
882
|
+
:column-positions="columnPositions"
|
|
757
883
|
@click="onClickRow"
|
|
758
884
|
@dblclick="onDoubleClickRow"
|
|
759
885
|
@click-cell="onClickCell"
|
|
@@ -14,7 +14,8 @@ import UCheckbox from "../ui.form-checkbox/UCheckbox.vue";
|
|
|
14
14
|
|
|
15
15
|
import defaultConfig from "./config";
|
|
16
16
|
|
|
17
|
-
import
|
|
17
|
+
import { StickySide } from "./types";
|
|
18
|
+
import type { Cell, CellObject, Row, UTableRowProps, Config, ColumnObject } from "./types";
|
|
18
19
|
|
|
19
20
|
const NESTED_ROW_SHIFT_REM = 1.5;
|
|
20
21
|
const LAST_NESTED_ROW_SHIFT_REM = 1;
|
|
@@ -166,6 +167,34 @@ function onInputCheckbox(row: Row) {
|
|
|
166
167
|
emit("toggleCheckbox", row);
|
|
167
168
|
}
|
|
168
169
|
|
|
170
|
+
function getStickyColumnStyle(column: ColumnObject) {
|
|
171
|
+
const position = props.columnPositions.get(column.key);
|
|
172
|
+
|
|
173
|
+
if (position === undefined) return {};
|
|
174
|
+
|
|
175
|
+
if (column.sticky === StickySide.Left) {
|
|
176
|
+
return { left: `${position / PX_IN_REM}rem` };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (column.sticky === StickySide.Right) {
|
|
180
|
+
return { right: `${position / PX_IN_REM}rem` };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function getStickyColumnClass(column: ColumnObject) {
|
|
187
|
+
if (column.sticky === StickySide.Left) {
|
|
188
|
+
return props.attrs.bodyCellStickyLeftAttrs.value.class as string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (column.sticky === StickySide.Right) {
|
|
192
|
+
return props.attrs.bodyCellStickyRightAttrs.value.class as string;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return "";
|
|
196
|
+
}
|
|
197
|
+
|
|
169
198
|
const { getDataTest } = useUI<Config>(defaultConfig);
|
|
170
199
|
</script>
|
|
171
200
|
|
|
@@ -179,8 +208,17 @@ const { getDataTest } = useUI<Config>(defaultConfig);
|
|
|
179
208
|
>
|
|
180
209
|
<td
|
|
181
210
|
v-if="selectable"
|
|
182
|
-
:style="
|
|
211
|
+
:style="{
|
|
212
|
+
...getNestedCheckboxShift(),
|
|
213
|
+
...(columns[0]?.sticky === StickySide.Left ? { left: '0' } : {}),
|
|
214
|
+
}"
|
|
183
215
|
v-bind="attrs.bodyCellCheckboxAttrs.value"
|
|
216
|
+
:class="
|
|
217
|
+
cx([
|
|
218
|
+
attrs.bodyCellCheckboxAttrs.value.class,
|
|
219
|
+
columns[0]?.sticky === StickySide.Left ? attrs.bodyCellStickyLeftAttrs.value.class : '',
|
|
220
|
+
])
|
|
221
|
+
"
|
|
184
222
|
@click.stop
|
|
185
223
|
@dblclick.stop
|
|
186
224
|
>
|
|
@@ -198,7 +236,14 @@ const { getDataTest } = useUI<Config>(defaultConfig);
|
|
|
198
236
|
v-for="(value, key, index) in mapRowColumns(row, columns)"
|
|
199
237
|
:key="index"
|
|
200
238
|
v-bind="attrs.bodyCellBaseAttrs.value"
|
|
201
|
-
:class="
|
|
239
|
+
:class="
|
|
240
|
+
cx([
|
|
241
|
+
columns[index].tdClass,
|
|
242
|
+
getCellClasses(row, String(key)),
|
|
243
|
+
getStickyColumnClass(columns[index]),
|
|
244
|
+
])
|
|
245
|
+
"
|
|
246
|
+
:style="getStickyColumnStyle(columns[index])"
|
|
202
247
|
@click="onClickCell(value, row, key)"
|
|
203
248
|
>
|
|
204
249
|
<div
|
package/ui.data-table/config.ts
CHANGED
|
@@ -30,7 +30,7 @@ export default /*tw*/ {
|
|
|
30
30
|
headerActionsCheckbox: "{UCheckbox}",
|
|
31
31
|
headerActionsCounter: "{>headerCounterBase} -ml-1.5",
|
|
32
32
|
tableWrapper: "border border-solid border-muted rounded-medium bg-default overflow-x-auto",
|
|
33
|
-
table: "min-w-full border-none text-medium w-
|
|
33
|
+
table: "min-w-full border-none text-medium w-auto table-auto",
|
|
34
34
|
header:
|
|
35
35
|
"border-b border-muted [&>tr:first-child>*]:first:rounded-tl-medium [&>tr:last-child>*]:last:rounded-tr-medium relative",
|
|
36
36
|
headerRow: "",
|
|
@@ -44,12 +44,15 @@ export default /*tw*/ {
|
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
46
|
},
|
|
47
|
+
headerCellSticky: "sticky z-20 bg-default",
|
|
48
|
+
headerCellStickyLeft: "{>headerCellSticky}",
|
|
49
|
+
headerCellStickyRight: "{>headerCellSticky}",
|
|
47
50
|
headerCellCheckbox: "{>headerCellBase} w-10 pr-2",
|
|
48
51
|
headerCheckbox: "{UCheckbox}",
|
|
49
52
|
headerCounter: "{>stickyHeaderCounter} ml-px",
|
|
50
53
|
headerLoader: "{ULoaderProgress} absolute top-auto bottom-0",
|
|
51
54
|
body: "group/body divide-none",
|
|
52
|
-
bodyRow: "hover:bg-muted",
|
|
55
|
+
bodyRow: "bg-default hover:bg-muted",
|
|
53
56
|
bodyRowChecked: "bg-lifted transition",
|
|
54
57
|
beforeBodyRow: "!p-0",
|
|
55
58
|
beforeBodyRowChecked: "{>bodyRowChecked} !p-0",
|
|
@@ -65,6 +68,9 @@ export default /*tw*/ {
|
|
|
65
68
|
},
|
|
66
69
|
},
|
|
67
70
|
},
|
|
71
|
+
bodyCellSticky: "sticky z-10 bg-inherit",
|
|
72
|
+
bodyCellStickyLeft: "{>bodyCellSticky}",
|
|
73
|
+
bodyCellStickyRight: "{>bodyCellSticky}",
|
|
68
74
|
bodyCellContent: "text-ellipsis overflow-hidden",
|
|
69
75
|
bodyCellCheckbox: "{>bodyCellBase} pr-2",
|
|
70
76
|
bodyCellDateDivider: "",
|
|
@@ -100,7 +106,7 @@ export default /*tw*/ {
|
|
|
100
106
|
},
|
|
101
107
|
},
|
|
102
108
|
stickyFooterRow: `
|
|
103
|
-
fixed bottom-0 -ml-px border
|
|
109
|
+
fixed bottom-0 -ml-px border border-solid border-muted bg-default
|
|
104
110
|
collapse group-[*]/footer-fixed:[visibility:inherit]
|
|
105
111
|
`,
|
|
106
112
|
i18n: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Meta, StoryFn } from "@storybook/vue3-vite";
|
|
2
|
+
|
|
2
3
|
import {
|
|
3
4
|
getArgTypes,
|
|
4
5
|
getSlotNames,
|
|
@@ -18,7 +19,9 @@ import URow from "../../ui.container-row/URow.vue";
|
|
|
18
19
|
import UIcon from "../../ui.image-icon/UIcon.vue";
|
|
19
20
|
import ULoader from "../../ui.loader/ULoader.vue";
|
|
20
21
|
|
|
21
|
-
import
|
|
22
|
+
import tooltip from "../../v.tooltip/vTooltip";
|
|
23
|
+
import type { Row, Props, ColumnObject } from "../types";
|
|
24
|
+
import { StickySide } from "../types";
|
|
22
25
|
|
|
23
26
|
interface UTableArgs extends Props {
|
|
24
27
|
slotTemplate?: string;
|
|
@@ -476,6 +479,220 @@ DateDividerCustomLabel.parameters = {
|
|
|
476
479
|
},
|
|
477
480
|
};
|
|
478
481
|
|
|
482
|
+
export const StickyColumns: StoryFn<UTableArgs> = (args: UTableArgs) => ({
|
|
483
|
+
components: { UTable, URow, UBadge, UButton, UIcon },
|
|
484
|
+
directives: { tooltip },
|
|
485
|
+
setup() {
|
|
486
|
+
function toggleLeft(key: string) {
|
|
487
|
+
const column = args.columns.find((item) => (item as ColumnObject).key === key);
|
|
488
|
+
|
|
489
|
+
if (!column || typeof column === "string") return;
|
|
490
|
+
|
|
491
|
+
column.sticky = column.sticky === StickySide.Left ? undefined : StickySide.Left;
|
|
492
|
+
args.columns = args.columns.slice();
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function toggleRight(key: string) {
|
|
496
|
+
const column = args.columns.find((item) => (item as ColumnObject).key === key);
|
|
497
|
+
|
|
498
|
+
if (!column || typeof column === "string") return;
|
|
499
|
+
|
|
500
|
+
column.sticky = column.sticky === StickySide.Right ? undefined : StickySide.Right;
|
|
501
|
+
args.columns = args.columns.slice();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function isPinned(key: string, side: string) {
|
|
505
|
+
const column = args.columns.find((item) => (item as ColumnObject).key === key);
|
|
506
|
+
|
|
507
|
+
if (!column || typeof column === "string") return;
|
|
508
|
+
|
|
509
|
+
return column?.sticky === side;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return { args, toggleLeft, toggleRight, isPinned };
|
|
513
|
+
},
|
|
514
|
+
template: `
|
|
515
|
+
<UTable v-bind="args">
|
|
516
|
+
<template #header-orderId="{ column }">
|
|
517
|
+
<URow gap="2xs" align="center">
|
|
518
|
+
<div>{{ column.label }}</div>
|
|
519
|
+
<UIcon
|
|
520
|
+
name="keep"
|
|
521
|
+
size="xs"
|
|
522
|
+
interactive
|
|
523
|
+
v-tooltip="isPinned('orderId', 'left') ? 'Unpin left' : 'Pin left'"
|
|
524
|
+
:color="isPinned('orderId', 'left') ? 'primary' : 'inherit'"
|
|
525
|
+
@click.stop="toggleLeft('orderId')"
|
|
526
|
+
/>
|
|
527
|
+
</URow>
|
|
528
|
+
</template>
|
|
529
|
+
|
|
530
|
+
<template #header-customerName="{ column }">
|
|
531
|
+
<URow gap="2xs" align="center">
|
|
532
|
+
<div>{{ column.label }}</div>
|
|
533
|
+
<UIcon
|
|
534
|
+
name="keep"
|
|
535
|
+
size="xs"
|
|
536
|
+
interactive
|
|
537
|
+
v-tooltip="isPinned('customerName', 'left') ? 'Unpin left' : 'Pin left'"
|
|
538
|
+
:color="isPinned('customerName', 'left') ? 'primary' : 'inherit'"
|
|
539
|
+
@click.stop="toggleLeft('customerName')"
|
|
540
|
+
/>
|
|
541
|
+
</URow>
|
|
542
|
+
</template>
|
|
543
|
+
|
|
544
|
+
<template #header-email="{ column }">
|
|
545
|
+
<URow gap="2xs" align="center">
|
|
546
|
+
<div>{{ column.label }}</div>
|
|
547
|
+
<UIcon
|
|
548
|
+
name="keep"
|
|
549
|
+
size="xs"
|
|
550
|
+
interactive
|
|
551
|
+
v-tooltip="isPinned('email', 'left') ? 'Unpin left' : 'Pin left'"
|
|
552
|
+
:color="isPinned('email', 'left') ? 'primary' : 'inherit'"
|
|
553
|
+
@click.stop="toggleLeft('email')"
|
|
554
|
+
/>
|
|
555
|
+
</URow>
|
|
556
|
+
</template>
|
|
557
|
+
|
|
558
|
+
<template #header-totalPrice="{ column }">
|
|
559
|
+
<URow gap="2xs" align="center">
|
|
560
|
+
<div>{{ column.label }}</div>
|
|
561
|
+
<UIcon
|
|
562
|
+
name="keep"
|
|
563
|
+
size="xs"
|
|
564
|
+
interactive
|
|
565
|
+
v-tooltip="isPinned('totalPrice', 'right') ? 'Unpin right' : 'Pin right'"
|
|
566
|
+
:color="isPinned('totalPrice', 'right') ? 'primary' : 'inherit'"
|
|
567
|
+
@click.stop="toggleRight('totalPrice')"
|
|
568
|
+
/>
|
|
569
|
+
</URow>
|
|
570
|
+
</template>
|
|
571
|
+
|
|
572
|
+
<template #header-action="{ column }">
|
|
573
|
+
<URow gap="2xs" align="center">
|
|
574
|
+
<div>{{ column.label }}</div>
|
|
575
|
+
<UIcon
|
|
576
|
+
name="keep"
|
|
577
|
+
size="xs"
|
|
578
|
+
interactive
|
|
579
|
+
v-tooltip="isPinned('action', 'right') ? 'Unpin right' : 'Pin right'"
|
|
580
|
+
:color="isPinned('action', 'right') ? 'primary' : 'inherit'"
|
|
581
|
+
@click.stop="toggleRight('action')"
|
|
582
|
+
/>
|
|
583
|
+
</URow>
|
|
584
|
+
</template>
|
|
585
|
+
|
|
586
|
+
<template #cell-status="{ value }">
|
|
587
|
+
<UBadge
|
|
588
|
+
:label="value"
|
|
589
|
+
variant="soft"
|
|
590
|
+
:color="
|
|
591
|
+
value === 'Delivered' ? 'success' :
|
|
592
|
+
value === 'Cancelled' ? 'error' :
|
|
593
|
+
value === 'Pending' ? 'notice' :
|
|
594
|
+
value === 'Shipped' ? 'info' : ''
|
|
595
|
+
"
|
|
596
|
+
/>
|
|
597
|
+
</template>
|
|
598
|
+
|
|
599
|
+
<template #cell-action>
|
|
600
|
+
<UButton label="View" size="xs" variant="soft" />
|
|
601
|
+
</template>
|
|
602
|
+
</UTable>
|
|
603
|
+
`,
|
|
604
|
+
});
|
|
605
|
+
StickyColumns.args = {
|
|
606
|
+
columns: [
|
|
607
|
+
{ key: "orderId", label: "Order ID", sticky: "left" },
|
|
608
|
+
{ key: "customerName", label: "Customer Name", thClass: "min-w-[200px]" },
|
|
609
|
+
{ key: "email", label: "Email", thClass: "min-w-[250px]", sticky: "left" },
|
|
610
|
+
{ key: "phone", label: "Phone", thClass: "min-w-[150px]" },
|
|
611
|
+
{ key: "address", label: "Address", thClass: "min-w-[300px]" },
|
|
612
|
+
{ key: "city", label: "City", thClass: "min-w-[150px]" },
|
|
613
|
+
{ key: "country", label: "Country", thClass: "min-w-[150px]" },
|
|
614
|
+
{ key: "status", label: "Status", thClass: "min-w-[120px]" },
|
|
615
|
+
{ key: "totalPrice", label: "Total Price", thClass: "min-w-[120px]" },
|
|
616
|
+
{ key: "action", label: "Actions", sticky: "right", thClass: "min-w-[100px]" },
|
|
617
|
+
],
|
|
618
|
+
rows: [
|
|
619
|
+
{
|
|
620
|
+
id: "row-1",
|
|
621
|
+
orderId: "ORD-1001",
|
|
622
|
+
customerName: "Alice Johnson",
|
|
623
|
+
email: "alice.johnson@example.com",
|
|
624
|
+
phone: "+1 (555) 123-4567",
|
|
625
|
+
address: "123 Main Street, Apt 4B",
|
|
626
|
+
city: "New York",
|
|
627
|
+
country: "USA",
|
|
628
|
+
status: "Delivered",
|
|
629
|
+
totalPrice: "$245.99",
|
|
630
|
+
action: "View",
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
id: "row-2",
|
|
634
|
+
orderId: "ORD-1002",
|
|
635
|
+
customerName: "Michael Smith",
|
|
636
|
+
email: "michael.smith@example.com",
|
|
637
|
+
phone: "+1 (555) 234-5678",
|
|
638
|
+
address: "456 Oak Avenue, Suite 200",
|
|
639
|
+
city: "Los Angeles",
|
|
640
|
+
country: "USA",
|
|
641
|
+
status: "Pending",
|
|
642
|
+
totalPrice: "$189.50",
|
|
643
|
+
action: "View",
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
id: "row-3",
|
|
647
|
+
orderId: "ORD-1003",
|
|
648
|
+
customerName: "Emma Brown",
|
|
649
|
+
email: "emma.brown@example.com",
|
|
650
|
+
phone: "+1 (555) 345-6789",
|
|
651
|
+
address: "789 Pine Road, Building C",
|
|
652
|
+
city: "Chicago",
|
|
653
|
+
country: "USA",
|
|
654
|
+
status: "Shipped",
|
|
655
|
+
totalPrice: "$312.75",
|
|
656
|
+
action: "View",
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
id: "row-4",
|
|
660
|
+
orderId: "ORD-1004",
|
|
661
|
+
customerName: "James Wilson",
|
|
662
|
+
email: "james.wilson@example.com",
|
|
663
|
+
phone: "+1 (555) 456-7890",
|
|
664
|
+
address: "321 Elm Street, Floor 3",
|
|
665
|
+
city: "Houston",
|
|
666
|
+
country: "USA",
|
|
667
|
+
status: "Cancelled",
|
|
668
|
+
totalPrice: "$156.20",
|
|
669
|
+
action: "View",
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
id: "row-5",
|
|
673
|
+
orderId: "ORD-1005",
|
|
674
|
+
customerName: "Sophia Davis",
|
|
675
|
+
email: "sophia.davis@example.com",
|
|
676
|
+
phone: "+1 (555) 567-8901",
|
|
677
|
+
address: "654 Maple Drive, Unit 12",
|
|
678
|
+
city: "Phoenix",
|
|
679
|
+
country: "USA",
|
|
680
|
+
status: "Delivered",
|
|
681
|
+
totalPrice: "$428.90",
|
|
682
|
+
action: "View",
|
|
683
|
+
},
|
|
684
|
+
],
|
|
685
|
+
};
|
|
686
|
+
StickyColumns.parameters = {
|
|
687
|
+
docs: {
|
|
688
|
+
description: {
|
|
689
|
+
story:
|
|
690
|
+
"Pin columns to the left or right edge of the table when scrolling horizontally. " +
|
|
691
|
+
"Use the header pin icons to toggle pinning for each column.",
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
};
|
|
695
|
+
|
|
479
696
|
export const HeaderCounterSlot = DefaultTemplate.bind({});
|
|
480
697
|
HeaderCounterSlot.args = {
|
|
481
698
|
selectable: true,
|
|
@@ -491,7 +708,7 @@ export const HeaderKeySlot = DefaultTemplate.bind({});
|
|
|
491
708
|
HeaderKeySlot.args = {
|
|
492
709
|
slotTemplate: `
|
|
493
710
|
<template #header-status="{ column }">
|
|
494
|
-
<UBadge :label="column
|
|
711
|
+
<UBadge :label="column.label" />
|
|
495
712
|
</template>
|
|
496
713
|
`,
|
|
497
714
|
};
|
|
@@ -620,9 +837,9 @@ ExpandSlot.args = {
|
|
|
620
837
|
slotTemplate: `
|
|
621
838
|
<template #expand="{ expanded }">
|
|
622
839
|
<UButton
|
|
623
|
-
:icon="expanded ? '
|
|
624
|
-
variant="
|
|
625
|
-
size="
|
|
840
|
+
:icon="expanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
|
|
841
|
+
variant="soft"
|
|
842
|
+
size="2xs"
|
|
626
843
|
square
|
|
627
844
|
/>
|
|
628
845
|
</template>
|
|
@@ -738,7 +955,7 @@ EmptyStateSlot.args = {
|
|
|
738
955
|
},
|
|
739
956
|
slotTemplate: `
|
|
740
957
|
<template #empty-state>
|
|
741
|
-
<ULoader loading
|
|
958
|
+
<ULoader loading :config="{ loader: 'mx-auto mb-4' }" />
|
|
742
959
|
<p class="text-center">Fetching latest data, please wait...</p>
|
|
743
960
|
</template>
|
|
744
961
|
`,
|
|
@@ -34,6 +34,8 @@ describe("UTableRow.vue", () => {
|
|
|
34
34
|
bodyCellNestedIconWrapperAttrs: ref({ class: "icon-wrapper" }),
|
|
35
35
|
bodyRowCheckedAttrs: ref({ class: "row-checked" }),
|
|
36
36
|
bodyRowAttrs: ref({ class: "row-base" }),
|
|
37
|
+
bodyCellStickyLeftAttrs: ref({ class: "sticky-left" }),
|
|
38
|
+
bodyCellStickyRightAttrs: ref({ class: "sticky-right" }),
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
const defaultConfig = {
|
|
@@ -44,6 +46,12 @@ describe("UTableRow.vue", () => {
|
|
|
44
46
|
} as Config;
|
|
45
47
|
|
|
46
48
|
function getDefaultProps(overrides = {}) {
|
|
49
|
+
const columnPositions = new Map<string, number>();
|
|
50
|
+
|
|
51
|
+
columnPositions.set("name", 0);
|
|
52
|
+
columnPositions.set("email", 100);
|
|
53
|
+
columnPositions.set("role", 200);
|
|
54
|
+
|
|
47
55
|
return {
|
|
48
56
|
row: defaultRow,
|
|
49
57
|
columns: defaultColumns,
|
|
@@ -56,6 +64,7 @@ describe("UTableRow.vue", () => {
|
|
|
56
64
|
config: defaultConfig,
|
|
57
65
|
isChecked: false,
|
|
58
66
|
isExpanded: false,
|
|
67
|
+
columnPositions,
|
|
59
68
|
...overrides,
|
|
60
69
|
};
|
|
61
70
|
}
|
package/ui.data-table/types.ts
CHANGED
|
@@ -39,11 +39,16 @@ export interface FlatRow extends Row {
|
|
|
39
39
|
parentRowId?: RowId;
|
|
40
40
|
nestedLevel: number;
|
|
41
41
|
}
|
|
42
|
+
export enum StickySide {
|
|
43
|
+
Left = "left",
|
|
44
|
+
Right = "right",
|
|
45
|
+
}
|
|
42
46
|
|
|
43
47
|
export interface ColumnObject {
|
|
44
48
|
key: string;
|
|
45
49
|
label?: string;
|
|
46
50
|
isShown?: boolean;
|
|
51
|
+
sticky?: "left" | "right";
|
|
47
52
|
class?: string | ((value: unknown | string, row: Row) => string);
|
|
48
53
|
tdClass?: string;
|
|
49
54
|
thClass?: string;
|
|
@@ -129,6 +134,8 @@ export interface UTableRowAttrs {
|
|
|
129
134
|
bodyCellNestedIconWrapperAttrs: Ref<UnknownObject>;
|
|
130
135
|
bodyRowCheckedAttrs: Ref<UnknownObject>;
|
|
131
136
|
bodyRowAttrs: Ref<UnknownObject>;
|
|
137
|
+
bodyCellStickyLeftAttrs: Ref<UnknownObject>;
|
|
138
|
+
bodyCellStickyRightAttrs: Ref<UnknownObject>;
|
|
132
139
|
}
|
|
133
140
|
|
|
134
141
|
export interface UTableRowProps {
|
|
@@ -143,4 +150,5 @@ export interface UTableRowProps {
|
|
|
143
150
|
config: Config;
|
|
144
151
|
isChecked: boolean;
|
|
145
152
|
isExpanded: boolean;
|
|
153
|
+
columnPositions: Map<string, number>;
|
|
146
154
|
}
|