diff --git a/README.md b/README.md index 495048997..d7bec35ec 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,10 @@ _All features can easily be enabled/disabled_ _**Fully Fleshed out [Docs](https://www.material-react-table.com/docs/guides#guides) are available for all features**_ -- [x] 43-53kb gzipped - [Bundlephobia](https://bundlephobia.com/package/material-react-table) +- [x] 30-54kb gzipped - [Bundlephobia](https://bundlephobia.com/package/material-react-table) - [x] Advanced TypeScript Generics Support (TypeScript Optional) - [x] Aggregation and Grouping (Sum, Average, Count, etc.) +- [x] Cell Actions (Right-click Context Menu) - [x] Click To Copy Cell Values - [x] Column Action Dropdown Menu - [x] Column Hiding @@ -79,7 +80,7 @@ _**Fully Fleshed out [Docs](https://www.material-react-table.com/docs/guides#gui - [x] Column Resizing - [x] Customize Icons - [x] Customize Styling of internal Mui Components -- [x] Data Editing (4 different editing modes) +- [x] Data Editing and Creating (5 different editing modes) - [x] Density Toggle - [x] Detail Panels (Expansion) - [x] Faceted Value Generation for Filter Options diff --git a/apps/material-react-table-docs/components/navigation/TopBar.tsx b/apps/material-react-table-docs/components/navigation/TopBar.tsx index 3dbe9e8fc..0e210815e 100644 --- a/apps/material-react-table-docs/components/navigation/TopBar.tsx +++ b/apps/material-react-table-docs/components/navigation/TopBar.tsx @@ -194,7 +194,7 @@ export const TopBar = ({ navOpen, setNavOpen }: Props) => { target="_blank" > - + @@ -207,7 +207,7 @@ export const TopBar = ({ navOpen, setNavOpen }: Props) => { Discord { }} size="small" > - {isLightTheme ? ( - - ) : ( - - )} + {isLightTheme ? : } diff --git a/apps/material-react-table-docs/examples/custom-headless/sandbox/src/JS.js b/apps/material-react-table-docs/examples/custom-headless/sandbox/src/JS.js index 6b0362094..f596b46f9 100644 --- a/apps/material-react-table-docs/examples/custom-headless/sandbox/src/JS.js +++ b/apps/material-react-table-docs/examples/custom-headless/sandbox/src/JS.js @@ -99,12 +99,16 @@ const Example = () => { ))} - {table.getRowModel().rows.map((row) => ( + {table.getRowModel().rows.map((row, rowIndex) => ( - {row.getVisibleCells().map((cell) => ( + {row.getVisibleCells().map((cell, _columnIndex) => ( {/* Use MRT's cell renderer that provides better logic than flexRender */} - + ))} diff --git a/apps/material-react-table-docs/examples/custom-headless/sandbox/src/TS.tsx b/apps/material-react-table-docs/examples/custom-headless/sandbox/src/TS.tsx index d856898aa..b8602a1ee 100644 --- a/apps/material-react-table-docs/examples/custom-headless/sandbox/src/TS.tsx +++ b/apps/material-react-table-docs/examples/custom-headless/sandbox/src/TS.tsx @@ -100,12 +100,16 @@ const Example = () => { ))} - {table.getRowModel().rows.map((row) => ( + {table.getRowModel().rows.map((row, rowIndex) => ( - {row.getVisibleCells().map((cell) => ( + {row.getVisibleCells().map((cell, _columnIndex) => ( {/* Use MRT's cell renderer that provides better logic than flexRender */} - + ))} diff --git a/apps/material-react-table-docs/examples/manual-selection/sandbox/src/JS.js b/apps/material-react-table-docs/examples/manual-selection/sandbox/src/JS.js index a8894a23c..a393af385 100644 --- a/apps/material-react-table-docs/examples/manual-selection/sandbox/src/JS.js +++ b/apps/material-react-table-docs/examples/manual-selection/sandbox/src/JS.js @@ -71,7 +71,7 @@ const Example = () => { onClick: () => setRowSelection((prev) => ({ ...prev, - [row.id]: !prev[row.id], + [row.id]: !prev[row.id], //this is a simple toggle implementation })), selected: rowSelection[row.id], sx: { diff --git a/apps/material-react-table-docs/examples/manual-selection/sandbox/src/TS.tsx b/apps/material-react-table-docs/examples/manual-selection/sandbox/src/TS.tsx index 3a2b47c2e..d701b32cc 100644 --- a/apps/material-react-table-docs/examples/manual-selection/sandbox/src/TS.tsx +++ b/apps/material-react-table-docs/examples/manual-selection/sandbox/src/TS.tsx @@ -85,7 +85,7 @@ const Example = () => { onClick: () => setRowSelection((prev) => ({ ...prev, - [row.id]: !prev[row.id], + [row.id]: !prev[row.id], //this is a simple toggle implementation })), selected: rowSelection[row.id], sx: { diff --git a/apps/material-react-table-docs/pages/changelog.mdx b/apps/material-react-table-docs/pages/changelog.mdx index 936edb96b..b71a6d7bd 100644 --- a/apps/material-react-table-docs/pages/changelog.mdx +++ b/apps/material-react-table-docs/pages/changelog.mdx @@ -12,6 +12,15 @@ import Head from 'next/head'; ### Version 2 +#### Version 2.11.0 - 2024-02-05 + +- Added new `enableBatchRowSelection` table option that is enabled by default that allows users to select multiple rows at once by holding down the shift key and clicking on a row +- Added small "Clear selection" button to the toolbar alert banner selected message by default when rows are selected +- Now exporting all `MRT_*Props` component prop types +- Added new override option for passing in custom spinner while loading data with the `muiCircularProgressProps.Component` prop +- Fixed Autocomplete filter showing filter values instead of display labels once value is selected +- Removed default Header html title attribute on all header cells + #### Version 2.10.0 - 2024-01-31 - Added automatic column order state recalculation for dynamic columns and dynamic MRT display columns being enabled/disabled @@ -20,7 +29,7 @@ import Head from 'next/head'; - Added new Cell Actions features which will show a MUI context menu when a cell is right-clicked - New `enableCellActions` table option - New `renderCellActionMenuItems` table and column options - - New `MRT_ActionMenuItem` component to make styling all MRT menu items consistently (icons, text, spacing) easier to be consistent. + - New `MRT_ActionMenuItem` component to make styling all MRT menu items consistently (icons, text, spacing) easier to be consistent - Fixed bug where the show all columns action menu item ignored the `enableHiding` column option #### Version 2.9.2 - 2024-01-25 diff --git a/apps/material-react-table-docs/pages/docs/guides/async-loading.mdx b/apps/material-react-table-docs/pages/docs/guides/async-loading.mdx index 1bd656aab..2750f9f7c 100644 --- a/apps/material-react-table-docs/pages/docs/guides/async-loading.mdx +++ b/apps/material-react-table-docs/pages/docs/guides/async-loading.mdx @@ -114,7 +114,25 @@ return ; -#### Only Show Progress Bars or Skeletons +#### Custom Loading Spinner component + +> New in v2.11.0 + +If you need to use a custom loading spinner component other than the built-in MUI one, you can now pass in custom component in the `muiCircularProgressProps` `Component` prop. + +```jsx +import { MyCustomSpinner } from './MyCustomSpinner'; + +const table = useMaterialReactTable({ + columns, + data, + muiCircularProgressProps: { + Component: , + }, +}); +``` + +### Only Show Progress Bars or Skeletons If you do not want both progress bars and cell skeletons to show, you can use the `showProgressBars` and `showSkeletons` states, instead. diff --git a/apps/material-react-table-docs/pages/docs/guides/column-filtering.mdx b/apps/material-react-table-docs/pages/docs/guides/column-filtering.mdx index c896acc08..4386690d2 100644 --- a/apps/material-react-table-docs/pages/docs/guides/column-filtering.mdx +++ b/apps/material-react-table-docs/pages/docs/guides/column-filtering.mdx @@ -8,7 +8,6 @@ import CustomizeFilterVariantsExample from '../../../examples/customize-filter-v import CustomizeFilterModesExample from '../../../examples/customize-filter-modes'; import CustomizeFilterComponentsExample from '../../../examples/customize-filter-components'; import EnableColumnFacetValuesExample from '../../../examples/enable-filter-facet-values'; -import RemoteExample from '../../../examples/remote'; {'Column Filtering Guide - Material React Table V2 Docs'} @@ -353,9 +352,7 @@ return ; > Specifying `manualFiltering` turns off all client-side filtering and assumes that the `data` you pass to `` is already filtered. -Here is the full Remote Data example featuring server-side **filtering**, pagination, and sorting. - - +See either the [React Query](/docs/examples/react-query) or [useEffect fetching](/docs/examples/remote) examples to see fully server-side **filtering**, pagination, and sorting in action. ### Customize Material UI Filter components diff --git a/apps/material-react-table-docs/pages/docs/guides/row-selection.mdx b/apps/material-react-table-docs/pages/docs/guides/row-selection.mdx index badfb1911..2fd15c803 100644 --- a/apps/material-react-table-docs/pages/docs/guides/row-selection.mdx +++ b/apps/material-react-table-docs/pages/docs/guides/row-selection.mdx @@ -58,30 +58,30 @@ const table = useMaterialReactTable({ return ; ``` -### Batch Row Selection - -> New in v2.11.0 +#### Enable Row Selection Conditionally Per Row -By default, when the user holds down the Shift key and clicks a row, all rows between the last selected row and the clicked row will be selected. This can be disabled with the `enableBatchRowSelection` table option. +You can also enable row selection conditionally per row with the same `enableRowSelection` table option, but with a callback function instead of a boolean. ```jsx -const table = useMantineReactTable({ +const table = useMaterialReactTable({ columns, data, - enableRowSelection: true, - enableBatchRowSelection: false, //disable batch row selection with shift key + enableRowSelection: (row) => row.original.age > 18, //disable row selection for rows with age <= 18 }); ``` -#### Enable Row Selection Conditionally Per Row +### Batch Row Selection -You can also enable row selection conditionally per row with the same `enableRowSelection` table option, but with a callback function instead of a boolean. +> New in v2.11.0 + +By default, when the user holds down the Shift key and clicks a row, all rows between the last selected row and the clicked row will be selected. This can be disabled with the `enableBatchRowSelection` table option. ```jsx -const table = useMaterialReactTable({ +const table = useMantineReactTable({ columns, data, - enableRowSelection: (row) => row.original.age > 18, //disable row selection for rows with age <= 18 + enableRowSelection: true, + enableBatchRowSelection: false, //disable batch row selection with shift key }); ``` @@ -174,8 +174,9 @@ const table = useMaterialReactTable({ data, enableRowSelection: true, //clicking anywhere on the row will select it - muiTableBodyRowProps: ({ row }) => ({ - onClick: row.getToggleSelectedHandler(), + muiTableBodyRowProps: ({ row, staticRowIndex, table }) => ({ + onClick: (event) => + getMRT_RowSelectionHandler()({ event, row, staticRowIndex, table }), //import this helper function from material-react-table sx: { cursor: 'pointer' }, }), }); diff --git a/packages/material-react-table/README.md b/packages/material-react-table/README.md index 495048997..d7bec35ec 100644 --- a/packages/material-react-table/README.md +++ b/packages/material-react-table/README.md @@ -68,9 +68,10 @@ _All features can easily be enabled/disabled_ _**Fully Fleshed out [Docs](https://www.material-react-table.com/docs/guides#guides) are available for all features**_ -- [x] 43-53kb gzipped - [Bundlephobia](https://bundlephobia.com/package/material-react-table) +- [x] 30-54kb gzipped - [Bundlephobia](https://bundlephobia.com/package/material-react-table) - [x] Advanced TypeScript Generics Support (TypeScript Optional) - [x] Aggregation and Grouping (Sum, Average, Count, etc.) +- [x] Cell Actions (Right-click Context Menu) - [x] Click To Copy Cell Values - [x] Column Action Dropdown Menu - [x] Column Hiding @@ -79,7 +80,7 @@ _**Fully Fleshed out [Docs](https://www.material-react-table.com/docs/guides#gui - [x] Column Resizing - [x] Customize Icons - [x] Customize Styling of internal Mui Components -- [x] Data Editing (4 different editing modes) +- [x] Data Editing and Creating (5 different editing modes) - [x] Density Toggle - [x] Detail Panels (Expansion) - [x] Faceted Value Generation for Filter Options diff --git a/packages/material-react-table/package.json b/packages/material-react-table/package.json index de0beb2f4..861043327 100644 --- a/packages/material-react-table/package.json +++ b/packages/material-react-table/package.json @@ -1,5 +1,5 @@ { - "version": "2.10.0", + "version": "2.11.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 5dce81b9b..140e99b45 100644 --- a/packages/material-react-table/src/components/body/MRT_TableBodyCell.tsx +++ b/packages/material-react-table/src/components/body/MRT_TableBodyCell.tsx @@ -299,6 +299,7 @@ export const MRT_TableBodyCell = ({ renderedCellValue: cell.renderValue() as any, row, rowRef, + staticColumnIndex, staticRowIndex, table, }) diff --git a/packages/material-react-table/src/components/body/MRT_TableBodyCellValue.tsx b/packages/material-react-table/src/components/body/MRT_TableBodyCellValue.tsx index fcd09a189..ce8d64ccc 100644 --- a/packages/material-react-table/src/components/body/MRT_TableBodyCellValue.tsx +++ b/packages/material-react-table/src/components/body/MRT_TableBodyCellValue.tsx @@ -13,6 +13,7 @@ const allowedTypes = ['string', 'number']; export interface MRT_TableBodyCellValueProps { cell: MRT_Cell; rowRef?: RefObject; + staticColumnIndex?: number; staticRowIndex?: number; table: MRT_TableInstance; } @@ -20,6 +21,7 @@ export interface MRT_TableBodyCellValueProps { export const MRT_TableBodyCellValue = ({ cell, rowRef, + staticColumnIndex, staticRowIndex, table, }: MRT_TableBodyCellValueProps) => { @@ -113,6 +115,7 @@ export const MRT_TableBodyCellValue = ({ renderedCellValue, row, rowRef, + staticColumnIndex, staticRowIndex, table, }); diff --git a/packages/material-react-table/src/components/inputs/MRT_FilterTextField.tsx b/packages/material-react-table/src/components/inputs/MRT_FilterTextField.tsx index b2c64a998..4cb644d19 100644 --- a/packages/material-react-table/src/components/inputs/MRT_FilterTextField.tsx +++ b/packages/material-react-table/src/components/inputs/MRT_FilterTextField.tsx @@ -161,6 +161,10 @@ export const MRT_FilterTextField = ({ ] || '' : (column.getFilterValue() as string) ?? '', ); + const [autocompleteValue, setAutocompleteValue] = + useState( + isAutocompleteFilter ? (filterValue as DropdownOption | null) : null, + ); const handleChangeDebounced = useCallback( debounce( @@ -196,6 +200,11 @@ export const MRT_FilterTextField = ({ textFieldProps?.onChange?.(event); }; + const handleAutocompleteChange = (newValue: DropdownOption) => { + setAutocompleteValue(newValue); + handleChange(getValueAndLabel(newValue).value); + }; + const handleClear = () => { if (isMultiSelectFilter) { setFilterValue([]); @@ -435,41 +444,35 @@ export const MRT_FilterTextField = ({ }, }} /> - ) : isAutocompleteFilter ? (() => { - const [autocompleteValue, setAutocompleteValue] = useState(null); - const handleAutocompleteChange = (newValue: DropdownOption) => { - setAutocompleteValue(newValue); - handleChange(getValueAndLabel(newValue).value); - }; - return getValueAndLabel(option).label} - onChange={(_e, newValue) => handleAutocompleteChange(newValue)} - options={ - dropdownOptions?.map((option) => getValueAndLabel(option)) ?? [] - } - {...autocompleteProps} - renderInput={(builtinTextFieldProps) => ( - getValueAndLabel(option).label} + onChange={(_e, newValue) => handleAutocompleteChange(newValue)} + options={ + dropdownOptions?.map((option) => getValueAndLabel(option)) ?? [] + } + {...autocompleteProps} + renderInput={(builtinTextFieldProps) => ( + ) => e.stopPropagation()} - /> - )} - value={autocompleteValue} - />; - } - )() : ( + }} + inputProps={{ + ...builtinTextFieldProps.inputProps, + ...commonTextFieldProps?.inputProps, + }} + onChange={handleTextFieldChange} + onClick={(e: MouseEvent) => e.stopPropagation()} + /> + )} + value={autocompleteValue} + /> + ) : ( ({ rowPinningDisplayMode, selectAllMode, }, + refs: { lastSelectedRowId }, } = table; const { density, isLoading } = getState(); @@ -76,6 +77,7 @@ export const MRT_SelectCheckbox = ({ if (isStickySelection) { table.setRowPinning({ bottom: [], top: [] }); } + lastSelectedRowId.current = null; }; const commonProps = { diff --git a/packages/material-react-table/src/components/menus/MRT_ShowHideColumnsMenu.tsx b/packages/material-react-table/src/components/menus/MRT_ShowHideColumnsMenu.tsx index 2ba27afce..10ec62354 100644 --- a/packages/material-react-table/src/components/menus/MRT_ShowHideColumnsMenu.tsx +++ b/packages/material-react-table/src/components/menus/MRT_ShowHideColumnsMenu.tsx @@ -76,6 +76,10 @@ export const MRT_ShowHideColumnsMenu = ({ getRightLeafColumns(), ]) as MRT_Column[]; + const isNestedColumns = allColumns.some( + (col) => col.columnDef.columnDefType === 'group', + ); + const [hoveredColumn, setHoveredColumn] = useState | null>( null, ); @@ -147,6 +151,7 @@ export const MRT_ShowHideColumnsMenu = ({ allColumns={allColumns} column={column} hoveredColumn={hoveredColumn} + isNestedColumns={isNestedColumns} key={`${index}-${column.id}`} setHoveredColumn={setHoveredColumn} table={table} diff --git a/packages/material-react-table/src/components/menus/MRT_ShowHideColumnsMenuItems.tsx b/packages/material-react-table/src/components/menus/MRT_ShowHideColumnsMenuItems.tsx index 31daf5002..2dfed2b35 100644 --- a/packages/material-react-table/src/components/menus/MRT_ShowHideColumnsMenuItems.tsx +++ b/packages/material-react-table/src/components/menus/MRT_ShowHideColumnsMenuItems.tsx @@ -27,6 +27,7 @@ export interface MRT_ShowHideColumnsMenuItemsProps allColumns: MRT_Column[]; column: MRT_Column; hoveredColumn: MRT_Column | null; + isNestedColumns: boolean; setHoveredColumn: Dispatch | null>>; table: MRT_TableInstance; } @@ -35,6 +36,7 @@ export const MRT_ShowHideColumnsMenuItems = ({ allColumns, column, hoveredColumn, + isNestedColumns, setHoveredColumn, table, ...rest @@ -131,9 +133,7 @@ export const MRT_ShowHideColumnsMenuItems = ({ > {columnDefType !== 'group' && enableColumnOrdering && - !allColumns.some( - (col) => col.columnDef.columnDefType === 'group', - ) && + !isNestedColumns && (columnDef.enableColumnOrdering !== false ? ( ({ allColumns={allColumns} column={c} hoveredColumn={hoveredColumn} + isNestedColumns={isNestedColumns} key={`${i}-${c.id}`} setHoveredColumn={setHoveredColumn} table={table} 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 9a8fa7b98..700ded570 100644 --- a/packages/material-react-table/src/components/toolbar/MRT_ToolbarAlertBanner.tsx +++ b/packages/material-react-table/src/components/toolbar/MRT_ToolbarAlertBanner.tsx @@ -2,6 +2,7 @@ import { Fragment, useMemo } from 'react'; import Alert, { type AlertProps } from '@mui/material/Alert'; import AlertTitle from '@mui/material/AlertTitle'; import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; import Chip from '@mui/material/Chip'; import Collapse from '@mui/material/Collapse'; import Stack from '@mui/material/Stack'; @@ -21,19 +22,21 @@ export const MRT_ToolbarAlertBanner = ({ ...rest }: MRT_ToolbarAlertBannerProps) => { const { + getFilteredSelectedRowModel, getPrePaginationRowModel, getState, options: { enableRowSelection, enableSelectAll, localization, + manualPagination, muiToolbarAlertBannerChipProps, muiToolbarAlertBannerProps, positionToolbarAlertBanner, renderToolbarAlertBannerContent, rowCount, }, - refs: { tablePaperRef }, + refs: { lastSelectedRowId, tablePaperRef }, } = table; const { density, grouping, rowSelection, showAlertBanner } = getState(); @@ -48,20 +51,33 @@ export const MRT_ToolbarAlertBanner = ({ table, }); + const totalRowCount = rowCount ?? getPrePaginationRowModel().rows.length; + const selectedRowCount = useMemo( - () => Object.values(rowSelection).filter(Boolean).length, - [rowSelection], + () => + manualPagination + ? Object.values(rowSelection).filter(Boolean).length + : getFilteredSelectedRowModel().rows.length, + [rowSelection, totalRowCount, manualPagination], ); - const selectedAlert = - selectedRowCount > 0 - ? localization.selectedCountOfRowCountRowsSelected + selectedRowCount > 0 ? ( + + {localization.selectedCountOfRowCountRowsSelected ?.replace('{selectedCount}', selectedRowCount.toLocaleString()) - ?.replace( - '{rowCount}', - (rowCount ?? getPrePaginationRowModel().rows.length).toString(), - ) - : null; + ?.replace('{rowCount}', totalRowCount.toString())} + + + ) : null; const groupedAlert = grouping.length > 0 ? ( diff --git a/packages/material-react-table/src/types.ts b/packages/material-react-table/src/types.ts index 7d133c6c0..282a9bbe6 100644 --- a/packages/material-react-table/src/types.ts +++ b/packages/material-react-table/src/types.ts @@ -380,7 +380,7 @@ export type MRT_StatefulTableOptions = >; }; -export type MRT_TableState = TableState & { +export interface MRT_TableState extends TableState { actionCell?: MRT_Cell | null; columnFilterFns: MRT_ColumnFilterFnsState; creatingRow: MRT_Row | null; @@ -402,7 +402,7 @@ export type MRT_TableState = TableState & { showProgressBars: boolean; showSkeletons: boolean; showToolbarDropZone: boolean; -}; +} export type MRT_ColumnDef = Omit< ColumnDef, @@ -429,6 +429,7 @@ export type MRT_ColumnDef = Omit< renderedCellValue: ReactNode; row: MRT_Row; rowRef?: RefObject; + staticColumnIndex?: number; staticRowIndex?: number; table: MRT_TableInstance; }) => ReactNode; diff --git a/packages/material-react-table/stories/features/Filtering.stories.tsx b/packages/material-react-table/stories/features/Filtering.stories.tsx index c88677b7a..684ebebf2 100644 --- a/packages/material-react-table/stories/features/Filtering.stories.tsx +++ b/packages/material-react-table/stories/features/Filtering.stories.tsx @@ -216,7 +216,7 @@ export const FilterFnAndFilterVariantsFaceted = () => ( { accessorKey: 'firstName', filterSelectOptions: data.map((row) => ({ - label: row.firstName.toUpperCase(), + label: row.firstName.toUpperCase().split('').reverse().join(''), value: row.firstName, })), //hard coded filterVariant: 'autocomplete', diff --git a/packages/material-react-table/stories/features/Selection.stories.tsx b/packages/material-react-table/stories/features/Selection.stories.tsx index ea1275fa3..42a4d8c0c 100644 --- a/packages/material-react-table/stories/features/Selection.stories.tsx +++ b/packages/material-react-table/stories/features/Selection.stories.tsx @@ -60,7 +60,7 @@ export const SelectionEnabledGrid = () => ( data={data} enableRowNumbers enableRowSelection - layoutMode='grid' + layoutMode="grid" /> ); @@ -70,7 +70,7 @@ export const SelectionEnabledGridNoGrow = () => ( data={data} enableRowNumbers enableRowSelection - layoutMode='grid-no-grow' + layoutMode="grid-no-grow" /> );