Skip to content

Commit

Permalink
feat: option to add row count on tables (#415)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fran McDade authored and Fran McDade committed Nov 22, 2024
1 parent 2296bc8 commit 96dcad9
Show file tree
Hide file tree
Showing 22 changed files with 283 additions and 66 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
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
13 changes: 13 additions & 0 deletions src/components/Table/common/columnDef.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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,
header: "",
id: ACCESSOR_KEYS.ROW_POSITION,
meta: { align: TABLE_CELL_PROPS.ALIGN.RIGHT, header: "" },
},
};
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,17 @@
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";
import { getRowPosition } from "./utils";

export const RowPositionCell = <TData extends RowData, TValue>({
className,
...cellContext
}: BaseComponentProps & CellContext<TData, TValue>): JSX.Element => {
return (
<Typography {...TYPOGRAPHY_PROPS} className={className} component="div">
{getRowPosition(cellContext)}
</Typography>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { CellContext, RowData } from "@tanstack/react-table";

/**
* Returns the index of the row in the table, for the current page.
* @param cellContext - Cell context.
* @returns row index.
*/
export function getRowIndex<TData extends RowData, TValue>(
cellContext: CellContext<TData, TValue>
): number {
const {
row,
table: { getRowModel },
} = cellContext;
const { rows } = getRowModel();
return rows.findIndex(({ id }) => id === row.id);
}

/**
* Returns the position of the row in the table.
* @param cellContext - Cell context.
* @returns row position.
*/
export const getRowPosition = <TData extends RowData, TValue>(
cellContext: CellContext<TData, TValue>
): number => {
const {
table: { getState },
} = cellContext;
const {
pagination: { pageIndex, pageSize },
} = getState();
const rowIndex = getRowIndex(cellContext);
return pageIndex * pageSize + (rowIndex + 1);
};
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
24 changes: 22 additions & 2 deletions src/components/Table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
PAGINATION_DIRECTION,
SORT_DIRECTION,
} from "../../common/analytics/entities";
import { ListViewConfig } from "../../config/entities";
import { ListConfig, ListViewConfig } from "../../config/entities";
import {
BREAKPOINT_FN_NAME,
useBreakpointHelper,
Expand Down Expand Up @@ -60,6 +60,7 @@ export interface TableProps<T extends RowData> {
items: T[];
listView?: ListViewConfig;
loading?: boolean;
tableOptions?: ListConfig<T>["tableOptions"];
}

/**
Expand All @@ -72,6 +73,7 @@ export interface TableProps<T extends RowData> {
* @param tableProps.initialState - Initial table state.
* @param tableProps.items - Row data to display.
* @param tableProps.listView - List view configuration.
* @param tableProps.tableOptions - TanStack table options.
* @returns Configured table element for display.
*/
export const TableComponent = <T extends RowData>({
Expand All @@ -80,6 +82,7 @@ export const TableComponent = <T extends RowData>({
initialState,
items,
listView,
tableOptions,
}: // eslint-disable-next-line sonarjs/cognitive-complexity -- TODO fix component length / complexity
TableProps<T>): JSX.Element => {
const tabletDown = useBreakpointHelper(BREAKPOINT_FN_NAME.DOWN, TABLET);
Expand Down Expand Up @@ -154,6 +157,22 @@ TableProps<T>): JSX.Element => {
rowSelection,
sorting,
};
/**
* TODO: Refactor `ListConfig` to follow the API patterns of the TanStack Table library.
* TODO: Update `ColumnConfig` to follow the `ColumnDef` API of TanStack Table.
* - Standardize column definitions to leverage the full power of TanStack Table's feature set and improve compatibility.
* TODO: Deprecate the following properties:
* - `defaultSort` in `ListConfig`: Replace this with TanStack Table's `tableOptions.initialState.sorting` feature.
* - `columnVisible` in `ColumnConfig`: Replace this with TanStack Table's `tableOptions.initialState.columnVisibility` feature.
* TODO: Define `columnVisibility` and `sorting` directly within `ListConfig` via the `tableOptions.initialState` property.
* - This will simplify the configuration structure and centralize table state definitions, reducing redundancy and improving clarity.
* - It will also allow for direct configuration of other TanStack Table options such as `columnOrder` via `tableOptions.initialState.columnOrder`.
*
* Current Workaround:
* - The `initialState` property from `tableOptions` is destructured to separate it from other options. This allows the remaining properties in `tableOptions` to be passed directly to the TanStack Table configuration without breaking the current ListConfig `defaultSort` and `columnVisible` properties.
*/
const { initialState: _initialState, ...restTableOptions } =
tableOptions ?? {};
const tableInstance = useReactTable({
_features: [ROW_PREVIEW],
columns,
Expand All @@ -174,7 +193,7 @@ TableProps<T>): JSX.Element => {
getPaginationRowModel: getPaginationRowModel(),
getRowId,
getSortedRowModel: clientFiltering ? getSortedRowModel() : undefined,
initialState,
initialState: { ...initialState, ..._initialState }, // Currently, `sorting` and `columnVisibility` are managed by the ExploreState.
manualPagination: true,
manualSorting: !clientFiltering,
onColumnVisibilityChange,
Expand All @@ -183,6 +202,7 @@ TableProps<T>): JSX.Element => {
onSortingChange,
pageCount,
state,
...restTableOptions,
});
const {
getAllColumns,
Expand Down
20 changes: 20 additions & 0 deletions src/components/TableCreator/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
import { RowData } from "@tanstack/react-table";
import { TABLE_CELL_PROPS } from "../../../styles/common/mui/tableCell";
import { RowPositionCell } from "../../Table/components/TableCell/components/RowPositionCell/rowPositionCell";
import { RowSelectionCell } from "../../Table/components/TableCell/components/RowSelectionCell/rowSelectionCell";
import { BaseColumnConfig } from "./entities";

export const ACCESSOR_KEYS = {
ROW_POSITION: "rowPosition",
SELECT: "select",
};

export const COLUMN_CONFIGS: Record<
string,
BaseColumnConfig<RowData, unknown>
> = {
ROW_POSITION: {
columnPinned: false,
columnVisible: true,
componentConfig: {
component: RowPositionCell,
viewBuilder: (_, viewContext) => viewContext?.cellContext,
},
disableHiding: true,
disableSorting: true,
header: "",
id: ACCESSOR_KEYS.ROW_POSITION,
meta: {
align: TABLE_CELL_PROPS.ALIGN.RIGHT,
header: "",
},
width: "max-content",
},
SELECT: {
columnPinned: false,
columnVisible: false,
Expand Down
9 changes: 8 additions & 1 deletion src/components/TableCreator/tableCreator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
RowData,
} from "@tanstack/react-table";
import React, { useMemo } from "react";
import { ColumnConfig, ListViewConfig } from "../../config/entities";
import {
ColumnConfig,
ListConfig,
ListViewConfig,
} from "../../config/entities";
import { PAPER_PANEL_STYLE } from "../common/Paper/paper";
import { ComponentCreator } from "../ComponentCreator/ComponentCreator";
import { Loading } from "../Loading/loading";
Expand All @@ -30,6 +34,7 @@ export interface TableCreatorProps<T> {
items: T[];
listView?: ListViewConfig;
loading?: boolean;
tableOptions?: ListConfig<T>["tableOptions"];
}

const createCell = <T extends RowData = RowData, TData = unknown>(
Expand Down Expand Up @@ -62,6 +67,7 @@ export const TableCreator = <T extends RowData>({
items,
listView,
loading,
tableOptions,
}: TableCreatorProps<T>): JSX.Element => {
const columnDefs: ColumnDef<T>[] = useMemo(
() =>
Expand Down Expand Up @@ -101,6 +107,7 @@ export const TableCreator = <T extends RowData>({
items={items}
listView={listView}
loading={loading}
tableOptions={tableOptions}
/>
</TableCreatorContainer>
);
Expand Down
Loading

0 comments on commit 96dcad9

Please sign in to comment.