sprintify-ui 0.7.11 → 0.8.1
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/dist/sprintify-ui.es.js +10482 -10348
- package/dist/style.css +1 -1
- package/dist/types/components/BaseDataIterator.vue.d.ts +50 -4
- package/dist/types/components/BaseDataIteratorSectionColumns.vue.d.ts +156 -68
- package/dist/types/components/BaseDataTable.vue.d.ts +86 -6
- package/dist/types/components/BaseDataTableTemplate.vue.d.ts +44 -28
- package/dist/types/components/BaseTable.vue.d.ts +30 -7
- package/dist/types/components/BaseTableCell.vue.d.ts +19 -1
- package/dist/types/components/BaseTableColumn.vue.d.ts +50 -3
- package/dist/types/components/BaseTableHead.vue.d.ts +6 -5
- package/dist/types/components/BaseTableHeader.vue.d.ts +12 -2
- package/dist/types/components/BaseTableRow.vue.d.ts +5 -0
- package/dist/types/composables/isFirstColumn.d.ts +4 -0
- package/dist/types/composables/isLastColumn.d.ts +4 -0
- package/dist/types/composables/paginatedData.d.ts +5 -5
- package/dist/types/services/table/types.d.ts +6 -5
- package/dist/types/types/index.d.ts +7 -2
- package/dist/types/utils/getApiData.d.ts +1 -1
- package/package.json +2 -1
- package/src/assets/main.css +0 -1
- package/src/components/BaseAvatar.vue +1 -0
- package/src/components/BaseDataIterator.stories.js +96 -1
- package/src/components/BaseDataIterator.vue +135 -11
- package/src/components/BaseDataIteratorSectionColumns.vue +2 -2
- package/src/components/BaseDataTable.stories.js +140 -50
- package/src/components/BaseDataTable.vue +82 -48
- package/src/components/BaseDataTableTemplate.vue +208 -372
- package/src/components/BaseTable.stories.js +57 -15
- package/src/components/BaseTable.vue +71 -9
- package/src/components/BaseTableBody.vue +1 -1
- package/src/components/BaseTableCell.vue +94 -36
- package/src/components/BaseTableColumn.vue +25 -2
- package/src/components/BaseTableHead.vue +17 -5
- package/src/components/BaseTableHeader.vue +39 -10
- package/src/components/BaseTableRow.vue +27 -6
- package/src/composables/isFirstColumn.ts +31 -0
- package/src/composables/isLastColumn.ts +31 -0
- package/src/composables/paginatedData.ts +22 -10
- package/src/services/table/classes.ts +13 -9
- package/src/services/table/types.ts +6 -5
- package/src/stories/List.stories.js +5 -1
- package/src/types/index.ts +7 -2
- package/src/utils/getApiData.ts +1 -1
- package/src/assets/base-table.css +0 -17
|
@@ -12,24 +12,25 @@ export default {
|
|
|
12
12
|
component: BaseTable,
|
|
13
13
|
args: {},
|
|
14
14
|
argTypes: {
|
|
15
|
-
|
|
15
|
+
size: {
|
|
16
16
|
control: {
|
|
17
17
|
type: 'select',
|
|
18
18
|
},
|
|
19
|
-
options: ['none', 'sm', 'md', 'lg'],
|
|
19
|
+
options: ['none', 'xs', 'sm', 'md', 'lg'],
|
|
20
20
|
},
|
|
21
21
|
},
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const headTemplate = `<BaseTableHead>
|
|
25
25
|
<BaseTableRow>
|
|
26
|
-
<BaseTableHeader>Label</BaseTableHeader>
|
|
27
|
-
<BaseTableHeader>ID</BaseTableHeader>
|
|
26
|
+
<BaseTableHeader sortable>Label</BaseTableHeader>
|
|
27
|
+
<BaseTableHeader sortable>ID</BaseTableHeader>
|
|
28
28
|
<BaseTableHeader>Type</BaseTableHeader>
|
|
29
|
+
<BaseTableHeader>Description</BaseTableHeader>
|
|
29
30
|
</BaseTableRow>
|
|
30
31
|
</BaseTableHead>`;
|
|
31
32
|
|
|
32
|
-
const cellsTemplate = `<BaseTableCell class="font-medium">
|
|
33
|
+
const cellsTemplate = `<BaseTableCell class="font-medium whitespace-nowrap">
|
|
33
34
|
{{ option.label }}
|
|
34
35
|
</BaseTableCell>
|
|
35
36
|
<BaseTableCell>
|
|
@@ -40,6 +41,9 @@ const cellsTemplate = `<BaseTableCell class="font-medium">
|
|
|
40
41
|
<BaseTableCell>
|
|
41
42
|
{{ option.type ?? 'N/A' }}
|
|
42
43
|
</BaseTableCell>
|
|
44
|
+
<BaseTableCell class="whitespace-nowrap">
|
|
45
|
+
Long description ...
|
|
46
|
+
</BaseTableCell>
|
|
43
47
|
`;
|
|
44
48
|
|
|
45
49
|
const components = {
|
|
@@ -59,8 +63,8 @@ const Template = (args) => ({
|
|
|
59
63
|
return { args, options };
|
|
60
64
|
},
|
|
61
65
|
template: `
|
|
62
|
-
<div class="
|
|
63
|
-
<BaseTable class="" v-bind="args">
|
|
66
|
+
<div class="border">
|
|
67
|
+
<BaseTable class="w-full" v-bind="args">
|
|
64
68
|
${headTemplate}
|
|
65
69
|
<BaseTableBody>
|
|
66
70
|
<BaseTableRow
|
|
@@ -80,6 +84,17 @@ const Template = (args) => ({
|
|
|
80
84
|
export const Demo = Template.bind({});
|
|
81
85
|
Demo.args = {};
|
|
82
86
|
|
|
87
|
+
export const FixedHeader = Template.bind({});
|
|
88
|
+
FixedHeader.args = {
|
|
89
|
+
fixedHeader: true,
|
|
90
|
+
maxHeight: 300,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const FixedColumn = Template.bind({});
|
|
94
|
+
FixedColumn.args = {
|
|
95
|
+
fixedColumn: true,
|
|
96
|
+
};
|
|
97
|
+
|
|
83
98
|
const TemplateRouterLink = (args) => ({
|
|
84
99
|
components: components,
|
|
85
100
|
setup() {
|
|
@@ -94,7 +109,6 @@ const TemplateRouterLink = (args) => ({
|
|
|
94
109
|
v-for="option in options"
|
|
95
110
|
:key="option.value"
|
|
96
111
|
:to="'/articles/' + option.value"
|
|
97
|
-
target="_blank"
|
|
98
112
|
:title="option.label"
|
|
99
113
|
>
|
|
100
114
|
${cellsTemplate}
|
|
@@ -110,26 +124,45 @@ RouterLink.args = {};
|
|
|
110
124
|
const TemplateCellClick = (args) => ({
|
|
111
125
|
components: components,
|
|
112
126
|
setup() {
|
|
113
|
-
|
|
127
|
+
|
|
128
|
+
const al = function () {
|
|
129
|
+
alert('clicked');
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return { args, options, al };
|
|
114
133
|
},
|
|
115
134
|
template: `
|
|
116
135
|
<div class="p-6">
|
|
117
136
|
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
137
|
+
<div class="text-sm mb-5">
|
|
138
|
+
<p>Row = a link to Bing</p>
|
|
139
|
+
<p>Cell #1 = a link to Google</p>
|
|
140
|
+
<p>Cell #2 = RouterLink to article </p>
|
|
141
|
+
<p>Cell #5 = Click </p>
|
|
142
|
+
</div>
|
|
121
143
|
|
|
122
144
|
<BaseTable class="" v-bind="args">
|
|
123
|
-
|
|
145
|
+
<BaseTableHead>
|
|
146
|
+
<BaseTableRow>
|
|
147
|
+
<BaseTableHeader sortable>Label</BaseTableHeader>
|
|
148
|
+
<BaseTableHeader sortable>ID</BaseTableHeader>
|
|
149
|
+
<BaseTableHeader>Type</BaseTableHeader>
|
|
150
|
+
<BaseTableHeader>Actions</BaseTableHeader>
|
|
151
|
+
<BaseTableHeader>Click</BaseTableHeader>
|
|
152
|
+
<BaseTableHeader>Ignore</BaseTableHeader>
|
|
153
|
+
</BaseTableRow>
|
|
154
|
+
</BaseTableHead>
|
|
124
155
|
<BaseTableBody>
|
|
125
156
|
<BaseTableRow
|
|
126
157
|
v-for="option in options"
|
|
127
158
|
:key="option.value"
|
|
159
|
+
href="https://bing.com"
|
|
160
|
+
target="_blank"
|
|
128
161
|
>
|
|
129
|
-
<BaseTableCell class="font-medium" href="https://google.com">
|
|
162
|
+
<BaseTableCell class="font-medium" href="https://google.com" target="_blank">
|
|
130
163
|
{{ option.label }}
|
|
131
164
|
</BaseTableCell>
|
|
132
|
-
<BaseTableCell>
|
|
165
|
+
<BaseTableCell :to="'/articles/' + option.value">
|
|
133
166
|
<BaseBadge class="font-mono">
|
|
134
167
|
{{ option.value ?? 'N/A' }}
|
|
135
168
|
</BaseBadge>
|
|
@@ -137,6 +170,15 @@ const TemplateCellClick = (args) => ({
|
|
|
137
170
|
<BaseTableCell>
|
|
138
171
|
{{ option.type ?? 'N/A' }}
|
|
139
172
|
</BaseTableCell>
|
|
173
|
+
<BaseTableCell>
|
|
174
|
+
...
|
|
175
|
+
</BaseTableCell>
|
|
176
|
+
<BaseTableCell @click="al()">
|
|
177
|
+
Click me
|
|
178
|
+
</BaseTableCell>
|
|
179
|
+
<BaseTableCell ignore-row-interactions>
|
|
180
|
+
ignore row interactions
|
|
181
|
+
</BaseTableCell>
|
|
140
182
|
</BaseTableRow>
|
|
141
183
|
</BaseTableBody>
|
|
142
184
|
</BaseTable>
|
|
@@ -1,38 +1,100 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
2
|
+
<div class="relative">
|
|
3
|
+
<div
|
|
4
|
+
ref="scrollableRef"
|
|
5
|
+
class="overflow-x-auto overflow-y-auto"
|
|
6
|
+
data-scroll-lock-scrollable
|
|
7
|
+
:style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }"
|
|
8
|
+
>
|
|
9
|
+
<table :class="classes">
|
|
10
|
+
<slot />
|
|
11
|
+
</table>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<slot name="loading">
|
|
15
|
+
<Transition
|
|
16
|
+
enter-active-class="transition ease-out duration-200"
|
|
17
|
+
enter-from-class="opacity-0"
|
|
18
|
+
enter-to-class="opacity-100"
|
|
19
|
+
leave-active-class="transition ease-in duration-200"
|
|
20
|
+
leave-from-class="opacity-100"
|
|
21
|
+
leave-to-class="opacity-0"
|
|
22
|
+
>
|
|
23
|
+
<div
|
|
24
|
+
v-if="loading"
|
|
25
|
+
class="absolute inset-0 z-[1] flex h-full w-full items-start justify-center"
|
|
26
|
+
>
|
|
27
|
+
<div class="absolute h-full w-full bg-white bg-opacity-60" />
|
|
28
|
+
|
|
29
|
+
<div class="pt-20">
|
|
30
|
+
<BaseSpinnerLarge class="h-10 w-10 text-blue-500" />
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</Transition>
|
|
34
|
+
</slot>
|
|
35
|
+
</div>
|
|
5
36
|
</template>
|
|
6
37
|
|
|
7
38
|
<script lang="ts" setup>
|
|
8
39
|
import { ClassNameValue, twMerge } from 'tailwind-merge';
|
|
9
|
-
import {
|
|
40
|
+
import { useScroll } from '@vueuse/core';
|
|
41
|
+
import BaseSpinnerLarge from '@/svg/BaseSpinnerLarge.vue';
|
|
42
|
+
import { Size } from '@/utils/sizes';
|
|
10
43
|
|
|
11
44
|
defineOptions({
|
|
12
45
|
inheritAttrs: false,
|
|
13
46
|
});
|
|
14
47
|
|
|
15
48
|
const props = withDefaults(defineProps<{
|
|
16
|
-
|
|
49
|
+
size?: Size,
|
|
50
|
+
fixedHeader?: boolean,
|
|
51
|
+
fixedColumn?: boolean,
|
|
17
52
|
grid?: boolean,
|
|
18
53
|
striped?: boolean,
|
|
19
54
|
flush?: boolean,
|
|
20
55
|
class?: ClassNameValue,
|
|
56
|
+
maxHeight?: number,
|
|
57
|
+
loading?: boolean,
|
|
21
58
|
}>(), {
|
|
22
|
-
|
|
59
|
+
size: 'md',
|
|
60
|
+
fixedHeader: false,
|
|
61
|
+
fixedColumn: false,
|
|
23
62
|
grid: false,
|
|
24
63
|
striped: false,
|
|
25
64
|
flush: false,
|
|
26
65
|
class: undefined,
|
|
66
|
+
maxHeight: undefined,
|
|
67
|
+
loading: false,
|
|
27
68
|
});
|
|
28
69
|
|
|
29
|
-
provide('BaseTable', computed(() => props));
|
|
30
|
-
|
|
31
70
|
const classes = computed(() => {
|
|
32
71
|
return twMerge(
|
|
33
|
-
'text-sm',
|
|
72
|
+
'border-separate border-spacing-0 text-sm',
|
|
34
73
|
props.class,
|
|
35
74
|
);
|
|
36
75
|
});
|
|
37
76
|
|
|
77
|
+
// Sticky styles
|
|
78
|
+
|
|
79
|
+
const horizontalScrolling = ref(false);
|
|
80
|
+
const scrollableRef = ref<null | HTMLElement>(null);
|
|
81
|
+
|
|
82
|
+
const { x } = useScroll(scrollableRef);
|
|
83
|
+
watch(x, (value) => {
|
|
84
|
+
horizontalScrolling.value = value > 0;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
function scrollTop() {
|
|
88
|
+
if (scrollableRef.value) {
|
|
89
|
+
scrollableRef.value.scrollTo({ top: 0, behavior: 'smooth' });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
provide('table:props', computed(() => props));
|
|
94
|
+
provide('table:horizontalScrolling', computed(() => horizontalScrolling.value));
|
|
95
|
+
|
|
96
|
+
defineExpose({
|
|
97
|
+
scrollTop,
|
|
98
|
+
});
|
|
99
|
+
|
|
38
100
|
</script>
|
|
@@ -1,37 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<td
|
|
3
|
-
|
|
3
|
+
ref="tdRef"
|
|
4
4
|
:align="align"
|
|
5
5
|
:colspan="colspan"
|
|
6
|
+
:class="classes"
|
|
7
|
+
:style="style"
|
|
8
|
+
:title="propsInternal.title"
|
|
9
|
+
@click="onClick"
|
|
10
|
+
@mouseenter="onMouseEnter"
|
|
11
|
+
@mouseleave="onMouseLeave"
|
|
6
12
|
>
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
:class="classes"
|
|
10
|
-
:to="propsInternal.to"
|
|
13
|
+
<a
|
|
14
|
+
v-if="propsInternal.href"
|
|
11
15
|
:href="propsInternal.href"
|
|
12
|
-
:title="propsInternal.title"
|
|
13
16
|
:target="propsInternal.target"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
tabindex="0"
|
|
18
|
+
class="absolute inset-0 focus:outline-none"
|
|
19
|
+
/>
|
|
20
|
+
<RouterLink
|
|
21
|
+
v-if="propsInternal.to"
|
|
22
|
+
:to="propsInternal.to"
|
|
23
|
+
tabindex="0"
|
|
24
|
+
class="absolute inset-0 focus:outline-none"
|
|
25
|
+
/>
|
|
26
|
+
<slot :hover="hoverInternal" />
|
|
17
27
|
</td>
|
|
18
28
|
</template>
|
|
19
29
|
|
|
20
30
|
<script lang="ts" setup>
|
|
21
|
-
import { RouteLocationRaw } from 'vue-router';
|
|
31
|
+
import { RouteLocationRaw, RouterLink } from 'vue-router';
|
|
22
32
|
import { TableProps, CellConfig, CellProps } from '../services/table/types'
|
|
23
33
|
import { cellClasses } from '../services/table/classes'
|
|
24
34
|
import { ClassNameValue, twMerge } from 'tailwind-merge';
|
|
25
35
|
import { cloneDeep, merge } from 'lodash';
|
|
26
|
-
import { ComputedRef } from 'vue';
|
|
36
|
+
import { ComputedRef, StyleValue } from 'vue';
|
|
37
|
+
import { useIsFirstColumn } from '../composables/isFirstColumn'
|
|
38
|
+
import { useIsLastColumn } from '../composables/isLastColumn'
|
|
27
39
|
|
|
28
40
|
defineOptions({
|
|
29
41
|
inheritAttrs: false,
|
|
30
42
|
})
|
|
31
43
|
|
|
32
|
-
const baseTable = inject('
|
|
33
|
-
const baseTableHead = inject('
|
|
34
|
-
const baseTableRow = inject('
|
|
44
|
+
const baseTable = inject('table:props') as ComputedRef<TableProps> | undefined;
|
|
45
|
+
const baseTableHead = inject('tableHead:props', undefined);
|
|
46
|
+
const baseTableRow = inject('tableRow:props', undefined) as ComputedRef<CellProps> | undefined;
|
|
47
|
+
const baseTableRowHover = inject('tableRow:hover', undefined) as ComputedRef<boolean> | undefined;
|
|
48
|
+
const baseTableHorizontalScrolling = inject('table:horizontalScrolling', undefined) as ComputedRef<boolean> | undefined;
|
|
49
|
+
const hoverForFullRow = inject('tableRow:hoverForFullRow') as ComputedRef<boolean> | undefined;
|
|
50
|
+
const setHoverForFullRow = inject('tableRow:setHoverForFullRow') as (active: boolean) => void;
|
|
35
51
|
|
|
36
52
|
if (!baseTableRow) {
|
|
37
53
|
throw new Error('BaseTableCell must be used within a BaseTableRow.');
|
|
@@ -47,6 +63,9 @@ const props = withDefaults(defineProps<{
|
|
|
47
63
|
align?: 'left' | 'center' | 'right',
|
|
48
64
|
colspan?: number | string,
|
|
49
65
|
class?: ClassNameValue,
|
|
66
|
+
style?: StyleValue,
|
|
67
|
+
onClick?: (e: MouseEvent) => void,
|
|
68
|
+
ignoreRowInteractions?: boolean,
|
|
50
69
|
}>(), {
|
|
51
70
|
href: undefined,
|
|
52
71
|
to: undefined,
|
|
@@ -55,57 +74,96 @@ const props = withDefaults(defineProps<{
|
|
|
55
74
|
align: 'left',
|
|
56
75
|
colspan: undefined,
|
|
57
76
|
class: undefined,
|
|
77
|
+
style: undefined,
|
|
78
|
+
onClick: undefined,
|
|
79
|
+
ignoreRowInteractions: false,
|
|
58
80
|
});
|
|
59
81
|
|
|
60
82
|
const cellConfig = computed<CellConfig>(() => {
|
|
61
83
|
return {
|
|
62
|
-
|
|
84
|
+
size: baseTable?.value?.size,
|
|
63
85
|
flush: baseTable?.value?.flush,
|
|
64
86
|
head: isHead.value,
|
|
65
87
|
}
|
|
66
88
|
});
|
|
67
89
|
|
|
68
|
-
const
|
|
69
|
-
|
|
90
|
+
const ignoreRowInteractionsInternal = computed(() => {
|
|
91
|
+
if (props.onClick || props.href || props.to) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return props.ignoreRowInteractions;
|
|
70
96
|
});
|
|
71
97
|
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
98
|
+
const propsInternal = computed<CellProps>(() => {
|
|
99
|
+
|
|
100
|
+
const baseTableRowMutated = cloneDeep(baseTableRow.value);
|
|
101
|
+
|
|
102
|
+
if (ignoreRowInteractionsInternal.value) {
|
|
103
|
+
baseTableRowMutated.href = undefined;
|
|
104
|
+
baseTableRowMutated.to = undefined;
|
|
105
|
+
baseTableRowMutated.target = undefined;
|
|
106
|
+
baseTableRowMutated.onClick = undefined;
|
|
75
107
|
}
|
|
76
108
|
|
|
77
|
-
|
|
78
|
-
|
|
109
|
+
return merge(baseTableRowMutated, props);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const clickable = computed(() => {
|
|
113
|
+
return !!propsInternal.value.onClick || !!propsInternal.value.href || !!propsInternal.value.to;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const hover = ref(false);
|
|
117
|
+
|
|
118
|
+
const hoverInternal = computed(() => {
|
|
119
|
+
// Hover for cell only
|
|
120
|
+
if (ignoreRowInteractionsInternal.value) {
|
|
121
|
+
return hover.value;
|
|
79
122
|
}
|
|
80
123
|
|
|
81
|
-
|
|
124
|
+
// Hover for full row
|
|
125
|
+
return (baseTableRowHover?.value ?? false) && (hoverForFullRow?.value ?? true);
|
|
82
126
|
});
|
|
83
127
|
|
|
84
128
|
const classes = computed(() => {
|
|
85
129
|
const base = cellClasses(cellConfig.value);
|
|
130
|
+
const baseTd = 'relative bg-white border-b border-slate-200 group-last/row:border-b-0';
|
|
86
131
|
const click = clickable.value ? 'cursor-pointer' : '';
|
|
87
|
-
const
|
|
88
|
-
const
|
|
132
|
+
const hover = clickable.value && hoverInternal.value ? 'bg-slate-50' : '';
|
|
133
|
+
const firstCol = isFirstColumn.value ? 'border-r border-r-transparent' : '';
|
|
134
|
+
const horizontalScrolling = baseTable?.value.fixedColumn && baseTableHorizontalScrolling?.value && isFirstColumn.value ? 'sticky z-[1] left-0 border-r-slate-200' : '';
|
|
135
|
+
const flushLeft = baseTable?.value.flush && isFirstColumn.value ? 'pl-0' : '';
|
|
136
|
+
const flushRight = baseTable?.value.flush && isLastColumn.value ? 'pr-0' : '';
|
|
89
137
|
|
|
90
138
|
return twMerge(
|
|
91
139
|
base,
|
|
140
|
+
baseTd,
|
|
92
141
|
click,
|
|
93
|
-
|
|
94
|
-
|
|
142
|
+
hover,
|
|
143
|
+
firstCol,
|
|
144
|
+
horizontalScrolling,
|
|
145
|
+
flushLeft,
|
|
146
|
+
flushRight,
|
|
95
147
|
props.class,
|
|
96
148
|
);
|
|
97
149
|
});
|
|
98
150
|
|
|
99
|
-
const
|
|
100
|
-
return propsInternal.value.href || propsInternal.value.to;
|
|
101
|
-
});
|
|
151
|
+
const tdRef = ref<HTMLTableCellElement | null>(null);
|
|
102
152
|
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
});
|
|
153
|
+
const { isFirstColumn } = useIsFirstColumn(tdRef);
|
|
154
|
+
const { isLastColumn } = useIsLastColumn(tdRef);
|
|
106
155
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
156
|
+
function onClick(event: MouseEvent) {
|
|
157
|
+
propsInternal.value.onClick?.(event);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function onMouseEnter() {
|
|
161
|
+
hover.value = true;
|
|
162
|
+
setHoverForFullRow(ignoreRowInteractionsInternal.value ? false : true)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function onMouseLeave() {
|
|
166
|
+
hover.value = false;
|
|
167
|
+
}
|
|
110
168
|
|
|
111
169
|
</script>
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { defineComponent, h, PropType } from 'vue';
|
|
3
|
+
import { BaseTableColumnData, CollectionItem } from '..';
|
|
4
|
+
import { RouteLocationRaw } from 'vue-router';
|
|
3
5
|
|
|
4
6
|
export default defineComponent({
|
|
5
7
|
name: 'BaseTableColumn',
|
|
8
|
+
inheritAttrs: false,
|
|
6
9
|
props: {
|
|
7
10
|
label: {
|
|
8
11
|
default: '',
|
|
@@ -12,6 +15,10 @@ export default defineComponent({
|
|
|
12
15
|
default: '',
|
|
13
16
|
type: [String, Number],
|
|
14
17
|
},
|
|
18
|
+
class: {
|
|
19
|
+
default: '',
|
|
20
|
+
type: [String, Array, Object],
|
|
21
|
+
},
|
|
15
22
|
field: {
|
|
16
23
|
default: '',
|
|
17
24
|
type: String,
|
|
@@ -44,8 +51,8 @@ export default defineComponent({
|
|
|
44
51
|
default: false,
|
|
45
52
|
type: Boolean,
|
|
46
53
|
},
|
|
47
|
-
|
|
48
|
-
default:
|
|
54
|
+
ignoreRowInteractions: {
|
|
55
|
+
default: false,
|
|
49
56
|
type: Boolean,
|
|
50
57
|
},
|
|
51
58
|
toggle: {
|
|
@@ -64,6 +71,22 @@ export default defineComponent({
|
|
|
64
71
|
default: undefined,
|
|
65
72
|
type: Function,
|
|
66
73
|
},
|
|
74
|
+
to: {
|
|
75
|
+
default: undefined,
|
|
76
|
+
type: Function as PropType<(row: CollectionItem) => RouteLocationRaw>,
|
|
77
|
+
},
|
|
78
|
+
href: {
|
|
79
|
+
default: undefined,
|
|
80
|
+
type: Function as PropType<(row: CollectionItem) => string>,
|
|
81
|
+
},
|
|
82
|
+
target: {
|
|
83
|
+
default: undefined,
|
|
84
|
+
type: String as PropType<'_blank' | '_self' | '_parent' | '_top'>,
|
|
85
|
+
},
|
|
86
|
+
onClick: {
|
|
87
|
+
default: undefined,
|
|
88
|
+
type: Function as PropType<(row: CollectionItem, index: number, column: BaseTableColumnData, colIndex: number, event: MouseEvent) => void>,
|
|
89
|
+
},
|
|
67
90
|
/** Adds native attributes to th :th-attrs="(column)" => ({})" */
|
|
68
91
|
thAttrs: {
|
|
69
92
|
type: Function,
|
|
@@ -1,23 +1,35 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<thead
|
|
2
|
+
<thead
|
|
3
|
+
:class="classes"
|
|
4
|
+
>
|
|
3
5
|
<slot />
|
|
4
6
|
</thead>
|
|
5
7
|
</template>
|
|
6
8
|
|
|
7
9
|
<script lang="ts" setup>
|
|
10
|
+
import { ClassNameValue, twMerge } from 'tailwind-merge';
|
|
8
11
|
|
|
9
12
|
const props = withDefaults(defineProps<{
|
|
10
|
-
|
|
13
|
+
class?: ClassNameValue,
|
|
11
14
|
}>(), {
|
|
12
|
-
|
|
15
|
+
class: undefined,
|
|
13
16
|
});
|
|
14
17
|
|
|
15
|
-
const baseTable = inject('
|
|
18
|
+
const baseTable = inject('table:props');
|
|
16
19
|
|
|
17
20
|
if (!baseTable) {
|
|
18
21
|
throw new Error('BaseTableHead must be used within a BaseTable.');
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
provide('
|
|
24
|
+
provide('tableHead:props', computed(() => props));
|
|
25
|
+
|
|
26
|
+
const classes = computed(() => {
|
|
27
|
+
const base = '';
|
|
28
|
+
|
|
29
|
+
return twMerge(
|
|
30
|
+
base,
|
|
31
|
+
props.class,
|
|
32
|
+
);
|
|
33
|
+
});
|
|
22
34
|
|
|
23
35
|
</script>
|
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<th
|
|
3
|
-
|
|
3
|
+
ref="thRef"
|
|
4
|
+
:class="classes"
|
|
4
5
|
:align="align"
|
|
5
6
|
:colspan="colspan"
|
|
7
|
+
:style="style"
|
|
8
|
+
@click="onClick"
|
|
6
9
|
>
|
|
7
|
-
<
|
|
8
|
-
<slot />
|
|
9
|
-
</div>
|
|
10
|
+
<slot />
|
|
10
11
|
</th>
|
|
11
12
|
</template>
|
|
12
13
|
|
|
13
14
|
<script lang="ts" setup>
|
|
15
|
+
import { useIsFirstColumn } from '@/composables/isFirstColumn';
|
|
16
|
+
import { useIsLastColumn } from '@/composables/isLastColumn';
|
|
14
17
|
import { cellClasses } from '@/services/table/classes';
|
|
15
18
|
import { CellConfig, TableProps } from '@/services/table/types';
|
|
16
19
|
import { ClassNameValue, twMerge } from 'tailwind-merge';
|
|
17
|
-
import { ComputedRef } from 'vue';
|
|
20
|
+
import { ComputedRef, StyleValue } from 'vue';
|
|
18
21
|
|
|
19
|
-
const baseTable = inject('
|
|
20
|
-
const baseTableHead = inject('
|
|
22
|
+
const baseTable = inject('table:props') as ComputedRef<TableProps> | undefined;
|
|
23
|
+
const baseTableHead = inject('tableHead:props', undefined);
|
|
24
|
+
const baseTableHorizontalScrolling = inject('table:horizontalScrolling', undefined) as ComputedRef<boolean> | undefined;
|
|
21
25
|
|
|
22
26
|
if (!baseTableHead) {
|
|
23
27
|
throw new Error('BaseTableCell must be used within a BaseTableHead.');
|
|
@@ -27,33 +31,58 @@ defineOptions({
|
|
|
27
31
|
inheritAttrs: false,
|
|
28
32
|
});
|
|
29
33
|
|
|
34
|
+
const emit = defineEmits(['click']);
|
|
35
|
+
|
|
30
36
|
const props = withDefaults(defineProps<{
|
|
31
37
|
class?: ClassNameValue,
|
|
38
|
+
style?: StyleValue,
|
|
32
39
|
align?: 'left' | 'center' | 'right',
|
|
33
40
|
colspan?: number,
|
|
34
41
|
}>(), {
|
|
35
42
|
class: undefined,
|
|
43
|
+
style: undefined,
|
|
36
44
|
align: 'left',
|
|
37
45
|
colspan: undefined,
|
|
38
46
|
});
|
|
39
47
|
|
|
48
|
+
function onClick(event: MouseEvent) {
|
|
49
|
+
emit('click', event);
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
const cellConfig = computed<CellConfig>(() => {
|
|
41
53
|
return {
|
|
42
|
-
|
|
54
|
+
size: baseTable?.value?.size,
|
|
43
55
|
flush: baseTable?.value?.flush,
|
|
44
56
|
head: true,
|
|
45
57
|
}
|
|
46
58
|
});
|
|
47
59
|
|
|
60
|
+
const thRef = ref<HTMLTableCellElement | null>(null);
|
|
61
|
+
|
|
62
|
+
const { isFirstColumn } = useIsFirstColumn(thRef);
|
|
63
|
+
const { isLastColumn } = useIsLastColumn(thRef);
|
|
64
|
+
|
|
65
|
+
|
|
48
66
|
const classes = computed(() => {
|
|
49
67
|
const base = cellClasses(cellConfig.value);
|
|
68
|
+
const baseTh = 'bg-white text-slate-500 border-b border-slate-300 group';
|
|
69
|
+
const sticky = baseTable?.value.fixedHeader ? 'sticky top-0 z-[2]' : '';
|
|
70
|
+
const firstCol = isFirstColumn.value ? 'border-r border-r-transparent' : '';
|
|
71
|
+
const horizontalScrolling = baseTable?.value.fixedColumn && baseTableHorizontalScrolling?.value && isFirstColumn.value ? 'sticky z-[3] left-0 border-r-slate-200' : '';
|
|
72
|
+
const flushLeft = baseTable?.value.flush && isFirstColumn.value ? 'pl-0' : '';
|
|
73
|
+
const flushRight = baseTable?.value.flush && isLastColumn.value ? 'pr-0' : '';
|
|
50
74
|
|
|
51
75
|
return twMerge(
|
|
52
|
-
'text-slate-500 font-normal',
|
|
53
76
|
base,
|
|
77
|
+
baseTh,
|
|
78
|
+
sticky,
|
|
79
|
+
firstCol,
|
|
80
|
+
horizontalScrolling,
|
|
81
|
+
flushLeft,
|
|
82
|
+
flushRight,
|
|
54
83
|
props.class,
|
|
55
84
|
);
|
|
56
|
-
})
|
|
85
|
+
});
|
|
57
86
|
|
|
58
87
|
|
|
59
88
|
</script>
|