implementation of datatable

This commit is contained in:
Amirhossein Mahmoodi
2024-04-16 11:45:14 +03:30
parent 78548e89e7
commit a8e28a4f8c
29 changed files with 2983 additions and 2 deletions

View File

@@ -0,0 +1,207 @@
import { parseFromValuesOrFunc } from "@/core/utils/utils";
import { TableBody, Typography } from "@mui/material";
import { useMRT_RowVirtualizer, useMRT_Rows } from "material-react-table";
import { memo, useMemo } from "react";
import DataTable_TableBodyRow, { Memo_DataTable_TableBodyRow } from "./TableBodyRow";
const DataTable_TableBody = ({
columnVirtualizer,
table,
...rest
}) => {
const {
getBottomRows,
getIsSomeRowsPinned,
getRowModel,
getState,
getTopRows,
options: {
enableStickyFooter,
enableStickyHeader,
layoutMode,
localization,
memoMode,
muiTableBodyProps,
renderDetailPanel,
renderEmptyRowsFallback,
rowPinningDisplayMode,
},
refs: { tableFooterRef, tableHeadRef, tablePaperRef },
} = table;
const { columnFilters, globalFilter, isFullScreen, rowPinning } = getState();
const tableBodyProps = {
...parseFromValuesOrFunc(muiTableBodyProps, { table }),
...rest,
};
const tableHeadHeight =
((enableStickyHeader || isFullScreen) &&
tableHeadRef.current?.clientHeight) ||
0;
const tableFooterHeight =
(enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;
const pinnedRowIds = useMemo(() => {
if (!rowPinning.bottom?.length && !rowPinning.top?.length) return [];
return getRowModel()
.rows.filter((row) => row.getIsPinned())
.map((r) => r.id);
}, [rowPinning, getRowModel().rows]);
const rows = useMRT_Rows(table);
const rowVirtualizer = useMRT_RowVirtualizer(table, rows);
const { virtualRows } = rowVirtualizer ?? {};
const commonRowProps = {
columnVirtualizer,
numRows: rows.length,
table,
};
return (
<>
{!rowPinningDisplayMode?.includes('sticky') &&
getIsSomeRowsPinned('top') && (
<TableBody
{...tableBodyProps}
sx={(theme) => ({
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
position: 'sticky',
top: tableHeadHeight - 1,
zIndex: 1,
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)),
})}
>
{getTopRows().map((row, staticRowIndex) => {
const props = {
...commonRowProps,
row,
staticRowIndex,
};
return memoMode === 'rows' ? (
<Memo_DataTable_TableBodyRow key={row.id} {...props} />
) : (
<DataTable_TableBodyRow key={row.id} {...props} />
);
})}
</TableBody>
)}
<TableBody
{...tableBodyProps}
sx={(theme) => ({
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
height: rowVirtualizer
? `${rowVirtualizer.getTotalSize()}px`
: undefined,
minHeight: !rows.length ? '100px' : undefined,
position: 'relative',
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)),
})}
>
{tableBodyProps?.children ??
(!rows.length ? (
<tr
style={{
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
}}
>
<td
colSpan={table.getVisibleLeafColumns().length}
style={{
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
}}
>
{renderEmptyRowsFallback?.({ table }) ?? (
<Typography
sx={{
color: 'text.secondary',
fontStyle: 'italic',
maxWidth: `min(100vw, ${tablePaperRef.current?.clientWidth ?? 360
}px)`,
py: '2rem',
textAlign: 'center',
width: '100%',
}}
>
{globalFilter || columnFilters.length
? localization.noResultsFound
: localization.noRecordsToDisplay}
</Typography>
)}
</td>
</tr>
) : (
<>
{(virtualRows ?? rows).map((rowOrVirtualRow, staticRowIndex) => {
let row = rowOrVirtualRow;
if (rowVirtualizer) {
if (renderDetailPanel) {
if (rowOrVirtualRow.index % 2 === 1) {
return null;
} else {
staticRowIndex = rowOrVirtualRow.index / 2;
}
} else {
staticRowIndex = rowOrVirtualRow.index;
}
row = rows[staticRowIndex];
}
const props = {
...commonRowProps,
pinnedRowIds,
row,
rowVirtualizer,
staticRowIndex,
virtualRow: rowVirtualizer
? (rowOrVirtualRow)
: undefined,
};
const key = `${row.id}-${row.index}`;
return memoMode === 'rows' ? (
<Memo_DataTable_TableBodyRow key={key} {...props} />
) : (
<DataTable_TableBodyRow key={key} {...props} />
);
})}
</>
))}
</TableBody>
{!rowPinningDisplayMode?.includes('sticky') &&
getIsSomeRowsPinned('bottom') && (
<TableBody
{...tableBodyProps}
sx={(theme) => ({
bottom: tableFooterHeight - 1,
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
position: 'sticky',
zIndex: 1,
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)),
})}
>
{getBottomRows().map((row, staticRowIndex) => {
const props = {
...commonRowProps,
row,
staticRowIndex,
};
return memoMode === 'rows' ? (
<Memo_DataTable_TableBodyRow key={row.id} {...props} />
) : (
<DataTable_TableBodyRow key={row.id} {...props} />
);
})}
</TableBody>
)}
</>
);
}
export default DataTable_TableBody
export const Memo_DataTable_TableBody = memo(
DataTable_TableBody,
(prev, next) => prev.table.options.data === next.table.options.data,
);

