Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
fix(DataTable): external pagination, and sticky table header (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
tewshi authored Dec 29, 2023
1 parent e10948b commit b21e6a6
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 48 deletions.
20 changes: 12 additions & 8 deletions example/cypress/e2e/data-table.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,33 +197,37 @@ describe('DataTable', () => {
});

it('checks for data tables with sticky header', () => {
cy.get('div[data-cy=table-expandable-0]').as('sticky');
cy.get('div[data-cy="table-expandable-0"]').as('sticky');

cy.get('@sticky')
.find('> div > table > tbody > tr:nth-child(5)')
.as('row4');

cy.get('@sticky')
.find('> div > table thead[data-id=head-clone]')
.find('> div > table > thead[data-id=head-clone]')
.should('exist');

cy.get('@sticky')
.find('> div > table > thead[data-id=head-main]')
.as('mainHead')
.should('exist');

cy.get('@row4')
.scrollIntoView()
.get('@sticky')
.find('> div > table thead[data-id=head-main]')
.get('@mainHead')
.should((thead) => {
const classes = Cypress.$(thead).attr('class');
expect(classes).to.contain('_sticky__header_');
expect(classes).to.contain('_stick__top_');
expect(classes).not.to.contain('_stick__top_');
});

cy.window()
.get('body')
.scrollTo('top')
.get('@sticky')
.find('> div > table thead[data-id=head-main][class*=_sticky__header_]')
.get('@mainHead')
.should((thead) => {
const classes = Cypress.$(thead).attr('class');
expect(classes).to.contain('_stick__top_');
expect(classes).not.to.contain('_stick__top_');
});
});
});
6 changes: 5 additions & 1 deletion example/src/assets/main.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
@import './style.css';

