Skip to content

Commit fddab62

Browse files
committed
Improvement - VueUiCarouselTable - Allow for any cell size
1 parent 37d4d15 commit fddab62

File tree

1 file changed

+52
-30
lines changed

1 file changed

+52
-30
lines changed

src/components/vue-ui-carousel-table.vue

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup>
2-
import { ref, computed, onMounted, watch, nextTick } from "vue";
2+
import { ref, computed, onMounted, watch, nextTick, onBeforeUnmount } from "vue";
33
import { useConfig } from "../useConfig";
44
import { useNestedProp } from "../useNestedProp";
55
import { createCsvContent, createUid, downloadCsv, error, objectIsEmpty, opacity } from "../lib";
@@ -59,8 +59,8 @@ const FINAL_CONFIG = computed(() => {
5959
return useNestedProp({
6060
userConfig: props.config,
6161
defaultConfig: DEFAULT_CONFIG
62-
})
63-
})
62+
});
63+
});
6464
6565
const { isPrinting, isImaging, generatePdf: makePdf, generateImage } = usePrinter({
6666
elementId: `carousel-table_${uid.value}`,
@@ -69,7 +69,7 @@ const { isPrinting, isImaging, generatePdf: makePdf, generateImage } = usePrinte
6969
7070
const mutableConfig = ref({
7171
showAnimation: FINAL_CONFIG.value.animation.use
72-
})
72+
});
7373
7474
const tableContainer = ref(null);
7575
const chartContainer = ref(null);
@@ -80,20 +80,35 @@ const captionHeight = ref(0);
8080
const tableRowHeight = ref(0);
8181
const isResponsive = ref(false);
8282
83+
const tbody = ref(null);
84+
const allTr = ref(null);
85+
const scrollIndex = ref(0);
86+
87+
function setTrElements() {
88+
if (tbody.value) {
89+
allTr.value = {
90+
elements: tbody.value.getElementsByTagName('tr'),
91+
heights: Array.from(tbody.value.getElementsByTagName('tr')).map(el => el.getBoundingClientRect().height)
92+
}
93+
}
94+
}
95+
96+
onMounted(setTrElements);
97+
98+
const maxTrHeight = computed(() => {
99+
if(!allTr.value || !allTr.value.heights.length) return 0;
100+
return Math.max(...allTr.value.heights) + captionHeight.value + tableRowHeight.value;
101+
})
102+
83103
const visibleCells = computed(() => {
84104
if(!props.dataset.body) return 0;
85105
return FINAL_CONFIG.value.tbody.tr.visible <= props.dataset.body.length ? FINAL_CONFIG.value.tbody.tr.visible :props.dataset.body.length;
86-
})
106+
});
87107
88108
const rowHeight = computed(() => {
89109
return ((FINAL_CONFIG.value.tbody.tr.height + FINAL_CONFIG.value.tbody.tr.td.padding.top + FINAL_CONFIG.value.tbody.tr.td.padding.bottom + FINAL_CONFIG.value.tbody.tr.border.size * 2) * visibleCells.value + captionHeight.value + tableRowHeight.value)
90110
});
91111
92-
const maxHeight = computed(() => {
93-
if (!props.dataset || !props.dataset.body || !props.dataset.head) return 0;
94-
return ((props.dataset.body.length * (isResponsive.value ? props.dataset.head.length : 1)) - visibleCells.value) * (FINAL_CONFIG.value.tbody.tr.height + FINAL_CONFIG.value.tbody.tr.td.padding.top + FINAL_CONFIG.value.tbody.tr.td.padding.bottom + (FINAL_CONFIG.value.tbody.tr.border.size * 2));
95-
})
96-
97112
const init = ref(0);
98113
const raf = ref(null);
99114
const lastTimestamp = ref(0);
@@ -109,7 +124,7 @@ onMounted(() => {
109124
tableRowHeight.value = tableRow.value.getBoundingClientRect().height;
110125
}
111126
112-
if (mutableConfig.value.showAnimation) {
127+
if (mutableConfig.value.showAnimation && !!allTr.value) {
113128
startAnimation();
114129
}
115130
});
@@ -125,23 +140,31 @@ function startAnimation() {
125140
}
126141
}
127142
143+
function hasReachedScrollBottom() {
144+
if(!tableContainer.value) return false;
145+
const { scrollTop, scrollHeight, clientHeight } = tableContainer.value;
146+
return scrollTop + clientHeight >= scrollHeight;
147+
}
148+
128149
function animate(timestamp) {
129150
if (isPaused.value) return;
130151
if (!lastTimestamp.value) lastTimestamp.value = timestamp;
131152
132153
const deltaTime = timestamp - lastTimestamp.value;
133154
134155
if (deltaTime >= FINAL_CONFIG.value.animation.speedMs) {
135-
init.value += (FINAL_CONFIG.value.tbody.tr.height + FINAL_CONFIG.value.tbody.tr.td.padding.top + FINAL_CONFIG.value.tbody.tr.td.padding.bottom + (FINAL_CONFIG.value.tbody.tr.border.size));
136-
if (init.value > maxHeight.value) {
156+
init.value += allTr.value.heights[scrollIndex.value];
157+
if (hasReachedScrollBottom() || scrollIndex.value >= allTr.value.heights.length) {
137158
init.value = 0;
138-
}
159+
scrollIndex.value = 0;
160+
}
139161
140162
if (tableContainer.value) {
141163
tableContainer.value.scrollTo({
142164
top: init.value,
143165
behavior: 'smooth'
144166
});
167+
scrollIndex.value += 1;
145168
}
146169
147170
lastTimestamp.value = timestamp;
@@ -156,6 +179,8 @@ function pauseAnimation() {
156179
raf.value = null;
157180
}
158181
182+
onBeforeUnmount(pauseAnimation)
183+
159184
function resumeAnimation() {
160185
if (!isPaused.value || !mutableConfig.value.showAnimation) return;
161186
isPaused.value = false;
@@ -202,6 +227,8 @@ onMounted(() => {
202227
})
203228
captionHeight.value = caption.value ? caption.value.getBoundingClientRect().height : 0;
204229
tableRowHeight.value = tableRow.value ? tableRow.value.getBoundingClientRect().height : 0;
230+
scrollIndex.value = 0;
231+
setTrElements();
205232
})
206233
if(tableContainer.value) {
207234
observer.observe(tableContainer.value);
@@ -260,7 +287,7 @@ defineExpose({
260287
ref="tableContainer"
261288
:id="`carousel-table_${uid}`"
262289
:style="{
263-
height: isPrinting || isImaging ? 'auto' : `${rowHeight}px`,
290+
height: isPrinting || isImaging ? 'auto' : `${Math.max(rowHeight, maxTrHeight)}px`,
264291
containerType: 'inline-size',
265292
position: 'relative',
266293
overflow: 'auto',
@@ -332,18 +359,19 @@ defineExpose({
332359
</tr>
333360
</thead>
334361

335-
<tbody v-if="dataset.body && dataset.head">
362+
<tbody v-if="dataset.body && dataset.head" ref="tbody">
336363
<tr
337364
v-for="(tr, i) in dataset.body"
338365
:style="{
339366
...FINAL_CONFIG.tbody.tr.style,
340-
border: `${FINAL_CONFIG.tbody.tr.border.size}px solid ${FINAL_CONFIG.tbody.tr.border.color}`
367+
border: `${FINAL_CONFIG.tbody.tr.border.size}px solid ${FINAL_CONFIG.tbody.tr.border.color}`,
368+
verticalAlign: 'middle'
341369
}"
342370
>
343371
<td
344372
role="cell"
345373
v-for="(td, j) in tr"
346-
:data-cell="(isResponsive && dataset.head[j].length > 50) ? dataset.head[j].slice(0, 50) + '...' : dataset.head[j] || ''"
374+
:data-cell="dataset.head[j] || ''"
347375
:style="{
348376
...FINAL_CONFIG.tbody.tr.td.style,
349377
border: `${FINAL_CONFIG.tbody.tr.td.border.size}px solid ${FINAL_CONFIG.tbody.tr.td.border.color}`,
@@ -352,10 +380,11 @@ defineExpose({
352380
paddingRight: FINAL_CONFIG.tbody.tr.td.padding.right + 'px',
353381
paddingBottom: FINAL_CONFIG.tbody.tr.td.padding.bottom + 'px',
354382
paddingLeft: FINAL_CONFIG.tbody.tr.td.padding.left + 'px',
383+
verticalAlign: 'middle'
355384
}"
356385
:height="`${FINAL_CONFIG.tbody.tr.height}px`"
357386
>
358-
{{ $slots.td ? '' : isResponsive ? typeof td === 'string' ? td.slice(0, 30) + '...' : td : td }}
387+
{{ $slots.td ? '' : td }}
359388
<slot name="td" v-bind="{ td, rowIndex: i, colIndex: j}"/>
360389
</td>
361390
</tr>
@@ -436,29 +465,22 @@ thead th, tbody td {
436465
display: grid;
437466
gap: 0.5rem;
438467
grid-template-columns: repeat(2, 1fr);
468+
align-items: center;
439469
padding: 0.5rem 1rem;
440470
outline: none !important;
441471
text-align: left;
442-
vertical-align: middle;
472+
height:max-content;
443473
}
444474
tr {
445-
outline: v-bind(tdo);
446-
}
447-
448-
td:first-child {
449-
padding-top: 1rem;
450-
}
451-
452-
td:last-child {
453-
padding-bottom: 1rem;
475+
height: fit-content;
454476
}
455477
456478
td::before {
457479
content: attr(data-cell) ": ";
458480
font-weight: 700;
459481
text-transform: capitalize;
460482
font-size: 10px;
461-
height: 100%;
483+
height: auto;
462484
}
463485
}
464486

0 commit comments

Comments
 (0)