View File

@@ -0,0 +1,307 @@
import { isCellEditable } from "material-react-table";
const { parseFromValuesOrFunc, getCommonMRTCellStyles } = require("@/core/utils/utils");
const { useTheme } = require("@emotion/react");
const { TableCell, Skeleton } = require("@mui/material");
const { useState, useEffect, useMemo, memo } = require("react");
const { default: DataTable_CopyButton } = require("../buttons/CopyButton");
const { default: DataTable_TableBodyCellValue } = require("./TableBodyCellValue");
const DataTable_TableBodyCell = ({
cell,
numRows,
rowRef,
staticColumnIndex,
staticRowIndex,
table,
...rest
}) => {
const theme = useTheme();
const {
getState,
options: {
columnResizeDirection,
columnResizeMode,
createDisplayMode,
editDisplayMode,
enableCellActions,
enableClickToCopy,
enableColumnOrdering,
enableColumnPinning,
enableGrouping,
layoutMode,
mrtTheme: { draggingBorderColor },
muiSkeletonProps,
muiTableBodyCellProps,
},
setHoveredColumn,
} = table;
const {
actionCell,
columnSizingInfo,
creatingRow,
density,
draggingColumn,
draggingRow,
editingCell,
editingRow,
hoveredColumn,
hoveredRow,
isLoading,
showSkeletons,
} = getState();
const { column, row } = cell;
const { columnDef } = column;
const { columnDefType } = columnDef;
const args = { cell, column, row, table };
const tableCellProps = {
...parseFromValuesOrFunc(muiTableBodyCellProps, args),
...parseFromValuesOrFunc(columnDef.muiTableBodyCellProps, args),
...rest,
};
const skeletonProps = parseFromValuesOrFunc(muiSkeletonProps, {
cell,
column,
row,
table,
});
const [skeletonWidth, setSkeletonWidth] = useState(100);
useEffect(() => {
if ((!isLoading && !showSkeletons) || skeletonWidth !== 100) return;
const size = column.getSize();
setSkeletonWidth(
columnDefType === 'display'
? size / 2
: Math.round(Math.random() * (size - size / 3) + size / 3),
);
}, [isLoading, showSkeletons]);
const draggingBorders = useMemo(() => {
const isDraggingColumn = draggingColumn?.id === column.id;
const isHoveredColumn = hoveredColumn?.id === column.id;
const isDraggingRow = draggingRow?.id === row.id;
const isHoveredRow = hoveredRow?.id === row.id;
const isFirstColumn = column.getIsFirstColumn();
const isLastColumn = column.getIsLastColumn();
const isLastRow = numRows && staticRowIndex === numRows - 1;
const isResizingColumn = columnSizingInfo.isResizingColumn === column.id;
const showResizeBorder =
isResizingColumn && columnResizeMode === 'onChange';
const borderStyle = showResizeBorder
? `2px solid ${draggingBorderColor} !important`
: isDraggingColumn || isDraggingRow
? `1px dashed ${theme.palette.grey[500]} !important`
: isHoveredColumn || isHoveredRow || isResizingColumn
? `2px dashed ${draggingBorderColor} !important`
: undefined;
if (showResizeBorder) {
return columnResizeDirection === 'ltr'
? { borderRight: borderStyle }
: { borderLeft: borderStyle };
}
return borderStyle
? {
borderBottom:
isDraggingRow || isHoveredRow || (isLastRow && !isResizingColumn)
? borderStyle
: undefined,
borderLeft:
isDraggingColumn ||
isHoveredColumn ||
((isDraggingRow || isHoveredRow) && isFirstColumn)
? borderStyle
: undefined,
borderRight:
isDraggingColumn ||
isHoveredColumn ||
((isDraggingRow || isHoveredRow) && isLastColumn)
? borderStyle
: undefined,
borderTop: isDraggingRow || isHoveredRow ? borderStyle : undefined,
}
: undefined;
}, [
columnSizingInfo.isResizingColumn,
draggingColumn,
draggingRow,
hoveredColumn,
hoveredRow,
staticRowIndex,
]);
const isColumnPinned =
enableColumnPinning &&
columnDef.columnDefType !== 'group' &&
column.getIsPinned();
const isEditable = isCellEditable({ cell, table });
const isEditing =
isEditable &&
!['custom', 'modal'].includes(editDisplayMode) &&
(editDisplayMode === 'table' ||
editingRow?.id === row.id ||
editingCell?.id === cell.id) &&
!row.getIsGrouped();
const isCreating =
isEditable && createDisplayMode === 'row' && creatingRow?.id === row.id;
const showClickToCopyButton =
(parseFromValuesOrFunc(enableClickToCopy, cell) === true ||
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) === true) &&
!['context-menu', false].includes(
// @ts-ignore
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell),
);
const isRightClickable = parseFromValuesOrFunc(enableCellActions, cell);
const cellValueProps = {
cell,
table,
};
const handleDoubleClick = (event) => {
tableCellProps?.onDoubleClick?.(event);
openEditingCell({ cell, table });
};
const handleDragEnter = (e) => {
tableCellProps?.onDragEnter?.(e);
if (enableGrouping && hoveredColumn?.id === 'drop-zone') {
setHoveredColumn(null);
}
if (enableColumnOrdering && draggingColumn) {
setHoveredColumn(
columnDef.enableColumnOrdering !== false ? column : null,
);
}
};
const handleDragOver = (e) => {
if (columnDef.enableColumnOrdering !== false) {
e.preventDefault();
}
};
const handleContextMenu = (e) => {
tableCellProps?.onContextMenu?.(e);
if (isRightClickable) {
e.preventDefault();
table.setActionCell(cell);
table.refs.actionCellRef.current = e.currentTarget;
}
};
return (
<TableCell
align={theme.direction === 'rtl' ? 'right' : 'left'}
data-index={staticColumnIndex}
data-pinned={!!isColumnPinned || undefined}
{...tableCellProps}
onContextMenu={handleContextMenu}
onDoubleClick={handleDoubleClick}
onDragEnter={handleDragEnter}
onDragOver={handleDragOver}
sx={(theme) => ({
'&:hover': {
outline:
actionCell?.id === cell.id ||
(editDisplayMode === 'cell' && isEditable) ||
(editDisplayMode === 'table' && (isCreating || isEditing))
? `1px solid ${theme.palette.grey[500]}`
: undefined,
textOverflow: 'clip',
},
alignItems: layoutMode?.startsWith('grid') ? 'center' : undefined,
cursor: isRightClickable
? 'context-menu'
: isEditable && editDisplayMode === 'cell'
? 'pointer'
: 'inherit',
outline:
actionCell?.id === cell.id
? `1px solid ${theme.palette.grey[500]}`
: undefined,
outlineOffset: '-1px',
overflow: 'hidden',
p:
density === 'compact'
? columnDefType === 'display'
? '0 0.5rem'
: '0.5rem'
: density === 'comfortable'
? columnDefType === 'display'
? '0.5rem 0.75rem'
: '1rem'
: columnDefType === 'display'
? '1rem 1.25rem'
: '1.5rem',
textOverflow: columnDefType !== 'display' ? 'ellipsis' : undefined,
whiteSpace:
row.getIsPinned() || density === 'compact' ? 'nowrap' : 'normal',
...getCommonMRTCellStyles({
column,
table,
tableCellProps,
theme,
}),
...draggingBorders,
})}
>
{tableCellProps.children ?? (
<>
{cell.getIsPlaceholder() ? (
columnDef.PlaceholderCell?.({ cell, column, row, table }) ?? null
) : showSkeletons !== false && (isLoading || showSkeletons) ? (
<Skeleton
animation="wave"
height={20}
width={skeletonWidth}
{...skeletonProps}
/>
) : columnDefType === 'display' &&
(['mrt-row-expand', 'mrt-row-numbers', 'mrt-row-select'].includes(
column.id,
) ||
!row.getIsGrouped()) ? (
columnDef.Cell?.({
cell,
column,
renderedCellValue: cell.renderValue(),
row,
rowRef,
staticColumnIndex,
staticRowIndex,
table,
})
) : showClickToCopyButton && columnDef.enableClickToCopy !== false ? (
<DataTable_CopyButton cell={cell} table={table}>
<DataTable_TableBodyCellValue {...cellValueProps} />
</DataTable_CopyButton>
) : (
<DataTable_TableBodyCellValue {...cellValueProps} />
)}
{cell.getIsGrouped() && !columnDef.GroupedCell && (
<> ({row.subRows?.length})</>
)}
</>
)}
</TableCell>
);
}
export default DataTable_TableBodyCell;
export const Memo_DataTable_TableBodyCell = memo(
DataTable_TableBodyCell,
(prev, next) => next.cell === prev.cell,
);

