sprintify-ui 0.7.11 → 0.8.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.
Files changed (44) hide show
  1. package/dist/sprintify-ui.es.js +10481 -10348
  2. package/dist/style.css +1 -1
  3. package/dist/types/components/BaseDataIterator.vue.d.ts +50 -4
  4. package/dist/types/components/BaseDataIteratorSectionColumns.vue.d.ts +156 -68
  5. package/dist/types/components/BaseDataTable.vue.d.ts +86 -6
  6. package/dist/types/components/BaseDataTableTemplate.vue.d.ts +44 -28
  7. package/dist/types/components/BaseTable.vue.d.ts +30 -7
  8. package/dist/types/components/BaseTableCell.vue.d.ts +19 -1
  9. package/dist/types/components/BaseTableColumn.vue.d.ts +50 -3
  10. package/dist/types/components/BaseTableHead.vue.d.ts +6 -5
  11. package/dist/types/components/BaseTableHeader.vue.d.ts +12 -2
  12. package/dist/types/components/BaseTableRow.vue.d.ts +5 -0
  13. package/dist/types/composables/isFirstColumn.d.ts +4 -0
  14. package/dist/types/composables/isLastColumn.d.ts +4 -0
  15. package/dist/types/composables/paginatedData.d.ts +5 -5
  16. package/dist/types/services/table/types.d.ts +6 -5
  17. package/dist/types/types/index.d.ts +7 -2
  18. package/dist/types/utils/getApiData.d.ts +1 -1
  19. package/package.json +2 -1
  20. package/src/assets/main.css +0 -1
  21. package/src/components/BaseAvatar.vue +1 -0
  22. package/src/components/BaseDataIterator.stories.js +96 -1
  23. package/src/components/BaseDataIterator.vue +135 -11
  24. package/src/components/BaseDataIteratorSectionColumns.vue +2 -2
  25. package/src/components/BaseDataTable.stories.js +140 -50
  26. package/src/components/BaseDataTable.vue +82 -48
  27. package/src/components/BaseDataTableTemplate.vue +207 -372
  28. package/src/components/BaseTable.stories.js +57 -15
  29. package/src/components/BaseTable.vue +71 -9
  30. package/src/components/BaseTableBody.vue +1 -1
  31. package/src/components/BaseTableCell.vue +94 -36
  32. package/src/components/BaseTableColumn.vue +25 -2
  33. package/src/components/BaseTableHead.vue +17 -5
  34. package/src/components/BaseTableHeader.vue +39 -10
  35. package/src/components/BaseTableRow.vue +27 -6
  36. package/src/composables/isFirstColumn.ts +31 -0
  37. package/src/composables/isLastColumn.ts +31 -0
  38. package/src/composables/paginatedData.ts +22 -10
  39. package/src/services/table/classes.ts +13 -9
  40. package/src/services/table/types.ts +6 -5
  41. package/src/stories/List.stories.js +5 -1
  42. package/src/types/index.ts +7 -2
  43. package/src/utils/getApiData.ts +1 -1
  44. 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
- spacing: {
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="p-6">
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
- return { args, options };
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
- <p class="mb-3">
119
- Only the first cell is clickable
120
- </p>
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
- ${headTemplate}
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
- <table :class="classes">
3
- <slot />
4
- </table>
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 { CellSpacing } from '../services/table/types'
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
- spacing?: CellSpacing,
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
- spacing: 'md',
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>
@@ -6,7 +6,7 @@
6
6
 
7
7
  <script lang="ts" setup>
8
8
 
9
- const baseTable = inject('BaseTable');
9
+ const baseTable = inject('table:props');
10
10
 
11
11
  if (!baseTable) {
12
12
  throw new Error('BaseTableBody must be used within a BaseTable.');
@@ -1,37 +1,53 @@
1
1
  <template>
2
2
  <td
3
- class="p-0 border-b border-slate-200 group-last/row:border-b-0"
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
- <component
8
- :is="componentName"
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
- <slot />
16
- </component>
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('BaseTable') as ComputedRef<TableProps> | undefined;
33
- const baseTableHead = inject('BaseTableHead', undefined);
34
- const baseTableRow = inject('BaseTableRow', undefined) as ComputedRef<CellProps> | undefined;
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
- spacing: baseTable?.value?.spacing,
84
+ size: baseTable?.value?.size,
63
85
  flush: baseTable?.value?.flush,
64
86
  head: isHead.value,
65
87
  }
66
88
  });
67
89
 
68
- const propsInternal = computed<CellProps>(() => {
69
- return merge(cloneDeep(baseTableRow.value), props);
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 componentName = computed(() => {
73
- if (propsInternal.value.href) {
74
- return 'a';
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
- if (propsInternal.value.to) {
78
- return 'router-link';
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
- return 'div';
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 clickRow = clickableRow.value ? 'group-hover/row:bg-slate-50' : '';
88
- const clickCell = clickableCell.value ? 'hover:bg-slate-50' : '';
132
+ const hover = clickable.value && hoverInternal.value ? 'bg-slate-50' : '';
133
+ const firstCol = isFirstColumn.value ? 'duration-300 transition-[border] 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
- clickRow,
94
- clickCell,
142
+ hover,
143
+ firstCol,
144
+ horizontalScrolling,
145
+ flushLeft,
146
+ flushRight,
95
147
  props.class,
96
148
  );
97
149
  });
98
150
 
99
- const clickable = computed(() => {
100
- return propsInternal.value.href || propsInternal.value.to;
101
- });
151
+ const tdRef = ref<HTMLTableCellElement | null>(null);
102
152
 
103
- const clickableRow = computed(() => {
104
- return !clickableCell.value && clickable.value;
105
- });
153
+ const { isFirstColumn } = useIsFirstColumn(tdRef);
154
+ const { isLastColumn } = useIsLastColumn(tdRef);
106
155
 
107
- const clickableCell = computed(() => {
108
- return props.href || props.to;
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
- clickable: {
48
- default: true,
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
- sticky?: boolean,
13
+ class?: ClassNameValue,
11
14
  }>(), {
12
- sticky: false,
15
+ class: undefined,
13
16
  });
14
17
 
15
- const baseTable = inject('BaseTable');
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('BaseTableHead', computed(() => props));
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
- class="p-0 border-b border-slate-200"
3
+ ref="thRef"
4
+ :class="classes"
4
5
  :align="align"
5
6
  :colspan="colspan"
7
+ :style="style"
8
+ @click="onClick"
6
9
  >
7
- <div :class="classes">
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('BaseTable') as ComputedRef<TableProps> | undefined;
20
- const baseTableHead = inject('BaseTableHead', undefined);
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
- spacing: baseTable?.value?.spacing,
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 ? 'duration-300 transition-[border] 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>