Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generics to DataView #2420

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ import { MRT_RowData } from "material-react-table";
* @param newIndex - The new index to move the row to.
* @returns A new array of data with the row moved to the specified index.
*/
export const reorderDataRowsLocally = ({
export const reorderDataRowsLocally = <TData extends MRT_RowData>({
currentData,
rowId,
newRowIndex,
}: {
currentData: MRT_RowData[];
currentData: TData[];
rowId: string;
newRowIndex: number;
}): MRT_RowData[] => {
}): TData[] => {
const updatedData = [...currentData];
const rowIndex = updatedData.findIndex((row) => row.id === rowId);

Expand Down
39 changes: 16 additions & 23 deletions packages/odyssey-react-mui/src/DataTable/useRowReordering.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { reorderDataRowsLocally } from "./reorderDataRowsLocally";
import { useOdysseyDesignTokens } from "../OdysseyDesignTokensContext";
import { MRT_Row, MRT_RowData, MRT_TableInstance } from "material-react-table";

export const useRowReordering = ({
export const useRowReordering = <TData extends MRT_RowData>({
totalRows,
onReorderRows,
data,
Expand All @@ -28,12 +28,10 @@ export const useRowReordering = ({
}: {
totalRows: DataTableProps["totalRows"];
onReorderRows: DataTableProps["onReorderRows"];
data: MRT_RowData[];
setData: Dispatch<SetStateAction<MRT_RowData[]>>;
draggingRow?: MRT_Row<MRT_RowData> | null;
setDraggingRow: Dispatch<
SetStateAction<MRT_Row<MRT_RowData> | null | undefined>
>;
data: TData[];
setData: Dispatch<SetStateAction<TData[]>>;
draggingRow?: MRT_Row<TData> | null;
setDraggingRow: Dispatch<SetStateAction<MRT_Row<TData> | null | undefined>>;
resultsPerPage: number;
page: number;
}) => {
Expand Down Expand Up @@ -68,7 +66,6 @@ export const useRowReordering = ({
const dragHandleStyles = {
padding: odysseyDesignTokens.Spacing1,
borderRadius: odysseyDesignTokens.BorderRadiusMain,

"&:focus-visible": {
boxShadow: `0 0 0 2px ${odysseyDesignTokens.HueNeutralWhite}, 0 0 0 4px ${odysseyDesignTokens.PalettePrimaryMain}`,
outline: "2px solid transparent",
Expand Down Expand Up @@ -106,12 +103,12 @@ export const useRowReordering = ({
return undefined;
};

const setHoveredRow = (
table: MRT_TableInstance<MRT_RowData>,
id: MRT_RowData["id"],
) => {
const setHoveredRow = (table: MRT_TableInstance<TData>, id: TData["id"]) => {
if (id) {
const nextRow: MRT_RowData = table.getRow(id);
// The `as MRT_Row<TData>` is necessary here to overcome some type/generic
// issues with the type of `setHoveredRow` defined by MRT. It's not ideal code,
// but it's the only way that works without a much larger rewrite.
const nextRow = table.getRow(id) as MRT_Row<TData>;

if (nextRow) {
table.setHoveredRow(nextRow);
Expand All @@ -120,8 +117,8 @@ export const useRowReordering = ({
};

type HandleDragHandleKeyDownArgs = {
table: MRT_TableInstance<MRT_RowData>;
row: MRT_Row<MRT_RowData>;
table: MRT_TableInstance<TData>;
row: MRT_Row<TData>;
event: KeyboardEvent<HTMLButtonElement>;
};

Expand Down Expand Up @@ -192,32 +189,28 @@ export const useRowReordering = ({
}
};

const handleDragHandleOnDragEnd = (table: MRT_TableInstance<MRT_RowData>) => {
const handleDragHandleOnDragEnd = (table: MRT_TableInstance<TData>) => {
const cols = table.getAllColumns();
cols[0].toggleVisibility();

const { draggingRow, hoveredRow } = table.getState();
if (draggingRow) {
updateRowOrder({
rowId: draggingRow.id,
newRowIndex: (hoveredRow as MRT_RowData).index,
newRowIndex: (hoveredRow as TData).index,
});
}

setDraggingRow(null);
};

const handleDragHandleOnDragCapture = (
table: MRT_TableInstance<MRT_RowData>,
) => {
const handleDragHandleOnDragCapture = (table: MRT_TableInstance<TData>) => {
if (!draggingRow && table.getState().draggingRow?.id) {
setDraggingRow(table.getState().draggingRow);
}
};

const resetDraggingAndHoveredRow = (
table: MRT_TableInstance<MRT_RowData>,
) => {
const resetDraggingAndHoveredRow = (table: MRT_TableInstance<TData>) => {
setDraggingRow(null);
table.setHoveredRow(null);
};
Expand Down
59 changes: 30 additions & 29 deletions packages/odyssey-react-mui/src/labs/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export type {

// The shape of the table columns,
// with props named to match their MRT_ColumnDef counterparts
export type DataTableColumn = {
export type DataTableColumn<TData extends MRT_RowData> = {
/**
* The unique ID of the column
*/
Expand All @@ -82,12 +82,12 @@ export type DataTableColumn = {
* Customize the way each cell in the column is
* displayed via a custom React component.
*/
Cell?: MRT_ColumnDef<MRT_RowData>["Cell"];
Cell?: MRT_ColumnDef<TData>["Cell"];
/**
* The UI control that will be used to filter the column.
* Defaults to a standard text input.
*/
filterVariant?: MRT_ColumnDef<MRT_RowData>["filterVariant"];
filterVariant?: MRT_ColumnDef<TData>["filterVariant"];
/**
* If the filter control has preset options (such as a select or multi-select),
* these are the options provided.
Expand Down Expand Up @@ -127,16 +127,16 @@ export type DataTableColumn = {
enableHiding?: boolean;
};

export type DataTableProps = {
export type DataTableProps<TData extends MRT_RowData> = {
/**
* The columns that make up the table
*/
columns: DataTableColumn[];
columns: DataTableColumn<TData>[];
/**
* The data that goes into the table, which will be displayed
* as the table rows
*/
data: MRT_TableOptions<MRT_RowData>["data"];
data: MRT_TableOptions<TData>["data"];
/**
* The total number of rows in the table. Optional, because it's sometimes impossible
* to calculate. Used in table pagination to know when to disable the "next"/"more" button.
Expand All @@ -145,7 +145,7 @@ export type DataTableProps = {
/**
* The function to get the ID of a row
*/
getRowId?: MRT_TableOptions<MRT_RowData>["getRowId"];
getRowId?: MRT_TableOptions<TData>["getRowId"];
/**
* The initial density of the table. This is available even if the table density
* isn't changeable.
Expand Down Expand Up @@ -219,7 +219,7 @@ export type DataTableProps = {
search?: string;
filters?: DataFilter[];
sort?: MRT_SortingState;
}) => MRT_TableOptions<MRT_RowData>["data"];
}) => MRT_TableOptions<TData>["data"];
/**
* Callback that fires when the user reorders rows within the table. Can be used
* to propogate order change to the backend.
Expand Down Expand Up @@ -248,24 +248,24 @@ export type DataTableProps = {
* Action buttons to display in each row
*/
rowActionButtons?: (
row: MRT_RowData,
row: TData,
) => ReactElement<typeof Button | typeof Fragment>;
/**
* Menu items to include in the optional actions menu on each row.
*/
rowActionMenuItems?: (
row: MRT_RowData,
row: TData,
) => ReactElement<typeof MenuItem | typeof Fragment>;
};

type TableType = MRT_TableInstance<MRT_RowData>;
type TableType<TData extends MRT_RowData> = MRT_TableInstance<TData>;

const reorderDataRowsLocally = ({
const reorderDataRowsLocally = <TData extends MRT_RowData>({
currentData,
rowId,
newIndex,
}: {
currentData: MRT_TableOptions<MRT_RowData>["data"];
currentData: MRT_TableOptions<TData>["data"];
rowId: string;
newIndex: number;
}) => {
Expand All @@ -284,7 +284,7 @@ const reorderDataRowsLocally = ({
return updatedData;
};

const DataTable = ({
const DataTable = <TData extends MRT_RowData>({
columns,
data: dataProp,
getRowId,
Expand All @@ -309,13 +309,12 @@ const DataTable = ({
hasRowSelection,
hasSearch,
hasSorting,
}: DataTableProps) => {
}: DataTableProps<TData>) => {
const odysseyDesignTokens = useOdysseyDesignTokens();
const { t } = useTranslation();
const [draggingRow, setDraggingRow] = useState<MRT_Row<MRT_RowData> | null>();
const [draggingRow, setDraggingRow] = useState<MRT_Row<TData> | null>();
const [showSkeletons, setShowSkeletons] = useState<boolean>(true);
const [data, setData] =
useState<MRT_TableOptions<MRT_RowData>["data"]>(dataProp);
const [data, setData] = useState<MRT_TableOptions<TData>["data"]>(dataProp);
const [page, setPage] = useState<number>(pageProp);
const [resultsPerPage, setResultsPerPage] =
useState<number>(resultsPerPageProp);
Expand Down Expand Up @@ -428,24 +427,24 @@ const DataTable = ({
const rowVirtualizerInstanceRef =
useRef<MRT_RowVirtualizer<HTMLDivElement, HTMLTableRowElement>>(null);

const setHoveredRow = (table: TableType, id: MRT_RowData["id"]) => {
const setHoveredRow = (table: TableType<TData>, id: TData["id"]) => {
if (id) {
const nextRow: MRT_RowData = table.getRow(id);
const nextRow = table.getRow(id) as MRT_Row<TData>;

if (nextRow) {
table.setHoveredRow(nextRow);
}
}
};

const resetDraggingAndHoveredRow = (table: TableType) => {
const resetDraggingAndHoveredRow = (table: TableType<TData>) => {
setDraggingRow(null);
table.setHoveredRow(null);
};

type HandleDragHandleKeyDownArgs = {
table: TableType;
row: MRT_Row<MRT_RowData>;
table: TableType<TData>;
row: MRT_Row<TData>;
event: KeyboardEvent<HTMLButtonElement>;
};

Expand Down Expand Up @@ -515,23 +514,25 @@ const DataTable = ({
[
data,
draggingRow,
odysseyDesignTokens,
odysseyDesignTokens.TransitionDurationMainAsNumber,
page,
resetDraggingAndHoveredRow,
resultsPerPage,
setHoveredRow,
updateRowOrder,
],
);

const handleDragHandleOnDragEnd = useCallback(
(table: TableType) => {
(table: TableType<TData>) => {
const cols = table.getAllColumns();
cols[0].toggleVisibility();

const { draggingRow, hoveredRow } = table.getState();
if (draggingRow) {
updateRowOrder({
rowId: draggingRow.id,
newIndex: (hoveredRow as MRT_RowData).index,
newIndex: (hoveredRow as TData).index,
});
}

Expand All @@ -541,7 +542,7 @@ const DataTable = ({
);

const handleDragHandleOnDragCapture = useCallback(
(table: TableType) => {
(table: TableType<TData>) => {
if (!draggingRow && table.getState().draggingRow?.id) {
setDraggingRow(table.getState().draggingRow);
}
Expand Down Expand Up @@ -683,7 +684,7 @@ const DataTable = ({

return (
<Box sx={{ display: "flex" }}>
{rowActionButtons?.(row)}
{rowActionButtons?.(row.original)}
{(rowActionMenuItems || hasRowReordering) && (
<MenuButton
endIcon={<MoreIcon />}
Expand All @@ -694,7 +695,7 @@ const DataTable = ({
>
{rowActionMenuItems && (
<>
{rowActionMenuItems(row)}
{rowActionMenuItems(row.original)}
<hr />
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import {
useOdysseyDesignTokens,
} from "../../OdysseyDesignTokensContext";

export type BulkActionsMenuProps = {
export type BulkActionsMenuProps<TData extends MRT_RowData> = {
data: MRT_RowData[];
menuItems: UniversalProps["bulkActionMenuItems"];
menuItems: UniversalProps<TData>["bulkActionMenuItems"];
rowSelection: MRT_RowSelectionState;
setRowSelection: Dispatch<SetStateAction<MRT_RowSelectionState>>;
};
Expand All @@ -41,12 +41,12 @@ const BulkActionsContainer = styled("div", {
gap: odysseyDesignTokens.Spacing2,
}));

const BulkActionsMenu = ({
const BulkActionsMenu = <TData extends MRT_RowData>({
data,
menuItems,
rowSelection,
setRowSelection,
}: BulkActionsMenuProps) => {
}: BulkActionsMenuProps<TData>) => {
const odysseyDesignTokens = useOdysseyDesignTokens();
const { t } = useTranslation();

Expand Down
Loading