diff --git a/package.json b/package.json
index 3855313..3e7a01c 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
"next": "14.1.0",
"react": "^18",
"react-dom": "^18",
- "sass": "^1.70.0",
+ "sass": "^1.75.0",
"stylis": "^4.3.1",
"stylis-plugin-rtl": "^2.1.1"
},
diff --git a/src/core/components/DataTable/body/TableBody.js b/src/core/components/DataTable/body/TableBody.js
new file mode 100644
index 0000000..e1620a3
--- /dev/null
+++ b/src/core/components/DataTable/body/TableBody.js
@@ -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') && (
+ ({
+ 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' ? (
+
+ ) : (
+
+ );
+ })}
+
+ )}
+ ({
+ 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 ? (
+
+ |
+ {renderEmptyRowsFallback?.({ table }) ?? (
+
+ {globalFilter || columnFilters.length
+ ? localization.noResultsFound
+ : localization.noRecordsToDisplay}
+
+ )}
+ |
+
+ ) : (
+ <>
+ {(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' ? (
+
+ ) : (
+
+ );
+ })}
+ >
+ ))}
+
+ {!rowPinningDisplayMode?.includes('sticky') &&
+ getIsSomeRowsPinned('bottom') && (
+ ({
+ 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' ? (
+
+ ) : (
+
+ );
+ })}
+
+ )}
+ >
+ );
+
+}
+export default DataTable_TableBody
+
+export const Memo_DataTable_TableBody = memo(
+ DataTable_TableBody,
+ (prev, next) => prev.table.options.data === next.table.options.data,
+);
\ No newline at end of file
diff --git a/src/core/components/DataTable/body/TableBodyCell.js b/src/core/components/DataTable/body/TableBodyCell.js
new file mode 100644
index 0000000..93c9631
--- /dev/null
+++ b/src/core/components/DataTable/body/TableBodyCell.js
@@ -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 (
+ ({
+ '&: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) ? (
+
+ ) : 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 ? (
+
+
+
+ ) : (
+
+ )}
+ {cell.getIsGrouped() && !columnDef.GroupedCell && (
+ <> ({row.subRows?.length})>
+ )}
+ >
+ )}
+
+ );
+
+}
+export default DataTable_TableBodyCell;
+
+export const Memo_DataTable_TableBodyCell = memo(
+ DataTable_TableBodyCell,
+ (prev, next) => next.cell === prev.cell,
+);
\ No newline at end of file
diff --git a/src/core/components/DataTable/body/TableBodyCellValue.js b/src/core/components/DataTable/body/TableBodyCellValue.js
new file mode 100644
index 0000000..6d4f05f
--- /dev/null
+++ b/src/core/components/DataTable/body/TableBodyCellValue.js
@@ -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 = (
+
+ {chunks?.map(({ key, match, text }) => (
+
+ theme.palette.mode === "dark"
+ ? theme.palette.common.white
+ : theme.palette.common.black,
+ padding: "2px 1px",
+ }
+ : undefined
+ }
+ >
+ {text}
+
+ )) ?? renderedCellValue}
+
+ );
+ }
+ }
+
+ if (columnDef.Cell && !isGroupedValue) {
+ renderedCellValue = columnDef.Cell({
+ cell,
+ column,
+ renderedCellValue,
+ row,
+ rowRef,
+ staticColumnIndex,
+ staticRowIndex,
+ table,
+ });
+ }
+
+ return renderedCellValue;
+};
+export default DataTable_TableBodyCellValue;
diff --git a/src/core/components/DataTable/body/TableBodyRow.js b/src/core/components/DataTable/body/TableBodyRow.js
new file mode 100644
index 0000000..e500eb0
--- /dev/null
+++ b/src/core/components/DataTable/body/TableBodyRow.js
@@ -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 (
+ <>
+ {
+ 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 ? (
+ |
+ ) : 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 ? (
+
+ ) : (
+
+ )
+ ) : null;
+ },
+ )}
+ {virtualPaddingRight ? (
+ |
+ ) : null}
+
+ {renderDetailPanel && !row.getIsGrouped() && (
+
+ )}
+ >
+ );
+}
+export default DataTable_TableBodyRow
+
+export const Memo_DataTable_TableBodyRow = memo(
+ DataTable_TableBodyRow,
+ (prev, next) =>
+ prev.row === next.row && prev.staticRowIndex === next.staticRowIndex,
+);
\ No newline at end of file
diff --git a/src/core/components/DataTable/body/TableDetailPanel.js b/src/core/components/DataTable/body/TableDetailPanel.js
new file mode 100644
index 0000000..0c9f8a9
--- /dev/null
+++ b/src/core/components/DataTable/body/TableDetailPanel.js
@@ -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 (
+ {
+ 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)),
+ })}
+ >
+ ({
+ 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
+ ) : (
+
+ {DetailPanel}
+
+ )}
+
+
+ );
+
+}
+export default DataTable_TableDetailPanel
\ No newline at end of file
diff --git a/src/core/components/DataTable/buttons/CopyButton.js b/src/core/components/DataTable/buttons/CopyButton.js
new file mode 100644
index 0000000..0ffe871
--- /dev/null
+++ b/src/core/components/DataTable/buttons/CopyButton.js
@@ -0,0 +1,74 @@
+import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Button, Tooltip } from "@mui/material";
+
+const DataTable_CopyButton = ({
+ cell,
+ table,
+ ...rest
+}) => {
+ const {
+ options: { localization, muiCopyButtonProps },
+ } = table;
+ const { column, row } = cell;
+ const { columnDef } = column;
+
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = (event, text) => {
+ event.stopPropagation();
+ navigator.clipboard.writeText(text);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 4000);
+ };
+
+ const buttonProps = {
+ ...parseFromValuesOrFunc(muiCopyButtonProps, {
+ cell,
+ column,
+ row,
+ table,
+ }),
+ ...parseFromValuesOrFunc(columnDef.muiCopyButtonProps, {
+ cell,
+ column,
+ row,
+ table,
+ }),
+ ...rest,
+ };
+
+ return (
+
+
+ );
+}
+export default DataTable_CopyButton
\ No newline at end of file
diff --git a/src/core/components/DataTable/buttons/GrabHandleButton.js b/src/core/components/DataTable/buttons/GrabHandleButton.js
new file mode 100644
index 0000000..5619abb
--- /dev/null
+++ b/src/core/components/DataTable/buttons/GrabHandleButton.js
@@ -0,0 +1,54 @@
+import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { IconButton, Tooltip } from "@mui/material";
+
+const DataTable_GrabHandleButton = ({
+ location,
+ table,
+ ...rest
+}) => {
+ const {
+ options: {
+ icons: { DragHandleIcon },
+ localization,
+ },
+ } = table;
+
+ return (
+
+ {
+ e.stopPropagation();
+ rest?.onClick?.(e);
+ }}
+ sx={(theme) => ({
+ '&:active': {
+ cursor: 'grabbing',
+ },
+ '&:hover': {
+ backgroundColor: 'transparent',
+ opacity: 1,
+ },
+ cursor: 'grab',
+ m: '0 -0.1rem',
+ opacity: location === 'row' ? 1 : 0.5,
+ p: '2px',
+ transition: 'all 150ms ease-in-out',
+ ...(parseFromValuesOrFunc(rest?.sx, theme)),
+ })}
+ title={undefined}
+ >
+
+
+
+ );
+
+}
+export default DataTable_GrabHandleButton
\ No newline at end of file
diff --git a/src/core/components/DataTable/buttons/ShowHideColumnsButton.js b/src/core/components/DataTable/buttons/ShowHideColumnsButton.js
new file mode 100644
index 0000000..d46281e
--- /dev/null
+++ b/src/core/components/DataTable/buttons/ShowHideColumnsButton.js
@@ -0,0 +1,41 @@
+import { IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import DataTable_ShowHideColumnsMenu from "../menus/ShowHideColumnsMenu";
+
+const DataTable_ShowHideColumnsButton = ({ table, ...rest }) => {
+ const {
+ options: {
+ icons: { ViewColumnIcon },
+ localization,
+ },
+ } = table;
+
+ const [anchorEl, setAnchorEl] = useState(null);
+
+ const handleClick = (event) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {anchorEl && (
+
+ )}
+ >
+ );
+}
+export default DataTable_ShowHideColumnsButton
\ No newline at end of file
diff --git a/src/core/components/DataTable/buttons/ToggleFiltersButton.js b/src/core/components/DataTable/buttons/ToggleFiltersButton.js
new file mode 100644
index 0000000..9885183
--- /dev/null
+++ b/src/core/components/DataTable/buttons/ToggleFiltersButton.js
@@ -0,0 +1,4 @@
+const DataTable_ToggleFiltersButton = ({ table, ...rest }) => {
+ return <>>
+}
+export default DataTable_ToggleFiltersButton
\ No newline at end of file
diff --git a/src/core/components/DataTable/head/TableHead.js b/src/core/components/DataTable/head/TableHead.js
new file mode 100644
index 0000000..055a4ed
--- /dev/null
+++ b/src/core/components/DataTable/head/TableHead.js
@@ -0,0 +1,63 @@
+import { parseFromValuesOrFunc } from "@/core/utils/utils";
+import { TableHead } from "@mui/material";
+import DataTable_TableHeadRow from "./TableHeadRow";
+
+const DataTable_TableHead = ({
+ columnVirtualizer,
+ table,
+ ...rest
+}) => {
+ const {
+ getState,
+ options: {
+ enableStickyHeader,
+ layoutMode,
+ muiTableHeadProps,
+ positionToolbarAlertBanner,
+ },
+ refs: { tableHeadRef },
+ } = table;
+ const { isFullScreen, showAlertBanner } = getState();
+
+ const tableHeadProps = {
+ ...parseFromValuesOrFunc(muiTableHeadProps, { table }),
+ ...rest,
+ };
+
+ const stickyHeader = enableStickyHeader || isFullScreen;
+
+ return (
+ {
+ tableHeadRef.current = ref;
+ if (tableHeadProps?.ref) {
+ // @ts-ignore
+ tableHeadProps.ref.current = ref;
+ }
+ }}
+ sx={(theme) => ({
+ display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
+ opacity: 0.97,
+ position: stickyHeader ? 'sticky' : 'relative',
+ top: stickyHeader && layoutMode?.startsWith('grid') ? 0 : undefined,
+ zIndex: stickyHeader ? 2 : undefined,
+ ...(parseFromValuesOrFunc(tableHeadProps?.sx, theme)),
+ })}
+ >
+ {table
+ .getHeaderGroups()
+ .map((headerGroup) => (
+
+ ))
+ }
+
+ );
+
+}
+export default DataTable_TableHead
\ No newline at end of file
diff --git a/src/core/components/DataTable/head/TableHeadCell.js b/src/core/components/DataTable/head/TableHeadCell.js
new file mode 100644
index 0000000..d7daaeb
--- /dev/null
+++ b/src/core/components/DataTable/head/TableHeadCell.js
@@ -0,0 +1,284 @@
+import { getCommonMRTCellStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { useTheme } from "@emotion/react";
+import { Box, TableCell } from "@mui/material";
+import { MRT_TableHeadCellSortLabel } from "material-react-table";
+import { useMemo } from "react";
+
+const DataTable_TableHeadCell = ({
+ columnVirtualizer,
+ header,
+ staticColumnIndex,
+ table,
+ ...rest
+}) => {
+ const theme = useTheme();
+ const {
+ getState,
+ options: {
+ columnResizeDirection,
+ columnResizeMode,
+ enableColumnActions,
+ enableColumnDragging,
+ enableColumnOrdering,
+ enableColumnPinning,
+ enableGrouping,
+ enableMultiSort,
+ layoutMode,
+ mrtTheme: { draggingBorderColor },
+ muiTableHeadCellProps,
+ },
+ refs: { tableHeadCellRefs },
+ setHoveredColumn,
+ } = table;
+ const {
+ columnSizingInfo,
+ density,
+ draggingColumn,
+ grouping,
+ hoveredColumn,
+ showColumnFilters,
+ } = getState();
+ const { column } = header;
+ const { columnDef } = column;
+ const { columnDefType } = columnDef;
+
+ const tableCellProps = {
+ ...parseFromValuesOrFunc(muiTableHeadCellProps, { column, table }),
+ ...parseFromValuesOrFunc(columnDef.muiTableHeadCellProps, {
+ column,
+ table,
+ }),
+ ...rest,
+ };
+
+ const isColumnPinned =
+ enableColumnPinning &&
+ columnDef.columnDefType !== 'group' &&
+ column.getIsPinned();
+
+ const showColumnActions =
+ (enableColumnActions || columnDef.enableColumnActions) &&
+ columnDef.enableColumnActions !== false;
+
+ const showDragHandle =
+ enableColumnDragging !== false &&
+ columnDef.enableColumnDragging !== false &&
+ (enableColumnDragging ||
+ (enableColumnOrdering && columnDef.enableColumnOrdering !== false) ||
+ (enableGrouping &&
+ columnDef.enableGrouping !== false &&
+ !grouping.includes(column.id)));
+
+ const headerPL = useMemo(() => {
+ let pl = 0;
+ if (column.getCanSort()) pl += 1;
+ if (showColumnActions) pl += 1.75;
+ if (showDragHandle) pl += 1.5;
+ return pl;
+ }, [showColumnActions, showDragHandle]);
+
+ const draggingBorders = useMemo(() => {
+ const showResizeBorder =
+ columnSizingInfo.isResizingColumn === column.id &&
+ columnResizeMode === 'onChange' &&
+ !header.subHeaders.length;
+
+ const borderStyle = showResizeBorder
+ ? `2px solid ${draggingBorderColor} !important`
+ : draggingColumn?.id === column.id
+ ? `1px dashed ${theme.palette.grey[500]}`
+ : hoveredColumn?.id === column.id
+ ? `2px dashed ${draggingBorderColor}`
+ : undefined;
+
+ if (showResizeBorder) {
+ return columnResizeDirection === 'ltr'
+ ? { borderRight: borderStyle }
+ : { borderLeft: borderStyle };
+ }
+ const draggingBorders = borderStyle
+ ? {
+ borderLeft: borderStyle,
+ borderRight: borderStyle,
+ borderTop: borderStyle,
+ }
+ : undefined;
+
+ return draggingBorders;
+ }, [draggingColumn, hoveredColumn, columnSizingInfo.isResizingColumn]);
+
+ const handleDragEnter = (_e) => {
+ if (enableGrouping && hoveredColumn?.id === 'drop-zone') {
+ setHoveredColumn(null);
+ }
+ if (enableColumnOrdering && draggingColumn && columnDefType !== 'group') {
+ setHoveredColumn(
+ columnDef.enableColumnOrdering !== false ? column : null,
+ );
+ }
+ };
+
+ const handleDragOver = (e) => {
+ if (columnDef.enableColumnOrdering !== false) {
+ e.preventDefault();
+ }
+ };
+
+
+ const HeaderElement =
+ parseFromValuesOrFunc(columnDef.Header, {
+ column,
+ header,
+ table,
+ }) ?? columnDef.header;
+
+
+ const columnRelativeDepth = header.depth - column.depth;
+
+ if (
+ columnRelativeDepth > 1
+ ) {
+ return null;
+ }
+
+ let rowSpan = 1;
+ if (header.isPlaceholder) {
+ const leafs = header.getLeafHeaders();
+ rowSpan = leafs[leafs.length - 1].depth - header.depth;
+ }
+
+ return (
+ {
+ if (node) {
+ tableHeadCellRefs.current[column.id] = node;
+ if (columnDefType !== 'group') {
+ columnVirtualizer?.measureElement?.(node);
+ }
+ }
+ }}
+ {...tableCellProps}
+ sx={(theme) => ({
+ '& :hover': {
+ '.MuiButtonBase-root': {
+ opacity: 1,
+ },
+ },
+ border: 1,
+ flexDirection: layoutMode?.startsWith('grid') ? 'column' : undefined,
+ fontWeight: 'bold',
+ overflow: 'visible',
+ p:
+ density === 'compact'
+ ? '0.5rem'
+ : density === 'comfortable'
+ ? columnDefType === 'display'
+ ? '0.75rem'
+ : '1rem'
+ : columnDefType === 'display'
+ ? '1rem 1.25rem'
+ : '1.5rem',
+ pb:
+ columnDefType === 'display'
+ ? 0
+ : showColumnFilters || density === 'compact'
+ ? '0.4rem'
+ : '0.6rem',
+ pt:
+ columnDefType === 'group' || density === 'compact'
+ ? '0.25rem'
+ : density === 'comfortable'
+ ? '.75rem'
+ : '1.25rem',
+ userSelect: enableMultiSort && column.getCanSort() ? 'none' : undefined,
+ verticalAlign: 'top',
+ ...getCommonMRTCellStyles({
+ column,
+ header,
+ table,
+ tableCellProps,
+ theme,
+ }),
+ ...draggingBorders,
+ }
+ )}
+ >
+ {tableCellProps.children ?? (
+
+
+
+ {HeaderElement}
+
+ {(column.getCanSort() && columnDefType !== 'group') && (
+
+ )}
+
+
+ )}
+
+ );
+
+}
+export default DataTable_TableHeadCell;
\ No newline at end of file
diff --git a/src/core/components/DataTable/head/TableHeadRow.js b/src/core/components/DataTable/head/TableHeadRow.js
new file mode 100644
index 0000000..f876cf1
--- /dev/null
+++ b/src/core/components/DataTable/head/TableHeadRow.js
@@ -0,0 +1,76 @@
+import { parseFromValuesOrFunc } from "@/core/utils/utils";
+import { TableRow } from "@mui/material";
+import DataTable_TableHeadCell from "./TableHeadCell";
+
+const DataTable_TableHeadRow = ({
+ columnVirtualizer,
+ headerGroup,
+ table,
+ ...rest
+}) => {
+ const {
+ options: {
+ enableStickyHeader,
+ layoutMode,
+ mrtTheme: { baseBackgroundColor },
+ muiTableHeadRowProps,
+ },
+ } = table;
+
+ const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } =
+ columnVirtualizer ?? {};
+
+ const tableRowProps = {
+ ...parseFromValuesOrFunc(muiTableHeadRowProps, {
+ headerGroup,
+ table,
+ }),
+ ...rest,
+ };
+
+ return (
+ ({
+ backgroundColor: baseBackgroundColor,
+ display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
+ position:
+ enableStickyHeader && layoutMode === 'semantic'
+ ? 'sticky'
+ : 'relative',
+ top: 0,
+ ...(parseFromValuesOrFunc(tableRowProps?.sx, theme)),
+ })}
+ >
+ {virtualPaddingLeft ? (
+ |
+ ) : null}
+ {(virtualColumns ?? headerGroup.headers).map(
+ (headerOrVirtualHeader, staticColumnIndex) => {
+ let header = headerOrVirtualHeader;
+
+ if (columnVirtualizer) {
+ staticColumnIndex = (headerOrVirtualHeader)
+ .index;
+ header = headerGroup.headers[staticColumnIndex];
+ }
+
+ return header ? (
+
+ ) : null;
+ },
+ )}
+ {virtualPaddingRight ? (
+ |
+ ) : null}
+
+ );
+
+}
+export default DataTable_TableHeadRow
\ No newline at end of file
diff --git a/src/core/components/DataTable/index.js b/src/core/components/DataTable/index.js
new file mode 100644
index 0000000..997e9f4
--- /dev/null
+++ b/src/core/components/DataTable/index.js
@@ -0,0 +1,19 @@
+import { useMaterialReactTable } from "material-react-table";
+import DataTable_Paper from "./table/Paper";
+
+const isTableInstanceProp = (props) => props.table !== undefined;
+
+const DataTable = (props) => {
+ let table;
+
+ if (isTableInstanceProp(props)) {
+ table = props.table;
+ } else {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ table = useMaterialReactTable(props);
+ }
+
+ return ;
+};
+
+export default DataTable;
diff --git a/src/core/components/DataTable/menus/ActionMenuItem.js b/src/core/components/DataTable/menus/ActionMenuItem.js
new file mode 100644
index 0000000..2b208b9
--- /dev/null
+++ b/src/core/components/DataTable/menus/ActionMenuItem.js
@@ -0,0 +1,50 @@
+import { Box, IconButton, ListItemIcon, MenuItem } from "@mui/material";
+
+const DataTable_ActionMenuItem = ({
+ icon,
+ label,
+ onOpenSubMenu,
+ table,
+ ...rest
+}) => {
+ const {
+ options: {
+ icons: { ArrowRightIcon },
+ },
+ } = table;
+
+ return (
+
+ );
+
+}
+export default DataTable_ActionMenuItem
\ No newline at end of file
diff --git a/src/core/components/DataTable/menus/CellActionMenu.js b/src/core/components/DataTable/menus/CellActionMenu.js
new file mode 100644
index 0000000..36638e0
--- /dev/null
+++ b/src/core/components/DataTable/menus/CellActionMenu.js
@@ -0,0 +1,100 @@
+import { parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Menu } from "@mui/material";
+import DataTable_ActionMenuItem from "./ActionMenuItem";
+
+const DataTable_CellActionMenu = ({
+ table,
+ ...rest
+}) => {
+ const {
+ getState,
+ options: {
+ editDisplayMode,
+ enableClickToCopy,
+ enableEditing,
+ icons: { ContentCopy, EditIcon },
+ localization,
+ mrtTheme: { menuBackgroundColor },
+ renderCellActionMenuItems,
+ },
+ refs: { actionCellRef },
+ } = table;
+ const { actionCell, density } = getState();
+ const cell = actionCell || null;
+ const { row } = cell;
+ const { column } = cell;
+ const { columnDef } = column;
+
+ const handleClose = (event) => {
+ event?.stopPropagation();
+ table.setActionCell(null);
+ actionCellRef.current = null;
+ };
+
+ const internalMenuItems = [
+ (parseFromValuesOrFunc(enableClickToCopy, cell) === 'context-menu' ||
+ parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) ===
+ 'context-menu') && (
+ }
+ key={'mrt-copy'}
+ label={localization.copy}
+ onClick={(event) => {
+ event.stopPropagation();
+ navigator.clipboard.writeText(cell.getValue());
+ handleClose();
+ }}
+ table={table}
+ />
+ ),
+ parseFromValuesOrFunc(enableEditing, row) && editDisplayMode === 'cell' && (
+ }
+ key={'mrt-edit'}
+ label={localization.edit}
+ onClick={() => {
+ openEditingCell({ cell, table });
+ handleClose();
+ }}
+ table={table}
+ />
+ ),
+ ].filter(Boolean);
+
+ const renderActionProps = {
+ cell,
+ closeMenu: handleClose,
+ column,
+ internalMenuItems,
+ row,
+ table,
+ };
+
+ const menuItems =
+ columnDef.renderCellActionMenuItems?.(renderActionProps) ??
+ renderCellActionMenuItems?.(renderActionProps);
+
+ return (
+ (!!menuItems?.length || !!internalMenuItems?.length) && (
+
+ )
+ );
+
+}
+export default DataTable_CellActionMenu
\ No newline at end of file
diff --git a/src/core/components/DataTable/menus/ShowHideColumnsMenu.js b/src/core/components/DataTable/menus/ShowHideColumnsMenu.js
new file mode 100644
index 0000000..12efae8
--- /dev/null
+++ b/src/core/components/DataTable/menus/ShowHideColumnsMenu.js
@@ -0,0 +1,140 @@
+import { Box, Button, Divider, Menu } from "@mui/material";
+import { useMemo, useState } from "react";
+import DataTable_ShowHideColumnsMenuItems from "./ShowHideColumnsMenuItems";
+
+const DataTable_ShowHideColumnsMenu = ({ anchorEl,
+ setAnchorEl,
+ table,
+ ...rest
+}) => {
+ const {
+ getAllColumns,
+ getAllLeafColumns,
+ getCenterLeafColumns,
+ getIsAllColumnsVisible,
+ getIsSomeColumnsPinned,
+ getIsSomeColumnsVisible,
+ getLeftLeafColumns,
+ getRightLeafColumns,
+ getState,
+ options: {
+ enableColumnOrdering,
+ enableColumnPinning,
+ enableHiding,
+ localization,
+ mrtTheme: { menuBackgroundColor },
+ },
+ } = table;
+
+ const { columnOrder, columnPinning, density } = getState();
+
+ const handleToggleAllColumns = (value) => {
+ getAllLeafColumns()
+ .filter((col) => col.columnDef.enableHiding !== false)
+ .forEach((col) => col.toggleVisibility(value));
+ };
+
+ const allColumns = useMemo(() => {
+ const columns = getAllColumns();
+ if (
+ columnOrder.length > 0 &&
+ !columns.some((col) => col.columnDef.columnDefType === 'group')
+ ) {
+ return [
+ ...getLeftLeafColumns(),
+ ...Array.from(new Set(columnOrder)).map((colId) =>
+ getCenterLeafColumns().find((col) => col?.id === colId),
+ ),
+ ...getRightLeafColumns(),
+ ].filter(Boolean);
+ }
+ return columns;
+ }, [
+ columnOrder,
+ columnPinning,
+ getAllColumns(),
+ getCenterLeafColumns(),
+ getLeftLeafColumns(),
+ getRightLeafColumns(),
+ ]);
+
+ const isNestedColumns = allColumns.some(
+ (col) => col.columnDef.columnDefType === 'group',
+ );
+
+ const [hoveredColumn, setHoveredColumn] = useState(null);
+
+ return (
+
+ );
+}
+export default DataTable_ShowHideColumnsMenu
\ No newline at end of file
diff --git a/src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js b/src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js
new file mode 100644
index 0000000..58425d9
--- /dev/null
+++ b/src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js
@@ -0,0 +1,160 @@
+import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Box, FormControlLabel, MenuItem, Switch, Tooltip, Typography } from "@mui/material";
+import { useRef, useState } from "react";
+import DataTable_GrabHandleButton from "../buttons/GrabHandleButton";
+
+const DataTable_ShowHideColumnsMenuItems = ({
+ allColumns,
+ column,
+ hoveredColumn,
+ isNestedColumns,
+ setHoveredColumn,
+ table,
+ ...rest
+}) => {
+ const {
+ getState,
+ options: {
+ enableColumnOrdering,
+ enableHiding,
+ localization,
+ mrtTheme: { draggingBorderColor },
+ },
+ setColumnOrder,
+ } = table;
+
+ const { columnOrder } = getState();
+ const { columnDef } = column;
+ const { columnDefType } = columnDef;
+
+ const switchChecked = column.getIsVisible();
+
+ const handleToggleColumnHidden = (column) => {
+ if (columnDefType === 'group') {
+ column?.columns?.forEach?.((childColumn) => {
+ childColumn.toggleVisibility(!switchChecked);
+ });
+ } else {
+ column.toggleVisibility();
+ }
+ };
+
+ const menuItemRef = useRef(null);
+
+ const [isDragging, setIsDragging] = useState(false);
+
+ const handleDragStart = (e) => {
+ setIsDragging(true);
+ try {
+ e.dataTransfer.setDragImage(menuItemRef.current, 0, 0);
+ } catch (e) {
+ console.error(e);
+ }
+ };
+
+ const handleDragEnd = (_e) => {
+ setIsDragging(false);
+ setHoveredColumn(null);
+ if (hoveredColumn) {
+ setColumnOrder(reorderColumn(column, hoveredColumn, columnOrder));
+ }
+ };
+
+ const handleDragEnter = (_e) => {
+ if (!isDragging && columnDef.enableColumnOrdering !== false) {
+ setHoveredColumn(column);
+ }
+ };
+
+ if (!columnDef.header || columnDef.visibleInShowHideMenu === false) {
+ return null;
+ }
+
+ return (
+ <>
+
+ {column.columns?.map((c, i) => (
+
+ ))}
+ >
+ );
+
+}
+export default DataTable_ShowHideColumnsMenuItems;
\ No newline at end of file
diff --git a/src/core/components/DataTable/table/Paper.js b/src/core/components/DataTable/table/Paper.js
new file mode 100644
index 0000000..db3bbec
--- /dev/null
+++ b/src/core/components/DataTable/table/Paper.js
@@ -0,0 +1,78 @@
+import { parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Paper } from "@mui/material";
+import DataTable_BottomToolbar from "../toolbar/BottomToolbar";
+import DataTable_TopToolbar from "../toolbar/TopToolbar";
+import DataTable_TableContainer from "./TableContainer";
+
+const DataTable_Paper = ({ table, ...rest }) => {
+ const {
+ getState,
+ options: {
+ enableBottomToolbar,
+ enableTopToolbar,
+ mrtTheme: { baseBackgroundColor },
+ muiTablePaperProps,
+ renderBottomToolbar,
+ renderTopToolbar,
+ },
+ refs: { tablePaperRef },
+ } = table;
+
+ const { isFullScreen } = getState();
+
+ const paperProps = {
+ ...parseFromValuesOrFunc(muiTablePaperProps, { table }),
+ ...rest,
+ };
+
+ return (
+ {
+ tablePaperRef.current = ref;
+ if (paperProps?.ref) {
+ //@ts-ignore
+ paperProps.ref.current = ref;
+ }
+ }}
+ style={{
+ ...(isFullScreen
+ ? {
+ bottom: 0,
+ height: '100dvh',
+ left: 0,
+ margin: 0,
+ maxHeight: '100dvh',
+ maxWidth: '100dvw',
+ padding: 0,
+ position: 'fixed',
+ right: 0,
+ top: 0,
+ width: '100dvw',
+ zIndex: 999,
+ }
+ : {}),
+ ...paperProps?.style,
+ }}
+ sx={(theme) => ({
+ backgroundColor: baseBackgroundColor,
+ backgroundImage: 'unset',
+ overflow: 'hidden',
+ transition: 'all 100ms ease-in-out',
+ ...(parseFromValuesOrFunc(paperProps?.sx, theme)),
+ })}
+ >
+ {enableTopToolbar &&
+ (parseFromValuesOrFunc(renderTopToolbar, { table }) ?? (
+
+ ))}
+
+ {enableBottomToolbar &&
+ (parseFromValuesOrFunc(renderBottomToolbar, { table }) ?? (
+
+ ))}
+
+ );
+};
+export default DataTable_Paper;
diff --git a/src/core/components/DataTable/table/Table.js b/src/core/components/DataTable/table/Table.js
new file mode 100644
index 0000000..2bbe1a9
--- /dev/null
+++ b/src/core/components/DataTable/table/Table.js
@@ -0,0 +1,78 @@
+import { parseCSSVarId, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Table } from "@mui/material";
+import { useMRT_ColumnVirtualizer } from "material-react-table";
+import { useMemo } from "react";
+import DataTable_TableBody, { Memo_DataTable_TableBody } from "../body/TableBody";
+import DataTable_TableHead from "../head/TableHead";
+
+const DataTable_Table = ({
+ table,
+ ...rest
+}) => {
+ const {
+ getFlatHeaders,
+ getState,
+ options: {
+ columns,
+ enableStickyHeader,
+ enableTableFooter,
+ enableTableHead,
+ layoutMode,
+ memoMode,
+ muiTableProps,
+ renderCaption,
+ },
+ } = table;
+ const { columnSizing, columnSizingInfo, columnVisibility, isFullScreen } =
+ getState();
+
+ const tableProps = {
+ ...parseFromValuesOrFunc(muiTableProps, { table }),
+ ...rest,
+ };
+
+ const Caption = parseFromValuesOrFunc(renderCaption, { table });
+
+ const columnSizeVars = useMemo(() => {
+ const headers = getFlatHeaders();
+ const colSizes = {};
+ for (let i = 0; i < headers.length; i++) {
+ const header = headers[i];
+ const colSize = header.getSize();
+ colSizes[`--header-${parseCSSVarId(header.id)}-size`] = colSize;
+ colSizes[`--col-${parseCSSVarId(header.column.id)}-size`] = colSize;
+ }
+ return colSizes;
+ }, [columns, columnSizing, columnSizingInfo, columnVisibility]);
+
+ const columnVirtualizer = useMRT_ColumnVirtualizer(table);
+
+ const commonTableGroupProps = {
+ columnVirtualizer,
+ table,
+ };
+
+ return (
+ ({
+ borderCollapse: 'separate',
+ display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
+ position: 'relative',
+ ...(parseFromValuesOrFunc(tableProps?.sx, theme)),
+ })}
+ >
+ {!!Caption && {Caption}}
+ {enableTableHead && }
+ {memoMode === 'table-body' || columnSizingInfo.isResizingColumn ? (
+
+ ) : (
+
+ )}
+ {/* {enableTableFooter && } */}
+
+ );
+}
+export default DataTable_Table
\ No newline at end of file
diff --git a/src/core/components/DataTable/table/TableContainer.js b/src/core/components/DataTable/table/TableContainer.js
new file mode 100644
index 0000000..aa4b625
--- /dev/null
+++ b/src/core/components/DataTable/table/TableContainer.js
@@ -0,0 +1,94 @@
+import { parseFromValuesOrFunc } from "@/core/utils/utils";
+import { TableContainer } from "@mui/material";
+import { useEffect, useLayoutEffect, useState } from "react";
+import DataTable_CellActionMenu from "../menus/CellActionMenu";
+import DataTable_Table from "./Table";
+import DataTable_TableLoadingOverlay from "./TableLoadingOverlay";
+
+const useIsomorphicLayoutEffect =
+ typeof window !== 'undefined' ? useLayoutEffect : useEffect;
+
+const DataTable_TableContainer = ({
+ table,
+ ...rest
+}) => {
+ const {
+ getState,
+ options: {
+ enableCellActions,
+ enableStickyHeader,
+ muiTableContainerProps,
+ },
+ refs: { bottomToolbarRef, tableContainerRef, topToolbarRef },
+ } = table;
+ const {
+ actionCell,
+ isFullScreen,
+ isLoading,
+ showLoadingOverlay,
+ } = getState();
+
+ const loading =
+ showLoadingOverlay !== false && (isLoading || showLoadingOverlay);
+
+ const [totalToolbarHeight, setTotalToolbarHeight] = useState(0);
+
+ const tableContainerProps = {
+ ...parseFromValuesOrFunc(muiTableContainerProps, {
+ table,
+ }),
+ ...rest,
+ };
+
+ useIsomorphicLayoutEffect(() => {
+ const topToolbarHeight =
+ typeof document !== 'undefined'
+ ? topToolbarRef.current?.offsetHeight ?? 0
+ : 0;
+
+ const bottomToolbarHeight =
+ typeof document !== 'undefined'
+ ? bottomToolbarRef?.current?.offsetHeight ?? 0
+ : 0;
+
+ setTotalToolbarHeight(topToolbarHeight + bottomToolbarHeight);
+ });
+
+ return (
+ {
+ if (node) {
+ tableContainerRef.current = node;
+ if (tableContainerProps?.ref) {
+ //@ts-ignore
+ tableContainerProps.ref.current = node;
+ }
+ }
+ }}
+ style={{
+ maxHeight: isFullScreen
+ ? `calc(100vh - ${totalToolbarHeight}px)`
+ : undefined,
+ ...tableContainerProps?.style,
+ }}
+ sx={(theme) => ({
+ maxHeight: enableStickyHeader
+ ? `clamp(350px, calc(100vh - ${totalToolbarHeight}px), 9999px)`
+ : undefined,
+ maxWidth: '100%',
+ overflow: 'auto',
+ position: 'relative',
+ ...(parseFromValuesOrFunc(tableContainerProps?.sx, theme)),
+ })}
+ >
+ {loading ? : null}
+
+ {enableCellActions && actionCell && }
+
+ );
+
+}
+export default DataTable_TableContainer
\ No newline at end of file
diff --git a/src/core/components/DataTable/table/TableLoadingOverlay.js b/src/core/components/DataTable/table/TableLoadingOverlay.js
new file mode 100644
index 0000000..55e4ae5
--- /dev/null
+++ b/src/core/components/DataTable/table/TableLoadingOverlay.js
@@ -0,0 +1,48 @@
+import { Box, CircularProgress } from "@mui/material";
+
+const DataTable_TableLoadingOverlay = ({
+ table,
+ ...rest
+}) => {
+ const {
+ options: {
+ localization,
+ mrtTheme: { baseBackgroundColor },
+ muiCircularProgressProps,
+ },
+ } = table;
+
+ const circularProgressProps = {
+ ...parseFromValuesOrFunc(muiCircularProgressProps, { table }),
+ ...rest,
+ };
+
+ return (
+
+ {circularProgressProps?.Component ?? (
+
+ )}
+
+ );
+
+}
+export default DataTable_TableLoadingOverlay
\ No newline at end of file
diff --git a/src/core/components/DataTable/toolbar/BottomToolbar.js b/src/core/components/DataTable/toolbar/BottomToolbar.js
new file mode 100644
index 0000000..15e7f5a
--- /dev/null
+++ b/src/core/components/DataTable/toolbar/BottomToolbar.js
@@ -0,0 +1,88 @@
+import { getCommonToolbarStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Box, alpha, useMediaQuery } from "@mui/material";
+import DataTable_LinearProgressBar from "./LinearProgressBar";
+import DataTable_TablePagination from "./TablePagination";
+
+const DataTable_BottomToolbar = ({
+ table,
+ ...rest
+}) => {
+ const {
+ getState,
+ options: {
+ enablePagination,
+ muiBottomToolbarProps,
+ positionPagination,
+ renderBottomToolbarCustomActions,
+ },
+ refs: { bottomToolbarRef },
+ } = table;
+ const { isFullScreen } = getState();
+
+ const isMobile = useMediaQuery('(max-width:720px)');
+ const toolbarProps = {
+ ...parseFromValuesOrFunc(muiBottomToolbarProps, { table }),
+ ...rest,
+ };
+
+ const stackAlertBanner = isMobile || !!renderBottomToolbarCustomActions;
+ return (
+ {
+ if (node) {
+ bottomToolbarRef.current = node;
+ if (toolbarProps?.ref) {
+ // @ts-ignore
+ toolbarProps.ref.current = node;
+ }
+ }
+ }}
+ sx={(theme) => ({
+ ...getCommonToolbarStyles({ table, theme }),
+ bottom: isFullScreen ? '0' : undefined,
+ boxShadow: `0 1px 2px -1px ${alpha(
+ theme.palette.grey[700],
+ 0.5,
+ )} inset`,
+ left: 0,
+ position: isFullScreen ? 'fixed' : 'relative',
+ right: 0,
+ ...(parseFromValuesOrFunc(toolbarProps?.sx, theme)),
+ })}
+ >
+
+
+ {renderBottomToolbarCustomActions ? (
+ renderBottomToolbarCustomActions({ table })
+ ) : (
+
+ )}
+
+ {enablePagination &&
+ ['both', 'bottom'].includes(positionPagination ?? '') && (
+
+ )}
+
+
+
+ );
+}
+export default DataTable_BottomToolbar
\ No newline at end of file
diff --git a/src/core/components/DataTable/toolbar/LinearProgressBar.js b/src/core/components/DataTable/toolbar/LinearProgressBar.js
new file mode 100644
index 0000000..cdcbc0a
--- /dev/null
+++ b/src/core/components/DataTable/toolbar/LinearProgressBar.js
@@ -0,0 +1,44 @@
+import { parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Collapse, LinearProgress } from "@mui/material";
+
+const DataTable_LinearProgressBar = ({
+ isTopToolbar,
+ table,
+ ...rest
+}) => {
+ const {
+ getState,
+ options: { muiLinearProgressProps },
+ } = table;
+ const { isSaving, showProgressBars } = getState();
+
+ const linearProgressProps = {
+ ...parseFromValuesOrFunc(muiLinearProgressProps, {
+ isTopToolbar,
+ table,
+ }),
+ ...rest,
+ };
+
+ return (
+
+
+
+ );
+}
+export default DataTable_LinearProgressBar
\ No newline at end of file
diff --git a/src/core/components/DataTable/toolbar/TablePagination.js b/src/core/components/DataTable/toolbar/TablePagination.js
new file mode 100644
index 0000000..cd70fda
--- /dev/null
+++ b/src/core/components/DataTable/toolbar/TablePagination.js
@@ -0,0 +1,217 @@
+import { flipIconStyles, getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { useTheme } from "@emotion/react";
+import { Box, IconButton, InputLabel, MenuItem, Pagination, PaginationItem, Select, Tooltip, Typography, useMediaQuery } from "@mui/material";
+
+const defaultRowsPerPage = [5, 10, 15, 20, 25, 30, 50, 100];
+
+const DataTable_TablePagination = ({
+ position = 'bottom',
+ table,
+ ...rest
+}) => {
+ const theme = useTheme();
+ const isMobile = useMediaQuery('(max-width: 720px)');
+
+ const {
+ getState,
+ options: {
+ enableToolbarInternalActions,
+ icons: { ChevronLeftIcon, ChevronRightIcon, FirstPageIcon, LastPageIcon },
+ localization,
+ muiPaginationProps,
+ paginationDisplayMode,
+ },
+ } = table;
+
+ const {
+ pagination: { pageIndex = 0, pageSize = 10 },
+ showGlobalFilter,
+ } = getState();
+
+ const paginationProps = {
+ ...parseFromValuesOrFunc(muiPaginationProps, {
+ table,
+ }),
+ ...rest,
+ };
+
+ const totalRowCount = table.getRowCount();
+ const numberOfPages = table.getPageCount();
+ const showFirstLastPageButtons = numberOfPages > 2;
+ const firstRowIndex = pageIndex * pageSize;
+ const lastRowIndex = Math.min(pageIndex * pageSize + pageSize, totalRowCount);
+
+ const {
+ SelectProps = {},
+ disabled = false,
+ rowsPerPageOptions = defaultRowsPerPage,
+ showFirstButton = showFirstLastPageButtons,
+ showLastButton = showFirstLastPageButtons,
+ showRowsPerPage = true,
+ ...restPaginationProps
+ } = paginationProps ?? {};
+
+ const disableBack = pageIndex <= 0 || disabled;
+ const disableNext = lastRowIndex >= totalRowCount || disabled;
+
+ if (isMobile && SelectProps?.native !== false) {
+ SelectProps.native = true;
+ }
+
+ const tooltipProps = getCommonTooltipProps();
+
+ return (
+
+ {showRowsPerPage && (
+
+
+ {localization.rowsPerPage}
+
+
+
+ )}
+ {paginationDisplayMode === 'pages' ? (
+ table.setPageIndex(newPageIndex - 1)}
+ page={pageIndex + 1}
+ renderItem={(item) => (
+
+ )}
+ showFirstButton={showFirstButton}
+ showLastButton={showLastButton}
+ {...restPaginationProps}
+ />
+ ) : paginationDisplayMode === 'default' ? (
+ <>
+ {`${lastRowIndex === 0 ? 0 : (firstRowIndex + 1).toLocaleString()
+ }-${lastRowIndex.toLocaleString()} ${localization.of
+ } ${totalRowCount.toLocaleString()}`}
+
+ {showFirstButton && (
+
+
+ table.firstPage()}
+ size="small"
+ >
+
+
+
+
+ )}
+
+
+ table.previousPage()}
+ size="small"
+ >
+
+
+
+
+
+
+ table.nextPage()}
+ size="small"
+ >
+
+
+
+
+ {showLastButton && (
+
+
+ table.lastPage()}
+ size="small"
+ >
+
+
+
+
+ )}
+
+ >
+ ) : null}
+
+ );
+}
+export default DataTable_TablePagination
\ No newline at end of file
diff --git a/src/core/components/DataTable/toolbar/ToolbarInternalButtons.js b/src/core/components/DataTable/toolbar/ToolbarInternalButtons.js
new file mode 100644
index 0000000..606add0
--- /dev/null
+++ b/src/core/components/DataTable/toolbar/ToolbarInternalButtons.js
@@ -0,0 +1,47 @@
+import { parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Box } from "@mui/material";
+import DataTable_ShowHideColumnsButton from "../buttons/ShowHideColumnsButton";
+import DataTable_ToggleFiltersButton from "../buttons/ToggleFiltersButton";
+
+const DataTable_ToolbarInternalButtons = ({ table, ...rest }) => {
+ const {
+ options: {
+ columnFilterDisplayMode,
+ enableColumnFilters,
+ enableColumnOrdering,
+ enableColumnPinning,
+ enableFilters,
+ enableHiding,
+ renderToolbarInternalActions,
+ },
+ } = table;
+
+
+ return (
+ ({
+ alignItems: 'center',
+ display: 'flex',
+ zIndex: 3,
+ ...(parseFromValuesOrFunc(rest?.sx, theme)),
+ })}
+ >
+ {renderToolbarInternalActions?.({
+ table,
+ }) ?? (
+ <>
+ {enableFilters &&
+ enableColumnFilters &&
+ columnFilterDisplayMode !== 'popover' && (
+
+ )}
+ {(enableHiding || enableColumnOrdering || enableColumnPinning) && (
+
+ )}
+ >
+ )}
+
+ );
+}
+export default DataTable_ToolbarInternalButtons
\ No newline at end of file
diff --git a/src/core/components/DataTable/toolbar/TopToolbar.js b/src/core/components/DataTable/toolbar/TopToolbar.js
new file mode 100644
index 0000000..4eb0aba
--- /dev/null
+++ b/src/core/components/DataTable/toolbar/TopToolbar.js
@@ -0,0 +1,86 @@
+import { getCommonToolbarStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { Box, useMediaQuery } from "@mui/material";
+import DataTable_LinearProgressBar from "./LinearProgressBar";
+import DataTable_TablePagination from "./TablePagination";
+import DataTable_ToolbarInternalButtons from "./ToolbarInternalButtons";
+
+const DataTable_TopToolbar = ({ table }) => {
+ const {
+ getState,
+ options: {
+ enablePagination,
+ enableToolbarInternalActions,
+ muiTopToolbarProps,
+ positionPagination,
+ renderTopToolbarCustomActions,
+ },
+ refs: { topToolbarRef },
+ } = table;
+ const { isFullScreen, showGlobalFilter } = getState();
+
+ const isMobile = useMediaQuery('(max-width:720px)');
+ const isTablet = useMediaQuery('(max-width:1024px)');
+
+ const toolbarProps = parseFromValuesOrFunc(muiTopToolbarProps, { table });
+
+ const stackAlertBanner =
+ isMobile ||
+ !!renderTopToolbarCustomActions ||
+ (showGlobalFilter && isTablet);
+
+ return (
+ {
+ topToolbarRef.current = ref;
+ if (toolbarProps?.ref) {
+ // @ts-ignore
+ toolbarProps.ref.current = ref;
+ }
+ }}
+ sx={(theme) => ({
+ ...getCommonToolbarStyles({ table, theme }),
+ position: isFullScreen ? 'sticky' : 'relative',
+ top: isFullScreen ? '0' : undefined,
+ ...(parseFromValuesOrFunc(toolbarProps?.sx, theme)),
+ })}
+ >
+
+ {renderTopToolbarCustomActions?.({ table }) ?? }
+ {enableToolbarInternalActions && (
+
+
+
+ )}
+
+ {enablePagination &&
+ ['both', 'top'].includes(positionPagination ?? '') && (
+
+ )}
+
+
+ );
+}
+
+export default DataTable_TopToolbar
\ No newline at end of file
diff --git a/src/core/utils/theme.js b/src/core/utils/theme.js
index 8f2bbec..3abbb52 100644
--- a/src/core/utils/theme.js
+++ b/src/core/utils/theme.js
@@ -1,10 +1,11 @@
'use client'
-import {createTheme} from "@mui/material";
+import { createTheme } from "@mui/material";
const theme = createTheme({
direction: 'rtl',
typography: {
fontFamily: `IRANSansFaNum, sans-serif`,
+ fontSize: 12
},
});
diff --git a/src/core/utils/utils.js b/src/core/utils/utils.js
new file mode 100644
index 0000000..8fe3844
--- /dev/null
+++ b/src/core/utils/utils.js
@@ -0,0 +1,162 @@
+import { alpha, darken } from "@mui/material";
+
+export const parseCSSVarId = (id) => id.replace(/[^a-zA-Z0-9]/g, '_');
+
+export const parseFromValuesOrFunc = (
+ fn,
+ arg
+) => (fn instanceof Function ? fn(arg) : fn);
+
+export const getCommonToolbarStyles = ({
+ table,
+}) => ({
+ alignItems: 'flex-start',
+ backgroundColor: table.options.mrtTheme.baseBackgroundColor,
+ display: 'grid',
+ flexWrap: 'wrap-reverse',
+ minHeight: '3.5rem',
+ overflow: 'hidden',
+ position: 'relative',
+ transition: 'all 150ms ease-in-out',
+ zIndex: 1,
+});
+
+export const getCommonTooltipProps = (
+ placement,
+) => ({
+ disableInteractive: true,
+ enterDelay: 1000,
+ enterNextDelay: 1000,
+ placement,
+});
+
+export const flipIconStyles = (theme) =>
+ theme.direction === 'rtl'
+ ? { style: { transform: 'scaleX(-1)' } }
+ : undefined;
+
+export const getCommonPinnedCellStyles = ({
+ column,
+ table,
+ theme,
+}) => {
+ const { baseBackgroundColor } = table.options.mrtTheme;
+ const isPinned = column?.getIsPinned();
+
+ return {
+ '&[data-pinned="true"]': {
+ '&:before': {
+ backgroundColor: alpha(
+ darken(
+ baseBackgroundColor,
+ theme.palette.mode === 'dark' ? 0.05 : 0.01,
+ ),
+ 0.97,
+ ),
+ boxShadow: column
+ ? isPinned === 'left' && column.getIsLastColumn(isPinned)
+ ? `-4px 0 4px -4px ${alpha(theme.palette.grey[700], 0.5)} inset`
+ : isPinned === 'right' && column.getIsFirstColumn(isPinned)
+ ? `4px 0 4px -4px ${alpha(theme.palette.grey[700], 0.5)} inset`
+ : undefined
+ : undefined,
+ ...commonCellBeforeAfterStyles,
+ },
+ },
+ };
+};
+
+export const getCommonMRTCellStyles = ({
+ column,
+ header,
+ table,
+ tableCellProps,
+ theme,
+}) => {
+ const {
+ getState,
+ options: { enableColumnVirtualization, layoutMode },
+ } = table;
+ const { draggingColumn } = getState();
+ const { columnDef } = column;
+ const { columnDefType } = columnDef;
+
+ const isColumnPinned =
+ columnDef.columnDefType !== 'group' && column.getIsPinned();
+
+ const widthStyles = {
+ minWidth: `max(calc(var(--${header ? 'header' : 'col'}-${parseCSSVarId(
+ header?.id ?? column.id,
+ )}-size) * 1px), ${columnDef.minSize ?? 30}px)`,
+ width: `calc(var(--${header ? 'header' : 'col'}-${parseCSSVarId(
+ header?.id ?? column.id,
+ )}-size) * 1px)`,
+ };
+
+ if (layoutMode === 'grid') {
+ widthStyles.flex = `${[0, false].includes(columnDef.grow)
+ ? 0
+ : `var(--${header ? 'header' : 'col'}-${parseCSSVarId(
+ header?.id ?? column.id,
+ )}-size)`
+ } 0 auto`;
+ } else if (layoutMode === 'grid-no-grow') {
+ widthStyles.flex = `${+(columnDef.grow || 0)} 0 auto`;
+ }
+
+ const pinnedStyles = isColumnPinned
+ ? {
+ ...getCommonPinnedCellStyles({ column, table, theme }),
+ left:
+ isColumnPinned === 'left'
+ ? `${column.getStart('left')}px`
+ : undefined,
+ opacity: 0.97,
+ position: 'sticky',
+ right:
+ isColumnPinned === 'right'
+ ? `${column.getAfter('right')}px`
+ : undefined,
+ }
+ : {};
+
+ return {
+ backgroundColor: 'inherit',
+ backgroundImage: 'inherit',
+ display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
+ justifyContent:
+ columnDefType === 'group'
+ ? 'center'
+ : layoutMode?.startsWith('grid')
+ ? tableCellProps.align
+ : undefined,
+ opacity:
+ table.getState().draggingColumn?.id === column.id ||
+ table.getState().hoveredColumn?.id === column.id
+ ? 0.5
+ : 1,
+ position: 'relative',
+ transition: enableColumnVirtualization
+ ? 'none'
+ : `padding 150ms ease-in-out`,
+ zIndex:
+ column.getIsResizing() || draggingColumn?.id === column.id
+ ? 2
+ : columnDefType !== 'group' && isColumnPinned
+ ? 1
+ : 0,
+ ...pinnedStyles,
+ ...widthStyles,
+ ...(parseFromValuesOrFunc(tableCellProps?.sx, theme)),
+ };
+};
+
+export const commonCellBeforeAfterStyles = {
+ content: '""',
+ height: '100%',
+ left: 0,
+ position: 'absolute',
+ top: 0,
+ width: '100%',
+ zIndex: -1,
+};
\ No newline at end of file