From 7fbe53ebe408cd6f69fdbdd5f1ff04474cbf80ee Mon Sep 17 00:00:00 2001 From: Kevin Van Cott Date: Wed, 24 Jan 2024 03:23:51 -0600 Subject: [PATCH] release v2.9.0 --- .../examples/advanced/sandbox/src/JS.js | 15 +++- .../examples/advanced/sandbox/src/TS.tsx | 10 ++- .../pages/changelog.mdx | 4 +- .../pages/migrating-to-v2.mdx | 1 + packages/material-react-table/package.json | 2 +- .../src/components/body/MRT_TableBodyCell.tsx | 1 - .../src/components/body/MRT_TableBodyRow.tsx | 67 ++++++++++------- .../components/inputs/MRT_SelectCheckbox.tsx | 10 +-- .../toolbar/MRT_ToolbarAlertBanner.tsx | 2 +- .../getMRT_RowActionsColumnDef.tsx | 1 + .../getMRT_RowDragColumnDef.tsx | 1 + .../getMRT_RowExpandColumnDef.tsx | 6 +- .../getMRT_RowNumbersColumnDef.tsx | 1 + .../getMRT_RowPinningColumnDef.tsx | 1 + .../getMRT_RowSelectColumnDef.tsx | 3 +- .../src/utils/displayColumn.utils.ts | 4 +- .../src/utils/row.utils.ts | 23 +++++- .../src/utils/style.utils.ts | 74 ++++++++++--------- .../stories/features/Aggregation.stories.tsx | 9 +++ .../stories/features/Selection.stories.tsx | 2 +- .../features/Virtualization.stories.tsx | 8 +- .../styling/TableHeadCellStyles.stories.tsx | 2 +- 22 files changed, 156 insertions(+), 91 deletions(-) diff --git a/apps/material-react-table-docs/examples/advanced/sandbox/src/JS.js b/apps/material-react-table-docs/examples/advanced/sandbox/src/JS.js index f1dca509a..7bad73365 100644 --- a/apps/material-react-table-docs/examples/advanced/sandbox/src/JS.js +++ b/apps/material-react-table-docs/examples/advanced/sandbox/src/JS.js @@ -137,7 +137,14 @@ const Example = () => { enableFacetedValues: true, enableRowActions: true, enableRowSelection: true, - initialState: { showColumnFilters: true, showGlobalFilter: true }, + initialState: { + showColumnFilters: true, + showGlobalFilter: true, + columnPinning: { + left: ['mrt-row-expand', 'mrt-row-select'], + right: ['mrt-row-actions'], + }, + }, paginationDisplayMode: 'pages', positionToolbarAlertBanner: 'bottom', muiSearchTextFieldProps: { @@ -153,9 +160,13 @@ const Example = () => { renderDetailPanel: ({ row }) => ( { initialState: { showColumnFilters: true, showGlobalFilter: true, + columnPinning: { + left: ['mrt-row-expand', 'mrt-row-select'], + right: ['mrt-row-actions'], + }, }, paginationDisplayMode: 'pages', positionToolbarAlertBanner: 'bottom', @@ -169,9 +173,13 @@ const Example = () => { renderDetailPanel: ({ row }) => ( ` element to be rendered within the table -- Fixed row hover opacity styles for pinned columns and selected rows +- Fixed row hover opacity style issues for pinned columns and selected rows with `::before` and `::after` pseudo elements in pinned cells - Standardized `data-index`, `data-pinned`, and `data-selected` attributes on body rows, head cells, body cells, and footer cells where applicable - Column virtualization performance optimizations diff --git a/apps/material-react-table-docs/pages/migrating-to-v2.mdx b/apps/material-react-table-docs/pages/migrating-to-v2.mdx index 5b64fc767..d5c8c43bc 100644 --- a/apps/material-react-table-docs/pages/migrating-to-v2.mdx +++ b/apps/material-react-table-docs/pages/migrating-to-v2.mdx @@ -29,6 +29,7 @@ This should be an easy to moderate upgrade for most developers. The only breakin 10. Improved column sizing and layout modes for column resizing features 11. All internal MRT components are now exported for custom headless use cases 12. New optional `createMRTColumnHelper` utility function for better `TValue`/`cell.getValue()` type inference +13. Many more features are compatible with virtualization See the full [changelog](/changelog#version-2.0.0---10-27-2023) for more details. diff --git a/packages/material-react-table/package.json b/packages/material-react-table/package.json index aef4cedb4..86c10df99 100644 --- a/packages/material-react-table/package.json +++ b/packages/material-react-table/package.json @@ -1,5 +1,5 @@ { - "version": "2.8.0", + "version": "2.9.0", "license": "MIT", "name": "material-react-table", "description": "A fully featured Material UI V5 implementation of TanStack React Table V8, written from the ground up in TypeScript.", diff --git a/packages/material-react-table/src/components/body/MRT_TableBodyCell.tsx b/packages/material-react-table/src/components/body/MRT_TableBodyCell.tsx index e630dddb8..c4c4139f7 100644 --- a/packages/material-react-table/src/components/body/MRT_TableBodyCell.tsx +++ b/packages/material-react-table/src/components/body/MRT_TableBodyCell.tsx @@ -263,7 +263,6 @@ export const MRT_TableBodyCell = ({ zIndex: draggingColumn?.id === column.id ? 2 : column.getIsPinned() ? 1 : 0, ...getCommonMRTCellStyles({ - cell, column, table, tableCellProps, diff --git a/packages/material-react-table/src/components/body/MRT_TableBodyRow.tsx b/packages/material-react-table/src/components/body/MRT_TableBodyRow.tsx index 90d0f03ac..f9423e6a1 100644 --- a/packages/material-react-table/src/components/body/MRT_TableBodyRow.tsx +++ b/packages/material-react-table/src/components/body/MRT_TableBodyRow.tsx @@ -19,7 +19,12 @@ import { type MRT_TableInstance, type MRT_VirtualItem, } from '../../types'; -import { getMRTTheme } from '../../utils/style.utils'; +import { getIsRowSelected } from '../../utils/row.utils'; +import { + getCommonPinnedCellStyles, + getMRTTheme, + pinnedBeforeAfterStyles, +} from '../../utils/style.utils'; import { parseFromValuesOrFunc } from '../../utils/utils'; interface Props { @@ -77,7 +82,8 @@ export const MRT_TableBodyRow = ({ const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } = columnVirtualizer ?? {}; - const isPinned = enableRowPinning && row.getIsPinned(); + const isRowSelected = getIsRowSelected({ row, table }); + const isRowPinned = enableRowPinning && row.getIsPinned(); const isDraggingRow = draggingRow?.id === row.id; const isHoveredRow = hoveredRow?.id === row.id; @@ -133,16 +139,27 @@ export const MRT_TableBodyRow = ({ selectedRowBackgroundColor, } = getMRTTheme(table, theme); + 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) { @@ -150,7 +167,7 @@ export const MRT_TableBodyRow = ({ rowVirtualizer?.measureElement(node); } }} - selected={row.getIsSelected()} + selected={isRowSelected} {...tableRowProps} style={{ transform: virtualRow @@ -160,18 +177,16 @@ export const MRT_TableBodyRow = ({ }} sx={(theme: Theme) => ({ '&:hover td': { - backgroundColor: - tableRowProps?.hover !== false - ? row.getIsSelected() - ? `${alpha(selectedRowBackgroundColor, 0.3)}` - : theme.palette.mode === 'dark' - ? `${lighten(baseBackgroundColor, 0.05)}` - : `${darken(baseBackgroundColor, 0.05)}` + '&:after': { + backgroundColor: cellHighlightColorHover + ? alpha(cellHighlightColorHover, 0.3) : undefined, + ...pinnedBeforeAfterStyles, + }, }, backgroundColor: `${baseBackgroundColor} !important`, bottom: - !virtualRow && bottomPinnedIndex !== undefined && isPinned + !virtualRow && bottomPinnedIndex !== undefined && isRowPinned ? `${ bottomPinnedIndex * rowHeight + (enableStickyFooter ? tableFooterHeight - 1 : 0) @@ -179,22 +194,22 @@ export const MRT_TableBodyRow = ({ : undefined, boxSizing: 'border-box', display: layoutMode?.startsWith('grid') ? 'flex' : undefined, - opacity: isPinned ? 0.97 : isDraggingRow || isHoveredRow ? 0.5 : 1, + opacity: isRowPinned ? 0.97 : isDraggingRow || isHoveredRow ? 0.5 : 1, position: virtualRow ? 'absolute' - : rowPinningDisplayMode?.includes('sticky') && isPinned + : rowPinningDisplayMode?.includes('sticky') && isRowPinned ? 'sticky' : undefined, td: { - backgroundColor: row.getIsSelected() - ? selectedRowBackgroundColor - : isPinned - ? pinnedRowBackgroundColor - : undefined, + '&:after': { + backgroundColor: cellHighlightColor, + ...pinnedBeforeAfterStyles, + }, + ...getCommonPinnedCellStyles({ table, theme }), }, top: virtualRow ? 0 - : topPinnedIndex !== undefined && isPinned + : topPinnedIndex !== undefined && isRowPinned ? `${ topPinnedIndex * rowHeight + (enableStickyHeader || isFullScreen ? tableHeadHeight - 1 : 0) @@ -203,7 +218,7 @@ export const MRT_TableBodyRow = ({ transition: virtualRow ? 'none' : 'all 150ms ease-in-out', width: '100%', zIndex: - rowPinningDisplayMode?.includes('sticky') && isPinned + rowPinningDisplayMode?.includes('sticky') && isRowPinned ? 2 : undefined, ...(sx as any), diff --git a/packages/material-react-table/src/components/inputs/MRT_SelectCheckbox.tsx b/packages/material-react-table/src/components/inputs/MRT_SelectCheckbox.tsx index f91f399c0..5ba292de4 100644 --- a/packages/material-react-table/src/components/inputs/MRT_SelectCheckbox.tsx +++ b/packages/material-react-table/src/components/inputs/MRT_SelectCheckbox.tsx @@ -8,19 +8,18 @@ import { type MRT_RowData, type MRT_TableInstance, } from '../../types'; +import { getIsRowSelected } from '../../utils/row.utils'; import { getCommonTooltipProps } from '../../utils/style.utils'; import { parseFromValuesOrFunc } from '../../utils/utils'; interface Props extends CheckboxProps { row?: MRT_Row; - selectAll?: boolean; staticRowIndex?: number; table: MRT_TableInstance; } export const MRT_SelectCheckbox = ({ row, - selectAll, staticRowIndex, table, ...rest @@ -39,6 +38,8 @@ export const MRT_SelectCheckbox = ({ } = table; const { density, isLoading } = getState(); + const selectAll = !row; + const checkboxProps = { ...(!row ? parseFromValuesOrFunc(muiSelectAllCheckboxProps, { table }) @@ -92,10 +93,7 @@ export const MRT_SelectCheckbox = ({ 'aria-label': selectAll ? localization.toggleSelectAll : localization.toggleSelectRow, - checked: selectAll - ? allRowsSelected - : row?.getIsSelected() || - (row?.getIsAllSubRowsSelected() && row.getCanSelectSubRows()), + checked: selectAll ? allRowsSelected : getIsRowSelected({ row, table }), disabled: isLoading || (row && !row.getCanSelect()) || row?.id === 'mrt-row-create', inputProps: { diff --git a/packages/material-react-table/src/components/toolbar/MRT_ToolbarAlertBanner.tsx b/packages/material-react-table/src/components/toolbar/MRT_ToolbarAlertBanner.tsx index 678d73d9f..cb397d0dc 100644 --- a/packages/material-react-table/src/components/toolbar/MRT_ToolbarAlertBanner.tsx +++ b/packages/material-react-table/src/components/toolbar/MRT_ToolbarAlertBanner.tsx @@ -139,7 +139,7 @@ export const MRT_ToolbarAlertBanner = ({ {enableRowSelection && enableSelectAll && positionToolbarAlertBanner === 'head-overlay' && ( - + )}{' '} {selectedAlert} diff --git a/packages/material-react-table/src/hooks/display-columns/getMRT_RowActionsColumnDef.tsx b/packages/material-react-table/src/hooks/display-columns/getMRT_RowActionsColumnDef.tsx index 0015fc3db..a295c2acb 100644 --- a/packages/material-react-table/src/hooks/display-columns/getMRT_RowActionsColumnDef.tsx +++ b/packages/material-react-table/src/hooks/display-columns/getMRT_RowActionsColumnDef.tsx @@ -28,6 +28,7 @@ export const getMRT_RowActionsColumnDef = ( ...defaultDisplayColumnProps({ header: 'actions', id: 'mrt-row-actions', + size: 70, tableOptions, }), }; diff --git a/packages/material-react-table/src/hooks/display-columns/getMRT_RowDragColumnDef.tsx b/packages/material-react-table/src/hooks/display-columns/getMRT_RowDragColumnDef.tsx index 1cfca880d..a4a02c28c 100644 --- a/packages/material-react-table/src/hooks/display-columns/getMRT_RowDragColumnDef.tsx +++ b/packages/material-react-table/src/hooks/display-columns/getMRT_RowDragColumnDef.tsx @@ -29,6 +29,7 @@ export const getMRT_RowDragColumnDef = ( ...defaultDisplayColumnProps({ header: 'move', id: 'mrt-row-drag', + size: 60, tableOptions, }), }; diff --git a/packages/material-react-table/src/hooks/display-columns/getMRT_RowExpandColumnDef.tsx b/packages/material-react-table/src/hooks/display-columns/getMRT_RowExpandColumnDef.tsx index e79bca23d..8e6a5032e 100644 --- a/packages/material-react-table/src/hooks/display-columns/getMRT_RowExpandColumnDef.tsx +++ b/packages/material-react-table/src/hooks/display-columns/getMRT_RowExpandColumnDef.tsx @@ -86,9 +86,11 @@ export const getMRT_RowExpandColumnDef = ( id: 'mrt-row-expand', size: groupedColumnMode === 'remove' - ? defaultColumn?.size + ? defaultColumn?.size ?? 180 : renderDetailPanel - ? 60 + ? enableExpandAll + ? 60 + : 70 : 100, tableOptions, }), diff --git a/packages/material-react-table/src/hooks/display-columns/getMRT_RowNumbersColumnDef.tsx b/packages/material-react-table/src/hooks/display-columns/getMRT_RowNumbersColumnDef.tsx index 0bcc94974..1a5f04b74 100644 --- a/packages/material-react-table/src/hooks/display-columns/getMRT_RowNumbersColumnDef.tsx +++ b/packages/material-react-table/src/hooks/display-columns/getMRT_RowNumbersColumnDef.tsx @@ -30,6 +30,7 @@ export const getMRT_RowNumbersColumnDef = ( ...defaultDisplayColumnProps({ header: 'rowNumbers', id: 'mrt-row-numbers', + size: 50, tableOptions, }), }; diff --git a/packages/material-react-table/src/hooks/display-columns/getMRT_RowPinningColumnDef.tsx b/packages/material-react-table/src/hooks/display-columns/getMRT_RowPinningColumnDef.tsx index 637ef46db..49127b966 100644 --- a/packages/material-react-table/src/hooks/display-columns/getMRT_RowPinningColumnDef.tsx +++ b/packages/material-react-table/src/hooks/display-columns/getMRT_RowPinningColumnDef.tsx @@ -24,6 +24,7 @@ export const getMRT_RowPinningColumnDef = ( ...defaultDisplayColumnProps({ header: 'pin', id: 'mrt-row-pin', + size: 60, tableOptions, }), }; diff --git a/packages/material-react-table/src/hooks/display-columns/getMRT_RowSelectColumnDef.tsx b/packages/material-react-table/src/hooks/display-columns/getMRT_RowSelectColumnDef.tsx index 5e5291761..a1864ccd6 100644 --- a/packages/material-react-table/src/hooks/display-columns/getMRT_RowSelectColumnDef.tsx +++ b/packages/material-react-table/src/hooks/display-columns/getMRT_RowSelectColumnDef.tsx @@ -28,12 +28,13 @@ export const getMRT_RowSelectColumnDef = ( ), Header: enableSelectAll && enableMultiRowSelection - ? ({ table }) => + ? ({ table }) => : undefined, grow: false, ...defaultDisplayColumnProps({ header: 'select', id: 'mrt-row-select', + size: enableSelectAll ? 60 : 70, tableOptions, }), }; diff --git a/packages/material-react-table/src/utils/displayColumn.utils.ts b/packages/material-react-table/src/utils/displayColumn.utils.ts index 20346c5e6..2275beb42 100644 --- a/packages/material-react-table/src/utils/displayColumn.utils.ts +++ b/packages/material-react-table/src/utils/displayColumn.utils.ts @@ -10,12 +10,12 @@ import { getAllLeafColumnDefs, getColumnId } from './column.utils'; export function defaultDisplayColumnProps({ header, id, - size = 60, + size, tableOptions, }: { header?: keyof MRT_Localization; id: MRT_DisplayColumnIds; - size?: number; + size: number; tableOptions: MRT_DefinedTableOptions; }) { const { defaultDisplayColumn, displayColumnDefOptions, localization } = diff --git a/packages/material-react-table/src/utils/row.utils.ts b/packages/material-react-table/src/utils/row.utils.ts index 9342e4ff7..c1ae8ef49 100644 --- a/packages/material-react-table/src/utils/row.utils.ts +++ b/packages/material-react-table/src/utils/row.utils.ts @@ -1,4 +1,25 @@ -import { type MRT_RowData, type MRT_TableInstance } from '../types'; +import { + type MRT_Row, + type MRT_RowData, + type MRT_TableInstance, +} from '../types'; +import { parseFromValuesOrFunc } from './utils'; + +export const getIsRowSelected = ({ + row, + table, +}: { + row: MRT_Row; + table: MRT_TableInstance; +}) => { + const { options: enableRowSelection } = table; + return ( + row.getIsSelected() || + (parseFromValuesOrFunc(enableRowSelection, row) && + row.getCanSelectSubRows() && + row.getIsAllSubRowsSelected()) + ); +}; export const getCanRankRows = ( table: MRT_TableInstance, diff --git a/packages/material-react-table/src/utils/style.utils.ts b/packages/material-react-table/src/utils/style.utils.ts index f0db14238..b9032fa65 100644 --- a/packages/material-react-table/src/utils/style.utils.ts +++ b/packages/material-react-table/src/utils/style.utils.ts @@ -4,7 +4,6 @@ import { type TooltipProps } from '@mui/material/Tooltip'; import { alpha, darken, lighten } from '@mui/material/styles'; import { type Theme } from '@mui/material/styles'; import { - type MRT_Cell, type MRT_Column, type MRT_Header, type MRT_RowData, @@ -43,7 +42,7 @@ export const getMRTTheme = ( }; }; -const pinnedBeforeAfterStyles = { +export const pinnedBeforeAfterStyles = { content: '""', height: '100%', left: 0, @@ -53,36 +52,59 @@ const pinnedBeforeAfterStyles = { zIndex: -1, }; +export const getCommonPinnedCellStyles = ({ + column, + table, + theme, +}: { + column?: MRT_Column; + table: MRT_TableInstance; + theme: Theme; +}) => { + const { baseBackgroundColor } = getMRTTheme(table, theme); + return { + '&[data-pinned="true"]': { + '&:before': { + backgroundColor: alpha( + darken( + baseBackgroundColor, + theme.palette.mode === 'dark' ? 0.05 : 0.01, + ), + 0.97, + ), + boxShadow: column + ? getIsLastLeftPinnedColumn(table, column) + ? `-4px 0 4px -4px ${alpha(theme.palette.grey[700], 0.5)} inset` + : getIsFirstRightPinnedColumn(column) + ? `4px 0 4px -4px ${alpha(theme.palette.grey[700], 0.5)} inset` + : undefined + : undefined, + ...pinnedBeforeAfterStyles, + }, + }, + }; +}; + export const getCommonMRTCellStyles = ({ - cell, column, header, table, tableCellProps, theme, }: { - cell?: MRT_Cell; column: MRT_Column; header?: MRT_Header; table: MRT_TableInstance; tableCellProps: TableCellProps; theme: Theme; }) => { - const { - baseBackgroundColor, - pinnedRowBackgroundColor, - selectedRowBackgroundColor, - } = getMRTTheme(table, theme); const { options: { enableColumnVirtualization, layoutMode }, } = table; const { columnDef } = column; - const { row } = cell ?? {}; const isColumnPinned = columnDef.columnDefType !== 'group' && column.getIsPinned(); - const isRowPinned = row?.getIsPinned(); - const isRowSelected = row?.getIsSelected(); const widthStyles: CSSProperties = { minWidth: `max(calc(var(--${header ? 'header' : 'col'}-${parseCSSVarId( @@ -107,34 +129,12 @@ export const getCommonMRTCellStyles = ({ const pinnedStyles = isColumnPinned ? { - '&:after': { - backgroundColor: isRowSelected - ? selectedRowBackgroundColor - : isRowPinned - ? pinnedRowBackgroundColor - : undefined, - ...pinnedBeforeAfterStyles, - }, - '&:before': { - backgroundColor: alpha( - darken( - baseBackgroundColor, - theme.palette.mode === 'dark' ? 0.05 : 0.01, - ), - 0.9, - ), - ...pinnedBeforeAfterStyles, - }, - boxShadow: getIsLastLeftPinnedColumn(table, column) - ? `-4px 0 8px -6px ${alpha(theme.palette.grey[700], 0.5)} inset` - : getIsFirstRightPinnedColumn(column) - ? `4px 0 8px -6px ${alpha(theme.palette.grey[700], 0.5)} inset` - : undefined, + ...getCommonPinnedCellStyles({ column, table, theme }), left: isColumnPinned === 'left' ? `${column.getStart('left')}px` : undefined, - opacity: 0.98, + opacity: 0.97, position: 'sticky', right: isColumnPinned === 'right' @@ -153,9 +153,11 @@ export const getCommonMRTCellStyles = ({ table.getState().hoveredColumn?.id === column.id ? 0.5 : 1, + position: 'relative', transition: enableColumnVirtualization ? 'none' : `padding 150ms ease-in-out`, + zIndex: 0, ...pinnedStyles, ...widthStyles, ...(parseFromValuesOrFunc(tableCellProps?.sx, theme) as any), diff --git a/packages/material-react-table/stories/features/Aggregation.stories.tsx b/packages/material-react-table/stories/features/Aggregation.stories.tsx index d844aa589..f1146bbda 100644 --- a/packages/material-react-table/stories/features/Aggregation.stories.tsx +++ b/packages/material-react-table/stories/features/Aggregation.stories.tsx @@ -121,6 +121,15 @@ export const Aggregation = () => ( ); +export const AggregationWithSelection = () => ( + +); + export const AggregationExpandedDefault = () => ( ( width: '100%', }} > - {selectedAlert}{' '} + {selectedAlert}{' '}