View File

@@ -0,0 +1,112 @@
import { Box } from "@mui/material";
const allowedTypes = ["string", "number"];
const DataTable_TableBodyCellValue = ({
cell,
rowRef,
staticColumnIndex,
staticRowIndex,
table,
}) => {
const {
getState,
options: {
enableFilterMatchHighlighting,
mrtTheme: { matchHighlightColor },
},
} = table;
const { column, row } = cell;
const { columnDef } = column;
const { globalFilter, globalFilterFn } = getState();
const filterValue = column.getFilterValue();
let renderedCellValue =
cell.getIsAggregated() && columnDef.AggregatedCell
? columnDef.AggregatedCell({
cell,
column,
row,
table,
})
: row.getIsGrouped() && !cell.getIsGrouped()
? null
: cell.getIsGrouped() && columnDef.GroupedCell
? columnDef.GroupedCell({
cell,
column,
row,
table,
})
: undefined;
const isGroupedValue = renderedCellValue !== undefined;
if (!isGroupedValue) {
renderedCellValue = cell.renderValue();
}
if (
enableFilterMatchHighlighting &&
columnDef.enableFilterMatchHighlighting !== false &&
String(renderedCellValue) &&
allowedTypes.includes(typeof renderedCellValue) &&
((filterValue &&
allowedTypes.includes(typeof filterValue) &&
["autocomplete", "text"].includes(columnDef.filterVariant)) ||
(globalFilter &&
allowedTypes.includes(typeof globalFilter) &&
column.getCanGlobalFilter()))
) {
const chunks = highlightWords?.({
matchExactly:
(filterValue ? columnDef._filterFn : globalFilterFn) !== "fuzzy",
query: (filterValue ?? globalFilter ?? "").toString(),
text: renderedCellValue?.toString(),
});
if (chunks?.length > 1 || chunks?.[0]?.match) {
renderedCellValue = (
<span aria-label={renderedCellValue} role="note">
{chunks?.map(({ key, match, text }) => (
<Box
aria-hidden="true"
component="span"
key={key}
sx={
match
? {
backgroundColor: matchHighlightColor,
borderRadius: "2px",
color: (theme) =>
theme.palette.mode === "dark"
? theme.palette.common.white
: theme.palette.common.black,
padding: "2px 1px",
}
: undefined
}
>
{text}
</Box>
)) ?? renderedCellValue}
</span>
);
}
}
if (columnDef.Cell && !isGroupedValue) {
renderedCellValue = columnDef.Cell({
cell,
column,
renderedCellValue,
row,
rowRef,
staticColumnIndex,
staticRowIndex,
table,
});
}
return renderedCellValue;
};
export default DataTable_TableBodyCellValue;

