Skip to content

Commit

Permalink
feat(Table): Added horizontal virtualization
Browse files Browse the repository at this point in the history
  • Loading branch information
Carlos Pinedo committed Nov 24, 2023
1 parent 7027df5 commit 8da3740
Show file tree
Hide file tree
Showing 15 changed files with 121 additions and 111 deletions.
15 changes: 6 additions & 9 deletions packages/table/src/core/Cell/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@ import { StyledTableCell } from './StyledTableCell';
import { useRenderContent } from './useRenderContent';
import { ColDef } from '../../declarations';
import { useInitialState } from '../../editors/useInitialState';
import { VirtualItem } from '@tanstack/react-virtual';

interface CellProps {
data: unknown;
columnDef: ColDef;
cellWidth?: React.CSSProperties['width'];
cellFlex?: React.CSSProperties['flex'];
virtualColumn: VirtualItem;
cellHeight?: React.CSSProperties['height'];
offsetX?: number;
}

export const Cell: React.FC<CellProps> = ({
data,
columnDef,
cellWidth,
cellFlex,
//virtualColumn,
cellHeight,
offsetX,
}) => {
const { onReset } = columnDef;

Expand All @@ -31,11 +30,9 @@ export const Cell: React.FC<CellProps> = ({
<StyledTableCell
onDoubleClick={onDoubleClick}
ref={cellRef}
/* cellWidth={
virtualColumn?.size ? `1 1 ${virtualColumn.size}px` : cellWidth
}*/
cellWidth={cellWidth}
cellFlex={cellFlex}
offsetX={offsetX}
height={cellHeight}
>
{isEditMode ? editionContent : viewContent}
</StyledTableCell>
Expand Down
14 changes: 6 additions & 8 deletions packages/table/src/core/Cell/StyledTableCell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,25 @@ import React from 'react';
import styled, { DefaultTheme } from 'styled-components';

interface StyledTableCellWrapperProps {
cellFlex?: React.CSSProperties['flex'];
cellWidth?: React.CSSProperties['width'];
height?: React.CSSProperties['height'];
offsetX?: number;
theme: DefaultTheme;
}

export const StyledTableCell = styled.td.attrs(
({ cellWidth, theme }: StyledTableCellWrapperProps) => ({
({ cellWidth, theme, offsetX, height }: StyledTableCellWrapperProps) => ({
style: {
//flex: cellFlex,
width: cellWidth,
color: theme.alias.color.text.body.base,
left: `${offsetX}px`,
height,
},
}),
)<StyledTableCellWrapperProps>`
position: relative;
display: flex;
align-items: center;
position: absolute;
top: 0;
box-sizing: border-box;
padding: 0 1.2rem;
height: 100%;
overflow: hidden;
flex: 0 0 auto;
`;
9 changes: 3 additions & 6 deletions packages/table/src/core/HeaderCell/HeaderCell.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { VirtualItem } from '@tanstack/react-virtual';
import React from 'react';
import { ColDef } from '../../declarations';
import { StyledHeaderCell } from './StyledHeaderCell';
Expand All @@ -7,22 +6,20 @@ import { Typography } from '@devoinc/genesys-ui';
interface HeaderCellProps {
scrolled?: boolean;
colDef: ColDef;
headerCellFlex: React.CSSProperties['flex'];
headerCellWidth: React.CSSProperties['width'];
virtualColumn: VirtualItem;
offsetX: number;
}

export const HeaderCell: React.FC<HeaderCellProps> = ({
scrolled,
colDef,
headerCellFlex,
headerCellWidth,
//virtualColumn,
offsetX,
}) => (
<StyledHeaderCell
scrolled={scrolled}
headerCellWidth={headerCellWidth}
headerCellFlex={headerCellFlex}
offsetX={offsetX}
>
<Typography.Heading size="h6">{colDef.headerName}</Typography.Heading>
</StyledHeaderCell>
Expand Down
12 changes: 5 additions & 7 deletions packages/table/src/core/HeaderCell/StyledHeaderCell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,23 @@ import { getSizes } from '../utils';
interface StyledHeaderCellProps {
scrolled?: boolean;
headerCellWidth: React.CSSProperties['width'];
headerCellFlex: React.CSSProperties['flex'];
offsetX?: number;
}

export const StyledHeaderCell = styled.th<StyledHeaderCellProps>`
display: flex;
align-items: center;
display: block;
top: 0;
left: 0;
box-sizing: border-box;
height: 4.2rem;
padding: 0 1.2rem;
width: ${({ headerCellWidth }) => headerCellWidth};
flex: ${({ headerCellFlex }) => headerCellFlex};
color: ${({ theme }) => theme.alias.color.text.heading.base};
flex: 0 0 auto;
transform: ${({ offsetX }) => `translateX(${offsetX}px)`};
${({ scrolled, theme }) => {
return css`
${scrolled && elevationMixin(theme)('stickyBottom')};
position: ${scrolled ? 'sticky' : 'relative'};
position: ${scrolled ? 'sticky' : 'absolute'};
`;
}}
Expand Down
32 changes: 11 additions & 21 deletions packages/table/src/core/Row/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import { StyledTableRow } from './StyledTableRow';
import { ColDef } from '../../declarations';
import { Cell } from '../Cell';
import { VirtualItem, Virtualizer } from '@tanstack/react-virtual';
import { getColDefByID } from '../utils';

interface RowProps {
columnDefs: ColDef[];
data: { [key: string]: unknown };
even: boolean;
styles?: React.CSSProperties;
columnVirtualizer: Virtualizer<undefined, Element>;
columnVirtualizer: Virtualizer<HTMLDivElement, Element>;
}

export const Row: React.FC<RowProps> = ({
Expand All @@ -20,7 +19,6 @@ export const Row: React.FC<RowProps> = ({
styles,
columnVirtualizer,
}) => {
const columnsNumber = columnDefs.length;
return (
<StyledTableRow
even={even}
Expand All @@ -29,24 +27,16 @@ export const Row: React.FC<RowProps> = ({
height={styles.height}
transform={styles.transform}
>
{columnVirtualizer.getVirtualItems().map((virtualColumn: VirtualItem) => {
const cellWidth = getColDefByID(columnDefs, virtualColumn)?.cellStyle
?.width;
return (
<Cell
columnDef={columnDefs[virtualColumn.index]}
key={`cell-${virtualColumn.key}`}
data={data[columnDefs[virtualColumn.index].id] ?? ''}
virtualColumn={virtualColumn}
cellFlex={
cellWidth
? `1 1 ${cellWidth}%`
: `1 1 calc(100% / ${columnsNumber})`
}
cellWidth={virtualColumn?.size ? `${virtualColumn.size}px` : null}
/>
);
})}
{columnVirtualizer.getVirtualItems().map((virtualColumn: VirtualItem) => (
<Cell
columnDef={columnDefs[virtualColumn.index]}
key={`cell-${virtualColumn.key}`}
data={data[columnDefs[virtualColumn.index].id] ?? ''}
cellWidth={`${virtualColumn.size}px`}
cellHeight={styles.height}
offsetX={virtualColumn.start}
/>
))}
</StyledTableRow>
);
};
4 changes: 1 addition & 3 deletions packages/table/src/core/Row/StyledTableRow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface StyledTableRowProps {
export const StyledTableRow = styled.tr.attrs<StyledTableRowProps>(
({ position, width, height, transform }) => ({
style: {
position,
position: position ?? 'absolute',
width: width ? `${width}px` : '100%',
height,
transform,
Expand All @@ -21,6 +21,4 @@ export const StyledTableRow = styled.tr.attrs<StyledTableRowProps>(
)<StyledTableRowProps>`
top: 0;
left: 0;
display: flex;
align-items: center;
`;
4 changes: 1 addition & 3 deletions packages/table/src/core/Table/StyledTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ export interface StyledTableProps {

export const StyledTable = styled.table<StyledTableProps>`
position: relative;
display: block;
height: ${({ height }) => height};
width: ${({ width }) => (width ? `${width}px` : '100%')};
//min-width: 1800px;
width: ${({ width }) => (width ? width : '100%')};
`;
7 changes: 5 additions & 2 deletions packages/table/src/core/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@ export const Table: React.FC<TableProps> = ({ tableOptions, data }) => {

return (
<StyledTableWrapper
ref={ref}
maxHeight={style?.wrapper?.maxHeight}
scrolled={style?.wrapper?.scrolled}
ref={ref}
height={'500px'}
>
<StyledTable>
<StyledTable
width={`${columnVirtualizer.getTotalSize()}px`}
height={`${rowVirtualizer.getTotalSize()}px`}
>
<TableHead
scrolled={style?.wrapper?.scrolled}
columnVirtualizer={columnVirtualizer}
Expand Down
20 changes: 16 additions & 4 deletions packages/table/src/core/Table/useTableVirtualization.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
import { useVirtualizer } from '@tanstack/react-virtual';
import { useRef } from 'react';
import { MutableRefObject, useRef } from 'react';
import { ColDef } from '../../declarations';

interface UseVirtualizationParams {
data: { [key: string]: unknown }[];
columnDefs: ColDef[];
}

const getEstimateColumnSize = (
colDefs: ColDef[],
colIndex: number,
tableRef: MutableRefObject<HTMLDivElement>,
) =>
colDefs[colIndex]?.cellStyle?.width ??
tableRef?.current?.offsetWidth / colDefs.length ??
300;

export const useTableVirtualization = ({
data,
columnDefs,
}: UseVirtualizationParams) => {
const ref = useRef();
const ref = useRef<HTMLDivElement>();
const rowVirtualizer = useVirtualizer({
count: data.length,
getScrollElement: () => ref.current,
estimateSize: () => 36,
estimateSize: () => 100,
overscan: 10,
});

const columnVirtualizer = useVirtualizer({
count: columnDefs.length,
getScrollElement: () => ref.current,
estimateSize: () => 300,
estimateSize: (index: number) =>
getEstimateColumnSize(columnDefs, index, ref),
horizontal: true,
getItemKey: (index: number) => columnDefs[index].id,
overscan: 2,
});

return { rowVirtualizer, columnVirtualizer, ref };
Expand Down
44 changes: 22 additions & 22 deletions packages/table/src/core/TableBody/TableBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from 'react';
import { Row } from '../Row';
import { ColDef } from '../../declarations';
import { StyledTableBody } from './StyledTableBody';
import { Virtualizer } from '@tanstack/react-virtual';
import { VirtualItem, Virtualizer } from '@tanstack/react-virtual';

interface TableBodyProps {
rowVirtualizer: Virtualizer<undefined, Element>;
columnVirtualizer: Virtualizer<undefined, Element>;
rowVirtualizer: Virtualizer<HTMLDivElement, Element>;
columnVirtualizer: Virtualizer<HTMLDivElement, Element>;
data: unknown;
columnDefs: ColDef[];
}
Expand All @@ -21,24 +21,24 @@ export const TableBody: React.FC<TableBodyProps> = ({
$height={`${rowVirtualizer.getTotalSize()}px`}
$width={`${columnVirtualizer.getTotalSize()}px`}
>
{rowVirtualizer.getVirtualItems().map((virtualRow, index) => {
return (
<Row
key={'tb_' + virtualRow.key}
columnDefs={columnDefs}
columnVirtualizer={columnVirtualizer}
data={data[virtualRow.index]}
even={(index + 1) % 2 === 0}
styles={{
height: `${virtualRow.size}px`,
transform: `translateY(${
virtualRow.start - index * virtualRow.size
}px)`,
width: '100%',
position: 'relative',
}}
/>
);
})}
{rowVirtualizer
.getVirtualItems()
.map((virtualRow: VirtualItem, index: number) => {
return (
<Row
key={'tb_' + virtualRow.key}
columnDefs={columnDefs}
columnVirtualizer={columnVirtualizer}
data={data[virtualRow.index]}
even={(index + 1) % 2 === 0}
styles={{
height: `${virtualRow.size}px`,
transform: `translateY(${virtualRow.start}px)`,
width: `${columnVirtualizer.getTotalSize()}px`,
position: 'absolute',
}}
/>
);
})}
</StyledTableBody>
);
8 changes: 5 additions & 3 deletions packages/table/src/core/TableHead/StyledTableHead.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import { elevationMixin } from '@devoinc/genesys-ui';

interface StyledTableHeadProps {
scrolled?: boolean;
isVirtual?: boolean;
width?: React.CSSProperties['width'];
}

export const StyledTableHead = styled.thead<StyledTableHeadProps>`
top: 0;
vertical-align: middle;
width: 100%;
display: inline-block;
position: sticky;
${({ scrolled = true, theme }) => {
return css`
Expand All @@ -26,4 +24,8 @@ export const StyledTableHead = styled.thead<StyledTableHeadProps>`
background-color: ${theme.cmp.table.head.color.background};
`;
}}
${({ width }) => css`
width: ${width};
`}
`;
11 changes: 10 additions & 1 deletion packages/table/src/core/TableHead/StyledTableHeadRow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import styled, { css } from 'styled-components';
interface StyledTableHeadRowProps {
scrolled?: boolean;
height?: React.CSSProperties['height'];
width?: React.CSSProperties['width'];
}

export const StyledTableHeadRow = styled.tr<StyledTableHeadRowProps>`
position: relative;
width: 100%;
display: flex;
display: block;
${({ scrolled, theme }) => {
const tokens = theme.cmp.table;
Expand All @@ -19,4 +20,12 @@ export const StyledTableHeadRow = styled.tr<StyledTableHeadRowProps>`
`solid ${cmpTokens.shape.borderSize.md} ${cmpTokens.color.background.after.base}`};
`;
}}
${({ width }) => css`
width: ${width};
`}
${({ height }) => css`
height: ${height};
`}
`;
Loading

0 comments on commit 8da3740

Please sign in to comment.