import clsx from 'clsx'; import classes from './MRT_TableBodyRow.module.css'; import { type DragEvent, memo, useMemo, useRef } from 'react'; import { Box, type TableProps, TableTr, type TableTrProps, } from '@mantine/core'; import { Memo_MRT_TableBodyCell, MRT_TableBodyCell } from './MRT_TableBodyCell'; import { MRT_TableDetailPanel } from './MRT_TableDetailPanel'; import { type MRT_Cell, type MRT_ColumnVirtualizer, type MRT_DensityState, type MRT_Row, type MRT_RowData, type MRT_RowVirtualizer, type MRT_TableInstance, type MRT_VirtualItem, } from '../../types'; import { getIsRowSelected } from '../../utils/row.utils'; import { parseFromValuesOrFunc } from '../../utils/utils'; interface Props extends TableTrProps { columnVirtualizer?: MRT_ColumnVirtualizer; numRows?: number; pinnedRowIds?: string[]; renderedRowIndex?: number; row: MRT_Row; rowVirtualizer?: MRT_RowVirtualizer; table: MRT_TableInstance; tableProps: Partial; virtualRow?: MRT_VirtualItem; } export const MRT_TableBodyRow = ({ children, columnVirtualizer, numRows, pinnedRowIds, renderedRowIndex = 0, row, rowVirtualizer, table, tableProps, virtualRow, ...rest }: Props) => { 'use no memo'; const { getState, options: { enableRowOrdering, enableRowPinning, enableStickyFooter, enableStickyHeader, layoutMode, mantineTableBodyRowProps, memoMode, 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 isRowStickyPinned = isRowPinned && rowPinningDisplayMode?.includes('sticky') && 'sticky'; const isDraggingRow = draggingRow?.id === row.id; const isHoveredRow = hoveredRow?.id === row.id; const tableRowProps = { ...parseFromValuesOrFunc(mantineTableBodyRowProps, { renderedRowIndex, row, table, }), ...rest, }; const [bottomPinnedIndex, topPinnedIndex] = useMemo(() => { if ( !enableRowPinning || !isRowStickyPinned || !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 defaultRowHeightByDensity: Record = { lg: 61, md: 53, sm: 45, xl: 69, xs: 37, }; const rowHeight = // @ts-ignore parseInt(tableRowProps?.style?.height, 10) || (defaultRowHeightByDensity[density] ?? defaultRowHeightByDensity['md']); const handleDragEnter = (_e: DragEvent) => { if (enableRowOrdering && draggingRow) { setHoveredRow(row); } }; const rowRef = useRef(null); let striped = tableProps.striped as boolean | string; if (striped) { if (striped === true) { striped = 'odd'; } if (striped === 'odd' && renderedRowIndex % 2 !== 0) { striped = false; } if (striped === 'even' && renderedRowIndex % 2 === 0) { striped = false; } } return ( <> { if (node) { rowRef.current = node; rowVirtualizer?.measureElement(node); } }} {...tableRowProps} __vars={{ ...tableRowProps?.__vars, '--mrt-pinned-row-bottom': !virtualRow && bottomPinnedIndex !== undefined && isRowPinned ? `${ bottomPinnedIndex * rowHeight + (enableStickyFooter ? tableFooterHeight - 1 : 0) }` : undefined, '--mrt-pinned-row-top': virtualRow ? undefined : topPinnedIndex !== undefined && isRowPinned ? `${ topPinnedIndex * rowHeight + (enableStickyHeader || isFullScreen ? tableHeadHeight - 1 : 0) }` : undefined, '--mrt-virtual-row-start': virtualRow ? `${virtualRow.start}` : undefined, }} className={clsx( classes.root, layoutMode?.startsWith('grid') && classes['root-grid'], virtualRow && classes['root-virtualized'], tableRowProps?.className, )} > {virtualPaddingLeft ? ( ) : null} {children ? children : (virtualColumns ?? row.getVisibleCells()).map( (cellOrVirtualCell, renderedColumnIndex) => { let cell = cellOrVirtualCell as MRT_Cell; if (columnVirtualizer) { renderedColumnIndex = (cellOrVirtualCell as MRT_VirtualItem) .index; cell = visibleCells[renderedColumnIndex]; } const cellProps = { cell, numRows, renderedColumnIndex, renderedRowIndex, rowRef, table, virtualCell: columnVirtualizer ? (cellOrVirtualCell as MRT_VirtualItem) : undefined, }; return memoMode === 'cells' && cell.column.columnDef.columnDefType === 'data' && !draggingColumn && !draggingRow && editingCell?.id !== cell.id && editingRow?.id !== row.id ? ( ) : ( ); }, )} {virtualPaddingRight ? ( ) : null} {renderDetailPanel && !row.getIsGrouped() && ( )} ); }; export const Memo_MRT_TableBodyRow = memo( MRT_TableBodyRow, (prev, next) => prev.row === next.row, ) as typeof MRT_TableBodyRow;