Skip to content

Commit

Permalink
Merge branch 'main' into jk-datatable-last-column
Browse files Browse the repository at this point in the history
  • Loading branch information
jordankoschei-okta authored Aug 7, 2024
2 parents ce4e406 + c42ca4a commit f56a856
Show file tree
Hide file tree
Showing 12 changed files with 505 additions and 259 deletions.
133 changes: 75 additions & 58 deletions packages/odyssey-react-mui/src/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import {
import { useScrollIndication } from "./useScrollIndication";
import styled from "@emotion/styled";
import { EmptyState } from "../EmptyState";
import { Button } from "../Button";
import { Callout } from "../Callout";

export type DataTableColumn<T extends DataTableRowData> = MRT_ColumnDef<T> & {
Expand Down Expand Up @@ -255,62 +256,6 @@ export type DataTableProps = {
maxPages?: number;
};

const displayColumnDefOptions = {
"mrt-row-actions": {
header: "",
grow: true,
muiTableBodyCellProps: {
align: "right",
sx: {
overflow: "visible",
width: "unset",
},
className: "ods-actions-cell",
},
muiTableHeadCellProps: {
align: "right",
sx: {
width: "unset",
},
className: "ods-actions-cell",
},
},
"mrt-row-drag": {
header: "",
muiTableBodyCellProps: {
sx: {
minWidth: 0,
width: "auto",
},
className: "ods-drag-handle",
},
muiTableHeadCellProps: {
sx: {
minWidth: 0,
width: "auto",
},
children: (
// Add a spacer to simulate the width of the drag handle in the column.
// Without this, the head cells are offset from their body cell counterparts
<Box sx={{ marginInline: "-0.1rem" }}>
<DragIndicatorIcon sx={{ marginInline: 1, opacity: 0 }} />
</Box>
),
},
},
"mrt-row-select": {
muiTableHeadCellProps: {
padding: "checkbox",
},
muiTableBodyCellProps: {
padding: "checkbox",
},
},
"mrt-row-expand": {
header: "",
},
};

const ScrollableTableContainer = styled("div", {
shouldForwardProp: (prop) =>
prop !== "odysseyDesignTokens" &&
Expand Down Expand Up @@ -687,14 +632,86 @@ const DataTable = ({
},
},
selectAllMode: "all",
displayColumnDefOptions:
displayColumnDefOptions as MRT_TableOptions<DataTableRowData>["displayColumnDefOptions"],
displayColumnDefOptions: {
"mrt-row-actions": {
header: "",
grow: true,
muiTableBodyCellProps: {
align: "right",
sx: {
overflow: "visible",
width: "unset",
},
className: "ods-actions-cell",
},
muiTableHeadCellProps: {
align: "right",
sx: {
width: "unset",
},
className: "ods-actions-cell",
children: (
<Box sx={{ display: "flex", visibility: "hidden" }}>
{rowActionButtons && rowActionButtons({ id: null })}
{((hasRowReordering && onReorderRows) || rowActionMenuItems) && (
<Box>
<Button
endIcon={<MoreIcon />}
size="small"
variant="floating"
ariaLabel={t("table.moreactions.arialabel")}
isDisabled
/>
</Box>
)}
</Box>
),
},
},
"mrt-row-drag": {
header: "",
muiTableBodyCellProps: {
sx: {
minWidth: 0,
width: "auto",
},
className: "ods-drag-handle",
},
muiTableHeadCellProps: {
sx: {
minWidth: 0,
width: "auto",
},
children: (
// Add a spacer to simulate the width of the drag handle in the column.
// Without this, the head cells are offset from their body cell counterparts
<Box sx={{ marginInline: "-0.1rem" }}>
<DragIndicatorIcon sx={{ marginInline: 1, opacity: 0 }} />
</Box>
),
},
},
"mrt-row-select": {
muiTableHeadCellProps: {
padding: "checkbox",
},
muiTableBodyCellProps: {
padding: "checkbox",
},
},
"mrt-row-expand": {
header: "",
},
},
muiTableBodyProps: () => ({
className: rowDensityClassName,
}),
defaultColumn: {
Cell: defaultCell,
},
muiTableBodyCellProps: ({ column }) => ({
className: column.getIsResizing() ? "isResizing" : "",
}),

// Reordering
enableRowOrdering: hasRowReordering && Boolean(onReorderRows),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
DragIndicatorIcon,
} from "../../icons.generated";
import { Box } from "../../Box";
import { Button } from "../../Button";
import { TableProps, TableState, UniversalProps } from "./componentTypes";
import { DataTableCell } from "./dataTypes";
import {
Expand Down Expand Up @@ -299,9 +300,48 @@ const TableContent = ({
ExpandMoreIcon: ChevronDownIcon,
},
...dataTableImmutableSettings,
displayColumnDefOptions: displayColumnDefOptions satisfies Partial<
MRT_TableOptions<MRT_RowData>["displayColumnDefOptions"]
>,
displayColumnDefOptions: {
...(displayColumnDefOptions satisfies Partial<
MRT_TableOptions<MRT_RowData>["displayColumnDefOptions"]
>),
"mrt-row-actions": {
header: "",
grow: true,
muiTableBodyCellProps: {
align: "right" as const,
sx: {
overflow: "visible",
width: "unset",
},
className: "ods-actions-cell",
},
muiTableHeadCellProps: {
align: "right" as const,
sx: {
width: "unset",
},
className: "ods-actions-cell",
children: (
<Box sx={{ display: "flex", visibility: "hidden" }}>
{tableOptions.rowActionButtons &&
tableOptions.rowActionButtons({ id: null })}
{((hasRowReordering === true && onReorderRows) ||
tableOptions.rowActionMenuItems) && (
<Box>
<Button
endIcon={<MoreIcon />}
size="small"
variant="floating"
ariaLabel={t("table.moreactions.arialabel")}
isDisabled
/>
</Box>
)}
</Box>
),
},
},
},
muiTableProps: {
ref: tableContentRef,
className:
Expand Down Expand Up @@ -364,6 +404,9 @@ const TableContent = ({
? "isSorted"
: "isUnsorted",
}),
muiTableBodyCellProps: ({ column }) => ({
className: column.getIsResizing() ? "isResizing" : "",
}),
enableSorting: tableOptions.hasSorting === true, // I don't know why this needs to be true, but it still works if undefined otherwise
onSortingChange: (sortingUpdater) => {
const newSortVal =
Expand Down
120 changes: 60 additions & 60 deletions packages/odyssey-react-mui/src/labs/DataComponents/TableSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import { Dispatch, SetStateAction, memo, useCallback, useMemo } from "react";
import { Checkbox as MuiCheckbox } from "@mui/material";
import { MRT_DensityState } from "material-react-table";
import { useTranslation } from "react-i18next";

import { densityValues } from "./constants";
Expand All @@ -36,25 +37,18 @@ const TableSettings = ({
const { hasChangeableDensity, hasColumnVisibility, columns } = tableOptions;
const { rowDensity, columnVisibility } = tableState;

const changeRowDensity = useCallback(
(value: (typeof densityValues)[number]) =>
(_event: React.MouseEvent<HTMLLIElement>) => {
// This is necessary to avoid linter errors, while the _event is necessary to satisfy the onClick type
if (process.env.NODE_ENV === "development") console.debug(_event);

setTableState((prevState) => ({
...prevState,
rowDensity: value,
}));
},
const changeRowDensity = useCallback<(value: MRT_DensityState) => void>(
(value) => {
setTableState((prevState) => ({
...prevState,
rowDensity: value,
}));
},
[setTableState],
);

const changeColumnVisibility = useCallback(
(columnId: string) => (_event: React.MouseEvent<HTMLLIElement>) => {
// This is necessary to avoid linter errors, while the _event is necessary to satisfy the onClick type
if (process.env.NODE_ENV === "development") console.debug(_event);

const changeColumnVisibility = useCallback<(columnId: string) => void>(
(columnId) => {
setTableState((prevState) => ({
...prevState,
columnVisibility: {
Expand All @@ -68,66 +62,72 @@ const TableSettings = ({
[setTableState],
);

const isColumnVisibilityChecked = useMemo(() => {
return columns.reduce(
(acc, column) => {
const isChecked = columnVisibility
? columnVisibility[column.accessorKey!] !== false
: true;
acc[column.accessorKey!] = isChecked;
return acc;
},
{} as Record<string, boolean>,
);
}, [columns, columnVisibility]);
const visibleColumns = useMemo(
() =>
new Set(
columns
.filter((column) =>
columnVisibility
? columnVisibility[column.accessorKey!] !== false
: true,
)
.map((column) => column.accessorKey!),
),
[columns, columnVisibility],
);

return (
<>
{hasChangeableDensity && (
const memoizedDensityMenu = useMemo(
() =>
hasChangeableDensity && (
<MenuButton
ariaLabel={t("table.density.arialabel")}
endIcon={<ListIcon />}
menuAlignment="right"
shouldCloseOnSelect={false}
>
<>
{densityValues.map((value: (typeof densityValues)[number]) => (
<MenuItem
key={value}
isSelected={rowDensity === value}
onClick={changeRowDensity(value)}
>
{`${value.charAt(0).toUpperCase()}${value.slice(1)}`}
</MenuItem>
))}
</>
{densityValues.map((value) => (
<MenuItem
key={value}
isSelected={rowDensity === value}
onClick={() => changeRowDensity(value)}
>
{`${value.charAt(0).toUpperCase()}${value.slice(1)}`}
</MenuItem>
))}
</MenuButton>
)}
),
[hasChangeableDensity, t, rowDensity, changeRowDensity],
);

{hasColumnVisibility && (
const memoizedColumnVisibilityMenu = useMemo(
() =>
hasColumnVisibility && (
<MenuButton
ariaLabel={t("table.columnvisibility.arialabel")}
endIcon={<ShowIcon />}
menuAlignment="right"
shouldCloseOnSelect={false}
>
<>
{columns
.filter((column) => column.enableHiding !== false)
.map((column) => (
<MenuItem
key={column.accessorKey}
onClick={changeColumnVisibility(column.id as string)}
>
<MuiCheckbox
checked={isColumnVisibilityChecked[column.accessorKey!]}
/>
{column.header}
</MenuItem>
))}
</>
{columns
.filter((column) => Boolean(column.enableHiding !== false))
.map((column) => (
<MenuItem
key={column.accessorKey}
onClick={() => changeColumnVisibility(column.id!)}
>
<MuiCheckbox checked={visibleColumns.has(column.id!)} />
{column.header}
</MenuItem>
))}
</MenuButton>
)}
),
[hasColumnVisibility, t, columns, changeColumnVisibility, visibleColumns],
);

return (
<>
{memoizedDensityMenu}
{memoizedColumnVisibilityMenu}
</>
);
};
Expand Down
Loading

0 comments on commit f56a856

Please sign in to comment.