Skip to content

Commit

Permalink
feat!: option to add row count on tables (#284) (#285)
Browse files Browse the repository at this point in the history
* feat: option to add row count on tables (#284)

* feat!: option to add row count on tables (#284)

* feat: removed row position from column configs (#284)

---------

Co-authored-by: Fran McDade <[email protected]>
  • Loading branch information
frano-m and Fran McDade authored Nov 25, 2024
1 parent 798312f commit 1643efb
Show file tree
Hide file tree
Showing 28 changed files with 381 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { TableCell as MTableCell } from "@mui/material";
import { TableCell } from "@mui/material";
import { flexRender, Row, RowData, Table } from "@tanstack/react-table";
import React, { Fragment } from "react";
import { getTableCellPadding } from "../../../../../Table/components/TableCell/common/utils";
import {
getTableCellAlign,
getTableCellPadding,
} from "../../../../../Table/components/TableCell/common/utils";
import { TableRow } from "../../../../../Table/components/TableRow/tableRow.styles";
import { TableView } from "../../table";

Expand Down Expand Up @@ -31,13 +34,14 @@ export const TableRows = <T extends RowData>({
if (cell.getIsAggregated()) return null; // Display of aggregated cells is currently not supported.
if (cell.getIsPlaceholder()) return null; // Display of placeholder cells is currently not supported.
return (
<MTableCell
<TableCell
key={cell.id}
align={getTableCellAlign(cell.column)}
padding={getTableCellPadding(cell.column.id)}
size={tableCellSize}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</MTableCell>
</TableCell>
);
})}
</TableRow>
Expand Down
9 changes: 7 additions & 2 deletions src/components/Detail/components/Table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import {
useBreakpointHelper,
} from "../../../../hooks/useBreakpointHelper";
import { TABLET } from "../../../../theme/common/breakpoints";
import { COLUMN_DEF } from "../../../Table/common/columnDef";
import { ROW_DIRECTION } from "../../../Table/common/entities";
import { TableHead } from "../../../Table/components/TableHead/tableHead";
import { ROW_POSITION } from "../../../Table/features/RowPosition/constants";
import { ROW_PREVIEW } from "../../../Table/features/RowPreview/constants";
import { GridTable } from "../../../Table/table.styles";
import { generateColumnDefinitions } from "./common/utils";
Expand Down Expand Up @@ -56,8 +58,11 @@ export const Table = <T extends RowData>({
const { stickyHeader = false } = table || {};
const { sx: tableContainerSx } = tableContainer || {};
const tableInstance = useReactTable({
_features: [ROW_PREVIEW],
columns: generateColumnDefinitions(columns),
_features: [ROW_POSITION, ROW_PREVIEW],
columns: generateColumnDefinitions([
COLUMN_DEF.ROW_POSITION as ColumnDef<T>,
...columns,
]),
data: items,
enableSorting: false,
getCoreRowModel: getCoreRowModel(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import { css } from "@emotion/react";
import styled from "@emotion/styled";
import { FormControl as MFormControl } from "@mui/material";
import { mediaTabletUp } from "../../../../styles/common/mixins/breakpoints";
import {
inkMain,
smokeLightest,
smokeMain,
} from "../../../../styles/common/mixins/colors";
import { inkMain, smokeMain } from "../../../../styles/common/mixins/colors";
import { textBodyLarge500 } from "../../../../styles/common/mixins/fonts";
import { ThemeProps } from "../../../../theme/theme";
import {
Expand Down Expand Up @@ -75,8 +71,6 @@ export const TableFormControl = styled(FormControl)`
.MuiTable-root {
th {
background-color: ${smokeLightest};
.MuiFormControlLabel-label {
font: inherit;
}
Expand Down
19 changes: 19 additions & 0 deletions src/components/Table/common/columnDef.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ColumnDef, RowData } from "@tanstack/react-table";
import { TABLE_CELL_PROPS } from "../../../styles/common/mui/tableCell";
import { ACCESSOR_KEYS } from "../../TableCreator/common/constants";
import { RowPositionCell } from "../components/TableCell/components/RowPositionCell/rowPositionCell";

export const COLUMN_DEF: Record<string, ColumnDef<RowData>> = {
ROW_POSITION: {
cell: RowPositionCell,
enableHiding: false,
enableSorting: false,
header: "",
id: ACCESSOR_KEYS.ROW_POSITION,
meta: {
align: TABLE_CELL_PROPS.ALIGN.RIGHT,
header: "",
width: "max-content",
},
},
};
3 changes: 1 addition & 2 deletions src/components/Table/common/gridTable.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ export const GridTable = styled(MTable, {
background-color: ${white};
}
td,
th {
td {
background-color: inherit;
}
Expand Down
27 changes: 22 additions & 5 deletions src/components/Table/components/TableCell/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import { TableCellProps as MTableCellProps } from "@mui/material";
import { CoreCell, CoreHeader, RowData } from "@tanstack/react-table";
import { TableCellProps } from "@mui/material";
import { Column, CoreCell, CoreHeader, RowData } from "@tanstack/react-table";
import { TABLE_CELL_PROPS } from "../../../../../styles/common/mui/tableCell";
import { ACCESSOR_KEYS } from "../../../../TableCreator/common/constants";

/**
* Returns table cell alignment based on the cell.
* @param column - Column.
* @returns table cell alignment.
*/
export function getTableCellAlign<T extends RowData, TValue>(
column: Column<T, TValue>
): TableCellProps["align"] {
return column.columnDef.meta?.align;
}

/**
* Returns table cell padding based on the cell ID.
* @param id - Cell ID.
* @returns table cell padding.
*/
export function getTableCellPadding<T extends RowData, TValue>(
id: CoreHeader<T, TValue>["id"] | CoreCell<T, TValue>["id"]
): MTableCellProps["padding"] {
if (id === ACCESSOR_KEYS.SELECT) {
return "checkbox";
): TableCellProps["padding"] {
switch (id) {
case ACCESSOR_KEYS.ROW_POSITION:
return TABLE_CELL_PROPS.PADDING.NORMAL;
case ACCESSOR_KEYS.SELECT:
return TABLE_CELL_PROPS.PADDING.CHECKBOX;
default:
return TABLE_CELL_PROPS.PADDING.NORMAL;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { TypographyOwnProps } from "@mui/material";
import { VARIANT } from "../../../../../../styles/common/mui/typography";

export const TYPOGRAPHY_PROPS: Partial<TypographyOwnProps> = {
sx: { marginRight: -2, paddingLeft: 2 },
variant: VARIANT.INHERIT,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Typography } from "@mui/material";
import { CellContext, RowData } from "@tanstack/react-table";
import React from "react";
import { BaseComponentProps } from "../../../../../types";
import { TYPOGRAPHY_PROPS } from "./constants";

export const RowPositionCell = <TData extends RowData, TValue>({
className,
...cellContext
}: BaseComponentProps & CellContext<TData, TValue>): JSX.Element => {
return (
<Typography {...TYPOGRAPHY_PROPS} className={className} component="div">
{cellContext.row.getRowPosition()}
</Typography>
);
};
12 changes: 8 additions & 4 deletions src/components/Table/components/TableHead/tableHead.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import {
TableCell as MTableCell,
TableHead as MTableHead,
TableRow as MTableRow,
TableCell,
TableSortLabel,
} from "@mui/material";
import { flexRender, RowData, Table } from "@tanstack/react-table";
import React, { Fragment } from "react";
import { ROW_DIRECTION } from "../../common/entities";
import { getTableSortLabelProps } from "../../common/utils";
import { getTableCellPadding } from "../TableCell/common/utils";
import {
getTableCellAlign,
getTableCellPadding,
} from "../TableCell/common/utils";

export interface TableHeadProps<T extends RowData> {
rowDirection: ROW_DIRECTION;
Expand All @@ -34,8 +37,9 @@ export const TableHead = <T extends RowData>({
},
} = header;
return header.column.getIsGrouped() ? null : (
<MTableCell
<TableCell
key={header.id}
align={getTableCellAlign(header.column)}
padding={getTableCellPadding(header.id)}
>
{header.column.getCanSort() && enableSortingInteraction ? (
Expand All @@ -53,7 +57,7 @@ export const TableHead = <T extends RowData>({
header.getContext()
)
)}
</MTableCell>
</TableCell>
);
})}
</MTableRow>
Expand Down
12 changes: 8 additions & 4 deletions src/components/Table/components/TableRows/tableRows.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { TableCell as MTableCell } from "@mui/material";
import { TableCell } from "@mui/material";
import { flexRender, Row, RowData, Table } from "@tanstack/react-table";
import { Virtualizer } from "@tanstack/react-virtual";
import React, { Fragment } from "react";
import { getTableCellPadding } from "../TableCell/common/utils";
import {
getTableCellAlign,
getTableCellPadding,
} from "../TableCell/common/utils";
import { TableRow } from "../TableRow/tableRow.styles";

export interface TableRowsProps<T extends RowData> {
Expand Down Expand Up @@ -30,12 +33,13 @@ export const TableRows = <T extends RowData>({
ref={virtualizer.measureElement}
>
{row.getVisibleCells().map((cell) => (
<MTableCell
<TableCell
key={cell.id}
align={getTableCellAlign(cell.column)}
padding={getTableCellPadding(cell.column.id)}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</MTableCell>
</TableCell>
))}
</TableRow>
);
Expand Down
34 changes: 34 additions & 0 deletions src/components/Table/features/RowPosition/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
Cell,
Column,
Row,
RowData,
RowModel,
Table,
TableFeature,
TableState,
} from "@tanstack/react-table";
import { InitialTableState } from "@tanstack/table-core/src/types";
import { getRowModel, getRowPosition, initInitialState } from "./utils";

export const ROW_POSITION: TableFeature = {
createCell: <T extends RowData, TValue>(
cell: Cell<T, TValue>,
column: Column<T>,
row: Row<T>,
table: Table<T>
): void => {
row.getRowPosition = (): number => {
return getRowPosition(row.id, table);
};
},
createTable: <T extends RowData>(table: Table<T>): void => {
const originalGetRowModel = table.getRowModel.bind(table);
table.getRowModel = (): RowModel<T> => {
return getRowModel(table, originalGetRowModel);
};
},
getInitialState: (initialState?: InitialTableState): Partial<TableState> => {
return initInitialState(initialState);
},
};
3 changes: 3 additions & 0 deletions src/components/Table/features/RowPosition/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface RowPositionRow {
getRowPosition: () => number;
}
80 changes: 80 additions & 0 deletions src/components/Table/features/RowPosition/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
InitialTableState,
RowData,
RowModel,
Table,
TableState,
} from "@tanstack/react-table";
import { ACCESSOR_KEYS } from "../../../TableCreator/common/constants";
import { DEFAULT_PAGINATION } from "../constants";

/**
* Returns row model, with getter for row position.
* @param table - Table.
* @param getRowModel - Table getRowModel function.
* @returns row model.
*/
export function getRowModel<T extends RowData>(
table: Table<T>,
getRowModel: Table<T>[`getRowModel`]
): RowModel<T> {
const rowModel = getRowModel();
rowModel.rows.forEach(({ id }, i) => {
rowModel.rowsById[id].getRowPosition = (): number =>
calculateRowPosition(table, i);
});
return rowModel;
}

/**
* Returns the position of the row in the table.
* @param rowId - Row ID.
* @param table - Table.
* @returns row position.
*/
export function getRowPosition<T extends RowData>(
rowId: string,
table: Table<T>
): number {
const { getRowModel } = table;
const { rowsById } = getRowModel();
return rowsById[rowId].getRowPosition();
}

/**
* Calculates the position of the row in the table.
* @param table - Table.
* @param index - Row index.
* @returns row position.
*/
function calculateRowPosition<T extends RowData>(
table: Table<T>,
index: number
): number {
const { getState } = table;
const {
pagination: { pageIndex, pageSize },
} = getState();
return pageIndex * pageSize + (index + 1);
}

/**
* Returns the initial table state.
* @param initialState - Initial state.
* @returns initial state.
*/
export function initInitialState(
initialState?: InitialTableState
): Partial<TableState> {
return {
...initialState,
columnVisibility: {
[ACCESSOR_KEYS.ROW_POSITION]: false,
...initialState?.columnVisibility,
},
pagination: {
...DEFAULT_PAGINATION,
...initialState?.pagination,
},
};
}
10 changes: 10 additions & 0 deletions src/components/Table/features/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { PaginationState } from "@tanstack/react-table";

/**
* Default TanStack pagination state.
* See https://tanstack.com/table/latest/docs/guide/custom-features#getinitialstate.
*/
export const DEFAULT_PAGINATION: PaginationState = {
pageIndex: 0,
pageSize: 10,
};
3 changes: 2 additions & 1 deletion src/components/Table/features/entities.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { RowData } from "@tanstack/react-table";
import { RowPositionRow } from "./RowPosition/types";
import {
RowPreviewInstance,
RowPreviewOptions,
Expand All @@ -9,5 +10,5 @@ import {
export type CustomFeatureInitialTableState = Partial<RowPreviewTableState>;
export type CustomFeatureInstance<T extends RowData> = RowPreviewInstance<T>;
export type CustomFeatureOptions = RowPreviewOptions;
export type CustomFeatureRow = RowPreviewRow;
export type CustomFeatureRow = RowPositionRow & RowPreviewRow;
export type CustomFeatureTableState = RowPreviewTableState;
Loading

0 comments on commit 1643efb

Please sign in to comment.