Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/swift-stamps-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@drivenets/design-system': patch
---

Update `DsTable` scroll, use thin scrollbar for header
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function generateTestData(count: number): Person[] {
}

const getScrollContainer = (): HTMLElement => {
const el = document.querySelector<HTMLElement>('[class*="virtualizedContainer"]');
const el = document.querySelector<HTMLElement>('[class*="virtualizedContainer"] tbody');
if (!el) {
throw new Error('Expected virtualized scroll container');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('DsTable Virtualized', () => {
await page.elementLocator(firstRowRoot).click();
await expect.element(firstRowCheckboxInput).toBeChecked();

const scrollContainer = document.querySelector('[class*="virtualizedContainer"]');
const scrollContainer = document.querySelector('[class*="virtualizedContainer"] tbody');

if (scrollContainer) {
scrollContainer.scrollTop = scrollContainer.scrollHeight;
Expand Down Expand Up @@ -88,7 +88,7 @@ describe('DsTable Virtualized', () => {
await page.getByRole('button', { name: 'chevron_right' }).nth(0).click();
await expect.element(page.getByText('Expanded: First1')).toBeVisible();

const scrollContainer = document.querySelector('[class*="virtualizedContainer"]');
const scrollContainer = document.querySelector('[class*="virtualizedContainer"] tbody');

if (scrollContainer) {
scrollContainer.scrollTop = scrollContainer.scrollHeight;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
@use '../../../../styles/scrollbars' as scrollbars;

.body {
display: grid;
display: block;
position: relative;
overflow-y: auto;
flex: 1;
min-height: 0;

@include scrollbars.scrollbar-on-hover;
}

// 1px row pinned at `top: <totalSize>` (set inline) so absolutely-positioned
// rows extend the parent's scrollable overflow area.
.sentinel {
position: absolute;
left: 0;
width: 1px;
height: 1px;
pointer-events: none;
visibility: hidden;
}

.emptyState {
position: absolute;
inset: 0;
top: var(--ds-table-header-height);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { useInfiniteScroll } from './use-infinite-scroll';

export const DsTableBodyVirtualized = <TData,>({
table,
tableContainerRef,
emptyState,
estimateSize,
overscan,
Expand All @@ -20,6 +19,7 @@ export const DsTableBodyVirtualized = <TData,>({
}: DsTableBodyVirtualizedProps<TData>) => {
const rowsMapRef = useRef(new Map<string, HTMLTableRowElement>());
const rowHeightsMapRef = useRef(new Map<string, number>());
const tbodyRef = useRef<HTMLTableSectionElement>(null);

const { rows } = table.getRowModel();

Expand All @@ -32,16 +32,16 @@ export const DsTableBodyVirtualized = <TData,>({
return item ? `${item.row.id}${item.isExpandedRowContent ? '-expanded-content' : ''}` : String(index);
};

const { loadDataIfNeeded } = useInfiniteScroll(tableContainerRef, rows.length, infiniteScroll);
const { loadDataIfNeeded } = useInfiniteScroll(tbodyRef, rows.length, infiniteScroll);

const rowVirtualizer = useVirtualizer<HTMLDivElement, HTMLTableRowElement>({
const rowVirtualizer = useVirtualizer<HTMLTableSectionElement, HTMLTableRowElement>({
count: rowsAndExpandedRowContent.length,
estimateSize: (index) => {
const cachedHeight = rowHeightsMapRef.current.get(getItemKey(index));
return cachedHeight || estimateSize;
}, // estimate row height for accurate scrollbar dragging
getItemKey,
getScrollElement: () => tableContainerRef.current,
getScrollElement: () => tbodyRef.current,
// measure dynamic row height, except in firefox because it measures table border height incorrectly
measureElement:
typeof window !== 'undefined' && navigator.userAgent.indexOf('Firefox') === -1
Expand Down Expand Up @@ -86,6 +86,7 @@ export const DsTableBodyVirtualized = <TData,>({

return (
<DsTableBody
ref={tbodyRef}
rowsMapRef={rowsMapRef}
rowHeightsMapRef={rowHeightsMapRef}
rowVirtualizer={rowVirtualizer}
Expand All @@ -97,7 +98,8 @@ export const DsTableBodyVirtualized = <TData,>({
};

interface DsTableBodyProps<TData> {
rowVirtualizer: Virtualizer<HTMLDivElement, HTMLTableRowElement>;
ref: RefObject<HTMLTableSectionElement | null>;
rowVirtualizer: Virtualizer<HTMLTableSectionElement, HTMLTableRowElement>;
rowsMapRef: RefObject<Map<string, HTMLTableRowElement>>;
rowHeightsMapRef: RefObject<Map<string, number>>;
rowsAndExpandedRowContent: {
Expand All @@ -109,6 +111,7 @@ interface DsTableBodyProps<TData> {
}

function DsTableBody<TData>({
ref,
rowVirtualizer,
rowsMapRef,
rowHeightsMapRef,
Expand All @@ -117,14 +120,10 @@ function DsTableBody<TData>({
rowSelection,
}: DsTableBodyProps<TData>) {
const virtualRows = rowVirtualizer.getVirtualItems();
const totalSize = rowVirtualizer.getTotalSize();

return (
<TableBody
className={styles.body}
style={{
height: `${rowVirtualizer.getTotalSize().toString()}px`, // tells scrollbar how big the table is
}}
>
<TableBody ref={ref} className={styles.body}>
{virtualRows.length > 0 ? (
virtualRows.map((virtualRow) => {
const row = rowsAndExpandedRowContent[virtualRow.index];
Expand All @@ -150,6 +149,10 @@ function DsTableBody<TData>({
<TableCell className={styles.emptyState}>{emptyState || EMPTY_TABLE_STATE_TEXT}</TableCell>
</TableRow>
)}

<tr aria-hidden className={styles.sentinel} style={{ top: `${totalSize.toString()}px` }}>
<td />
</tr>
</TableBody>
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type RefObject, type ReactNode } from 'react';
import { type ReactNode } from 'react';
import { type RowSelectionState, type Table } from '@tanstack/react-table';

export interface DsTableBodyVirtualizedProps<TData> {
Expand All @@ -7,11 +7,6 @@ export interface DsTableBodyVirtualizedProps<TData> {
* and column state.
*/
table: Table<TData>;
/**
* Ref to the scrollable container that hosts the virtualized rows. Required by
* the virtualizer to measure viewport size and listen for scroll events.
*/
tableContainerRef: RefObject<HTMLDivElement | null>;
/**
* Optional content rendered in place of rows when the table has no data.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
@use '../../styles/variables' as vars;

.stickyHeader {
position: sticky;
top: 0;
z-index: 10;
background-color: var(--background);
}

.virtualizedHeader {
display: grid;
display: block;
}

.headerRow {
Expand Down Expand Up @@ -57,6 +54,7 @@

.selectHeaderCell {
padding: 0;
justify-content: center;
}

.headerSortContainer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
)}
>
{headerGroup.headers.map((header) => {
const headerStyle = getColumnSizeStyle(header.column.getSize(), virtualized);
const headerStyle = getColumnSizeStyle(header.column.getSize());
const canSort = header.column.getCanSort();
const isSelectColumn = header.column.id === SELECT_COLUMN_ID;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const DsTableRowVirtualized = <TData,>({
<>
{row.getVisibleCells().map((cell, idx) => {
const isLastColumn = idx === row.getVisibleCells().length - 1;
const cellStyle = getColumnSizeStyle(cell.column.getSize(), true);
const cellStyle = getColumnSizeStyle(cell.column.getSize());

return (
<TableCell
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface DsTableRowVirtualizedProps<TData> {
/**
* TanStack virtualizer driving the scroll window for the table body.
*/
rowVirtualizer: Virtualizer<HTMLDivElement, HTMLTableRowElement>;
rowVirtualizer: Virtualizer<HTMLTableSectionElement, HTMLTableRowElement>;
/**
* Virtual item descriptor for this row (index, start, size) from the virtualizer.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,5 @@
.selectableCell {
padding: 0;
text-align: center;
justify-content: center;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@use '../../styles/typography';
@use '../../styles/utilities' as utils;
@use '../../styles/scrollbars' as scrollbars;
@use './styles/variables' as vars;

:root {
Expand All @@ -21,7 +22,48 @@ $bulk-actions-height: 60px;

.dataTableContainer {
max-height: 100%;
overflow: auto;
overflow-x: auto;
overflow-y: hidden;
display: flex;
flex-direction: column;

@include scrollbars.scrollbar-on-hover;

> table {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
width: max-content;
min-width: 100%;
}

thead {
display: block;
flex-shrink: 0;
padding-right: scrollbars.$scrollbar-thin-size;
}

tbody {
display: block;
overflow-y: auto;
flex: 1;
min-height: 0;
scrollbar-gutter: stable;

@include scrollbars.scrollbar-on-hover;
}

thead tr,
tbody tr {
display: flex;
}

thead th,
tbody td {
display: flex;
align-items: center;
}
}

.table {
Expand All @@ -45,14 +87,44 @@ $bulk-actions-height: 60px;
text-align: center;
}

.virtualized {
display: grid;
}

.virtualizedContainer {
position: relative;
height: vars.$virtualized-height;
overflow: auto;
overflow-x: auto;
overflow-y: hidden;
display: flex;
flex-direction: column;

@include scrollbars.scrollbar-on-hover;

> table {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
width: max-content;
min-width: 100%;
}

thead {
display: block;
flex-shrink: 0;
padding-right: scrollbars.$scrollbar-thin-size;
}

tbody {
flex: 1;
min-height: 0;
}

thead tr {
display: flex;
}

thead th {
display: flex;
align-items: center;
}
}

.bulkActionsVisible {
Expand Down
9 changes: 1 addition & 8 deletions packages/design-system/src/components/ds-table/ds-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -298,18 +298,11 @@ const DsTable = <TData extends { id: string }, TValue>({
)}
>
<DragWrapper>
<Table
className={classnames(
fullWidth && styles.fullWidth,
!bordered && styles.tableNoBorder,
virtualized && styles.virtualized,
)}
>
<Table className={classnames(fullWidth && styles.fullWidth, !bordered && styles.tableNoBorder)}>
<DsTableHeader table={table} />
{virtualized ? (
<DsTableBodyVirtualized
table={table}
tableContainerRef={tableContainerRef}
emptyState={emptyState}
estimateSize={virtualizedOptions?.estimateSize || ROW_SIZE_HEIGHT_MAP[rowSize]}
overscan={virtualizedOptions?.overscan}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,8 @@
.destructiveAction {
color: var(--background-error);
}

.horizontalScrollWrapper {
width: 700px;
height: 320px;
}
Loading
Loading