@layer base {
html {
@apply overflow-hidden;
}

body {
@apply bg-white text-black;
@apply bg-white text-black h-screen overflow-y-auto overflow-x-hidden;
}

.dark body {
Expand Down
1 change: 1 addition & 0 deletions example/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const RuiPlugin = createRui({
defaults: {
table: {
itemsPerPage,
globalItemsPerPage: false,
},
},
});
Expand Down
44 changes: 25 additions & 19 deletions src/components/tables/DataTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,14 @@ const {
expanded,
singleExpand,
stickyOffset,
stickyHeader,
} = toRefs(props);
const css = useCssModule();
const { stick, table, tableScroller } = useStickyTableHeader(stickyOffset);
const { stick, table, tableScroller } = useStickyTableHeader(
stickyOffset,
stickyHeader,
);
const tableDefaults = useTable();
const globalItemsPerPageSettings = computed(() => {
if (props.globalItemsPerPage !== undefined) {
Expand Down Expand Up @@ -287,6 +291,10 @@ const paginationData: Ref<TablePaginationData> = computed({
};
}
if (get(paginationModifiers)?.external) {
return paginated;
}
return {
total: get(searchData).length,
limit: paginated.limit,
Expand Down Expand Up @@ -745,11 +753,7 @@ const slots = useSlots();
{ [css.thead__loader_linear]: !noData },
]"
>
<th
:class="css.progress"
:colspan="columns.length + (selectedData ? 1 : 0)"
scope="col"
>
<th :class="css.progress" :colspan="colspan" scope="col">
<div :class="css.progress__wrapper">
<Progress
:circular="noData"
Expand Down Expand Up @@ -781,6 +785,11 @@ const slots = useSlots();
</tr>
</thead>
<tbody :class="[css.tbody, { [css['tbody--striped']]: striped }]">
<slot
v-if="slots['body.prepend'] && !(loading && noData)"
:colspan="colspan"
name="body.prepend"
/>
<template v-for="(row, index) in filtered">
<tr
:key="`row-${index}`"
Expand Down Expand Up @@ -859,10 +868,7 @@ const slots = useSlots();
leave-from-class="opacity-100 translate-y-0"
leave-to-class="opacity-0 translate-y-1"
>
<td
:class="css.td"
:colspan="columns.length + (selectedData ? 1 : 0)"
>
<td :class="css.td" :colspan="colspan">
<slot name="no-data">
<div :class="css.empty">
<p v-if="empty.label" :class="css.empty__label">
Expand All @@ -884,6 +890,7 @@ const slots = useSlots();
</tr>
<slot
v-if="slots['body.append'] && !(loading && noData)"
:colspan="colspan"
name="body.append"
/>
</tbody>
Expand Down Expand Up @@ -1094,11 +1101,11 @@ const slots = useSlots();
@apply flex flex-col space-y-3 items-center justify-center flex-1 py-2;
&__label {
@apply text-body-1 font-bold text-center text-current;
@apply text-body-1 font-bold text-center text-current pb-0 mb-0;
}
&__description {
@apply text-body-2 text-center text-rui-text-secondary;
@apply text-body-2 text-center text-rui-text-secondary pb-0 mb-0;
}
}
}
Expand All @@ -1107,6 +1114,7 @@ const slots = useSlots();
.checkbox {
@apply ps-4 w-14;
@apply max-w-[3.125rem] #{!important};
}
&.dense {
Expand Down Expand Up @@ -1136,13 +1144,13 @@ const slots = useSlots();
}
.table {
@apply divide-gray-700;
@apply divide-white/[0.12];
.thead {
@apply divide-y divide-gray-700;
@apply divide-y divide-white/[0.12];
&.sticky__header.stick__top {
th {
@apply bg-[#121212] border-b border-b-gray-700;
@apply bg-[#121212] border-b border-b-white/[0.12];
}
}
Expand All @@ -1165,17 +1173,15 @@ const slots = useSlots();
}
> .tr {
@apply hover:bg-white/[0.04];
&__selected {
@apply bg-rui-dark-primary/[0.08];
}
&__expandable {
@apply bg-[#121212] hover:bg-[#121212];
}
.td {
@apply text-gray-400;
}
}
}
}
Expand Down
34 changes: 14 additions & 20 deletions src/composables/sticky-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { type Ref } from 'vue';
/**
* Setup sticky table header
*/
export const useStickyTableHeader = (offsetTop: Ref<number> = ref(0)) => {
export const useStickyTableHeader = (
offsetTop: Ref<number> = ref(0),
sticky: Ref<boolean> = ref(false),
) => {
const table: Ref<HTMLTableElement | null> = ref(null);
const tableScroller: Ref<HTMLElement | null> = ref(null);
const stick: Ref<boolean> = ref(false);
Expand All @@ -18,7 +21,7 @@ export const useStickyTableHeader = (offsetTop: Ref<number> = ref(0)) => {
const updateHeaderCellWidth = () => {
const root = get(table);

if (!root) {
if (!get(sticky) || !root) {
return;
}

Expand All @@ -40,10 +43,10 @@ export const useStickyTableHeader = (offsetTop: Ref<number> = ref(0)) => {
});
};

const addStickyClass = () => {
const toggleStickyClass = () => {
const root = get(table);

if (!root) {
if (!get(sticky) || !root) {
return;
}

Expand Down Expand Up @@ -99,28 +102,19 @@ export const useStickyTableHeader = (offsetTop: Ref<number> = ref(0)) => {
};

const updateHeader = () => {
addStickyClass();
updateHeaderCellWidth();
};

watchEffect(() => {
if (!get(table)?.querySelector(selectors.head)) {
if (!get(sticky) || !get(table)?.querySelector(selectors.head)) {
return;
}

updateHeader();

const scroller = get(tableScroller);

if (scroller) {
useResizeObserver(get(tableScroller), updateHeader);
}
});
toggleStickyClass();
updateHeaderCellWidth();
};

onMounted(() => {
useEventListener(window, 'scroll', addStickyClass);
updateHeader();
useEventListener(document.body, 'scroll', toggleStickyClass);
useEventListener(window, 'resize', updateHeader);
useEventListener(tableScroller, 'scroll', updateHeader);
useResizeObserver(get(tableScroller), updateHeader);
});

return {
Expand Down

0 comments on commit b21e6a6

Please sign in to comment.