diff --git a/packages/odyssey-react-mui/src/DataTable/reorderDataRowsLocally.tsx b/packages/odyssey-react-mui/src/DataTable/reorderDataRowsLocally.tsx index 393f13325..3f9d8d7e9 100644 --- a/packages/odyssey-react-mui/src/DataTable/reorderDataRowsLocally.tsx +++ b/packages/odyssey-react-mui/src/DataTable/reorderDataRowsLocally.tsx @@ -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 = ({ 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); diff --git a/packages/odyssey-react-mui/src/DataTable/useRowReordering.tsx b/packages/odyssey-react-mui/src/DataTable/useRowReordering.tsx index aca67be71..3c01e4d4f 100644 --- a/packages/odyssey-react-mui/src/DataTable/useRowReordering.tsx +++ b/packages/odyssey-react-mui/src/DataTable/useRowReordering.tsx @@ -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 = ({ totalRows, onReorderRows, data, @@ -28,12 +28,10 @@ export const useRowReordering = ({ }: { totalRows: DataTableProps["totalRows"]; onReorderRows: DataTableProps["onReorderRows"]; - data: MRT_RowData[]; - setData: Dispatch>; - draggingRow?: MRT_Row | null; - setDraggingRow: Dispatch< - SetStateAction | null | undefined> - >; + data: TData[]; + setData: Dispatch>; + draggingRow?: MRT_Row | null; + setDraggingRow: Dispatch | null | undefined>>; resultsPerPage: number; page: number; }) => { @@ -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", @@ -106,12 +103,12 @@ export const useRowReordering = ({ return undefined; }; - const setHoveredRow = ( - table: MRT_TableInstance, - id: MRT_RowData["id"], - ) => { + const setHoveredRow = (table: MRT_TableInstance, id: TData["id"]) => { if (id) { - const nextRow: MRT_RowData = table.getRow(id); + // The `as MRT_Row` 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; if (nextRow) { table.setHoveredRow(nextRow); @@ -120,8 +117,8 @@ export const useRowReordering = ({ }; type HandleDragHandleKeyDownArgs = { - table: MRT_TableInstance; - row: MRT_Row; + table: MRT_TableInstance; + row: MRT_Row; event: KeyboardEvent; }; @@ -192,7 +189,7 @@ export const useRowReordering = ({ } }; - const handleDragHandleOnDragEnd = (table: MRT_TableInstance) => { + const handleDragHandleOnDragEnd = (table: MRT_TableInstance) => { const cols = table.getAllColumns(); cols[0].toggleVisibility(); @@ -200,24 +197,20 @@ export const useRowReordering = ({ if (draggingRow) { updateRowOrder({ rowId: draggingRow.id, - newRowIndex: (hoveredRow as MRT_RowData).index, + newRowIndex: (hoveredRow as TData).index, }); } setDraggingRow(null); }; - const handleDragHandleOnDragCapture = ( - table: MRT_TableInstance, - ) => { + const handleDragHandleOnDragCapture = (table: MRT_TableInstance) => { if (!draggingRow && table.getState().draggingRow?.id) { setDraggingRow(table.getState().draggingRow); } }; - const resetDraggingAndHoveredRow = ( - table: MRT_TableInstance, - ) => { + const resetDraggingAndHoveredRow = (table: MRT_TableInstance) => { setDraggingRow(null); table.setHoveredRow(null); }; diff --git a/packages/odyssey-react-mui/src/labs/DataTable.tsx b/packages/odyssey-react-mui/src/labs/DataTable.tsx index 6e4e42001..9ae400785 100644 --- a/packages/odyssey-react-mui/src/labs/DataTable.tsx +++ b/packages/odyssey-react-mui/src/labs/DataTable.tsx @@ -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 = { /** * The unique ID of the column */ @@ -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["Cell"]; + Cell?: MRT_ColumnDef["Cell"]; /** * The UI control that will be used to filter the column. * Defaults to a standard text input. */ - filterVariant?: MRT_ColumnDef["filterVariant"]; + filterVariant?: MRT_ColumnDef["filterVariant"]; /** * If the filter control has preset options (such as a select or multi-select), * these are the options provided. @@ -127,16 +127,16 @@ export type DataTableColumn = { enableHiding?: boolean; }; -export type DataTableProps = { +export type DataTableProps = { /** * The columns that make up the table */ - columns: DataTableColumn[]; + columns: DataTableColumn[]; /** * The data that goes into the table, which will be displayed * as the table rows */ - data: MRT_TableOptions["data"]; + data: MRT_TableOptions["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. @@ -145,7 +145,7 @@ export type DataTableProps = { /** * The function to get the ID of a row */ - getRowId?: MRT_TableOptions["getRowId"]; + getRowId?: MRT_TableOptions["getRowId"]; /** * The initial density of the table. This is available even if the table density * isn't changeable. @@ -219,7 +219,7 @@ export type DataTableProps = { search?: string; filters?: DataFilter[]; sort?: MRT_SortingState; - }) => MRT_TableOptions["data"]; + }) => MRT_TableOptions["data"]; /** * Callback that fires when the user reorders rows within the table. Can be used * to propogate order change to the backend. @@ -248,24 +248,24 @@ export type DataTableProps = { * Action buttons to display in each row */ rowActionButtons?: ( - row: MRT_RowData, + row: TData, ) => ReactElement; /** * Menu items to include in the optional actions menu on each row. */ rowActionMenuItems?: ( - row: MRT_RowData, + row: TData, ) => ReactElement; }; -type TableType = MRT_TableInstance; +type TableType = MRT_TableInstance; -const reorderDataRowsLocally = ({ +const reorderDataRowsLocally = ({ currentData, rowId, newIndex, }: { - currentData: MRT_TableOptions["data"]; + currentData: MRT_TableOptions["data"]; rowId: string; newIndex: number; }) => { @@ -284,7 +284,7 @@ const reorderDataRowsLocally = ({ return updatedData; }; -const DataTable = ({ +const DataTable = ({ columns, data: dataProp, getRowId, @@ -309,13 +309,12 @@ const DataTable = ({ hasRowSelection, hasSearch, hasSorting, -}: DataTableProps) => { +}: DataTableProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); const { t } = useTranslation(); - const [draggingRow, setDraggingRow] = useState | null>(); + const [draggingRow, setDraggingRow] = useState | null>(); const [showSkeletons, setShowSkeletons] = useState(true); - const [data, setData] = - useState["data"]>(dataProp); + const [data, setData] = useState["data"]>(dataProp); const [page, setPage] = useState(pageProp); const [resultsPerPage, setResultsPerPage] = useState(resultsPerPageProp); @@ -428,9 +427,9 @@ const DataTable = ({ const rowVirtualizerInstanceRef = useRef>(null); - const setHoveredRow = (table: TableType, id: MRT_RowData["id"]) => { + const setHoveredRow = (table: TableType, id: TData["id"]) => { if (id) { - const nextRow: MRT_RowData = table.getRow(id); + const nextRow = table.getRow(id) as MRT_Row; if (nextRow) { table.setHoveredRow(nextRow); @@ -438,14 +437,14 @@ const DataTable = ({ } }; - const resetDraggingAndHoveredRow = (table: TableType) => { + const resetDraggingAndHoveredRow = (table: TableType) => { setDraggingRow(null); table.setHoveredRow(null); }; type HandleDragHandleKeyDownArgs = { - table: TableType; - row: MRT_Row; + table: TableType; + row: MRT_Row; event: KeyboardEvent; }; @@ -515,15 +514,17 @@ const DataTable = ({ [ data, draggingRow, - odysseyDesignTokens, + odysseyDesignTokens.TransitionDurationMainAsNumber, page, + resetDraggingAndHoveredRow, resultsPerPage, + setHoveredRow, updateRowOrder, ], ); const handleDragHandleOnDragEnd = useCallback( - (table: TableType) => { + (table: TableType) => { const cols = table.getAllColumns(); cols[0].toggleVisibility(); @@ -531,7 +532,7 @@ const DataTable = ({ if (draggingRow) { updateRowOrder({ rowId: draggingRow.id, - newIndex: (hoveredRow as MRT_RowData).index, + newIndex: (hoveredRow as TData).index, }); } @@ -541,7 +542,7 @@ const DataTable = ({ ); const handleDragHandleOnDragCapture = useCallback( - (table: TableType) => { + (table: TableType) => { if (!draggingRow && table.getState().draggingRow?.id) { setDraggingRow(table.getState().draggingRow); } @@ -683,7 +684,7 @@ const DataTable = ({ return ( - {rowActionButtons?.(row)} + {rowActionButtons?.(row.original)} {(rowActionMenuItems || hasRowReordering) && ( } @@ -694,7 +695,7 @@ const DataTable = ({ > {rowActionMenuItems && ( <> - {rowActionMenuItems(row)} + {rowActionMenuItems(row.original)}
)} diff --git a/packages/odyssey-react-mui/src/labs/DataView/BulkActionsMenu.tsx b/packages/odyssey-react-mui/src/labs/DataView/BulkActionsMenu.tsx index bc39f705f..b396934b3 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/BulkActionsMenu.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/BulkActionsMenu.tsx @@ -25,9 +25,9 @@ import { useOdysseyDesignTokens, } from "../../OdysseyDesignTokensContext"; -export type BulkActionsMenuProps = { +export type BulkActionsMenuProps = { data: MRT_RowData[]; - menuItems: UniversalProps["bulkActionMenuItems"]; + menuItems: UniversalProps["bulkActionMenuItems"]; rowSelection: MRT_RowSelectionState; setRowSelection: Dispatch>; }; @@ -41,12 +41,12 @@ const BulkActionsContainer = styled("div", { gap: odysseyDesignTokens.Spacing2, })); -const BulkActionsMenu = ({ +const BulkActionsMenu = ({ data, menuItems, rowSelection, setRowSelection, -}: BulkActionsMenuProps) => { +}: BulkActionsMenuProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); const { t } = useTranslation(); diff --git a/packages/odyssey-react-mui/src/labs/DataView/CardLayoutContent.tsx b/packages/odyssey-react-mui/src/labs/DataView/CardLayoutContent.tsx index e647ab407..dfe9c8615 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/CardLayoutContent.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/CardLayoutContent.tsx @@ -30,19 +30,19 @@ import { RowActions } from "./RowActions"; import { DataCard } from "./DataCard"; import { CardLayout, CardLayoutProps, UniversalProps } from "./componentTypes"; -export type CardLayoutContentProps = { +export type CardLayoutContentProps = { currentLayout: CardLayout; - data: MRT_RowData[]; - draggingRow?: MRT_Row | null; + data: TData[]; + draggingRow?: MRT_Row | null; emptyState: ReactNode; - getRowId: UniversalProps["getRowId"]; - hasRowReordering: UniversalProps["hasRowReordering"]; - hasRowSelection: UniversalProps["hasRowSelection"]; + getRowId: UniversalProps["getRowId"]; + hasRowReordering: UniversalProps["hasRowReordering"]; + hasRowSelection: UniversalProps["hasRowSelection"]; isEmpty?: boolean; isLoading: boolean; isNoResults?: boolean; isRowReorderingDisabled?: boolean; - onReorderRows: UniversalProps["onReorderRows"]; + onReorderRows: UniversalProps["onReorderRows"]; pagination: { pageIndex: number; pageSize: number }; rowReorderingUtilities: { dragHandleStyles: CSSObject; @@ -64,15 +64,13 @@ export type CardLayoutContentProps = { row, event, }: { - table: MRT_TableInstance; - row: MRT_Row; + table: MRT_TableInstance; + row: MRT_Row; event: React.KeyboardEvent; }) => void; - handleDragHandleOnDragCapture: ( - table: MRT_TableInstance, - ) => void; - handleDragHandleOnDragEnd: (table: MRT_TableInstance) => void; - resetDraggingAndHoveredRow: (table: MRT_TableInstance) => void; + handleDragHandleOnDragCapture: (table: MRT_TableInstance) => void; + handleDragHandleOnDragEnd: (table: MRT_TableInstance) => void; + resetDraggingAndHoveredRow: (table: MRT_TableInstance) => void; updateRowOrder: ({ rowId, newRowIndex, @@ -83,8 +81,13 @@ export type CardLayoutContentProps = { }; rowSelection: MRT_RowSelectionState; setRowSelection: Dispatch>; - cardLayoutOptions: CardLayoutProps; - totalRows: UniversalProps["totalRows"]; + cardLayoutOptions: CardLayoutProps; + totalRows: UniversalProps["totalRows"]; +}; +type CardLayoutContentComponent = (( + props: CardLayoutContentProps, +) => JSX.Element) & { + displayName?: string; }; const StackContainer = styled("div", { @@ -134,7 +137,7 @@ const CheckboxContainer = styled("div", { marginBlockStart: `-${odysseyDesignTokens.Spacing1}`, })); -const CardLayoutContent = ({ +const CardLayoutContent = ({ currentLayout, data, emptyState, @@ -151,7 +154,7 @@ const CardLayoutContent = ({ setRowSelection, cardLayoutOptions, totalRows, -}: CardLayoutContentProps) => { +}: CardLayoutContentProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); const handleRowSelectionChange = useCallback( @@ -185,7 +188,7 @@ const CardLayoutContent = ({ {emptyState} ) : ( <> - {data.map((row: MRT_RowData, index: number) => { + {data.map((row: TData, index: number) => { const { overline, title, @@ -251,7 +254,9 @@ const CardLayoutContent = ({ ); }; -const MemoizedCardLayoutContent = memo(CardLayoutContent); +const MemoizedCardLayoutContent = memo( + CardLayoutContent, +) as CardLayoutContentComponent; MemoizedCardLayoutContent.displayName = "CardLayoutContent"; export { MemoizedCardLayoutContent as CardLayoutContent }; diff --git a/packages/odyssey-react-mui/src/labs/DataView/DataCard.tsx b/packages/odyssey-react-mui/src/labs/DataView/DataCard.tsx index 19360acbf..4059352dd 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/DataCard.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/DataCard.tsx @@ -50,13 +50,13 @@ export const CARD_IMAGE_SIZE_COMPACT = "48px"; export const cardVariantValues = ["tile", "stack", "compact"] as const; -export type DataCardProps = { +export type DataCardProps = { children?: ReactNode; description?: string; image?: ReactElement; overline?: string; - renderDetailPanel?: CardLayoutProps["renderDetailPanel"]; - row: MRT_RowData; + renderDetailPanel?: CardLayoutProps["renderDetailPanel"]; + row: TData; title?: string; variant?: (typeof cardVariantValues)[number]; } & ( @@ -74,6 +74,12 @@ export type DataCardProps = { } ); +type DataCardComponent = (( + props: DataCardProps, +) => JSX.Element) & { + displayName?: string; +}; + const AccessoryContainer = styled("div", { shouldForwardProp: (prop) => prop !== "odysseyDesignTokens" && prop !== "variant", @@ -158,7 +164,7 @@ const AccessoryPlaceholder = styled(MuiIconButton)(() => ({ })); const buttonProviderValue = { isFullWidth: true }; -const DataCard = ({ +const DataCard: DataCardComponent = ({ Accessory: AccessoryProp, button, children, @@ -171,7 +177,7 @@ const DataCard = ({ row, title, variant = "tile", -}: DataCardProps) => { +}: DataCardProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); const { t } = useTranslation(); @@ -318,7 +324,7 @@ const DataCard = ({ ); }; -const MemoizedDataCard = memo(DataCard); +const MemoizedDataCard = memo(DataCard) as DataCardComponent; MemoizedDataCard.displayName = "DataCard"; export { MemoizedDataCard as DataCard }; diff --git a/packages/odyssey-react-mui/src/labs/DataView/DataTable.tsx b/packages/odyssey-react-mui/src/labs/DataView/DataTable.tsx index 5292be942..c9a237b87 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/DataTable.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/DataTable.tsx @@ -14,10 +14,17 @@ import { memo, useMemo } from "react"; import { DataView } from "./DataView"; import { TableLayoutProps, UniversalProps } from "./componentTypes"; +import { MRT_RowData } from "material-react-table"; -export type DataTableProps = UniversalProps & TableLayoutProps; +export type DataTableProps = UniversalProps & + TableLayoutProps; +type DataTableComponent = (( + props: DataTableProps, +) => JSX.Element) & { + displayName?: string; +}; -const DataTable = ({ +const DataTable = ({ additionalActionButton, additionalActionMenuItems, bulkActionMenuItems, @@ -54,7 +61,7 @@ const DataTable = ({ rowActionMenuItems, searchDelayTime, totalRows, -}: DataTableProps) => { +}: DataTableProps) => { const tableLayoutOptions = useMemo( () => ({ columns, @@ -115,7 +122,7 @@ const DataTable = ({ ); }; -const MemoizedDataTable = memo(DataTable); +const MemoizedDataTable = memo(DataTable) as DataTableComponent; MemoizedDataTable.displayName = "DataTable"; export { MemoizedDataTable as DataTable }; diff --git a/packages/odyssey-react-mui/src/labs/DataView/DataView.tsx b/packages/odyssey-react-mui/src/labs/DataView/DataView.tsx index c0f03b9c4..da78767c9 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/DataView.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/DataView.tsx @@ -50,7 +50,13 @@ import { } from "../../OdysseyDesignTokensContext"; import styled from "@emotion/styled"; -export type DataViewProps = UniversalProps & ViewProps; +export type DataViewProps = UniversalProps & + ViewProps; +type DataViewComponent = (( + props: DataViewProps, +) => JSX.Element) & { + displayName?: string; +}; const DataViewContainer = styled("div", { shouldForwardProp: (prop) => prop !== "odysseyDesignTokens", @@ -87,7 +93,7 @@ const MetaTextContainer = styled("div", { marginInlineEnd: odysseyDesignTokens.Spacing2, })); -const DataView = ({ +const DataView = ({ additionalActionButton, additionalActionMenuItems, availableLayouts = allAvailableLayouts, @@ -127,7 +133,7 @@ const DataView = ({ maxPages, maxResultsPerPage, onPaginationChange, -}: DataViewProps) => { +}: DataViewProps) => { const odysseyDesignTokens = useOdysseyDesignTokens(); const { t } = useTranslation(); @@ -135,23 +141,23 @@ const DataView = ({ initialLayout ?? availableLayouts[0], ); - const [data, setData] = useState([]); + const [data, setData] = useState([]); const [isLoading, setIsLoading] = useState(isLoadingProp ?? true); const [isEmpty, setIsEmpty] = useState(isEmptyProp ?? true); const [isNoResults, setIsNoResults] = useState( isNoResultsProp ?? false, ); const [errorMessage, setErrorMessage] = - useState(errorMessageProp); + useState["errorMessage"]>(errorMessageProp); const [search, setSearch] = useState(""); const [initialFilters, setInitialFilters] = - useState(filtersProp); + useState["filters"]>(filtersProp); const [filters, setFilters] = - useState(filtersProp); + useState["filters"]>(filtersProp); - const [draggingRow, setDraggingRow] = useState | null>(); + const [draggingRow, setDraggingRow] = useState | null>(); const [rowSelection, setRowSelection] = useState({}); @@ -204,7 +210,7 @@ const DataView = ({ ], ); - const getRowId = getRowIdProp ? getRowIdProp : (row: MRT_RowData) => row.id; + const getRowId = getRowIdProp ? getRowIdProp : (row: TData) => row.id; // Update pagination state if props change useEffect(() => { @@ -488,7 +494,7 @@ const DataView = ({ ); }; -const MemoizedDataView = memo(DataView); +const MemoizedDataView = memo(DataView) as DataViewComponent; MemoizedDataView.displayName = "DataView"; export { MemoizedDataView as DataView }; diff --git a/packages/odyssey-react-mui/src/labs/DataView/DetailPanel.tsx b/packages/odyssey-react-mui/src/labs/DataView/DetailPanel.tsx index a69f92ee1..29a20320e 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/DetailPanel.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/DetailPanel.tsx @@ -12,14 +12,14 @@ import { memo } from "react"; import { CardLayoutProps } from "./componentTypes"; -import { DataRow } from "./dataTypes"; +import { MRT_RowData } from "material-react-table"; -const DetailPanel = ({ +const DetailPanel = ({ row, renderDetailPanel, }: { - row: DataRow; - renderDetailPanel: CardLayoutProps["renderDetailPanel"]; + row: TData; + renderDetailPanel: CardLayoutProps["renderDetailPanel"]; }) => { if (!renderDetailPanel) return null; return renderDetailPanel({ row }); diff --git a/packages/odyssey-react-mui/src/labs/DataView/RowActions.tsx b/packages/odyssey-react-mui/src/labs/DataView/RowActions.tsx index 4587ae6c4..07934e9d6 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/RowActions.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/RowActions.tsx @@ -25,7 +25,7 @@ import { MenuItem } from "../../MenuItem"; import { DataTableProps } from "./DataTable"; import { MenuButtonProps } from "../../MenuButton"; -export type RowActionsProps = { +export type RowActionsProps = { isRowReorderingDisabled?: boolean; row: MRT_Row | MRT_RowData; rowActionButtons?: ( @@ -33,7 +33,7 @@ export type RowActionsProps = { ) => ReactElement | ReactElement; rowActionMenuItems?: (row: MRT_RowData) => MenuButtonProps["children"]; rowIndex: number; - totalRows?: DataTableProps["totalRows"]; + totalRows?: DataTableProps["totalRows"]; updateRowOrder?: ({ newRowIndex, rowId, @@ -43,14 +43,14 @@ export type RowActionsProps = { }) => void; }; -const RowActions = ({ +const RowActions = ({ isRowReorderingDisabled, row, rowActionMenuItems, rowIndex, totalRows, updateRowOrder, -}: RowActionsProps) => { +}: RowActionsProps) => { const { t } = useTranslation(); const handleToFrontClick = useCallback(() => { diff --git a/packages/odyssey-react-mui/src/labs/DataView/TableLayoutContent.tsx b/packages/odyssey-react-mui/src/labs/DataView/TableLayoutContent.tsx index e09faee93..125e459b9 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/TableLayoutContent.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/TableLayoutContent.tsx @@ -65,20 +65,20 @@ const RowActionsContainer = styled("div")(() => ({ display: "flex", })); -export type TableLayoutContentProps = { - columns: TableLayoutProps["columns"]; +export type TableLayoutContentProps = { + columns: TableLayoutProps["columns"]; data: MRT_RowData[]; - draggingRow?: MRT_Row | null; + draggingRow?: MRT_Row | null; emptyState: ReactNode; enableVirtualization?: boolean; - getRowId: UniversalProps["getRowId"]; - hasRowReordering: UniversalProps["hasRowReordering"]; - hasRowSelection: UniversalProps["hasRowSelection"]; + getRowId: UniversalProps["getRowId"]; + hasRowReordering: UniversalProps["hasRowReordering"]; + hasRowSelection: UniversalProps["hasRowSelection"]; isEmpty?: boolean; isLoading: boolean; isNoResults?: boolean; isRowReorderingDisabled?: boolean; - onReorderRows: UniversalProps["onReorderRows"]; + onReorderRows: UniversalProps["onReorderRows"]; pagination: { pageIndex: number; pageSize: number; @@ -103,15 +103,13 @@ export type TableLayoutContentProps = { row, event, }: { - table: MRT_TableInstance; - row: MRT_Row; + table: MRT_TableInstance; + row: MRT_Row; event: React.KeyboardEvent; }) => void; - handleDragHandleOnDragCapture: ( - table: MRT_TableInstance, - ) => void; - handleDragHandleOnDragEnd: (table: MRT_TableInstance) => void; - resetDraggingAndHoveredRow: (table: MRT_TableInstance) => void; + handleDragHandleOnDragCapture: (table: MRT_TableInstance) => void; + handleDragHandleOnDragEnd: (table: MRT_TableInstance) => void; + resetDraggingAndHoveredRow: (table: MRT_TableInstance) => void; updateRowOrder: ({ rowId, newRowIndex, @@ -123,12 +121,18 @@ export type TableLayoutContentProps = { rowSelection: MRT_RowSelectionState; setRowSelection: Dispatch>; setTableState: Dispatch>; - tableLayoutOptions: TableLayoutProps; + tableLayoutOptions: TableLayoutProps; tableState: TableState; - totalRows: UniversalProps["totalRows"]; + totalRows: UniversalProps["totalRows"]; }; -const TableLayoutContent = ({ +type TableLayoutContentComponent = (( + props: TableLayoutContentProps, +) => JSX.Element) & { + displayName?: string; +}; + +const TableLayoutContent = ({ columns, data, draggingRow, @@ -150,7 +154,7 @@ const TableLayoutContent = ({ tableLayoutOptions, tableState, totalRows, -}: TableLayoutContentProps) => { +}: TableLayoutContentProps) => { const [isTableContainerScrolledToStart, setIsTableContainerScrolledToStart] = useState(true); const [isTableContainerScrolledToEnd, setIsTableContainerScrolledToEnd] = @@ -198,7 +202,7 @@ const TableLayoutContent = ({ }, [tableState]); const defaultCell = useCallback< - ({ cell }: { cell: DataTableCell }) => ReactElement | string + ({ cell }: { cell: DataTableCell }) => ReactElement | string >(({ cell }) => { const value = cell.getValue(); const hasTextWrapping = @@ -219,7 +223,7 @@ const TableLayoutContent = ({ } = rowReorderingUtilities; const renderRowActions = useCallback( - ({ row }: { row: MRT_Row }) => { + ({ row }: { row: MRT_Row }) => { const currentIndex = row.index + (pagination.pageIndex - 1) * pagination.pageSize; return ( @@ -310,8 +314,8 @@ const TableLayoutContent = ({ const hasColumnWithGrow = columns.some((column) => column.grow === true); - const dataTable = useMaterialReactTable({ - data: !isEmpty && !isNoResults ? data : [], + const dataTable = useMaterialReactTable({ + data: (!isEmpty && !isNoResults ? data : []) as TData[], columns, getRowId, state: { @@ -477,7 +481,9 @@ const TableLayoutContent = ({ ); }; -const MemoizedTableLayoutContent = memo(TableLayoutContent); +const MemoizedTableLayoutContent = memo( + TableLayoutContent, +) as TableLayoutContentComponent; MemoizedTableLayoutContent.displayName = "TableLayoutContent"; export { MemoizedTableLayoutContent as TableLayoutContent }; diff --git a/packages/odyssey-react-mui/src/labs/DataView/TableSettings.tsx b/packages/odyssey-react-mui/src/labs/DataView/TableSettings.tsx index 7abc448c3..94cb23aee 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/TableSettings.tsx +++ b/packages/odyssey-react-mui/src/labs/DataView/TableSettings.tsx @@ -12,7 +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 { MRT_DensityState, MRT_RowData } from "material-react-table"; import { useTranslation } from "react-i18next"; import { densityValues } from "./constants"; @@ -21,17 +21,23 @@ import { MenuButton } from "../../MenuButton"; import { MenuItem } from "../../MenuItem"; import { TableLayoutProps, TableState } from "./componentTypes"; -export type TableSettingsProps = { +export type TableSettingsProps = { setTableState: Dispatch>; - tableLayoutOptions: TableLayoutProps; + tableLayoutOptions: TableLayoutProps; tableState: TableState; }; -const TableSettings = ({ +type TableSettingsComponent = (( + props: TableSettingsProps, +) => JSX.Element) & { + displayName?: string; +}; + +const TableSettings: TableSettingsComponent = ({ setTableState, tableLayoutOptions, tableState, -}: TableSettingsProps) => { +}: TableSettingsProps) => { const { t } = useTranslation(); const { hasChangeableDensity, hasColumnVisibility, columns } = @@ -133,7 +139,7 @@ const TableSettings = ({ ); }; -const MemoizedTableSettings = memo(TableSettings); +const MemoizedTableSettings = memo(TableSettings) as TableSettingsComponent; MemoizedTableSettings.displayName = "TableSettings"; export { MemoizedTableSettings as TableSettings }; diff --git a/packages/odyssey-react-mui/src/labs/DataView/componentTypes.ts b/packages/odyssey-react-mui/src/labs/DataView/componentTypes.ts index c557495e5..664339b4b 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/componentTypes.ts +++ b/packages/odyssey-react-mui/src/labs/DataView/componentTypes.ts @@ -28,11 +28,11 @@ import { DataRowSelectionState, DataTableColumn, } from "./dataTypes"; -import { DataTableRowActionsProps } from "../../DataTable/DataTableRowActions"; import { MenuButtonProps } from "../.."; import { paginationTypeValues } from "../DataTablePagination"; import { DataCardProps } from "./DataCard"; import { type PaginationProps } from "../../Pagination"; +import { RowActionsProps } from "./RowActions"; export type DataLayout = (typeof availableLayouts)[number]; export type CardLayout = (typeof availableCardLayouts)[number]; @@ -40,7 +40,7 @@ export type CardLayout = (typeof availableCardLayouts)[number]; export type AvailableLayouts = DataLayout[]; export type AvailableCardLayouts = CardLayout[]; -export type UniversalProps = { +export type UniversalProps = { additionalActionButton?: ReactNode; additionalActionMenuItems?: ReactNode; bulkActionMenuItems?: ( @@ -50,15 +50,15 @@ export type UniversalProps = { emptyPlaceholder?: ReactNode; enableVirtualization?: boolean; errorMessage?: string; - filters?: Array | string>; + filters?: Array | string>; getData: ({ page, resultsPerPage, search, filters, sort, - }: DataGetDataType) => MRT_RowData[] | Promise; - getRowId?: MRT_TableOptions["getRowId"]; + }: DataGetDataType) => TData[] | Promise; + getRowId?: MRT_TableOptions["getRowId"]; hasFilters?: boolean; hasPagination?: boolean; hasRowReordering?: boolean; @@ -96,30 +96,30 @@ export type UniversalProps = { "hasPageInput" | "hasRowCountInput" | "hasRowCountLabel" >; -export type TableLayoutProps = { - columns: DataTableColumn[]; +export type TableLayoutProps = { + columns: DataTableColumn[]; hasChangeableDensity?: boolean; hasColumnResizing?: boolean; hasColumnVisibility?: boolean; hasSorting?: boolean; initialDensity?: MRT_DensityState; - renderDetailPanel?: MRT_TableOptions["renderDetailPanel"]; - rowActionButtons?: DataTableRowActionsProps["rowActionButtons"]; - rowActionMenuItems?: DataTableRowActionsProps["rowActionMenuItems"]; + renderDetailPanel?: MRT_TableOptions["renderDetailPanel"]; + rowActionButtons?: RowActionsProps["rowActionButtons"]; + rowActionMenuItems?: RowActionsProps["rowActionMenuItems"]; }; -export type CardLayoutProps = { - itemProps: (row: MRT_RowData) => Omit; +export type CardLayoutProps = { + itemProps: (row: TData) => Omit, "row">; maxGridColumns?: number; - renderDetailPanel?: (props: { row: MRT_RowData }) => ReactNode; - rowActionMenuItems?: DataTableRowActionsProps["rowActionMenuItems"]; + renderDetailPanel?: (props: { row: TData }) => ReactNode; + rowActionMenuItems?: RowActionsProps["rowActionMenuItems"]; }; -export type ViewProps = { +export type ViewProps = { availableLayouts?: L[]; initialLayout?: L; - cardLayoutOptions?: CardLayoutProps; - tableLayoutOptions?: TableLayoutProps; + cardLayoutOptions?: CardLayoutProps; + tableLayoutOptions?: TableLayoutProps; }; export type TableState = { diff --git a/packages/odyssey-react-mui/src/labs/DataView/dataTypes.ts b/packages/odyssey-react-mui/src/labs/DataView/dataTypes.ts index 640b15e00..67171a473 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/dataTypes.ts +++ b/packages/odyssey-react-mui/src/labs/DataView/dataTypes.ts @@ -29,7 +29,10 @@ export type DataQueryParamsType = { sort?: MRT_SortingState; }; -export type DataTableColumn = MRT_ColumnDef & { +export type DataTableColumn< + TData extends MRT_RowData, + TValue = unknown, +> = MRT_ColumnDef & { /** * @deprecated use hasTextWrapping instead of enableWrapping */ @@ -37,21 +40,24 @@ export type DataTableColumn = MRT_ColumnDef & { hasTextWrapping?: boolean; }; -export type DataTableColumnInstance = Omit< - MRT_Column, +export type DataTableColumnInstance = Omit< + MRT_Column, "columnDef" > & { - columnDef: DataTableColumn; + columnDef: DataTableColumn; }; -export type DataTableCell = Omit< - MRT_Cell, +export type DataTableCell = Omit< + MRT_Cell, "column" > & { - column: DataTableColumnInstance; + column: DataTableColumnInstance; }; -export type DataColumns = DataTableColumn[]; +export type DataColumns< + TData extends MRT_RowData, + TValue = unknown, +> = DataTableColumn[]; export type DataRow = MRT_RowData; diff --git a/packages/odyssey-react-mui/src/labs/DataView/fetchData.ts b/packages/odyssey-react-mui/src/labs/DataView/fetchData.ts index 33bac6a16..b48bc848a 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/fetchData.ts +++ b/packages/odyssey-react-mui/src/labs/DataView/fetchData.ts @@ -17,23 +17,25 @@ import { t } from "i18next"; import { DataQueryParamsType } from "./dataTypes"; import { UniversalProps } from "./componentTypes"; -type DataRequestType = { +type DataRequestType = { dataQueryParams: DataQueryParamsType; - errorMessageProp: UniversalProps["errorMessage"]; - getData: UniversalProps["getData"]; - setData: Dispatch>; - setErrorMessage: Dispatch>; + errorMessageProp: UniversalProps["errorMessage"]; + getData: UniversalProps["getData"]; + setData: Dispatch>; + setErrorMessage: Dispatch< + SetStateAction["errorMessage"]> + >; setIsLoading?: Dispatch>; }; -export const fetchData = async ({ +export const fetchData = async ({ dataQueryParams, errorMessageProp, getData, setData, setErrorMessage, setIsLoading, -}: DataRequestType) => { +}: DataRequestType) => { setIsLoading?.(true); setErrorMessage(errorMessageProp); try { diff --git a/packages/odyssey-react-mui/src/labs/DataView/useFilterConversion.ts b/packages/odyssey-react-mui/src/labs/DataView/useFilterConversion.ts index 349cf3884..ff897eedf 100644 --- a/packages/odyssey-react-mui/src/labs/DataView/useFilterConversion.ts +++ b/packages/odyssey-react-mui/src/labs/DataView/useFilterConversion.ts @@ -17,15 +17,15 @@ import { DataFilter } from "../DataFilters"; import { DataTableColumn } from "../../DataTable"; import { UniversalProps, TableLayoutProps } from "./componentTypes"; -type FilterConversionType = { - columns?: TableLayoutProps["columns"]; - filters?: UniversalProps["filters"]; +type FilterConversionType = { + columns?: TableLayoutProps["columns"]; + filters?: UniversalProps["filters"]; }; -export const useFilterConversion = ({ +export const useFilterConversion = ({ columns, filters, -}: FilterConversionType) => { +}: FilterConversionType) => { const convertFilterSelectOptions = useCallback( (options: DataTableColumn["filterSelectOptions"]) => options?.map((option) => @@ -45,14 +45,14 @@ export const useFilterConversion = ({ ); const convertColumnToFilter = useCallback( - (column: DataTableColumn) => + (column: DataTableColumn) => column.enableColumnFilter !== false && column.accessorKey - ? ({ + ? { id: column.accessorKey, label: column.header, variant: column.filterVariant, options: convertFilterSelectOptions(column.filterSelectOptions), - } satisfies DataFilter as DataFilter) + } : null, [convertFilterSelectOptions], ); diff --git a/packages/odyssey-storybook/src/components/odyssey-labs/DataTable/DataTable.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-labs/DataTable/DataTable.stories.tsx index d48b2d642..f748b4839 100644 --- a/packages/odyssey-storybook/src/components/odyssey-labs/DataTable/DataTable.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-labs/DataTable/DataTable.stories.tsx @@ -39,10 +39,10 @@ import { paginationTypeValues, } from "@okta/odyssey-react-mui"; -type DataTableMetaProps = DataViewProps & - TableLayoutProps & { - tableRowActionMenuItems: TableLayoutProps["rowActionMenuItems"]; - listRowActionMenuItems: CardLayoutProps["rowActionMenuItems"]; +type DataTableMetaProps = DataViewProps & + TableLayoutProps & { + tableRowActionMenuItems: TableLayoutProps["rowActionMenuItems"]; + listRowActionMenuItems: CardLayoutProps["rowActionMenuItems"]; hasCustomEmptyPlaceholder: boolean; hasCustomNoResultsPlaceholder: boolean; hasActionMenuItems: boolean; diff --git a/packages/odyssey-storybook/src/components/odyssey-labs/DataView/DataView.stories.tsx b/packages/odyssey-storybook/src/components/odyssey-labs/DataView/DataView.stories.tsx index a35f7471b..35ecd4651 100644 --- a/packages/odyssey-storybook/src/components/odyssey-labs/DataView/DataView.stories.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-labs/DataView/DataView.stories.tsx @@ -52,11 +52,11 @@ import { DataTableRowData, } from "@okta/odyssey-react-mui"; -type DataViewMetaProps = DataViewProps & - TableLayoutProps & - CardLayoutProps & { - tableRowActionMenuItems: TableLayoutProps["rowActionMenuItems"]; - cardRowActionMenuItems: CardLayoutProps["rowActionMenuItems"]; +type DataViewMetaProps = DataViewProps & + TableLayoutProps & + CardLayoutProps & { + tableRowActionMenuItems: TableLayoutProps["rowActionMenuItems"]; + cardRowActionMenuItems: CardLayoutProps["rowActionMenuItems"]; hasCustomEmptyPlaceholder: boolean; hasCustomNoResultsPlaceholder: boolean; hasActionMenuItems: boolean; @@ -920,7 +920,7 @@ export const AdditionalActions: StoryObj = { export const ColumnGrowDemo: StoryObj = { render: function C() { const columns = useMemo( - (): DataColumns => [ + (): DataColumns => [ { accessorKey: "name", header: "Name", @@ -1016,11 +1016,11 @@ export const PaginationHook: StoryObj = { }, }; -const stackItemProps = (row: DataRow) => ({ +const stackItemProps = (row: Person) => ({ overline: "Overline", title: row.name, description: `${row.name} is ${row.age} years old.`, - variant: "stack" as DataCardProps["variant"], + variant: "stack" as DataCardProps["variant"], image: Logo, }); @@ -1043,10 +1043,10 @@ export const StackCards: StoryObj = { }, }; -const compactItemProps = (row: DataRow) => ({ +const compactItemProps = (row: Person) => ({ title: row.name, description: `${row.name} is ${row.age} years old.`, - variant: "compact" as DataCardProps["variant"], + variant: "compact" as DataCardProps["variant"], image: Logo, }); @@ -1075,7 +1075,7 @@ export const GrowColumnWithoutActions: StoryObj = { const [data, setData] = useState(personData); const { getData } = useDataCallbacks(data, setData); - const columns: DataColumns = [ + const columns: DataColumns = [ { accessorKey: "order", header: "ID", @@ -1110,7 +1110,7 @@ export const GrowColumnWithActions: StoryObj = { const [data, setData] = useState(personData); const { getData } = useDataCallbacks(data, setData); - const columns: DataColumns = [ + const columns: DataColumns = [ { accessorKey: "order", header: "ID", diff --git a/packages/odyssey-storybook/src/components/odyssey-labs/DataView/personData.tsx b/packages/odyssey-storybook/src/components/odyssey-labs/DataView/personData.tsx index 31cfaf949..e29b01c48 100644 --- a/packages/odyssey-storybook/src/components/odyssey-labs/DataView/personData.tsx +++ b/packages/odyssey-storybook/src/components/odyssey-labs/DataView/personData.tsx @@ -23,7 +23,7 @@ export type Person = { risk: "high" | "medium" | "low"; }; -export const columns: DataColumns = [ +export const columns: DataColumns = [ { accessorKey: "order", header: "ID",