View File

@@ -0,0 +1,254 @@
import { commonCellBeforeAfterStyles, getCommonPinnedCellStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
import { useTheme } from "@emotion/react";
import { TableRow, alpha, darken, lighten } from "@mui/material";
import { getIsRowSelected } from "material-react-table";
import { memo, useMemo, useRef } from "react";
import DataTable_TableBodyCell, { Memo_DataTable_TableBodyCell } from "./TableBodyCell";
import DataTable_TableDetailPanel from "./TableDetailPanel";
const DataTable_TableBodyRow = ({
columnVirtualizer,
numRows,
pinnedRowIds,
row,
rowVirtualizer,
staticRowIndex,
table,
virtualRow,
...rest
}) => {
const theme = useTheme();
const {
getState,
options: {
enableRowOrdering,
enableRowPinning,
enableStickyFooter,
enableStickyHeader,
layoutMode,
memoMode,
mrtTheme: {
baseBackgroundColor,
pinnedRowBackgroundColor,
selectedRowBackgroundColor,
},
muiTableBodyRowProps,
renderDetailPanel,
rowPinningDisplayMode,
},
refs: { tableFooterRef, tableHeadRef },
setHoveredRow,
} = table;
const {
density,
draggingColumn,
draggingRow,
editingCell,
editingRow,
hoveredRow,
isFullScreen,
rowPinning,
} = getState();
const visibleCells = row.getVisibleCells();
const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } =
columnVirtualizer ?? {};
const isRowSelected = getIsRowSelected({ row, table });
const isRowPinned = enableRowPinning && row.getIsPinned();
const isDraggingRow = draggingRow?.id === row.id;
const isHoveredRow = hoveredRow?.id === row.id;
const tableRowProps = {
...parseFromValuesOrFunc(muiTableBodyRowProps, {
row,
staticRowIndex,
table,
}),
...rest,
};
const [bottomPinnedIndex, topPinnedIndex] = useMemo(() => {
if (
!enableRowPinning ||
!rowPinningDisplayMode?.includes('sticky') ||
!pinnedRowIds ||
!row.getIsPinned()
)
return [];
return [
[...pinnedRowIds].reverse().indexOf(row.id),
pinnedRowIds.indexOf(row.id),
];
}, [pinnedRowIds, rowPinning]);
const tableHeadHeight =
((enableStickyHeader || isFullScreen) &&
tableHeadRef.current?.clientHeight) ||
0;
const tableFooterHeight =
(enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;
const sx = parseFromValuesOrFunc(tableRowProps?.sx, theme);
const defaultRowHeight =
density === 'compact' ? 37 : density === 'comfortable' ? 53 : 69;
const customRowHeight =
// @ts-ignore
parseInt(tableRowProps?.style?.height ?? sx?.height, 10) || undefined;
const rowHeight = customRowHeight || defaultRowHeight;
const handleDragEnter = (_e) => {
if (enableRowOrdering && draggingRow) {
setHoveredRow(row);
}
};
const handleDragOver = (e) => {
e.preventDefault();
};
const rowRef = useRef(null);
const cellHighlightColor = isRowSelected
? selectedRowBackgroundColor
: isRowPinned
? pinnedRowBackgroundColor
: undefined;
const cellHighlightColorHover =
tableRowProps?.hover !== false
? isRowSelected
? cellHighlightColor
: theme.palette.mode === 'dark'
? `${lighten(baseBackgroundColor, 0.3)}`
: `${darken(baseBackgroundColor, 0.3)}`
: undefined;
return (
<>
<TableRow
data-index={renderDetailPanel ? staticRowIndex * 2 : staticRowIndex}
data-pinned={!!isRowPinned || undefined}
data-selected={isRowSelected || undefined}
onDragEnter={handleDragEnter}
onDragOver={handleDragOver}
ref={(node) => {
if (node) {
rowRef.current = node;
rowVirtualizer?.measureElement(node);
}
}}
selected={isRowSelected}
{...tableRowProps}
style={{
transform: virtualRow
? `translateY(${virtualRow.start}px)`
: undefined,
...tableRowProps?.style,
}}
sx={(theme) => ({
'&:hover td:after': cellHighlightColorHover
? {
backgroundColor: alpha(cellHighlightColorHover, 0.3),
...commonCellBeforeAfterStyles,
}
: undefined,
backgroundColor: `${baseBackgroundColor} !important`,
bottom:
!virtualRow && bottomPinnedIndex !== undefined && isRowPinned
? `${bottomPinnedIndex * rowHeight +
(enableStickyFooter ? tableFooterHeight - 1 : 0)
}px`
: undefined,
boxSizing: 'border-box',
display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
opacity: isRowPinned ? 0.97 : isDraggingRow || isHoveredRow ? 0.5 : 1,
position: virtualRow
? 'absolute'
: rowPinningDisplayMode?.includes('sticky') && isRowPinned
? 'sticky'
: 'relative',
td: {
...getCommonPinnedCellStyles({ table, theme }),
},
'td:after': cellHighlightColor
? {
backgroundColor: cellHighlightColor,
...commonCellBeforeAfterStyles,
}
: undefined,
top: virtualRow
? 0
: topPinnedIndex !== undefined && isRowPinned
? `${topPinnedIndex * rowHeight +
(enableStickyHeader || isFullScreen ? tableHeadHeight - 1 : 0)
}px`
: undefined,
transition: virtualRow ? 'none' : 'all 150ms ease-in-out',
width: '100%',
zIndex:
rowPinningDisplayMode?.includes('sticky') && isRowPinned ? 2 : 0,
...(sx),
})}
>
{virtualPaddingLeft ? (
<td style={{ display: 'flex', width: virtualPaddingLeft }} />
) : null}
{(virtualColumns ?? visibleCells).map(
(cellOrVirtualCell, staticColumnIndex) => {
let cell = cellOrVirtualCell;
if (columnVirtualizer) {
staticColumnIndex = (cellOrVirtualCell).index;
cell = visibleCells[staticColumnIndex];
}
const props = {
cell,
numRows,
rowRef,
staticColumnIndex,
staticRowIndex,
table,
};
return cell ? (
memoMode === 'cells' &&
cell.column.columnDef.columnDefType === 'data' &&
!draggingColumn &&
!draggingRow &&
editingCell?.id !== cell.id &&
editingRow?.id !== row.id ? (
<Memo_DataTable_TableBodyCell key={cell.id} {...props} />
) : (
<DataTable_TableBodyCell key={cell.id} {...props} />
)
) : null;
},
)}
{virtualPaddingRight ? (
<td style={{ display: 'flex', width: virtualPaddingRight }} />
) : null}
</TableRow>
{renderDetailPanel && !row.getIsGrouped() && (
<DataTable_TableDetailPanel
parentRowRef={rowRef}
row={row}
rowVirtualizer={rowVirtualizer}
staticRowIndex={staticRowIndex}
table={table}
virtualRow={virtualRow}
/>
)}
</>
);
}
export default DataTable_TableBodyRow
export const Memo_DataTable_TableBodyRow = memo(
DataTable_TableBodyRow,
(prev, next) =>
prev.row === next.row && prev.staticRowIndex === next.staticRowIndex,
);

View File

@@ -0,0 +1,93 @@
import { parseFromValuesOrFunc } from "@/core/utils/utils";
import { Collapse, TableCell, TableRow } from "@mui/material";
const DataTable_TableDetailPanel = ({
parentRowRef,
row,
rowVirtualizer,
staticRowIndex,
table,
virtualRow,
...rest
}) => {
const {
getState,
getVisibleLeafColumns,
options: {
layoutMode,
mrtTheme: { baseBackgroundColor },
muiDetailPanelProps,
muiTableBodyRowProps,
renderDetailPanel,
},
} = table;
const { isLoading } = getState();
const tableRowProps = parseFromValuesOrFunc(muiTableBodyRowProps, {
isDetailPanel: true,
row,
staticRowIndex,
table,
});
const tableCellProps = {
...parseFromValuesOrFunc(muiDetailPanelProps, {
row,
table,
}),
...rest,
};
const DetailPanel = !isLoading && renderDetailPanel?.({ row, table });
return (
<TableRow
className="Mui-TableBodyCell-DetailPanel"
data-index={renderDetailPanel ? staticRowIndex * 2 + 1 : staticRowIndex}
ref={(node) => {
if (node) {
rowVirtualizer?.measureElement?.(node);
}
}}
{...tableRowProps}
sx={(theme) => ({
display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
position: virtualRow ? 'absolute' : undefined,
top: virtualRow
? `${parentRowRef.current?.getBoundingClientRect()?.height}px`
: undefined,
transform: virtualRow
? `translateY(${virtualRow?.start}px)`
: undefined,
width: '100%',
...(parseFromValuesOrFunc(tableRowProps?.sx, theme)),
})}
>
<TableCell
className="Mui-TableBodyCell-DetailPanel"
colSpan={getVisibleLeafColumns().length}
{...tableCellProps}
sx={(theme) => ({
backgroundColor: virtualRow ? baseBackgroundColor : undefined,
borderBottom: !row.getIsExpanded() ? 'none' : undefined,
display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
py: !!DetailPanel && row.getIsExpanded() ? '1rem' : 0,
transition: !virtualRow ? 'all 150ms ease-in-out' : undefined,
width: `100%`,
...(parseFromValuesOrFunc(tableCellProps?.sx, theme)),
})}
>
{virtualRow ? (
row.getIsExpanded() && DetailPanel
) : (
<Collapse in={row.getIsExpanded()} mountOnEnter unmountOnExit>
{DetailPanel}
</Collapse>
)}
</TableCell>
</TableRow>
);
}
export default DataTable_TableDetailPanel